@@ -2169,7 +2169,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
21692169 break
21702170 } else {
21712171 const modelInfo = this . api . getModel ( ) . info
2172- const state = await this . providerRef . deref ( ) ?. getState ( )
21732172 const toolProtocol = resolveToolProtocol ( this . apiConfiguration , modelInfo )
21742173 nextUserContent = [ { type : "text" , text : formatResponse . noToolsUsed ( toolProtocol ) } ]
21752174 this . consecutiveMistakeCount ++
@@ -2960,11 +2959,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
29602959 // Apply exponential backoff similar to first-chunk errors when auto-resubmit is enabled
29612960 const stateForBackoff = await this . providerRef . deref ( ) ?. getState ( )
29622961 if ( stateForBackoff ?. autoApprovalEnabled ) {
2963- await this . backoffAndAnnounce (
2964- currentItem . retryAttempt ?? 0 ,
2965- error ,
2966- streamingFailedMessage ,
2967- )
2962+ await this . backoffAndAnnounce ( currentItem . retryAttempt ?? 0 , error )
29682963
29692964 // Check if task was aborted during the backoff
29702965 if ( this . abort ) {
@@ -3066,10 +3061,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
30663061 // Need to save assistant responses to file before proceeding to
30673062 // tool use since user can exit at any moment and we wouldn't be
30683063 // able to save the assistant's response.
3069- let didEndLoop = false
30703064
30713065 // Check if we have any content to process (text or tool uses)
30723066 const hasTextContent = assistantMessage . length > 0
3067+
30733068 const hasToolUses = this . assistantMessageContent . some (
30743069 ( block ) => block . type === "tool_use" || block . type === "mcp_tool_use" ,
30753070 )
@@ -3139,10 +3134,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
31393134 }
31403135
31413136 await this . addToApiConversationHistory (
3142- {
3143- role : "assistant" ,
3144- content : assistantContent ,
3145- } ,
3137+ { role : "assistant" , content : assistantContent } ,
31463138 reasoningMessage || undefined ,
31473139 )
31483140
@@ -3191,7 +3183,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
31913183 // Add periodic yielding to prevent blocking
31923184 await new Promise ( ( resolve ) => setImmediate ( resolve ) )
31933185 }
3194- // Continue to next iteration instead of setting didEndLoop from recursive call
3186+
31953187 continue
31963188 } else {
31973189 // If there's no assistant_responses, that means we got no text
@@ -3218,13 +3210,11 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
32183210 // Reuse the state variable from above
32193211 if ( state ?. autoApprovalEnabled ) {
32203212 // Auto-retry with backoff - don't persist failure message when retrying
3221- const errorMsg =
3222- "Unexpected API Response: The language model did not provide any assistant messages. This may indicate an issue with the API or the model's output."
3223-
32243213 await this . backoffAndAnnounce (
32253214 currentItem . retryAttempt ?? 0 ,
3226- new Error ( "Empty assistant response" ) ,
3227- errorMsg ,
3215+ new Error (
3216+ "Unexpected API Response: The language model did not provide any assistant messages. This may indicate an issue with the API or the model's output." ,
3217+ ) ,
32283218 )
32293219
32303220 // Check if task was aborted during the backoff
@@ -3811,18 +3801,8 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
38113801
38123802 // note that this api_req_failed ask is unique in that we only present this option if the api hasn't streamed any content yet (ie it fails on the first chunk due), as it would allow them to hit a retry button. However if the api failed mid-stream, it could be in any arbitrary state where some tools may have executed, so that error is handled differently and requires cancelling the task entirely.
38133803 if ( autoApprovalEnabled ) {
3814- let errorMsg
3815-
3816- if ( error . error ?. metadata ?. raw ) {
3817- errorMsg = JSON . stringify ( error . error . metadata . raw , null , 2 )
3818- } else if ( error . message ) {
3819- errorMsg = error . message
3820- } else {
3821- errorMsg = "Unknown error"
3822- }
3823-
38243804 // Apply shared exponential backoff and countdown UX
3825- await this . backoffAndAnnounce ( retryAttempt , error , errorMsg )
3805+ await this . backoffAndAnnounce ( retryAttempt , error )
38263806
38273807 // CRITICAL: Check if task was aborted during the backoff countdown
38283808 // This prevents infinite loops when users cancel during auto-retry
@@ -3870,7 +3850,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
38703850 }
38713851
38723852 // Shared exponential backoff for retries (first-chunk and mid-stream)
3873- private async backoffAndAnnounce ( retryAttempt : number , error : any , header ?: string ) : Promise < void > {
3853+ private async backoffAndAnnounce ( retryAttempt : number , error : any ) : Promise < void > {
38743854 try {
38753855 const state = await this . providerRef . deref ( ) ?. getState ( )
38763856 const baseDelay = state ?. requestDelaySeconds || 5
@@ -3900,7 +3880,9 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
39003880 }
39013881
39023882 const finalDelay = Math . max ( exponentialDelay , rateLimitDelay )
3903- if ( finalDelay <= 0 ) return
3883+ if ( finalDelay <= 0 ) {
3884+ return
3885+ }
39043886
39053887 // Build header text; fall back to error message if none provided
39063888 let headerText
0 commit comments