Skip to content

Commit ba55bbd

Browse files
ihowerseratch
andauthored
fix: #2163 Preserve non-text tool outputs in LiteLLM and chatcmpl converters (#2214)
Co-authored-by: Kazuhiro Sera <[email protected]>
1 parent 7404531 commit ba55bbd

File tree

2 files changed

+15
-2
lines changed

2 files changed

+15
-2
lines changed

src/agents/extensions/models/litellm_model.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,9 @@ async def _fetch_response(
280280
)
281281

282282
converted_messages = Converter.items_to_messages(
283-
input, preserve_thinking_blocks=preserve_thinking_blocks
283+
input,
284+
preserve_thinking_blocks=preserve_thinking_blocks,
285+
preserve_tool_output_all_content=True,
284286
)
285287

286288
# Fix for interleaved thinking bug: reorder messages to ensure tool_use comes before tool_result # noqa: E501

src/agents/models/chatcmpl_converter.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)