state: extend interface with recentHistory/taskState; loop uses selective context

This commit is contained in:
Levi Neely 2026-05-17 10:10:33 +02:00
parent 54351e8c85
commit 283a2e24d8
5 changed files with 46 additions and 14 deletions

View File

@ -969,12 +969,6 @@ func (s *agent) executeTurn(ctx context.Context, input string, handler EventHand
s.cfg.IncrToolCallCount = func() int64 {
return s.toolCallCount.Add(1)
}
s.cfg.TaskState = func() *TaskState {
if s.session == nil {
return nil
}
return s.session.TaskState
}
s.cfg.SaveSession = func() { s.saveSession() }
s.cfg.AutoCompact = func(ctx context.Context) {
if ctx.Err() != nil || s.session == nil {

View File

@ -62,8 +62,6 @@ type agentConfig struct {
PlanFile string
// IncrToolCallCount increments and returns the session-wide tool call counter.
IncrToolCallCount func() int64
// TaskState returns the current task state, or nil if not set.
TaskState func() *TaskState
}
// readPlanFile returns the contents of the plan file, or empty string if
@ -88,15 +86,20 @@ func run(ctx context.Context, cfg agentConfig, state state) error {
var resultCache sync.Map
for {
history := state.history()
var history []backend.Message
if ts := state.taskState(); ts != nil {
// Structured mode: task state + recent tail only.
history = state.recentHistory(recentTailSize)
} else {
history = state.history()
}
if cfg.preamble != "" {
history = append([]backend.Message{{Role: "system", Content: cfg.preamble}}, history...)
}
if cfg.TaskState != nil {
if ts := cfg.TaskState(); ts != nil {
if msg := ts.render(); msg != "" {
history = append([]backend.Message{history[0], {Role: "user", Content: msg}}, history[1:]...)
}
if ts := state.taskState(); ts != nil {
if msg := ts.render(); msg != "" {
// Insert after system prompt, before conversation.
history = append([]backend.Message{history[0], {Role: "user", Content: msg}}, history[1:]...)
}
}

View File

@ -48,6 +48,17 @@ func (s *simpleState) history() []backend.Message {
return s.msgs
}
func (s *simpleState) recentHistory(n int) []backend.Message {
if n >= len(s.msgs) {
return s.msgs
}
return s.msgs[len(s.msgs)-n:]
}
func (s *simpleState) taskState() *TaskState { return nil }
func (s *simpleState) updateTaskState(TaskState) {}
func (s *simpleState) update(msg backend.Message, results []toolResult) {
s.msgs = append(s.msgs, msg)
for _, r := range results {

View File

@ -137,6 +137,21 @@ func (s *Session) history() []backend.Message {
return s.messages
}
func (s *Session) recentHistory(n int) []backend.Message {
if n >= len(s.messages) {
return s.messages
}
return s.messages[len(s.messages)-n:]
}
func (s *Session) taskState() *TaskState {
return s.TaskState
}
func (s *Session) updateTaskState(ts TaskState) {
s.TaskState = &ts
}
func (s *Session) addUsage(u backend.Usage, estimated bool) {
s.TotalInputTokens += u.InputTokens
s.TotalCachedInputTokens += u.CachedInputTokens

View File

@ -17,6 +17,15 @@ type state interface {
// The first entry is always the initial user message containing the goal.
history() []backend.Message
// recentHistory returns the last n messages from the history.
recentHistory(n int) []backend.Message
// taskState returns the current structured task state, or nil if not set.
taskState() *TaskState
// updateTaskState replaces the current task state.
updateTaskState(ts TaskState)
// Update appends the assistant's reply and any tool results to the history.
// Called once per loop iteration after Act completes.
update(assistant backend.Message, results []toolResult)