96 lines
2.7 KiB
Go
96 lines
2.7 KiB
Go
package fs
|
|
|
|
import (
|
|
"ollie/agent"
|
|
"ollie/backend"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
func LoadAgentConfig(agentsDir, name string, open func(string) (*os.File, error)) *agent.AgentConfig {
|
|
if open == nil {
|
|
open = os.Open
|
|
}
|
|
path := agent.AgentConfigPath(agentsDir, name)
|
|
f, err := open(path)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
defer f.Close()
|
|
cfg, _ := agent.Load(f)
|
|
return cfg
|
|
}
|
|
|
|
// FormatEvent converts an agent Event to bytes for appending to a chat log.
|
|
// Streaming roles (assistant, reasoning) return only the content chunk;
|
|
// the caller (startEventLog) is responsible for writing the [[[role]]] header.
|
|
func FormatEvent(ev agent.Event) []byte {
|
|
switch ev.Role {
|
|
case "user":
|
|
return []byte("[[[user]]]\n" + ev.Content + "\n[[[end]]]\n")
|
|
case "assistant":
|
|
return []byte(ev.Content)
|
|
case "reasoning":
|
|
return []byte(ev.Content)
|
|
case "call":
|
|
args := squashWhitespace(ev.Content)
|
|
return []byte("[[[call:" + ev.Name + "]]]\n" + args + "\n[[[end]]]\n")
|
|
case "tool":
|
|
return []byte("[[[tool:" + ev.Name + "]]]\n" + strings.TrimRight(ev.Content, "\n") + "\n[[[end]]]\n")
|
|
case "error":
|
|
return []byte("[[[error]]]\n" + ev.Content + "\n[[[end]]]\n")
|
|
case "info":
|
|
return []byte("[[[info]]]\n" + ev.Content + "\n[[[end]]]\n")
|
|
case "retry":
|
|
return []byte(ev.Content)
|
|
case "stalled":
|
|
return []byte("[[[stalled]]]\n[[[end]]]\n")
|
|
case "maxsteps":
|
|
return []byte("[[[maxsteps]]]\n" + ev.Content + "\n[[[end]]]\n")
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func squashWhitespace(s string) string {
|
|
return strings.Join(strings.Fields(s), " ")
|
|
}
|
|
|
|
// replayMessagesToLog renders the tail of a persisted message list into the
|
|
// session's chat log so that restored sessions show recent history.
|
|
func replayMessagesToLog(as *AgentLog, messages []backend.Message) {
|
|
const maxReplay = 20
|
|
start := len(messages) - maxReplay
|
|
if start < 0 {
|
|
start = 0
|
|
}
|
|
// Skip system messages at the start of the replay window.
|
|
for start < len(messages) && messages[start].Role == "system" {
|
|
start++
|
|
}
|
|
for _, m := range messages[start:] {
|
|
switch m.Role {
|
|
case "system":
|
|
// skip
|
|
case "user":
|
|
as.AppendLog([]byte("[[[user]]]\n" + m.Content + "\n[[[end]]]\n"))
|
|
case "assistant":
|
|
header := "[[[assistant]]]"
|
|
if m.ID != "" {
|
|
header = "[[[assistant:" + m.ID + "]]]"
|
|
}
|
|
as.AppendLog([]byte(header + "\n"))
|
|
if m.Content != "" {
|
|
as.AppendLog([]byte(m.Content + "\n"))
|
|
}
|
|
for _, tc := range m.ToolCalls {
|
|
args := squashWhitespace(string(tc.Arguments))
|
|
as.AppendLog([]byte("[[[call:" + tc.Name + "]]]\n" + args + "\n[[[end]]]\n"))
|
|
}
|
|
as.AppendLog([]byte("[[[end]]]\n"))
|
|
case "tool":
|
|
as.AppendLog([]byte("[[[tool]]]\n" + strings.TrimRight(m.Content, "\n") + "\n[[[end]]]\n"))
|
|
}
|
|
}
|
|
}
|