diff --git a/pkg/agent/core.go b/pkg/agent/core.go index 7804d81..340c60d 100644 --- a/pkg/agent/core.go +++ b/pkg/agent/core.go @@ -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 { diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index bfe360a..0b1498c 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -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:]...) } } diff --git a/pkg/agent/loop_maxsteps_helpers_test.go b/pkg/agent/loop_maxsteps_helpers_test.go index 2e48bbd..a53481f 100644 --- a/pkg/agent/loop_maxsteps_helpers_test.go +++ b/pkg/agent/loop_maxsteps_helpers_test.go @@ -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 { diff --git a/pkg/agent/session.go b/pkg/agent/session.go index 48b8cb5..513fa95 100644 --- a/pkg/agent/session.go +++ b/pkg/agent/session.go @@ -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 diff --git a/pkg/agent/state.go b/pkg/agent/state.go index f7819d2..b87c67d 100644 --- a/pkg/agent/state.go +++ b/pkg/agent/state.go @@ -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)