Repository navigation
[integration][java][python] Send user images to Ollama - #1178
Conversation
|
The only failure is the ReAct e2e test, which also failed on main: https://github.com/apache/flink-agents/actions/runs/36512441540 |
wenjin272
left a comment
There was a problem hiding this comment.
Thanks for adding Ollama image support and the live tests! I left three comments below based on the review and local testing.
| return base64.b64encode(png).decode() | ||
|
|
||
|
|
||
| @pytest.mark.skipif(not _client_ready(), reason="OLLAMA_VISION_MODEL is not set") |
There was a problem hiding this comment.
Could we add multimodal tests to the existing Java and Python E2E modules, so they run in the it-java and it-python CI jobs?
Unlike the OpenAI tests, these do not require external API credentials: both IT jobs already install and start an Ollama server. With a small vision model provisioned, we can exercise the full agent execution path with real image input in CI, rather than leave this coverage behind an opt-in environment variable.
There was a problem hiding this comment.
Good idea; I'll add Java and Python E2E image tests running in it-java/it-python.
There was a problem hiding this comment.
Added in 4356394: Java and Python E2E tests send a real image through an agent.
| // Without the calls, the history shows tool results the model never requested. | ||
| ollamaMessage.setToolCalls(toOllamaToolCalls(toolCalls)); | ||
| } | ||
| final List<byte[]> images = toOllamaImages(message); |
There was a problem hiding this comment.
Could we preserve the media validation exception types through the public chat() API? toOllamaImages() throws UnsupportedContentBlockException or IllegalArgumentException, but doChat() wraps both in a generic RuntimeException. I reproduced this through chat(), so callers cannot catch the exceptions documented by this PR, unlike the Python implementation.
Please narrow the catch or rethrow runtime exceptions unchanged, and cover these cases through chat() rather than only buildRequest().
There was a problem hiding this comment.
Done in d2bc595: chat() rethrows them unchanged, with tests through chat().
| assertThat(response.getText()).isNotBlank(); | ||
| } | ||
|
|
||
| private static String redSquarePng() throws Exception { |
There was a problem hiding this comment.
Both Java and Python live tests failed locally with Ollama 0.17.5 and qwen3.5:2b: the image processor rejects the 16×16 fixture with height:16 or width:16 must be larger than factor:32. Changing only the image dimensions to 64×64 made both tests pass. Could we use a larger fixture?
Also, both tests inherit think=true, while the suggested qwen2.5vl:3b does not support thinking. Please explicitly configure think=false for that model so the tests exercise image handling rather than fail on an unrelated parameter.
There was a problem hiding this comment.
Done: the fixture is now 64x64 and both live tests set think=false.
f7cf087 to
4356394
Compare
wenjin272
left a comment
There was a problem hiding this comment.
Thanks for addressing my comments. LGTM
Linked issue: #1059
Purpose of change
A user
ChatMessagewith image blocks now reaches Ollama with its images, in Java and Python, so vision models such asqwen2.5vlorllavacan see them. Until now the Ollama connections sent only the text and dropped the images silently. This is the second provider step of #1059 Phase 2, after #1164.Runtime flow
convertToOllamaChatMessagesin Java,__convert_to_ollama_messagesin Python), including assistant tool calls (forwarded in Java since [integration][java] Forward assistant tool calls in the Ollama chat history #1166).ImageBlocks are decoded and attached as the message'simages; any other media throws before the request is sent.imagesfield.Key decisions
/api/chathas onecontentstring and oneimageslist per message, so block order is kept among the images but not between text and images.UnsupportedContentBlockException/UnsupportedContentBlockErrorfrom [integration][java][python] Send multimodal user messages through OpenAI Chat Completions #1164.Behavioral Semantics
Interaction decisions
imagescontent= text projection,images= the images in block orderUnsupportedContentBlockException; nothing sentUnsupportedContentBlockException; nothing sentBehavioral contracts
images.images, in block order, and serialize back to the original Base64 strings.contentis the text projection.UnsupportedContentBlockExceptionnaming the block but not its data or URL.UnsupportedContentBlockException.IllegalArgumentException/ValueError("could not be decoded"), not the unsupported-block error.chat()with their own types; Java no longer wraps runtime exceptions in a plainRuntimeException.Java and Python behave identically for each contract.
Failure behavior
Tests
OllamaMultimodalTesttest_ollama_multimodal.pytestTextOnlyMessageHasNoImagestest_text_only_message_has_no_imagestestBase64ImagesAttachedInBlockOrdertest_base64_images_attached_in_block_ordertestUnsupportedMediaFailsExplicitlytest_unsupported_media_fails_explicitlytestImagesOutsideUserMessagesFailtest_images_outside_user_messages_failtestInvalidBase64Failstest_invalid_base64_failstestChatKeepsMediaErrorTypeschat()MultimodalChatIntegrationTest(it-java)multimodal_chat_test.py(it-python)The end-to-end tests run an agent on Flink whose input row carries a 64x64 PNG, through the chat request event and built-in chat action to the CI Ollama server, with
qwen3.5:2b(about 2.7 GB; override withOLLAMA_VISION_MODEL). Opt-in live tests (OllamaMultimodalLiveTest,test_ollama_multimodal_live.py) send the same image straight through the connection.Not verified:
qwen3.5:2banswering "Red" for the red square.Implementation invariants and supporting evidence
OllamaChatMessage.imagesisList<byte[]>serialized withFileToBase64Serializer; ollama-python 0.6.1Message.imagesholdsImagevalues whose serializer base64-encodes bytes and treats strings as paths first.API
No new API; it uses the
UnsupportedContentBlockException/UnsupportedContentBlockErroradded in #1164.Compatibility: text-only requests are unchanged. User images used to be dropped silently; they are now sent. Other media, and media in non-user messages, now fail instead of being dropped.
Documentation
doc-neededdoc-not-neededdoc-includedA multimodal note in the Ollama section of
chat_models.md, and Ollama added to the provider-support note.Was this patch authored or co-authored using generative AI tooling?
If yes, include a
Generated-by: <tool name and version> (<model name and version>)line, for exampleGenerated-by: Claude Code 2.1.226 (Claude Opus 4.6), in the commit message so it reaches Git history. Repeat the same line here for reviewer visibility. See the ASF generative tooling guidance.Generated-by: Claude Code 2.1.259 (Claude Opus 5.5)