Repository navigation
fix(converter): store the bytes of every Codex tool output image the port names - #42
Merged
Merged
Conversation
…port names
The harbor 0.24.0 port turns an inline image in a Codex tool output list into
a blob placeholder through a throwaway BlobCollector, but the pre-pass
(extract_codex_blobs) lifted only strict input_image data URLs. An MCP image
block ({"type": "image", "data": <base64>, "mimeType": ...}), and an
input_image whose data URL carries parameters or whose base64 is wrapped, got
a placeholder naming a sha256 the corpus blob store never received.
- blobs.codex_tool_image_ref is now the one rule both sides use: harbor's
supported image types (image/jpg read as image/jpeg), a data URL's own
media type winning, whitespace removed before strict decoding. The port's
_inline_image_text calls it; the pre-pass lifts a tool output's MCP image
by it, and an input_image the strict match misses, so the collector holds
the bytes and the index maps them to the output's call_id.
- Message content is unchanged: an image block there is not lifted.
- An image the port calls [image omitted] (unsupported type, bad base64, no
media type, a remote URL) stays in the record untouched.
Placeholder text is byte-identical, so the parity oracle and its
_image_content_forgiven rule are untouched. CONVERTER_SCHEMA_VERSION goes to
8: affected results gain extra.images, their bytes reach the blob store, and
a list the port dumps as JSON holds the placeholder item where it held the
base64. Digest re-pinned.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
fix(converter): store the bytes of every Codex tool output image the port names
Follow-up to #41. The harbor 0.24.0 port turns an inline image in a Codex tool output list into a blob placeholder (
[image sha256:<hex> image/png <n> bytes]) through a throwawayBlobCollector(), but the pre-passextract_codex_blobslifted only strictinput_imagedata URLs. An MCP image block,{"type": "image", "data": <base64>, "mimeType": ...}, got a placeholder naming a sha256 the corpus blob store never received. The same was true of aninput_imagein a tool output whose data URL carries parameters (data:image/png;charset=x;base64,...) or whose base64 is wrapped across lines: the port accepts both, the pre-pass's strict match did not.What changed
domain/blobs.py:codex_tool_image_ref(data, media_type, collector)is the one rule for an inline Codex tool output image, ported from harbor'sCodex._image_media_type/_save_tool_output_image: png, jpeg, gif or webp (image/jpgread asimage/jpeg), a data URL's own media type winning overmimeType, whitespace removed before strict base64 decoding.CODEX_TOOL_IMAGE_MEDIA_TYPESandcodex_tool_image_media_typemoved here fromcodex_conversion.py.function_call_outputandcustom_tool_call_outputlists only: an MCPimageblock by that rule (mimeType, elsemime_type), and aninput_imagethe strict data URL match misses. The collector stores the bytes and the index maps them to the output'scall_id, so the result gains typedextra.images.codex_conversion._inline_image_textcalls the same function, so the placeholder text and the stored blob agree byte for byte.imageblock there is not lifted, since the port reads onlytextfields there), and every image the port calls[image omitted](unsupported type, bad base64, no media type, a remote URL), which stays in the record untouched.Schema version
CONVERTER_SCHEMA_VERSION7 -> 8, digest re-pinned. Placeholder text is byte-identical, but artifacts change for sessions with such images: their results gainextra.images, their bytes reach the blob store, and a tool output list the port dumps as JSON (one element of an unknown type) holds the placeholder item where it held the base64. A bump re-converts the whole corpus on the next materialize.Gates
mise run check: green. 2418 passed, 1 skipped in 279.83s; ruff lint and format, ty, pyright (0 errors), import-linter (7 kept, 0 broken), actionlint, lefthook validate.test_parity_codex.py,test_harbor_oracle.py,test_parity_live.py: 10 passed, 1 skipped (the golden re-freeze helper)._image_content_forgivenis untouched.packages/atif-converter/tests/test_codex_blobs.py, 22 tests: MCP image lifted and indexed in both output kinds;mime_typekey, jpg alias, data URL and data URL parameters, wrapped base64; 8 unlifted cases (bmp, text/plain, bad base64, empty, no media type, remote URL, non-string data, no data); message content untouched;input_imagewith parameters or wrapped base64 lifted in a tool output but not in message content; end to end throughconvert_codex_and_audit, each placeholder's sha256 is a blob inresult.blobswhose bytes hash to it; raw and pre-passed records convert to the same trajectory.Planted defects
src(git stashof both source files): 11 of 21 new tests fail._codex_image_ref: 9 fail.input_imagefallback disabled: 2 fail.blobs.pyalone breaks the import ofcodex_tool_image_refincodex_conversion.py, so collection fails.Risks and what to look at
input_imagefallback goes beyond the plan's MCP-only scope. It closes the same unresolved-placeholder gap for the port's wider data URLs and changes no placeholder text.mimeType, bothtext/plainresources), so this case is unmeasured.input_imagepath still lifts types the port omits (for exampleimage/bmp), as on main.🤖 Generated with Claude Code