From 8422663daf2887fc5c6c7d8ddb43f3de2a644d34 Mon Sep 17 00:00:00 2001 From: xgopilot Date: Tue, 5 May 2026 16:26:57 +0000 Subject: [PATCH] fix(prompt): clarify todo handling on task switches Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: phantom5099 <245659304+phantom5099@users.noreply.github.com> --- internal/context/prompt_test.go | 6 ++++++ internal/context/source_todos.go | 4 ++-- internal/context/source_todos_test.go | 8 +++++++- internal/promptasset/templates/core/tool_usage.md | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/internal/context/prompt_test.go b/internal/context/prompt_test.go index b442d67e..70517671 100644 --- a/internal/context/prompt_test.go +++ b/internal/context/prompt_test.go @@ -125,6 +125,12 @@ func TestDefaultToolUsagePromptIncludesPermissionAndAntiLoopGuidance(t *testing. if !strings.Contains(toolUsage, "`todo_write`") { t.Fatalf("expected Tool Usage to mention todo_write for task state, got %q", toolUsage) } + if !strings.Contains(toolUsage, "If the user clearly switches to a different task") { + t.Fatalf("expected Tool Usage to cover task switches, got %q", toolUsage) + } + if !strings.Contains(toolUsage, "otherwise mark it `canceled` before starting the new task") { + t.Fatalf("expected Tool Usage to explain canceled vs completed on task switches, got %q", toolUsage) + } if !strings.Contains(toolUsage, "Execute todos sequentially in the main loop") { t.Fatalf("expected Tool Usage to enforce sequential todo execution, got %q", toolUsage) } diff --git a/internal/context/source_todos.go b/internal/context/source_todos.go index 50f7f55c..5b900603 100644 --- a/internal/context/source_todos.go +++ b/internal/context/source_todos.go @@ -81,8 +81,8 @@ func (todosSource) Sections(ctx context.Context, input BuildInput) ([]promptSect } lines = append(lines, "", - "stale_todo_reminder: If any todo above is no longer relevant to the current task,", - "cancel it via todo_write set_status=canceled before signaling completion.", + "stale_todo_reminder: If the user clearly switches to a different task, do not carry old unfinished todos forward.", + "Mark each old todo completed only if the work is actually done; otherwise cancel it via todo_write before starting the new task.", ) return []promptSection{ diff --git a/internal/context/source_todos_test.go b/internal/context/source_todos_test.go index e467ea95..cc80a233 100644 --- a/internal/context/source_todos_test.go +++ b/internal/context/source_todos_test.go @@ -54,13 +54,19 @@ func TestTodosSourceSections(t *testing.T) { if sections[0].Title != "Todo State" { t.Fatalf("title = %q, want %q", sections[0].Title, "Todo State") } - if strings.Contains(sections[0].Content, "done") { + if strings.Contains(sections[0].Content, `id="done"`) { t.Fatalf("expected terminal todo filtered, got %q", sections[0].Content) } lines := strings.Split(sections[0].Content, "\n") if len(lines) < 2 || !strings.Contains(lines[0], "in-progress") { t.Fatalf("expected in_progress todo first, got %q", sections[0].Content) } + if !strings.Contains(sections[0].Content, "If the user clearly switches to a different task") { + t.Fatalf("expected task-switch reminder in english, got %q", sections[0].Content) + } + if !strings.Contains(sections[0].Content, "completed only if the work is actually done") { + t.Fatalf("expected completed-vs-canceled guidance, got %q", sections[0].Content) + } } func TestTodosSourceSectionsBoundaries(t *testing.T) { diff --git a/internal/promptasset/templates/core/tool_usage.md b/internal/promptasset/templates/core/tool_usage.md index e80cf99f..88d7349e 100644 --- a/internal/promptasset/templates/core/tool_usage.md +++ b/internal/promptasset/templates/core/tool_usage.md @@ -29,6 +29,7 @@ - `todo_write` `set_status` requires: `{"action":"set_status","id":"","status":"pending|in_progress|blocked|completed|failed|canceled"}`. - `todo_write` `update` requires: `{"action":"update","id":"","patch":{...}}`; include `expected_revision` when known to prevent concurrent overwrite. - Mark todos `completed` only after the relevant artifact or verification exists. +- If the user clearly switches to a different task, do not carry old unfinished todos forward. Mark each old todo `completed` only if the work is actually done; otherwise mark it `canceled` before starting the new task. - Mark todos `blocked` with a concrete reason when waiting on permission, user input, external resources, or an internal dependency. - Execute todos sequentially in the main loop unless the user explicitly asks for another strategy. - `spawn_subagent` only supports `mode=inline`: the subagent runs now and returns structured output in the same turn.