diff --git a/src/strands/models/anthropic.py b/src/strands/models/anthropic.py index 812171a0c..c80b6b29a 100644 --- a/src/strands/models/anthropic.py +++ b/src/strands/models/anthropic.py @@ -28,6 +28,14 @@ T = TypeVar("T", bound=BaseModel) +IMAGE_MEDIA_TYPES = { + "gif": "image/gif", + "jpeg": "image/jpeg", + "jpg": "image/jpeg", + "png": "image/png", + "webp": "image/webp", +} + class AnthropicModel(Model): """Anthropic model provider implementation.""" @@ -131,10 +139,14 @@ def _format_request_message_content(self, content: ContentBlock) -> dict[str, An } if "image" in content: + image_format = content["image"]["format"] return { "source": { "data": base64.b64encode(content["image"]["source"]["bytes"]).decode("utf-8"), - "media_type": mimetypes.types_map.get(f".{content['image']['format']}", "application/octet-stream"), + "media_type": IMAGE_MEDIA_TYPES.get( + image_format, + mimetypes.types_map.get(f".{image_format}", "application/octet-stream"), + ), "type": "base64", }, "type": "image", diff --git a/tests/strands/models/test_anthropic.py b/tests/strands/models/test_anthropic.py index 0ebdb161c..7366dc3c9 100644 --- a/tests/strands/models/test_anthropic.py +++ b/tests/strands/models/test_anthropic.py @@ -1,4 +1,5 @@ import logging +import mimetypes import unittest.mock import warnings @@ -254,6 +255,21 @@ def test_format_request_with_image(model, model_id, max_tokens): assert tru_request == exp_request +def test_format_request_with_webp_image_does_not_depend_on_mimetypes(model, model_id, max_tokens, monkeypatch): + monkeypatch.delitem(mimetypes.types_map, ".webp", raising=False) + + messages = [ + { + "role": "user", + "content": [{"image": {"format": "webp", "source": {"bytes": b"webpimage"}}}], + }, + ] + + tru_request = model.format_request(messages) + + assert tru_request["messages"][0]["content"][0]["source"]["media_type"] == "image/webp" + + def test_format_request_with_reasoning(model, model_id, max_tokens): messages = [ {