diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py index 14c67986b06..d39a08102f6 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py @@ -473,26 +473,26 @@ class LiteLLMAnthropicMessagesAdapter: self._translate_anthropic_image_to_openai( cast(dict, source) ) - or "" ) - tool_result = ChatCompletionToolMessage( - role="tool", - tool_call_id=content.get( - "tool_use_id", "" - ), - content=[ - ChatCompletionImageObject( - type="image_url", - image_url=ChatCompletionImageUrlObject( - url=openai_image_url - ), - ) - ], - ) - self._add_cache_control_if_applicable( - content, tool_result, model - ) - tool_message_list.append(tool_result) # type: ignore[arg-type] + if openai_image_url: + tool_result = ChatCompletionToolMessage( + role="tool", + tool_call_id=content.get( + "tool_use_id", "" + ), + content=[ + ChatCompletionImageObject( + type="image_url", + image_url=ChatCompletionImageUrlObject( + url=openai_image_url + ), + ) + ], + ) + self._add_cache_control_if_applicable( + content, tool_result, model + ) + tool_message_list.append(tool_result) # type: ignore[arg-type] else: # For multiple content items, combine into a single tool message # with list content to preserve all items while having one tool_use_id diff --git a/tests/test_litellm/llms/anthropic/experimental_pass_through/adapters/test_anthropic_experimental_pass_through_adapters_transformation.py b/tests/test_litellm/llms/anthropic/experimental_pass_through/adapters/test_anthropic_experimental_pass_through_adapters_transformation.py index ae970e1ff06..2b99c74fd1a 100644 --- a/tests/test_litellm/llms/anthropic/experimental_pass_through/adapters/test_anthropic_experimental_pass_through_adapters_transformation.py +++ b/tests/test_litellm/llms/anthropic/experimental_pass_through/adapters/test_anthropic_experimental_pass_through_adapters_transformation.py @@ -750,10 +750,13 @@ def test_translate_anthropic_messages_to_openai_tool_result_with_base64_image(): break assert tool_message is not None, "Tool message not found in result" - # Tool messages in OpenAI format have string content (data URL), not list - assert isinstance(tool_message["content"], str) - assert tool_message["content"].startswith("data:image/jpeg;base64,") - assert "/9j/4AAQSkZJRgABAQAAAQABAAD" in tool_message["content"] + # Tool messages with images use list content with ChatCompletionImageObject + assert isinstance(tool_message["content"], list) + assert len(tool_message["content"]) == 1 + image_obj = tool_message["content"][0] + assert image_obj["type"] == "image_url" + assert image_obj["image_url"]["url"].startswith("data:image/jpeg;base64,") + assert "/9j/4AAQSkZJRgABAQAAAQABAAD" in image_obj["image_url"]["url"] def test_translate_anthropic_messages_to_openai_tool_result_with_url_image(): @@ -806,10 +809,13 @@ def test_translate_anthropic_messages_to_openai_tool_result_with_url_image(): break assert tool_message is not None, "Tool message not found in result" - # Tool messages in OpenAI format have string content (URL), not list - assert isinstance(tool_message["content"], str) + # Tool messages with images use list content with ChatCompletionImageObject + assert isinstance(tool_message["content"], list) + assert len(tool_message["content"]) == 1 + image_obj = tool_message["content"][0] + assert image_obj["type"] == "image_url" assert ( - tool_message["content"] + image_obj["image_url"]["url"] == "https://i0.wp.com/picjumbo.com/wp-content/uploads/amazing-stone-path-in-forest-free-image.jpg" )