diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index e2d2a303eb..4f04d72397 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -2129,6 +2129,13 @@ export class Task extends EventEmitter implements TaskLike { block.type === "tool_use" && block.name === "attempt_completion", ) + // Only treat as pending completion if there are no other unanswered + // tool_use blocks — otherwise the rewind path is more appropriate. + if (toolUse) { + const hasOtherToolUse = content.some((block) => block.type === "tool_use" && block !== toolUse) + if (hasOtherToolUse) return undefined + } + return toolUse?.id } diff --git a/src/core/task/__tests__/rewind-integration.spec.ts b/src/core/task/__tests__/rewind-integration.spec.ts index d09848f287..6d447461c9 100644 --- a/src/core/task/__tests__/rewind-integration.spec.ts +++ b/src/core/task/__tests__/rewind-integration.spec.ts @@ -456,13 +456,15 @@ describe("rewind-integration", () => { expect(parsedContent.status).toBe("completed") }) - it("attempt_completion alongside another tool_use in same assistant message", () => { + it("attempt_completion alongside another tool_use in same assistant message returns undefined", () => { const task = createTask(mockProvider) const now = Date.now() // Edge case: assistant message contains both a read_file tool_use and // an attempt_completion tool_use. getPendingAttemptCompletionToolUseId - // should still detect the attempt_completion. + // should return undefined so the rewind path is used instead — + // the other tool_uses never executed, so treating it as a pending + // completion would bypass the rewind and produce misleading context. task.apiConversationHistory = [ { role: "user", @@ -491,6 +493,6 @@ describe("rewind-integration", () => { ] as any[] const pendingId: string | undefined = (task as any).getPendingAttemptCompletionToolUseId() - expect(pendingId).toBe("toolu_completion_888") + expect(pendingId).toBeUndefined() }) })