checks all todos are done before responding

This commit is contained in:
Arjun 2025-11-18 10:08:04 +05:30
parent cb26602a02
commit fda8c4c024
3 changed files with 26 additions and 1 deletions

View file

@ -22,6 +22,7 @@ Always consult this catalog first so you load the right skills before taking act
## Task tracking
- Maintain a durable todo list for multi-step efforts using the \`todoList\`, \`todoWrite\`, and \`todoUpdate\` builtin tools (state persists only within this copilot session).
- Before delivering your final response, verify every todo is marked \`done\` or \`blocked\`—use \`todoUpdate\` to reflect progress or issues.
- Treat the <system-reminder> text returned by those tools as internal guidancenever echo these reminders to the user verbatim.
## Execution reminders

View file

@ -13,6 +13,7 @@ import { LlmStepStreamEvent } from "../entities/llm-step-events.js";
import { execTool } from "./exec-tool.js";
import { RunEvent } from "../entities/run-events.js";
import { BuiltinTools } from "./builtin-tools.js";
import { readTodoState, pushTodoState, popTodoState } from "./todo-store.js";
import { collectSystemReminders } from "../assistant/reminders/manager.js";
export async function mapAgentTool(t: z.infer<typeof ToolAttachment>): Promise<Tool> {
@ -237,6 +238,8 @@ export async function* streamAgentTurn(opts: {
messages: z.infer<typeof MessageList>;
}): AsyncGenerator<z.infer<typeof RunEvent>, void, unknown> {
const { agent, messages } = opts;
pushTodoState();
try {
// set up tools
const tools: ToolSet = {};
@ -350,9 +353,21 @@ export async function* streamAgentTurn(opts: {
continue;
}
const completionReminder = await outstandingTodosReminder();
if (completionReminder) {
messages.push({
role: "system",
content: completionReminder,
});
continue;
}
// otherwise, break
return;
}
} finally {
popTodoState();
}
}
async function* streamLlm(
@ -444,6 +459,15 @@ function attachRemindersToResult(result: any, reminders: string[]) {
systemReminders: reminders,
};
}
async function outstandingTodosReminder(): Promise<string | null> {
const state = await readTodoState();
const remaining = state.todos.filter(todo => todo.status !== "done" && todo.status !== "blocked");
if (remaining.length === 0) {
return null;
}
return `<system-reminder>\nBefore concluding, finish every todo via the todo tools or mark it as blocked if an issue prevents completion. Outstanding items: ${JSON.stringify(remaining)}\n</system-reminder>`;
}
export const MappedToolCall = z.object({
toolCall: ToolCallPart,
agentTool: ToolAttachment,

View file

@ -275,7 +275,7 @@ export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
},
todoList: {
description: 'Return the durable todo list for the current session',
description: 'Return the todo list for the current copilot session',
inputSchema: z.object({}),
execute: async () => {
const state = await readTodoState();