Ada AI

Coding agents

Point coding agents like Pi, OpenCode, and Codex at Ada AI so every request flows through your proxy key, your upstreams, and your routing rules.

Ada AI is OpenAI-compatible, so coding agents that already speak the Chat Completions API work unchanged — point the agent at https://api.ada.ai/v1, use a proxy key (sk-rc-…) as the API key, and pick a model you've enabled on at least one upstream. Codex speaks the Responses API instead; Ada serves that too.

You need a proxy key first

If you haven't already, mint one in the dashboard under Keys → New key and add an upstream whose model list is synced. See the Quickstart if you're starting from scratch. The key screen shows a ready-to-paste snippet for each agent on this page.

The two pieces you always set

SettingValue
Base URLhttps://api.ada.ai/v1
API keyYour proxy key, sk-rc-… — not a provider key. The proxy already holds your provider keys.

Put the key in your environment once and let every tool read it from there:

~/.bashrc or ~/.zshrc
export ADA_API_KEY="sk-rc-..."

The model you select must be present on at least one of your enabled upstreams, or be one of your invokers. Run GET /v1/models to see the union across them (see Models & routing).

Pi

The @adaai/cli package adds Ada AI to Pi as a first-class provider: it registers ada, discovers your models from /v1/models (invokers included), enriches them with capability metadata so reasoning and context limits behave per model, and keeps the catalog fresh across sessions.

Install it once:

pi install npm:@adaai/cli

With ADA_API_KEY exported, Pi is ready — no config file:

pi -m ada:glm-4.7 "Reply with exactly: ok"

Inside a session, /model lists the ada:* models, and /ada forces a catalog refresh (for example right after you sync a new upstream). Run pi extensions to confirm the ada provider is loaded.

Signing in from the terminal

The extension also implements Ada's device flow: /login ada opens your browser, you approve the request and pick the owner (personal or an organization), and Pi stores the minted key itself. Sign out with /logout ada.

Device flow availability

/login ada needs the gateway's device-flow routes, which are backed by Redis. Until that is enabled in production the command returns 404 page not found; use ADA_API_KEY instead.

Keep the key out of your shell profile (macOS)

An exported env var is readable by every process your shell starts. On macOS you can keep the key in Keychain instead and let Pi read it at startup. Store it once:

Store the key (once per Mac)
security add-generic-password -s ada-api-key -a "$USER" -w 'sk-rc-...'

Then put the credential in ~/.pi/agent/auth.json, Pi's credential store, and point its key at a command that reads it back:

~/.pi/agent/auth.json
{
  "ada": {
    "type": "api_key",
    "key": "!security find-generic-password -s ada-api-key -a \"$USER\" -w"
  }
}

Pi resolves an auth.json command once per process and caches it, prefers it over environment variables, and creates the file with 0600 permissions. The first time Pi reads the item, macOS may prompt to allow access — click Always Allow.

Without the extension

Plain Pi can talk to Ada AI through a provider entry in ~/.pi/agent/models.json. You list the models yourself and there is no /login ada, but nothing else is needed:

~/.pi/agent/models.json
{
  "providers": {
    "ada": {
      "baseUrl": "https://api.ada.ai/v1",
      "api": "openai-completions",
      "apiKey": "$ADA_API_KEY",
      "models": [
        { "id": "glm-4.7", "name": "GLM 4.7" },
        { "id": "Qwen/Qwen3.6-35B-A3B-FP8", "name": "Qwen 3.6 35B A3B", "reasoning": true }
      ]
    }
  }
}

The file reloads every time you open /model. apiKey accepts "$VAR", a "!command" whose stdout is the key, or a literal. If an upstream rejects the developer role or reasoning_effort, add "compat": { "supportsDeveloperRole": false, "supportsReasoningEffort": false } to the provider so Pi falls back to a system message and omits the field.

OpenCode

OpenCode reads providers from ~/.config/opencode/opencode.json (global) or opencode.json in your project root. Add an ada provider backed by the @ai-sdk/openai-compatible package — the package OpenCode uses for any OpenAI-compatible API:

~/.config/opencode/opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "ada": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Ada AI",
      "options": {
        "baseURL": "https://api.ada.ai/v1",
        "apiKey": "{env:ADA_API_KEY}"
      },
      "models": {
        "Qwen/Qwen3.6-35B-A3B-FP8": { "name": "Qwen 3.6 35B A3B" },
        "moonshotai/Kimi-K2.7-Code": { "name": "Kimi K2.7 Code" },
        "glm-4.7": { "name": "GLM 4.7" }
      }
    }
  }
}
FieldNotes
adaThe provider ID — any string. You'll select models as ada/<model-id>.
npmThe AI SDK package. @ai-sdk/openai-compatible works for any OpenAI-compatible API.
nameDisplay name in the /models picker.
options.baseURLThe Ada AI endpoint, https://api.ada.ai/v1.
options.apiKeyYour proxy key. {env:VAR} reads it from the environment at load time; an unset variable becomes an empty string, so export it before starting OpenCode.
modelsA map of model IDs (from GET /v1/models, invoker names included) to display names.

You can also run /connect in the TUI and paste the key; it's stored in ~/.local/share/opencode/auth.json.

Select a model with /models and pick ada/<model-id>, set a default in the config with "model": "ada/glm-4.7", or override for one run:

opencode run -m "ada/glm-4.7" "Reply with exactly: ok"

Codex

OpenAI's Codex CLI speaks the Responses API, and its custom providers accept only wire_api = "responses". Ada exposes POST /v1/responses for exactly this: the request is routed like every other call (your upstreams, invokers, a,b chains, failover, usage), passed through unchanged to upstreams that implement the Responses API natively (OpenAI, Azure OpenAI), and translated to chat completions for every other upstream, with the answer synthesised back into Responses events. A chain like gpt-6-astra,claude-fable-5-1 fails over across both kinds.

Custom providers are only honoured in the user-level file:

~/.codex/config.toml
model_provider = "ada"
model = "gpt-6-astra"        # any model your upstreams serve, an invoker name, or "a,b"

[model_providers.ada]
name = "Ada AI"
base_url = "https://api.ada.ai/v1"
env_key = "ADA_API_KEY"
wire_api = "responses"
request_max_retries = 2      # Ada already fails over across upstreams
stream_idle_timeout_ms = 300000

Then run codex with ADA_API_KEY exported. Codex's "Sign in with ChatGPT" is not involved and is not supported through Ada.

What to expect:

  • Stateless. Ada stores nothing: store is forced to false on the way out and previous_response_id is refused with a 400. Codex sends the full input each turn for custom providers, so this does not affect it.
  • Translation limits. OpenAI's built-in tools (web_search, file_search, computer_use, …) have no chat-completions equivalent; a request carrying them to a chat-only upstream gets a 400 naming the tool.
  • Headers and usage are the same as chat completions: X-Ada-Resolved-Model, X-Ada-Attempts, X-Ada-Failover-Attempts; tokens land in usage from the Responses usage block.

A one-shot check outside Codex:

curl -s https://api.ada.ai/v1/responses \
  -H "Authorization: Bearer $ADA_API_KEY" -H 'Content-Type: application/json' \
  -d '{"model":"gpt-6-astra","input":"Say OK."}' | jq '.output[-1].content[0].text, .usage'

Ada AI exposes many models across upstreams; these are well-suited to agentic coding tasks and accept the standard chat-completions shape:

ModelStrengths
Qwen/Qwen3.6-35B-A3B-FP8Reasoning-heavy refactors. Use a thinking level (high, max) when the task needs planning.
moonshotai/Kimi-K2.7-CodeStrong tool-calling and long-context code comprehension.
swiss-ai/Apertus-70B-Instruct-2509Large instruction-following model for broad tasks.
glm-4.7Fast, general-purpose.

An invoker is often the better choice than any single model: it gives the agent one stable name (provider-best, say) while you change the chain behind it in the dashboard. See Models & routing.

The exact set depends on which upstreams you've enabled and synced. Run curl https://api.ada.ai/v1/models -H "Authorization: Bearer $ADA_API_KEY" to see exactly what your key can address right now.

Verify it works

A one-shot check that the agent reaches Ada AI and routes correctly — the model echoed back in the response confirms the proxy selected your upstream:

pi -m ada:glm-4.7 --no-tools --no-session --print "Reply with exactly: ok"

Troubleshooting

model not found / 400 from the proxy

The model ID isn't on any of your enabled upstreams. Either the upstream needs Sync models run (in the dashboard, or POST /me/upstreams/{id}/sync-models), or the ID doesn't match what that upstream exposes. Model IDs are exact and case-sensitive — Qwen/Qwen3.6-35B-A3B-FP8 is not qwen3.6-35b. In Pi, run /ada after syncing so the catalog picks the model up. See Models & routing.

401 / invalid_api_key

You're using a provider key instead of an Ada AI proxy key, or the proxy key was revoked. Proxy keys start with sk-rc-. Mint a new one under Keys → New key (see API keys).

/login ada says 404 page not found

The gateway's device-flow routes are not enabled. Export ADA_API_KEY with a key from the dashboard instead; the extension picks it up on the next start.

Reasoning leaks into the response, or developer role errors

Some OpenAI-compatible upstreams don't understand the developer role or the reasoning_effort field that coding agents send by default. With the Pi extension this is handled per model from the catalog metadata; with a manual models.json entry, add the compat flags shown above. The proxy passes these through unchanged.

Requests hit the wrong upstream

Routing follows upstream priority, descending — the highest number is tried first, and the proxy fails over to the next on errors it classifies as retryable. If two upstreams expose the same model, raise the priority on the one you want first, or make an invoker whose member order says exactly what you want. See Models & routing.

Next steps

On this page