@@ -766,7 +766,7 @@ export class Cline {
766766 async * attemptApiRequest ( previousApiReqIndex : number ) : ApiStream {
767767 let mcpHub : McpHub | undefined
768768
769- const { mcpEnabled } = await this . providerRef . deref ( ) ?. getState ( ) ?? { }
769+ const { mcpEnabled, alwaysApproveResubmit , requestDelaySeconds } = await this . providerRef . deref ( ) ?. getState ( ) ?? { }
770770
771771 if ( mcpEnabled ?? true ) {
772772 mcpHub = this . providerRef . deref ( ) ?. mcpHub
@@ -799,8 +799,30 @@ export class Cline {
799799 }
800800 }
801801
802- // Convert to Anthropic.MessageParam by spreading only the API-required properties
803- const cleanConversationHistory = this . apiConversationHistory . map ( ( { role, content } ) => ( { role, content } ) )
802+ // Clean conversation history by:
803+ // 1. Converting to Anthropic.MessageParam by spreading only the API-required properties
804+ // 2. Converting image blocks to text descriptions if model doesn't support images
805+ const cleanConversationHistory = this . apiConversationHistory . map ( ( { role, content } ) => {
806+ // Handle array content (could contain image blocks)
807+ if ( Array . isArray ( content ) ) {
808+ if ( ! this . api . getModel ( ) . info . supportsImages ) {
809+ // Convert image blocks to text descriptions
810+ content = content . map ( block => {
811+ if ( block . type === 'image' ) {
812+ // Convert image blocks to text descriptions
813+ // Note: We can't access the actual image content/url due to API limitations,
814+ // but we can indicate that an image was present in the conversation
815+ return {
816+ type : 'text' ,
817+ text : '[Referenced image in conversation]'
818+ } ;
819+ }
820+ return block ;
821+ } ) ;
822+ }
823+ }
824+ return { role, content }
825+ } )
804826 const stream = this . api . createMessage ( systemPrompt , cleanConversationHistory )
805827 const iterator = stream [ Symbol . asyncIterator ] ( )
806828
@@ -810,18 +832,33 @@ export class Cline {
810832 yield firstChunk . value
811833 } catch ( error ) {
812834 // 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.
813- const { response } = await this . ask (
814- "api_req_failed" ,
815- error . message ?? JSON . stringify ( serializeError ( error ) , null , 2 ) ,
816- )
817- if ( response !== "yesButtonClicked" ) {
818- // this will never happen since if noButtonClicked, we will clear current task, aborting this instance
819- throw new Error ( "API request failed" )
835+ if ( alwaysApproveResubmit ) {
836+ const requestDelay = requestDelaySeconds || 5
837+ // Automatically retry with delay
838+ await this . say (
839+ "error" ,
840+ `${ error . message ?? "Unknown error" } ↺ Retrying in ${ requestDelay } seconds...` ,
841+ )
842+ await this . say ( "api_req_retry_delayed" )
843+ await delay ( requestDelay * 1000 )
844+ await this . say ( "api_req_retried" )
845+ // delegate generator output from the recursive call
846+ yield * this . attemptApiRequest ( previousApiReqIndex )
847+ return
848+ } else {
849+ const { response } = await this . ask (
850+ "api_req_failed" ,
851+ error . message ?? JSON . stringify ( serializeError ( error ) , null , 2 ) ,
852+ )
853+ if ( response !== "yesButtonClicked" ) {
854+ // this will never happen since if noButtonClicked, we will clear current task, aborting this instance
855+ throw new Error ( "API request failed" )
856+ }
857+ await this . say ( "api_req_retried" )
858+ // delegate generator output from the recursive call
859+ yield * this . attemptApiRequest ( previousApiReqIndex )
860+ return
820861 }
821- await this . say ( "api_req_retried" )
822- // delegate generator output from the recursive call
823- yield * this . attemptApiRequest ( previousApiReqIndex )
824- return
825862 }
826863
827864 // no error, so we can continue to yield all remaining chunks
0 commit comments