diff --git a/src/core/tools/NewTaskTool.ts b/src/core/tools/NewTaskTool.ts index f36d8e1e37..bc95d9edb6 100644 --- a/src/core/tools/NewTaskTool.ts +++ b/src/core/tools/NewTaskTool.ts @@ -109,16 +109,23 @@ export class NewTaskTool extends BaseTool<"new_task"> { return } + // IMPORTANT: Push the tool_result BEFORE delegation, because delegateParentAndOpenChild + // disposes the parent task. If we push after, the tool_result is lost and + // flushPendingToolResultsToHistory will generate a placeholder "interrupted" tool_result, + // causing duplicate tool_results when the child completes (EXT-665). + // + // The child taskId isn't known yet, so we use a generic message. The actual completion + // result will be injected by reopenParentFromDelegation when the child completes. + pushToolResult(`Delegating to subtask...`) + // Delegate parent and open child as sole active task - const child = await (provider as any).delegateParentAndOpenChild({ + await (provider as any).delegateParentAndOpenChild({ parentTaskId: task.taskId, message: unescapedMessage, initialTodos: todoItems, mode, }) - // Reflect delegation in tool result (no pause/unpause, no wait) - pushToolResult(`Delegated to child task ${child.taskId}`) return } catch (error) { await handleError("creating new task", error) diff --git a/src/core/tools/__tests__/newTaskTool.spec.ts b/src/core/tools/__tests__/newTaskTool.spec.ts index fc383c13ee..5bce727391 100644 --- a/src/core/tools/__tests__/newTaskTool.spec.ts +++ b/src/core/tools/__tests__/newTaskTool.spec.ts @@ -175,7 +175,7 @@ describe("newTaskTool", () => { ) // Verify side effects - expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Delegated to child task")) + expect(mockPushToolResult).toHaveBeenCalledWith("Delegating to subtask...") }) it("should not un-escape single escaped \@", async () => { @@ -280,7 +280,7 @@ describe("newTaskTool", () => { expect(mockStartSubtask).toHaveBeenCalledWith("Test message", [], "code") // Should complete successfully - expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Delegated to child task")) + expect(mockPushToolResult).toHaveBeenCalledWith("Delegating to subtask...") }) it("should work with todos parameter when provided", async () => { @@ -311,7 +311,7 @@ describe("newTaskTool", () => { "code", ) - expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Delegated to child task")) + expect(mockPushToolResult).toHaveBeenCalledWith("Delegating to subtask...") }) it("should error when mode parameter is missing", async () => { @@ -423,7 +423,7 @@ describe("newTaskTool", () => { expect(mockStartSubtask).toHaveBeenCalledWith("Test message", [], "code") // Should complete successfully - expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Delegated to child task")) + expect(mockPushToolResult).toHaveBeenCalledWith("Delegating to subtask...") }) it("should REQUIRE todos when VSCode setting is enabled", async () => { @@ -501,7 +501,7 @@ describe("newTaskTool", () => { ) // Should complete successfully - expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Delegated to child task")) + expect(mockPushToolResult).toHaveBeenCalledWith("Delegating to subtask...") }) it("should work with empty todos string when VSCode setting is enabled", async () => { @@ -536,7 +536,7 @@ describe("newTaskTool", () => { expect(mockStartSubtask).toHaveBeenCalledWith("Test message", [], "code") // Should complete successfully - expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Delegated to child task")) + expect(mockPushToolResult).toHaveBeenCalledWith("Delegating to subtask...") }) it("should check VSCode setting with Package.name configuration key", async () => { @@ -671,7 +671,7 @@ describe("newTaskTool delegation flow", () => { ) expect(pauseEvents.length).toBe(0) - // Assert: tool result reflects delegation - expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Delegated to child task child-1")) + // Assert: tool result reflects delegation (pushed BEFORE delegation, so no child ID yet) + expect(mockPushToolResult).toHaveBeenCalledWith("Delegating to subtask...") }) })