@@ -38,6 +38,16 @@ class StreamingState:
3838 function_calls : dict [int , ResponseFunctionToolCall ] = field (default_factory = dict )
3939
4040
41+ class SequenceNumber :
42+ def __init__ (self ):
43+ self ._sequence_number = 0
44+
45+ def get_and_increment (self ) -> int :
46+ num = self ._sequence_number
47+ self ._sequence_number += 1
48+ return num
49+
50+
4151class ChatCmplStreamHandler :
4252 @classmethod
4353 async def handle_stream (
@@ -47,13 +57,14 @@ async def handle_stream(
4757 ) -> AsyncIterator [TResponseStreamEvent ]:
4858 usage : CompletionUsage | None = None
4959 state = StreamingState ()
50-
60+ sequence_number = SequenceNumber ()
5161 async for chunk in stream :
5262 if not state .started :
5363 state .started = True
5464 yield ResponseCreatedEvent (
5565 response = response ,
5666 type = "response.created" ,
67+ sequence_number = sequence_number .get_and_increment (),
5768 )
5869
5970 # This is always set by the OpenAI API, but not by others e.g. LiteLLM
@@ -89,6 +100,7 @@ async def handle_stream(
89100 item = assistant_item ,
90101 output_index = 0 ,
91102 type = "response.output_item.added" ,
103+ sequence_number = sequence_number .get_and_increment (),
92104 )
93105 yield ResponseContentPartAddedEvent (
94106 content_index = state .text_content_index_and_output [0 ],
@@ -100,6 +112,7 @@ async def handle_stream(
100112 annotations = [],
101113 ),
102114 type = "response.content_part.added" ,
115+ sequence_number = sequence_number .get_and_increment (),
103116 )
104117 # Emit the delta for this segment of content
105118 yield ResponseTextDeltaEvent (
@@ -108,6 +121,7 @@ async def handle_stream(
108121 item_id = FAKE_RESPONSES_ID ,
109122 output_index = 0 ,
110123 type = "response.output_text.delta" ,
124+ sequence_number = sequence_number .get_and_increment (),
111125 )
112126 # Accumulate the text into the response part
113127 state .text_content_index_and_output [1 ].text += delta .content
@@ -134,6 +148,7 @@ async def handle_stream(
134148 item = assistant_item ,
135149 output_index = 0 ,
136150 type = "response.output_item.added" ,
151+ sequence_number = sequence_number .get_and_increment (),
137152 )
138153 yield ResponseContentPartAddedEvent (
139154 content_index = state .refusal_content_index_and_output [0 ],
@@ -145,6 +160,7 @@ async def handle_stream(
145160 annotations = [],
146161 ),
147162 type = "response.content_part.added" ,
163+ sequence_number = sequence_number .get_and_increment (),
148164 )
149165 # Emit the delta for this segment of refusal
150166 yield ResponseRefusalDeltaEvent (
@@ -153,6 +169,7 @@ async def handle_stream(
153169 item_id = FAKE_RESPONSES_ID ,
154170 output_index = 0 ,
155171 type = "response.refusal.delta" ,
172+ sequence_number = sequence_number .get_and_increment (),
156173 )
157174 # Accumulate the refusal string in the output part
158175 state .refusal_content_index_and_output [1 ].refusal += delta .refusal
@@ -190,6 +207,7 @@ async def handle_stream(
190207 output_index = 0 ,
191208 part = state .text_content_index_and_output [1 ],
192209 type = "response.content_part.done" ,
210+ sequence_number = sequence_number .get_and_increment (),
193211 )
194212
195213 if state .refusal_content_index_and_output :
@@ -201,6 +219,7 @@ async def handle_stream(
201219 output_index = 0 ,
202220 part = state .refusal_content_index_and_output [1 ],
203221 type = "response.content_part.done" ,
222+ sequence_number = sequence_number .get_and_increment (),
204223 )
205224
206225 # Actually send events for the function calls
@@ -216,13 +235,15 @@ async def handle_stream(
216235 ),
217236 output_index = function_call_starting_index ,
218237 type = "response.output_item.added" ,
238+ sequence_number = sequence_number .get_and_increment (),
219239 )
220240 # Then, yield the args
221241 yield ResponseFunctionCallArgumentsDeltaEvent (
222242 delta = function_call .arguments ,
223243 item_id = FAKE_RESPONSES_ID ,
224244 output_index = function_call_starting_index ,
225245 type = "response.function_call_arguments.delta" ,
246+ sequence_number = sequence_number .get_and_increment (),
226247 )
227248 # Finally, the ResponseOutputItemDone
228249 yield ResponseOutputItemDoneEvent (
@@ -235,6 +256,7 @@ async def handle_stream(
235256 ),
236257 output_index = function_call_starting_index ,
237258 type = "response.output_item.done" ,
259+ sequence_number = sequence_number .get_and_increment (),
238260 )
239261
240262 # Finally, send the Response completed event
@@ -258,6 +280,7 @@ async def handle_stream(
258280 item = assistant_msg ,
259281 output_index = 0 ,
260282 type = "response.output_item.done" ,
283+ sequence_number = sequence_number .get_and_increment (),
261284 )
262285
263286 for function_call in state .function_calls .values ():
@@ -289,4 +312,5 @@ async def handle_stream(
289312 yield ResponseCompletedEvent (
290313 response = final_response ,
291314 type = "response.completed" ,
315+ sequence_number = sequence_number .get_and_increment (),
292316 )
0 commit comments