Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions internal/context/prompt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/context/source_todos.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
8 changes: 7 additions & 1 deletion internal/context/source_todos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions internal/promptasset/templates/core/tool_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
- `todo_write` `set_status` requires: `{"action":"set_status","id":"<todo_id>","status":"pending|in_progress|blocked|completed|failed|canceled"}`.
- `todo_write` `update` requires: `{"action":"update","id":"<todo_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.
Expand Down
Loading