Skip to content

Providers & auth

ka does not integrate providers one by one: it speaks three wire protocols, which between them cover essentially every endpoint:

Wire Covers
anthropic_messages Anthropic
openai_chat OpenAI and every OpenAI-compatible endpoint: Ollama, vLLM, LM Studio, gateways, DeepSeek, Groq, Mistral, Together, …
openai_responses OpenAI’s Responses API for reasoning models: item-based history, flat tool definitions, reasoning.effort, streamed reasoning summaries

All three are vendored (reqwest + rustls + hand-rolled SSE): no provider SDKs, no extra weight. Per-model quirks live in a dialect profile (a data table, not code): context window, supported efforts, cache mode, char-per-token ratio, flags like replay_reasoning for byte-exact <think> re-emission on Ollama.

  • A curated registry of vendors works selector-only: openai, anthropic, google, zai, zai-plan, deepseek, mistral, groq, cerebras, qwen, moonshot, xai, nvidia, openrouter, together, fireworks, ollama, lmstudio, llamacpp, vllm.
  • On top, a generated overlay seeded from models.dev adds 500+ models across 27 vendors, with context windows and published pricing, including subscription coding plans (zai-coding-plan/glm-5.3 and friends) as unpriced plan rows.
  • ka models lists everything; --no-discovery skips probing local endpoints.

On startup (unless disabled), ka probes well-known local endpoints (Ollama, LM Studio, vLLM, llama.cpp) and converts what it finds into ephemeral catalog rows. Explicit config always wins over discovery.

Some providers run web search on their own servers. With the server_search dialect flag on a model:

[dialects."anthropic/claude-sonnet-5".flags]
server_search = true

the wire injects the provider’s own search tool (Anthropic and OpenAI Responses support it) and drops ka’s client-side web_search hand for that model, so no [[search]] API key is needed. The streamed query and sources surface as visible text; failed searches surface as errors, never as silence. Injection honors the web feature toggle: disable web and native search goes with it, fail-closed like every toggle. openai_chat refuses the flag with an instructive error.

Keys are never written into config files. ka resolves each provider’s key through, in order:

  1. the environment (ANTHROPIC_API_KEY, …)
  2. ./.env in the project
  3. ~/.config/ka/.env (created 0600)
  4. the OS keyring (via /key)
  5. !cmd indirection: the key is the stdout of a shell command (for vault setups)
# in .env
ANTHROPIC_API_KEY=sk-ant-…
# or in ka.toml contexts that take a command:
# api_key = "!pass show anthropic"

ka providers shows every vendor with its key env var and whether it is set.

When a turn fails on the active model with a provider/auth error after retries are exhausted, ka re-dispatches the same messages on the next entry of your fallback chain (at most 2 hops per turn):

[fallback]
models = [
"anthropic/claude-sonnet-5",
"openai/gpt-5.1",
"ollama/qwen3.5:9b",
]