Skip to content

Commit 8acdf74

Browse files
committed
New write_todos tool!
1 parent d8a9679 commit 8acdf74

File tree

10 files changed

+149
-2
lines changed

10 files changed

+149
-2
lines changed

.agents/types/tools.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export type ToolName =
2020
| 'think_deeply'
2121
| 'web_search'
2222
| 'write_file'
23+
| 'write_todos'
2324

2425
/**
2526
* Map of tool names to their parameter types
@@ -43,6 +44,7 @@ export interface ToolParamsMap {
4344
think_deeply: ThinkDeeplyParams
4445
web_search: WebSearchParams
4546
write_file: WriteFileParams
47+
write_todos: WriteTodosParams
4648
}
4749

4850
/**
@@ -59,7 +61,7 @@ export interface AddMessageParams {
5961
export interface CodeSearchParams {
6062
/** The pattern to search for. */
6163
pattern: string
62-
/** Optional ripgrep flags to customize the search (e.g., "-i" for case-insensitive, "-t ts -t js" for TypeScript and JavaScript files only, "-A 3" for 3 lines after match, "-B 2" for 2 lines before match, "--type-not py" to exclude Python files). */
64+
/** Optional ripgrep flags to customize the search (e.g., "-i" for case-insensitive, "-g *.ts -g *.js" for TypeScript and JavaScript files only, "-g !*.test.ts" to exclude Typescript test files, "-A 3" for 3 lines after match, "-B 2" for 2 lines before match, --no-ignore to include files in ignored by .gitignore). */
6365
flags?: string
6466
/** Optional working directory to search within, relative to the project root. Defaults to searching the entire project. */
6567
cwd?: string
@@ -221,6 +223,19 @@ export interface WriteFileParams {
221223
content: string
222224
}
223225

226+
/**
227+
* Write a todo list to track tasks. Use this frequently to maintain a step-by-step plan.
228+
*/
229+
export interface WriteTodosParams {
230+
/** List of todos with their completion status */
231+
todos: {
232+
/** Description of the task */
233+
task: string
234+
/** Whether the task is completed */
235+
completed: boolean
236+
}[]
237+
}
238+
224239
/**
225240
* Get parameters type for a specific tool
226241
*/

common/src/templates/initial-agents-dir/types/tools.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export type ToolName =
2020
| 'think_deeply'
2121
| 'web_search'
2222
| 'write_file'
23+
| 'write_todos'
2324

2425
/**
2526
* Map of tool names to their parameter types
@@ -43,6 +44,7 @@ export interface ToolParamsMap {
4344
think_deeply: ThinkDeeplyParams
4445
web_search: WebSearchParams
4546
write_file: WriteFileParams
47+
write_todos: WriteTodosParams
4648
}
4749

4850
/**
@@ -59,7 +61,7 @@ export interface AddMessageParams {
5961
export interface CodeSearchParams {
6062
/** The pattern to search for. */
6163
pattern: string
62-
/** Optional ripgrep flags to customize the search (e.g., "-i" for case-insensitive, "-t ts -t js" for TypeScript and JavaScript files only, "-A 3" for 3 lines after match, "-B 2" for 2 lines before match, "--type-not py" to exclude Python files). */
64+
/** Optional ripgrep flags to customize the search (e.g., "-i" for case-insensitive, "-g *.ts -g *.js" for TypeScript and JavaScript files only, "-g !*.test.ts" to exclude Typescript test files, "-A 3" for 3 lines after match, "-B 2" for 2 lines before match, --no-ignore to include files in ignored by .gitignore). */
6365
flags?: string
6466
/** Optional working directory to search within, relative to the project root. Defaults to searching the entire project. */
6567
cwd?: string
@@ -221,6 +223,19 @@ export interface WriteFileParams {
221223
content: string
222224
}
223225

226+
/**
227+
* Write a todo list to track tasks. Use this frequently to maintain a step-by-step plan.
228+
*/
229+
export interface WriteTodosParams {
230+
/** List of todos with their completion status */
231+
todos: {
232+
/** Description of the task */
233+
task: string
234+
/** Whether the task is completed */
235+
completed: boolean
236+
}[]
237+
}
238+
224239
/**
225240
* Get parameters type for a specific tool
226241
*/

common/src/tools/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const toolNames = [
4141
'update_subgoal',
4242
'web_search',
4343
'write_file',
44+
'write_todos',
4445
] as const
4546

4647
export const publishedTools = [
@@ -62,6 +63,7 @@ export const publishedTools = [
6263
'think_deeply',
6364
'web_search',
6465
'write_file',
66+
'write_todos',
6567
// 'spawn_agent_inline',
6668
] as const
6769

common/src/tools/list.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { thinkDeeplyParams } from './params/tool/think-deeply'
2424
import { updateSubgoalParams } from './params/tool/update-subgoal'
2525
import { webSearchParams } from './params/tool/web-search'
2626
import { writeFileParams } from './params/tool/write-file'
27+
import { writeTodosParams } from './params/tool/write-todos'
2728

2829
import type {
2930
$ToolParams,
@@ -61,6 +62,7 @@ export const $toolParams = {
6162
update_subgoal: updateSubgoalParams,
6263
web_search: webSearchParams,
6364
write_file: writeFileParams,
65+
write_todos: writeTodosParams,
6466
} satisfies {
6567
[K in ToolName]: $ToolParams<K>
6668
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import z from 'zod/v4'
2+
3+
import type { $ToolParams } from '../../constants'
4+
5+
const toolName = 'write_todos'
6+
const endsAgentStep = false
7+
export const writeTodosParams = {
8+
toolName,
9+
endsAgentStep,
10+
parameters: z
11+
.object({
12+
todos: z
13+
.array(
14+
z.object({
15+
task: z.string().describe('Description of the task'),
16+
completed: z.boolean().describe('Whether the task is completed'),
17+
}),
18+
)
19+
.describe(
20+
'List of todos with their completion status. Try to order the todos the same way you will complete them. Do not mark todos as completed if you have not completed them yet!',
21+
),
22+
})
23+
.describe(
24+
'Write a todo list to track tasks. Use this frequently to maintain a step-by-step plan.',
25+
),
26+
outputs: z.tuple([
27+
z.object({
28+
type: z.literal('json'),
29+
value: z.object({
30+
todos: z.array(z.object({ task: z.string(), completed: z.boolean() })),
31+
}),
32+
}),
33+
]),
34+
} satisfies $ToolParams

npm-app/src/utils/tool-renderers.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,4 +347,27 @@ export const toolRenderers: Record<ToolName, ToolCallRenderer> = {
347347
lookup_agent_info: {
348348
...defaultToolCallRenderer,
349349
},
350+
write_todos: {
351+
...defaultToolCallRenderer,
352+
onParamChunk: (content, paramName, toolName) => {
353+
// Don't render chunks for todos array, wait for the full list
354+
return null
355+
},
356+
onParamEnd: (paramName, toolName, content) => {
357+
if (paramName !== 'todos') {
358+
return null
359+
}
360+
let todos: Array<{ task: string; completed: boolean }> = []
361+
try {
362+
todos = JSON.parse(content)
363+
} catch (e) {
364+
return null
365+
}
366+
// Format as checkbox list
367+
const formattedTodos = todos
368+
.map((todo) => `${todo.completed ? '[x]' : '[]'} ${todo.task}`)
369+
.join('\n')
370+
return gray(formattedTodos)
371+
},
372+
},
350373
}

packages/agent-runtime/src/tools/definitions/list.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { thinkDeeplyTool } from './tool/think-deeply'
2323
import { updateSubgoalTool } from './tool/update-subgoal'
2424
import { webSearchTool } from './tool/web-search'
2525
import { writeFileTool } from './tool/write-file'
26+
import { writeTodosTool } from './tool/write-todos'
2627

2728
import type { ToolDescription } from './tool-def-type'
2829
import type { ToolName } from '@codebuff/common/tools/constants'
@@ -52,6 +53,7 @@ const toolDescriptions = {
5253
update_subgoal: updateSubgoalTool,
5354
web_search: webSearchTool,
5455
write_file: writeFileTool,
56+
write_todos: writeTodosTool,
5557
} satisfies {
5658
[K in ToolName]: ToolDescription<K>
5759
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { getToolCallString } from '@codebuff/common/tools/utils'
2+
3+
import type { ToolDescription } from '../tool-def-type'
4+
5+
const toolName = 'write_todos'
6+
export const writeTodosTool = {
7+
toolName,
8+
description: `
9+
Use this tool to track your objectives through an ordered step-by-step plan. Call this tool after you have gathered context on the user's request to plan out the implementation steps for the user's request.
10+
11+
After completing each todo step, call this tool again to update the list and mark that task as completed. Note that each time you call this tool, rewrite ALL todos with their current status.
12+
13+
Use this tool frequently as you work through tasks to update the list of todos with their current status. Doing this is extremely useful because it helps you stay on track and complete all the requirements of the user's request. It also helps inform the user of your plans and the current progress, which they want to know at all times.
14+
15+
Example:
16+
${getToolCallString(toolName, {
17+
todos: [
18+
{ task: 'Create new implementation in foo.ts', completed: true },
19+
{ task: 'Update bar.ts to use the new implementation', completed: false },
20+
{ task: 'Write tests for the new implementation', completed: false },
21+
{
22+
task: 'Run the tests to verify the new implementation',
23+
completed: false,
24+
},
25+
],
26+
})}
27+
`.trim(),
28+
} satisfies ToolDescription

packages/agent-runtime/src/tools/handlers/list.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { handleThinkDeeply } from './tool/think-deeply'
2121
import { handleUpdateSubgoal } from './tool/update-subgoal'
2222
import { handleWebSearch } from './tool/web-search'
2323
import { handleWriteFile } from './tool/write-file'
24+
import { handleWriteTodos } from './tool/write-todos'
2425

2526
import type { CodebuffToolHandlerFunction } from './handler-function-type'
2627
import type { ToolName } from '@codebuff/common/tools/constants'
@@ -58,6 +59,7 @@ export const codebuffToolHandlers = {
5859
update_subgoal: handleUpdateSubgoal,
5960
web_search: handleWebSearch,
6061
write_file: handleWriteFile,
62+
write_todos: handleWriteTodos,
6163
} satisfies {
6264
[K in ToolName]: CodebuffToolHandlerFunction<K>
6365
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { CodebuffToolHandlerFunction } from '../handler-function-type'
2+
3+
type ToolName = 'write_todos'
4+
export const handleWriteTodos: CodebuffToolHandlerFunction<ToolName> = (
5+
params,
6+
) => {
7+
const { previousToolCallFinished, toolCall } = params
8+
const { todos } = toolCall.input
9+
10+
return {
11+
result: (async () => {
12+
await previousToolCallFinished
13+
return [
14+
{
15+
type: 'json',
16+
value: {
17+
todos,
18+
},
19+
},
20+
]
21+
})(),
22+
state: {},
23+
}
24+
}

0 commit comments

Comments
 (0)