Skip to content

Commit 7645aad

Browse files
qdaxbmrubens
andauthored
add todo tool (#5182)
Co-authored-by: Matt Rubens <[email protected]>
1 parent 6ec017c commit 7645aad

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2367
-4
lines changed

packages/types/src/global-settings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export const globalSettingsSchema = z.object({
4747
alwaysAllowExecute: z.boolean().optional(),
4848
alwaysAllowFollowupQuestions: z.boolean().optional(),
4949
followupAutoApproveTimeoutMs: z.number().optional(),
50+
alwaysAllowUpdateTodoList: z.boolean().optional(),
5051
allowedCommands: z.array(z.string()).optional(),
5152
allowedMaxRequests: z.number().nullish(),
5253
autoCondenseContext: z.boolean().optional(),
@@ -195,6 +196,7 @@ export const EVALS_SETTINGS: RooCodeSettings = {
195196
alwaysAllowSubtasks: true,
196197
alwaysAllowExecute: true,
197198
alwaysAllowFollowupQuestions: true,
199+
alwaysAllowUpdateTodoList: true,
198200
followupAutoApproveTimeoutMs: 0,
199201
allowedCommands: ["*"],
200202

packages/types/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ export * from "./terminal.js"
2020
export * from "./tool.js"
2121
export * from "./type-fu.js"
2222
export * from "./vscode.js"
23+
export * from "./todo.js"

packages/types/src/message.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export const clineSays = [
106106
"condense_context",
107107
"condense_context_error",
108108
"codebase_search_result",
109+
"user_edit_todos",
109110
] as const
110111

111112
export const clineSaySchema = z.enum(clineSays)

packages/types/src/todo.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { z } from "zod"
2+
3+
/**
4+
* TodoStatus
5+
*/
6+
export const todoStatusSchema = z.enum(["pending", "in_progress", "completed"] as const)
7+
8+
export type TodoStatus = z.infer<typeof todoStatusSchema>
9+
10+
/**
11+
* TodoItem
12+
*/
13+
export const todoItemSchema = z.object({
14+
id: z.string(),
15+
content: z.string(),
16+
status: todoStatusSchema,
17+
})
18+
19+
export type TodoItem = z.infer<typeof todoItemSchema>

packages/types/src/tool.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const toolNames = [
3333
"new_task",
3434
"fetch_instructions",
3535
"codebase_search",
36+
"update_todo_list",
3637
] as const
3738

3839
export const toolNamesSchema = z.enum(toolNames)

src/core/assistant-message/presentAssistantMessage.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { attemptCompletionTool } from "../tools/attemptCompletionTool"
2626
import { newTaskTool } from "../tools/newTaskTool"
2727

2828
import { checkpointSave } from "../checkpoints"
29+
import { updateTodoListTool } from "../tools/updateTodoListTool"
2930

3031
import { formatResponse } from "../prompts/responses"
3132
import { validateToolUse } from "../tools/validateToolUse"
@@ -205,6 +206,8 @@ export async function presentAssistantMessage(cline: Task) {
205206
return `[${block.name} to '${block.params.mode_slug}'${block.params.reason ? ` because: ${block.params.reason}` : ""}]`
206207
case "codebase_search": // Add case for the new tool
207208
return `[${block.name} for '${block.params.query}']`
209+
case "update_todo_list":
210+
return `[${block.name}]`
208211
case "new_task": {
209212
const mode = block.params.mode ?? defaultModeSlug
210213
const message = block.params.message ?? "(no message)"
@@ -410,6 +413,9 @@ export async function presentAssistantMessage(cline: Task) {
410413
case "write_to_file":
411414
await writeToFileTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
412415
break
416+
case "update_todo_list":
417+
await updateTodoListTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
418+
break
413419
case "apply_diff": {
414420
// Get the provider and state to check experiment settings
415421
const provider = cline.providerRef.deref()

src/core/environment/getEnvironmentDetails.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { arePathsEqual } from "../../utils/path"
1818
import { formatResponse } from "../prompts/responses"
1919

2020
import { Task } from "../task/Task"
21+
import { formatReminderSection } from "./reminder"
2122

2223
export async function getEnvironmentDetails(cline: Task, includeFileDetails: boolean = false) {
2324
let details = ""
@@ -273,5 +274,6 @@ export async function getEnvironmentDetails(cline: Task, includeFileDetails: boo
273274
}
274275
}
275276

276-
return `<environment_details>\n${details.trim()}\n</environment_details>`
277+
const reminderSection = formatReminderSection(cline.todoList)
278+
return `<environment_details>\n${details.trim()}\n${reminderSection}\n</environment_details>`
277279
}

src/core/environment/reminder.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { TodoItem, TodoStatus } from "@roo-code/types"
2+
3+
/**
4+
* Format the reminders section as a markdown block in English, with basic instructions.
5+
*/
6+
export function formatReminderSection(todoList?: TodoItem[]): string {
7+
if (!todoList || todoList.length === 0) {
8+
return ""
9+
}
10+
const statusMap: Record<TodoStatus, string> = {
11+
pending: "Pending",
12+
in_progress: "In Progress",
13+
completed: "Completed",
14+
}
15+
const lines: string[] = [
16+
"====",
17+
"",
18+
"REMINDERS",
19+
"",
20+
"Below is your current list of reminders for this task. Keep them updated as you progress.",
21+
"",
22+
]
23+
24+
lines.push("| # | Content | Status |")
25+
lines.push("|---|---------|--------|")
26+
todoList.forEach((item, idx) => {
27+
const escapedContent = item.content.replace(/\\/g, "\\\\").replace(/\|/g, "\\|")
28+
lines.push(`| ${idx + 1} | ${escapedContent} | ${statusMap[item.status] || item.status} |`)
29+
})
30+
lines.push("")
31+
32+
lines.push(
33+
"",
34+
"IMPORTANT: When task status changes, remember to call the `update_todo_list` tool to update your progress.",
35+
"",
36+
)
37+
return lines.join("\n")
38+
}

src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,76 @@ Example:
368368
</new_task>
369369

370370

371+
## update_todo_list
372+
373+
**Description:**
374+
Replace the entire TODO list with an updated checklist reflecting the current state. Always provide the full list; the system will overwrite the previous one. This tool is designed for step-by-step task tracking, allowing you to confirm completion of each step before updating, update multiple task statuses at once (e.g., mark one as completed and start the next), and dynamically add new todos discovered during long or complex tasks.
375+
376+
**Checklist Format:**
377+
- Use a single-level markdown checklist (no nesting or subtasks).
378+
- List todos in the intended execution order.
379+
- Status options:
380+
- [ ] Task description (pending)
381+
- [x] Task description (completed)
382+
- [-] Task description (in progress)
383+
384+
**Status Rules:**
385+
- [ ] = pending (not started)
386+
- [x] = completed (fully finished, no unresolved issues)
387+
- [-] = in_progress (currently being worked on)
388+
389+
**Core Principles:**
390+
- Before updating, always confirm which todos have been completed since the last update.
391+
- You may update multiple statuses in a single update (e.g., mark the previous as completed and the next as in progress).
392+
- When a new actionable item is discovered during a long or complex task, add it to the todo list immediately.
393+
- Do not remove any unfinished todos unless explicitly instructed.
394+
- Always retain all unfinished tasks, updating their status as needed.
395+
- Only mark a task as completed when it is fully accomplished (no partials, no unresolved dependencies).
396+
- If a task is blocked, keep it as in_progress and add a new todo describing what needs to be resolved.
397+
- Remove tasks only if they are no longer relevant or if the user requests deletion.
398+
399+
**Usage Example:**
400+
<update_todo_list>
401+
<todos>
402+
[x] Analyze requirements
403+
[x] Design architecture
404+
[-] Implement core logic
405+
[ ] Write tests
406+
[ ] Update documentation
407+
</todos>
408+
</update_todo_list>
409+
410+
*After completing "Implement core logic" and starting "Write tests":*
411+
<update_todo_list>
412+
<todos>
413+
[x] Analyze requirements
414+
[x] Design architecture
415+
[x] Implement core logic
416+
[-] Write tests
417+
[ ] Update documentation
418+
[ ] Add performance benchmarks
419+
</todos>
420+
</update_todo_list>
421+
422+
**When to Use:**
423+
- The task involves multiple steps or requires ongoing tracking.
424+
- You need to update the status of several todos at once.
425+
- New actionable items are discovered during task execution.
426+
- The user requests a todo list or provides multiple tasks.
427+
- The task is complex and benefits from clear, stepwise progress tracking.
428+
429+
**When NOT to Use:**
430+
- There is only a single, trivial task.
431+
- The task can be completed in one or two simple steps.
432+
- The request is purely conversational or informational.
433+
434+
**Task Management Guidelines:**
435+
- Mark task as completed immediately after all work of the current task is done.
436+
- Start the next task by marking it as in_progress.
437+
- Add new todos as soon as they are identified.
438+
- Use clear, descriptive task names.
439+
440+
371441
# Tool Use Guidelines
372442

373443
1. In <thinking> tags, assess what information you already have and what information you need to proceed with the task.

src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,76 @@ Example:
265265
</new_task>
266266

267267

268+
## update_todo_list
269+
270+
**Description:**
271+
Replace the entire TODO list with an updated checklist reflecting the current state. Always provide the full list; the system will overwrite the previous one. This tool is designed for step-by-step task tracking, allowing you to confirm completion of each step before updating, update multiple task statuses at once (e.g., mark one as completed and start the next), and dynamically add new todos discovered during long or complex tasks.
272+
273+
**Checklist Format:**
274+
- Use a single-level markdown checklist (no nesting or subtasks).
275+
- List todos in the intended execution order.
276+
- Status options:
277+
- [ ] Task description (pending)
278+
- [x] Task description (completed)
279+
- [-] Task description (in progress)
280+
281+
**Status Rules:**
282+
- [ ] = pending (not started)
283+
- [x] = completed (fully finished, no unresolved issues)
284+
- [-] = in_progress (currently being worked on)
285+
286+
**Core Principles:**
287+
- Before updating, always confirm which todos have been completed since the last update.
288+
- You may update multiple statuses in a single update (e.g., mark the previous as completed and the next as in progress).
289+
- When a new actionable item is discovered during a long or complex task, add it to the todo list immediately.
290+
- Do not remove any unfinished todos unless explicitly instructed.
291+
- Always retain all unfinished tasks, updating their status as needed.
292+
- Only mark a task as completed when it is fully accomplished (no partials, no unresolved dependencies).
293+
- If a task is blocked, keep it as in_progress and add a new todo describing what needs to be resolved.
294+
- Remove tasks only if they are no longer relevant or if the user requests deletion.
295+
296+
**Usage Example:**
297+
<update_todo_list>
298+
<todos>
299+
[x] Analyze requirements
300+
[x] Design architecture
301+
[-] Implement core logic
302+
[ ] Write tests
303+
[ ] Update documentation
304+
</todos>
305+
</update_todo_list>
306+
307+
*After completing "Implement core logic" and starting "Write tests":*
308+
<update_todo_list>
309+
<todos>
310+
[x] Analyze requirements
311+
[x] Design architecture
312+
[x] Implement core logic
313+
[-] Write tests
314+
[ ] Update documentation
315+
[ ] Add performance benchmarks
316+
</todos>
317+
</update_todo_list>
318+
319+
**When to Use:**
320+
- The task involves multiple steps or requires ongoing tracking.
321+
- You need to update the status of several todos at once.
322+
- New actionable items are discovered during task execution.
323+
- The user requests a todo list or provides multiple tasks.
324+
- The task is complex and benefits from clear, stepwise progress tracking.
325+
326+
**When NOT to Use:**
327+
- There is only a single, trivial task.
328+
- The task can be completed in one or two simple steps.
329+
- The request is purely conversational or informational.
330+
331+
**Task Management Guidelines:**
332+
- Mark task as completed immediately after all work of the current task is done.
333+
- Start the next task by marking it as in_progress.
334+
- Add new todos as soon as they are identified.
335+
- Use clear, descriptive task names.
336+
337+
268338
# Tool Use Guidelines
269339

270340
1. In <thinking> tags, assess what information you already have and what information you need to proceed with the task.

0 commit comments

Comments
 (0)