Inline raw multimodal images in the v1 train client#2120
Draft
eligotts wants to merge 19 commits into
Draft
Conversation
Every image carries its ref, so no cache miss can occur. Removes _generate_with_image_ref_retry / _has_descriptor_only_images / _retryable_mm_error_type / _json_error_type / _RETRYABLE_MM_ERROR_TYPES; rollouts call generate() directly. Obsolete retry tests removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fload # Conflicts: # verifiers/v1/clients/train.py
…fload # Conflicts: # verifiers/v1/cli/dashboard/eval.py
- prepare_images_inplace handles the full renderer part treaty: nested image_url dicts, direct-string image_url, direct image strings, and typed pydantic parts; non-string sources raise with the shape named. - Interception server labels prepare_messages failures as InterceptionError instead of misattributing them to the user simulator. - Test covers all shapes plus http rejection (skips until the renderers pin ships mm_store). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fload Reconciles this branch's raw-image offload work with main's independent retry-coalescing and harness-segment-resume refactor of the interception server, and its v1 trace/graph model evolution: - interception/server.py: main's single-shot handle_request (graph-atomicity retry coalescing) and _stream (record_call/error tracking, tools threading) are authoritative. Dropped this branch's obsolete mid-request user-simulator injection (session.user/session.opening, prepare_messages call sites) — main's d21100b moved that to Harness.launch/resume, so injected messages now re-enter as normal request bodies already covered by prepare_request_body (kept, re-wired at the top of handle_request). - graph.py: kept finish_reason/usage/multi_modal_data/previous_multi_modal_data (this branch) alongside main's SkipJsonSchema wrapping convention and commit()'s new (tools, -> assistant node id) signature. Caught and fixed an auto-merge dropping the FinishReason/Usage imports (caused a pydantic model-not-fully-defined failure at Trace construction). - trace.py: kept this branch's more accurate multi_modal_data docstring; took main's tuple-based bridge-mutation assertion in the test suite. - ARCHITECTURE.md: main deleted this file (moved to the shorter docs/v1/ architecture.md, which doesn't cover this depth of internals) — accepted the deletion; folded the one load-bearing fact (why multi_modal_data is JSON-excluded) into _NODE_DUMP_EXCLUDE's docstring instead of resurrecting a dedicated architecture doc. Full suite (with local renderers checkout, minus PRIME_API_KEY-gated e2e): all passing.
Its only callers were the interception server's mid-request user-simulator injection sites, which main's harness-segment-resume refactor removed — resumed user turns now re-enter as ordinary request bodies, already covered by prepare_request_body at request ingress.
Intermediate storage mode: base64 data images stay inline in messages through the interception server, trace graph, and rollout records; raw descriptor sidecars carry the inline source (raw_image_data) instead of file:// run-asset URIs. - Removed verifiers/utils/multimodal.py (the ingress offload walker), the Client.prepare_request_body hook, its TrainClient override, and the interception server's request-preparation step. - graph.py sidecar validation requires the inline raw_image_data field; processed-tensor payloads are still rejected. - v0 renderer_client passes messages through unmodified. Suite (with the inline renderers checkout, minus PRIME_API_KEY-gated e2e/envs): all passing.
There was a problem hiding this comment.
🟡 Medium
verifiers/verifiers/v1/graph.py
Line 633 in 6e09559
The assistant node created in _commit_turn omits finish_reason and usage, so every committed response records finish_reason=None and usage=None even though Response carries those values. Truncation detection and provider usage/cost dashboards cannot work because the data is silently dropped. The MessageNode.model_construct(...) call for the assistant node needs to pass finish_reason=response.finish_reason and usage=response.usage.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @verifiers/v1/graph.py around line 633:
The assistant node created in `_commit_turn` omits `finish_reason` and `usage`, so every committed response records `finish_reason=None` and `usage=None` even though `Response` carries those values. Truncation detection and provider usage/cost dashboards cannot work because the data is silently dropped. The `MessageNode.model_construct(...)` call for the assistant node needs to pass `finish_reason=response.finish_reason` and `usage=response.usage`.
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.
Summary
Intermediate multimodal storage mode — the inline bundle. Keeps the v1 raw-descriptor training contract (sidecars carry renderer descriptors + hashes + placeholders; processed tensors are rejected) but base64 data images stay inline in message content end to end — no ingress offload, no shared image directory.
verifiers/utils/multimodal.py(the ingress offload walker), theClient.prepare_request_bodyhook, itsTrainClientoverride, and the interception server's request-preparation step: requests flow to the model boundary unmodified.graph.pysidecar validation requires the inlineraw_image_datafield on raw descriptors; processed-tensor payloads (pixel_valuesetc.) are still rejected.renderer_clientpasses messages through unmodified.results.jsonlon multimodal runs).Relationship to the offload bundle
Cut from the offload branch (#1746); same processor-ownership architecture (renderer geometry math, vLLM-front + trainer materialization in prime-rl), minus the storage layer. The offload bundle (renderers #89 / verifiers #1746 / prime-rl #2836) adds content-addressed
file://offload at ingress on top of this contract.Companion inline PRs: renderers #110, prime-rl
feat/v1-inline-mm.Validation
PRIME_API_KEY-gated e2e/envs): all passing.Note
Inline raw multimodal images in the v1 train client bridging path
TrainClient.generateso bridging is now allowed for prompts with images; multimodal renderers receive concatenated previous-turn multimodal sidecars viaprevious_multi_modal_dataduringbridge_to_next_turn.graph.pythat multimodal sidecars are raw image descriptor dicts (containingraw_image_data), rejecting processed payloads withpixel_values,image_embeds, orimage_featuresat (de)serialization time._attribute_mmto track per-modality placeholder ranges alongside items and hashes, and exposes these viaPendingTurn.previous_multi_modal_dataandBranch.multi_modal_data.multi_modal_datathrough the legacy token conversion path inlegacy.pyand includes live trajectory in legacy rollout outputs.TypeError/ValueError.📊 Macroscope summarized 6e09559. 6 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.