@@ -214,10 +214,16 @@ def format_request_messages(cls, messages: Messages, system_prompt: Optional[str
214214 for message in messages :
215215 contents = message ["content" ]
216216
217+ # Check for reasoningContent and warn user
218+ if any ("reasoningContent" in content for content in contents ):
219+ logger .warning (
220+ "reasoningContent is not supported in multi-turn conversations with the Chat Completions API."
221+ )
222+
217223 formatted_contents = [
218224 cls .format_request_message_content (content )
219225 for content in contents
220- if not any (block_type in content for block_type in ["toolResult" , "toolUse" ])
226+ if not any (block_type in content for block_type in ["toolResult" , "toolUse" , "reasoningContent" ])
221227 ]
222228 formatted_tool_calls = [
223229 cls .format_request_message_tool_call (content ["toolUse" ]) for content in contents if "toolUse" in content
@@ -405,38 +411,46 @@ async def stream(
405411
406412 logger .debug ("got response from model" )
407413 yield self .format_chunk ({"chunk_type" : "message_start" })
408- yield self .format_chunk ({"chunk_type" : "content_start" , "data_type" : "text" })
409-
410414 tool_calls : dict [int , list [Any ]] = {}
415+ data_type = None
416+ finish_reason = None # Store finish_reason for later use
417+ event = None # Initialize for scope safety
411418
412419 async for event in response :
413420 # Defensive: skip events with empty or missing choices
414421 if not getattr (event , "choices" , None ):
415422 continue
416423 choice = event .choices [0 ]
417424
418- if choice .delta .content :
419- yield self .format_chunk (
420- {"chunk_type" : "content_delta" , "data_type" : "text" , "data" : choice .delta .content }
421- )
422-
423425 if hasattr (choice .delta , "reasoning_content" ) and choice .delta .reasoning_content :
426+ chunks , data_type = self ._stream_switch_content ("reasoning_content" , data_type )
427+ for chunk in chunks :
428+ yield chunk
424429 yield self .format_chunk (
425430 {
426431 "chunk_type" : "content_delta" ,
427- "data_type" : "reasoning_content" ,
432+ "data_type" : data_type ,
428433 "data" : choice .delta .reasoning_content ,
429434 }
430435 )
431436
437+ if choice .delta .content :
438+ chunks , data_type = self ._stream_switch_content ("text" , data_type )
439+ for chunk in chunks :
440+ yield chunk
441+ yield self .format_chunk (
442+ {"chunk_type" : "content_delta" , "data_type" : data_type , "data" : choice .delta .content }
443+ )
444+
432445 for tool_call in choice .delta .tool_calls or []:
433446 tool_calls .setdefault (tool_call .index , []).append (tool_call )
434447
435448 if choice .finish_reason :
449+ finish_reason = choice .finish_reason # Store for use outside loop
450+ if data_type :
451+ yield self .format_chunk ({"chunk_type" : "content_stop" , "data_type" : data_type })
436452 break
437453
438- yield self .format_chunk ({"chunk_type" : "content_stop" , "data_type" : "text" })
439-
440454 for tool_deltas in tool_calls .values ():
441455 yield self .format_chunk ({"chunk_type" : "content_start" , "data_type" : "tool" , "data" : tool_deltas [0 ]})
442456
@@ -445,17 +459,37 @@ async def stream(
445459
446460 yield self .format_chunk ({"chunk_type" : "content_stop" , "data_type" : "tool" })
447461
448- yield self .format_chunk ({"chunk_type" : "message_stop" , "data" : choice . finish_reason })
462+ yield self .format_chunk ({"chunk_type" : "message_stop" , "data" : finish_reason or "end_turn" })
449463
450464 # Skip remaining events as we don't have use for anything except the final usage payload
451465 async for event in response :
452466 _ = event
453467
454- if event .usage :
468+ if event and hasattr ( event , "usage" ) and event .usage :
455469 yield self .format_chunk ({"chunk_type" : "metadata" , "data" : event .usage })
456470
457471 logger .debug ("finished streaming response from model" )
458472
473+ def _stream_switch_content (self , data_type : str , prev_data_type : str | None ) -> tuple [list [StreamEvent ], str ]:
474+ """Handle switching to a new content stream.
475+
476+ Args:
477+ data_type: The next content data type.
478+ prev_data_type: The previous content data type.
479+
480+ Returns:
481+ Tuple containing:
482+ - Stop block for previous content and the start block for the next content.
483+ - Next content data type.
484+ """
485+ chunks = []
486+ if data_type != prev_data_type :
487+ if prev_data_type is not None :
488+ chunks .append (self .format_chunk ({"chunk_type" : "content_stop" , "data_type" : prev_data_type }))
489+ chunks .append (self .format_chunk ({"chunk_type" : "content_start" , "data_type" : data_type }))
490+
491+ return chunks , data_type
492+
459493 @override
460494 async def structured_output (
461495 self , output_model : Type [T ], prompt : Messages , system_prompt : Optional [str ] = None , ** kwargs : Any
0 commit comments