refactor(coding-agent/tools): wrapped todo_write parameters in an ops object

- Changed the todo-write parameter schema from a bare operations array to an object containing an `ops` array.
- Updated request parsing and renderer logic to consume `params.ops` and `args.ops` when processing todo operations.
- Updated session and unit tests to invoke todo_write with wrapped `{ ops: [...] }` payloads.
This commit is contained in:
can1357
2026-04-26 05:11:59 +02:00
parent 5d6f8a7951
commit 652f49442f
5 changed files with 178 additions and 141 deletions
@@ -1,20 +1,22 @@
Manages a phased task list through an ordered list of flat operations.
Manages a phased task list through an `ops` array of flat operations.
The next pending task is auto-promoted to `in_progress` after completing the current one.
<protocol>
## Shape
Pass an array of operation objects:
Pass an object with an `ops` array:
```ts
[
{ op: "replace", phases: [...] },
{ op: "start", task: "task-3" },
{ op: "done", phase: "Implementation" },
{ op: "rm" },
{ op: "drop", task: "task-9" },
{ op: "append", phase: "Implementation", items: [{ id: "task-10", label: "Run tests" }] }
]
{
ops: [
{ op: "replace", phases: [...] },
{ op: "start", task: "task-3" },
{ op: "done", phase: "Implementation" },
{ op: "rm" },
{ op: "drop", task: "task-9" },
{ op: "append", phase: "Implementation", items: [{ id: "task-10", label: "Run tests" }] },
],
}
```
## Operation fields
@@ -58,17 +60,17 @@ Create a todo list when:
<examples>
# Initial setup
`[{op: "replace", phases: [{name: "Investigation", tasks: [{content: "Read source"}, {content: "Map callsites"}]}, {name: "Implementation", tasks: [{content: "Apply fix"}, {content: "Run tests"}]}]}]`
`{"ops":[{"op":"replace","phases":[{"name":"Investigation","tasks":[{"content":"Read source"},{"content":"Map callsites"}]},{"name":"Implementation","tasks":[{"content":"Apply fix"},{"content":"Run tests"}]}]}]}`
# Complete one task
`[{op: "done", task: "task-2"}]`
`{"ops":[{"op":"done","task":"task-2"}]}`
# Complete a whole phase
`[{op: "done", phase: "Implementation"}]`
`{"ops":[{"op":"done","phase":"Implementation"}]}`
# Remove all tasks
`[{op: "rm"}]`
`{"ops":[{"op":"rm"}]}`
# Drop one task
`[{op: "drop", task: "task-7"}]`
`{"ops":[{"op":"drop","task":"task-7"}]}`
# Append tasks to a phase
`[{op: "append", phase: "Implementation", items: [{id: "task-8", label: "Handle retries"}, {id: "task-9", label: "Run tests"}]}]`
`{"ops":[{"op":"append","phase":"Implementation","items":[{"id":"task-8","label":"Handle retries"},{"id":"task-9","label":"Run tests"}]}]}`
</examples>
<avoid>
+20 -13
View File
@@ -73,13 +73,18 @@ const TodoOpEntry = Type.Object({
items: Type.Optional(Type.Array(AppendItem, { minItems: 1, description: "items to append for op=append" })),
});
const todoWriteSchema = Type.Array(TodoOpEntry, {
minItems: 1,
description: "ordered todo operations",
});
const todoWriteSchema = Type.Object(
{
ops: Type.Array(TodoOpEntry, {
minItems: 1,
description: "ordered todo operations",
}),
},
{ description: "Apply ordered todo operations" },
);
type TodoWriteParams = Static<typeof todoWriteSchema>;
type TodoOpEntryValue = TodoWriteParams[number];
type TodoOpEntryValue = TodoWriteParams["ops"][number];
// =============================================================================
// File format
@@ -332,7 +337,7 @@ function applyEntry(file: TodoFile, entry: TodoOpEntryValue, errors: string[]):
function applyParams(file: TodoFile, params: TodoWriteParams): { file: TodoFile; errors: string[] } {
const errors: string[] = [];
for (const entry of params) {
for (const entry of params.ops) {
file = applyEntry(file, entry, errors);
}
normalizeInProgressTask(file.phases);
@@ -428,12 +433,14 @@ export class TodoWriteTool implements AgentTool<typeof todoWriteSchema, TodoWrit
// TUI Renderer
// =============================================================================
type TodoWriteRenderArgs = Array<{
op?: string;
task?: string;
phase?: string;
items?: Array<{ id?: string; label?: string }>;
}>;
type TodoWriteRenderArgs = {
ops?: Array<{
op?: string;
task?: string;
phase?: string;
items?: Array<{ id?: string; label?: string }>;
}>;
};
function formatTodoLine(item: TodoItem, uiTheme: Theme, prefix: string): string {
const checkbox = uiTheme.checkbox;
@@ -451,7 +458,7 @@ function formatTodoLine(item: TodoItem, uiTheme: Theme, prefix: string): string
export const todoWriteToolRenderer = {
renderCall(args: TodoWriteRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
const ops = args?.map(entry => {
const ops = args?.ops?.map(entry => {
const parts = [entry.op ?? "update"];
if (entry.task) parts.push(entry.task);
if (entry.phase) parts.push(entry.phase);