preview provider connection identity and harness bindings without changing execution - #6387
Merged
Conversation
#6366) Adds a read-only import preview for the connection/harness/route graph designed in docs/plans/2026-09-06-provider-connections-and-harnesses.md. `GET /api/providers/management/preview` answers what an import WOULD create from the provider records an install already runs, and which records it would leave alone and why — without persisting a graph, running a migration, or changing how anything executes. Three pure modules back it: - `providerHarnesses.js` — which agent program a record drives, the modes it supports, and the model-name adapters. Canonicalizing a stored model alias is verified against the real OpenCode adapter rather than guessed, so import never rewrites a saved model string by stripping a prefix. - `providerConnections.js` — what backend a record reaches. Identity compares real server-side credentials and refuses once a value has been redacted, so a sanitized record can never merge two connections; dynamic, external, unparsable or endpoint-less configuration stays isolated with a reason. - `providerGraphPreview.js` — the version-1 management DTOs and the builder. Only the already-proven same-harness CLI/TUI sibling groups share a binding; two harnesses on one daemon surface as a link SUGGESTION requiring explicit confirmation, never an automatic merge that would hand one route another's credentials. Every original executable route ID survives, and the preview re-materializes each original record — pins, secrets, consent flags and unknown custom fields included — which is both the import-fidelity proof and the downgrade contract for an install that drops back to running providers.json alone. The flat `GET /api/providers` shape is untouched. Guarded by a boundary test: serving the preview makes no outbound request, and nothing in the builder's static import closure can spawn a process, open a pty, or reach a provider service — a configuration screen must never be what starts a generation call.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Read-only import preview for the provider connection graph designed in
docs/plans/2026-09-06-provider-connections-and-harnesses.md.GET /api/providers/management/previewanswers what an import would create from the provider records an install already runs — and which records it would leave alone, with reasons. It persists no graph, ships no migration, adds no management UI, and changes nothing about execution.server/lib/providerHarnesses.js— which agent program a record drives (claude / opencode / codex / antigravity / cursor / grok / kimi / pi), its supported modes and wire protocol, plus the model-name adapters. Canonicalizing a stored alias is verified against the real OpenCode adapter, so import never rewrites a saved model string by heuristically stripping a prefix.server/lib/providerConnections.js— what backend a record reaches. Identity compares real server-side credentials and refuses once a value has been redacted, so a sanitized record can never merge two connections. Dynamic env references, external harness config files, unparsable config, foreign namespaces and undeclared endpoints stay isolated with an explicit reason.server/lib/providerGraphPreview.js— the version-1 management DTOs (Zod,.strict()) and the builder. Only the already-proven same-harness CLI/TUI sibling groups (providerModeGroups) share a binding; two harnesses on one daemon surface as a link suggestion requiring explicit confirmation, never an automatic merge that would hand one route another's credentials.providerGraphUniquenessViolationschecks the UNIQUE constraints the durable schema (Persist provider connections with recoverable legacy route projection #6367) will enforce, including the partial index for null-harness API bindings.Every original executable route ID survives, and
projectPreviewToProvidersre-materializes each original record — pins, secrets, consent flags and unknown custom fields included. That is both the import-fidelity proof and the downgrade contract for an install that drops back to runningproviders.jsonalone.GET /api/providersis unchanged.routeModeEligibilityis the pure declarative half of mode eligibility (harness support + enabled + caller-allowed mode + text-transport consent); prerequisite probing and fallback candidate policy stay with #6368.Test plan
cd server && npm test— 2010 files / 39,950 tests green.server/lib/providerConnections.test.js— transport identity: env-var vs endpoint transport, redacted credentials refused, remote host never equated with the local daemon, lossless owned-field round-trip.server/lib/providerGraphPreview.test.js— the three fixtures from the issue (Claude Ollama, OpenCode Ollama, separate remote Ollama API), no cross-harness merge, custom same-harness config imported as a distinct variant, isolation reasons, unresolved aliases and stale pins, and a fidelity round-trip over the entire shipped provider catalog (49 records).server/routes/providers.management.test.js— the route, no credential material in the body,GET /api/providersstill byte-compatible, and the boundary test: serving the preview makes no outbound request, and nothing in the builder's static import closure can spawn a process, open a pty, or reach a service module.npm run generate:api-docsre-run; the catalog gains exactly the one new operation.Closes #6366