From da36db8f2bdfef7fd371ea7a0dae422637a02bef Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Sun, 17 May 2026 10:54:10 +0200 Subject: [PATCH] =?UTF-8?q?loop:=20introduce=20StepContext=20=E2=80=94=20p?= =?UTF-8?q?er-turn=20context=20object=20assembled=20once?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/agent/loop.go | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index d48220c..cee06e6 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -65,19 +65,31 @@ func run(ctx context.Context, cfg agentConfig, state state) error { // sync.Map is required because execOne may run in concurrent goroutines. var resultCache sync.Map + // stepCtx carries per-turn context assembled once at the top of each iteration. + type StepContext struct { + Goal string + TaskState *TaskState + Recent []backend.Message // last N messages (hot window) + } + for { + sc := StepContext{ + Goal: cfg.preamble, + TaskState: state.taskState(), + Recent: state.recentHistory(hotTailSize), + } + var history []backend.Message - if ts := state.taskState(); ts != nil { - // Structured mode: task state + recent tail only. - history = state.recentHistory(hotTailSize) + if sc.TaskState != nil { + history = sc.Recent } else { history = state.history() } - if cfg.preamble != "" { - history = append([]backend.Message{{Role: "system", Content: cfg.preamble}}, history...) + if sc.Goal != "" { + history = append([]backend.Message{{Role: "system", Content: sc.Goal}}, history...) } - if ts := state.taskState(); ts != nil { - if msg := ts.render(); msg != "" && len(history) > 0 { + if sc.TaskState != nil { + if msg := sc.TaskState.render(); msg != "" && len(history) > 0 { // Insert after system prompt, before conversation. history = append([]backend.Message{history[0], {Role: "user", Content: msg}}, history[1:]...) }