Problem / current state
Parent architecture epic: #493. Scoping design: #503 and spike/openxla/MULTIMODAL_VLM_DESIGN.md.
The current OpenXLA/IREE path is still text-only at the request boundary, but the implementation has evolved beyond the original 2025 design assumptions:
src/lib/mlxcel-xla/src/emitter/model.rs has a mature shared text layer stack, but token prefill still gathers embed[tokens]; there is no embeddings-prefill entry.
src/lib/mlxcel-xla/src/emitter/model.rs and src/lib/mlxcel-xla/src/iree.rs hard-code a 256-token context/prefill shape. A normal LLaVA image alone contributes 576 or 729 patch tokens at common resolutions, before text and generation headroom.
src/lib/mlxcel-xla/src/iree.rs and src/lib/mlxcel-xla/csrc/xla_iree.c load only token-prefill/decode modules, and XlaBatchEngine::Pending owns only token IDs.
src/backend/session.rs has an XLA path that can ignore supplied input embeddings and run token-only generation. Multimodal support must fail closed until the real path exists.
src/server/batch/xla_worker.rs rejects images, audio, and video. spawn_xla_model_worker owns no VLM/audio preprocessor.
- The mature MLX stack returns
MlxArray-backed InputEmbeddings; its VLM loaders commonly construct a full text decoder. XLA needs an owned backend-neutral payload and filtered processor/encoder/embedding loading, not a duplicate decoder.
- Qwen M-RoPE, Qwen3 DeepStack, Gemma3 additive masks, Molmo sparse/indexed pooling, and Youtu windowed vision have different contracts and cannot be represented by one generic “merge image tokens” task.
- Phi4MM and Gemma3n audio are not currently executable reference paths in mlxcel. Phi4MM explicitly rejects audio placeholders and skips audio/speech-LoRA weights; Gemma3n loads text/vision but no audio tower. Their MLX reference implementations must be qualified before XLA ports.
Goal
Accept supported multimodal requests on the OpenXLA/IREE backend and produce reference-correct output through CLI and continuous-batch OpenAI-compatible serving, while preserving text-only behavior and using explicit, bounds-checked contracts for:
- compiled context capacity and admission;
- prefill from owned embeddings, positions, masks, and optional family side inputs;
- host preprocessing without a duplicate full decoder;
- IREE encoder/projector execution where required;
- per-request/slot multimodal state, cancellation, metrics, and capability truth;
- independent intermediate and token-exact architecture validation.
Implementation DAG
GitHub native sub-issue and blocked-by relationships are authoritative. The checklist below is a readable index.
A. Independent foundation / oracle work
B. Core runtime and first end-to-end image path
C. Family-side language contracts
D. Vision-family breadth
E. Audio serving and XLA execution
Architectural invariants
- Text prefill, embeddings prefill, family-specific prefill, and decode are separate versioned module contracts; no path accepts a tensor and then ignores it.
- Compiled context capacity, dtype, architecture config, position/mask mode, KV layout, encoder shape buckets, and side-input schema participate in artifact compatibility.
- Logical token IDs remain available for penalties, detokenization, stop matching, and public usage accounting; expanded multimodal length owns cache admission/positioning.
- Host preprocessors return owned contiguous tensor descriptors and may retain only required processor/encoder/projector/embedding weights, never a duplicate full decoder.
- Media acquisition/decode/resampling follows existing security and size limits in a bounded cancellable stage outside the scheduler loop.
- All request-specific M-RoPE deltas, DeepStack/PLE tensors, audio modes/adapters, and large host buffers are slot-scoped and cleared on prefill completion, cancellation, error, and slot reuse.
- Host-first execution is an explicit qualified fallback/oracle. An IREE-capable family may not silently execute its encoder on MLX.
- A family is advertised in
SessionCapabilities only when model weights/config, processor, runtime modules, and execution dispatch all support it through the same predicate.
Validation and merge gates
- Every emitter task needs structural/golden IR tests and a real IREE execution; emitter-string success alone is insufficient.
- Every family pins checkpoint/source revisions, deterministic media/prompts, dtype-specific intermediate tolerances, and token-exact greedy output.
- Compare processor outputs, encoder/projector intermediates, merged embeddings/positions/masks/side inputs, prefill logits, selected all-layer KV values, and final tokens. Report the first divergent stage.
- Exercise non-streaming CLI and streaming server paths, including mixed text/multimodal batching, cancellation, slot reuse, capacity overflow, malformed media, and per-request failure isolation.
- Run the existing text-only XLA architecture oracle and continuous-batch suites for every merge.
- Record target/device, commands, compile time, host/device memory, transfers, prefill latency, and decode throughput for real IREE qualification.
Epic acceptance criteria
References
Problem / current state
Parent architecture epic: #493. Scoping design: #503 and
spike/openxla/MULTIMODAL_VLM_DESIGN.md.The current OpenXLA/IREE path is still text-only at the request boundary, but the implementation has evolved beyond the original 2025 design assumptions:
src/lib/mlxcel-xla/src/emitter/model.rshas a mature shared text layer stack, but token prefill still gathersembed[tokens]; there is no embeddings-prefill entry.src/lib/mlxcel-xla/src/emitter/model.rsandsrc/lib/mlxcel-xla/src/iree.rshard-code a 256-token context/prefill shape. A normal LLaVA image alone contributes 576 or 729 patch tokens at common resolutions, before text and generation headroom.src/lib/mlxcel-xla/src/iree.rsandsrc/lib/mlxcel-xla/csrc/xla_iree.cload only token-prefill/decode modules, andXlaBatchEngine::Pendingowns only token IDs.src/backend/session.rshas an XLA path that can ignore supplied input embeddings and run token-only generation. Multimodal support must fail closed until the real path exists.src/server/batch/xla_worker.rsrejects images, audio, and video.spawn_xla_model_workerowns no VLM/audio preprocessor.MlxArray-backedInputEmbeddings; its VLM loaders commonly construct a full text decoder. XLA needs an owned backend-neutral payload and filtered processor/encoder/embedding loading, not a duplicate decoder.Goal
Accept supported multimodal requests on the OpenXLA/IREE backend and produce reference-correct output through CLI and continuous-batch OpenAI-compatible serving, while preserving text-only behavior and using explicit, bounds-checked contracts for:
Implementation DAG
GitHub native sub-issue and
blocked-byrelationships are authoritative. The checklist below is a readable index.A. Independent foundation / oracle work
prefill_embeddings.mainwith explicit additive attention bias and token-prefill parity.B. Core runtime and first end-to-end image path
C. Family-side language contracts
D. Vision-family breadth
image_patch_idmerge. Blocked by test(xla): validate a LLaVA reference architecture end to end #862 and feat(xla): define operator-level MLX/IREE numeric contracts #932.E. Audio serving and XLA execution
Architectural invariants
SessionCapabilitiesonly when model weights/config, processor, runtime modules, and execution dispatch all support it through the same predicate.Validation and merge gates
Epic acceptance criteria
References
spike/openxla/MULTIMODAL_VLM_DESIGN.md