Skip to content

Providers & Models

PizzaPi is built on the pi coding agent, which supports 30+ AI providers out of the box. You can authenticate with a paid subscription via OAuth, set API keys, or add custom providers like Ollama or LM Studio for local models.


These providers use OAuth — authenticate with /login inside a session:

Provider Subscription
Anthropic Claude Pro / Max
OpenAI ChatGPT Plus / Pro
GitHub Copilot Copilot subscription

Pi 1.0’s native OpenAI ChatGPT login supersedes the older inherited OpenAI Codex subscription provider for new sign-ins. Existing legacy entries may still appear from older runner auth state, but prefer OpenAI for ChatGPT-backed sessions.

These are the most commonly used API-key providers. Many other built-in providers (DeepSeek, Fireworks, Together, Moonshot AI, Ollama Cloud, Cloudflare, OpenCode, and more) are also available — run pizza models to see the providers configured on your system and their required env vars.

Provider Environment Variable
Anthropic ANTHROPIC_API_KEY
OpenAI OPENAI_API_KEY
Google Gemini GEMINI_API_KEY
Azure OpenAI AZURE_OPENAI_API_KEY
Google Vertex AI GOOGLE_CLOUD_API_KEY
Amazon Bedrock AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY
Mistral MISTRAL_API_KEY
Groq GROQ_API_KEY
Cerebras CEREBRAS_API_KEY
xAI XAI_API_KEY
OpenRouter OPENROUTER_API_KEY
Vercel AI Gateway AI_GATEWAY_API_KEY
Hugging Face HF_TOKEN
Kimi For Coding KIMI_API_KEY
MiniMax MINIMAX_API_KEY

Inside a PizzaPi session, type /login in the chat input. You’ll be prompted to select a provider and complete the OAuth flow in your browser. Tokens are stored in ~/.pizzapi/auth.json and auto-refresh when they expire.

The web UI’s Runner Settings → Model providers panel drives the same runner login flow. It supports ordinary browser redirects, provider selection prompts, and copy-code/manual-code prompts such as Anthropic’s headless login flow. It handles provider credentials only; configure MCP connections separately through PizzaPi’s MCP settings.

OpenAI ChatGPT login uses a stable installation deviceId in the runner’s settings.json. The web login flow and pizza auth openai create and reuse this ID through Pi’s settings manager, just like terminal /login.

Use /logout to clear stored credentials.

Set the provider’s environment variable before starting PizzaPi:

Terminal window
export ANTHROPIC_API_KEY=sk-ant-...

Or store it in the auth file at ~/.pizzapi/auth.json:

{
"anthropic": { "type": "api_key", "key": "sk-ant-..." },
"openai": { "type": "api_key", "key": "sk-..." }
}

The auth file is created with 0600 permissions (user read/write only). Auth file credentials take priority over environment variables.

The key field in auth.json supports three formats:

Format Example Description
Shell command "!security find-generic-password -ws 'anthropic'" Executes command, uses stdout
Environment variable "$MY_ANTHROPIC_KEY" or "${MY_ANTHROPIC_KEY}" Reads the named env var. A $ prefix (or ${...}) is required for interpolation; a bare name is treated as a literal value.
Literal value "sk-ant-..." Used directly

Shell commands are useful for pulling keys from password managers:

{
"anthropic": { "type": "api_key", "key": "!op read 'op://vault/item/credential'" }
}

When multiple sources provide credentials for the same provider:

  1. CLI --api-key flag (highest priority)
  2. auth.json entry (API key or OAuth token)
  3. Custom provider keys from models.json
  4. Environment variable (final fallback)

Use the /model command in the chat input to open the model selector. This shows all available models across your authenticated providers.

In the PizzaPi web UI you can also use /cycle_model (alias of /model) to cycle through a subset of models, and /effort (or /cycle_effort) to change reasoning effort.

Pi 1.0 model catalogs can include chat, image, and classifier operations. PizzaPi’s chat model picker and runner model defaults intentionally show chat models only; image and classifier models are used programmatically through codemode or extensions and are not selectable as the session’s chat model.

Virtual models remain selectable like normal chat models. When Pi reports a concrete responseModel different from the selected model, PizzaPi shows both on that assistant message (selected → response) so you can distinguish the requested model from the model that answered.

Set your preferred default model in ~/.pizzapi/settings.json:

{
"defaultProvider": "anthropic",
"defaultModel": "claude-sonnet-4-20250514",
"defaultThinkingLevel": "medium"
}

Limit which models appear when cycling:

{
"enabledModels": ["claude-*", "gpt-4o", "gemini-2*"]
}

The web UI’s model-visibility preference syncs hidden models to the runner as PIZZAPI_HIDDEN_MODELS, a JSON array of provider/modelId keys:

Terminal window
export PIZZAPI_HIDDEN_MODELS='["openrouter/vendor/model","ollama-cloud/glm-5.2"]'

Workers read this list when listing, switching, cycling, and spawning model-aware helpers. Mid-session changes arrive through a relay hidden_models_update and refresh the worker’s environment. This is a UI preference and hard block by model name; it is not a security boundary.

fallbackModels is an ordered chain in ~/.pizzapi/settings.json:

{
"fallbackModels": [
"openai-codex:gpt-5.5",
"ollama-cloud:glm-5.2"
]
}

Fallback runs only when the current assistant turn ends with stopReason: "error" and the error text matches a usage-limit, quota, rate-limit, or provider-capacity condition. Context-window exhaustion is not a rate limit. PizzaPi records the last user input for the session, switches to the next authenticated fallback model, and re-sends that input as a steer message.

Cascade behavior:

  1. If the current model is in the fallback chain, PizzaPi starts after that entry.
  2. Otherwise it starts at the beginning of the chain.
  3. Models that cannot be resolved, have already been tried for this prompt, or lack configured auth are skipped.
  4. The process repeats until a fallback succeeds or the chain is exhausted.

The UI receives a visible fallback_status notice such as “Primary model hit a provider limit. Retrying with …”. If no captured input exists, PizzaPi sends a generic retry instruction instead of silently doing nothing.

Enable Runner → Settings → Models → Wait for rate limits to return, or set "waitForRateLimits": true in ~/.pizzapi/settings.json. It defaults to false; saved settings apply on the next session start.

After a usage-limit failure exhausts the fallback chain (including an empty chain), PizzaPi can wait for the current model’s subscription quota to recover. It checks quota before waiting, waits until the latest applicable exhausted window resets, then checks again before continuing. Anthropic model-family windows are matched to the selected model. Missing, stale, malformed, or unknown quota is not evidence that usage is available. If recovery cannot be verified, waiting stops with a visible reason rather than retrying blindly.

Use these commands in the TUI or web session composer:

Command Effect
/rate-limit-wait on Enable waiting for this session; start waiting if there is a pending usage-limit failure.
/rate-limit-wait off Disable waiting for this session and cancel any current wait.
/rate-limit-wait cancel Cancel the current wait without changing the setting.
/rate-limit-wait status Show whether waiting is disabled, enabled, or active.

New input, a model change, or session shutdown cancels an active wait. Stop also cancels automatic waiting during a running task. For a wait started by /rate-limit-wait on after the task has already ended, use /rate-limit-wait cancel; there is no running task to stop. Waiting does not survive a worker restart. Automatic recovery is limited to three attempts per input. The automatic recovery path continues the interrupted conversation instead of re-sending the original task. It does not handle context-length errors, fix authentication, or guarantee recovery from API billing/spend caps or provider overload.


PizzaPi adds a few provider helpers on top of pi’s built-in catalog.

Provider Auth Catalog behavior
ollama-cloud OLLAMA_API_KEY or an ollama-cloud API-key entry in ~/.pizzapi/auth.json Registered by a PizzaPi extension with a static fallback catalog; the runner/worker refreshes a live cache at ~/.pizzapi/ollama-cloud-models-cache.json.
openrouter pi-ai’s OpenRouter auth (OPENROUTER_API_KEY and supported stored auth) Fetches https://openrouter.ai/api/v1/models, keeps tool-capable models, maps pricing/context/modality metadata, and caches for 24 hours at ~/.pizzapi/openrouter-models-cache.json.
nvidia NVIDIA_API_KEY Fetches https://integrate.api.nvidia.com/v1/models, filters obvious non-chat models, unions live IDs with pi-ai’s static catalog, applies NVIDIA reasoning-effort constraints, and caches for 24 hours at ~/.pizzapi/nvidia-models-cache.json.

OpenRouter and NVIDIA keep pi-ai’s native auth and streaming behavior; PizzaPi swaps the model catalog used by the runtime. If a live fetch fails or no cache exists, the provider falls back to the static pi-ai catalog.


PizzaPi tracks two related things:

Data Source Where it appears
Tokens and cost Assistant and tool-result usage fields (including codemode model calls), plus standalone usage entries Session totals and usage dashboards.
Subscription quota windows Provider usage APIs for Anthropic and OpenAI Codex Usage indicator badges in the web UI.

format-usage.ts maps display providers to quota providers: claude-subscription uses Anthropic quota, openai/openai-codex use OpenAI Codex quota, and Google/Gemini CLI providers map to google-gemini-cli when usage data exists.

remote-provider-usage.ts caches quota windows in the worker and, under the runner daemon, reads the daemon’s shared usage cache file instead of every worker polling providers independently. Anthropic usage is cached for 15 minutes; other usage data uses a 5-minute cache. Snapshots carry per-provider freshness timestamps; refreshing the shared file does not make old quota fresh. Forced refresh requests go through runner IPC; runner-managed workers do not fall back to independent provider requests when IPC is slow or unavailable. Failed checks have a 60-second cooldown, including manual refreshes. The usage badge displays UNKNOWN, rather than disappearing or implying 100% availability, when quota cannot be verified. Anthropic credential discovery includes the anthropic and claude-subscription providers and Claude Code’s stored OAuth credentials.


Set PIZZAPI_LOG_PROVIDER_REQUEST=1 to log summarized outbound Anthropic /v1/messages requests for diagnostics:

Terminal window
PIZZAPI_LOG_PROVIDER_REQUEST=1 pizzapi

The logger wraps globalThis.fetch and only matches https://api.anthropic.com/v1/messages... by exact hostname and path prefix. It logs request URL, headers, and a summarized body: system block count/characters, message count, tool names, and other top-level fields. Authorization is not printed raw; bearer tokens are reduced to a short fingerprint.


Add local or custom models (Ollama, vLLM, LM Studio, proxies) via ~/.pizzapi/models.json. The file reloads each time you open /model — edit it mid-session without restarting.

{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"models": [
{ "id": "llama3.1:8b" },
{ "id": "qwen2.5-coder:7b" }
]
}
}
}
{
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"models": [
{
"id": "llama3.1:8b",
"name": "Llama 3.1 8B (Local)",
"reasoning": false,
"input": ["text"],
"contextWindow": 128000,
"maxTokens": 32000,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
}
]
}
}
}
API Use For
openai-completions Most compatible — Ollama, vLLM, LM Studio, OpenRouter
openai-responses OpenAI Responses API
openai-codex-responses OpenAI Codex CLI agent API
anthropic-messages Anthropic Messages API
azure-openai-responses Azure OpenAI Responses API
google-generative-ai Google Generative AI
google-vertex Google Vertex AI
mistral-conversations Mistral chat completions
bedrock-converse-stream Amazon Bedrock Converse
Field Description
baseUrl API endpoint URL
api API type (see above)
apiKey API key (supports shell command, env var, or literal)
headers Custom headers (same resolution as apiKey)
authHeader Set true to add Authorization: Bearer <apiKey>
models Array of model definitions
modelOverrides Per-model overrides for built-in models
Field Required Default Description
id Yes — Model identifier passed to the API
name No id Human-readable label
api No provider’s Override API type for this model
reasoning No false Supports extended thinking
thinkingLevelMap No — Map of thinking levels to API parameter values
input No ["text"] Input types: ["text"] or ["text", "image"]
contextWindow No 128000 Context window (tokens)
maxTokens No 16384 Max output tokens
cost No all zeros Per-million-token costs
headers No — Per-model custom headers
compat No — OpenAI compatibility overrides
baseUrl No provider’s Override endpoint for this model

For servers with partial OpenAI compatibility, use the compat field at the provider or model level:

{
"providers": {
"local-llm": {
"baseUrl": "http://localhost:8080/v1",
"api": "openai-completions",
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [{ "id": "my-model" }]
}
}
}

This commonly applies to Ollama, vLLM, SGLang, and similar servers that don’t understand the developer role or reasoning_effort parameter.


Terminal window
export AZURE_OPENAI_API_KEY=...
# Use either the full base URL...
export AZURE_OPENAI_BASE_URL=https://your-resource.openai.azure.com
# ...or just the resource name as a shorthand
export AZURE_OPENAI_RESOURCE_NAME=your-resource
# Optional (defaults to v1)
export AZURE_OPENAI_API_VERSION=v1
export AZURE_OPENAI_DEPLOYMENT_NAME_MAP=gpt-4=my-gpt4,gpt-4o=my-gpt4o
Terminal window
# Option 1: AWS Profile
export AWS_PROFILE=your-profile
# Option 2: IAM Keys
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...
# Optional region (defaults to us-east-1)
export AWS_REGION=us-west-2
Terminal window
# Option 1: Application Default Credentials
gcloud auth application-default login
export GOOGLE_CLOUD_PROJECT=your-project
export GOOGLE_CLOUD_LOCATION=us-central1
# Option 2: API key
export GOOGLE_CLOUD_API_KEY=...

Route a built-in provider through a proxy without redefining its models:

{
"providers": {
"anthropic": {
"baseUrl": "https://my-proxy.example.com/v1"
}
}
}

All built-in Anthropic models remain available — only the endpoint changes.