@@ -340,6 +340,7 @@ def items_to_messages(
340340 cls ,
341341 items : str | Iterable [TResponseInputItem ],
342342 preserve_thinking_blocks : bool = False ,
343+ preserve_tool_output_all_content : bool = False ,
343344 ) -> list [ChatCompletionMessageParam ]:
344345 """
345346 Convert a sequence of 'Item' objects into a list of ChatCompletionMessageParam.
@@ -350,6 +351,12 @@ def items_to_messages(
350351 for reasoning models like Claude 4 Sonnet/Opus which support interleaved
351352 thinking. When True, thinking blocks are reconstructed and included in
352353 assistant messages with tool calls.
354+ preserve_tool_output_all_content: Whether to preserve non-text content (like images)
355+ in tool outputs. When False (default), only text content is extracted.
356+ OpenAI Chat Completions API doesn't support non-text content in tool results.
357+ When True, all content types including images are preserved. This is useful
358+ for model providers (e.g. Anthropic via LiteLLM) that support processing
359+ non-text content in tool results.
353360
354361 Rules:
355362 - EasyInputMessage or InputMessage (role=user) => ChatCompletionUserMessageParam
@@ -541,10 +548,14 @@ def ensure_assistant_message() -> ChatCompletionAssistantMessageParam:
541548 output_content = cast (
542549 Union [str , Iterable [ResponseInputContentWithAudioParam ]], func_output ["output" ]
543550 )
551+ if preserve_tool_output_all_content :
552+ tool_result_content = cls .extract_all_content (output_content )
553+ else :
554+ tool_result_content = cls .extract_text_content (output_content ) # type: ignore[assignment]
544555 msg : ChatCompletionToolMessageParam = {
545556 "role" : "tool" ,
546557 "tool_call_id" : func_output ["call_id" ],
547- "content" : cls . extract_text_content ( output_content ),
558+ "content" : tool_result_content , # type: ignore[typeddict-item]
548559 }
549560 result .append (msg )
550561
0 commit comments