@@ -338,27 +338,42 @@ async def iterate_stream(s, response_id: str = "") -> AsyncGenerator[str, None]:
338338 yield sse_format ("textDelta" , wrap_for_oob_swap (current_item_id , event .delta ))
339339
340340 case ResponseOutputTextAnnotationAddedEvent ():
341- if event .annotation and current_item_id :
341+ # Use event.item_id (not current_item_id) because annotations
342+ # may fire after other output items (e.g. code interpreter)
343+ # have changed current_item_id to a different element.
344+ annotation_target_id = event .item_id or current_item_id
345+ if event .annotation and annotation_target_id :
342346 if event .annotation ["type" ] == "file_citation" :
343347 filename = event .annotation ["filename" ]
344348 # Emit a literal HTML anchor to avoid markdown parsing edge cases
345349 encoded_filename = url_quote (filename , safe = "" )
346350 file_url_path = files_router .url_path_for ("download_stored_file" , file_name = encoded_filename )
347351 citation = f"(<a href=\" { file_url_path } \" >†</a>)"
348- yield sse_format ("textDelta" , wrap_for_oob_swap (current_item_id , citation ))
352+ yield sse_format ("textDelta" , wrap_for_oob_swap (annotation_target_id , citation ))
349353 elif event .annotation ["type" ] == "container_file_citation" :
350354 container_id = event .annotation ["container_id" ]
351355 file_id = event .annotation ["file_id" ]
352- file = await client .containers .files .retrieve (file_id , container_id = container_id )
353- container_file_path = file .path
356+ filename = event .annotation .get ("filename" , "" )
354357 file_url_path = files_router .url_path_for ("download_container_file" , container_id = container_id , file_id = file_id )
355- replacement_payload = f"sandbox:{ container_file_path } |{ file_url_path } "
356- yield sse_format ("textReplacement" , wrap_for_oob_swap (current_item_id , replacement_payload ))
358+ # Check if the file is an image by extension
359+ image_extensions = (".png" , ".jpg" , ".jpeg" , ".gif" , ".svg" , ".webp" )
360+ if filename .lower ().endswith (image_extensions ):
361+ img_html = (
362+ f'<div class="imageOutput">'
363+ f'<img src="{ file_url_path } " alt="Code interpreter output" />'
364+ f'</div>'
365+ )
366+ yield sse_format ("imageOutput" , img_html )
367+ else :
368+ file = await client .containers .files .retrieve (file_id , container_id = container_id )
369+ container_file_path = file .path
370+ replacement_payload = f"sandbox:{ container_file_path } |{ file_url_path } "
371+ yield sse_format ("textReplacement" , wrap_for_oob_swap (annotation_target_id , replacement_payload ))
357372 elif event .annotation ["type" ] == "url_citation" :
358373 url = event .annotation ["url" ]
359374 title = event .annotation .get ("title" , url )
360375 citation = f'(<a href="{ escape (url )} " target="_blank" rel="noopener noreferrer">{ escape (title )} </a>)'
361- yield sse_format ("textDelta" , wrap_for_oob_swap (current_item_id , citation ))
376+ yield sse_format ("textDelta" , wrap_for_oob_swap (annotation_target_id , citation ))
362377 else :
363378 logger .error (f"Unhandled annotation type: { event .annotation ['type' ]} " )
364379
0 commit comments