@@ -433,7 +433,10 @@ export class LLMStream extends llm.LLMStream {
433433 if ( this . toolCallId && tool . id && tool . index !== this . toolIndex ) {
434434 callChunk = this . createRunningToolCallChunk ( id , delta ) ;
435435 this . toolCallId = this . fncName = this . fncRawArguments = undefined ;
436- this . toolExtra = undefined ;
436+ // Note: We intentionally do NOT reset toolExtra here.
437+ // For Gemini 3+, the thought_signature is only provided on the first tool call
438+ // in a parallel batch, but must be applied to ALL tool calls in the batch.
439+ // We preserve toolExtra so subsequent tool calls inherit the thought_signature.
437440 }
438441
439442 // Start or continue building the current tool call
@@ -443,9 +446,14 @@ export class LLMStream extends llm.LLMStream {
443446 this . fncName = tool . function . name ;
444447 this . fncRawArguments = tool . function . arguments || '' ;
445448 // Extract extra from tool call (e.g., Google thought signatures)
446- this . toolExtra =
449+ // Only update toolExtra if this tool call has extra_content.
450+ // Otherwise, inherit from previous tool call (for parallel Gemini tool calls).
451+ const newToolExtra =
447452 // eslint-disable-next-line @typescript-eslint/no-explicit-any
448453 ( ( tool as any ) . extra_content as Record < string , unknown > | undefined ) ?? undefined ;
454+ if ( newToolExtra ) {
455+ this . toolExtra = newToolExtra ;
456+ }
449457 } else if ( tool . function . arguments ) {
450458 this . fncRawArguments = ( this . fncRawArguments || '' ) + tool . function . arguments ;
451459 }
@@ -464,6 +472,7 @@ export class LLMStream extends llm.LLMStream {
464472 ) {
465473 const callChunk = this . createRunningToolCallChunk ( id , delta ) ;
466474 this . toolCallId = this . fncName = this . fncRawArguments = undefined ;
475+ // Reset toolExtra at the end of the response (not between parallel tool calls)
467476 this . toolExtra = undefined ;
468477 return callChunk ;
469478 }
0 commit comments