返回 CodeWhale
PROVIDERS.md
根目录 / docs / PROVIDERS.md
1 # Provider Registry
2
3 This registry describes provider behavior that is wired into the current
4 Codewhale codebase. It is intentionally conservative: shipped entries are
5 limited to provider IDs, config keys, auth paths, base URLs, model resolution,
6 and capability metadata that the code already knows about.
7
8 DeepSeek remains the default provider, but every entry in `ProviderKind::ALL`
9 is a first-class selectable provider route. `ALL` is the catalog/picker
10 surface — one identity per vendor. Dual-wire dialect kinds (`*Anthropic`, e.g.
11 `deepseek-anthropic`) and the Model Studio plan variants stay on the enum for
12 serde and `provider_for_kind` but are deliberately **not** catalog rows:
13 a plan is `mode`/`base_url` and a dialect is `wire = openai|anthropic` on the
14 primary provider config (`crates/config/src/provider_kind.rs:186-197`). Hosted
15 routes, generic OpenAI-compatible endpoints, the OpenAI Codex/ChatGPT route,
16 native Anthropic, and local runtimes all run the same terminal harness against
17 the selected provider/model/base URL.
18
19 Sources to keep in sync:
20
21 - `crates/config/src/lib.rs` - shared provider IDs, defaults, env precedence.
22 - `crates/tui/src/config.rs` - TUI provider IDs, provider capability metadata,
23 and provider-specific env handling.
24 - `crates/agent/src/lib.rs` - static `ModelRegistry` used by
25 `codewhale model list` and `codewhale model resolve`.
26 - `config.example.toml` and `docs/CONFIGURATION.md` - user-facing config
27 examples and environment variable reference.
28 - `scripts/check-provider-registry.py` - drift check for canonical provider
29 IDs, live TUI provider IDs, TOML table names, static registry rows, and
30 documented defaults.
31
32 ## Provider Selection
33
34 The canonical provider IDs are the 36 entries of `ProviderKind::ALL`
35 (`crates/config/src/provider_kind.rs:198-234`), in that order:
36
37 `deepseek`, `nvidia-nim`, `openai`, `atlascloud`, `wanjie-ark`, `volcengine`,
38 `openrouter`, `xiaomi-mimo`, `novita`, `fireworks`, `siliconflow`, `arcee`,
39 `siliconflow-CN`, `moonshot`, `sglang`, `vllm`, `ollama`, `huggingface`,
40 `together`, `qianfan`, `openai-codex`, `anthropic`, `openmodel`, `zai`,
41 `stepfun`, `minimax`, `deepinfra`, `sakana`, `longcat`, `opencode-go`,
42 `opencode-zen`, `meta`, `xai`, `telecomjs`, `modelstudio-token-plan`, and
43 `custom`.
44
45 `deepseek-anthropic` is *not* on this list — it is a wire dialect of
46 `deepseek`, reached with `wire = "anthropic"`, not a separate route to select.
47
48 Use any of these surfaces to select a provider:
49
50 - CLI: `codewhale --provider <id>`
51 - TUI: `/provider <id>` or the provider picker
52 - Env: `CODEWHALE_PROVIDER=<id>`; `DEEPSEEK_PROVIDER=<id>` is the legacy alias
53 - Config: `provider = "<id>"`
54
55 `deepseek-cn`, `deepseek_china`, `deepseekcn`, and `deepseek-china` are accepted
56 as legacy aliases for `deepseek`. They do not select a different official host;
57 DeepSeek uses the same official API host worldwide.
58
59 `deepseek_anthropic`, `deepseek-claude`, and `deepseek_claude` select
60 `deepseek-anthropic`, the opt-in DeepSeek route that speaks the Anthropic
61 Messages API at `https://api.deepseek.com/anthropic`. It keeps the normal
62 DeepSeek API key path but uses `x-api-key` plus `anthropic-version: 2023-06-01`
63 instead of Bearer auth.
64
65 `huggingface`, `hugging-face`, `hugging_face`, and `hf` all select the
66 Hugging Face Inference Providers route. This is the OpenAI-compatible router
67 path for chat/inference, not Hub browsing, model-card inspection, uploads, or
68 artifact export.
69
70 `telecomjs`, `telecom-js`, `telecom_js`, `telecomjs-cn`, and `tokenhub` all
71 select the TelecomJS TokenHub route. Its authenticated `/models` catalog is
72 key-scoped and remains isolated from every other provider's live snapshot.
73
74 Fresh shared config writes to `~/.codewhale/config.toml`. Existing
75 `~/.deepseek/config.toml` files are still read for compatibility.
76
77 ### Wire Protocol Compatibility
78
79 Provider selection is explicit. A model string prefix such as
80 `deepseek-ai/...`, `deepseek/...`, `qwen/...`, or `arcee-ai/...` is a
81 provider-owned wire ID or catalog namespace hint under the selected provider.
82 It is not a provider switch and must not be treated as proof that the route is
83 DeepSeek, OpenRouter, or any other provider.
84
85 Set the route with `provider = "<id>"`, `CODEWHALE_PROVIDER=<id>`, or
86 `codewhale --provider <id>`. Set the request model with `CODEWHALE_MODEL`, a
87 provider-specific model env var, top-level `default_text_model`, or
88 `[providers.<table>].model`. Set the endpoint with `CODEWHALE_BASE_URL`, a
89 provider-specific base URL env var, or `[providers.<table>].base_url`. Set auth
90 with `codewhale auth set --provider <id>`, `[providers.<table>].api_key`, or
91 the listed provider env vars.
92
93 | Provider ID | TOML table | Wire protocol | Auth env vars |
94 | --- | --- | --- | --- |
95 | `deepseek` | `[providers.deepseek]` | OpenAI Chat Completions | `DEEPSEEK_API_KEY` |
96 | `deepseek-anthropic` | `[providers.deepseek_anthropic]` | Anthropic Messages | `DEEPSEEK_API_KEY` |
97 | `nvidia-nim` | `[providers.nvidia_nim]` | OpenAI Chat Completions | `NVIDIA_API_KEY`, `NVIDIA_NIM_API_KEY`, `DEEPSEEK_API_KEY` |
98 | `openai` | `[providers.openai]` | OpenAI Chat Completions | `OPENAI_API_KEY` |
99 | `atlascloud` | `[providers.atlascloud]` | OpenAI Chat Completions | `ATLASCLOUD_API_KEY` |
100 | `wanjie-ark` | `[providers.wanjie_ark]` | OpenAI Chat Completions | `WANJIE_ARK_API_KEY`, `WANJIE_API_KEY`, `WANJIE_MAAS_API_KEY` |
101 | `volcengine` | `[providers.volcengine]` | OpenAI Chat Completions | `VOLCENGINE_API_KEY`, `VOLCENGINE_ARK_API_KEY`, `ARK_API_KEY` |
102 | `openrouter` | `[providers.openrouter]` | OpenAI Chat Completions | `OPENROUTER_API_KEY` |
103 | `xiaomi-mimo` | `[providers.xiaomi_mimo]` | OpenAI Chat Completions | `XIAOMI_MIMO_TOKEN_PLAN_API_KEY`, `MIMO_TOKEN_PLAN_API_KEY`, `XIAOMI_MIMO_API_KEY`, `XIAOMI_API_KEY`, `MIMO_API_KEY` |
104 | `novita` | `[providers.novita]` | OpenAI Chat Completions | `NOVITA_API_KEY` |
105 | `fireworks` | `[providers.fireworks]` | OpenAI Chat Completions | `FIREWORKS_API_KEY` |
106 | `siliconflow` | `[providers.siliconflow]` | OpenAI Chat Completions | `SILICONFLOW_API_KEY` |
107 | `arcee` | `[providers.arcee]` | OpenAI Chat Completions | `ARCEE_API_KEY` |
108 | `siliconflow-CN` | `[providers.siliconflow_cn]` | OpenAI Chat Completions | `SILICONFLOW_API_KEY` |
109 | `moonshot` | `[providers.moonshot]` | OpenAI Chat Completions | `MOONSHOT_API_KEY`, `KIMI_API_KEY` |
110 | `sglang` | `[providers.sglang]` | OpenAI Chat Completions | `SGLANG_API_KEY` |
111 | `vllm` | `[providers.vllm]` | OpenAI Chat Completions | `VLLM_API_KEY` |
112 | `ollama` | `[providers.ollama]` | Ollama-local OpenAI-compatible Chat Completions | `OLLAMA_API_KEY` |
113 | `huggingface` | `[providers.huggingface]` | OpenAI Chat Completions | `HUGGINGFACE_API_KEY`, `HF_TOKEN` |
114 | `together` | `[providers.together]` | OpenAI Chat Completions | `TOGETHER_API_KEY` |
115 | `qianfan` | `[providers.qianfan]` | OpenAI Chat Completions | `QIANFAN_API_KEY`, `BAIDU_QIANFAN_API_KEY` |
116 | `openai-codex` | `[providers.openai_codex]` | OpenAI Responses | `OPENAI_CODEX_ACCESS_TOKEN`, `CODEX_ACCESS_TOKEN` |
117 | `anthropic` | `[providers.anthropic]` | Anthropic Messages | `ANTHROPIC_API_KEY` |
118 | `openmodel` | `[providers.openmodel]` | Anthropic Messages | `OPENMODEL_API_KEY` |
119 | `zai` | `[providers.zai]` | OpenAI Chat Completions | `ZAI_API_KEY`, `Z_AI_API_KEY` |
120 | `stepfun` | `[providers.stepfun]` | OpenAI Chat Completions | `STEPFUN_API_KEY`, `STEP_API_KEY` |
121 | `minimax` | `[providers.minimax]` | OpenAI Chat Completions | `MINIMAX_API_KEY` |
122 | `deepinfra` | `[providers.deepinfra]` | OpenAI Chat Completions | `DEEPINFRA_API_KEY`, `DEEPINFRA_TOKEN` |
123 | `sakana` | `[providers.sakana]` | OpenAI Chat Completions | `FUGU_API_KEY`, `SAKANA_API_KEY` |
124 | `longcat` | `[providers.longcat]` | OpenAI Chat Completions | `LONGCAT_API_KEY` |
125 | `opencode-go` | `[providers.opencode_go]` | OpenAI Chat Completions | `OPENCODE_GO_API_KEY` |
126 | `opencode-zen` | `[providers.opencode_zen]` | Model-aware: OpenAI Responses, Anthropic Messages, or OpenAI Chat Completions | `OPENCODE_ZEN_API_KEY`, `OPENCODE_API_KEY` |
127 | `meta` | `[providers.meta]` | OpenAI Chat Completions | `META_MODEL_API_KEY`, `MODEL_API_KEY` |
128 | `telecomjs` | `[providers.telecomjs]` | OpenAI Chat Completions | `TELECOMJS_API_KEY` |
129 | `xai` | `[providers.xai]` | OpenAI Chat Completions | `XAI_API_KEY` |
130 | `modelstudio-token-plan` | `[providers.modelstudio_token_plan]` | OpenAI Chat Completions | `MODELSTUDIO_API_KEY`, `DASHSCOPE_API_KEY` |
131 | `modelstudio-token-plan-anthropic` | `[providers.modelstudio_token_plan_anthropic]` | Anthropic Messages | `MODELSTUDIO_API_KEY`, `DASHSCOPE_API_KEY` |
132 | `modelstudio-coding-plan` | `[providers.modelstudio_coding_plan]` | OpenAI Chat Completions | `MODELSTUDIO_API_KEY`, `DASHSCOPE_API_KEY` |
133 | `modelstudio-coding-plan-anthropic` | `[providers.modelstudio_coding_plan_anthropic]` | Anthropic Messages | `MODELSTUDIO_API_KEY`, `DASHSCOPE_API_KEY` |
134
135 Default base URLs and models for each route are listed in the shipped provider
136 table below. The wire protocol values above are derived from
137 `crates/config/src/provider.rs`: `ChatCompletions` is the default,
138 `openai-codex` overrides to `Responses`; `deepseek-anthropic`, `anthropic`, and
139 `openmodel` override to `AnthropicMessages`; and `opencode-zen` resolves the
140 protocol from the selected model's curated offering.
141
142 ## Auth And Env Rules
143
144 For hosted providers, `codewhale auth set --provider <id>` saves an API key for
145 that provider. API-key environment variables are fallback inputs after saved
146 config and keyring credentials; an explicit process-level `--api-key` still
147 wins for that launch.
148
149 For base URL and model selection, prefer:
150
151 - `CODEWHALE_BASE_URL` / `CODEWHALE_MODEL` for the active provider.
152 - Provider-specific base URL/model env vars when listed below.
153 - `DEEPSEEK_BASE_URL`, `DEEPSEEK_MODEL`, and `DEEPSEEK_DEFAULT_TEXT_MODEL` as
154 legacy aliases.
155
156 Non-local `http://` base URLs are rejected unless
157 `DEEPSEEK_ALLOW_INSECURE_HTTP=1` is set. Loopback HTTP URLs are allowed for
158 self-hosted runtimes.
159
160 ## Custom DeepSeek-Compatible Endpoints
161
162 Most custom DeepSeek-compatible deployments can use an existing provider ID.
163 Do not create `[providers.deepseek_custom]`; the provider table names are fixed.
164 Instead, choose the closest shipped route and override its endpoint/model:
165
166 - DeepSeek-compatible hosted API: keep `provider = "deepseek"` and set
167 `[providers.deepseek].base_url` plus `[providers.deepseek].model`, or launch
168 with `DEEPSEEK_BASE_URL` and `DEEPSEEK_MODEL`.
169 - Generic OpenAI-compatible gateway: use `provider = "openai"` with
170 `[providers.openai].base_url` plus `[providers.openai].model`, or launch with
171 `OPENAI_BASE_URL` and `OPENAI_MODEL`.
172 - Multiple named OpenAI-compatible gateways, or local routes you want to pin
173 from an AgentProfile, can use a custom table such as
174 `[providers.lm-studio] kind = "openai-compatible"` and select it with
175 `provider = "lm-studio"` or a profile `provider = "lm-studio"`.
176 - Local OpenAI-compatible runtimes: use `provider = "vllm"`, `"sglang"`, or
177 `"ollama"` with the matching provider-specific base URL/model values.
178
179 Example user config for a DeepSeek-compatible host:
180
181 ```toml
182 provider = "deepseek"
183
184 [providers.deepseek]
185 api_key = "YOUR_API_KEY"
186 base_url = "https://your-provider.example/v1"
187 model = "deepseek-ai/DeepSeek-V4-Pro"
188 ```
189
190 Example user config for a generic gateway:
191
192 ```toml
193 provider = "openai"
194
195 [providers.openai]
196 api_key = "YOUR_GATEWAY_API_KEY"
197 base_url = "https://gateway.example/v1"
198 model = "your-deepseek-compatible-model"
199 ```
200
201 Alibaba Cloud Model Studio (Bailian / DashScope) is a first-class provider as
202 of v0.9.4 with two plan profiles: Token Plan (Personal / Team) and Coding Plan.
203 Both plans expose an OpenAI-compatible Chat Completions endpoint and an
204 Anthropic-compatible Messages endpoint.
205
206 **Token Plan** (Personal and Team share the same AP-Southeast endpoint):
207
208 ```toml
209 provider = "modelstudio-token-plan"
210
211 [providers.modelstudio_token_plan]
212 api_key = "YOUR_MODELSTUDIO_API_KEY"
213 # base_url defaults to https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1
214 model = "qwen3.8-max" # or qwen3.8-max-preview | qwen3.7-plus | qwen3.7-max |
215 # qwen3.6-flash | deepseek-v4-pro | deepseek-v4-flash-0731 |
216 # glm-5.2
217 ```
218
219 **Coding Plan** (separate international endpoint):
220
221 ```toml
222 provider = "modelstudio-coding-plan"
223
224 [providers.modelstudio_coding_plan]
225 api_key = "YOUR_MODELSTUDIO_API_KEY"
226 # base_url defaults to https://coding-intl.dashscope.aliyuncs.com/v1
227 model = "qwen3.8-max"
228 ```
229
230 **Anthropic-compatible dialect** — both plans also expose a native Anthropic
231 Messages path. Select it with the `-anthropic` provider suffix:
232
233 ```toml
234 provider = "modelstudio-token-plan-anthropic"
235
236 [providers.modelstudio_token_plan_anthropic]
237 api_key = "YOUR_MODELSTUDIO_API_KEY"
238 # base_url defaults to https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic
239 model = "qwen3.8-max"
240 ```
241
242 Create or copy a Model Studio API key from the
243 [Bailian console](https://bailian.console.aliyun.com/). The API key is shared
244 across all four provider IDs above; only the base URL and wire protocol differ.
245
246 **Thinking / reasoning.** Reasoning surfaces in the TUI's Thinking view on both
247 dialects, per Model Studio's
248 [deep-thinking docs](https://www.alibabacloud.com/help/en/model-studio/deep-thinking).
249
250 On the OpenAI-compatible routes the top-level controls are **route- and
251 model-specific**, and Codewhale fails closed: they are sent only when the
252 configured `base_url` is an official Alibaba Chat Completions host
253 (`*.maas.aliyuncs.com/compatible-mode/v1`, including workspace-scoped hosts, or
254 `coding-intl.dashscope.aliyuncs.com/v1`). A custom `base_url` on the same
255 provider ID gets `thinking`, `enable_thinking`, `preserve_thinking`, and
256 `reasoning_effort` stripped, so an arbitrary OpenAI-compatible gateway is never
257 handed Alibaba's dialect. On a verified host:
258
259 - **Hybrid models** (`qwen3.7-*`, `qwen3.6-*`, `deepseek-v4*`, `glm-*`,
260 `kimi-k2.6*`) get `enable_thinking`: `false` for `off`, `true` otherwise.
261 - **Thinking-only models** — `qwen3.8-max` (catalogued `thinking: always_on`),
262 `qwen3.8-max-preview` (effort/budget options, no toggle), and
263 `kimi-k2.7-code` — get **no** enable/disable switch at all. Sending one is at
264 best ignored.
265 - `preserve_thinking` is sent for the models documented to accept it
266 (`qwen3.7-max`/`-plus`, `qwen3.6-max-preview`/`-plus`/`-flash`, `kimi-k2.6*`,
267 `kimi-k2.7-code`), so the next turn keeps the assistant's trace.
268 - `reasoning_effort` is sent only for the two families with a documented ladder
269 — `deepseek-v4*` and `glm-5`/`5.1`/`5.2` — mapped to `high` or `max`.
270
271 Reasoning streams back as `delta.reasoning_content`. It is replayed to the
272 provider on later turns only for the `preserve_thinking` models above and the
273 thinking-only models; `deepseek-v3.1`, `deepseek-v3.2`, and `glm-*` history
274 stays stripped pending live confirmation that DashScope accepts
275 `reasoning_content` in input messages. (`deepseek-v4*` replays regardless — the
276 DeepSeek thinking-mode contract requires it on every provider.)
277
278 On the Anthropic-compatible routes, thinking uses the documented
279 `{"type":"enabled","budget_tokens":N}` / `{"type":"disabled"}` shapes from the
280 [Anthropic-compatible Messages API](https://www.alibabacloud.com/help/en/model-studio/anthropic-api-messages),
281 with `budget_tokens` derived from the effort level.
282
283 DeepSeek (`deepseek-v4-pro`, `deepseek-v4-flash-0731`) and GLM (`glm-5.2`)
284 models served by Model Studio are provider-scoped and do not collide with the
285 first-party DeepSeek or Zhipu/Z.ai routes. Model Studio publishes no `glm-5.3`
286 entry, so Codewhale does not offer one on this route.
287 Pay-as-you-go workspace-id templating is not yet in the built-in provider; use
288 a custom provider entry for that plan until a follow-up adds it.
289
290 Private gateways with broken or intercepted certificates should use
291 `SSL_CERT_FILE` with a trusted CA bundle. The legacy
292 `insecure_skip_tls_verify = true` key is still parsed so `codewhale doctor` can
293 report stale configs, but provider clients reject it instead of skipping TLS
294 certificate verification.
295
296 Keep `provider`, `api_key`, and `base_url` in user config or process
297 environment. Project-local config overlays intentionally cannot set those keys,
298 so a repository cannot silently redirect prompts or credentials to another
299 endpoint.
300
301 ## Credential Links
302
303 Provider setup surfaces use the same typed credential metadata as onboarding,
304 `/provider`, `/links`, setup receipts, and doctor output. A missing URL is
305 intentional: local, OAuth-only, and user-defined routes show their supported
306 configuration path instead of guessing a vendor page.
307
308 | Provider ID | Credential or console link |
309 | --- | --- |
310 | `deepseek`, `deepseek-anthropic` | [DeepSeek API keys](https://platform.deepseek.com/api_keys) |
311 | `nvidia-nim` | [NVIDIA NIM API keys](https://build.nvidia.com/settings/api-keys) |
312 | `openai` | [OpenAI API keys](https://platform.openai.com/api-keys) |
313 | `atlascloud` | [Atlas Cloud API keys](https://atlascloud.ai/docs/en/api-keys) |
314 | `wanjie-ark` | [Wanjie MaaS APIKEY docs](https://docs.wanjiedata.com/maas/maas-openapi-v1.html) |
315 | `volcengine` | [Volcengine Ark API keys](https://console.volcengine.com/ark/apiKey) |
316 | `openrouter` | [OpenRouter keys](https://openrouter.ai/settings/keys) |
317 | `xiaomi-mimo` | [Xiaomi MiMo Token Plan](https://platform.xiaomimimo.com/token-plan) |
318 | `novita` | [Novita key management](https://novita.ai/en/settings/key-management) |
319 | `fireworks` | [Fireworks API keys](https://fireworks.ai/api-keys) |
320 | `siliconflow` | [SiliconFlow global API keys](https://cloud.siliconflow.com/account/ak) |
321 | `siliconflow-CN` | [SiliconFlow China API keys](https://cloud.siliconflow.cn/account/ak) |
322 | `arcee` | [Arcee API key guide](https://docs.arcee.ai/other/create-your-first-api-key) |
323 | `moonshot` | [Kimi API platform keys](https://platform.kimi.ai/console/api-keys) or [Kimi Code membership console](https://www.kimi.com/code/console) |
324 | `zai` | [Z.ai model API](https://z.ai/model-api) |
325 | `stepfun` | [StepFun Open Platform](https://platform.stepfun.ai/) |
326 | `minimax`, `minimax-anthropic` | [MiniMax interface keys](https://platform.minimax.io/user-center/basic-information/interface-key) |
327 | `huggingface` | [Hugging Face tokens](https://huggingface.co/settings/tokens) |
328 | `deepinfra` | [DeepInfra API keys](https://deepinfra.com/dash/api_keys) |
329 | `together` | [Together API keys](https://api.together.ai/settings/api-keys) |
330 | `qianfan` | [Baidu Cloud access keys](https://console.bce.baidu.com/iam/#/iam/accesslist) |
331 | `anthropic` | [Anthropic API keys](https://console.anthropic.com/settings/keys) |
332 | `openmodel` | [OpenModel console](https://console.openmodel.ai/) ([authentication guide](https://docs.openmodel.ai/en/docs/getting-started/authentication)) |
333 | `openai-codex` | Run `codex login`, then explicitly grant Codewhale read-only access to that exact credential file; no Codewhale API key is stored. |
334 | `sglang`, `vllm`, `ollama` | Local OpenAI-compatible endpoints are keyless by default; configure a key only when the server requires one. |
335 | `sakana` | [Sakana AI API keys](https://console.sakana.ai/api-keys) ([get started](https://console.sakana.ai/get-started)) |
336 | `longcat` | [Meituan LongCat platform](https://longcat.chat/platform) |
337 | `opencode-go` | [OpenCode Go](https://opencode.ai/docs/go/) |
338 | `opencode-zen` | [OpenCode Zen](https://opencode.ai/docs/zen/) |
339 | `meta` | [Meta Model API](https://developer.meta.com/ai/) |
340 | `telecomjs` | [TelecomJS TokenHub](https://aigw.telecomjs.com/) |
341 | `xai` | [xAI Console](https://console.x.ai/) for an API key, Codewhale-owned device login, or explicitly consented read-only Grok CLI credentials. |
342 | `modelstudio-token-plan`, `modelstudio-token-plan-anthropic`, `modelstudio-coding-plan`, `modelstudio-coding-plan-anthropic` | [Alibaba Cloud Model Studio (Bailian console)](https://bailian.console.aliyun.com/) — create or copy a Model Studio API key. |
343 | `custom` | Set the named provider's `base_url` and `api_key_env` or `api_key`; no canonical vendor credential page exists. |
344
345 For Kimi, the official [quickstart](https://platform.kimi.ai/docs/overview)
346 directs users to sign in, open **API Keys**, create and copy a key, and keep it
347 secret. Codewhale links straight to that console and accepts the copied key.
348 It never probes or impersonates `kimi_cli`/`kimi_code_cli`; first-class Kimi
349 OAuth remains blocked on a vendor-registered Codewhale identity.
350
351 ### External CLI credential consent
352
353 Credential files owned by another CLI are disabled by default. Without an
354 explicit grant, provider discovery, setup, routing, `auth status`, and doctor
355 do not stat, read, refresh, contact an identity provider for, or rewrite Codex,
356 Grok, Kimi, or future external credential files.
357
358 Codewhale currently supports exact-path, provider-scoped **read-only** grants
359 for the Codex CLI and Grok CLI:
360
361 ```bash
362 codex login
363 codewhale auth external-consent --provider openai-codex --mode read-only
364
365 grok login
366 codewhale auth external-consent --provider xai --mode read-only
367
368 codewhale auth status --provider openai-codex
369 codewhale auth external-revoke --provider openai-codex
370 ```
371
372 Pass `--path /absolute/path/to/auth.json` when the external CLI uses a custom
373 location. Consent persists the provider, external owner, exact absolute path,
374 and consent schema version. Later environment-variable changes do not redirect
375 that authority to a different file. Read-only grants never refresh, contact an
376 identity/discovery service, or rewrite the external file; normal requests to
377 the explicitly selected provider may use its token. An expired token fails
378 with login guidance. Doctor reports structural consent/config state without
379 opening credential files and is always non-mutating.
380
381 `managed` is reserved for a future provider-specific preservation adapter.
382 v0.9.1 rejects it before file or network I/O because no reviewed adapter can
383 yet preserve every unknown external schema field safely. Codewhale-started xAI
384 device login instead atomically activates a Codewhale-owned generation named
385 `$CODEWHALE_HOME/credentials/xai-auth-<generation>.json`, stores only that
386 validated basename in config, and revokes any Grok-file grant. Superseded
387 generations are cleaned only after the new config pointer commits.
388 Kimi remains API-key-only; external consent for Kimi is rejected.
389
390 ## Shipped Providers
391
392 | Provider ID | TOML table | Auth env | Base URL env and default | Default or static models | Notes |
393 | --- | --- | --- | --- | --- | --- |
394 | `deepseek` | `[providers.deepseek]` | `DEEPSEEK_API_KEY` | `CODEWHALE_BASE_URL` / `DEEPSEEK_BASE_URL`; default `https://api.deepseek.com/beta` | `deepseek-v4-pro`, `deepseek-v4-flash`; compatibility aliases `deepseek-chat`, `deepseek-reasoner` | First-class default. Beta URL enables strict tool mode, chat prefix completion, and FIM completion. Set `https://api.deepseek.com` or `/v1` explicitly to opt out of beta-only features. Reasoning effort maps to the documented wire ladder `low`/`high`/`max` plus the `thinking` toggle: `off` sends `thinking: {"type":"disabled"}`, `low` sends `reasoning_effort: "low"`, `medium` rounds up to `"high"` (the wire has no medium), and `high`/`max` pass through. |
395 | `deepseek-anthropic` | `[providers.deepseek_anthropic]` | `DEEPSEEK_API_KEY` | `DEEPSEEK_ANTHROPIC_BASE_URL`; default `https://api.deepseek.com/anthropic` | `deepseek-v4-pro`, `deepseek-v4-flash`; compatibility aliases `deepseek-chat`, `deepseek-reasoner` | Opt-in DeepSeek route for the Anthropic Messages wire protocol. Uses `/v1/messages`, `x-api-key`, and `anthropic-version: 2023-06-01`. Keep `provider = "deepseek"` for the default Chat Completions path. |
396 | `nvidia-nim` | `[providers.nvidia_nim]` | `NVIDIA_API_KEY`, `NVIDIA_NIM_API_KEY`, fallback `DEEPSEEK_API_KEY` | `NVIDIA_NIM_BASE_URL`, `NIM_BASE_URL`, `NVIDIA_BASE_URL`; default `https://integrate.api.nvidia.com/v1` | `deepseek-ai/deepseek-v4-pro`, `deepseek-ai/deepseek-v4-flash` | Hosted DeepSeek V4 through NVIDIA NIM. `NVIDIA_NIM_MODEL` is accepted by the TUI config path. |
397 | `openai` | `[providers.openai]` | `OPENAI_API_KEY` | `OPENAI_BASE_URL`; default `https://api.openai.com/v1` | Registry entries: `deepseek-v4-pro`, `deepseek-v4-flash`, `gpt-5.6`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`; default config model `deepseek-v4-pro` | Generic OpenAI-compatible route for gateways and custom endpoints, including Alibaba Bailian / Model Studio DashScope when configured with that endpoint. The [GPT-5.6 family](https://developers.openai.com/api/docs/models/gpt-5.6-sol) uses OpenAI's documented 1.05M context, 128K max output, and reasoning levels. Use this for explicit third-party OpenAI-compatible routes instead of inventing a new provider ID. `OPENAI_MODEL` is accepted. |
398 | `atlascloud` | `[providers.atlascloud]` | `ATLASCLOUD_API_KEY` | `ATLASCLOUD_BASE_URL`; default `https://api.atlascloud.ai/v1` | Default `deepseek-ai/deepseek-v4-flash`; explicit `vendor/model-id` values pass through when AtlasCloud is selected | OpenAI-compatible hosted route. `ATLASCLOUD_MODEL` is accepted by the TUI config path, the static `ModelRegistry` keeps DeepSeek V4 fallback rows, and provider-hinted CLI model IDs are sent to AtlasCloud exactly as requested. Use Atlas Cloud's own catalog or Coding Plan page for the current provider-owned model list and pricing. |
399 | `wanjie-ark` | `[providers.wanjie_ark]` | `WANJIE_ARK_API_KEY`, `WANJIE_API_KEY`, `WANJIE_MAAS_API_KEY` | `WANJIE_ARK_BASE_URL`, `WANJIE_BASE_URL`, `WANJIE_MAAS_BASE_URL`; default `https://maas-openapi.wanjiedata.com/api/v1` | `deepseek-reasoner` | OpenAI-compatible hosted route. `WANJIE_ARK_MODEL`, `WANJIE_MODEL`, and `WANJIE_MAAS_MODEL` are accepted. |
400 | `volcengine` | `[providers.volcengine]` | `VOLCENGINE_API_KEY`, `VOLCENGINE_ARK_API_KEY`, `ARK_API_KEY` | `VOLCENGINE_BASE_URL`, `VOLCENGINE_ARK_BASE_URL`, `ARK_BASE_URL`; default `https://ark.cn-beijing.volces.com/api/coding/v3` | `DeepSeek-V4-Pro`, `DeepSeek-V4-Flash` | Volcengine/Volcano Engine Ark OpenAI-compatible coding endpoint. `VOLCENGINE_MODEL` and `VOLCENGINE_ARK_MODEL` are accepted. |
401 | `openrouter` | `[providers.openrouter]` | `OPENROUTER_API_KEY` | `OPENROUTER_BASE_URL`; default `https://openrouter.ai/api/v1` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`; recent large IDs include `arcee-ai/trinity-large-thinking`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-flash`, `qwen/qwen3.6-35b-a3b`, `qwen/qwen3.6-max-preview`, `qwen/qwen3.6-27b`, `qwen/qwen3.6-plus`, `google/gemma-4-31b-it`, `z-ai/glm-5.1`, `z-ai/glm-5.2`, `moonshotai/kimi-k2.7-code`, `moonshotai/kimi-k2.6` | Additive open-model routing layer. It does not replace DeepSeek; it lets users route supported model IDs through OpenRouter when they choose it. |
402 | `xiaomi-mimo` | `[providers.xiaomi_mimo]` | `XIAOMI_MIMO_TOKEN_PLAN_API_KEY`, `MIMO_TOKEN_PLAN_API_KEY`, `XIAOMI_MIMO_API_KEY`, `XIAOMI_API_KEY`, `MIMO_API_KEY` | `XIAOMI_MIMO_BASE_URL`, `MIMO_BASE_URL`, `XIAOMI_MIMO_MODE`, `MIMO_MODE`; default `https://token-plan-sgp.xiaomimimo.com/v1` | Chat: `mimo-v2.5-pro`, `mimo-v2.5-pro-ultraspeed`, `mimo-v2.5`; speech/TTS: `mimo-v2.5-tts`, `mimo-v2.5-tts-voicedesign`, `mimo-v2.5-tts-voiceclone`, `mimo-v2-tts` | Xiaomi MiMo OpenAI-compatible chat completions route. Token Plan keys (`tp-...`) use `api-key` auth and the token-plan endpoint by default; pay-as-you-go mode uses standard API keys (`sk-...`) and `https://api.xiaomimimo.com/v1`. It sends `max_completion_tokens` and uses MiMo's `thinking` field for reasoning control. Token Plan cost/usage is credit/quota based; Codewhale shows it as unknown until Xiaomi exposes a reliable balance API. `codewhale speech` / `tts` uses the TTS models. |
403 | `novita` | `[providers.novita]` | `NOVITA_API_KEY` | `NOVITA_BASE_URL`; default `https://api.novita.ai/openai/v1` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash` | OpenAI-compatible hosted route for DeepSeek model IDs. Use config or `CODEWHALE_MODEL` / `DEEPSEEK_MODEL` for model overrides. |
404 | `fireworks` | `[providers.fireworks]` | `FIREWORKS_API_KEY` | `FIREWORKS_BASE_URL`; default `https://api.fireworks.ai/inference/v1` | `accounts/fireworks/models/deepseek-v4-pro` | OpenAI-compatible hosted route. Use config or `CODEWHALE_MODEL` / `DEEPSEEK_MODEL` for model overrides. |
405 | `siliconflow` | `[providers.siliconflow]` | `SILICONFLOW_API_KEY` | `SILICONFLOW_BASE_URL`; default `https://api.siliconflow.com/v1` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | OpenAI-compatible hosted route. Official docs use the `.com` endpoint. `SILICONFLOW_MODEL` is accepted. Reasoning aliases `deepseek-reasoner` and `deepseek-r1` map to Pro; `deepseek-chat` and `deepseek-v3` map to Flash. |
406 | `siliconflow-CN` | `[providers.siliconflow_cn]` | `SILICONFLOW_API_KEY` | `SILICONFLOW_BASE_URL`; default `https://api.siliconflow.cn/v1` | Uses the SiliconFlow model set | China regional SiliconFlow route. Falls back to `[providers.siliconflow]` for api_key / base_url / model when unset. Select it with `provider = "siliconflow-CN"` or `CODEWHALE_PROVIDER=siliconflow-CN`. |
407 | `arcee` | `[providers.arcee]` | `ARCEE_API_KEY` | `ARCEE_BASE_URL`; default `https://api.arcee.ai/api/v1` | `trinity-large-thinking`, `trinity-large-preview` | Arcee AI direct OpenAI-compatible route, tracked as 256K-context BF16 serving. `ARCEE_MODEL` is accepted. OpenRouter's `arcee-ai/trinity-large-thinking` remains the OpenRouter namespaced model ID; direct Arcee uses the bare `trinity-large-thinking` ID. |
408 | `moonshot` | `[providers.moonshot]` | `MOONSHOT_API_KEY`, `KIMI_API_KEY` | `MOONSHOT_BASE_URL`, `KIMI_BASE_URL`; default `https://api.moonshot.ai/v1` | Direct Moonshot: `kimi-k3`, `kimi-k2.7-code`, `kimi-k2.6`; Kimi Code membership: `k3`, `kimi-for-coding`, `kimi-for-coding-highspeed` at `https://api.kimi.com/coding/v1` | Moonshot/Kimi route. `kimi` and `kimi-k2` aliases select `kimi-k2.7-code`; `MOONSHOT_MODEL`, `KIMI_MODEL_NAME`, and `KIMI_MODEL` are accepted. Kimi thinking streams through `reasoning_content`; Codewhale keeps it in Thinking cells and replays it for thinking/tool-call continuity. For direct K3, use exact `base_url = "https://api.moonshot.ai/v1"` and `model = "kimi-k3"`; it is always-thinking and receives top-level `reasoning_effort = "low" | "high" | "max"` (`off` normalizes to `low`), uses only `max_completion_tokens`, and omits `temperature`/`top_p` per the [K3 quickstart](https://platform.kimi.ai/docs/guide/kimi-k3-quickstart). For Kimi Code K3, use a key from the [Kimi Code console](https://www.kimi.com/code/console), exact `base_url = "https://api.kimi.com/coding/v1"`, and bare `model = "k3"`; `off` becomes enabled `low`, while normal dispatched `auto` selects and sends a concrete Codewhale tier. Only an omitted reasoning setting leaves the provider default in control. That membership route defaults safely to 262,144 context tokens; the [Kimi Code model-tier table](https://www.kimi.com/code/docs/en/kimi-code/models.html) grants Allegretto and higher plans up to 1M, which those plans may express as `context_window = 1048576`. `k3[1m]` is Claude Code-only and Codewhale rejects it. `kimi-for-coding` remains the valid K2.7 membership route, and `kimi-for-coding-highspeed` is its own high-speed roster entry (262,144 context); membership ids are rejected on the direct platform endpoint, and `kimi-k3` stays rejected on the membership endpoint. Billing is decided by the endpoint the route resolves to, judged once against the two exact product endpoints: direct Moonshot (`https://api.moonshot.ai/v1` or the default) bills metered with dollar estimates, the exact Kimi Code membership endpoint bills as Kimi Code quota and never shows dollar estimates, and anything else — a gateway host, a neighboring Kimi-hosted path — reports `cost: unknown` rather than borrowing either product. An imported Kimi Code token with no `base_url` in its table still resolves to the membership endpoint, so it bills as Kimi Code quota and never accrues dollars. A completed turn, parent or sub-agent, is billed from the immutable endpoint receipt its own client was built with, never from a later config re-read: `MOONSHOT_BASE_URL`/`KIMI_BASE_URL` are merged into the *active* provider's table only, and an in-turn provider switch can move the ambient config off the route that actually ran. Legacy `auth_mode = "kimi_oauth"` fails to API-key guidance without probing Kimi CLI files. Codewhale does not impersonate `kimi_cli` or `kimi_code_cli`. **China-region keys:** contributor field evidence (@vFONGv, PR #5229, verified on Windows 10) reports that a China-region Moonshot key must be paired with `base_url = "https://api.moonshot.cn/v1"`; left on the default international host (`https://api.moonshot.ai/v1`) it fails authentication. We have no China-region key to verify this ourselves, so it is recorded as a user report rather than a tested route. Note also that editing `base_url` alone does not take effect until `codewhale auth set` is re-run for that provider. |
409 | `zai` | `[providers.zai]` | `ZAI_API_KEY`, `Z_AI_API_KEY` | `ZAI_BASE_URL`, `Z_AI_BASE_URL`; default `https://api.z.ai/api/coding/paas/v4`; general API `https://api.z.ai/api/paas/v4` | `GLM-5.2` default; `GLM-5.1` and `GLM-5-Turbo` available; `GLM-5.3` registered/selectable but **not live on the Z.ai API as of 2026-08-03** | Z.AI GLM Coding Plan route. `GLM-5.2` is the default; set `model = "GLM-5.1"` or `ZAI_MODEL=GLM-5.1` for the smaller model, or `GLM-5-Turbo` for the fast variant used by faster/explore sub-agents. `GLM-5.3` is registered so the id resolves and routes to Z.ai rather than being rewritten to another model, but Z.ai's live `/models` catalog did not list it on 2026-08-03 — selecting it will fail upstream until Z.ai ships it. Its metadata (context, output, reasoning controls) is inherited from `GLM-5.2` pending official Z.ai release metadata, and it carries no price. |
410 | `stepfun` | `[providers.stepfun]` | `STEPFUN_API_KEY`, `STEP_API_KEY` | `STEPFUN_BASE_URL`, `STEP_BASE_URL`; default `https://api.stepfun.ai/v1`; Coding Plan endpoint `https://api.stepfun.ai/step_plan/v1` | `step-3.7-flash` | StepFun / StepFlash direct OpenAI-compatible route. `/provider` setup asks which billing route the key belongs to — pay-as-you-go or Step Plan — validates the key against the chosen endpoint, and writes the answer to `[providers.stepfun].base_url` only. A base URL that is neither recognized route is left alone and the question is skipped. You can also set `[providers.stepfun].base_url` or `STEP_BASE_URL` to the Coding Plan URL by hand. Offline accounting labels recognized routes as `stepfun-payg` or `stepfun-plan` without persisting the raw endpoint, and only the standard PAYG route receives token pricing. `STEPFUN_MODEL` and `STEP_MODEL` are accepted. |
411 | `minimax` | `[providers.minimax]` | `MINIMAX_API_KEY` | `MINIMAX_BASE_URL`; default `https://api.minimax.io/v1`; China `https://api.minimaxi.com/v1` | `MiniMax-M3`, `MiniMax-M2.7`, `MiniMax-M2.7-highspeed`, `MiniMax-M2.5`, `MiniMax-M2.5-highspeed`, `MiniMax-M2.1`, `MiniMax-M2.1-highspeed`, `MiniMax-M2` | MiniMax direct OpenAI-compatible route. Codewhale sends `reasoning_split = true` so MiniMax thinking arrives separately from answer text. Both MiniMax dialects sell pay-as-you-go and Token Plan over the same endpoints and the same key, so billing is classified from the credential *product*, never from the endpoint or from a default. `mode = "token-plan"` in `[providers.minimax]`/`[providers.minimax_anthropic]`, or a Token Plan key shaped `sk-cp…`, bills as MiniMax Token Plan quota with no dollar estimates; an explicit pay-as-you-go mode (`pay-as-you-go`/`payg`/`metered`) wins over key shape. The key's product prefix is only visible when the key is in config, bound by `api_key_env`, or exported as `MINIMAX_API_KEY` on an official endpoint — a key saved through `codewhale auth set` (secret store / OS keyring) is deliberately not read to classify billing. With no explicit mode and no visible product marker the route reports `cost: unknown` rather than assuming pay-as-you-go, so a Token Plan account is never charged invented dollars. Custom/gateway endpoints also fail closed with `cost: unknown`. Official M3 input modalities are text, image, and video; M2.7 is text-only. |
412 | `minimax-anthropic` | `[providers.minimax_anthropic]` | `MINIMAX_API_KEY` | `MINIMAX_ANTHROPIC_BASE_URL`; default `https://api.minimax.io/anthropic`; China `https://api.minimaxi.com/anthropic` | `MiniMax-M3`, `MiniMax-M2.7` | MiniMax direct Anthropic-compatible Messages route. Keep the `/anthropic` suffix because Codewhale appends `/v1/messages`; the route uses `x-api-key`. M3 supports adaptive or disabled thinking. M2.7 always keeps thinking enabled. |
413 | `sglang` | `[providers.sglang]` | Optional `SGLANG_API_KEY` | `SGLANG_BASE_URL`; default `http://localhost:30000/v1` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | Self-hosted OpenAI-compatible route. Localhost deployments commonly omit auth. `SGLANG_MODEL` is accepted. |
414 | `vllm` | `[providers.vllm]` | Optional `VLLM_API_KEY` | `VLLM_BASE_URL`; default `http://localhost:8000/v1` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | Self-hosted vLLM OpenAI-compatible route. Localhost deployments commonly omit auth. `VLLM_MODEL` is accepted. |
415 | `ollama` | `[providers.ollama]` | Optional `OLLAMA_API_KEY` | `OLLAMA_BASE_URL`; default `http://localhost:11434/v1` | `deepseek-coder:1.3b`; provider-hinted custom tags pass through | Self-hosted Ollama OpenAI-compatible route. Localhost deployments commonly omit auth. `OLLAMA_MODEL` is accepted. |
416 | `huggingface` | `[providers.huggingface]` | `HUGGINGFACE_API_KEY`, `HF_TOKEN` | `HUGGINGFACE_BASE_URL`, `HF_BASE_URL`; default `https://router.huggingface.co/v1` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | Hugging Face Inference Providers OpenAI-compatible router route. Accepted aliases: `huggingface`, `hugging-face`, `hugging_face`, `hf`. Org-prefixed model IDs pass through. `HUGGINGFACE_MODEL` and `HF_MODEL` are accepted. Hub browsing/export are separate future features. |
417 | `deepinfra` | `[providers.deepinfra]` | `DEEPINFRA_API_KEY`, `DEEPINFRA_TOKEN` | `DEEPINFRA_BASE_URL`; default `https://api.deepinfra.com/v1/openai` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | DeepInfra OpenAI-compatible route. Drop-in replacement for OpenAI SDK. |
418 | `together` | `[providers.together]` | `TOGETHER_API_KEY` | `TOGETHER_BASE_URL`; default `https://api.together.xyz/v1` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash`, `thinkingmachines/inkling` | Together AI OpenAI-compatible route. `TOGETHER_MODEL` is accepted. Model aliases `deepseek-v4-pro` and `deepseek-v4-flash` normalize to Together's org-prefixed IDs; `inkling` and `together-inkling` normalize to Together's published lowercase Inkling wire ID. Inkling uses the exact `none`/`minimal`/`low`/`medium`/`high`/`max` reasoning vocabulary from Thinking Machines' [official model repository](https://huggingface.co/thinkingmachines/Inkling). Together's [launch post](https://www.together.ai/blog/together-ai-brings-thinking-machines-labs-new-model-inkling-on-day-0) currently says Inkling is live with 1M context, while its [model detail page](https://www.together.ai/models/inkling) says coming soon with 256K context and publishes no price. Until Together's active `/models` endpoint and the Models.dev catalog resolve that conflict, Inkling is not seeded into Codewhale's offline picker and no route-specific context or cost is inferred. |
419 | `qianfan` | `[providers.qianfan]` | `QIANFAN_API_KEY`, `BAIDU_QIANFAN_API_KEY` | `QIANFAN_BASE_URL`, `BAIDU_QIANFAN_BASE_URL`; default `https://api.baiduqianfan.ai/v1` | `ernie-4.0-turbo-8k`; provider-scoped custom Qianfan service/model IDs pass through | Baidu Qianfan OpenAI-compatible route. Requests use Bearer auth and Chat Completions payloads. `QIANFAN_MODEL` and `BAIDU_QIANFAN_MODEL` are accepted; aliases `baidu-qianfan`, `baidu_qianfan`, and `baidu` resolve to this provider. Tool/function calling is model-scoped in Qianfan docs, so Codewhale preserves the selected wire model and leaves live capability proof to follow-up route/capability work. |
420 | `openai-codex` | `[providers.openai_codex]` | Process token via `OPENAI_CODEX_ACCESS_TOKEN`/`CODEX_ACCESS_TOKEN`, or exact-path read-only consent after `codex login` | `OPENAI_CODEX_BASE_URL`/`CODEX_BASE_URL`; default `https://chatgpt.com/backend-api` | `gpt-5.5` | **Experimental.** Talks to the OpenAI Responses API at `/codex/responses`. Codex CLI files are disabled by default; `codewhale auth external-consent --provider openai-codex --mode read-only` grants access to one exact file. Codewhale never refreshes or rewrites that external file, and expired tokens fail closed. `OPENAI_CODEX_MODEL`/`CODEX_MODEL` and `OPENAI_CODEX_ACCOUNT_ID`/`CODEX_ACCOUNT_ID` are accepted. Codewhale budgets this route with the 400K Codex-family effective context window even when the public API model table lists a larger native `gpt-5.5` window. |
421 | `anthropic` | `[providers.anthropic]` | `ANTHROPIC_API_KEY` | `ANTHROPIC_BASE_URL`; default `https://api.anthropic.com` | `claude-opus-4-8`, `claude-sonnet-4-6` (default), `claude-haiku-4-5` | Native Anthropic Messages API route (`/v1/messages`, `x-api-key` + `anthropic-version: 2023-06-01`) — not OpenAI-compatible. Prompt caching via `cache_control` breakpoints, adaptive thinking + `output_config.effort`, signed thinking blocks replayed verbatim, cache telemetry normalized per #2961. `ANTHROPIC_MODEL` is accepted. |
422 | `openmodel` | `[providers.openmodel]` | `OPENMODEL_API_KEY` | `OPENMODEL_BASE_URL`; default `https://api.openmodel.ai` | `deepseek-v4-flash`; provider-scoped custom model IDs pass through | OpenModel Anthropic-compatible Messages route. Uses `/v1/messages`, Bearer auth, and `anthropic-version: 2023-06-01`; OpenModel selects DeepSeek, DashScope, Xiaomi, Claude, and other routes by model id. `OPENMODEL_MODEL` is accepted. |
423 | `sakana` | `[providers.sakana]` | `FUGU_API_KEY`, `SAKANA_API_KEY` | `SAKANA_BASE_URL`; default `https://api.sakana.ai/v1` | `fugu` (default), `fugu-ultra-20260615` | Sakana AI Fugu OpenAI-compatible route. Standard Chat Completions wire protocol; streaming supported. `fugu-ultra-20260615` is the heavy/reasoning variant. Env var aliases: `FUGU_API_KEY` (primary), `SAKANA_API_KEY`; provider aliases: `sakana-ai`, `sakana_ai`, `fugu`. |
424 | `longcat` | `[providers.longcat]` | `LONGCAT_API_KEY` | `LONGCAT_BASE_URL`; default `https://api.longcat.chat/openai/v1` | `LongCat-2.0` (default) | Meituan LongCat curated model gateway. OpenAI-compatible Chat Completions wire protocol. Sign up at https://longcat.chat/platform for an API key. Provider aliases: `long-cat`, `meituan-longcat`, `meituan`. |
425 | `opencode-go` | `[providers.opencode_go]` | `OPENCODE_GO_API_KEY` | `OPENCODE_GO_BASE_URL`; default `https://opencode.ai/zen/go/v1` | `deepseek-v4-pro` (default), `grok-4.5`, `glm-5.2`, `glm-5.1`, `kimi-k3`, `kimi-k2.7-code`, `kimi-k2.6`, `deepseek-v4-flash`, `mimo-v2.5`, `mimo-v2.5-pro` | [OpenCode Go](https://opencode.ai/docs/go/) subscription route using OpenAI-compatible Chat Completions. `OPENCODE_GO_MODEL` is accepted. Codewhale uses bare wire IDs; familiar `opencode-go/<model-id>` input aliases normalize to the bare ID. Go models documented only on the Anthropic `/messages` endpoint are deliberately not advertised by this route until Codewhale supports per-model wire selection. Billing surfaces show the Go allowance instead of token-price estimates. |
426 | `opencode-zen` | `[providers.opencode_zen]` | `OPENCODE_ZEN_API_KEY`, fallback `OPENCODE_API_KEY` | `OPENCODE_ZEN_BASE_URL`; default `https://opencode.ai/zen/v1` | `gpt-5.5` (default); current documented GPT, Claude, Qwen, DeepSeek, MiniMax, GLM, Kimi, Grok, and free-model IDs | [OpenCode Zen](https://opencode.ai/docs/zen/) model-aware gateway. `OPENCODE_ZEN_MODEL` is accepted, and official `opencode/<model-id>` selectors normalize to bare wire IDs. GPT rows use `/responses`; Claude and Qwen rows use `/messages`; DeepSeek, MiniMax, GLM, Kimi, Grok, and the listed free rows use `/chat/completions`. Responses and Chat Completions authenticate with Bearer `Authorization`, while Anthropic Messages uses `x-api-key`; none of these routes use ChatGPT/Codex OAuth guidance or headers. Gemini currently fails closed because its model-specific Google wire protocol is not implemented. Unknown models also fail closed until their protocol is present in the curated catalog. |
427 | `meta` | `[providers.meta]` | `META_MODEL_API_KEY`, `MODEL_API_KEY` | `META_MODEL_API_BASE_URL`, `MODEL_API_BASE_URL`; default `https://api.meta.ai/v1` | `muse-spark-1.2` (default) | [Meta Model API](https://developer.meta.com/ai/resources/blog/build-with-muse-spark/) public-preview route using OpenAI-compatible Chat Completions. Muse Spark 1.2 keeps its wire ID, tool support, 1M context, 32K output metadata, and `none` through `xhigh` reasoning effort. `META_MODEL_API_MODEL` and `MODEL_API_MODEL` are accepted. Provider aliases: `meta-ai`, `meta_model_api`, `muse`, `muse-spark`. |
428 | `telecomjs` | `[providers.telecomjs]` | `TELECOMJS_API_KEY` | `TELECOMJS_BASE_URL`; default `https://aigw.telecomjs.com/v1` | `deepseek-v4-pro` conservative fallback; authenticated `/models` rows when a key is configured | TelecomJS TokenHub OpenAI-compatible Chat Completions route. Live catalogs are isolated by provider and key fingerprint, stale rows survive transient refresh failures, and unsupported reasoning request fields are omitted. `TELECOMJS_MODEL` is accepted. Provider aliases: `telecom-js`, `telecom_js`, `telecomjs-cn`, `tokenhub`. |
429 | `xai` | `[providers.xai]` | `XAI_API_KEY`, Codewhale-owned device OAuth, or explicit read-only Grok CLI consent | `XAI_BASE_URL`; default `https://api.x.ai/v1` | `grok-4.5` (default), `grok-4.3`, `grok-build`, `grok-composer-2.5-fast`, `grok-4.20-0309-reasoning`, `grok-4.20-0309-non-reasoning` | xAI/Grok OpenAI-compatible Chat Completions route. **API-key** (default): Bearer token from console.x.ai via `XAI_API_KEY` / keyring / `api_key`. **OAuth**: `codewhale auth xai-device` uses SSH-friendly device login and Codewhale-owned storage, which may refresh itself. Existing Grok CLI credentials require `codewhale auth external-consent --provider xai --mode read-only`; the granted external file is never refreshed or rewritten. OAuth may return HTTP 403 on some SuperGrok tiers — keep API-key as the reliable fallback. `XAI_MODEL` is accepted. Provider aliases: `x-ai`, `x_ai`, `grok`. |
430 | `modelstudio-token-plan` | `[providers.modelstudio_token_plan]` | `MODELSTUDIO_API_KEY`, `DASHSCOPE_API_KEY` | `MODELSTUDIO_TOKEN_PLAN_BASE_URL`; default `https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1` | `qwen3.8-max` (default), `qwen3.8-max-preview`, `qwen3.7-plus`, `qwen3.7-max`, `qwen3.6-flash`, `deepseek-v4-pro`, `deepseek-v4-flash-0731`, `glm-5.2` | Alibaba Cloud Model Studio Token Plan OpenAI-compatible Chat Completions route. Token Plan Personal and Team share this endpoint. All listed models are reasoning-capable text/coding models. DeepSeek and GLM entries are provider-scoped and do not collide with first-party routes. `MODELSTUDIO_TOKEN_PLAN_MODEL` is accepted. Provider aliases: `modelstudio-token-plan`, `alibaba-token-plan`, `dashscope-token-plan`. |
431 | `modelstudio-token-plan-anthropic` | `[providers.modelstudio_token_plan_anthropic]` | `MODELSTUDIO_API_KEY`, `DASHSCOPE_API_KEY` | default `https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic` | Same model catalog as `modelstudio-token-plan` | Token Plan Anthropic-compatible Messages route (`/apps/anthropic`). Same API key as the OpenAI dialect. Provider aliases: `modelstudio-token-plan-anthropic`, `alibaba-token-plan-anthropic`. |
432 | `modelstudio-coding-plan` | `[providers.modelstudio_coding_plan]` | `MODELSTUDIO_API_KEY`, `DASHSCOPE_API_KEY` | `MODELSTUDIO_CODING_PLAN_BASE_URL`; default `https://coding-intl.dashscope.aliyuncs.com/v1` | `qwen3.8-max` (default); same catalog as Token Plan | Alibaba Cloud Model Studio Coding Plan OpenAI-compatible Chat Completions route. `MODELSTUDIO_CODING_PLAN_MODEL` is accepted. Provider aliases: `modelstudio-coding-plan`, `alibaba-coding-plan`, `dashscope-coding-plan`. |
433 | `modelstudio-coding-plan-anthropic` | `[providers.modelstudio_coding_plan_anthropic]` | `MODELSTUDIO_API_KEY`, `DASHSCOPE_API_KEY` | default `https://coding-intl.dashscope.aliyuncs.com/apps/anthropic` | Same model catalog as `modelstudio-coding-plan` | Coding Plan Anthropic-compatible Messages route (`/apps/anthropic`). Provider aliases: `modelstudio-coding-plan-anthropic`, `alibaba-coding-plan-anthropic`. |
434
435 ### OpenCode Zen protocol catalog
436
437 Zen Responses and Chat Completions requests authenticate with Bearer
438 `Authorization`; Zen Anthropic Messages requests use `x-api-key`. None of these
439 routes add ChatGPT/Codex OAuth headers.
440
441 The bundled Zen transport snapshot follows the [official endpoint
442 table](https://opencode.ai/docs/zen/) and is intentionally explicit:
443
444 - Responses: `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5`,
445 `gpt-5.5-pro`, `gpt-5.4`, `gpt-5.4-pro`, `gpt-5.4-mini`, `gpt-5.4-nano`,
446 `gpt-5.3-codex`, `gpt-5.3-codex-spark`, `gpt-5.2`, `gpt-5.2-codex`,
447 `gpt-5.1`, `gpt-5.1-codex`, `gpt-5.1-codex-max`,
448 `gpt-5.1-codex-mini`, `gpt-5`, `gpt-5-codex`, `gpt-5-nano`.
449 - Anthropic Messages: `claude-fable-5`, `claude-opus-4-8`,
450 `claude-opus-4-7`, `claude-opus-4-6`, `claude-opus-4-5`,
451 `claude-sonnet-5`, `claude-sonnet-4-6`, `claude-sonnet-4-5`,
452 `claude-haiku-4-5`, `qwen3.7-max`, `qwen3.7-plus`, `qwen3.6-plus`,
453 `qwen3.5-plus`.
454 - Chat Completions: `deepseek-v4-pro`, `deepseek-v4-flash`, `minimax-m3`,
455 `minimax-m2.7`, `minimax-m2.5`, `glm-5.2`, `glm-5.1`, `glm-5`,
456 `kimi-k2.5`, `kimi-k2.6`, `kimi-k2.7-code`, `grok-4.5`,
457 `grok-build-0.1`, `big-pickle`, `mimo-v2.5-free`,
458 `north-mini-code-free`, `nemotron-3-ultra-free`,
459 `deepseek-v4-flash-free`.
460
461 Gemini entries are excluded because the official table assigns them Google's
462 model-specific protocol. A catalog miss never falls back to another Zen wire
463 shape, including when a custom Zen base URL is configured.
464
465 ### Hugging Face Provider vs MCP vs Hub
466
467 Codewhale's `huggingface` provider ID is only the OpenAI-compatible chat
468 inference route through Hugging Face Inference Providers. It is selected with
469 `/provider huggingface`, `CODEWHALE_PROVIDER=huggingface`, or
470 `provider = "huggingface"`.
471
472 Hugging Face MCP is a separate external-tool route. Configure it through the
473 MCP config described in `docs/MCP.md`, preferably using the settings-generated
474 snippet from <https://huggingface.co/settings/mcp>. In the TUI, `/hf mcp status`
475 checks whether the Hugging Face MCP server appears in the resolved MCP config,
476 `/hf mcp setup` prints the settings workflow and a placeholder-only shape, and
477 `/hf concepts` explains the provider/MCP/Hub distinction.
478
479 Hub publishing or repository management remains explicit user action through
480 Hub-native tooling such as `huggingface_hub` or git. The `/hf` helper does not
481 upload to Hugging Face and does not perform direct Hugging Face Hub HTTP search.
482
483 ### Xiaomi MiMo Notes
484
485 `xiaomi-mimo` defaults to `mimo-v2.5-pro` for long-context reasoning and coding
486 work. The chat picker also exposes `mimo-v2.5-pro-ultraspeed` and the latest
487 Omni model `mimo-v2.5`. Xiaomi MiMo TTS is available through
488 `codewhale --provider xiaomi-mimo speech "text" --model tts` (or the `tts`
489 alias). In Act and Operate, the provider-specific `speech` / `tts` tools are
490 available through deferred discovery when the Xiaomi MiMo route is configured.
491
492 `/provider xiaomi-mimo ultraspeed` and `/provider xiaomi-mimo pro-ultraspeed`
493 both select `mimo-v2.5-pro-ultraspeed`. Speech aliases such as `tts`,
494 `voice-design`, and `voice-clone` are separate from normal chat defaults.
495
496 Token Plan keys default to the Singapore endpoint
497 `https://token-plan-sgp.xiaomimimo.com/v1`. If your MiMo account is provisioned
498 for the China region, set `base_url = "https://token-plan-cn.xiaomimimo.com/v1"`
499 explicitly in `[providers.xiaomi_mimo]` or set `mode = "token-plan-cn"`. Europe
500 Token Plan accounts can set
501 `base_url = "https://token-plan-ams.xiaomimimo.com/v1"` or use
502 `mode = "token-plan-ams"`; `mode = "pay-as-you-go"`
503 selects the standard API endpoint and standard MiMo key family. Xiaomi Token
504 Plan docs and console expose credit/quota semantics, but Codewhale does not
505 currently have a documented balance endpoint to poll, so cost display remains
506 unknown rather than reusing token-price estimates from another provider.
507
508 Voice-design and voice-clone shorthands map to `mimo-v2.5-tts-voicedesign` and
509 `mimo-v2.5-tts-voiceclone`. Xiaomi's current
510 [image-understanding guide](https://platform.xiaomimimo.com/docs/en-US/usage-guide/multimodal-understanding/image-understanding)
511 includes `mimo-v2.5` for image input. Codewhale exposes image analysis through the
512 separate `[vision_model]` / `image_analyze` path; set that model to
513 `mimo-v2.5` when using MiMo for vision.
514
515 ### OpenRouter-Compatible Base URLs
516
517 OpenRouter-compatible gateways should usually stay on the `openrouter`
518 provider with a provider-scoped `base_url` override instead of moving through
519 the generic `openai` route. That keeps OpenRouter-style reasoning, streaming,
520 cache usage, and namespaced wire model parsing attached to the selected route:
521
522 ```toml
523 provider = "openrouter"
524
525 [providers.openrouter]
526 api_key = "sk-..."
527 base_url = "https://openrouter-compatible.example/v1"
528 model = "deepseek/deepseek-v4-pro"
529 ```
530
531 Codewhale preserves the `deepseek/` wire-model prefix under the OpenRouter
532 provider scope; it does not infer a switch to the direct DeepSeek provider from
533 that model string. Cache fields such as `prompt_cache_hit_tokens`,
534 `prompt_cache_miss_tokens`, and `prompt_tokens_details.cached_tokens` are
535 parsed when the upstream gateway sends them. If a key/account type omits those
536 fields, Codewhale treats them as absent for that response rather than as a
537 different provider route.
538
539 ### Recent OpenRouter Large Models
540
541 OpenRouter completions and static registry rows include the April 2026 onward
542 large models verified through OpenRouter's model metadata:
543 `arcee-ai/trinity-large-thinking`, `qwen/qwen3.6-flash`,
544 `qwen/qwen3.6-35b-a3b`, `qwen/qwen3.6-max-preview`, `qwen/qwen3.6-27b`,
545 `qwen/qwen3.6-plus`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`,
546 `xiaomi/mimo-v2.5`, `moonshotai/kimi-k2.7-code`, `moonshotai/kimi-k2.6`,
547 `z-ai/glm-5.1`, `z-ai/glm-5.2`, `z-ai/glm-5-turbo`, `tencent/hy3-preview`,
548 `google/gemma-4-31b-it`, `google/gemma-4-26b-a4b-it`, and
549 `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free`.
550 `minimax/minimax-m3` was added from OpenRouter's May 31, 2026 listing as a 1M
551 context multimodal model for coding, tool use, and long-horizon agentic work.
552 `z-ai/glm-5.2` is now the default GLM route on both the Z.AI Coding Plan and
553 OpenRouter; `GLM-5.1` / `z-ai/glm-5.1` remain available as the smaller model,
554 and `GLM-5-Turbo` / `z-ai/glm-5-turbo` serve as the faster same-family sibling
555 used by faster/explore sub-agents.
556 `GLM-5.3` / `z-ai/glm-5.3` are deliberately **not** in the verified list
557 above. Zhipu/Z.ai had not released GLM-5.3 as of 2026-08-03 — the live Z.ai
558 `/models` catalog did not list it, and OpenRouter cannot mirror a model that
559 does not exist upstream, so neither id was verified against provider metadata
560 and neither can be. They are registered only so the ids resolve to the Z.ai and
561 OpenRouter routes instead of being rewritten to a different vendor's model;
562 requests to them fail upstream until Z.ai ships the model. They change no
563 default, and their catalog metadata — context window, max output, and reasoning
564 controls — is inherited wholesale from `GLM-5.2` pending official Z.ai release
565 metadata rather than measured, so no capability, limit, or benchmark claim here
566 is a published GLM-5.3 fact. They carry no price until Z.ai publishes one.
567 Correct this in `crates/config/assets/models_dev.bundled.json`
568 (`_meta.pending_release_metadata`) first.
569
570 ## Static Model Registry
571
572 `codewhale model list` and `codewhale model resolve` use the static registry in
573 `crates/agent/src/lib.rs`. This is not the same as live `/models` discovery.
574 Use `/models` or `codewhale models` to fetch model IDs from the active API
575 endpoint when the endpoint supports model listing.
576
577 | Provider | Static registry entries | Tool calls | Registry reasoning flag |
578 | --- | --- | --- | --- |
579 | `deepseek` | `deepseek-v4-pro`, `deepseek-v4-flash` | yes | yes |
580 | `nvidia-nim` | `deepseek-ai/deepseek-v4-pro`, `deepseek-ai/deepseek-v4-flash` | yes | yes |
581 | `openai` | `deepseek-v4-pro`, `deepseek-v4-flash`, `gpt-5.6`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna` | yes | yes |
582 | `atlascloud` | `deepseek-ai/deepseek-v4-flash`, `deepseek-ai/deepseek-v4-pro` | yes | yes |
583 | `wanjie-ark` | `deepseek-reasoner` | yes | yes |
584 | `volcengine` | `DeepSeek-V4-Pro`, `DeepSeek-V4-Flash` | yes | yes |
585 | `openrouter` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`, `arcee-ai/trinity-large-thinking`, `minimax/minimax-m3`, `minimax/minimax-m2.7`, `xiaomi/mimo-v2.5-pro`, `xiaomi/mimo-v2.5`, `qwen/qwen3.6-flash`, `qwen/qwen3.6-35b-a3b`, `qwen/qwen3.6-max-preview`, `qwen/qwen3.6-27b`, `qwen/qwen3.6-plus`, `qwen/qwen3.7-max`, `moonshotai/kimi-k2.7-code`, `moonshotai/kimi-k2.6`, `z-ai/glm-5.1`, `z-ai/glm-5.2`, `z-ai/glm-5.3`, `z-ai/glm-5-turbo`, `tencent/hy3-preview`, `google/gemma-4-31b-it`, `google/gemma-4-26b-a4b-it`, `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free`, `nvidia/nemotron-3-ultra-550b-a55b` | yes | yes |
586 | `xiaomi-mimo` | `mimo-v2.5-pro`, `mimo-v2.5-pro-ultraspeed`, `mimo-v2.5`; speech/TTS IDs are selected through `codewhale speech` / `tts` | yes | yes for chat models; no for speech/TTS models |
587 | `novita` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash` | yes | yes |
588 | `fireworks` | `accounts/fireworks/models/deepseek-v4-pro` | yes | yes |
589 | `siliconflow` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | yes | yes |
590 | `arcee` | `trinity-large-thinking`, `trinity-large-preview`; provider-hinted custom model IDs pass through | yes | yes for `trinity-large-thinking`; no for `trinity-large-preview` |
591 | `moonshot` | `kimi-k2.7-code`, `kimi-k2.6` | yes | yes |
592 | `zai` | `GLM-5.2`, `GLM-5.1`, `GLM-5.3`, `GLM-5-Turbo`; provider-hinted custom model IDs pass through | yes | yes |
593 | `stepfun` | `step-3.7-flash` | yes | no |
594 | `minimax` | `MiniMax-M3`, `MiniMax-M2.7`, `MiniMax-M2.7-highspeed`, `MiniMax-M2.5`, `MiniMax-M2.5-highspeed`, `MiniMax-M2.1`, `MiniMax-M2.1-highspeed`, `MiniMax-M2` | yes | yes |
595 | `minimax-anthropic` | `MiniMax-M3`, `MiniMax-M2.7` | yes | yes |
596 | `sglang` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | yes | yes |
597 | `vllm` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | yes | yes |
598 | `ollama` | `deepseek-coder:1.3b`; custom tags pass through when provider hint is `ollama` | yes | no |
599 | `huggingface` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | yes | no |
600 | `deepinfra` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | yes | yes |
601 | `together` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash`, `thinkingmachines/inkling` | yes | yes |
602 | `openai-codex` | `gpt-5.5` | yes | yes |
603 | `anthropic` | `claude-opus-4-8`, `claude-sonnet-4-6`, `claude-haiku-4-5` | yes | yes for `claude-opus-4-8` and `claude-sonnet-4-6`; no for `claude-haiku-4-5` |
604 | `openmodel` | `deepseek-v4-flash`; provider-scoped custom model IDs pass through | yes | model-dependent |
605 | `sakana` | `fugu`, `fugu-ultra-20260615` | yes | yes for `fugu-ultra-20260615` |
606 | `longcat` | `LongCat-2.0` | yes | yes |
607 | `opencode-go` | `deepseek-v4-pro`, `grok-4.5`, `glm-5.2`, `glm-5.1`, `kimi-k3`, `kimi-k2.7-code`, `kimi-k2.6`, `deepseek-v4-flash`, `mimo-v2.5`, `mimo-v2.5-pro` | yes | yes |
608 | `meta` | `muse-spark-1.2` | yes | yes |
609 | `xai` | `grok-4.5`, `grok-4.3`, `grok-build`, `grok-composer-2.5-fast`, `grok-4.20-0309-reasoning`, `grok-4.20-0309-non-reasoning` | yes | yes for `grok-4.5`, `grok-4.3`, `grok-build`, and `grok-4.20-0309-reasoning` |
610 | `modelstudio-token-plan`, `modelstudio-coding-plan` | `qwen3.8-max`, `qwen3.8-max-preview`, `qwen3.7-plus`, `qwen3.7-max`, `qwen3.6-flash`, `deepseek-v4-pro`, `deepseek-v4-flash-0731`, `glm-5.2` | yes | yes |
611
612 AtlasCloud keeps the same default model as the config layer and adds
613 provider-scoped aliases for the Pro and Flash rows. Other AtlasCloud model IDs
614 should still be selected through `ATLASCLOUD_MODEL`, config, or live model
615 listing when available.
616
617 ## Capability Metadata
618
619 `codewhale-tui doctor --json` exposes the `capability` object. It is static
620 metadata, not a live API probe. Current fields are:
621
622 `resolved_provider`, `resolved_model`, `context_window`, `max_output`,
623 `thinking_supported`, `cache_telemetry_supported`, and `request_payload_mode`.
624
625 When configuration cannot be loaded or validated, `doctor --json` exits
626 nonzero and prints a bounded, secret-redacted JSON error envelope with
627 `status = "error"` and `error.kind = "config_validation"` instead of emitting
628 misleading route or capability metadata.
629
630 Most shipped providers use the Chat Completions request payload mode. Native
631 Messages routes, including `minimax-anthropic`, use `/v1/messages`, and
632 `openai-codex` uses Responses.
633
634 For OpenAI-compatible gateways or self-hosted runtimes whose real window
635 differs from the static table, set `[providers.<name>] context_window = N`.
636 The configured value becomes the route-effective context window for prompts,
637 context-pressure checks, compaction, and output-cap budgeting.
638
639 `max_output` is optional and truthful: it is `null` (and omitted from the
640 capability struct on the wire) when the route publishes no output maximum we
641 can stand behind — the Kimi Code membership `kimi-for-coding` family is the
642 canonical example, since the membership catalog owns their limits. An unknown
643 output ceiling is never backfilled with a placeholder, and it applies **no**
644 compatibility clamp to a turn's requested `max_tokens`; only a concrete
645 route/offering maximum narrows the request. A model the catalogue simply has no
646 row for is a different fact — absence is not permission, so an uncatalogued id
647 keeps a conservative ceiling. The "Max output metadata" column below reads
648 `unknown` wherever no documented maximum exists.
649
650 | Provider/model class | Context window | Max output metadata | Thinking support | Cache telemetry | FIM endpoint |
651 | --- | --- | --- | --- | --- | --- |
652 | DeepSeek V4 (`deepseek-v4-pro`, `deepseek-v4-flash`) | 1,000,000 | 384,000 | yes | yes | DeepSeek beta only |
653 | DeepSeek compatibility aliases (`deepseek-chat`, `deepseek-reasoner`) | 1,000,000 | 384,000 | yes | yes | DeepSeek beta only |
654 | NVIDIA NIM V4 registry models | 1,000,000 | 384,000 | yes | yes | not documented in code |
655 | Volcengine Ark V4 model IDs | 1,000,000 | 384,000 | yes | yes | not documented in code |
656 | OpenRouter, Novita, Fireworks, SiliconFlow, SGLang, and vLLM V4 model IDs | 1,000,000 | 384,000 | yes | no | not documented in code |
657 | Xiaomi MiMo `mimo-v2.5-pro`, `mimo-v2.5-pro-ultraspeed`, `mimo-v2.5` | 1,000,000 | 131,072 | yes | no | not documented in code |
658 | OpenRouter Qwen 3.6 Flash / Plus | 1,000,000 | 65,536 | yes | no | not documented in code |
659 | OpenRouter Qwen 3.6 35B / 27B | 262,144 | 262,140 | yes | no | not documented in code |
660 | OpenRouter Qwen 3.6 Max Preview | 262,144 | 65,536 | yes | no | not documented in code |
661 | OpenAI API `gpt-5.5` | 1,050,000 | 128,000 | yes | no | not documented in code |
662 | OpenAI API `gpt-5.6`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna` | 1,050,000 | 128,000 | yes | no | not documented in code |
663 | Meta Model API `muse-spark-1.2` | 1,000,000 | 32,000 | yes | no | not documented in code |
664 | OpenAI Codex / ChatGPT route (`openai-codex`) | 400,000 effective | 128,000 | yes | no | route uses Responses payload at `/codex/responses` |
665 | OpenModel default/custom model IDs | 200,000 fallback unless model metadata or config overrides it | 64,000 fallback | model-dependent | no | route uses Messages payload at `/v1/messages` |
666 | Wanjie Ark `reasoner` / `r1` model IDs | 128,000 | unknown (no documented maximum) | yes | no | not documented in code |
667 | Direct Arcee API `trinity-large-thinking` | 262,144 | 262,144 | yes | no | not documented in code |
668 | Direct Arcee API `trinity-large-preview` | 262,144 | unknown (no documented maximum) | no in doctor capability metadata | no | not documented in code |
669 | Direct Moonshot `kimi-k3` | 1,048,576 | 1,048,576 documented maximum; 131,072 provider default | yes | no | exact route uses `max_completion_tokens` and omits fixed sampling fields ([K3 quickstart](https://platform.kimi.ai/docs/guide/kimi-k3-quickstart)) |
670 | Kimi Code membership `k3` | 262,144 safe baseline; 1,048,576 with an explicit entitled-plan override | 131,072 conservative default ceiling; membership maximum is not published | yes | no | exact `https://api.kimi.com/coding/v1` route |
671 | Direct Moonshot/Kimi K2.7/K2.6 (`kimi-k2.7-code`, `kimi-k2.6`) | 262,144 | 32,768 | yes | no | provider-reported bundled catalog |
672 | Kimi Code membership `kimi-for-coding`, `kimi-for-coding-highspeed` | 262,144 | unknown — the membership catalog owns these limits and no client-side ceiling is claimed | yes | no | exact `https://api.kimi.com/coding/v1` route |
673 | Direct Z.AI `GLM-5.2` (default) | 1,000,000 | 131,072 | yes | no | not documented in code |
674 | Direct Z.AI `GLM-5.3` | 1,000,000 | 131,072 | yes | no | model not released by Z.ai as of 2026-08-03; every value inherited from `GLM-5.2` pending official Z.ai release metadata |
675 | Direct Z.AI `GLM-5.1` | 202,752 | 131,072 | yes | no | not documented in code |
676 | Direct Z.AI `GLM-5-Turbo` | 202,752 | 131,072 | yes | no | faster/explore sub-agent sibling |
677 | Direct MiniMax `MiniMax-M3` | 1,000,000 | 524,288 | yes | no | not documented in code |
678 | Direct MiniMax M2.x models | 204,800 | unknown until MiniMax output metadata is promoted | yes | no | not documented in code |
679 | MiniMax Messages route (`MiniMax-M3`, `MiniMax-M2.7`) | model-specific values above | model-specific values above | yes | no | route uses `/anthropic/v1/messages` |
680 | Generic `openai` and AtlasCloud | 128,000 | unknown (no documented maximum) | no in doctor capability metadata | no | not documented in code |
681 | Ollama | 8,192 | unknown (no documented maximum) | no | no | not documented in code |
682 | Hugging Face Inference Providers V4 model IDs | 131,072 | unknown (no documented maximum) | yes | no | not documented in code |
683 | Other recognized DeepSeek model IDs | 128,000 unless the model name carries an explicit `Nk` hint | unknown (no documented maximum) | no unless V4/reasoner logic matches | DeepSeek/NIM only | DeepSeek beta only |
684
685 MiniMax M3 uses input-length and service tiers. Codewhale omits
686 `service_tier`, so requests use the standard tier and cost estimates select the
687 correct standard rate from total input usage. Priority rates are listed to keep
688 the official tier structure visible. Prices are USD per million tokens.
689
690 | Model / service tier | Input length | Input | Output | Cache read | Cache write |
691 | --- | --- | ---: | ---: | ---: | ---: |
692 | `MiniMax-M3` standard | up to 512,000 input tokens | $0.30 | $1.20 | $0.06 | not published |
693 | `MiniMax-M3` standard | over 512,000 input tokens | $0.60 | $2.40 | $0.12 | not published |
694 | `MiniMax-M3` priority | up to 512,000 input tokens | $0.45 | $1.80 | $0.09 | not published |
695 | `MiniMax-M3` priority | over 512,000 input tokens | $0.90 | $3.60 | $0.18 | not published |
696 | `MiniMax-M2.7` standard | all supported inputs | $0.30 | $1.20 | $0.06 | $0.375 |
697
698 These values come from the [MiniMax pay-as-you-go pricing
699 guide](https://platform.minimax.io/docs/guides/pricing-paygo). M3 thinking is
700 adaptive or disabled; the OpenAI-compatible API defaults to adaptive and the
701 Anthropic-compatible API defaults to disabled. M2.7 thinking cannot be
702 disabled. Codewhale sends explicit controls when the user selects a reasoning
703 mode.
704
705 Tool-call support is tracked separately by the static `ModelRegistry` and by
706 the endpoint's ability to accept OpenAI-compatible `tools` payloads. A custom
707 OpenAI-compatible or local endpoint can still reject tool calls even if
708 Codewhale can send the schema.
709
710 ### Hugging Face Inference Providers Notes
711
712 The shipped Hugging Face route targets the OpenAI-compatible Inference Providers
713 router at `https://router.huggingface.co/v1`. Configure auth with
714 `HUGGINGFACE_API_KEY` first, or `HF_TOKEN` as a fallback. Configure the endpoint
715 with `HUGGINGFACE_BASE_URL` first, or `HF_BASE_URL` as a fallback; configure the
716 model with `HUGGINGFACE_MODEL` first, or `HF_MODEL` as a fallback.
717
718 This route does not imply Hub browsing, model-card metadata, dataset access,
719 Jobs, uploads, or export. Those remain explicit Model Lab work items so
720 provider auth and artifact movement stay separate.
721
722 ### When a Local Model Prints Tool JSON
723
724 Codewhale only executes tools when the provider returns Chat Completions
725 `tool_calls` or streamed `delta.tool_calls`. If a local model prints text such
726 as `{"name":"File","arguments":{"action":"search_content",...}}` in the
727 assistant message, that is ordinary model output, not an executable tool
728 request.
729
730 For OpenAI-compatible or local runtimes, check:
731
732 - The endpoint accepts the `tools` array in `/v1/chat/completions` requests.
733 - The selected model or chat template is configured for function/tool calls.
734 - The server returns `tool_calls` in the response rather than plain JSON text.
735 - The compatibility layer does not strip tools before forwarding the request.
736 - If in doubt, test a small `File` `read` or `search_content` action against a
737 known tool-calling model before debugging Codewhale's tool registry.
738
739 Changing `provider`, `base_url`, or `model` can select a route that supports the
740 OpenAI-compatible payload shape, but Codewhale cannot convert arbitrary JSON
741 text into a trusted tool call after the model has emitted it as prose.
742
743 DeepSeek will retire `deepseek-chat` and `deepseek-reasoner` on 2026-07-24 at
744 15:59 UTC. Codewhale migrates either name to `deepseek-v4-flash` before a
745 request reaches DeepSeek's first-party OpenAI or Anthropic endpoint. If no
746 reasoning tier was configured, `deepseek-chat` also migrates to `off` and
747 `deepseek-reasoner` to `high`, preserving their former non-thinking / thinking
748 intent; an explicit `reasoning_effort` remains authoritative. The mapping is
749 deliberately not global: Wanjie Ark, aggregators, self-hosted runtimes, and
750 custom endpoints continue to own their model ids.
751
752 ## Reasoning Effort
753
754 `/reasoning <effort>` (and the `reasoning_effort` config key) is translated to
755 each provider's wire dialect by the client before the request is sent. `off`
756 disables thinking where the route supports it. Both exact K3 routes map `off`
757 to their lowest supported tier, `low`, and the model is never switched to
758 satisfy `off` — but they do so for different reasons:
759
760 - **Kimi Code membership K3** (exact `https://api.kimi.com/coding/v1` with bare
761 `model = "k3"`) — the membership roster declares K3 always-thinking, so `off`
762 cannot be honored without changing what the model is. The clamp preserves the
763 fixed K3 identity.
764 - **Direct Moonshot K3** (exact `https://api.moonshot.ai/v1` with
765 `model = "kimi-k3"`) — this clamp is *defensive*, not a documented contract.
766 The direct platform publishes no `off` state for K3, and Codewhale will not
767 assert a fixed-thinking guarantee it cannot verify for a given key's
768 entitlement, so the requested `off` is normalized to the lowest tier with the
769 live entitlement left unknown.
770
771 Normal dispatched
772 `auto` uses Codewhale's auto-reasoning selector and sends a concrete tier;
773 only an omitted reasoning setting leaves the provider default in control.
774 Providers marked "omitted" receive no reasoning fields at all for that tier.
775
776 | Provider | `off` | `low`/`medium`/`high` | `max`/`xhigh` |
777 | --- | --- | --- | --- |
778 | `deepseek`, `deepseek-cn`, `siliconflow`, `siliconflow-CN`, `sglang`, `volcengine`, `atlascloud` | `thinking: {type: disabled}` | `reasoning_effort: "high"` + `thinking: {type: enabled}` | `reasoning_effort: "max"` + `thinking: {type: enabled}` |
779 | `openrouter`, `novita`, other `together` models | `thinking: {type: disabled}` | `reasoning_effort` pass-through + `thinking: {type: enabled}` | `reasoning_effort: "xhigh"` + `thinking: {type: enabled}` |
780 | `together` + `thinkingmachines/inkling` | `reasoning_effort: "none"` | exact `minimal`/`low`/`medium`/`high` `reasoning_effort` | `reasoning_effort: "max"` |
781 | Direct Moonshot `kimi-k3` at exact `https://api.moonshot.ai/v1` | top-level `reasoning_effort: "low"` (effective normalization) | top-level `reasoning_effort: "low"` / `"high"` (`medium` becomes `high`) | top-level `reasoning_effort: "max"` |
782 | Kimi Code membership `k3` at exact `https://api.kimi.com/coding/v1` | `thinking: {type: enabled, effort: "low"}` (effective normalization) | `thinking: {type: enabled, effort: "low" | "high"}` | `thinking: {type: enabled, effort: "max"}` |
783 | Other `moonshot` routes | `thinking: {type: disabled}` | `thinking: {type: enabled}` | `thinking: {type: enabled}` |
784 | `ollama` | `think: false` | `think: true` | `think: true` |
785 | `xiaomi-mimo` | `thinking: {type: disabled}` | `thinking: {type: enabled}` | `thinking: {type: enabled}` |
786 | First-party `minimax` `MiniMax-M3` | `reasoning_split: true` + `thinking: {type: disabled}` | `reasoning_split: true` + `thinking: {type: adaptive}`; effective tier granularity unavailable | `reasoning_split: true` + `thinking: {type: adaptive}`; effective tier granularity unavailable |
787 | First-party Z.ai `GLM-5.2` | `thinking: {type: disabled}`; no `reasoning_effort` | enabled thinking; only effective `high` adds `reasoning_effort: "high"` | enabled thinking + `reasoning_effort: "max"` |
788 | First-party Z.ai `GLM-5.3` | `thinking: {type: disabled}`; no `reasoning_effort` | enabled thinking; only effective `high` adds `reasoning_effort: "high"` | enabled thinking + `reasoning_effort: "max"` |
789 | First-party Z.ai `GLM-5-Turbo` | `thinking: {type: disabled}` | enabled thinking; effort granularity unavailable | enabled thinking; effort granularity unavailable |
790 | Compatible gateways configured as `zai` | omitted; effective unavailable | omitted; effective unavailable | omitted; effective unavailable |
791 | `nvidia-nim` | `chat_template_kwargs.thinking: false` | `chat_template_kwargs`: `thinking: true` + `reasoning_effort: "high"` | `chat_template_kwargs`: `thinking: true` + `reasoning_effort: "max"` |
792 | `vllm` | `chat_template_kwargs.enable_thinking: false` | `chat_template_kwargs.enable_thinking: true` + `reasoning_effort` low/medium/high | `chat_template_kwargs.enable_thinking: true` + `reasoning_effort: "high"` (vLLM has no max tier) |
793 | `arcee`, `huggingface` | omitted | `reasoning_effort` pass-through | `reasoning_effort: "high"` |
794 | `fireworks` | omitted | `reasoning_effort: "high"` | `reasoning_effort: "max"` |
795 | `openai`, `wanjie-ark`, `telecomjs` | omitted | omitted | omitted |
796 | `openmodel` | Anthropic Messages adapter handles thinking/output configuration | Anthropic Messages adapter handles thinking/output configuration | Anthropic Messages adapter handles thinking/output configuration |
797 | `openai-codex` | Responses API `reasoning` field (handled by the Responses bridge) | Responses API `reasoning` field | Responses API `reasoning` field |
798
799 AtlasCloud serves DeepSeek models, so it speaks the DeepSeek reasoning dialect,
800 including the `max` tier (#3024).
801
802 On the exact MiniMax OpenAI-compatible Chat endpoints, `MiniMax-M3` uses
803 `max_completion_tokens`. Other MiniMax models and compatible gateways retain
804 `max_tokens`; the MiniMax Anthropic endpoints use the separate Messages
805 adapter.
806
807 ## Drift Check
808
809 Run this before changing provider IDs, provider TOML tables, static model
810 registry rows, or provider default strings:
811
812 ```bash
813 python3 scripts/check-provider-registry.py
814 ```
815
816 The check fails when:
817
818 - `docs/PROVIDERS.md` omits a canonical `ProviderKind::as_str()` ID.
819 - `crates/tui/src/config.rs` `ApiProvider::as_str()` diverges from
820 `ProviderKind::as_str()` except for the explicit `deepseek-cn` legacy alias.
821 - The shipped-provider table omits or adds a `[providers.*]` TOML table.
822 - The static model registry table drifts from providers used by
823 `crates/agent/src/lib.rs`.
824 - A provider default model or base URL constant in `crates/tui/src/config.rs`
825 is no longer mentioned here.
826
827 ## Planned, Not Shipped Yet
828
829 These items belong to the v0.8.48+ provider-abstraction milestone or related
830 provider docs work, but they are not native shipped behavior in this checkout:
831
832 - A unified `Provider` trait in `codewhale-agent` that owns env precedence,
833 secret resolution, base URL normalization, auth-header construction, and
834 provider metadata. Those responsibilities are still split across
835 `crates/config`, `crates/secrets`, and `crates/tui/src/client.rs`.
836 - Hugging Face model passport metadata in the picker, including license, base
837 model, context length, chat template, tool-call support, reasoning support,
838 and gated/private status.
839
839 lines MARKDOWN