11import * as vscode from "vscode"
22
3- import { RooCodeEventName } from "@roo-code/types"
3+ import { RooCodeEventName , type HistoryItem } from "@roo-code/types"
44import { TelemetryService } from "@roo-code/telemetry"
55
66import { Task } from "../task/Task"
@@ -19,6 +19,18 @@ export interface AttemptCompletionCallbacks extends ToolCallbacks {
1919 toolDescription : ( ) => string
2020}
2121
22+ /**
23+ * Interface for provider methods needed by AttemptCompletionTool for delegation handling.
24+ */
25+ interface DelegationProvider {
26+ getTaskWithId ( id : string ) : Promise < { historyItem : HistoryItem } >
27+ reopenParentFromDelegation ( params : {
28+ parentTaskId : string
29+ childTaskId : string
30+ completionResultSummary : string
31+ } ) : Promise < void >
32+ }
33+
2234export class AttemptCompletionTool extends BaseTool < "attempt_completion" > {
2335 readonly name = "attempt_completion" as const
2436
@@ -70,51 +82,36 @@ export class AttemptCompletionTool extends BaseTool<"attempt_completion"> {
7082 if ( task . parentTaskId ) {
7183 // Check if this subtask has already completed and returned to parent
7284 // to prevent duplicate tool_results when user revisits from history
73- const provider = task . providerRef . deref ( )
85+ const provider = task . providerRef . deref ( ) as DelegationProvider | undefined
7486 if ( provider ) {
7587 try {
76- const { historyItem } = await ( provider as any ) . getTaskWithId ( task . taskId )
88+ const { historyItem } = await provider . getTaskWithId ( task . taskId )
7789 if ( historyItem ?. status === "completed" ) {
7890 // Subtask already completed - skip delegation flow entirely
7991 // Fall through to normal completion ask flow below (outside this if block)
8092 // This shows the user the completion result and waits for acceptance
8193 // without injecting another tool_result to the parent
8294 } else {
8395 // Normal subtask completion - do delegation
84- const didApprove = await askFinishSubTaskApproval ( )
85-
86- if ( ! didApprove ) {
87- pushToolResult ( formatResponse . toolDenied ( ) )
88- return
89- }
90-
91- pushToolResult ( "" )
92-
93- // Use the new metadata-driven delegation flow
94- await ( provider as any ) . reopenParentFromDelegation ( {
95- parentTaskId : task . parentTaskId ,
96- childTaskId : task . taskId ,
97- completionResultSummary : result ,
98- } )
99- return
96+ const delegated = await this . delegateToParent (
97+ task ,
98+ result ,
99+ provider ,
100+ askFinishSubTaskApproval ,
101+ pushToolResult ,
102+ )
103+ if ( delegated ) return
100104 }
101105 } catch {
102106 // If we can't get the history, proceed with normal delegation flow
103- const didApprove = await askFinishSubTaskApproval ( )
104-
105- if ( ! didApprove ) {
106- pushToolResult ( formatResponse . toolDenied ( ) )
107- return
108- }
109-
110- pushToolResult ( "" )
111-
112- await ( provider as any ) . reopenParentFromDelegation ( {
113- parentTaskId : task . parentTaskId ,
114- childTaskId : task . taskId ,
115- completionResultSummary : result ,
116- } )
117- return
107+ const delegated = await this . delegateToParent (
108+ task ,
109+ result ,
110+ provider ,
111+ askFinishSubTaskApproval ,
112+ pushToolResult ,
113+ )
114+ if ( delegated ) return
118115 }
119116 }
120117 }
@@ -135,6 +132,35 @@ export class AttemptCompletionTool extends BaseTool<"attempt_completion"> {
135132 }
136133 }
137134
135+ /**
136+ * Handles the common delegation flow when a subtask completes.
137+ * Returns true if delegation was performed and the caller should return early.
138+ */
139+ private async delegateToParent (
140+ task : Task ,
141+ result : string ,
142+ provider : DelegationProvider ,
143+ askFinishSubTaskApproval : ( ) => Promise < boolean > ,
144+ pushToolResult : ( result : string ) => void ,
145+ ) : Promise < boolean > {
146+ const didApprove = await askFinishSubTaskApproval ( )
147+
148+ if ( ! didApprove ) {
149+ pushToolResult ( formatResponse . toolDenied ( ) )
150+ return true
151+ }
152+
153+ pushToolResult ( "" )
154+
155+ await provider . reopenParentFromDelegation ( {
156+ parentTaskId : task . parentTaskId ! ,
157+ childTaskId : task . taskId ,
158+ completionResultSummary : result ,
159+ } )
160+
161+ return true
162+ }
163+
138164 override async handlePartial ( task : Task , block : ToolUse < "attempt_completion" > ) : Promise < void > {
139165 const result : string | undefined = block . params . result
140166 const command : string | undefined = block . params . command
0 commit comments