Skip to content

[Feature] Omni disagg: connector plumbing and downstream handlers - #6893

Draft
RishabhSaini wants to merge 4 commits into
vllm-project:mainfrom
RishabhSaini:standalone-omni-disagg
Draft

RishabhSaini wants to merge 4 commits into
vllm-project:mainfrom
RishabhSaini:standalone-omni-disagg

Conversation

@RishabhSaini

@RishabhSaini RishabhSaini commented Sep 1, 2026 •

Copy link
Copy Markdown

Purpose

Extends standalone stage mode (#6883) to support omni multi-stage disaggregation across separate pods.

Ref #6389

Problem

PR 1 (#6883) enables TTS disagg with inline JSON transfer. Omni disagg (thinker → talker) transfers hidden state embeddings (float tensors, 1-15MB) which is impractical inline. The data needs to go through connectors (Mooncake/Mori RDMA) with the coordinator passing only a small transfer handle — the same pattern vLLM P/D uses for KV cache via kv_transfer_params.

Solution

Reuse kv_transfer_params end-to-end. No new fields or protocols.

The flow:

  1. Thinker's model runner caches its connector endpoint info (host, zmq_port) at init.
  2. Scheduler populates kv_transfer_params on finished requests using this connector info (fallback when the KV connector returns None).
  3. Chat/speech handler includes kv_transfer_params in the response — already wired, no handler changes.
  4. Coordinator reads the handle, forwards it in the downstream request body as opaque bytes.
  5. Downstream engine extracts it from SamplingParams.extra_args (same as P/D).
  6. register_chunk_recv stashes per-request sender info. The recv thread passes it as metadata to connector.get() Path 2, enabling multi-thinker routing.

Other changes

Downstream handlers (serving_stage.py): Two modes — run_downstream_audio (final stage → WAV) and run_downstream_intermediate (middle stage → stage_output JSON). Coordinator signals via output_mode.

clear_connectors param: extract_standalone_stage_config(clear_connectors=False) preserves original stage_id (connector keys depend on it), connectors, and custom_process_next_stage_input_func (controls embedding accumulation). Default True preserves PR 1 TTS behavior.

Backward compatibility

All None defaults — orchestrator-managed deployments see no behavior change. SharedMemoryConnector (no get_connection_info) returns None, correctly preventing cross-pod handles for same-node-only connectors.

Limitations

  • Connector E2E not tested (needs Mooncake/Mori infra + Qwen3-Omni)
  • Standalone omni requires a cross-network connector deploy YAML (not SharedMemory)

Test Plan

  • clear_connectors=False preserves stage_id, connectors, producer hook
  • clear_connectors=True clears (backward compat)
  • Codec token transposition (codebook-major order)
  • Per-request sender stashed and cleaned up correctly
  • Recv methods forward metadata kwarg to connector.get()
  • Orchestrator-managed requests use default sender (no override)
  • TTS E2E not regressed
  • Omni E2E with connectors (needs infra)

Test Result

23/23 unit tests passed. TTS E2E verified on 2x NVIDIA H200.

Follow-on work

Async-chunk streaming for standalone stages, so the upstream stage streams frames directly to the downstream stage and recovers the ~92% TTFP reduction that standalone mode loses today.

Image gen disagg for BAGEL and HunyuanImage3, which needs CFG companion fan-out/fan-in.

This PR reuses kv_transfer_params for omni embedding transfer handles since the field is already wired end-to-end. If the community prefers a dedicated stage_transfer_params field, the change is mechanical.

Add --standalone flag that boots any single pipeline stage as an
independent HTTP server for disaggregated multi-stage serving.

- extract_standalone_stage_config() utility extracts one stage from a
  multi-stage OmegaConf config, adjusting stage_id, final_output,
  clearing connectors and next-stage transforms
- Engine fixes: postprocess() for latent-output stages, generate in
  supported_tasks for non-tokenizer stages
- /v1/stage/run endpoint with entry mode (wraps speech handler, returns
  raw stage_output JSON) and downstream mode (accepts codec tokens,
  returns WAV audio)
- Standalone gate: endpoint returns 404 on non-standalone servers
- Client disconnect abort, codec size validation, sample rate from model

Ref: vllm-project#6389
Signed-off-by: RishabhSaini <rishabhsaini01@gmail.com>
Server launch script (run_standalone_servers.sh) and reference
coordinator client (standalone_disagg_client.py) that chains
talker → code2wav over /v1/stage/run. Uses httpx, matching
existing example patterns. No external deps beyond vllm-omni.

Signed-off-by: RishabhSaini <rishabhsaini01@gmail.com>
Tests for extract_standalone_stage_config (stage extraction, connector
clearing, transform stripping, input processor preservation,
final_output_type inference) and CLI validation (--standalone requires
--stage-id, mutually exclusive with --headless).

12 tests, all CPU-only (core_model marker).

Signed-off-by: RishabhSaini <rishabhsaini01@gmail.com>
@RishabhSaini
RishabhSaini force-pushed the standalone-omni-disagg branch from a9732e9 to ddc8460 Compare September 1, 2026 04:13
…_connectors

- Add kv_transfer_params flow for standalone omni disagg: connector_info
  on OmniConnectorOutput → scheduler populates kv_transfer_params on
  finished requests → chat/speech response carries it → coordinator
  forwards to downstream stage → per-request sender resolution in recv
  thread via connector.get(metadata=...)
- Extract downstream handlers to serving_stage.py (audio final +
  intermediate mode)
- Add clear_connectors param to extract_standalone_stage_config
- Initialize _per_request_sender in mixin __init__, add to prune scan
- Tests for clear_connectors, serving_stage utilities, connector plumbing

Ref vllm-project#6389

Signed-off-by: RishabhSaini <rishabhsaini01@gmail.com>
@hsliuustc0106 hsliuustc0106 added core related to core module: cache, scheduler, engine, worker, modelrunner omni code related to omni models enhancement New feature or request labels Sep 2, 2026
@hsliuustc0106

Copy link
Copy Markdown
Collaborator

This PR touches vllm_omni/entrypoints/, vllm_omni/core/, examples/online_serving/, vllm_omni/worker/, tests/entrypoints/ (14 files). Based on CODEOWNERS coverage of the changed files, the most-related reviewers appear to be:

@Gaohan123 @Sy0307 @fake0fan

Could one of you take a look when you get a chance? Thanks!

@RishabhSaini

Copy link
Copy Markdown
Author

Follow-ons from #6883 review to pick up:

  1. clear_connectors param preserves connectors/input_sources when False (review), already in this PR
  2. Move extract_standalone_stage_config logic inside the engine (review)
  3. Align NPU latent broadening with GPU, NPU checks == "audio" but GPU checks in ("audio", "latent") (review)
  4. OmniSerializer for connector transport (review)

Copy link
Copy Markdown
Collaborator

@RishabhSaini Are you planning to continue work on this PR? Please reply by 2026-10-20 04:14:48 UTC.

A yes or a brief plan is enough; code changes do not need to be finished within these three days. If you are waiting on a review or other maintainer action, please let us know.

If there is no reply, new commit, or maintainer takeover by then, we will recheck the PR's status before deciding whether to close it as inactive. It can be reopened when work resumes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core related to core module: cache, scheduler, engine, worker, modelrunner enhancement New feature or request omni code related to omni models

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants