39
39
templates = Jinja2Templates (directory = "templates" )
40
40
41
41
42
+ def wrap_for_oob_swap (step_id : str , text_value : str ) -> str :
43
+ return f'<span hx-swap-oob="beforeend:#step-{ step_id } ">{ text_value } </span>'
44
+
45
+
42
46
# Route to submit a new user message to a thread and mount a component that
43
47
# will start an assistant run stream
44
48
@router .post ("/send" )
@@ -145,26 +149,27 @@ async def handle_assistant_stream(
145
149
# Assuming one citation per delta for now
146
150
break
147
151
148
- sse_data = f'<span hx-swap-oob="beforeend:#step- { step_id } "> { text_value } </span>'
152
+ sse_data = wrap_for_oob_swap ( step_id , text_value )
149
153
yield sse_format (
150
154
"textDelta" ,
151
155
sse_data
152
156
)
153
157
154
158
if isinstance (event , ThreadRunStepCreated ) and event .data .type == "tool_calls" :
159
+ logger .debug (f"Tool Call Created - Data: { str (event .data )} " )
155
160
step_id = event .data .id
156
- logger .debug (f"Tool Call Created - Step ID: { step_id } " )
157
161
158
162
yield sse_format (
159
- f "toolCallCreated" ,
163
+ "toolCallCreated" ,
160
164
templates .get_template ('components/assistant-step.html' ).render (
161
165
step_type = 'toolCall' ,
162
- stream_name = f'toolDelta { step_id } '
166
+ step_id = step_id
163
167
)
164
168
)
165
169
166
170
if isinstance (event , ThreadRunStepDelta ) and event .data .delta .step_details and event .data .delta .step_details .type == "tool_calls" :
167
171
tool_calls = event .data .delta .step_details .tool_calls
172
+ step_id = event .data .id
168
173
if tool_calls :
169
174
# TODO: Support parallel function calling
170
175
tool_call = tool_calls [0 ]
@@ -174,39 +179,44 @@ async def handle_assistant_stream(
174
179
if tool_call .type == "function" :
175
180
if tool_call .function and tool_call .function .name :
176
181
yield sse_format (
177
- f "toolDelta{ step_id } " ,
178
- tool_call .function .name + "< br>"
182
+ "toolDelta" ,
183
+ wrap_for_oob_swap ( step_id , f"<em> { tool_call .function .name } tool call</em>< br>")
179
184
)
180
185
if tool_call .function and tool_call .function .arguments :
181
186
yield sse_format (
182
- f "toolDelta{ step_id } " ,
183
- tool_call .function .arguments
187
+ "toolDelta" ,
188
+ wrap_for_oob_swap ( step_id , tool_call .function .arguments )
184
189
)
185
190
186
191
# Handle code interpreter tool calls
187
192
elif tool_call .type == "code_interpreter" :
188
193
if tool_call .code_interpreter and tool_call .code_interpreter .input :
189
194
logger .debug (f"Code Interpreter Input: { tool_call .code_interpreter .input } " )
190
195
yield sse_format (
191
- f "toolDelta{ step_id } " ,
192
- str (tool_call .code_interpreter .input )
196
+ "toolDelta" ,
197
+ wrap_for_oob_swap ( step_id , str (tool_call .code_interpreter .input ) )
193
198
)
194
199
if tool_call .code_interpreter and tool_call .code_interpreter .outputs :
195
200
for output in tool_call .code_interpreter .outputs :
196
201
logger .debug (f"Code Interpreter Output Type: { output .type } " )
197
202
if output .type == "logs" and output .logs :
198
203
yield sse_format (
199
- f "toolDelta{ step_id } " ,
200
- str (output .logs )
204
+ "toolDelta" ,
205
+ wrap_for_oob_swap ( step_id , str (output .logs ) )
201
206
)
202
207
elif output .type == "image" and output .image and output .image .file_id :
203
208
logger .debug (f"Image Output - File ID: { output .image .file_id } " )
204
209
# Create the image HTML on the backend
205
210
image_html = f'<img src="/assistants/{ assistant_id } /files/{ output .image .file_id } /content" class="code-interpreter-image">'
206
211
yield sse_format (
207
- f "imageOutput" ,
208
- image_html
212
+ "imageOutput" ,
213
+ wrap_for_oob_swap ( step_id , image_html )
209
214
)
215
+ elif tool_call .type == "file_search" :
216
+ yield sse_format (
217
+ "toolDelta" ,
218
+ wrap_for_oob_swap (step_id , "<em>File search tool call</em>" )
219
+ )
210
220
211
221
# If the assistant run requires an action (a tool call), break and handle it
212
222
if isinstance (event , ThreadRunRequiresAction ):
0 commit comments