fix(openrouter): profile moonshotai/kimi-k3 with truthful max_tokens and reasoning effort - #1325
Conversation
…and reasoning effort
OpenRouter reports max_completion_tokens: null for moonshotai/kimi-k3, so the generic fallback fabricated max_tokens = ceil(context_length * 0.2) (209,716 for a 1M window), and no reasoning effort was ever populated so the reasoning field was dropped from requests. Long turns then burned the upstream 32,768-token output cap on invisible thinking billed as completion tokens.
Add a Moonshot K3 capability profile (maxTokens 32768, supportsReasoningEffort [low, high, max] with model default high, supportsTemperature false) applied in parseOpenRouterModel at fetch time and re-applied in OpenRouterHandler.getModel() at consumption time, so users with stale cached model info are fixed without a re-fetch. The default request body becomes {max_tokens: 32768, reasoning: {effort: high}} with temperature omitted (K3 is fixed at 1.0 server-side).
Adds parse-time, stale-cache, and createMessage wire tests, plus shouldUseReasoningEffort cases for array capability with a model default effort.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
Included review availability: Your plan provides up to 4 included reviews per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe OpenRouter fetcher adds a Moonshot K3 profile for ChangesMoonshot K3 OpenRouter support
Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to The change applies truthful Kimi K3 token and reasoning defaults through both fetch and cached-model paths, with focused automated coverage; no actionable merge-blocking risk remains beyond normal checks and review. Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant OpenRouterHandler
participant ModelCache
participant applyOpenRouterMoonshotK3Profile
participant applyRouterToolPreferences
participant OpenRouterRequest
OpenRouterHandler->>ModelCache: resolve model info
ModelCache-->>OpenRouterHandler: cached model record
OpenRouterHandler->>applyOpenRouterMoonshotK3Profile: reapply K3 profile
applyOpenRouterMoonshotK3Profile-->>OpenRouterHandler: corrected model info
OpenRouterHandler->>applyRouterToolPreferences: apply tool preferences
applyRouterToolPreferences-->>OpenRouterHandler: request-ready model info
OpenRouterHandler->>OpenRouterRequest: send max_tokens and reasoning effort
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Related GitHub Issue
Closes: #1316
Description
OpenRouter reports
max_completion_tokens: nullformoonshotai/kimi-k3, so the generic fallback fabricatedmax_tokens = ceil(context_length * 0.2)(209,716 for a 1M context window), and since no reasoning effort was ever populated for non-Anthropic ids, thereasoningfield was dropped from every request. Long turns then burned the upstream 32,768-token output cap on invisible thinking (measured: 507 s / 309 s turns, hidden reasoning billed as completion tokens).This fix adds a Moonshot K3 capability profile:
applied in two places:
parseOpenRouterModel()returns its result through the exportedapplyOpenRouterMoonshotK3Profile()(id-list based, matching the existing per-model override pattern in the same file),OpenRouterHandler.getModel()re-applies the profile to the resolved record, because parsed records are persisted in the model cache and records cached before this profile existed still carry the fabricated value. This also covers theopenRouterSpecificProviderendpoint path, which flows through the samegetModel().Result: a default Kimi K3 request now carries
{"max_tokens": 32768, "reasoning": {"effort": "high"}}with notemperaturekey (K3 is documented fixed at 1.0; omitting the field lets the server default apply, same pattern as the Claude 4.5/5 overrides). The generic 0.2 fallback and all existing model overrides are untouched.Notes:
moonshotai/kimi-latestis included in the id set as a forward-compatible alias — it is not currently listed in the live OpenRouter catalogue (verified againstopenrouter.ai/api/v1/models), so the entry is inert until/if OpenRouter lists it.src/shared/api.tsorModelInfotype changes were needed: the array-capability + model-default-effort logic inshouldUseReasoningEffortand thereasoningEffortfield already exist.finish_reason: "length"handling inNativeToolCallParsernoted in the issue was left untouched (never observed firing; out of scope per the issue).Test Procedure
Manual verification would additionally require a live OpenRouter key + Moonshot model access; the wire test asserts the exact outgoing request shape.
Pre-Submission Checklist
Get in Touch
easonLiangWorldedtech
Summary by CodeRabbit
New Features
Bug Fixes