@@ -559,6 +559,45 @@ ${JSON.stringify(schema)}
559559 return trimmed ;
560560 }
561561
562+ /**
563+ * Repair truncated JSON by closing unterminated strings and missing braces.
564+ * Handles cases where LLM output was cut off mid-string (e.g. long HTML content).
565+ */
566+ private repairTruncatedJson ( content : string ) : string {
567+ if ( ! content ) return content ;
568+
569+ let repaired = content ;
570+
571+ // Count unescaped double quotes to detect unterminated strings
572+ let inString = false ;
573+ for ( let i = 0 ; i < repaired . length ; i ++ ) {
574+ if ( repaired [ i ] === '\\' && inString ) {
575+ i ++ ; // skip escaped character
576+ continue ;
577+ }
578+ if ( repaired [ i ] === '"' ) {
579+ inString = ! inString ;
580+ }
581+ }
582+
583+ // Close unterminated string
584+ if ( inString ) {
585+ repaired += '"' ;
586+ this . logger . debug ( 'Closed unterminated string in truncated JSON' ) ;
587+ }
588+
589+ // Close missing braces
590+ const openBraces = ( repaired . match ( / \{ / g) || [ ] ) . length ;
591+ const closeBraces = ( repaired . match ( / \} / g) || [ ] ) . length ;
592+ const missingBraces = openBraces - closeBraces ;
593+ if ( missingBraces > 0 ) {
594+ repaired += '}' . repeat ( missingBraces ) ;
595+ this . logger . debug ( `Added ${ missingBraces } closing braces to complete JSON` ) ;
596+ }
597+
598+ return repaired ;
599+ }
600+
562601 /**
563602 * Complete a tool call when closing tag is found
564603 */
@@ -618,18 +657,8 @@ ${JSON.stringify(schema)}
618657 // Add closing brace if it seems like valid JSON that was truncated
619658 let toolCallContent = this . extractCleanJsonContent ( extendedState . currentToolCallBuffer ) ;
620659
621- // Attempt to repair incomplete JSON
622- if ( toolCallContent && ! toolCallContent . endsWith ( '}' ) ) {
623- // Simple heuristic: if it looks like JSON and has opening braces, try to close them
624- const openBraces = ( toolCallContent . match ( / \{ / g) || [ ] ) . length ;
625- const closeBraces = ( toolCallContent . match ( / \} / g) || [ ] ) . length ;
626- const missingBraces = openBraces - closeBraces ;
627-
628- if ( missingBraces > 0 ) {
629- toolCallContent += '}' . repeat ( missingBraces ) ;
630- this . logger . debug ( `Added ${ missingBraces } closing braces to complete JSON` ) ;
631- }
632- }
660+ // Attempt to repair incomplete JSON (unterminated strings + missing braces)
661+ toolCallContent = this . repairTruncatedJson ( toolCallContent ) ;
633662
634663 const toolCallData = JSON . parse ( toolCallContent ) ;
635664
0 commit comments