Skip to content

feat(registry): register Kimi k3[1m] 1M-context model as built-in#4404

Open
Bahamutnelson wants to merge 2 commits into
router-for-me:devfrom
Bahamutnelson:feat/kimi-k3-1m
Open

feat(registry): register Kimi k3[1m] 1M-context model as built-in#4404
Bahamutnelson wants to merge 2 commits into
router-for-me:devfrom
Bahamutnelson:feat/kimi-k3-1m

Conversation

@Bahamutnelson

@Bahamutnelson Bahamutnelson commented Jul 17, 2026

Copy link
Copy Markdown

Summary

Kimi K3 has a dedicated 1M-context variant with its own model ID: k3[1m]. It is documented in the official Kimi Code docs (Using in Other Coding Agents): plans Allegretto and above can use k3[1m] with a 1,048,576-token context window, while plain k3 / kimi-k3 is limited to 262,144 tokens.

The proxy currently rejects requests for it:

POST /v1/messages {"model":"k3[1m]",...}
→ 502 {"type":"error","error":{"type":"api_error","message":"unknown provider for model k3[1m]"}}

Root cause

Model → provider resolution does an exact-name lookup in the model registry (util.GetProviderName). The kimi catalog is seeded from the embedded internal/registry/models/models.json and then wholesale replaced by the remote catalog (router-for-me/models) at startup and on every periodic refresh. Neither contains k3[1m], so the name is unregistered. Adding it to models.json alone would not be durable — the next remote refresh would silently drop it again.

The fix

Follows the existing WithCodexBuiltins / WithXAIBuiltins pattern: a new WithKimiBuiltins() helper injects a hard-coded k3[1m] definition inside GetKimiModels(), so the registration survives remote catalog refreshes.

Metadata mirrors kimi-k3: context_length 1048576, max_completion_tokens 65536, thinking levels low/high/max.

The [/] characters are safe end-to-end: thinking-suffix parsing only handles (...), the registry does verbatim name lookups, and the kimi executor forwards the model name in the JSON request body (never in a URL path).

Verification (tested live, works)

  • Upstream accepts the ID: direct calls to https://api.kimi.com/coding/v1/messages with a Kimi Code OAuth token returned HTTP 200 for k3, k3[1m], and kimi-k3 alike (2026-07-17, account with 1M-tier plan).
  • Through a patched proxy instance: POST /v1/messages {"model":"k3[1m]","max_tokens":1,...} → HTTP 200, response "model":"k3[1m]"; regression check kimi-k3 → HTTP 200; thinking suffix form k3[1m](high) → HTTP 200.
  • End-to-end 1M proof: a 272,006-token request (input_tokens as reported by the API) through the patched proxy to k3[1m] returned HTTP 200 — above the 262,144 limit of the plain k3 variant, confirming the 1M window is actually served on a 1M-tier account.
  • Alias integration: oauth-model-alias entries attach cleanly to the builtin name — with a local entry kimi: [{name: "k3[1m]", alias: <custom-alias>, fork: true}], a request to the alias was routed to the kimi credential and answered HTTP 200 with "model":"k3[1m]" (before the patch, aliasing this name failed with unknown provider).
  • GET /v1/models on the patched instance lists k3[1m] alongside the existing kimi models, including after the remote catalog refresh that runs at startup.
  • go vet ./internal/registry/, go test ./internal/registry/ ./internal/thinking/..., go build ./... all green (go1.26.0). Tests added for the builtin's metadata and its inclusion in GetKimiModels().

Notes

  • Complements fix(registry): sync embedded Kimi K3 catalog #4378 (which syncs the embedded kimi-k3 definition but does not add k3[1m]).
  • The durable fix on the catalog side would be adding k3[1m] to the router-for-me/models repo too; this builtin keeps this repo correct regardless.

The upstream Kimi Code API accepts the model name k3[1m] (the 1M-context
variant of Kimi K3), but the proxy rejected it with
"unknown provider for model k3[1m]" because the model is not present in
either the embedded models.json catalog or the remote catalog fetched
from router-for-me/models.

Follow the existing WithCodexBuiltins/WithXAIBuiltins pattern: inject a
hard-coded Kimi built-in via a new WithKimiBuiltins helper applied in
GetKimiModels, so the definition survives remote catalog refreshes.

Metadata mirrors kimi-k3: 1048576 context length, 65536 max completion
tokens, thinking levels low/high/max.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@github-actions
github-actions Bot changed the base branch from main to dev July 17, 2026 20:03
@github-actions

Copy link
Copy Markdown

This pull request targeted main.

The base branch has been automatically changed to dev.

@Bahamutnelson
Bahamutnelson marked this pull request as ready for review July 17, 2026 20:11
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 574541e3a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

ContextLength: 1048576,
MaxCompletionTokens: 65536,
Thinking: &ThinkingSupport{
Levels: []string{"low", "high", "max"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Map Claude medium/xhigh efforts for K3

With k3[1m] exposed through the Claude-compatible Kimi path, Claude Code requests that set /effort medium or /effort xhigh will be parsed as unsupported levels and then clamped by ValidateConfig to the nearest lower supported value from this list (mediumlow, xhighhigh). Kimi’s K3 Claude Code guidance maps those same efforts upward (mediumhigh, xhighmax; see https://www.kimi.com/code/docs/third-party-tools/other-coding-agents.html), so users selecting those efforts get a weaker reasoning mode than requested unless this builtin is accompanied by Kimi-specific effort mapping/clamping.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 7baf4e9.

ThinkingSupport gains a declarative LevelMapping field, resolved before level validation (strict same-family paths map instead of erroring) and inside clampLevel (covering budget-derived and auto-derived levels). The k3[1m] built-in now declares medium -> high and xhigh -> max per Kimi's K3 guidance, so Claude Code users get the requested reasoning mode instead of a silent downgrade.

Covered by TestKimiK31MClaudeEffortMapsUpward (medium→high, xhigh→max, low/high/max unchanged), TestKimiK31MClaudeBudgetMapsUpward (budget 8192 → medium → high) and TestKimiK31MNativeStrictPathMapsInsteadOfError.

Claude Code requests with effort "medium" or "xhigh" were clamped down
to "low"/"high" for k3[1m]: the nearest-level clamp prefers the lower
level on ties, while Kimi's K3 guidance maps those same efforts upward
(medium -> high, xhigh -> max).

Add a declarative LevelMapping field to ThinkingSupport, resolved before
level validation (so strict same-family paths map instead of erroring)
and inside clampLevel (covering budget-derived and auto-derived levels).
Declare the K3 mapping on the k3[1m] built-in.

Addresses PR router-for-me#4404 review feedback.
@Bahamutnelson

Copy link
Copy Markdown
Author

Client compatibility note (Claude Code users): recent Claude Code versions natively parse the model[1m] suffix for their own 1M-context feature and strip it before sending — claude --model "k3[1m]" reaches the proxy as plain k3, which is unregistered (the remote catalog only serves kimi-k3). This PR registers k3[1m] for clients that can send the ID verbatim; Claude Code users additionally need an alias so the stripped name routes to the 1M variant:

oauth-model-alias:
  kimi:
    - name: "k3[1m]"
      alias: "k3"
      fork: true

Verified locally: with this alias, k3, k3[1m] and the alias all return HTTP 200 with "model":"k3[1m]" upstream. The [/] characters themselves remain safe throughout the proxy — the stripping happens client-side, before the request is sent.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7baf4e9cb0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +165 to +166
Thinking: &ThinkingSupport{
Levels: []string{"low", "high", "max"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Emit K3 effort as reasoning_effort

For OpenAI/chat-completions requests routed to Kimi (i.e. not the Claude /v1/messages delegation), adding Thinking here makes ApplyThinking consume a client reasoning_effort and the existing Kimi applier then delete it and emit the K2.x-shaped thinking.effort. Kimi Code documents K3 effort as top-level reasoning_effort: low/high/max (https://www.kimi.com/code/docs/en/kimi-code/models), so a request like {"model":"k3[1m]","reasoning_effort":"low"} is forwarded with the wrong field shape and can be rejected or ignored instead of selecting low effort; K3 needs a model-specific Kimi output path.

Useful? React with 👍 / 👎.

Comment on lines +171 to +174
LevelMapping: map[string]string{
"medium": "high",
"xhigh": "max",
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Map all documented K3 effort aliases

Kimi Code's K3 mapping table also accepts ultra as max and minimum/light as low (https://www.kimi.com/code/docs/en/kimi-code/models). Because this map only adds medium and xhigh, requests from OpenAI/Kimi-compatible clients that send reasoning_effort:"ultra" or thinking.effort:"light" reach ValidateConfig as unsupported levels; clampLevel cannot clamp unknown labels, so the proxy returns a validation error instead of forwarding the documented K3 effort.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant