fix(coding-agent): reject task-N ID confusion, error on partial todo apply
- todo-write.md adds an explicit note that tasks are referenced by verbatim content text; the tool never emits task-N IDs. - resolveTaskOrError rejects ^task-\d+$ inputs with a clarifying error. - execute sets isError:true when any op failed. - appendItems short-circuits on the first "already exists" error so the call no longer applies the prefix of a doomed batch.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
**Tasks are referenced by their verbatim content string, not by any auto-generated ID. There is no "task-1"/"task-N" identifier — the tool never emits one. Pass the task's content text in the `task` field.**
|
||||
|
||||
Manages a phased task list. Pass `ops`: a flat array of operations.
|
||||
The next pending task is auto-promoted to `in_progress` after each completion.
|
||||
Allowed `op` values are only `init`, `start`, `done`, `drop`, `rm`, `append`, and `note`. `pending` is a task status, not an `op`; leave not-yet-started tasks implicit in `init`/`append` lists.
|
||||
|
||||
@@ -150,9 +150,15 @@ function resolveTaskOrError(
|
||||
}
|
||||
const hit = findTaskByContent(phases, content);
|
||||
if (!hit) {
|
||||
const totalTasks = phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
||||
const hint = totalTasks === 0 ? " (todo list is empty — was it replaced or not yet created?)" : "";
|
||||
errors.push(`Task "${content}" not found${hint}`);
|
||||
if (/^task-\d+$/.test(content)) {
|
||||
errors.push(
|
||||
`Task "${content}" not found. Tasks are referenced by content, not by IDs — pass the task's full text from the previous result.`,
|
||||
);
|
||||
} else {
|
||||
const totalTasks = phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
||||
const hint = totalTasks === 0 ? " (todo list is empty — was it replaced or not yet created?)" : "";
|
||||
errors.push(`Task "${content}" not found${hint}`);
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
@@ -209,7 +215,7 @@ function appendItems(phases: TodoPhase[], entry: TodoOpEntryValue, errors: strin
|
||||
for (const content of entry.items) {
|
||||
if (findTaskByContent(phases, content)) {
|
||||
errors.push(`Task "${content}" already exists`);
|
||||
continue;
|
||||
return phases;
|
||||
}
|
||||
phase.tasks.push({ content, status: "pending" });
|
||||
}
|
||||
@@ -513,6 +519,7 @@ export class TodoWriteTool implements AgentTool<typeof todoWriteSchema, TodoWrit
|
||||
return {
|
||||
content: [{ type: "text", text: formatSummary(updated, errors) }],
|
||||
details: { phases: updated, storage },
|
||||
isError: errors.length > 0 ? true : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user