diff --git a/packages/core/src/core/__snapshots__/prompts.test.ts.snap b/packages/core/src/core/__snapshots__/prompts.test.ts.snap index 3ecd1ca596f..37387b5b46e 100644 --- a/packages/core/src/core/__snapshots__/prompts.test.ts.snap +++ b/packages/core/src/core/__snapshots__/prompts.test.ts.snap @@ -23,7 +23,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -219,7 +219,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -431,7 +431,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -622,7 +622,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -813,7 +813,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -1004,7 +1004,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -1195,7 +1195,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -1386,7 +1386,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -1577,7 +1577,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -1768,7 +1768,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -1982,7 +1982,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -2262,7 +2262,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -2476,7 +2476,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -2752,7 +2752,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -2943,7 +2943,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. @@ -3134,7 +3134,7 @@ You have access to the todo_write tool to keep user-visible progress for work th When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. diff --git a/packages/core/src/core/prompts.test.ts b/packages/core/src/core/prompts.test.ts index 33e120dc3ac..72f3e4e3043 100644 --- a/packages/core/src/core/prompts.test.ts +++ b/packages/core/src/core/prompts.test.ts @@ -168,6 +168,12 @@ describe('Core System Prompt (prompts.ts)', () => { expect(prompt).toContain( 'rather than one item per error, file, command, or minor edit', ); + expect(prompt).toContain( + 'When an active Todo plan covers work delegated through top-level Agent calls', + ); + expect(prompt).not.toContain( + 'For complex work delegated through top-level Agent calls, create the relevant todo first', + ); expect(prompt).not.toContain('VERY frequently'); expect(prompt).not.toContain('EXTREMELY helpful'); expect(prompt).not.toContain('write 10 items to the todo list'); diff --git a/packages/core/src/core/prompts.ts b/packages/core/src/core/prompts.ts index c039abf5f46..46c626ae6dd 100644 --- a/packages/core/src/core/prompts.ts +++ b/packages/core/src/core/prompts.ts @@ -317,7 +317,7 @@ You have access to the ${ToolNames.TODO_WRITE} tool to keep user-visible progres When you create a todo list: - Keep it short and outcome-oriented. Use a few meaningful, logically ordered, verifiable steps rather than one item per error, file, command, or minor edit. -- For complex work delegated through top-level Agent calls, create the relevant todo first and pass its ID as \`todo_id\` so the execution can be associated with the plan node. +- When an active Todo plan covers work delegated through top-level Agent calls, pass the matching Todo ID as \`todo_id\` so the execution can be associated with that plan node. Do not create a Todo solely to wrap a delegation that does not otherwise need task tracking. - Keep at most one item in_progress. Keep the list current, mark finished work completed, and revise it when the scope or approach changes. When work completes together, update multiple statuses in one tool call rather than making bookkeeping-only calls. - Do not repeat the full todo list in prose after calling the tool; briefly communicate only important context or the next step. diff --git a/packages/core/src/tools/todoWrite.test.ts b/packages/core/src/tools/todoWrite.test.ts index 0359de14594..bc3ab1bdb49 100644 --- a/packages/core/src/tools/todoWrite.test.ts +++ b/packages/core/src/tools/todoWrite.test.ts @@ -327,7 +327,7 @@ describe('TodoWriteTool', () => { const result = await tool .build({ - todos: [{ id: '1', content: 'Still done', status: 'completed' }], + todos: [{ id: '1', content: 'Done', status: 'completed' }], }) .execute(mockAbortSignal); @@ -348,7 +348,28 @@ describe('TodoWriteTool', () => { mockAtomicWrite.mockResolvedValue(undefined); const result = await tool - .build({ todos: [{ id: '2', content: 'New', status: 'pending' }] }) + .build({ todos: [{ id: '1', content: 'New', status: 'pending' }] }) + .execute(mockAbortSignal); + const display = result.returnDisplay as { planId?: string }; + + expect(display.planId).toEqual(expect.any(String)); + expect(display.planId).not.toBe('finished-plan'); + }); + + it('should start a new plan for a distinct all-completed snapshot', async () => { + mockFs.readFile.mockResolvedValue( + JSON.stringify({ + planId: 'finished-plan', + todos: [{ id: '1', content: 'Done', status: 'completed' }], + }), + ); + mockFs.mkdir.mockResolvedValue(undefined); + mockAtomicWrite.mockResolvedValue(undefined); + + const result = await tool + .build({ + todos: [{ id: '1', content: 'Already done', status: 'completed' }], + }) .execute(mockAbortSignal); const display = result.returnDisplay as { planId?: string }; diff --git a/packages/core/src/tools/todoWrite.ts b/packages/core/src/tools/todoWrite.ts index 931433e36bf..72f09baa1c7 100644 --- a/packages/core/src/tools/todoWrite.ts +++ b/packages/core/src/tools/todoWrite.ts @@ -8,6 +8,7 @@ import type { ToolResult } from './tools.js'; import { BaseDeclarativeTool, BaseToolInvocation, Kind } from './tools.js'; import type { FunctionDeclaration } from '@google/genai'; import { randomUUID } from 'node:crypto'; +import { isDeepStrictEqual } from 'node:util'; import * as fs from 'fs/promises'; import * as fsSync from 'fs'; import * as path from 'path'; @@ -370,7 +371,7 @@ class TodoWriteToolInvocation extends BaseToolInvocation< finalTodos.length > 0 && (oldTodos.length === 0 || (oldTodos.every((todo) => todo.status === 'completed') && - finalTodos.some((todo) => todo.status !== 'completed'))); + !isDeepStrictEqual(finalTodos, oldTodos))); const activePlanId = finalTodos.length === 0 ? undefined diff --git a/packages/web-shell/client/components/messages/PlanExecutionView.test.tsx b/packages/web-shell/client/components/messages/PlanExecutionView.test.tsx index 1fbc2862483..f546e4c22b1 100644 --- a/packages/web-shell/client/components/messages/PlanExecutionView.test.tsx +++ b/packages/web-shell/client/components/messages/PlanExecutionView.test.tsx @@ -135,6 +135,20 @@ describe('PlanExecutionView', () => { }); }); + it('does not block a todo on an unknown dependency', () => { + const todo: TodoItem = { + id: 'standalone', + content: 'Standalone', + status: 'pending', + blockedBy: ['missing'], + }; + + expect(getPlanNodeState(todo, new Map([[todo.id, todo]]), [], [])).toEqual({ + status: 'ready', + attention: false, + }); + }); + it('restores cancellation from replay output after the live task leaves', () => { const cancelled = { ...agentTool('build'), diff --git a/packages/web-shell/client/components/messages/PlanExecutionView.tsx b/packages/web-shell/client/components/messages/PlanExecutionView.tsx index 220d8029156..922c5e9f936 100644 --- a/packages/web-shell/client/components/messages/PlanExecutionView.tsx +++ b/packages/web-shell/client/components/messages/PlanExecutionView.tsx @@ -228,7 +228,7 @@ function getPlanNodeStateFromIndex( return { status: 'paused', attention }; if (todo.status === 'completed') return { status: 'completed', attention }; const blocked = (todo.blockedBy ?? []).some( - (id) => todosById.get(id)?.status !== 'completed', + (id) => todosById.has(id) && todosById.get(id)?.status !== 'completed', ); if (blocked) return { status: 'blocked', attention }; if (todo.status === 'in_progress')