@@ -19,6 +19,7 @@ export class ChatToResponsesStreamConverter {
1919 private itemAdded : boolean = false ;
2020 private partAdded : boolean = false ;
2121 private emittedFunctionItems : Set < string > = new Set ( ) ;
22+ private completedEmitted : boolean = false ;
2223
2324 constructor ( ) {
2425 this . toolCalls = new Map ( ) ;
@@ -139,28 +140,27 @@ export class ChatToResponsesStreamConverter {
139140 }
140141 }
141142
142- // if finish reason was sent for this choice, emit text. done
143+ // if finish reason was sent for this choice, emit done + completed
143144 if ( choice ?. finish_reason ) {
144- const doneEvt : ResponseOutputTextDoneEvent = {
145- type : "response.output_text.done" ,
146- item_id : `msg_${ this . responseId } ` ,
147- output_index : 0 ,
148- content_index : 0 ,
149- text : this . textBuffer ,
150- } ;
151- events . push ( doneEvt ) ;
152-
153- // close part and item
154- if ( this . partAdded ) {
155- events . push ( {
156- type : "response.content_part.done" ,
145+ if ( this . itemAdded ) {
146+ const doneEvt : ResponseOutputTextDoneEvent = {
147+ type : "response.output_text.done" ,
157148 item_id : `msg_${ this . responseId } ` ,
158149 output_index : 0 ,
159150 content_index : 0 ,
160- part : { type : "output_text" , text : this . textBuffer , annotations : [ ] } ,
161- } as any ) ;
162- }
163- if ( this . itemAdded ) {
151+ text : this . textBuffer ,
152+ } ;
153+ events . push ( doneEvt ) ;
154+
155+ if ( this . partAdded ) {
156+ events . push ( {
157+ type : "response.content_part.done" ,
158+ item_id : `msg_${ this . responseId } ` ,
159+ output_index : 0 ,
160+ content_index : 0 ,
161+ part : { type : "output_text" , text : this . textBuffer , annotations : [ ] } ,
162+ } as any ) ;
163+ }
164164 events . push ( {
165165 type : "response.output_item.done" ,
166166 output_index : 0 ,
@@ -178,14 +178,12 @@ export class ChatToResponsesStreamConverter {
178178
179179 // Finalize any function calls
180180 this . toolCalls . forEach ( ( tc ) => {
181- // Done event with full arguments
182181 events . push ( {
183182 type : "response.function_call_arguments.done" ,
184183 item_id : tc . item_id ,
185184 output_index : 0 ,
186185 arguments : tc . arguments || "{}" ,
187186 } as any ) ;
188- // Output item done
189187 events . push ( {
190188 type : "response.output_item.done" ,
191189 output_index : 0 ,
@@ -200,11 +198,50 @@ export class ChatToResponsesStreamConverter {
200198 } ,
201199 } as any ) ;
202200 } ) ;
201+
202+ // Emit completed now if usage not provided
203+ const usage = this . finalUsage || undefined ;
204+ const completed : ResponseCompletedEvent = {
205+ type : "response.completed" ,
206+ response : {
207+ id : this . responseId ,
208+ object : "response" ,
209+ created : this . created ,
210+ created_at : this . created as any ,
211+ status : "completed" as any ,
212+ model : this . model ,
213+ output : [
214+ ...( this . itemAdded
215+ ? ( [
216+ {
217+ type : "message" as const ,
218+ role : "assistant" as const ,
219+ content : [
220+ { type : "output_text" as const , text : this . textBuffer } ,
221+ ] ,
222+ } ,
223+ ] as any )
224+ : [ ] ) ,
225+ ...Array . from ( this . toolCalls . values ( ) ) . map ( ( tc ) => ( {
226+ id : `fc_${ tc . id } ` ,
227+ type : "function_call" as const ,
228+ status : "completed" as const ,
229+ name : tc . name || "" ,
230+ call_id : tc . id ,
231+ arguments : tc . arguments || "{}" ,
232+ parsed_arguments : null ,
233+ } ) ) ,
234+ ] ,
235+ ...( usage ? { usage } : { } ) ,
236+ } ,
237+ } ;
238+ events . push ( completed ) ;
239+ this . completedEmitted = true ;
203240 }
204241 }
205242
206- // usage usagealley (haha...?) arrives in the final chunk with empty choices
207- if ( c . usage ) {
243+ // usage arrives in the final chunk with empty choices
244+ if ( c . usage && ! this . completedEmitted ) {
208245 const usage : ResponsesUsage = {
209246 input_tokens : c . usage . prompt_tokens ,
210247 output_tokens : c . usage . completion_tokens ,
@@ -253,6 +290,7 @@ export class ChatToResponsesStreamConverter {
253290 } ,
254291 } ;
255292 events . push ( completed ) ;
293+ this . completedEmitted = true ;
256294 }
257295
258296 return events ;
0 commit comments