Skip to content

feat(frontends): add the Shepherd Model Gateway (SMG) router - #38

Closed
cquil11 wants to merge 17 commits into
mainfrom
feat/smg-frontend
Closed

cquil11 wants to merge 17 commits into
mainfrom
feat/smg-frontend

Conversation

@cquil11

@cquil11 cquil11 commented Oct 1, 2026 •

Copy link
Copy Markdown
  • Add frontend.type: smg for Shepherd Model Gateway, reusing StaticRouterFrontend for launch, worker registration, and readiness.
  • Support aggregated SGLang, vLLM, and TRT-LLM workers. P/D supports SGLang with bootstrap rendezvous and vLLM over gRPC with NIXL. TRT-LLM P/D is unsupported.
  • Probe HTTP workers on /health and gRPC workers over TCP before starting SMG. Check registered worker counts through /workers.
  • Manage SMG's separate Prometheus port and use each engine's native worker metrics endpoint for Tachometer and AIPerf.
  • Keep one API endpoint per multi-node vLLM DP deployment when the frontend uses direct workers without expanding node-local DP pools.
  • Run the recipe's setup_script in the router container. Add documentation and five examples using SMG v1.11.0, including a separate frontend.container_image option.

Validation

agentx-fast against srt-slurm dba469b6 through InferenceX #3665.

Scenario Cluster Run Result
SGLang aggregated b300-dsxe 36971299038 Passed
SGLang 1P1D, Mooncake gb300-nv 36971304852 Passed
vLLM DEP16, 2 nodes b200-nscale 36971310560 Passed
vLLM 1P1D, gRPC + NIXL gb300-nv 36971316742 Passed
TRT-LLM aggregated, 2 nodes b200-nscale 36971322666 Passed

Note

Medium Risk
New frontend type touches launch topology, health gates, and metrics scraping across engines; misconfiguration is mostly caught at recipe load, but P/D and gRPC paths add operational complexity.

Overview
Adds frontend.type: smg so jobs can run the engine-agnostic Shepherd Model Gateway in front of static worker URLs (aggregated SGLang/vLLM/TRT-LLM, SGLang HTTP P/D with bootstrap ports, vLLM gRPC+NIXL P/D). Recipe validation rejects unsupported P/D mixes (e.g. TRT-LLM P/D, HTTP vLLM P/D).

Orchestration and readiness: SMGFrontend extends the static-router path—smg launch with managed --prometheus-port, optional frontend.container_image and setup script in the router container, HTTP /health or TCP probes for gRPC workers before start, and readiness via GET /workers counts.

Metrics and topology: Frontends gain worker_metrics_path(backend, mode) so Tachometer/AIPerf scrape each engine’s route (/metrics vs TRT-LLM /prometheus/metrics; none for gRPC). Backends expose prometheus_metrics_path and is_grpc_mode; static routers advertise grpc:// when needed. vLLM drops bootstrap port allocation where KV uses NIXL, and multi-node DP behind non–DP-expanding frontends stays one API URL on the leader.

Docs (docs/smg.md), schema updates, five examples, launch snapshots, and tests cover the new frontend.

Reviewed by Cursor Bugbot for commit ad0eef7. Bugbot is set up for automated code reviews on this repo. Configure here.

@cquil11
cquil11 requested a review from ishandhanani as a code owner October 1, 2026 21:56
@cquil11
cquil11 changed the base branch from main to chore/sync-upstream-20261001 October 1, 2026 22:27
@cquil11
cquil11 removed the request for review from ishandhanani October 1, 2026 22:28
@cquil11
cquil11 changed the base branch from chore/sync-upstream-20261001 to main October 2, 2026 01:31

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/srtctl/frontends/static_router.py Resolved

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/srtctl/frontends/static_router.py Resolved

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Register frontend.type: smg, a StaticRouterFrontend that launches
`smg launch` with the allocated worker URLs: --worker-urls for aggregated
workers of any backend, --pd-disaggregation with --prefill URL BOOTSTRAP_PORT
and --decode URL for prefill/decode. Readiness counts SMG's GET /workers
registry, workers are probed before SMG starts, and the Prometheus listener
is bound on SMG_METRICS_PORT and scraped by tachometer.

Add docs/smg.md, a vLLM aggregated and an SGLang P/D example with their
launch snapshots, and tests.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
Share vLLM Router's setup-script preamble as setup_script_preamble in
static_router.py and use it for SMG too, so a recipe can pip install smg
into the model image instead of pulling a separate router image.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
A direct vLLM worker behind a router that does not expand node-local DP
pools (smg) is one vllm serve that balances its DP ranks itself: the
leader node serves the API and the other nodes run headless ranks. The
backend gave every node of such a DP endpoint an HTTP port, so SMG was
handed the headless nodes' URLs too. Keep the standard topology (an
HTTP port on the leader only) for every direct worker launch except
routers that expand node-local DP, as frontend.type: vllm already did.

Add examples/vllm/smg-dep16.yaml (two-node DP16 with EP behind SMG)
and document why SMG's --dp-aware rank pinning is not used for vLLM
HTTP workers.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
Promote is_grpc_mode(mode) to BackendProtocol. SGLang keeps grpc-mode,
vLLM answers roles.<role>.args.grpc (vllm serve --grpc, served by
smg-grpc-servicer), and the HTTP-only engines answer False.
StaticRouterFrontend.worker_scheme now picks grpc:// from that one hook
for every static router, so sglang-router's override goes away and smg
advertises gRPC workers the same way.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
…tarts

The pre-start probe only polled HTTP /health, so gRPC workers were
handed to the router before they were up. Wait for a gRPC worker's
port to accept connections instead (vLLM's gRPC server binds it after
the engine starts), within the same health-check budget.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
The mock orchestrator patches every readiness wait; the gRPC worker
port probe added to StaticRouterFrontend.start_frontends was not, so a
dry run of a gRPC recipe waited out the health-check budget.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
SMG learns a vLLM worker's KV connector only over gRPC (the servicer
reports kv_transfer_config in GetServerInfo), so vLLM P/D behind SMG
uses grpc: true workers with engine.connector: nixl; SMG tags the
prefill leg for a remote decode and relays the NIXL handoff to decode.
Add examples/vllm/smg-disagg-grpc.yaml, its snapshot, and docs.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
Signed-off-by: Cam Quilici <cjquilici@gmail.com>
trtllm-serve serves Prometheus text at /prometheus/metrics; its /metrics is
JSON iteration stats. A static router in front of trtllm-serve workers
advertised /metrics for them, so the tachometer targets and the AIPerf
metrics URLs read the wrong route.

Each backend now names its native server's Prometheus path
(native_metrics_path), and frontends answer the worker path through
worker_metrics_path(backend): Dynamo keeps /metrics, frontends whose
workers are the engine's own server use the backend's path. metrics_path
stays the router's own route. return_perf_metrics, which mounts the
trtllm-serve route, now defaults on behind every direct-worker frontend,
not only trtllm_serve.

Adds examples/trtllm/smg-agg.yaml and its launch snapshot.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
@cquil11
cquil11 force-pushed the feat/smg-frontend branch from dba469b to 5f5b055 Compare October 5, 2026 14:55

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5f5b055. Configure here.

Comment thread src/srtctl/frontends/static_router.py Resolved
Signed-off-by: Cam Quilici <cjquilici@gmail.com>
Signed-off-by: Cam Quilici <cjquilici@gmail.com>
bootstrap_port: int | None = None


def setup_script_preamble(config: Any) -> str | None:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this alr existed for vllm frontend as well so move as common function to be used by vllm router and smg

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
…path

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
Signed-off-by: Cam Quilici <cjquilici@gmail.com>
vLLM hands the KV cache over its NIXL side channel, so a static router such as SMG was told about a bootstrap port nothing listened on.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
A gRPC-mode worker (vllm serve --grpc) starts no HTTP listener, so worker_metrics_path is now per mode and None for gRPC roles; Tachometer and the AIPerf server-metrics URLs skip them.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
Like the other direct-worker frontends, check the recipe layout at load:
a P/D topology must use one engine in both roles, may not be TRT-LLM,
and with vLLM must serve gRPC in both roles, since over HTTP the decode
worker recomputes the prompt with no KV handoff.

Signed-off-by: Cam Quilici <cjquilici@gmail.com>
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown

src/srtctl diff: +241 -80

@cquil11

cquil11 commented Oct 7, 2026

Copy link
Copy Markdown
Author

Merged upstream in NVIDIA#569.

@cquil11 cquil11 closed this Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants