package session 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") 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") case "tool": return []byte("[tool:" + ev.Name + "]\n" + strings.TrimRight(ev.Content, "\n") + "\n") case "error": return []byte("[error]\n" + ev.Content + "\n") case "info": return []byte("[info]\n" + ev.Content) case "retry": return []byte("[retry]\n" + ev.Content + "s\n") case "stalled": return []byte("[stalled]\n") case "maxsteps": return []byte("[maxsteps]\n" + ev.Content + "\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(sess *Session, 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": sess.AppendLog([]byte("[user]\n" + m.Content + "\n")) case "assistant": header := "[assistant]" if m.ID != "" { header = "[assistant:" + m.ID + "]" } sess.AppendLog([]byte(header + "\n")) if m.Content != "" { sess.AppendLog([]byte(m.Content + "\n")) } for _, tc := range m.ToolCalls { args := squashWhitespace(string(tc.Arguments)) sess.AppendLog([]byte("[call:" + tc.Name + "]\n" + args + "\n")) } case "tool": sess.AppendLog([]byte("[tool]\n" + strings.TrimRight(m.Content, "\n") + "\n")) } } }