Skip to content

feat: parse diffusion worker args natively from sglang's diffusion ServerArgs - #13667

Draft
marckarp wants to merge 2 commits into
ai-dynamo:mainfrom
marckarp:feat/sglang-diffusion-native-args
Draft

feat: parse diffusion worker args natively from sglang's diffusion ServerArgs#13667
marckarp wants to merge 2 commits into
ai-dynamo:mainfrom
marckarp:feat/sglang-diffusion-native-args

Conversation

@marckarp

@marckarp marckarp commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Supersedes #13376

#13376 was auto-closed when its base branch (#13343's) was deleted on merge, and GitHub does not allow reopening it. This PR is the same change rebased onto main (which now contains #13343), plus fixes for all three review comments from #13376:

  • Launchers passing LLM-only flags--skip-tokenizer-init removed from both checked-in diffusion launch scripts, and the video launcher now uses the canonical --tp-size; the repo was swept for other callers passing LLM-only flags to diffusion workers (these two scripts were the only ones)
  • Abbreviated/aliased flags recorded raw — the explicit-args side channel now resolves each flag to its parser destination (--tp 2 correctly lands as tp_size=2), unit-tested
  • num_gpus derivation removed — restored num_gpus = tp_size * dp_size when --num-gpus is not explicitly set; an explicit --num-gpus wins

Additionally, --help on a diffusion worker now prints the diffusion engine's options (plus Dynamo's) instead of the LLM engine options a diffusion worker would reject.

Both launch scripts were executed end to end against sglang 0.5.17: the image launcher serves /v1/images/generations and the video launcher serves /v1/videos (HTTP 200 with generated content in both cases). As a bonus demonstration of the strict parser: an invocation typo (--model instead of --model-path) during validation was rejected with ambiguous option: --model could match --model-path, --model-subfolder, --model-variant, --model-id — previously it would have been silently ignored and the default model loaded.

Overview

Design direction (build on the native diffusion parser, on top of the 0.5.17 bump, now merged via #13343) was agreed in team review.

Image/video diffusion workers currently parse CLI args with the LLM ServerArgs parser, hand-copy 13 fields into a SimpleNamespace stub, and call DiffGenerator.from_pretrained() with 5 hardcoded kwargs. Consequences:

  • Nearly every diffusion engine option (torch compile, quantization, batching, warmup, attention backend, …) is silently stuck at its default.
  • Unknown or LLM-only flags are silently absorbed — a typo'd flag and a working flag are indistinguishable.
  • --enable-torch-compile collides with the same-named LLM flag: it parses into the LLM ServerArgs and never reaches the diffusion config; passing it a value crashes the worker.
  • The stub itself drops flags it claims to carry: --trust-remote-code never reached the engine, and dist_timeout was forced to None, disabling the engine's default distributed-init timeout.

What this PR does

Build the worker CLI from sglang's native diffusion ServerArgs, mirroring how the LLM path builds its CLI from the LLM ServerArgs:

  • diffusion_args.py (new) — native parser + DiffusionWorkerArgs adapter. Engine fields delegate to the natively parsed diffusion ServerArgs; Dynamo-side settings (--served-model-name, --enable-metrics) are registered only when the engine parser does not define them natively, so when sglang ships its own (already on sglang main) it wins automatically. Fields Dynamo's shared worker code probes on any server_args are pinned to inert values. Explicitly-provided flags are passed through the parser's _sglang_explicit_arg_names side channel so resolution never depends on process argv (keeps the module testable and embeddable). Version-tolerant import for the server_args module/package layout change.
  • args.py — diffusion/video workers branch to the native parser before any LLM-specific processing; the stub is deleted.
  • init_diffusion.py — both image and video inits hand the full parsed config to DiffGenerator.from_server_args(), replacing the 5 hardcoded kwargs.
  • Tests — 13 hermetic unit tests (fake engine parser injected via sys.modules; no GPU, no model): parsing, adapter delegation, dynamo-side flag splitting, abbreviation resolution, num_gpus derivation, help routing, loud rejection.

Breaking change / migration

LLM-only flags on diffusion worker command lines — previously silently ignored — now fail at startup with unrecognized arguments. Example: a deployment passing --skip-tokenizer-init to an --image-diffusion-worker must drop that flag. This is the intended contract (same as the LLM path): loud rejection is what makes the newly reachable flags trustworthy. If reviewers prefer a softer landing (warn-and-ignore for one release), that's a small follow-up.

Verification

  • Parser against real sglang 0.5.17 (upstream lmsysorg/sglang:v0.5.17-cu130-runtime): 126 engine fields reachable (previously 5); invalid values rejected with actionable messages (--performance-mode: invalid choice: ... choose from 'manual', 'auto', 'speed', 'memory'); unknown flags rejected loudly; Dynamo-side flags kept out of the engine config.
  • Unit tests: 13/13.
  • Launch scripts executed end to end against sglang 0.5.17: image_diffusion.sh serves /v1/images/generations and text-to-video-diffusion.sh serves /v1/videos (HTTP 200, generated content verified in both).
  • Live image e2e (FLUX.1-schnell, 1×B200): worker boots through the native path; --warmup-mode server — previously unreachable — confirmed active in the resolved engine config and engine logs; /v1/images/generations returns HTTP 200; warm request 0.97 s at 1024².
  • Live video e2e (Wan2.1-T2V-1.3B, 1×B200): worker boots through the native path with --video-generation-worker; full pipeline runs and /v1/videos returns a playable file.
  • Resolved-config diff, stub vs native (107 fields): zero unintended changes. The only diffs were the explicitly passed warmup flags, the two stub bugs now fixed (trust_remote_code, dist_timeout), and a per-boot random port.
  • Assembled check: sglang v0.5.17 image + current dynamo wheel + this branch's files boots a frontend+worker pair and serves image generation end-to-end (HTTP 200). The official container build of this combination lands via CI — which also covers the image_diffusion.sh launch-script run that chore(sglang): bump to 0.5.17 #13343's validation had to skip for lack of model access.

Notes for reviewers

Part of DYN-3974

🤖 Generated with Claude Code

marckarp and others added 2 commits August 20, 2026 17:13
…rverArgs

Image/video diffusion workers previously parsed CLI args with the LLM
ServerArgs parser, hand-copied 13 fields into a SimpleNamespace stub, and
called DiffGenerator.from_pretrained() with 5 hardcoded kwargs. Every other
diffusion engine option (torch compile, quantization, batching, warmup,
attention backend, ...) was silently stuck at its default, and unknown or
LLM-only flags were silently absorbed.

Build the worker CLI from sglang's native diffusion ServerArgs instead,
mirroring how the LLM path builds its CLI from the LLM ServerArgs:

- diffusion_args.py: native parser + DiffusionWorkerArgs adapter. Engine
  fields delegate to the parsed diffusion ServerArgs; Dynamo-side settings
  (--served-model-name, --enable-metrics) are registered only when the
  engine parser does not define them natively, so future native flags win
  automatically. Fields Dynamo's shared worker code probes are pinned
  inert. Explicitly-provided flags are communicated through the parser's
  side channel so resolution never depends on process argv.
- args.py: diffusion/video workers branch to the native parser before any
  LLM-specific processing; the stub is removed.
- init_diffusion.py: hand the full parsed config to
  DiffGenerator.from_server_args() for both image and video workers.

BREAKING: LLM-only flags on diffusion worker command lines (previously
silently ignored) now fail at startup with "unrecognized arguments".
Remove such flags from existing deployment configs.

Verification:
- 126 engine fields reachable on sglang 0.5.17 (previously 5); invalid
  values and unknown flags now rejected with actionable errors
- unit tests 9/9; live image and video deployments on B200 generate
  successfully with --warmup-mode server (previously unreachable)
  confirmed active in the resolved engine config
- resolved-config diff vs the stub path: no unintended changes; the stub
  was also silently dropping --trust-remote-code and nulling dist_timeout,
  both now honored
- assembled check against sglang v0.5.17 + current dynamo wheel: worker
  boots and serves /v1/images/generations end-to-end

Signed-off-by: Marc Karp <mkarp@nvidia.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…chers

Address review findings on the native diffusion arg parsing:

- Resolve each explicitly provided flag to its parser destination instead
  of recording its raw spelling. argparse accepts abbreviations and
  aliases (e.g. --tp for --tp-size); recording the raw text made the
  engine treat the real field as unspecified and fall back to defaults.
- Restore the num_gpus = tp_size * dp_size derivation when --num-gpus is
  not explicitly set. The engine defaults num_gpus to 1 and does not
  derive it from parallelism degrees, so tp/dp > 1 without --num-gpus
  under-allocated.
- Remove the LLM-only --skip-tokenizer-init flag from both checked-in
  diffusion launch scripts (previously silently ignored, now rejected),
  and use the canonical --tp-size in the video launcher.

Also route --help through the diffusion parser when a diffusion worker
flag is present: the Dynamo parser's help printed LLM engine options,
which a diffusion worker now rejects; help and parser must agree.

Verified: 13/13 unit tests; both launchers' argument vectors parse
against real sglang 0.5.17 (old vectors rejected naming the offending
flag); both launch scripts executed end to end against sglang 0.5.17
serve generation requests (image via /v1/images/generations, video via
/v1/videos).

Signed-off-by: Marc Karp <mkarp@nvidia.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 22, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@marckarp
marckarp deployed to external_collaborator August 22, 2026 00:25 — with GitHub Actions Active
@marckarp
marckarp deployed to external_collaborator August 22, 2026 00:25 — with GitHub Actions Active
@github-actions

Copy link
Copy Markdown
Contributor

👋 Hi marckarp! Thank you for contributing to ai-dynamo/dynamo.

Just a reminder: The NVIDIA Test Github Validation CI runs an essential subset of the testing framework to quickly catch errors.Your PR reviewers may elect to test the changes comprehensively before approving your changes.

🚀

@github-actions github-actions Bot added feat external-contribution Pull request is from an external contributor backend::sglang Relates to the sglang backend labels Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend::sglang Relates to the sglang backend external-contribution Pull request is from an external contributor feat size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant