feat(vllm): support multimodal sidecar requests - #12214
Conversation
This comment has been minimized.
This comment has been minimized.
19ed720 to
33dad93
Compare
WalkthroughThe vLLM sidecar now uses separate Inference, Control, and health gRPC services. It discovers model and server metadata at startup, supports multimodal requests and KV event sources, removes local model-path configuration, and updates mock services, launches, tests, and documentation. ChangesvLLM split API integration
Estimated code review effort: 4 (Complex) | ~60 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (4)
lib/sidecar/vllm/src/model.rs (1)
107-118: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winReturn the trimmed value from
requiredandnonempty.Both helpers test
value.trim().is_empty()but return the original string. Aserved_model_nameof" llama "therefore passes validation and is used verbatim.engine.rscopies that value intoproto_request.modelat line 206 and intoWorkerConfig.served_model_nameat line 121, so the surrounding whitespace becomes part of the routing key and of the model name sent back to vLLM.♻️ Proposed change
fn required(field: &str, value: String) -> Result<String, DynamoError> { - if value.trim().is_empty() { + let value = value.trim(); + if value.is_empty() { return Err(client::protocol_error(format!( "Control returned an empty {field}" ))); } - Ok(value) + Ok(value.to_string()) } fn nonempty(value: String) -> Option<String> { - (!value.trim().is_empty()).then_some(value) + let value = value.trim(); + (!value.is_empty()).then(|| value.to_string()) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/sidecar/vllm/src/model.rs` around lines 107 - 118, Update the `required` and `nonempty` helpers to return the trimmed input value after validating it, while preserving their existing error and `Option` behavior for blank strings. Ensure callers such as `proto_request.model` and `WorkerConfig.served_model_name` receive the normalized value without surrounding whitespace.lib/sidecar/vllm/src/convert.rs (1)
16-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftCentralize the cache-salt prefix in a shared protocol crate.
The two crates define separate copies of this protocol value. A prefix change can produce incompatible cache salts while both crates compile. Move the value to a common dependency and import it from there.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/sidecar/vllm/src/convert.rs` around lines 16 - 17, Remove the local DYNAMO_CACHE_SALT_PREFIX definition in convert.rs and source the prefix from a shared protocol crate instead. Add or use the appropriate common-crate dependency and import its canonical cache-salt prefix, ensuring the existing cache-salt construction continues using that shared symbol.lib/sidecar/vllm/src/tests.rs (2)
1087-1096: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider asserting that Control
Abortis never called.
lib/sidecar/vllm/README.mdline 76 states that the sidecar does not call the ControlAbortRPC and relies on stream drop instead. The fake implementsabortat lines 216-221, but no test observes it. A counter onFakeVllmwould pin that documented contract and catch a future change that starts sendingAbort.♻️ Proposed test addition
struct FakeVllm { requests: Arc<Mutex<Vec<pb::GenerateRequest>>>, + aborts: Arc<AtomicUsize>,async fn abort( &self, _request: Request<pb::AbortRequest>, ) -> Result<Response<pb::AbortResponse>, Status> { + self.aborts.fetch_add(1, Ordering::SeqCst); Ok(Response::new(pb::AbortResponse {})) }Then assert
server.service.aborts.load(Ordering::SeqCst) == 0after the cancellation completes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/sidecar/vllm/src/tests.rs` around lines 1087 - 1096, Update the FakeVllm test fixture and decode_cancellation_waits_for_submission_and_first_token to track Control Abort invocations with an atomic counter, increment it in the fake abort implementation, and assert the counter remains zero after cancellation completes, preserving the sidecar’s stream-drop-only cancellation contract.
94-98: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueName the expanded multimodal prompt token count.
The literal
601encodes "expanded multimodal prompt length" and appears again at lines 728, 765, 780, and 798. A named constant states the intent and keeps the fake and its assertions aligned when the value changes.♻️ Proposed refactor
+/// Prompt length the fake reports once media expands the prompt. +const EXPANDED_MULTIMODAL_PROMPT_TOKENS: u32 = 601; + let prompt_tokens = if request.media.is_empty() { prompt_tokens } else { - 601 + EXPANDED_MULTIMODAL_PROMPT_TOKENS };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/sidecar/vllm/src/tests.rs` around lines 94 - 98, Replace the repeated multimodal prompt token literal 601 with a clearly named shared constant representing the expanded multimodal prompt length, including the assignment in the shown test and the references near lines 728, 765, 780, and 798. Reuse that constant in the fake and its assertions so all related expectations remain aligned.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/mocker/servers/vllm/src/server.rs`:
- Around line 279-288: Ensure cancellable requests retain an addressable
caller-supplied ID by validating that GenerateRequest.request_id is non-empty
before scheduling, rather than allowing PreparedRequest::new to replace it with
a random UUID. Update the Generate request handling path and return an
appropriate invalid-argument error for empty IDs, preserving normal scheduling
and Abort’s stable_uuid lookup for valid IDs.
- Line 134: Update the mock server’s explicit data-parallel rank handling:
either validate GenerateRequest.data_parallel_rank against DP_RANK and reject
mismatches, or set supports_explicit_data_parallel_rank to false. Preserve
rank-zero scheduling only for matching requests, since convert.rs forwards the
routed rank into this field.
In `@lib/sidecar/vllm/proto/control.proto`:
- Around line 14-16: The vendored Control protocol must match the pinned source
byte-for-byte: replace lib/sidecar/vllm/proto/control.proto lines 14-16 with the
verbatim pinned content, removing the extra blank line between
GetServerInfoRequest and ServerInfo. In lib/sidecar/vllm/proto/README.md lines
8-13, retain the unmodified-copy statement and checksum only after verifying
they match the corrected checked-in bytes.
In `@lib/sidecar/vllm/src/engine.rs`:
- Around line 100-107: Update VllmSidecarEngine construction and start flow to
retain the configured startup Duration rather than the absolute deadline
computed during argument parsing. Keep bootstrap_discover bounded by its
separately derived deadline, then have VllmSidecarEngine::start derive a fresh
deadline via client::startup_deadline(self.transport.startup_deadline) and use
it for connect, wait_for_services, and discover.
- Around line 238-243: Update the request_cancelled branch in the engine’s
stream-message handling to wrap stream.message() in a bounded timeout while
draining deferred cancellation. If the timeout expires, drop the gRPC stream and
continue by emitting the cancelled result; preserve the existing
shutdown-cancellation race behavior.
In `@lib/sidecar/vllm/src/model.rs`:
- Around line 59-65: Normalize model aliases before constructing ModelIdentity
so equivalent alias sets compare consistently across RPC responses. In the
identity construction block, sort model.served_model_aliases and assign the
normalized order to aliases while preserving the existing ModelIdentity fields
and ensure_same_identity behavior.
---
Nitpick comments:
In `@lib/sidecar/vllm/src/convert.rs`:
- Around line 16-17: Remove the local DYNAMO_CACHE_SALT_PREFIX definition in
convert.rs and source the prefix from a shared protocol crate instead. Add or
use the appropriate common-crate dependency and import its canonical cache-salt
prefix, ensuring the existing cache-salt construction continues using that
shared symbol.
In `@lib/sidecar/vllm/src/model.rs`:
- Around line 107-118: Update the `required` and `nonempty` helpers to return
the trimmed input value after validating it, while preserving their existing
error and `Option` behavior for blank strings. Ensure callers such as
`proto_request.model` and `WorkerConfig.served_model_name` receive the
normalized value without surrounding whitespace.
In `@lib/sidecar/vllm/src/tests.rs`:
- Around line 1087-1096: Update the FakeVllm test fixture and
decode_cancellation_waits_for_submission_and_first_token to track Control Abort
invocations with an atomic counter, increment it in the fake abort
implementation, and assert the counter remains zero after cancellation
completes, preserving the sidecar’s stream-drop-only cancellation contract.
- Around line 94-98: Replace the repeated multimodal prompt token literal 601
with a clearly named shared constant representing the expanded multimodal prompt
length, including the assignment in the shown test and the references near lines
728, 765, 780, and 798. Reuse that constant in the fake and its assertions so
all related expectations remain aligned.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 4ceb21e6-8a5e-4a78-a8df-105f48e668f2
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (29)
.github/workflows/copyright-check.ps1.pre-commit-config.yamldocs/fern/pages/developer-guide/knowledge-base/modular-components/backends/vllm/sidecar.mdlib/backend-common/src/lib.rslib/mocker/servers/vllm/Cargo.tomllib/mocker/servers/vllm/README.mdlib/mocker/servers/vllm/src/main.rslib/mocker/servers/vllm/src/server.rslib/mocker/servers/vllm/src/server_request.rslib/mocker/servers/vllm/src/server_tests.rslib/mocker/servers/vllm/tests/sidecar.rslib/sidecar/vllm/Cargo.tomllib/sidecar/vllm/Dockerfilelib/sidecar/vllm/README.mdlib/sidecar/vllm/build.rslib/sidecar/vllm/deploy/agg.yamllib/sidecar/vllm/deploy/disagg.yamllib/sidecar/vllm/launch/agg.shlib/sidecar/vllm/launch/disagg.shlib/sidecar/vllm/proto/README.mdlib/sidecar/vllm/proto/control.protolib/sidecar/vllm/proto/inference.protolib/sidecar/vllm/src/args.rslib/sidecar/vllm/src/client.rslib/sidecar/vllm/src/convert.rslib/sidecar/vllm/src/engine.rslib/sidecar/vllm/src/model.rslib/sidecar/vllm/src/tests.rslib/sidecar/vllm/tests/executable.rs
💤 Files with no reviewable changes (4)
- lib/sidecar/vllm/deploy/disagg.yaml
- lib/sidecar/vllm/deploy/agg.yaml
- lib/sidecar/vllm/src/args.rs
- lib/sidecar/vllm/launch/disagg.sh
44fed80 to
11f4662
Compare
b30afd1 to
020c15c
Compare
dfbf023 to
30e68eb
Compare
020c15c to
f828c08
Compare
tanmayv25
left a comment
There was a problem hiding this comment.
Automated multi-agent code-review pass over this PR's diff (framing + expert lenses, each finding adversarially verified). Findings below are all minor / non-blocking.
30e68eb to
7b775cc
Compare
f828c08 to
9bf2ce9
Compare
furionw
left a comment
There was a problem hiding this comment.
Do we have e2e test for sidecar agg, P/D in general?
can we also have ones for multimodal agg and multimodal P/D ?
|
We don’t have any tests for sidecar yet (including E2E). We have some launch scripts and deploy examples, but only for regular agg/disagg. CI tests and more extensive launch examples will be added prior to 1.5.0 once we work it out with ops. We will add multimodal support at that time. |
7b775cc to
8304227
Compare
9bf2ce9 to
03acc34
Compare
1 similar comment
8304227 to
696dfeb
Compare
03acc34 to
c25fbb9
Compare
|
/ok to test e5f0c8e |
e5f0c8e to
b501531
Compare
Signed-off-by: Connor Carpenter <connorc@nvidia.com>
b501531 to
9b0962b
Compare
|
/ok to test 9b0962b |
Summary
Part 4 of a 4-PR stack.
MediaItemmessages.mm_hashestoMediaItem.uuidso repeated images use the same keys as vLLM KV events.Stack
Base: #12735
Validation
cargo test -p dynamo-sidecar-common -p dynamo-vllm-sidecar -p dynamo-vllm-mocker— 38 tests passedcargo clippy -p dynamo-sidecar-common -p dynamo-vllm-sidecar -p dynamo-vllm-mocker --all-targets -- -D warningscargo fmt --all -- --check