fix(vllm): migrate GLM-Image NIXL config to the stages deploy schema - #12984
Merged
Conversation
The config was the last user of vLLM-Omni's legacy `stage_args` schema, which bypasses the deploy-config resolution in stage_config.py. That resolution is what keeps the AR scheduler class and the `async_scheduling` engine arg in sync: _resolve_scheduler() returns OmniARScheduler for sync and OmniARAsyncScheduler for async, and the caller derives the engine arg from whichever it picked. Bypassing it, the config pinned `scheduler_cls: OmniARScheduler` (the synchronous scheduler) while leaving `async_scheduling` unset, so the engine ran async scheduling against a sync scheduler. The sync scheduler does not populate CachedRequestData.all_token_ids, but the model runner's async-scheduling resume path indexes it unconditionally, killing the AR engine core with a KeyError on the first request. Migrate to the `stages` schema and drop `scheduler_cls` so the matched scheduler/async_scheduling pair is resolved by vLLM-Omni. Topology that GLM_IMAGE_PIPELINE already freezes (stage/model types, model and tokenizer subdirs, input sources, AR->DiT input processor, final-output flags) is removed rather than restated -- this retires the `engine_input_source: []` workaround, since input sources now come from the pipeline. Deployment knobs, env-var device/TP selection, sampling params, and connector wiring are carried over unchanged. The launch script needs no change: --stage-configs-path detects a `stages` document and routes it to the deploy-config loader. Signed-off-by: Guan Luo <41310872+GuanLuo@users.noreply.github.com>
Contributor
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (1)
WalkthroughThe GLM-Image Nixl configuration now uses the deployment configuration schema. It defines deployment-level settings, connectors, and stage edges. The AR and DiT stages use direct deployment-stage fields. ChangesGLM-Image deployment configuration
Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
This comment has been minimized.
This comment has been minimized.
ptarasiewiczNV
approved these changes
Aug 11, 2026
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.
Overview:
GLM-Image AR→DiT disaggregation over NIXL dies on the first
/v1/images/generationsrequest. The AR stage's engine core exits, the requestreturns HTTP 500, and the deployment does not recover:
followed by
Stage-0 replica-0 is deadand[AsyncOmni] Engine dead.Summary
stage_configs/glm_image_nixl.yamlwas the last config on vllm-omni's legacystage_argsschema. That schema bypasses the deploy-config resolution invllm_omni/config/stage_config.py, which is what keeps the AR scheduler classand the
async_schedulingengine arg consistent:_resolve_scheduler()returnsOmniARSchedulerfor sync andOmniARAsyncSchedulerfor async, and the callerderives the engine arg from whichever it selected.
Bypassing that, the config pinned
scheduler_cls: OmniARScheduler— thesynchronous scheduler — and left
async_schedulingunset, so the engine ranasync scheduling against a sync scheduler. The sync scheduler does not populate
CachedRequestData.all_token_ids, but the model runner's async-schedulingresume path indexes it unconditionally. First request, KeyError, dead engine
core.
The
scheduler_clsline dates to #10071 and was plausible when written: thesync/async split in
omni_ar_scheduler.pylanded separately, keeping the oldname for the sync variant while
async_schedulingdefaults on. The only otherplace that line appears upstream is a
platforms.npublock, where it isharmless because the NPU model runner has no
all_token_idsresume path.This migrates the file to the
stagesschema and dropsscheduler_cls, so thematched scheduler /
async_schedulingpair is resolved by vllm-omni rather thanhand-declared.
Details:
#12709 fixed an earlier crash in this same file and named this cause exactly —
"the legacy
stage_argsconfig format applies no schema defaults", and "the SHMvariant is unaffected because it consumes vllm-omni's own packaged config in the
stagesformat, whose parser supplies the default". That fix supplied the onemissing default; this removes the reason defaults go missing at all.
Topology that
GLM_IMAGE_PIPELINEalready freezes is dropped rather thanrestated: stage and model types, model/tokenizer subdirs, input sources, the
AR→DiT input processor, and final-output flags. That retires the
engine_input_source: []workaround from #12709, since input sources now comefrom the pipeline.
async_chunk: falseis now explicit —DeployConfigdefaults it toTrueandGLM-Image declares no async-chunk next-stage processor. This matches vllm-omni's
own
deploy/glm_image.yaml.Deployment knobs, env-var device/TP selection, and sampling params carry over
unchanged. Top-level
connectors:/edges:are thestages-schema spelling ofthe previous
runtime.connectors/runtime.edges; the connector initializernormalizes both to the same internal shape. The dropped
runtime.defaults(
window_size,max_inflight) has no consumer in vllm-omni.The launch script needs no change:
--stage-configs-pathdetects astagesdocument and routes it to the deploy-config loader.
Validation
pre-commit run --files examples/backends/vllm/launch/stage_configs/glm_image_nixl.yaml— clean.pair:
scheduler_cls=OmniARAsyncSchedulerwithasync_scheduling=True.disagg_omni_glm_image_nixl.sh: both stagesstart,
/v1/images/generationsreturns an image, and the AR engine core nolonger dies on the first request.
Where should the reviewer start?
Single file,
-73/+46. The load-bearing change is the absence ofscheduler_cls— everything else is schema translation or removal of topologythe pipeline already owns.
One thing carried over unchanged and worth a second opinion: stage 1's
output_connectors: {to_stage_router: dit_to_router}. Theto_stage_routerkeyappears nowhere in either this repo or vllm-omni, so the DiT→router hop may not
actually be on NIXL. Left as-is here to keep this change to the crash fix;
worth its own issue.
🤖 Generated with Claude Code
Summary by CodeRabbit