Model ProvidersNine provider types, encrypted keys, subscription OAuth, and reasoning levels verified against live APIs.

A model provider is a named record on an account: a type, a base URL, and references to encrypted secrets. Agents name a provider and a model; the runtime maps both onto the Pi SDK at execution time.

type ModelProviderConfig = { type: string modelDefaults?: Record<string, unknown> secretRefs?: Record<string, string> baseUrl?: string authMode?: 'api-key' | 'subscription' }

The provider table

PROVIDER_SPECS (agents/src/api-service.ts:6689-6756) is the whole registry — adding a provider type is usually one entry here plus a matching entry in the desktop's provider-registry.ts.

Type

Pi API

Default base URL

Custom URL

Key required

openai

openai-completions¹

https://api.openai.com/v1

no

yes

anthropic

anthropic-messages

https://api.anthropic.com

no

yes

google

google-generative-ai

https://generativelanguage.googleapis.com/v1beta

no

yes

openrouter

openai-completions

https://openrouter.ai/api/v1

no

yes

deepseek

openai-completions

https://api.deepseek.com

no

yes

groq

openai-completions

https://api.groq.com/openai/v1

no

yes

xai

openai-completions

https://api.x.ai/v1

no

yes

ollama

openai-completions

http://localhost:11434/v1

yes

no

custom

openai-completions

yes

no

¹ openai reroutes to openai-responses when the resolved model is reasoning-flagged (:6923).

For pinned providers the spec's default base URL always wins even if a baseUrl was stored; only ollama and custom honor an override (resolveProviderBaseUrl, :6804-6809). Model lists come from live endpoints: GET /models with a bearer token for OpenAI-compatible, x-api-key plus anthropic-version: 2023-06-01 for Anthropic, and a supportedGenerationMethods filter for Google.

Secrets

API keys live in the secrets table, encrypted with AES-256-GCM. The key is 32 random bytes generated once and stored in server_config under secret_encryption_key_v1; each write gets a fresh 12-byte nonce, and the stored ciphertext is nonce || encrypted (encryptSecret, agents/src/api-service.ts:9915-9952).

Two honest caveats: the encryption key sits in the same SQLite database it protects — there is no OS keychain or KMS integration — and there is no general secret-deletion action, though deleting a provider removes its key. Both are tracked in Security.

Nothing plaintext ever leaves: RedactedModelProvider exposes hasSecrets: boolean, and RedactedSecret carries a literal hasValue: true rather than any bytes.

Subscription sign-in (OAuth)

Beyond API keys, a provider can use authMode: 'subscription' — today only OpenAI ("Sign in with ChatGPT"). The flow lives in agents/src/provider-oauth.ts and is deliberately headless: the server has no localhost of its own to catch a redirect, so loginOpenAICodexHeadless runs PKCE without a loopback listener and the user pastes the code back through SubmitProviderOAuthCode.

Execution then reroutes to the openai-codex Pi provider against https://chatgpt.com/backend-api, with its own model catalog (gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4). Refreshed tokens are persisted back through the encrypted secret store by PersistedOAuthBackend. When a token goes bad the secret is flagged needsReauth, surfacing as authStatus: 'needs-login' in the UI.

The whole feature is gated by the operator flag SEED_AGENTS_SUBSCRIPTION_AUTH; with it off, StartProviderOAuth returns 403.

Reasoning levels

ReasoningLevel is minimal | low | medium | high | xhigh. What each model accepts is genuinely inconsistent, and the file header (agents/protocol/src/reasoning.ts:1-8) explains why the table is hand-verified: providers gate levels per model generation — e.g. OpenAI's gpt-5 family accepts minimal but not none, while gpt-5.1+ accepts none but not minimal.

Family

Levels

When unset

OpenAI gpt-5 / gpt-5-mini

minimal, low, medium, high

provider default (cannot disable)

OpenAI gpt-5.1

low, medium, high

off (effort: 'none')

OpenAI gpt-5.2+ (5.4, 5.6)

low, medium, high, xhigh

off

OpenAI o-series (o1/o3/o4)

low, medium, high

provider default

Anthropic claude-3-7+

minimal, low, medium, high

off

Google gemini-2.5+

minimal, low, medium, high

off, except -pro (default)

gpt-5-chat* exposes no reasoning control at all.

One footgun to know about: provider.modelDefaults is shallow-merged over the Pi-generated payload, so a stray reasoning key there will clobber the level the agent asked for.

Related

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime