refactor: rename plan to tasks and extract task entries from tool calls

This commit is contained in:
Mohamed Boudra
2026-02-02 22:09:17 +07:00
parent 303a82d1c7
commit 30f1682ca1
10 changed files with 201 additions and 41 deletions
@@ -66,7 +66,7 @@ describe("curateAgentActivity", () => {
expect(result).toBe("[ListFiles]");
});
test("serializes todo items as [Plan]", () => {
test("serializes todo items as [Tasks]", () => {
const timeline: AgentTimelineItem[] = [
{
type: "todo",
@@ -80,7 +80,7 @@ describe("curateAgentActivity", () => {
const result = curateAgentActivity(timeline);
expect(result).toContain("[Plan]");
expect(result).toContain("[Tasks]");
expect(result).toContain("- [x] Read the file");
expect(result).toContain("- [ ] Fix the bug");
expect(result).toContain("- [ ] Run tests");
@@ -137,7 +137,7 @@ export function curateAgentActivity(
}
case "todo":
flushBuffers(lines, buffers);
lines.push("[Plan]");
lines.push("[Tasks]");
for (const entry of item.items) {
const checkbox = entry.completed ? "[x]" : "[ ]";
lines.push(`- ${checkbox} ${entry.text}`);
@@ -865,15 +865,19 @@ async function startAgentMcpServer(): Promise<AgentMcpServerHandle> {
"Devise a plan to create a file named dummy.txt containing the word plan-test. After planning, proceed to execute your plan."
);
let sawPlan = false;
let capturedPlan: string | null = null;
for await (const event of events) {
await autoApprove(session, event);
if (
event.type === "timeline" &&
event.item.type === "todo" &&
event.item.items.some((entry) => entry.text.includes("dummy.txt"))
) {
sawPlan = true;
if (event.type === "permission_requested" && event.request.kind === "plan") {
const planFromMetadata =
typeof event.request.metadata?.planText === "string"
? event.request.metadata.planText
: null;
const planFromInput =
typeof (event.request.input as any)?.plan === "string"
? ((event.request.input as any)?.plan as string)
: null;
capturedPlan = planFromMetadata ?? planFromInput ?? capturedPlan;
}
if (event.type === "turn_completed" || event.type === "turn_failed") {
@@ -881,7 +885,8 @@ async function startAgentMcpServer(): Promise<AgentMcpServerHandle> {
}
}
expect(sawPlan).toBe(true);
expect(capturedPlan).not.toBeNull();
expect(capturedPlan?.includes("dummy.txt")).toBe(true);
expect(await session.getCurrentMode()).toBe("acceptEdits");
const filePath = path.join(cwd, "dummy.txt");
@@ -1159,10 +1159,6 @@ class ClaudeAgentSession implements AgentSession {
input,
options
): Promise<PermissionResult> => {
if (toolName === "ExitPlanMode") {
this.emitPlanTodoItems(input);
}
const requestId = `permission-${randomUUID()}`;
const metadata: AgentMetadata = {};
if (options.toolUseID) {
@@ -1234,19 +1230,6 @@ class ClaudeAgentSession implements AgentSession {
});
};
private emitPlanTodoItems(input: AgentMetadata) {
const planText = typeof input.plan === "string" ? input.plan : JSON.stringify(input);
const todoItems = planText
.split("\n")
.map((line) => line.trim())
.filter(Boolean)
.map((text) => ({ text, completed: false }));
this.enqueueTimeline({
type: "todo",
items: todoItems.length > 0 ? todoItems : [{ text: planText, completed: false }],
});
}
private enqueueTimeline(item: AgentTimelineItem) {
this.pushEvent({ type: "timeline", item, provider: "claude" });
}