Usage · 08
Configure DeepSeek and OpenAI-Compatible Model Providers
Configure native, catalog, and custom routes while keeping credentials write-only, model metadata honest, and sessions reproducible.
- Reading time
- 18 minutes
- Sources verified
Know what Settings changes and when
Open Settings → Models after starting the Web UI. Provider cards are backed by adapter-owned settings namespaces, not a browser-only list. Saving a valid profile updates the user settings layer, and adapters re-read resolved settings once per operation. A changed endpoint, catalog, or request default therefore reaches the next model request without a server restart; an in-flight stream keeps the connection facts it started with.
The composition entry remains the base layer. User settings override it, while schema validation and adapter-specific validation reject an unusable draft instead of storing it. If an external edit becomes invalid, the settings service retains the last good namespace snapshot and warns. This keeps a typo from silently removing every provider route.
Settings → Models → edit draft → validate namespace/profile
accepted → persist settings → next operation resolves new facts
rejected → show settings-rejected → keep previous working factsKeep credentials write-only and reference-based
Configuration carries a credential reference such as DEEPSEEK_API_KEY, never the secret. The Models page sends a new key to the credential provider, then receives only redacted state: whether the reference is configured, its source, and whether it is writable. It never reads the literal saved value back. The local provider stores managed values in $DSH_HOME/.credentials.yaml while settings retain apiKeyEnv.
Resolution happens per model request, so a managed key rotation reaches the next operation. Inherited environment values are read-only and shadow the managed file; trying to overwrite them through the UI is refused. Environment changes after launch are not observable and require restart. Never place a literal key in settings.yaml, cordis.yml, screenshots, shell history, or diagnostic exports.
# $DSH_HOME/settings.yaml — safe reference, no literal secret
llm-deepseek:
apiKeyEnv: DEEPSEEK_API_KEY
baseURL: https://api.deepseek.comconst info = await ctx.credentials.describe(credentialRef('DEEPSEEK_API_KEY'))
// { configured: true, source: 'file', writable: true }
// No secret value is returned.Configure the native DeepSeek route
The native adapter owns the provider route deepseek-official. Its card asks for one key. By default apiKeyEnv is DEEPSEEK_API_KEY and baseURL resolves from configured settings, then DEEPSEEK_BASE_URL, then the public endpoint. The adapter advertises V4 Flash and V4 Pro by default; an explicit models list replaces that catalog, while an empty list advertises none. Catalog metadata guides selectors but the native adapter passes an unlisted model id through to the wire.
llm-deepseek:
apiKeyEnv: DEEPSEEK_API_KEY
baseURL: https://api.deepseek.com
defaultContextWindow: 1000000
maxTokens: 256000
models:
- id: deepseek-v4-flash
name: DeepSeek-V4-Flash
- id: private-reasoner
contextWindow: 512000
maxTokens: 32768The route is chat-completions and text-only. Its model context capacity influences pressure handling, while maxTokens supplies an output default unless a request overrides it. Do not advertise a capacity merely because a marketing page mentions it; configure the limit actually supported by the selected gateway and deployment.

Add an installed catalog provider
Choose Add provider for a route already known to the installed pi-ai catalog, such as OpenAI or Anthropic. The catalog supplies provider identity, endpoint, protocol, model list, capabilities, and defaults. Usually you provide only the appropriate credential. A profile can override the base URL for a proxy, narrow the model list, correct capacities, or reshape individual catalog models.
Native authentication providers are different. Bedrock needs AWS credentials and region, Vertex uses application-default credentials and project facts, Azure needs provider environment plus api-version, and Codex uses OAuth. A generic API-key field cannot substitute for those protocols. Prefer the catalog route when its authentication and wire semantics match rather than declaring a superficially compatible custom endpoint.
llm-pi-ai:
providers:
openai:
apiKeyEnv: OPENAI_API_KEY
baseURL: https://proxy.example.com/v1
retryPolicy:
mode: normal
maxRetries: 3Declare a custom compatible provider completely
Choose Add a custom provider for a company gateway, self-hosted endpoint, or provider absent from the installed catalog. Supply a lowercase Provider ID, display name, base URL, supported API protocol, credential, and at least one uniquely identified model. A hand-declared route cannot inherit missing transport facts, so api, baseURL, and models are required.
The Provider ID is permanent. Requests, saved sessions, the default model, settings paths, and credential references rely on it. Renaming it in place strands those references. Add a new provider, validate it, move new sessions to it, and only then remove the old route. Display name, endpoint, protocol, credential reference, and catalog remain editable.
llm-pi-ai:
providers:
acme-gateway:
displayName: Acme Gateway
apiKeyEnv: ACME_GATEWAY_API_KEY
api: openai-completions
baseURL: https://gateway.acme.example/v1
defaultContextWindow: 65536
defaultMaxTokens: 4096
models:
- id: acme-chat
name: Acme Chat
contextWindow: 65536
maxTokens: 4096- provider key: permanent lowercase route identity.
- displayName: editable UI label.
- api: exact protocol spoken by the endpoint.
- baseURL: endpoint used by every model on the route.
- models: served ids plus honest capacity and capability metadata.

Treat model discovery as draft assistance
Fetch available models interrogates the endpoint with the base URL, protocol, and one-shot credential currently displayed in the form. For OpenAI-compatible endpoints it calls GET /models. The credential is used for that interrogation and is never stored by discovery. Returned entries are candidates, not registered models; selecting them updates the draft, and only Save persists settings and credentials.
Most listing endpoints reveal only ids. Discovery cannot prove context capacity, output limits, reasoning dialect, or image support. Duplicate or unusable ids are dropped, and adoption still owes metadata required by the adapter. Catalog providers use installed knowledge without a network request. If an endpoint lacks GET /models, enter the models manually.
form draft { provider?, baseURL, api, one-shot key }
→ Fetch available models
→ GET /models when supported
→ candidate ids only
→ select candidates into draft
→ review capacities/modalities
→ Save settings and credential separatelyDeclare image input conservatively
A manually entered model is treated as text-only unless metadata says otherwise. The harness refuses an attached image before network transmission when the selected model lacks image input. This conservative default avoids persisting an image in a session whose endpoint cannot accept it. DeepSeek's native chat-completions adapter is text-only and cannot be changed by configuration.
For a custom vision model, add input: [text, image] to that model in settings.yaml. Use route defaultInput only when every otherwise undescribed model supports those modalities. A per-model input wins, then installed catalog metadata, then route fallback. These fields are deployment claims, not endpoint verification: over-claiming admits an image that the provider may reject after it is durable.
llm-pi-ai:
providers:
vision-gateway:
apiKeyEnv: VISION_API_KEY
api: openai-completions
baseURL: https://vision.example/v1
defaultInput: [text]
models:
- id: text-chat
- id: vision-preview
input: [text, image]If a provider rejects an image, remove the incorrect image grant and start a new session. The prior session still contains the attached image, so retrying the same request repeats the incompatible history.
Understand defaults and session stickiness
Configured providers appear in the model picker. Selecting one also sets the default for new sessions. Once a session has sent a request, its provider, model, rendered request header, and subsequent changes are recorded in its own log. Editing the global default does not silently reroute that established conversation. This makes replay and capacity decisions reconstructable.
Existing session S: first request records acme-gateway/acme-chat
Global selection changes to deepseek-official/deepseek-v4-flash
New session N uses the new default
Session S remains on its logged route unless explicitly changedIf the saved default names a deleted provider, the composer shows Select model and blocks input. Select a live route rather than recreating an unrelated provider under the old permanent id. Before deleting a route, inventory active sessions and automation that reference it.
Know how route and model fields resolve
On a catalog route, omitted endpoint, protocol, models, capacities, reasoning support, and modalities inherit installed catalog facts. Supplying models narrows or replaces the served catalog, and each named entry may still inherit unset fields from the installed model with the same id. modelOverrides changes selected installed entries without discarding their siblings. On a hand-declared route no catalog can complete the minimum contract, so the profile must spell the protocol, endpoint, and non-empty model list.
Capacity fields have different jobs. contextWindow describes total model capacity for pressure and compaction decisions. A configured model maxTokens becomes the default output request budget; a catalog capability alone is not automatically a request default. Route fallbacks cover otherwise unsized models, but they are deployment guesses that should be corrected against endpoint behavior. The adapter does not magically reconcile an output budget larger than an endpoint permits.
Catalog resolution for one model
identity: profile model id → installed model with same id
modalities: model input → catalog input → route defaultInput
capacity: model contextWindow → catalog capacity → route fallback
output request default: configured model maxTokens → configured route default
transport: route override → installed endpoint/protocolReasoning deserves the same care. A private OpenAI-compatible URL may not reveal whether thinking uses OpenAI, DeepSeek, or another dialect. Configure only supported reasoning efforts and compatibility switches documented by the adapter, then verify wire behavior with a non-production key. Protocol compatibility at the HTTP path does not imply reasoning-field compatibility.
Diagnose failures by stable boundary
MISSING_CREDENTIAL means the configured reference resolved nowhere; store it through Models or supply the named environment variable. INVALID_CREDENTIAL means a value exists but cannot safely form an authentication header; replace it without logging it. UNKNOWN_MODEL on pi-ai means the selected id is not in that route's resolved catalog. A discovery 401 points to the one-shot key or endpoint authentication, while NO_DISCOVERY or INVALID_DISCOVERY belongs to discovery composition or draft identity.
MISSING_CREDENTIAL → configure the referenced secret
INVALID_CREDENTIAL → replace malformed value; never print it
UNKNOWN_MODEL → select/add model under the same provider route
401 from Fetch → check key and base URL
image refused locally → correct input metadata
provider rejects image → metadata over-claimed endpoint support
TRANSPORT → DNS/TLS/proxy/baseURL boundaryNative DeepSeek maps provider responses to stable AUTH, QUOTA, RATE_LIMIT, CONTEXT_WINDOW_EXCEEDED, INVALID_REQUEST, SERVER, and HTTP status codes; transport, timeout, abort, and malformed-stream failures have separate identities. Preserve the first stable code, HTTP status, retry-after, and request id, but redact message content, endpoints containing secrets, and credentials.
Verify and secure a provider before production
Use a new session and test plain text, tool calling, cancellation, context pressure, rate limiting, invalid authentication, and every declared modality. Confirm the selected provider/model in durable request headers, not only the picker label. For a custom gateway, verify TLS ownership, data retention, regional routing, request logging, and whether harness attribution and stable anonymous/session headers reach it.
Provider acceptance checklist
[ ] permanent route id documented
[ ] baseURL hostname and TLS verified
[ ] protocol matches endpoint behavior
[ ] credential is write-only and least privilege
[ ] model ids, context windows, and output limits tested
[ ] image claims tested per model
[ ] discovery results reviewed before save
[ ] existing-session stickiness understood
[ ] stable errors and request ids retained redacted
[ ] deletion/rollback plan protects referenced sessionsPin the harness and catalog revision because provider protocols and preview configuration evolve. Rotate test credentials after evaluation. A compatible wire shape does not guarantee identical tool calls, reasoning fields, streaming termination, safety policy, billing, or retry semantics; verify the behavior your workload depends on.
Official sources
- Provider configuration guide ↗Supports: Settings workflows, custom provider identity, discovery, image input, selection, and troubleshooting
- DeepSeek adapter ↗Supports: deepseek-official config and catalog, dynamic resolution and error codes
- Pi AI provider adapter ↗Supports: catalog and custom profile fields, modalities, protocol, and UNKNOWN_MODEL
- Credential seam ↗Supports: reference-only configuration, per-operation resolution and redacted describe
- Local credential provider ↗Supports: layer precedence, managed file safety and environment shadowing
- Settings subsystem ↗Supports: namespace validation, layering, and last-good behavior
- LLM service ↗Supports: provider directory, discovery draft contract, and model metadata

