@@ -455,6 +455,25 @@ For file fields, use placeholder images for demo data: "placeholder.jpg" (square
455455 return tools
456456}
457457
458+ // Extract code from failed tool calls (when model writes tool call as text instead of using API)
459+ function extract_failed_tool_call ( text : string ) : string | null {
460+ // Pattern 1: write_code({ code: "..." }) or write_code({ code: `...` })
461+ const fn_match = text . match ( / w r i t e _ c o d e \s * \( \s * \{ \s * c o d e : \s * [ ` " ' ] ( [ \s \S ] + ?) [ ` " ' ] \s * \} \s * \) / )
462+ if ( fn_match ) return fn_match [ 1 ]
463+
464+ // Pattern 2: JSON-style { "name": "write_code", ... "code": "..." }
465+ const json_match = text . match ( / " n a m e " : \s * " w r i t e _ c o d e " [ \s \S ] * ?" c o d e " : \s * [ ` " ' ] ( [ \s \S ] + ?) [ ` " ' ] / )
466+ if ( json_match ) return json_match [ 1 ]
467+
468+ // Pattern 3: ```svelte block after mentioning write_code
469+ if ( text . includes ( 'write_code' ) ) {
470+ const svelte_match = text . match ( / ` ` ` s v e l t e \n ( [ \s \S ] + ?) ` ` ` / )
471+ if ( svelte_match && svelte_match [ 1 ] . length > 100 ) return svelte_match [ 1 ]
472+ }
473+
474+ return null
475+ }
476+
458477export async function run_agent (
459478 config : AgentConfig ,
460479 project_id : string ,
@@ -516,6 +535,7 @@ export async function run_agent(
516535 // Stream both text and tool calls using fullStream
517536 let full_text = ''
518537 const seen_tool_calls = new Set < string > ( )
538+ let had_write_code_call = false
519539
520540 for await ( const part of result . fullStream ) {
521541 if ( part . type === 'text-delta' ) {
@@ -529,6 +549,7 @@ export async function run_agent(
529549 const toolCallId = ( part as any ) . toolCallId
530550 if ( toolCallId && seen_tool_calls . has ( toolCallId ) ) continue
531551 if ( toolCallId ) seen_tool_calls . add ( toolCallId )
552+ if ( part . toolName === 'write_code' ) had_write_code_call = true
532553 callbacks ?. onToolCall ?.( toolCallId , part . toolName , ( part as any ) . input || { } )
533554 } else if ( part . type === 'tool-result' ) {
534555 // AI SDK 5.x uses 'output' property for tool results
@@ -548,6 +569,17 @@ export async function run_agent(
548569 }
549570 }
550571
572+ // Fallback: if model wrote code as text instead of calling write_code tool, extract and apply it
573+ if ( ! had_write_code_call ) {
574+ const missed_code = extract_failed_tool_call ( full_text )
575+ if ( missed_code ) {
576+ console . log ( '[Agent] Detected failed write_code call in text, auto-applying code' )
577+ await updateProject ( project_id , { frontend_code : missed_code } )
578+ callbacks ?. onToolCall ?.( 'auto-extract' , 'write_code' , { code : '[extracted from response]' } )
579+ callbacks ?. onToolResult ?.( 'auto-extract' , 'write_code' , 'Auto-applied code from response' )
580+ }
581+ }
582+
551583 const usage = await result . usage
552584
553585 return {
0 commit comments