Conversation
vLLM serves exactly one model per process, so its launch command names
the model. Add a {model} placeholder resolved from a new runtime.model,
a runtime.extra_args tail appended to runtime.args, and the persistent
engine:set-model / one-shot engine:start {model} setters that choose it.
Starting an engine whose launch template needs {model} with none
configured now fails with guidance instead of spawning.
The bundled vllm.json is Linux-only (vLLM ships no Windows or macOS GPU
build), process mode, port 8000, /health readiness with a 30-minute
budget for the first weight download, and the OpenAI list/loaded/chat
actions. Adoption is the primary path: process mode reconciles an
already-serving listener even when detect misses, so a user's own
`vllm serve` or the vllm/vllm-openai container is picked up.
engine:set-port and engine:set-model share one override file, so both
now read-modify-write it rather than replacing it with a single-key
delta, and the file is unlinked only once no override remains.
allowedPlaceholders had been doing double duty as the set an
engine:action caller may not supply. Split out
reservedActionPlaceholders so {model} stays caller-suppliable on a
model action while remaining a valid manifest placeholder.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Can GULDOGAN <cguldogan@gmail.com>
vLLM speaks the same OpenAI HTTP surface as LM Studio, so it needs the same router rather than a new binary: lmstudio-proxy becomes the OpenAI-compatible proxy for every such engine. It subscribes to lm and vl, each routing candidate records which engine it represents, and workloads are tagged with that engine instead of a package constant. A peer advertises lm and vl at the same value — its one proxy port — so a dual-engine peer still projects to a single routing target whose per-engine model attribution says which engine owns what. A manual node is the exception: the user supplies an engine's own address and LM Studio and vLLM sit on different ports, so node/add-manual and node/remove-manual now carry an engine and the manual overlay is keyed by (engine, node). The reachability cache is keyed the same way, while scheduledOn and node selection stay keyed by the bare node id. node/set-local-backend becomes per-engine, so one node may run both engines at once and clearing one leaves the other routing. Cluster ingress picks the local engine that actually serves the requested model — read from the engines themselves, since this node's own discovery entry can lag — and answers GET /v1/models by merging both local engines, which a single forward would have hidden half of. Broker: runAutoAdvertiseVLLM registers vl at the OpenAI proxy's port and hands the engine's loopback port to that proxy. There is no managed facade for vLLM, so the loop carries none of LM Studio's facade handling. Manual nodes gain a vllm_* triple probed on 8000, with vLLM's own /version as the disambiguator from any other OpenAI server. The scheduler ranks vllm alongside the others, and the TUI's second proxy panel now names both engines it fronts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Can GULDOGAN <cguldogan@gmail.com>
Add the 'vllm' engine type, display name, links, capabilities and icon, and offer it in onboarding on Linux only, never pre-selected. A node reported by the OpenAI-compatible proxy is no longer necessarily LM Studio, so the bridge stops inferring the engine from the proxy's name: a source that fronts one engine still names it, while the OpenAI proxy's nodes carry per-engine model attribution and that is what says whether a node runs LM Studio, vLLM, or both. The proxy's ready port and its manual-node bridge now apply to every engine it fronts, and those bridge calls name their engine so two engines on one host cannot collide. vLLM serves one model per process, chosen before it starts, so engine settings gains a "Model to serve" field behind a new hasServedModel capability. It relays the new engine:set-model, and EngineStatus gains the configured model so the field can render what is actually set. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Can GULDOGAN <cguldogan@gmail.com>
README, overview, architecture and the per-service READMEs now name three engines, and engine-lifecycle gains a vLLM section covering what makes it different: Linux only, adoption of an instance you already run as the normal path, one model per process chosen before start, a first start that can take many minutes, and no model operations. lmstudio-proxy's README is rewritten as the OpenAI-compatible proxy that fronts both LM Studio and vLLM, keeping the binary name as the wire contract it is. Versions: lmstudio-proxy MAJOR (node/add-manual and node/remove-manual now require an engine); engine-manager, ui-broker, manual-nodes and job-scheduler MINOR (additive IPC); node-scanner, errors, workload-manager and tui PATCH (recompiled for the shared discovery key, plus the TUI's panel label). node-info, node-settings and cluster-manager are unchanged. Product and installer MINOR for the new engine. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Can GULDOGAN <cguldogan@gmail.com>
The engine manager writes manifest overrides for its own host, and there is no remote served-model control on the wire, so a peer's row could never hold a value. Gate the row (and the accordion's "Ports and model" title) on the local node, and drop the now-unreachable read-only branch from the row. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Can GULDOGAN <cguldogan@gmail.com>
The parity and backend docs, and the READMEs of the broker, scheduler, TUI,
and node-scanner, all enumerate engines or service keys by hand and nothing
in the contract checker notices a missing engine. Add vLLM to each: the
routing row, the vl discovery key, the three advertise loops, the per-engine
schedule:priority list, the OpenAI-compatible proxy's two engines, the
per-engine node/set-local-backend, and the fact that vLLM has no model
operations at all because the model is a start-time setting.
Also fix a mangled sentence in the manual-nodes README ("The engine engine
ports are compiled in") introduced when the probe list grew a fourth leg.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Can GULDOGAN <cguldogan@gmail.com>
|
+1 — this would be a big deal for DGX Spark owners specifically. Our setup: a small home/lab cluster of NVIDIA GB10 (DGX Spark) nodes paired in PAIR, each serving production models via The mismatch today is that PAIR sees and manages the nodes (pairing, health, workload signals all work great) but the engine-manager only probes the fixed Ollama/LM Studio ports, so a healthy The issue body's "adopt an already-running vLLM on the configured port" framing is exactly what we'd use — we don't need PAIR to install or lifecycle-manage vLLM (systemd/docker handles that), just detect Happy to test a preview build on a 6-node all-GB10 cluster if that's useful. |
full implementation is here I would love to see it :) |
|
I built and ran the suite at a4b96a3 on macOS arm64, since this adds an engine and a second platform data point seemed worth having. The vLLM work passes; the two failures I hit are pre-existing on main and are not from this PR. Environment: darwin/arm64 (Apple Silicon), Go 1.26.5, Node 25.9.0, clean tree at a4b96a3. Desktop ( Go:
Both reproduce at main with identical messages, so neither is caused by this change. On those two, in case it saves anyone time:
Two small notes on the manifest, neither of them asks:
|
|
Filed the macOS piece separately as #17, since it reproduces at origin/main and is a different root cause from anything here. Nothing in it blocks this PR. |
|
Small one from the same pass: three files in this PR are not gofmt-clean. So Two other notes from testing this branch on Apple Silicon, so they are not mistaken for anything here:
|
|
I've built on this PR at https://github.com/jlacroix82/Personal-AI-Router/tree/feat/vllm-sglang Extension commit: jlacroix82@58508c6 The extension adds:
I also fixed the broker's Validation on Linux ARM64, Node 26.5.0, Go 1.26.5:
This is stub-backed validation, not a claim of a completed production-cluster rollout. Native single-model controls are retained; externally managed processes remain under their supervisor. Authenticated engine endpoints and fully dynamic arbitrary-engine registration are still outside this change. The adapter repository now also has a separate SGLang manifest/configuration, non-conflicting wrapper/child ports, two passing mock-adapter tests, and GUI setup instructions: Happy for the SGLang follow-up to stay separate from #9. The branch is available to review or cherry-pick once the vLLM foundation is settled. |
feat/vllm-tailscale is the fork's combined branch: vLLM (PR NVIDIA#9), nodes across overlay networks such as Tailscale (PR NVIDIA#10), scripted headless pairing (PR NVIDIA#11), the fork's installer and release workflow, and now SGLang as a fourth engine. It is what the headless installer and the release packages build from.
|
Thanks all for your contributions to the project! We are just getting back from the long weekend and will be reviewing this PR and all the others as well. We are very excited about vLLM support! Hang tight. :) |
I saw this after the SGLang PR had already been submitted. You could open a PR as well maybe your version has a better chance of being accepted? |
|
Follow-up on the vLLM/SGLang GUI branch: testing against an existing native deployment turned up a few things that needed tightening up. Changes are in 21a363d on feat/vllm-sglang:
Validation: 224 desktop unit tests pass; typecheck, contracts and dead-code checks pass. Lint has no errors (one existing formatting warning). Go suites pass for shared, engine-manager, broker, OpenAI proxy, scheduler and TUI; inference-dispatcher tests and both adapter tests pass. ARM64 packaging succeeds. A live native vLLM embedding endpoint is detected as external/loaded, retains embedding metadata through PAIR, and rejects a chat request at the proxy. The model container was not restarted. SGLang adoption/routing has simulated-server coverage, not a new live SGLang GPU benchmark. Remote fleet rollout and controlled throughput benchmarking are still separate steps. Participating nodes need matching preview services and deployment policy; stock PAIR does not acquire this behavior from a manifest alone. Setup and limits. The optional adapter repo also has updated identity overrides and setup notes in a40049a. Service versions: engine-manager 0.20.0, OpenAI proxy 1.2.0, scheduler 0.7.0, broker 0.42.1 and TUI 0.8.1. These changes are on my fork branch; this comment links the follow-up rather than modifying the PR author's source branch. |
|
Another follow-up from testing this against the running Spark cluster: the UI was mixing up “PAIR owns this process” with “this process is running.” It also treated distributed workers with no HTTP server as stopped. The fix is on my fork: ff26f5b, branch
I rolled the matching PAIR services and policy onto eight cluster devices hosting three distributed vLLM deployments, plus the local embedding host. The live GUI reports all nine vLLM switches checked and read-only, with three cluster API heads and five workers. Model-container IDs, start times and PIDs stayed unchanged. No model containers were restarted and no inference benchmark load was sent. Validation: 226 desktop unit tests; shared, engine-manager, broker, scheduler, OpenAI proxy and TUI Go suites; typecheck, contracts, dead-code and SPDX checks. Lint has no errors and one existing unrelated formatting warning. Two ingress tests now isolate their config so a developer's actual deployment policy can't change their expected results. One limit worth being explicit about: Docker “running” describes the container, not the health of every child process. Head API readiness is still checked separately. Non-Docker workers remain unknown until a suitable observer exists. SGLang follows the same code path and has test coverage, but I don't currently have a live SGLang deployment for a GPU integration run. Setup and wire-field details: external deployments. This is a follow-up commit for the PR author to pick up; it doesn't change the PR's source branch directly. |
Description
PAIR supports two inference engines, Ollama and LM Studio. This adds vLLM as a third, on the same footing: detected or adopted, started and stopped, advertised over discovery, routed to, scheduled, and shown in the desktop and terminal interfaces.
User-visible outcome:
vllm serve …or thevllm/vllm-openaicontainer) is adopted rather than restarted. That is the normal path./v1/models. A peer's request is routed to whichever local engine owns the requested model.GET /version). The scheduler ranks vLLM nodes with the same load signal as the other engines.Scope
Included: engine manifest (
services/nvpair-engine-manager/manifests/vllm.json, Linux amd64/arm64), theruntime.model/runtime.extra_argsmanifest fields and the persistentengine:set-modelmethod, discovery keyvl, the OpenAI-compatible proxy generalised to any OpenAI-compatible engine (binary name and relay namespace unchanged; README retitled), broker advertise loop and manual-node bridge, scheduler engine list, TUI labels, desktop engine type and capabilities, docs.Excluded: a managed port facade for vLLM (it keeps port 8000 and is never moved), model download or deletion for vLLM, and any Windows or macOS install path.
Breaking change for API consumers of
lmstudio-proxy:node/add-manualandnode/remove-manualnow require anenginefield (lmstudioorvllm), hence its MAJOR bump.Related: a sibling PR makes nodes added by address first-class peers on overlay networks. Both touch
services/nvpair-manual-nodes/manager.goandservices/versions.json; whichever merges second needs a small conflict resolution (vLLM becomes a third engine leg of the bare-host probe, and the higher version of each component is kept).Validation
Environment: macOS 15 arm64, Go 1.27, Node 23.
All pass, except
nvpair-engine-manager TestUninstallTerminatesRunningInstance, which fails identically on a pristinemainon this host (it cannot resolve the image path of the process holding a port) and is unrelated.End-to-end: a stub serving vLLM's
/health,/version,/v1/models, and/v1/chat/completionswas adopted by the real broker (engine:get-installedreported it running on its port with the configured model), the OpenAI proxy listed its model and completed a chat request, and the workload was taggedvllm. Adoption of a real two-node vLLM (--tensor-parallel-size 2 --nnodes 2) on Linux arm64 has also been exercised. The manifest'sinstallblock and the 30-minute readiness budget have not been run on real Linux GPU hardware.Risk
enginefield on the proxy's manual-node methods is required (MAJOR bump onlmstudio-proxy).EngineStatusgains an optionalmodel. Everything else is additive.--host 127.0.0.1; an adopted instance keeps whatever bind it was started with, exactly as an adopted Ollama does.Versions:
lmstudio-proxy0.16.2→1.0.0,nvpair-engine-manager0.17.4→0.18.0,nvpair-ui-broker0.40.2→0.41.0,nvpair-manual-nodes0.11.1→0.12.0,nvpair-job-scheduler0.4.1→0.5.0, patch bumps fornvpair-node-scanner,nvpair-errors,nvpair-workload-manager,nvpair-tui; product 0.91.7→0.92.0.Checklist
git commit -s), certifying the Developer Certificate of Origin.services/versions.json, and described user-visible changes above so they reach the release notes.Related: #10 (touches the same manual-nodes file; see the note under Scope) and #11.