Skip to content

feat(runtime): add hierarchical Model/WorkerSet architecture for multi-namespace support - #6054

Merged
tmonty12 merged 32 commits into
mainfrom
tmonty12/hierarchical-model-architecture
Feb 23, 2026
Merged

tmonty12 merged 32 commits into
mainfrom
tmonty12/hierarchical-model-architecture

Conversation

@tmonty12

@tmonty12 tmonty12 commented Feb 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Introduces a hierarchical Model → WorkerSet architecture in the frontend's ModelManager, replacing the previous flat engine map design
  • Each Model holds a DashMap<namespace, Arc<WorkerSet>> where each WorkerSet owns its own complete pipeline (engines, KV router, prefill router, worker monitor)
  • Requests are routed to WorkerSets via weighted random selection based on worker count, providing proportional load distribution
  • Workers register into namespaces derived from DYN_NAMESPACE + optional DYN_NAMESPACE_WORKER_SUFFIX environment variable

Motivation

This change enables rolling upgrades with full isolation between old and new workers. During a rolling update:

  1. New workers register under a different namespace suffix (e.g., dynamo-v2) while old workers remain under the original namespace (dynamo)
  2. Each namespace gets its own independent WorkerSet with a dedicated pipeline — KV router, prefill router, and worker monitor are all isolated
  3. The frontend routes traffic proportionally: as new workers come up and old workers drain, traffic naturally shifts to the new version
  4. Once old workers are fully drained, their WorkerSet is cleaned up automatically

Without this isolation, old and new workers would share a single KV cache router and prefill router, leading to compatibility issues during transitions (e.g., KV cache blocks being routed between incompatible model versions).

Key Changes

  • Model struct (discovery/model.rs): Manages multiple WorkerSets per model, weighted selection, aggregated engine views
  • WorkerSet struct (discovery/worker_set.rs): Owns a complete pipeline with atomic worker counting
  • ModelManager (discovery/model_manager.rs): Delegates through the Model layer; handles per-namespace checksum validation
  • ModelWatcher (discovery/watcher.rs): Builds per-WorkerSet pipelines, cleans up empty namespaces/models on worker departure
  • Namespace utilities (Python + Rust): DYN_NAMESPACE_WORKER_SUFFIX support for worker-side namespace configuration
  • In-process model support (http.rs, grpc.rs): Convenience methods that create synthetic single-namespace WorkerSets

Test plan

  • Unit tests for Model weighted selection, worker counting, and engine aggregation
  • Unit tests for WorkerSet lifecycle
  • Existing integration tests pass (http_metrics.rs updated for new API)
  • End-to-end rolling update test with two namespaces

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added --namespace-prefix CLI flag and NamespaceFilter (Global/Exact/Prefix) for refined discovery
    • Introduced namespace-scoped WorkerSets and model-centric orchestration for multi-namespace deployments
    • Engines now return parsing options alongside streams/clients
    • Exposed optional namespace_prefix on local models and a utility to compute worker namespaces
  • Improvements

    • Consolidated model lifecycle and removal semantics (single remove_model)
    • Prefill/router activation and watcher flows are now namespace-scoped

@tmonty12
tmonty12 requested a review from a team as a code owner February 6, 2026 23:20
@tmonty12
tmonty12 requested review from a team February 6, 2026 23:20
@copy-pr-bot

copy-pr-bot Bot commented Feb 6, 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.

@github-actions github-actions Bot added backend::vllm Relates to the vllm backend backend::sglang Relates to the sglang backend backend::trtllm Relates to the trtllm backend frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` labels Feb 6, 2026
@coderabbitai

coderabbitai Bot commented Feb 6, 2026 •

Copy link
Copy Markdown
Contributor

Walkthrough

This PR centralizes worker namespace resolution (get_worker_namespace), introduces NamespaceFilter, adds Model and WorkerSet abstractions, refactors ModelManager for per-model/per-namespace orchestration, plumbs namespace_prefix through CLI and bindings, and updates discovery, entrypoints, and prefill routing to be namespace-aware.

Changes

Cohort / File(s) Summary
Namespace utility
components/src/dynamo/common/utils/__init__.py, components/src/dynamo/common/utils/namespace.py
Added namespace module with get_worker_namespace(default="dynamo") and exported it via __all__; standardized worker-namespace resolution including optional worker suffix.
Python consumers
components/src/dynamo/mocker/args.py, components/src/dynamo/sglang/args.py, components/src/dynamo/trtllm/utils/trtllm_utils.py, components/src/dynamo/vllm/args.py
Replaced direct DYN_NAMESPACE env reads with get_worker_namespace() calls to form default endpoints and Config.namespace.
Frontend CLI
components/src/dynamo/frontend/main.py
Added --namespace-prefix flag (env default DYN_NAMESPACE_PREFIX) and forwarded namespace_prefix into engine kwargs when provided.
Rust: namespace API
lib/llm/src/namespace.rs
Removed GLOBAL_NAMESPACE constant; added NamespaceFilter (Global, Exact, Prefix) with constructors, matches, and is_global helpers and tests.
Discovery: types & storage
lib/llm/src/discovery.rs, lib/llm/src/discovery/model.rs, lib/llm/src/discovery/worker_set.rs, lib/llm/src/discovery/model_manager.rs
Introduced Model and WorkerSet; refactored ModelManager to model-centric DashMap of Models, per-namespace WorkerSet management, per-namespace checksum logic, model lifecycle APIs, and prefill router registration/activation keyed by (model, namespace).
Discovery watcher
lib/llm/src/discovery/watcher.rs
Replaced target_namespace option with NamespaceFilter, made watch/cards handling namespace-filtered and per-namespace WorkerSet-aware, and updated prefill activation/cleanup to be namespace-scoped.
Worker-set plumbing (KV/prefill)
lib/llm/src/kv_router/prefill_router.rs
PrefillRouter constructor now accepts a namespace: String; activation wiring uses per-namespace worker monitors.
Entrypoints / runtime
lib/llm/src/entrypoint/input/common.rs, lib/llm/src/entrypoint/input/grpc.rs, lib/llm/src/entrypoint/input/http.rs, lib/llm/src/local_model.rs
Replaced Option target_namespace with NamespaceFilter across entrypoints; added optional namespace_prefix to LocalModelBuilder/LocalModel and propagated it through builders.
GRPC / HTTP engine parsing plumbing
lib/llm/src/grpc/service/openai.rs, lib/llm/src/grpc/service/kserve.rs, lib/llm/src/http/service/openai.rs
Engine getters now return (engine, ParsingOptions) via _with_parsing variants; callers destructure parsing options and thread them into response/stream construction.
Bindings & CLI propagation
lib/bindings/python/rust/llm/entrypoint.rs, lib/bindings/c/src/lib.rs
Added namespace_prefix: Option<String> to Python EntrypointArgs and propagated it into engine builder; updated C binding call to register_prefill_router(model_name, namespace).
Tests & minor consumers
lib/llm/tests/http_metrics.rs, various small consumers
Updated tests and call sites to use unified remove_model() and new API shapes (parsing-aware engine returns, namespace-aware watch signatures, etc.).

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐇 I sniffed the env for names and found a thread,

stitched prefixes, filters, sets where workers tread.
Models gather, namespaces hum in tune,
routers chirp, prefill hops beneath the moon.
A burrowed patchwork — neat, with carrots strewn 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main architectural change: introducing a hierarchical Model/WorkerSet structure for multi-namespace support.
Description check ✅ Passed The description includes all required sections (Overview via Summary, Details via Motivation/Key Changes, Related context) and thoroughly explains the change rationale, architecture, and implementation details.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/llm/src/discovery/model_manager.rs (1)

579-621: ⚠️ Potential issue | 🔴 Critical

Concurrent register_prefill_router calls can lose a channel—including unguarded paths in C bindings.

The remove → inspect → insert pattern on DashMap is not atomic. Two concurrent threads calling register_prefill_router("llama", "ns1") can both see None from remove, both create channels, and the second insert overwrites the first sender, dropping tx1 and causing rx1 to resolve with a RecvError.

The Rust watcher code is protected: registering_worker_sets (a DashSet<String> keyed on model_namespace_key(model_name, namespace)) in watcher.rs guards do_worker_set_registration, which contains the only production call to register_prefill_router at line 424. This serializes concurrent registrations for the same model+namespace.

However, lib/bindings/c/src/lib.rs:1421 calls register_prefill_router directly without the DashSet guard, creating an unprotected concurrent path. If the C bindings are used to register prefill routers concurrently for the same model+namespace, the race condition manifests.

Either move the guard into register_prefill_router itself, or document that this function must only be called from within a registering_worker_sets guard and audit all call sites (including C bindings).

🤖 Fix all issues with AI agents
In `@components/src/dynamo/common/utils/namespace.py`:
- Around line 7-18: get_namespace may return values containing "." (from
DYN_NAMESPACE or DYN_NAMESPACE_WORKER_SUFFIX) which breaks downstream parsing of
dyn://{namespace}.component.endpoint; update get_namespace to validate and
reject or sanitize dots: check os.environ.get("DYN_NAMESPACE") and
os.environ.get("DYN_NAMESPACE_WORKER_SUFFIX") and either raise a clear
ValueError/log an error if either contains a "." or replace "." with "-" (choose
one policy consistently), and ensure the function get_namespace documents this
behavior so callers (and CI) won't produce malformed dyn endpoints.

In `@lib/llm/src/discovery/model_manager.rs`:
- Around line 572-573: The current model_namespace_key(model_name: &str,
namespace: &str) builds keys with ":" which can collide when model names include
":"; change the key format to a collision-safe scheme (e.g., use a fixed
multi-char delimiter like "::ns::" or a non-printable separator like '\0', or
better: encode each component with percent-encoding/base64/hex) and update any
code that parses or compares these keys to use the new scheme; specifically
modify model_namespace_key to produce the safe-encoded/delimiter-separated
string and ensure any consumers that split or match keys use the corresponding
decode/split logic so existing lookups remain correct.

In `@lib/llm/src/entrypoint/input/common.rs`:
- Around line 83-86: The code spawns a watcher task that currently hardcodes
NamespaceFilter::Global (inner_watch_obj/watcher_task/watch/discovery_stream),
which ignores model flags; instead build the NamespaceFilter from the model
configuration (use the same logic as grpc.rs/http.rs that derives from
model.namespace and model.namespace_prefix), create the filter variable before
spawning the tokio::spawn, and then pass or move that filter into the async
closure so the watch call uses the constructed filter rather than
NamespaceFilter::Global; ensure the filter is clonable or moved into the closure
to avoid lifetime issues.

In `@lib/llm/src/namespace.rs`:
- Line 4: The change of GLOBAL_NAMESPACE to "default" breaks tests and runtime
expectations that use "dynamo" as the global namespace; restore GLOBAL_NAMESPACE
to "dynamo" and update the global-check logic so is_global_namespace(...) treats
both "dynamo" and the empty string (and optionally "default" if backward
compatibility desired) as global; specifically modify the constant
GLOBAL_NAMESPACE back to "dynamo" and adjust the is_global_namespace function to
return true for namespace == GLOBAL_NAMESPACE || namespace.is_empty() (and add
"default" to the allowed set only if you want to accept both).
🧹 Nitpick comments (10)
components/src/dynamo/common/utils/__init__.py (1)

10-25: Docstring doesn't list the new namespace submodule.

The module docstring (lines 10-15) enumerates submodules but omits the newly added namespace module, while __all__ and imports include it.

Suggested fix
 Submodules:
     - endpoint_types: Endpoint type parsing utilities
+    - namespace: Namespace resolution utilities
     - otel_tracing: OpenTelemetry tracing header utilities
     - paths: Workspace directory detection and path utilities
     - prometheus: Prometheus metrics collection and logging utilities
components/src/dynamo/vllm/args.py (1)

366-368: Inconsistent import location compared to other backends.

get_namespace is imported at module level in mocker/args.py, sglang/args.py, and trtllm_utils.py, but here it's imported inside parse_args(). Consider moving it to the top-level imports for consistency.

Suggested refactor

Add to the top-level imports (e.g., near line 19):

from dynamo.common.utils.namespace import get_namespace

Then at line 368, simply:

-    from dynamo.common.utils.namespace import get_namespace
-
-    config.namespace = get_namespace()
+    config.namespace = get_namespace()
lib/llm/tests/http_metrics.rs (1)

506-564: Commented-out cleanup block — consider removing or converting to a TODO.

This entire block is wrapped in /* ... */ and has no effect. If the intent is to implement this later, a brief // TODO: comment would be clearer than leaving ~60 lines of dead code.

lib/llm/src/namespace.rs (1)

48-53: Prefix matching may be broader than intended.

starts_with("ns") matches "ns-abc123" but also "nsomething". The doc comment on line 18 implies delimiter-separated variants ("ns", "ns-abc123"). If the intent is to match only the exact prefix or prefix followed by a delimiter (e.g., -), consider tightening the match:

NamespaceFilter::Prefix(prefix) => namespace == prefix || namespace.starts_with(&format!("{}-", prefix)),

If the broader starts_with behavior is intentional, this is fine as-is — just noting the subtlety.

lib/llm/src/http/service/openai.rs (1)

1010-1011: Unnecessary .clone() on parsing_options.

parsing_options is not used after being passed to from_annotated_stream in either chat_completions or responses, so the .clone() is redundant — you can pass it by value directly.

🔧 Remove unnecessary clones
-            NvCreateChatCompletionResponse::from_annotated_stream(stream, parsing_options.clone())
+            NvCreateChatCompletionResponse::from_annotated_stream(stream, parsing_options)

(Same for line 1272.)

Also applies to: 1271-1272

lib/llm/src/discovery/model.rs (1)

185-201: load_threshold_config updates all monitors but returns from the first — document this intentional asymmetry.

When config is Some, all WorkerSet monitors are updated (correct for consistent thresholds during rollout), but only the first monitor's config is returned. This is fine, but a brief inline comment would clarify the intent for future readers.

📝 Suggested comment
     pub fn load_threshold_config(
         &self,
         config: Option<&LoadThresholdConfig>,
     ) -> Option<LoadThresholdConfig> {
+        // When setting: update ALL monitors so all WorkerSets use consistent thresholds.
+        // When getting: return from any monitor (they should all agree).
         let mut result = None;
lib/llm/src/discovery/model_manager.rs (4)

349-368: TOCTOU between has_chat_engine() check and add_worker_set() in all add_*_model methods.

The check-then-act pattern (if model_entry.has_chat_engine() → return Err then add_worker_set) is not atomic. Two concurrent callers could both pass the check and both add WorkerSets. For in-process models this is likely single-threaded initialization so the practical risk is low, but it's worth noting. The same pattern repeats in add_completions_model, add_embeddings_model, add_tensor_model, add_images_model, and add_prefill_model.


117-138: Subtle race window in add_worker_set: newly created empty model can be removed before WorkerSet is added.

get_or_create_model (line 123) may create an empty Model. Between that call and model.add_worker_set (line 124), a concurrent remove_worker_set → remove_model_if_empty could find the model empty and remove it from the DashMap. The add_worker_set would then mutate a detached Arc<Model> invisible to lookups.

This is a narrow window, and the watcher-level DashSet guard likely prevents it, but worth documenting or adding an assertion that the model is still in the map after the add.


345-347: Acknowledged: TODO for passing real ModelDeploymentCard to in-process WorkerSets.

The TODO is well-documented. Just noting that until this is addressed, ParsingOptions (tool_call_parser, reasoning_parser) will always be defaults for in-process models, which could cause subtle behavioral differences compared to dynamically-discovered models.

Would you like me to open an issue to track passing the real ModelDeploymentCard from callers?


484-517: remove_*_model methods rely on matching the synthetic namespace format from add_*_model.

The namespace strings (e.g., __local_chat_{}) are duplicated between add and remove methods. If one side changes format without the other, removal silently fails. Consider extracting a shared helper.

Proposed refactor
+    fn local_namespace(kind: &str, model: &str) -> String {
+        format!("__local_{}_{}", kind, model)
+    }
+
     pub fn add_chat_completions_model(
         &self,
         model: &str,
         card_checksum: &str,
         engine: OpenAIChatCompletionsStreamingEngine,
     ) -> Result<(), ModelManagerError> {
         let model_entry = self.get_or_create_model(model);
         if model_entry.has_chat_engine() {
             return Err(ModelManagerError::ModelAlreadyExists(model.to_string()));
         }
-        let namespace = format!("__local_chat_{}", model);
+        let namespace = Self::local_namespace("chat", model);
         // ...
     }

     pub fn remove_chat_completions_model(&self, model: &str) -> Result<(), ModelManagerError> {
-        let namespace = format!("__local_chat_{}", model);
+        let namespace = Self::local_namespace("chat", model);
         self.remove_worker_set(model, &namespace)
             .map(|_| ())
             .ok_or_else(|| ModelManagerError::ModelNotFound(model.to_string()))
     }

Comment thread lib/llm/src/discovery/model_manager.rs Resolved
Comment thread lib/llm/src/entrypoint/input/common.rs Resolved
Comment thread lib/llm/src/namespace.rs Resolved
@tmonty12
tmonty12 force-pushed the tmonty12/hierarchical-model-architecture branch 2 times, most recently from 79725ce to 5ed7ea7 Compare February 9, 2026 19:04
@tmonty12 tmonty12 changed the title Add hierarchical Model/WorkerSet architecture for multi-namespace support feat(runtime): add hierarchical Model/WorkerSet architecture for multi-namespace support Feb 9, 2026
@github-actions github-actions Bot added the feat label Feb 9, 2026
@github-actions github-actions Bot added the router Relates to routing, KV-aware routing, etc. label Feb 9, 2026
@ai-dynamo ai-dynamo deleted a comment from coderabbitai Bot Feb 11, 2026
@tmonty12

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@ai-dynamo ai-dynamo deleted a comment from coderabbitai Bot Feb 11, 2026
@coderabbitai

coderabbitai Bot commented Feb 11, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
lib/bindings/c/src/lib.rs (2)

1267-1284: ⚠️ Potential issue | 🔴 Critical

Build failure: activate_prefill_router requires 3 arguments, but only 2 are provided.

The method requires model_name, namespace, and endpoint parameters. The namespace parameter must be added—&endpoint_id.namespace is available in scope.

🐛 Proposed fix
-                    if let Err(e) = model_manager.activate_prefill_router(card.name(), endpoint)
+                    if let Err(e) = model_manager.activate_prefill_router(card.name(), &endpoint_id.namespace, endpoint)

1383-1388: ⚠️ Potential issue | 🔴 Critical

Fix signature mismatch in cards_for_model call.

The call cards_for_model(model_name, Some(namespace), false) is incorrect. The function signature expects only two parameters: model_name: &str and namespace_filter: &NamespaceFilter. The current call passes three arguments with mismatched types—the second parameter should be a reference to a NamespaceFilter (not Option<&str>), and the third boolean argument doesn't exist.

Proposed fix
+    use dynamo_llm::namespace::NamespaceFilter;
+
+    let namespace_filter = NamespaceFilter::Exact(namespace.to_string());
     let cards = watcher
-        .cards_for_model(model_name, Some(namespace), false)
+        .cards_for_model(model_name, &namespace_filter)
         .await
         .with_context(|| format!("Failed to discover model: {}", model_name))?;
lib/llm/tests/http_metrics.rs (1)

356-359: ⚠️ Potential issue | 🟠 Major

Fix type error: watch expects NamespaceFilter, not Option.

The watch method in ModelWatcher (lib/llm/src/discovery/watcher.rs:117) takes a NamespaceFilter parameter, not Option. Passing None here is a type mismatch. Use NamespaceFilter::Global instead, which matches all namespaces (semantically equivalent to no filtering).

Fix
+    use dynamo_llm::namespace::NamespaceFilter;
+
     let _watcher_task = tokio::spawn(async move {
-        model_watcher.watch(discovery_stream, None).await;
+        model_watcher.watch(discovery_stream, NamespaceFilter::Global).await;
     });
🤖 Fix all issues with AI agents
In `@lib/llm/src/discovery/model_manager.rs`:
- Around line 343-347: The WorkerSet creation for in-process models currently
uses ModelDeploymentCard::default(), causing parsing_options() to be wrong and
losing tool/reasoning parsers; update the add_*_model functions that build
WorkerSet (the in-process convenience methods) to accept a ModelDeploymentCard
parameter instead of using ModelDeploymentCard::default(), pass that card into
WorkerSet construction so parsing_options() reflects the real config, and update
call-sites in http.rs and grpc.rs to supply the actual ModelDeploymentCard (and
adjust any engine parameter as needed) so parsing behavior matches the deployed
model.

In `@lib/llm/src/discovery/watcher.rs`:
- Around line 692-718: Call site is passing three args to cards_for_model but
the function signature expects (&self, model_name: &str, namespace_filter:
&NamespaceFilter); replace the erroneous call like .cards_for_model(model_name,
Some(namespace), false) with .cards_for_model(model_name,
&NamespaceFilter::Exact(namespace.to_string())), and ensure NamespaceFilter is
in scope (import or fully qualify) so the reference type matches the function
signature.

In `@lib/llm/src/namespace.rs`:
- Around line 25-83: The tests expect "default" to be treated as a global
namespace but is_global_namespace currently only checks GLOBAL_NAMESPACE and
empty string, causing from_namespace_and_prefix to produce Exact("default");
update is_global_namespace to treat "default" as a global alias (e.g., return
true when namespace == GLOBAL_NAMESPACE || namespace.is_empty() || namespace ==
"default") so from_namespace_and_prefix and the test
(test_from_namespace_and_prefix_global) will align and produce
NamespaceFilter::Global for Some("default"); ensure references to
GLOBAL_NAMESPACE and is_global_namespace are used so behavior remains consistent
across from_namespace_and_prefix and other callers.
🧹 Nitpick comments (1)
components/src/dynamo/common/utils/__init__.py (1)

10-26: Docstring is missing entries for namespace and runtime submodules.

The module docstring (lines 10-15) lists endpoint_types, otel_tracing, paths, and prometheus but omits the newly added namespace and the existing runtime submodule, both of which are now exported.

Proposed fix
 Submodules:
     - endpoint_types: Endpoint type parsing utilities
+    - namespace: Worker namespace resolution utilities
     - otel_tracing: OpenTelemetry tracing header utilities
     - paths: Workspace directory detection and path utilities
     - prometheus: Prometheus metrics collection and logging utilities
+    - runtime: Runtime endpoint parsing utilities
 """

Comment thread lib/llm/src/discovery/model_manager.rs Resolved
Comment thread lib/llm/src/discovery/watcher.rs Resolved
Comment thread lib/llm/src/namespace.rs Resolved
@tmonty12
tmonty12 force-pushed the tmonty12/hierarchical-model-architecture branch from 071545c to 9df3b9d Compare February 11, 2026 18:10
tmonty12 and others added 25 commits February 23, 2026 14:07
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>
Signed-off-by: tmontfort <tmontfort@nvidia.com>

This branch had an error being deployed

1 failed deployment
GITLAB — ddaff5d2 Deployed Feb 23, 2026 by copy-pr-bot[bot] via Trigger CI Pipeline #18006
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 backend::trtllm Relates to the trtllm backend backend::vllm Relates to the vllm backend feat frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` router Relates to routing, KV-aware routing, etc. size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants