fix(anthropic): convert image_url blocks inside tool_result content

_tool_result_block passed list content through unchanged, so image_url
blocks returned by tools (e.g. read_file on an image file, which
returns OpenAI-format image_url blocks via build_image_content_blocks)
reached the Anthropic API unconverted and were rejected. User-role
messages already ran through _convert_user_content at the call site,
so inbound Telegram photos worked, but tool results did not.

Run _convert_user_content on list content inside _tool_result_block
so image_url blocks become native Anthropic image blocks. Required
making _convert_user_content a @staticmethod (it did not use self)
and calling _convert_image_block via the class to match.

Repro: an agent calling read_file on any image file got a
"Non-transient LLM error with image content, retrying without images"
warning and the image was silently dropped from the conversation.
This commit is contained in:
lentan
2026-04-22 22:10:53 +08:00
committed by Xubin Ren
parent 42c4af2118
commit 29a08df06a
+6 -3
View File
@@ -167,7 +167,9 @@ class AnthropicProvider(LLMProvider):
"type": "tool_result",
"tool_use_id": msg.get("tool_call_id", ""),
}
if isinstance(content, (str, list)):
if isinstance(content, list):
block["content"] = AnthropicProvider._convert_user_content(content)
elif isinstance(content, str):
block["content"] = content
else:
block["content"] = str(content) if content else ""
@@ -208,7 +210,8 @@ class AnthropicProvider(LLMProvider):
return blocks or [{"type": "text", "text": ""}]
def _convert_user_content(self, content: Any) -> Any:
@staticmethod
def _convert_user_content(content: Any) -> Any:
"""Convert user message content, translating image_url blocks."""
if isinstance(content, str) or content is None:
return content or "(empty)"
@@ -221,7 +224,7 @@ class AnthropicProvider(LLMProvider):
result.append({"type": "text", "text": str(item)})
continue
if item.get("type") == "image_url":
converted = self._convert_image_block(item)
converted = AnthropicProvider._convert_image_block(item)
if converted:
result.append(converted)
continue