@@ -48,6 +48,9 @@ async def handle_stream(
48
48
usage : CompletionUsage | None = None
49
49
state = StreamingState ()
50
50
51
+ is_reasoning_model = False
52
+ emit_reasoning_content = False
53
+ emit_content = False
51
54
async for chunk in stream :
52
55
if not state .started :
53
56
state .started = True
@@ -62,9 +65,16 @@ async def handle_stream(
62
65
continue
63
66
64
67
delta = chunk .choices [0 ].delta
68
+ reasoning_content = None
69
+ content = None
70
+ if hasattr (delta , "reasoning_content" ):
71
+ reasoning_content = delta .reasoning_content
72
+ is_reasoning_model = True
73
+ if hasattr (delta , "content" ):
74
+ content = delta .content
65
75
66
76
# Handle text
67
- if delta . content :
77
+ if reasoning_content or content :
68
78
if not state .text_content_index_and_output :
69
79
# Initialize a content tracker for streaming text
70
80
state .text_content_index_and_output = (
@@ -100,16 +110,59 @@ async def handle_stream(
100
110
),
101
111
type = "response.content_part.added" ,
102
112
)
103
- # Emit the delta for this segment of content
104
- yield ResponseTextDeltaEvent (
105
- content_index = state .text_content_index_and_output [0 ],
106
- delta = delta .content ,
107
- item_id = FAKE_RESPONSES_ID ,
108
- output_index = 0 ,
109
- type = "response.output_text.delta" ,
110
- )
111
- # Accumulate the text into the response part
112
- state .text_content_index_and_output [1 ].text += delta .content
113
+
114
+ if reasoning_content is not None :
115
+ if not emit_reasoning_content :
116
+ emit_reasoning_content = True
117
+
118
+ reasoning_content_title = "# reasoning content\n \n "
119
+ # Emit the reasoning content title
120
+ yield ResponseTextDeltaEvent (
121
+ content_index = state .text_content_index_and_output [0 ],
122
+ delta = reasoning_content_title ,
123
+ item_id = FAKE_RESPONSES_ID ,
124
+ output_index = 0 ,
125
+ type = "response.output_text.delta" ,
126
+ )
127
+ # Accumulate the text into the response part
128
+ state .text_content_index_and_output [1 ].text += reasoning_content_title
129
+
130
+ # Emit the delta for this segment of content
131
+ yield ResponseTextDeltaEvent (
132
+ content_index = state .text_content_index_and_output [0 ],
133
+ delta = reasoning_content ,
134
+ item_id = FAKE_RESPONSES_ID ,
135
+ output_index = 0 ,
136
+ type = "response.output_text.delta" ,
137
+ )
138
+ # Accumulate the text into the response part
139
+ state .text_content_index_and_output [1 ].text += reasoning_content
140
+
141
+ if content is not None :
142
+ if not emit_content and is_reasoning_model :
143
+ emit_content = True
144
+ content_title = "\n \n # content\n \n "
145
+ # Emit the content title
146
+ yield ResponseTextDeltaEvent (
147
+ content_index = state .text_content_index_and_output [0 ],
148
+ delta = content_title ,
149
+ item_id = FAKE_RESPONSES_ID ,
150
+ output_index = 0 ,
151
+ type = "response.output_text.delta" ,
152
+ )
153
+ # Accumulate the text into the response part
154
+ state .text_content_index_and_output [1 ].text += content_title
155
+
156
+ # Emit the delta for this segment of content
157
+ yield ResponseTextDeltaEvent (
158
+ content_index = state .text_content_index_and_output [0 ],
159
+ delta = content ,
160
+ item_id = FAKE_RESPONSES_ID ,
161
+ output_index = 0 ,
162
+ type = "response.output_text.delta" ,
163
+ )
164
+ # Accumulate the text into the response part
165
+ state .text_content_index_and_output [1 ].text += content
113
166
114
167
# Handle refusals (model declines to answer)
115
168
if delta .refusal :
0 commit comments