@@ -181,17 +181,133 @@ def convert_anthropic_to_openai_payload(anthropic_payload: dict) -> dict:
181181 )
182182 elif block_type == 'tool_result' :
183183 # Tool results become separate tool messages in OpenAI format
184- tool_content = block .get ('content' , '' )
185- if isinstance (tool_content , list ):
186- tool_text_parts = []
187- for tc in tool_content :
188- if isinstance (tc , dict ) and tc .get ('type' ) == 'text' :
189- tool_text_parts .append (tc .get ('text' , '' ))
190- tool_content = '\n ' .join (tool_text_parts )
184+ tool_result_content = block .get ('content' , '' )
185+ tool_content : str | list = ''
186+
187+ if isinstance (tool_result_content , str ):
188+ tool_content = tool_result_content
189+ elif isinstance (tool_result_content , list ):
190+ # Build a multimodal content array to preserve
191+ # images and other non-text content types.
192+ converted_parts = []
193+ for content_block in tool_result_content :
194+ if not isinstance (content_block , dict ):
195+ continue
196+ content_type = content_block .get ('type' , 'text' )
197+
198+ if content_type == 'text' :
199+ converted_parts .append (
200+ {
201+ 'type' : 'text' ,
202+ 'text' : content_block .get ('text' , '' ),
203+ }
204+ )
205+ elif content_type == 'image' :
206+ source = content_block .get ('source' , {})
207+ if source .get ('type' ) == 'base64' :
208+ media_type = source .get (
209+ 'media_type' , 'image/png'
210+ )
211+ data = source .get ('data' , '' )
212+ converted_parts .append (
213+ {
214+ 'type' : 'image_url' ,
215+ 'image_url' : {
216+ 'url' : f'data:{ media_type } ;base64,{ data } ' ,
217+ },
218+ }
219+ )
220+ elif source .get ('type' ) == 'url' :
221+ converted_parts .append (
222+ {
223+ 'type' : 'image_url' ,
224+ 'image_url' : {
225+ 'url' : source .get ('url' , '' ),
226+ },
227+ }
228+ )
229+ elif content_type == 'document' :
230+ # Documents have no direct OpenAI equivalent;
231+ # convert to a text representation.
232+ document_source = content_block .get (
233+ 'source' , {}
234+ )
235+ document_title = content_block .get (
236+ 'title' , 'Document'
237+ )
238+ document_context = content_block .get (
239+ 'context' , ''
240+ )
241+ document_text = (
242+ f'[Document: { document_title } ]'
243+ )
244+ if document_context :
245+ document_text += f'\n { document_context } '
246+ if (
247+ document_source .get ('type' ) == 'text'
248+ and document_source .get ('data' )
249+ ):
250+ document_text += (
251+ f'\n { document_source ["data" ]} '
252+ )
253+ converted_parts .append (
254+ {'type' : 'text' , 'text' : document_text }
255+ )
256+ elif content_type == 'search_result' :
257+ # Convert search results to a text
258+ # representation with source attribution.
259+ search_title = content_block .get ('title' , '' )
260+ search_url = content_block .get ('source' , '' )
261+ search_content_blocks = content_block .get (
262+ 'content' , []
263+ )
264+ search_texts = []
265+ for search_block in search_content_blocks :
266+ if (
267+ isinstance (search_block , dict )
268+ and search_block .get ('type' ) == 'text'
269+ ):
270+ search_texts .append (
271+ search_block .get ('text' , '' )
272+ )
273+ search_body = '\n ' .join (search_texts )
274+ search_text = (
275+ f'[Search Result: { search_title } ]'
276+ )
277+ if search_url :
278+ search_text += f'\n Source: { search_url } '
279+ if search_body :
280+ search_text += f'\n { search_body } '
281+ converted_parts .append (
282+ {'type' : 'text' , 'text' : search_text }
283+ )
284+
285+ # Flatten to string when only text parts are present
286+ if all (
287+ part .get ('type' ) == 'text'
288+ for part in converted_parts
289+ ):
290+ tool_content = '\n ' .join (
291+ part .get ('text' , '' )
292+ for part in converted_parts
293+ )
294+ elif converted_parts :
295+ tool_content = converted_parts
296+ else :
297+ tool_content = ''
191298
192299 # Propagate error status if present
193300 if block .get ('is_error' ):
194- tool_content = f'Error: { tool_content } '
301+ if isinstance (tool_content , str ):
302+ tool_content = f'Error: { tool_content } '
303+ elif isinstance (tool_content , list ):
304+ tool_content .insert (
305+ 0 ,
306+ {
307+ 'type' : 'text' ,
308+ 'text' : 'Error: ' ,
309+ },
310+ )
195311
196312 messages .append (
197313 {
0 commit comments