@@ -2473,12 +2473,14 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
24732473 // Finalize the streaming tool call
24742474 const finalToolUse = NativeToolCallParser . finalizeStreamingToolCall ( event . id )
24752475
2476+ // Get the index for this tool call
2477+ const toolUseIndex = this . streamingToolCallIndices . get ( event . id )
2478+
24762479 if ( finalToolUse ) {
24772480 // Store the tool call ID
24782481 ; ( finalToolUse as any ) . id = event . id
24792482
24802483 // Get the index and replace partial with final
2481- const toolUseIndex = this . streamingToolCallIndices . get ( event . id )
24822484 if ( toolUseIndex !== undefined ) {
24832485 this . assistantMessageContent [ toolUseIndex ] = finalToolUse
24842486 }
@@ -2491,6 +2493,25 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
24912493
24922494 // Present the finalized tool call
24932495 presentAssistantMessage ( this )
2496+ } else if ( toolUseIndex !== undefined ) {
2497+ // finalizeStreamingToolCall returned null (malformed JSON or missing args)
2498+ // We still need to mark the tool as non-partial so it gets executed
2499+ // The tool's validation will catch any missing required parameters
2500+ const existingToolUse = this . assistantMessageContent [ toolUseIndex ]
2501+ if ( existingToolUse && existingToolUse . type === "tool_use" ) {
2502+ existingToolUse . partial = false
2503+ // Ensure it has the ID for native protocol
2504+ ; ( existingToolUse as any ) . id = event . id
2505+ }
2506+
2507+ // Clean up tracking
2508+ this . streamingToolCallIndices . delete ( event . id )
2509+
2510+ // Mark that we have new content to process
2511+ this . userMessageContentReady = false
2512+
2513+ // Present the tool call - validation will handle missing params
2514+ presentAssistantMessage ( this )
24942515 }
24952516 }
24962517 }
@@ -2611,12 +2632,14 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
26112632 // Finalize the streaming tool call
26122633 const finalToolUse = NativeToolCallParser . finalizeStreamingToolCall ( event . id )
26132634
2635+ // Get the index for this tool call
2636+ const toolUseIndex = this . streamingToolCallIndices . get ( event . id )
2637+
26142638 if ( finalToolUse ) {
26152639 // Store the tool call ID
26162640 ; ( finalToolUse as any ) . id = event . id
26172641
26182642 // Get the index and replace partial with final
2619- const toolUseIndex = this . streamingToolCallIndices . get ( event . id )
26202643 if ( toolUseIndex !== undefined ) {
26212644 this . assistantMessageContent [ toolUseIndex ] = finalToolUse
26222645 }
@@ -2629,6 +2652,25 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
26292652
26302653 // Present the finalized tool call
26312654 presentAssistantMessage ( this )
2655+ } else if ( toolUseIndex !== undefined ) {
2656+ // finalizeStreamingToolCall returned null (malformed JSON or missing args)
2657+ // We still need to mark the tool as non-partial so it gets executed
2658+ // The tool's validation will catch any missing required parameters
2659+ const existingToolUse = this . assistantMessageContent [ toolUseIndex ]
2660+ if ( existingToolUse && existingToolUse . type === "tool_use" ) {
2661+ existingToolUse . partial = false
2662+ // Ensure it has the ID for native protocol
2663+ ; ( existingToolUse as any ) . id = event . id
2664+ }
2665+
2666+ // Clean up tracking
2667+ this . streamingToolCallIndices . delete ( event . id )
2668+
2669+ // Mark that we have new content to process
2670+ this . userMessageContentReady = false
2671+
2672+ // Present the tool call - validation will handle missing params
2673+ presentAssistantMessage ( this )
26322674 }
26332675 }
26342676 }
@@ -2898,9 +2940,11 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
28982940 this . assistantMessageContent = parsedBlocks
28992941 }
29002942
2901- // Only present partial blocks that were just completed (from XML parsing)
2902- // Native tool blocks were already presented during streaming, so don't re-present them
2903- if ( partialBlocks . length > 0 && partialBlocks . some ( ( block ) => block . type !== "tool_use" ) ) {
2943+ // Present any partial blocks that were just completed
2944+ // For XML protocol: includes both text and tool_use blocks parsed from the text stream
2945+ // For native protocol: tool_use blocks were already presented during streaming via
2946+ // tool_call_partial events, but we still need to present them if they exist (e.g., malformed)
2947+ if ( partialBlocks . length > 0 ) {
29042948 // If there is content to update then it will complete and
29052949 // update `this.userMessageContentReady` to true, which we
29062950 // `pWaitFor` before making the next request.
0 commit comments