[Feature]: Engine-agnostic credential so PAIR can talk to an authenticated local engine
Maintainer antworten meist innerhalb von 5 Tagen
@Truenya arbeitet bereits daran.
Seit 04.9.2026.
Bewertung
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Anfängerfreundlichkeit
- 48/100
Rechercherichtung
Beginne damit, Engine-Anfragen durch services/nvpair-engine-manager/registry.go, actions.go und pull.go nachzuverfolgen, und folge dann controlmodels.go, controlstream.go, lmstudio-proxy und ollama-proxy. Als erledigt gilt die Aufgabe, wenn authentifizierte Inventar-, Steuerungs- und Inferenzanfragen funktionieren, falsche Anmeldedaten einen eindeutigen Fehler erzeugen, Anmeldedaten lokal bleiben und redigiert werden und die aufgeführten Validierungsszenarien bestehen.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Area
Engine or model management
User problem
PAIR has no way to hold a credential for the local inference engine it manages, so enabling the engine's own authentication makes the engine invisible to PAIR and takes the cluster's routing offline.
Local engines increasingly ship a bearer-token auth option: LM Studio has "Require Authentication" with a token manager in its server settings, llama.cpp's server has --api-key, and Ollama deployments are commonly fronted by a reverse proxy that requires one. These are first-class, documented features of the engines PAIR supports.
Today, turning any of them on breaks PAIR completely. Observed on 0.1.1 (13b6811), built from source with make build-services, nvpair-ui-broker 0.40.2:
| Request | Result |
|---|---|
| Engine directly, with credential | 200 |
| Engine directly, no credential | 401 |
PAIR proxy /v1/models, no credential |
503 {"error":"model inventory unavailable"} |
PAIR proxy /v1/models, credential in Authorization |
503 {"error":"model inventory unavailable"} |
PAIR Ollama proxy /api/tags |
503 {"error":"model inventory unavailable"} |
nvpair-engine-manager reaches the engine over plain loopback HTTP with no credential — fmt.Sprintf("http://127.0.0.1:%d%s", port, path) in services/nvpair-engine-manager/actions.go:114 and pull.go:98. The engine answers 401, inventory comes back empty, and because the proxies only route to a node whose inventory advertises the exact requested model, nothing is ever eligible.
The blast radius is cluster-wide, not local to the affected node. Any peer that would have routed to that engine also returns 503, since the models it was relying on have disappeared from the merged inventory.
Two things make this hard to self-diagnose:
- Supplying the credential as a client
Authorizationheader on the proxy does not help. The request fails at the eligibility gate before any forwarding, so the header never reaches the engine. - The error names the wrong subsystem.
model inventory unavailablepoints at inventory, not at the401that caused it.services/lmstudio-proxy/proxy.go:1005documents401as a "genuine client error" that is deliberately not retried, which is the correct call for a client mistake but hides an engine-side auth failure.
There is no existing mechanism to work around. A repo-wide code search finds zero hits for apiKey, api_key, or LMSTUDIO_API_KEY. Every Authorization hit in the tree belongs to CORS allow-headers, cluster mTLS/truststore, tests, or a vendored RFC text — none touch the engine hop. The docs, including known-issues.mdx and troubleshooting.mdx, never mention engine authentication. The only available workaround is to turn the engine's auth back off.
Desired outcome
An engine-agnostic credential that PAIR carries on every engine-bound request, rather than anything specific to one engine.
The engine registry is already the right seam and is already engine-agnostic — services/nvpair-engine-manager/registry.go:142 models an engine as a URL template (http://127.0.0.1:{port}/) and probes both OpenAI-shaped (/v1/models, /api/v1/models) and Ollama-shaped (/api/tags, /api/ps) surfaces. A per-engine credential field there would cover every current and future engine at once, instead of adding an LM Studio-specific setting that Ollama and a bare llama.cpp server would each need duplicated later.
Concretely:
- A per-engine credential, configurable by flag and environment variable, and surfaced wherever engines are configured (settings and the TUI's Engines tab).
- Applied on every request PAIR makes to that engine: inventory probes, the control operations in
controlmodels.go/controlstream.go(/v1/models/load,/unload,/delete,/pull), and inference forwarding in bothlmstudio-proxyandollama-proxy. A credential that covers inference but not inventory would still leave the node unroutable. - Sent as
Authorization: Bearer <value>by default, since that is what LM Studio,llama.cpp --api-key, and typical Ollama reverse proxies all accept. A configurable header name would future-proof engines that differ. - A distinguishable error when the engine rejects the credential. An engine returning
401to PAIR should surface as an engine authentication failure, not asmodel inventory unavailable.
Both proxies are near-identical clones sharing routing, failover, and CORS code, so this should land once in shared code and apply to both.
Alternatives considered
- Forward the client's
Authorizationheader to the engine. Rejected: it does not fix inventory, which is fetched bynvpair-engine-manageroutside any client request, and inventory is what gates routing. It would also mean every client needs the engine's credential, which defeats PAIR being the front door. - Turn the engine's authentication off. The current de facto workaround. It is not viable for anyone who enabled engine auth deliberately, and it silently narrows what PAIR can sit in front of.
- An LM Studio-specific setting. Narrower to implement, but the same gap already exists for
llama.cpp --api-keyand proxied Ollama, so it would need duplicating per engine. The registry abstraction makes the generic version roughly the same amount of work.
Compatibility and security implications
- Fully backward compatible. No credential configured means today's behavior exactly — no header added.
- The credential must not cross the cluster boundary. It authenticates a node to its own loopback engine. It should never be forwarded to peers or included in anything advertised over mDNS. Peer-to-peer auth is already handled by cluster mTLS pinning, and
services/lmstudio-proxy/ingress.go:87-93documents the mTLS pin as "the sole authorization boundary," forwarding trusted peers straight to the loopback engine — that model is unchanged, since the receiving node applies its own credential locally. - Storage alongside existing per-user material in the cluster/data dir, at the same file permissions as other node secrets.
- Redaction: it must be excluded from logs and from the log sanitizer in
resources/scripts/referenced bySUPPORT.md. - No wire-format or API-compatibility change: this only adds a header on requests PAIR already makes.
Validation approach
- Start a supported engine with authentication enabled (LM Studio "Require Authentication", or
llama.cppserver with--api-key). Confirm the engine returns401unauthenticated and200with the credential. - Without configuring PAIR, confirm the current failure:
GET /v1/modelson the PAIR proxy returns503 {"error":"model inventory unavailable"}, on that node and on any peer that would route to it. - Configure the credential in PAIR. Expect
GET /v1/modelson the proxy to list the engine's models again, andPOST /v1/chat/completionsagainst one of those model IDs to complete — from the engine-bearing node and from a peer routing to it. - Exercise a control operation (model load or unload) to confirm the credential is applied outside the inference path.
- Configure a deliberately wrong credential. Expect an error that identifies engine authentication as the cause, distinct from an empty-inventory error.
- Confirm the credential appears in no log output and in no sanitizer bundle, and that a peer node never receives it.
Confirmations
- I searched existing issues for duplicates.
- I agree to follow the Code of Conduct.
- Vorherrschende Sprache
- Go
- Sterne
- 1.6k
- Forks
- 266
- Ø Merge
- 3 T. 6 Std.
- Gemergte PRs (30 T.)
- 22
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Hat eine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus NVIDIA/Personal-AI-Router
-
Schwierigkeit 5/5 Über eine Woche Anfängerfreundlichkeit 20/100
NVIDIA/Personal-AI-Router#165 ·
Maintainer antworten meist innerhalb von 5 Tagen
-
bug
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 46/100
NVIDIA/Personal-AI-Router#164 ·
Maintainer antworten meist innerhalb von 5 Tagen
-
enhancement
Schwierigkeit 4/5 Über eine Woche Anfängerfreundlichkeit 12/100
NVIDIA/Personal-AI-Router#162 ·
Maintainer antworten meist innerhalb von 5 Tagen
-
enhancement
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 25/100
NVIDIA/Personal-AI-Router#154 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 5 Tagen
-
[Feature]: [Ollama] Alert the user about model pull failuresEvtl. vergeben @ckelseynv hat das vor 3 Tagen übernommen. Offenenhancement
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 56/100
NVIDIA/Personal-AI-Router#152 · 1 Kommentar · 1 zugewiesene Person ·
Maintainer antworten meist innerhalb von 5 Tagen
Alle Issues in NVIDIA/Personal-AI-Router
Ähnliche Issues
-
unbounded value for n in `/v1/logs` can panic/OOMEvtl. vergeben Ein verknüpfter Pull Request ist offen oder bereits gemergt. Offensmall item
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
canonical/pebble#1127 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 89/100
open-policy-agent/opa#9366 · 1 Reaktion ·
Maintainer antworten meist innerhalb von 1 Tag
-
defect
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
nats-io/nats-server#8752 ·
Maintainer antworten meist innerhalb von 1 Tag
-
enhancement needs-acceptance wg/router-models-inference-runtime
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
vllm-project/semantic-router#5015 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
fileserver: precompressed sidecar's Content-Encoding and Content-Length end up on error responsesEvtl. vergeben @NitinKumar004 hat das heute übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 73/100
caddyserver/caddy#8204 ·
Maintainer antworten meist innerhalb von 1 Tag