Skip to content

Support returning ContentToolResultImage from a tool with ChatAnthropic #118

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion chatlas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from ._anthropic import ChatAnthropic, ChatBedrockAnthropic
from ._auto import ChatAuto
from ._chat import Chat
from ._content import ContentToolRequest, ContentToolResult
from ._content import ContentToolRequest, ContentToolResult, ContentToolResultImage
from ._content_image import content_image_file, content_image_plot, content_image_url
from ._content_pdf import content_pdf_file, content_pdf_url
from ._databricks import ChatDatabricks
Expand Down Expand Up @@ -46,6 +46,7 @@
"content_pdf_url",
"ContentToolRequest",
"ContentToolResult",
"ContentToolResultImage",
"interpolate",
"interpolate_file",
"Provider",
Expand Down
24 changes: 22 additions & 2 deletions chatlas/_anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
ContentText,
ContentToolRequest,
ContentToolResult,
ContentToolResultImage,
ContentToolResultResource,
)
from ._logging import log_model_default
from ._provider import Provider, StandardModelParamNames, StandardModelParams
Expand Down Expand Up @@ -515,8 +517,26 @@ def _as_content_block(content: Content) -> "ContentBlockParam":
"tool_use_id": content.id,
"is_error": content.error is not None,
}
# Anthropic supports non-text contents like ImageBlockParam
res["content"] = content.get_model_value() # type: ignore

if isinstance(content, ContentToolResultImage):
res["content"] = [
{
"type": "image",
"source": {
"type": "base64",
"media_type": content.mime_type,
"data": content.value,
},
}
]
elif isinstance(content, ContentToolResultResource):
raise NotImplementedError(
"ContentToolResultResource is not currently supported by Anthropic."
)
else:
# Anthropic supports non-text contents like ImageBlockParam
res["content"] = content.get_model_value() # type: ignore

return res

raise ValueError(f"Unknown content type: {type(content)}")
Expand Down
9 changes: 9 additions & 0 deletions chatlas/_google.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
ContentText,
ContentToolRequest,
ContentToolResult,
ContentToolResultImage,
ContentToolResultResource,
)
from ._logging import log_model_default
from ._merge import merge_dicts
Expand Down Expand Up @@ -424,6 +426,13 @@ def _as_part_type(self, content: Content) -> "Part":
)
)
elif isinstance(content, ContentToolResult):
if isinstance(
content, (ContentToolResultImage, ContentToolResultResource)
):
raise NotImplementedError(
"Tool results with images or resources aren't supported by Google (Gemini). "
)

if content.error:
resp = {"error": content.error}
else:
Expand Down
8 changes: 8 additions & 0 deletions chatlas/_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
ContentText,
ContentToolRequest,
ContentToolResult,
ContentToolResultImage,
ContentToolResultResource,
)
from ._logging import log_model_default
from ._merge import merge_dicts
Expand Down Expand Up @@ -482,6 +484,12 @@ def _as_message_param(turns: list[Turn]) -> list["ChatCompletionMessageParam"]:
}
)
elif isinstance(x, ContentToolResult):
if isinstance(
x, (ContentToolResultImage, ContentToolResultResource)
):
raise NotImplementedError(
"OpenAI does not support tool results with images or resources."
)
tool_results.append(
ChatCompletionToolMessageParam(
# Currently, OpenAI only allows for text content in tool results
Expand Down
18 changes: 5 additions & 13 deletions tests/test_provider_anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

import httpx
import pytest

from chatlas import ChatAnthropic, ContentToolResult
from chatlas import ChatAnthropic, ContentToolResultImage

from .conftest import (
assert_data_extraction,
Expand Down Expand Up @@ -108,17 +107,10 @@ def get_picture():
# Local copy of https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png
with open(test_images_dir / "dice.png", "rb") as image:
bytez = image.read()
res = [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": base64.b64encode(bytez).decode("utf-8"),
},
}
]
return ContentToolResult(value=res, model_format="as_is")
return ContentToolResultImage(
value=base64.b64encode(bytez).decode("utf-8"),
mime_type="image/png",
)

chat = ChatAnthropic()
chat.register_tool(get_picture)
Expand Down
Loading