Repository navigation
[integrations][java][python][docs] Send images and documents in tool results to Anthropic - #1331
Merged
Merged
Conversation
…results to Anthropic A tool result holding media is now sent as one tool_result block whose content keeps the result's text, image and document blocks in order, with the same media rules as user messages. A text-only tool result is sent unchanged. Media Anthropic cannot send still fails before the request, with the reason used for user messages. Media in an assistant message still fails; its reason now names tool results as well. The providers page gets a tool-result media table, and the Tool Use warning now names Anthropic as the integration that sends tool media. Generated-by: Claude Code 2.1.309 (Claude Opus 5.5)
wenjin272
approved these changes
Oct 29, 2026
wenjin272
left a comment
Contributor
There was a problem hiding this comment.
Thanks for taking this on. LGTM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked issue: #1216
Purpose of change
The Anthropic integration now sends images and documents returned by a tool to the model, in Java and Python. A tool result holding media becomes one
tool_resultblock whosecontentkeeps the result's text, image and document blocks in order. Before, any media in a tool result failed the request.Tools can return screenshots, charts or documents the model must read before it continues, and Anthropic accepts them inside
tool_result.content. This is the first part of the plan in the issue; the other integrations still reject media in tool results. The fields below cover the adapter change; the docs part adds a tool-result media table to the providers page and updates the Tool Use warning.Runtime flow
Java:
AnthropicChatUtils.convertToAnthropicMessagepasses a tool message toconvertToolResult. A result of onlyTextBlocks is sent ascontent(String), the concatenated text, as before. Otherwise each block becomes aToolResultBlockParam.Content.Blockin order:ofText,ofImagethroughtoImageBlockParam(now shared with user messages), orofDocumentthrough the existingtoDocumentBlockParam. Other media throws.Python:
convert_to_anthropic_messagealready built thetool_resultcontent from the result's blocks; its media check now accepts tool messages too, so_to_media_blockruns for them.Key decisions
ToolResultBlockParam.Content.Block.ofImage/ofDocument, and the Python adapter sends plain dicts.Behavioral Semantics
Interaction decisions
tool_result.contentblocks in orderBehavioral contracts
tool_resultblock:tool_use_idis the call ID,is_errorthe result's flag, andcontentits blocks in order:TextBlockastext,ImageBlockasimage,DocumentBlockasdocumenttitled by the block'sname.UnsupportedContentBlockException(Java) /UnsupportedContentBlockError(Python) with the same message as in a user message. The message names no URL or data.IllegalArgumentException/ValueError, not the unsupported type.only user messages and tool results can carry media, not assistant messages.tool_resultblock with its own call ID and content, text-only or not.Failure behavior
Every failure above is raised while the request is built, so nothing is sent; media is never dropped or stringified. Java
chat()rethrowsUnsupportedContentBlockExceptionunchanged and wraps other build errors inRuntimeException, as for user messages. Media the model rejects comes back as the service's error.Tests
AnthropicMultimodalTest/ Pythontest_anthropic_multimodal.pytestToolResultMediaIsSentInOrder/test_tool_result_media_is_sent_in_order;testErrorToolResultWithMedia/test_error_tool_result_with_mediatool_resulttestTextOnlyToolResultIsUnchanged(exact JSON) /test_text_only_tool_result_is_unchangedtestUnsupportedToolResultMediaFailsAsForUserMessages/test_unsupported_tool_result_media_fails_as_for_user_messagestestInvalidBase64TextDocumentInToolResultFails/test_invalid_base64_text_document_in_tool_result_failstestMediaInAssistantMessagesFails/test_media_in_assistant_messages_failstestParallelToolResultsKeepTheirCorrelation/test_parallel_tool_results_keep_their_correlationtest_anthropic_reads_image_returned_by_tool(test_anthropic_chat_model.py): a tool returns a red PNG; the answer must say "red"Coverage by risk: each accepted media kind and source appears in a tool result in both languages, and each unsupported kind is compared with its user-message error.
Not verified:
TEST_API_KEY(an Anthropic key). CI doesn't run it: no workflow sets that variable, and secrets aren't passed to fork PRs. It has not been run locally either.Test runs, test-file changes and implementation invariants
mvn -B test -pl integrations/chat-models/anthropic: 118 passed (AnthropicMultimodalTest13).pytest -k "not e2e_tests" -m "not integration" flink_agents/integrations/chat_models/anthropic flink_agents/api: 1201 passed, 15 skipped. Whole unit suite: 2877 passed, 16 skipped../tools/lint.sh --check(ruff 0.11.13, Spotless),ruff format --checkand./tools/check-license.shpass.TEST_MODELor the default model.allMatch(TextBlock), so an empty result is still sent as"".ToolResultBlockholds only text and media blocks, so no other block type reachestoToolResultContent.ToolResponse.error(...)builds a text-only result, so media withis_errorcomes only from aToolResultBlockbuilt directly.API
No signature or dependency change. For a caller who changes nothing: text-only tool results are sent unchanged; supported media in a tool result is now sent instead of raising; unsupported media still raises the same type, now with the user-message reason instead of
only user messages can carry media, not tool messages. The assistant reason adds "and tool results".Documentation
doc-neededdoc-not-neededdoc-includedWas this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code 2.1.309 (Claude Opus 5.5)