@@ -213,29 +213,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
213213 }
214214 }
215215
216- if ( delta . tool_calls ) {
217- for ( const toolCall of delta . tool_calls ) {
218- if ( toolCall . id ) {
219- activeToolCallIds . add ( toolCall . id )
220- }
221- yield {
222- type : "tool_call_partial" ,
223- index : toolCall . index ,
224- id : toolCall . id ,
225- name : toolCall . function ?. name ,
226- arguments : toolCall . function ?. arguments ,
227- }
228- }
229- }
230-
231- // Emit tool_call_end events when finish_reason is "tool_calls"
232- // This ensures tool calls are finalized even if the stream doesn't properly close
233- if ( finishReason === "tool_calls" && activeToolCallIds . size > 0 ) {
234- for ( const id of activeToolCallIds ) {
235- yield { type : "tool_call_end" , id }
236- }
237- activeToolCallIds . clear ( )
238- }
216+ yield * this . processToolCalls ( delta , finishReason , activeToolCallIds )
239217
240218 if ( chunk . usage ) {
241219 lastUsage = chunk . usage
@@ -471,30 +449,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
471449 }
472450 }
473451
474- // Emit raw tool call chunks - NativeToolCallParser handles state management
475- if ( delta . tool_calls ) {
476- for ( const toolCall of delta . tool_calls ) {
477- if ( toolCall . id ) {
478- activeToolCallIds . add ( toolCall . id )
479- }
480- yield {
481- type : "tool_call_partial" ,
482- index : toolCall . index ,
483- id : toolCall . id ,
484- name : toolCall . function ?. name ,
485- arguments : toolCall . function ?. arguments ,
486- }
487- }
488- }
489- }
490-
491- // Emit tool_call_end events when finish_reason is "tool_calls"
492- // This ensures tool calls are finalized even if the stream doesn't properly close
493- if ( finishReason === "tool_calls" && activeToolCallIds . size > 0 ) {
494- for ( const id of activeToolCallIds ) {
495- yield { type : "tool_call_end" , id }
496- }
497- activeToolCallIds . clear ( )
452+ yield * this . processToolCalls ( delta , finishReason , activeToolCallIds )
498453 }
499454
500455 if ( chunk . usage ) {
@@ -507,6 +462,46 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
507462 }
508463 }
509464
465+ /**
466+ * Helper generator to process tool calls from a stream chunk.
467+ * Tracks active tool call IDs and yields tool_call_partial and tool_call_end events.
468+ * @param delta - The delta object from the stream chunk
469+ * @param finishReason - The finish_reason from the stream chunk
470+ * @param activeToolCallIds - Set to track active tool call IDs (mutated in place)
471+ */
472+ private * processToolCalls (
473+ delta : OpenAI . Chat . Completions . ChatCompletionChunk . Choice . Delta | undefined ,
474+ finishReason : string | null | undefined ,
475+ activeToolCallIds : Set < string > ,
476+ ) : Generator <
477+ | { type : "tool_call_partial" ; index : number ; id ?: string ; name ?: string ; arguments ?: string }
478+ | { type : "tool_call_end" ; id : string }
479+ > {
480+ if ( delta ?. tool_calls ) {
481+ for ( const toolCall of delta . tool_calls ) {
482+ if ( toolCall . id ) {
483+ activeToolCallIds . add ( toolCall . id )
484+ }
485+ yield {
486+ type : "tool_call_partial" ,
487+ index : toolCall . index ,
488+ id : toolCall . id ,
489+ name : toolCall . function ?. name ,
490+ arguments : toolCall . function ?. arguments ,
491+ }
492+ }
493+ }
494+
495+ // Emit tool_call_end events when finish_reason is "tool_calls"
496+ // This ensures tool calls are finalized even if the stream doesn't properly close
497+ if ( finishReason === "tool_calls" && activeToolCallIds . size > 0 ) {
498+ for ( const id of activeToolCallIds ) {
499+ yield { type : "tool_call_end" , id }
500+ }
501+ activeToolCallIds . clear ( )
502+ }
503+ }
504+
510505 protected _getUrlHost ( baseUrl ?: string ) : string {
511506 try {
512507 return new URL ( baseUrl ?? "" ) . host
0 commit comments