agent/new: fork_at= parameter for historical context forking
Sub-agents can now inherit parent context truncated at a specific user turn: fork_at=5 means 'fork from the state after the 5th user message.' Enables backtracking without losing unsummarized context from before a failed approach. Without fork_at (or fork_at=0), full history is inherited as before.
This commit is contained in:
parent
c34f4a1b31
commit
ecb9406413
|
|
@ -345,13 +345,17 @@ func buildSessionChildren(
|
|||
virtfs.FileNode("new", 0666,
|
||||
virtfs.Doc("Create agent. With prompt=, runs as sub-agent: blocks until done, returns reply."),
|
||||
virtfs.Rdwr(func(ctx context.Context, data []byte) ([]byte, error) {
|
||||
params, prompt, parentID := parseAgentNewRequest(data)
|
||||
params, prompt, parentID, forkAt := parseAgentNewRequest(data)
|
||||
params.ParentID = parentID
|
||||
|
||||
// Sub-agent inherits parent's context.
|
||||
// Sub-agent inherits parent's context (optionally truncated at fork_at).
|
||||
if prompt != "" && parentID != "" {
|
||||
if parent := s.FindAgent(parentID); parent != nil {
|
||||
params.History = agent.RestoreHistoryFromMessages(parent.Messages())
|
||||
msgs := parent.Messages()
|
||||
if forkAt > 0 {
|
||||
msgs = messagesUpToTurn(msgs, forkAt)
|
||||
}
|
||||
params.History = agent.RestoreHistoryFromMessages(msgs)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"ollie/cmd/olliesrv/internal/agent"
|
||||
"ollie/cmd/olliesrv/internal/backend"
|
||||
"ollie/cmd/olliesrv/internal/session"
|
||||
"ollie/toolsrv/protocol"
|
||||
"ollie/virtfs"
|
||||
|
|
@ -90,11 +91,11 @@ var (
|
|||
// - Space-separated key=value (legacy format from GUI)
|
||||
//
|
||||
// A bare word (no =) is treated as the profile name (legacy positional arg).
|
||||
// Returns AgentParams, the prompt (empty if not a sub-agent request), and the parent agent ID.
|
||||
func parseAgentNewRequest(data []byte) (session.AgentParams, string, string) {
|
||||
// Returns AgentParams, prompt, parent agent ID, and fork_at (user-turn index, 0=all).
|
||||
func parseAgentNewRequest(data []byte) (session.AgentParams, string, string, int) {
|
||||
s := strings.TrimSpace(string(data))
|
||||
if s == "" {
|
||||
return session.AgentParams{Profile: "default"}, "", ""
|
||||
return session.AgentParams{Profile: "default"}, "", "", 0
|
||||
}
|
||||
|
||||
var tokens []string
|
||||
|
|
@ -106,6 +107,7 @@ func parseAgentNewRequest(data []byte) (session.AgentParams, string, string) {
|
|||
|
||||
p := session.AgentParams{Profile: "default"}
|
||||
var prompt, parent string
|
||||
var forkAt int
|
||||
for _, tok := range tokens {
|
||||
tok = strings.TrimSpace(tok)
|
||||
if tok == "" {
|
||||
|
|
@ -130,10 +132,27 @@ func parseAgentNewRequest(data []byte) (session.AgentParams, string, string) {
|
|||
prompt = v
|
||||
case "parent":
|
||||
parent = v
|
||||
case "fork_at":
|
||||
fmt.Sscanf(v, "%d", &forkAt)
|
||||
}
|
||||
} else if p.Profile == "default" {
|
||||
p.Profile = tok
|
||||
}
|
||||
}
|
||||
return p, prompt, parent
|
||||
return p, prompt, parent, forkAt
|
||||
}
|
||||
|
||||
// messagesUpToTurn returns messages up to (and including) the Nth user turn.
|
||||
// Turn 1 = first user message and everything before the second user message.
|
||||
func messagesUpToTurn(msgs []backend.Message, n int) []backend.Message {
|
||||
userCount := 0
|
||||
for i, m := range msgs {
|
||||
if m.Role == "user" {
|
||||
userCount++
|
||||
if userCount > n {
|
||||
return msgs[:i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue