Context
Our curated BYOK catalog already offers a "Kimi Code Plan" variant (curated-models.json, baseURL https://api.kimi.com/coding/v1, maxConcurrentRequests: 30) routed through the openai_compatible provider. This variant is broken in production: Moonshot gates the coding plan's OpenAI-compatible endpoint (/chat/completions) behind a User-Agent whitelist of approved coding agents.
Empirically validated with a real coding-plan key (2026-06-03):
| Test |
Result |
POST /coding/v1/chat/completions with openai-node / LangChain / curl UA |
403 access_terminated_error ("only available for Coding Agents such as Kimi CLI, Claude Code, Roo Code, Kilo Code...") |
Same request with whitelisted UA (claude-code/2.0.0) |
200 |
GET /coding/v1/models (any UA) |
200 — not gated → our BYOK connection test passes, then every review 403s |
POST /coding/v1/messages (Anthropic-compatible surface, generic UA) |
200 — no UA gate, full tool calling + streaming work |
The Anthropic-compatible surface is the officially documented path for non-whitelisted clients — Moonshot's docs state "no whitelist approval needed, and it works with more clients" (third-party tools docs). No UA spoofing involved.
Both of our SDK paths were validated end-to-end against the coding endpoint:
- Vercel AI SDK
createAnthropic({ baseURL: 'https://api.kimi.com/coding/v1' }) → tool calling OK
- LangChain
ChatAnthropic({ anthropicApiUrl: 'https://api.kimi.com/coding' }) → OK (note: each SDK wants a different baseURL shape — Vercel includes /v1, LangChain does not)
Coding-plan facts:
- Keys are not interchangeable with the Developer API (
api.moonshot.ai) — separate consoles, separate billing
- Canonical model ID is
kimi-for-coding (auto-upgrading alias); kimi-k2.6, kimi-code, k2p5 are accepted and normalized, so the curated kimi-k2.6 id keeps working
- Responses always include
reasoning_content; json_schema response format and tool calling are supported
- Plan limits: ~30 concurrent requests, quota windows (5h/weekly)
Proposal
Route the Kimi Code Plan variant through an Anthropic-style client with a custom base URL instead of openai_compatible.
Backend
Frontend
Docs
ToS considerations (why this approach)
- OpenAI endpoint + UA spoofing was rejected: Moonshot's guidelines explicitly forbid client-identifier tampering and the customer's membership takes the suspension risk
- The Anthropic surface is the documented no-whitelist path, so there is no protocol-level violation; the remaining gray zone is the "personal interactive use only" clause for automated server-side review — the key is the customer's own (BYOK, no resale), so this is surfaced via UI disclaimer rather than blocked
- In parallel, it may be worth reaching out to Moonshot (support@moonshot.cn) about an official agent partnership/whitelist (how Roo Code / Kilo Code were added); there is no public self-service process
Context
Our curated BYOK catalog already offers a "Kimi Code Plan" variant (
curated-models.json, baseURLhttps://api.kimi.com/coding/v1,maxConcurrentRequests: 30) routed through theopenai_compatibleprovider. This variant is broken in production: Moonshot gates the coding plan's OpenAI-compatible endpoint (/chat/completions) behind a User-Agent whitelist of approved coding agents.Empirically validated with a real coding-plan key (2026-06-03):
POST /coding/v1/chat/completionswith openai-node / LangChain / curl UAaccess_terminated_error("only available for Coding Agents such as Kimi CLI, Claude Code, Roo Code, Kilo Code...")claude-code/2.0.0)GET /coding/v1/models(any UA)POST /coding/v1/messages(Anthropic-compatible surface, generic UA)The Anthropic-compatible surface is the officially documented path for non-whitelisted clients — Moonshot's docs state "no whitelist approval needed, and it works with more clients" (third-party tools docs). No UA spoofing involved.
Both of our SDK paths were validated end-to-end against the coding endpoint:
createAnthropic({ baseURL: 'https://api.kimi.com/coding/v1' })→ tool calling OKChatAnthropic({ anthropicApiUrl: 'https://api.kimi.com/coding' })→ OK (note: each SDK wants a different baseURL shape — Vercel includes/v1, LangChain does not)Coding-plan facts:
api.moonshot.ai) — separate consoles, separate billingkimi-for-coding(auto-upgrading alias);kimi-k2.6,kimi-code,k2p5are accepted and normalized, so the curatedkimi-k2.6id keeps workingreasoning_content;json_schemaresponse format and tool calling are supportedProposal
Route the Kimi Code Plan variant through an Anthropic-style client with a custom base URL instead of
openai_compatible.Backend
baseURLsupport to the Anthropic provider path (today hardcoded toapi.anthropic.com), or introduce ananthropic_compatibleBYOK provider:packages/kodus-common/src/llm/providerAdapters/anthropicAdapter.ts(LangChain — passanthropicApiUrl, no/v1suffix)libs/code-review/infrastructure/agents/llm/byok-to-vercel.ts(Vercel —createAnthropic({ baseURL }), with/v1suffix)test-byok-connection.use-case.tsfor this provider: probe the real/v1/messagesendpoint (a minimal 1-token request) instead of/v1/models, which is ungated and currently yields a false-positive "connection OK" followed by 403s on every reviewmaxConcurrentRequests(30) flowing through the existing BYOK concurrency gateFrontend
kimi-codevariant inapps/web/src/features/ee/byok/_data/curated-models.jsonto the Anthropic-compatible provider + correct baseURLDocs
docs.kodus.ioMoonshot guide with the two plans, key sources, and the guideline caveatToS considerations (why this approach)