(params: AttemptCompletionParams, task: Task, callbacks: AttemptCompletionCallbacks)
| 39 | readonly name = "attempt_completion" as const |
| 40 | |
| 41 | async execute(params: AttemptCompletionParams, task: Task, callbacks: AttemptCompletionCallbacks): Promise<void> { |
| 42 | const { result } = params |
| 43 | const { handleError, pushToolResult, askFinishSubTaskApproval } = callbacks |
| 44 | |
| 45 | // Prevent attempt_completion if any tool failed in the current turn |
| 46 | if (task.didToolFailInCurrentTurn) { |
| 47 | const errorMsg = t("common:errors.attempt_completion_tool_failed") |
| 48 | |
| 49 | await task.say("error", errorMsg) |
| 50 | pushToolResult(formatResponse.toolError(errorMsg)) |
| 51 | return |
| 52 | } |
| 53 | |
| 54 | const preventCompletionWithOpenTodos = vscode.workspace |
| 55 | .getConfiguration(Package.commandIDPrefix) |
| 56 | .get<boolean>("preventCompletionWithOpenTodos", false) |
| 57 | |
| 58 | const hasIncompleteTodos = task.todoList && task.todoList.some((todo) => todo.status !== "completed") |
| 59 | |
| 60 | if (preventCompletionWithOpenTodos && hasIncompleteTodos) { |
| 61 | task.consecutiveMistakeCount++ |
| 62 | task.recordToolError("attempt_completion") |
| 63 | |
| 64 | pushToolResult( |
| 65 | formatResponse.toolError( |
| 66 | "Cannot complete task while there are incomplete todos. Please finish all todos before attempting completion.", |
| 67 | ), |
| 68 | ) |
| 69 | |
| 70 | return |
| 71 | } |
| 72 | |
| 73 | try { |
| 74 | if (!result) { |
| 75 | task.consecutiveMistakeCount++ |
| 76 | task.recordToolError("attempt_completion") |
| 77 | pushToolResult(await task.sayAndCreateMissingParamError("attempt_completion", "result")) |
| 78 | return |
| 79 | } |
| 80 | |
| 81 | task.consecutiveMistakeCount = 0 |
| 82 | |
| 83 | await task.say("completion_result", result, undefined, false) |
| 84 | |
| 85 | // Check for subtask using parentTaskId (metadata-driven delegation) |
| 86 | if (task.parentTaskId) { |
| 87 | // Check if this subtask has already completed and returned to parent |
| 88 | // to prevent duplicate tool_results when user revisits from history |
| 89 | const provider = task.providerRef.deref() as DelegationProvider | undefined |
| 90 | if (provider) { |
| 91 | try { |
| 92 | const { historyItem } = await provider.getTaskWithId(task.taskId) |
| 93 | const status = historyItem?.status |
| 94 | |
| 95 | if (status === "completed") { |
| 96 | // Subtask already completed - skip delegation flow entirely |
| 97 | // Fall through to normal completion ask flow below (outside this if block) |
| 98 | // This shows the user the completion result and waits for acceptance |
nothing calls this directly
no test coverage detected