Skip to content

fix(openrouter): profile moonshotai/kimi-k3 with truthful max_tokens and reasoning effort - #1325

Open
easonLiangWorldedtech wants to merge 1 commit into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:fix/issue-1316-openrouter-kimi-k3
Open

fix(openrouter): profile moonshotai/kimi-k3 with truthful max_tokens and reasoning effort#1325
easonLiangWorldedtech wants to merge 1 commit into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:fix/issue-1316-openrouter-kimi-k3

Conversation

@easonLiangWorldedtech

@easonLiangWorldedtech easonLiangWorldedtech commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Related GitHub Issue

Closes: #1316

Description

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 context window), and since no reasoning effort was ever populated for non-Anthropic ids, the reasoning field 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:

const MOONSHOT_K3_OPENROUTER_PROFILE: Partial<ModelInfo> = {
	maxTokens: 32_768,
	supportsReasoningEffort: ["low", "high", "max"],
	reasoningEffort: "high",
	supportsTemperature: false,
}

applied in two places:

  • Fetch timeparseOpenRouterModel() returns its result through the exported applyOpenRouterMoonshotK3Profile() (id-list based, matching the existing per-model override pattern in the same file),
  • Consumption timeOpenRouterHandler.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 the openRouterSpecificProvider endpoint path, which flows through the same getModel().

Result: a default Kimi K3 request now carries {"max_tokens": 32768, "reasoning": {"effort": "high"}} with no temperature key (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-latest is included in the id set as a forward-compatible alias — it is not currently listed in the live OpenRouter catalogue (verified against openrouter.ai/api/v1/models), so the entry is inert until/if OpenRouter lists it.
  • No src/shared/api.ts or ModelInfo type changes were needed: the array-capability + model-default-effort logic in shouldUseReasoningEffort and the reasoningEffort field already exist.
  • The latent finish_reason: "length" handling in NativeToolCallParser noted in the issue was left untouched (never observed firing; out of scope per the issue).

Test Procedure

cd src
pnpm exec vitest run api/providers/fetchers/__tests__/openrouter.spec.ts api/providers/__tests__/openrouter.spec.ts shared/__tests__/api.spec.ts
# 83/83 passing, incl. 8 new tests:
# - parse-time profile for moonshotai/kimi-k3 and moonshotai/kimi-latest (maxTokens 32768, ladder, default effort, temperature off)
# - applyOpenRouterMoonshotK3Profile: stale-cache override, input non-mutation, pass-through for other models
# - OpenRouterHandler.fetchModel: stale cached record (209716 / boolean flag) corrected at consumption time
# - OpenRouterHandler.createMessage wire test: outgoing body has max_tokens 32768, reasoning {effort: "high"}, no temperature
# - shouldUseReasoningEffort: array capability + model default with no settings -> true; enableReasoningEffort: false still wins
pnpm exec eslint --prune-suppressions --max-warnings=0 api/providers/fetchers/openrouter.ts api/providers/openrouter.ts api/providers/fetchers/__tests__/openrouter.spec.ts api/providers/__tests__/openrouter.spec.ts shared/__tests__/api.spec.ts   # clean, no suppression count changes
pnpm check-types   # 11/11 packages passing

Manual verification would additionally require a live OpenRouter key + Moonshot model access; the wire test asserts the exact outgoing request shape.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes (see "Test Procedure").
  • Visual Snapshot (UI changes only): N/A — no UI changes.
  • Documentation Impact: No documentation updates are required.
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Get in Touch

easonLiangWorldedtech

Summary by CodeRabbit

  • New Features

    • Added support for Moonshot K3 and Kimi Latest models.
    • Configured a 32,768-token limit and low, high, and max reasoning-effort options, with high selected by default.
    • Disabled temperature controls for these models.
    • Updated cached model information to use the corrected settings.
  • Bug Fixes

    • Improved validation of reasoning-effort defaults and disabled reasoning settings.

…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.
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4570e1d8-dc88-43da-88b1-eb7a5c9fed1a

📥 Commits

Reviewing files that changed from the base of the PR and between 871bb98 and 0b38812.

📒 Files selected for processing (5)
  • src/api/providers/__tests__/openrouter.spec.ts
  • src/api/providers/fetchers/__tests__/openrouter.spec.ts
  • src/api/providers/fetchers/openrouter.ts
  • src/api/providers/openrouter.ts
  • src/shared/__tests__/api.spec.ts

Included review availability: Your plan provides up to 4 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The OpenRouter fetcher adds a Moonshot K3 profile for moonshotai/kimi-k3 and moonshotai/kimi-latest. Parsed and cached records now use a 32,768-token limit, default high reasoning effort, supported effort values, and disabled temperature support.

Changes

Moonshot K3 OpenRouter support

Layer / File(s) Summary
Profile and reasoning capability contract
src/api/providers/fetchers/openrouter.ts, src/api/providers/fetchers/__tests__/openrouter.spec.ts, src/shared/__tests__/api.spec.ts
The fetcher applies the Moonshot K3 profile during parsing. Tests cover both model IDs, profile immutability, unrelated models, and array-based reasoning-effort settings.
Cached model request flow
src/api/providers/openrouter.ts, src/api/providers/__tests__/openrouter.spec.ts
OpenRouterHandler reapplies the profile to cached records before tool preferences. Tests verify corrected model data and requests with max_tokens: 32768, high reasoning effort, and no temperature.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 0b388

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: edelauna

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
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy issue #1316 by correcting max_tokens, enabling default reasoning effort, and honoring Kimi K3 fixed-temperature behavior.
Out of Scope Changes check ✅ Passed All code and test changes support the linked Kimi K3 OpenRouter fix, including stale-cache handling and reasoning-effort coverage.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 5 files.
Title check ✅ Passed The title clearly and concisely identifies the OpenRouter Kimi K3 profile fix and its key capability changes.
Description check ✅ Passed The description includes the linked issue, implementation details, test procedure, checklist, scope notes, and documentation assessment.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-review PR changes are ready and waiting for maintainer re-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] OpenRouter + Kimi K3: requests sent with no reasoning effort and fabricated max_tokens=209,716 → multi-minute invisible-thinking turns

2 participants