fix: preserve discoverable goal todos
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<todo_context>
|
||||
Current persisted todo state for this goal follows. Goal continuations do not get a visible user nudge, so treat this as live progress state, not old transcript decoration.
|
||||
Before continuing substantial work, compare your next action with these todos. If an item is stale, already finished, or no longer the active pointer, call the `todo` tool first to mark it done or rewrite the list. Do not leave a stale in_progress item while working on later phases.
|
||||
{{#if canCallTodoTool}}Before continuing substantial work, compare your next action with these todos. If an item is stale, already finished, or no longer the active pointer, call the `todo` tool first to mark it done or rewrite the list. Do not leave a stale in_progress item while working on later phases.{{else}}Before continuing substantial work, compare your next action with these todos as read-only progress state. The `todo` tool is discoverable but not active in this turn; if the list needs edits, activate `todo` first instead of ignoring the persisted state.{{/if}}
|
||||
|
||||
Overall: {{closed}}/{{total}} done, {{open}} open.
|
||||
{{#each phases}}
|
||||
|
||||
@@ -6512,7 +6512,11 @@ export class AgentSession {
|
||||
|
||||
#buildGoalTodoContext(): string | undefined {
|
||||
if (!this.settings.get("todo.enabled")) return undefined;
|
||||
if (!this.getActiveToolNames().includes("todo")) return undefined;
|
||||
const activeToolNames = this.getActiveToolNames();
|
||||
const canCallTodoTool = activeToolNames.includes("todo");
|
||||
const canDiscoverTodoTool =
|
||||
!canCallTodoTool && this.getDiscoverableTools({ source: "builtin" }).some(tool => tool.name === "todo");
|
||||
if (!canCallTodoTool && !canDiscoverTodoTool) return undefined;
|
||||
const phases = this.getTodoPhases().filter(phase => phase.tasks.length > 0);
|
||||
if (phases.length === 0) return undefined;
|
||||
|
||||
@@ -6533,6 +6537,7 @@ export class AgentSession {
|
||||
}));
|
||||
|
||||
return prompt.render(goalTodoContextPrompt, {
|
||||
canCallTodoTool,
|
||||
closed: String(closed),
|
||||
open: String(open),
|
||||
phases: promptPhases,
|
||||
|
||||
@@ -302,6 +302,31 @@ describe("InteractiveMode goal mode integration", () => {
|
||||
expect(content.match(/<\/todo_context>/g)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("includes read-only todo state when todo is discoverable but inactive", async () => {
|
||||
harness.settings.set("tools.discoveryMode", "all");
|
||||
await harness.mode.handleGoalModeCommand("Ship the release");
|
||||
harness.session.setTodoPhases([
|
||||
{
|
||||
name: "Verification",
|
||||
tasks: [{ content: "Run focused checks", status: "pending" }],
|
||||
},
|
||||
]);
|
||||
expect(harness.session.getActiveToolNames()).not.toContain("todo");
|
||||
expect(harness.session.getDiscoverableTools({ source: "builtin" }).some(tool => tool.name === "todo")).toBe(true);
|
||||
const sendCustomMessage = vi.spyOn(harness.session, "sendCustomMessage").mockResolvedValue(false);
|
||||
|
||||
await harness.session.sendGoalModeContext({ deliverAs: "steer" });
|
||||
|
||||
const message = sendCustomMessage.mock.calls[0]?.[0];
|
||||
const content = typeof message?.content === "string" ? message.content : "";
|
||||
expect(message?.customType).toBe("goal-mode-context");
|
||||
expect(content).toContain("<todo_context>");
|
||||
expect(content).toContain("Run focused checks");
|
||||
expect(content).toContain("read-only progress state");
|
||||
expect(content).toContain("discoverable but not active");
|
||||
expect(content).not.toContain("call the `todo` tool first");
|
||||
});
|
||||
|
||||
it("omits persisted todo state when todo tool is inactive", async () => {
|
||||
await harness.mode.handleGoalModeCommand("Ship the release");
|
||||
harness.session.setTodoPhases([
|
||||
|
||||
Reference in New Issue
Block a user