Skip to content

feat: introduce native model runtime contract - #2530

Open
Paramveersingh-S wants to merge 5 commits into
vllm-project:mainfrom
Paramveersingh-S:feature/native-router-phase1
Open

feat: introduce native model runtime contract #2530
Paramveersingh-S wants to merge 5 commits into
vllm-project:mainfrom
Paramveersingh-S:feature/native-router-phase1

Conversation

@Paramveersingh-S

@Paramveersingh-S Paramveersingh-S commented Jul 14, 2026

Copy link
Copy Markdown

Overview

This is Phase 1 of splitting PR #2458 into smaller, staged, and behavior-preserving pull requests to address Issue #2396.

As requested in previous reviews, this PR focuses strictly on introducing the backend-neutral native runtime contracts and taxonomy. It does not touch any existing call sites or Rust logic, ensuring that the legacy candle-binding singletons and existing runtime behaviors are 100% preserved.

Key Additions

  • Taxonomy Lockdown (taxonomy.go): Established strict Backend, Capability, Family, ArtifactFormat, and Modality constants to eliminate string duplication and prevent future taxonomy drift.
  • Native Contracts (adapter.go, request.go): Defined the BackendAdapter interface that future backend adapters (Candle, ONNX, OpenVINO) will implement. Introduced CapabilitySet, LoadRequest, and InferenceRequest to formalize hardware and feature support.
  • Thread-Safe Registry (registry.go): Introduced the central native.Registry component to track loaded model bindings securely.
  • ABI Tests (ffi_layout_test.go): Added stub test files for catching layout/taxonomy drifts at the CGO boundary.

This PR only adds the new foundational types to src/semantic-router/pkg/modelruntime/native. Because no existing init() side effects, Rust code, or CGO calls were modified, this guarantees that we bypass the Rust LazyLock and Go NUL-byte CI failures encountered previously.

Fixes #2396 (part of 2396)

@netlify

netlify Bot commented Jul 14, 2026

Copy link
Copy Markdown

Deploy Preview for vllm-semantic-router ready!

Name Link
🔨 Latest commit 16d9530
🔍 Latest deploy log https://app.netlify.com/projects/vllm-semantic-router/deploys/6a75f3ea7bda2200087b0078
😎 Deploy Preview https://deploy-preview-2530--vllm-semantic-router.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

👥 vLLM Semantic Team Notification

The following members have been identified for the changed files in this PR and have been automatically assigned when their GitHub accounts are assignable in this repository:

📁 src/semantic-router

Owners: @FAUST-BENCHOU, @shraderdm, @drivebyer, @ramkrishs, @WUKUNTAI-0211, @AayushSaini101, @siloteemu
Files changed:

  • src/semantic-router/pkg/modelruntime/native/adapter.go
  • src/semantic-router/pkg/modelruntime/native/registry.go
  • src/semantic-router/pkg/modelruntime/native/registry_test.go
  • src/semantic-router/pkg/modelruntime/native/request.go
  • src/semantic-router/pkg/modelruntime/native/taxonomy.go

vLLM Semantic Router

🎉 Thanks for your contributions!

This comment was automatically generated based on the OWNER files in the repository.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

✅ Supply Chain Security Report — All Clear

Scanner Status Findings
AST Codebase Scan (Py, Go, JS/TS, Rust) 48 finding(s) — MEDIUM: 41 · LOW: 7
AST PR Diff Scan No issues detected
Regex Fallback Scan No issues detected

Scanned at 2026-08-07T15:10:14.549Z · View full workflow logs

Signed-off-by: Param <param15.veer.singh@gmail.com>
Signed-off-by: Param <param15.veer.singh@gmail.com>
Signed-off-by: Param <param15.veer.singh@gmail.com>
@Paramveersingh-S
Paramveersingh-S force-pushed the feature/native-router-phase1 branch from 595306e to 023ef3d Compare July 14, 2026 13:30
Signed-off-by: Param <param15.veer.singh@gmail.com>

@Xunzhuo Xunzhuo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for splitting the original refactor. Keeping Phase 1 additive is the right boundary, and go test -race ./pkg/modelruntime/native passes on this head. I am requesting changes because the foundational contract still cannot support a backend-neutral request path, and downstream phases already expose the gaps.

Please fix this phase before rebasing the later phases:

  • Use a module-prefixed title such as [Router] ....
  • Replace Fixes #2396 with Part of #2396; Phase 1 does not satisfy the roadmap issue and must not close it when merged.
  • Make #2532 base on this branch, #2533 on #2532, and #2534 on #2533 (or land/rebase them sequentially). Today all four target main and contain independently recreated Phase 1 commits, so their diffs overlap and cannot be merged as a clean stack.

The inline comments cover the contract, normalized model-info shape, registry semantics, and tests. Once those are addressed, this additive first slice can be reviewed independently of the backend migrations.

type BackendAdapter interface {
Name() Backend
Capabilities() CapabilitySet
LoadModel(ctx context.Context, req LoadRequest) (ModelHandle, error)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P1] The neutral contract has no inference operation. InferenceRequest is declared, but neither BackendAdapter nor ModelHandle can execute it and there is no response type. A migrated caller would still have to import a concrete binding after LoadModel, defeating the issue's core goal that request paths ask for a capability/model ref rather than a backend package. Please put inference on the handle or adapter (with a handle argument), and use typed capability-specific request/response shapes instead of an unconsumed map[string]interface{} bag.

IsLoaded bool
MaxSequenceLength int
DefaultDimension int
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P1] This is not yet the normalized model-info contract required by #2396 or consumed by Phase 4. It omits artifact format, modality, dimensions/layers as requested-vs-runtime metadata, provider/device, version, runtime feature flags/unsupported reasons, and registry metadata; it also allows only one capability. If this foundational type lands now, the API migration will either lose existing information or require an immediate breaking expansion. Please define the complete normalized discovery shape in Phase 1 and add round-trip/discovery tests before call sites depend on it.

r.mu.RLock()
defer r.mu.RUnlock()
list := make([]BackendAdapter, 0, len(r.adapters))
for _, adapter := range r.adapters {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P1] Iterating a Go map makes List() nondeterministic. Phase 4 emits /models in exactly this order, so identical processes can return different response ordering and order-sensitive tests/clients will flake. Return adapters in a stable backend order (or sort the collected keys) and assert it with multiple registrations.

func (r *AdapterRegistry) Register(adapter BackendAdapter) {
r.mu.Lock()
defer r.mu.Unlock()
r.adapters[adapter.Name()] = adapter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P2] Registration has no invalid/duplicate contract: a typed-nil adapter can panic at Name(), and a second adapter silently replaces the first backend. Since registration becomes the composition boundary, please return an error for nil/empty names and duplicate backends (or document and test an intentional replacement API separately). The current concurrency smoke test deliberately avoids the nil case but does not validate registry composition semantics.

"testing"
)

// In a real scenario, this would import C and use unsafe.Sizeof to verify structs against C headers.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P2] This file is explicitly a placeholder and does not test FFI layout or discriminants, so it cannot be presented as the ABI drift coverage requested by #2396. Either add real Go/Rust/C boundary checks (for example generated discriminants plus unsafe.Sizeof/offset assertions against the exported C structs) or rename this to a registry/taxonomy unit test and leave ABI coverage to the Rust-binding phase. A test that only compares a Go string constant to a literal will not catch binding drift.

@Paramveersingh-S

Copy link
Copy Markdown
Author

Thanks for the detailed review! I've updated the PR title and description as requested. I've also pushed a new commit that addresses all your points:

  • [P1] Inference Contract: Replaced the map bag with strongly-typed request/response interfaces (like EmbeddingRequest) and added the Inference method to BackendAdapter.
  • [P1] Model-Info Shape: Expanded ModelInfo into the complete discovery shape required by Modularize native router model bindings and runtime capability contracts #2396 (added dimensions/layers, format, modality, feature flags, etc.).
  • [P1] Registry Determinism: List() now returns adapters in alphabetical order by backend name for stable /models responses.
  • [P2] Registration Rules: Register() now strictly returns an error for nil adapters, empty names, or duplicate backends.
  • [P2] ABI Tests: Removed the placeholder ffi_layout_test.go and replaced it with registry_test.go to test taxonomy, duplicate/nil errors, and ordering. Actual FFI boundary tests will be added in the Rust-binding phases.

The base contracts are fully updated and tested. I'll make sure to sequentially rebase the other phases

@Xunzhuo Xunzhuo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the update. The latest head addresses most of the original feedback: inference is now part of the adapter contract, ModelInfo is expanded, list ordering is deterministic, registration rejects ordinary nil/empty/duplicate inputs, and the placeholder ABI test is gone.

Changes are still required before this contract becomes the base of the remaining phases:

  1. EmbeddingRequest must carry the per-inference dimension/layer options supported by current Candle APIs; load-time fields are not equivalent.
  2. Info() must return an error so backend discovery failures do not silently become an empty model list.
  3. Register must reject typed-nil adapters, with a regression test.
  4. Fix the failing gofumpt check.

Please also use a [Router] title, change Fixes #2396 to Part of #2396, remove the obsolete ffi_layout_test.go description, and make the Phase 2–4 PR bases reflect the actual stack before further review.

Overview
This is Phase 1 of splitting PR vllm-project#2458 into smaller, staged, and behavior-preserving pull requests.
Part of vllm-project#2396

Signed-off-by: Param <param15.veer.singh@gmail.com>
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@2adb301). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2530   +/-   ##
=======================================
  Coverage        ?   33.93%           
=======================================
  Files           ?       20           
  Lines           ?     2959           
  Branches        ?        0           
=======================================
  Hits            ?     1004           
  Misses          ?     1849           
  Partials        ?      106           
Flag Coverage Δ
operator 33.93% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added the wg/router-models-runtime-ecosystem Owned by the Router Models, Runtime and Ecosystem Workgroup. label Aug 22, 2026
@github-actions github-actions Bot added this to the v0.5 milestone Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr/blocked Blocked on a named decision, dependency, or required check. wg/router-models-runtime-ecosystem Owned by the Router Models, Runtime and Ecosystem Workgroup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modularize native router model bindings and runtime capability contracts

9 participants