[api][java][python] Align multimodal message contracts and safe logging - #1163
Merged
Merged
Conversation
wenjin272
force-pushed
the
codex/multimodal-contract-fixes
branch
from
September 28, 2026 03:53
2d83149 to
6e1d41f
Compare
Zhuoxi2000
reviewed
Sep 28, 2026
Zhuoxi2000
left a comment
Contributor
There was a problem hiding this comment.
Structured output now matches Python; the message validation looks consistent. Could MediaFieldDeserializers be package-private? Jackson still instantiates its nested deserializers.
wenjin272
force-pushed
the
codex/multimodal-contract-fixes
branch
from
September 28, 2026 04:33
6e1d41f to
b619b3d
Compare
Preserve structured-output blocks, validate media fields consistently across languages, reject invalid block collections, and avoid logging raw media sources. Add regression coverage and document the contracts. Generated-by: Codex (model/version not exposed) Co-authored-by: Codex <codex@openai.com>
wenjin272
force-pushed
the
codex/multimodal-contract-fixes
branch
from
September 28, 2026 04:48
b619b3d to
3e06a62
Compare
Contributor
Author
|
Thanks @Zhuoxi2000! Made MediaFieldDeserializers package-private, keeping its nested deserializers public. All 23 targeted message tests pass, including JSON and map deserialization coverage. Updated in 3e06a62. |
Merged
5 tasks
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: #1059 (follow-up to #1060; the tracking issue remains open)
Purpose of change
Preserve multimodal responses during Java structured-output parsing, prevent raw media from appearing in the Python chat failure debug message, and align Java/Python media field validation.
Runtime flow
Java structured-output parsing reads the text projection, parses it into the requested schema, and returns a message preserving the original blocks and tool calls with the parsed value added to
extraArgs. Python's terminal FAIL path logs the request ID and message count, then rethrows the original exception. Media construction/deserialization validates field types before messages enter normal JSON, bridge, or state paths.Key decisions
Behavioral Semantics
Interaction decisions
Behavioral contracts
size_bytesaccepts only integers in[0, 2^63 - 1]or null.Failure behavior
Invalid media fields and block collections raise construction/deserialization errors rather than being coerced or dropped. Failed block replacement leaves existing blocks unchanged. Python
validate_assignmentapplies to every ChatMessage field, not only blocks. Structured-output parse errors and chat retry policy are unchanged. This is not blanket log sanitization: arbitrary exception text and generic maps are outside these guarantees. Restoring Python-originated built-in Event types remains separately tracked in #1125.Tests
structuredOutputPreservesOriginalBlocks; Pythontest_structured_output_preserves_original_blockstest_media_representations_hide_payloads_but_wire_preserves_them; Javabase64PayloadPreservationAndSafeRepresentationsmediaFieldsRejectScalarCoercionOnJsonAndMapPaths; Python media-string/source/size parameterized testsnullBlocksFailAtEveryEntryPoint; Python null construction/assignment and list-copy/append/dump teststestOmittedBlocksDefaultToEmptyButExplicitNullIsRejectedtest_base64_preserves_unvalidated_payloadandtest_base64_size_and_wire_preservationCoverage focuses on wire compatibility, map conversion, accidental media disclosure, and content preservation. Python API/Plan/runtime-tests regression: 1046 passed, 13 skipped. Final Java targeted regression: 122 tests, 11 skipped, zero failures/errors, covering message JSON, structured output, prompt maps, resource adapter, Event Log, and state serde.
Not verified: live provider calls, full E2E jobs, skipped cross-language snapshot cases, non-empty tool-call preservation during structured-output parsing, exhaustive assignment validation for non-block fields, or generic-map Event Log sanitization. No provider converter or Event-type restoration is implemented here.
Verification commands and implementation details
mvn test -pl runtime -am -Dtest=ChatMessageSerializationTest,ChatMessageTest,ChatModelActionTest,PythonPromptTest,JavaResourceAdapterTest,FileEventLoggerTest,ActionStateSerdeTest,CrossLanguageEventSnapshotTest -Dsurefire.failIfNoSpecifiedTests=false(JDK 17; rebuilds changed sources).PYTHONPATH=<venv-site-packages> python/.venv/bin/pytest -q python/flink_agents/api python/flink_agents/plan python/flink_agents/runtime/tests -m 'not integration'.git diff --checkpasses.model_dump()continue emitting lists.API
Wire shape is unchanged. Inputs relying on scalar coercion, invalid sizes, or Java null block lists are now rejected; Python field reassignment is now validated. Python list append remains available. Java structured output retains original text formatting instead of replacing it with cleaned JSON text. URL diagnostic strings become redacted. Normal JSON/state/bridge serialization retains the original media data and URL.
Documentation
doc-neededdoc-not-neededdoc-includedWas this patch authored or co-authored using generative AI tooling?
Generated-by: Codex (model/version not exposed)