feat: add Kimi K3 and K2.7 high-speed support#2243
Conversation
- Add kimi-k3 (1M context) and kimi-k2.7-code-highspeed (256k) to Kimi provider catalogue - Route selected IDs to upstream Kimi Code IDs with correct context windows - Support global (api.moonshot.ai) and China (api.moonshot.cn) regions with env overrides - Update registry, frontend family/display logic, and unit tests
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b8413b56db
ℹ️ 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".
- Use region-specific upstream model ID for K2.7 (global → kimi-k2.7-code, china → kimi-for-coding) - Honor KIMI_REGION env when probing models in getModels() - Reject OpenAI-compatible /v1 base URL overrides in buildSdkConfig - Route moonshot-k3 alias to K3 fixed ID - Update unit tests for new region-aware behavior
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6b83e7fd8
ℹ️ 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".
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1 (GLM)
Model: glm-5.1 | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: REQUEST_CHANGES — 2 P3 nits remain. All substantive findings (incl. the 4 Codex findings) are resolved.
Verified ✅
- Routing is correct.
ProviderContextManager.getSdkModelId()(context-manager.ts:36) returnsANTHROPIC_MODELfirst, so the upstream Kimi Code IDs win: K3→k3, highspeed→kimi-k2.7-code-highspeed, K2.7 region-aware (global→kimi-k2.7-code, china→kimi-for-coding).translateModelIdForSdkis only a dead-path fallback. - All 4 Codex findings fixed in
e6b83e7(global K2.7 region routing,getModelsKIMI_REGIONprobe,/v1URL rejection,moonshot-k3alias) with matching tests. - Static metadata auto-included:
STATIC_MODEL_METADATAspreadsKimiProvider.MODELS(model-service.ts:121), so the new entries need no manual addition. Frontend family/logo/labels all handle the new IDs. - Tests pass locally: kimi-provider 60/0, model-service-provider-routing 32/0, web useModelSwitcher+session-utils 80/80.
- CI red is pre-existing, not from this PR:
Daemon Unit Tests (1-core)(Logger console-suppression flakiness — passes locally, zero kimi failures) andDaemon Online (rpc-4)(Dev Proxy won't start in CI) fail identically on the priordevrun 29557054640.
P3 findings (cleanup, not correctness)
P3-1 — Dead branch in resolveUpstreamModelId (packages/daemon/src/lib/providers/kimi-provider.ts:361-368)
The K2.7-alias if and the final fallback both return the same value, so the condition is dead:
if (id === 'kimi-k2.7-code' || id === 'kimi' || id === 'kimi-for-coding' || id.startsWith('moonshot-'))
return KimiProvider.getModelIdForRegion(region);
return KimiProvider.getModelIdForRegion(region); // identicalFix: collapse to a single return KimiProvider.getModelIdForRegion(region); (keep the doc comment above).
P3-2 — Family detection misses bare k3 (packages/web/src/hooks/useModelSwitcher.ts:116)
inferProviderFromModelId was updated to treat k3 as kimi (~line 216), but the family-detection branch was not. A session saved as bare k3 resolves provider kimi but family sonnet (wrong icon/grouping). Fix: add || mid === 'k3' to the kimi family condition.
For QA (online verification — not a code blocker)
The task flags K3's reasoning_effort="max" and "omit temperature/top_p/n/penalties"; none are set in code. Almost certainly fine — NeoKai uses the Anthropic-compatible Kimi Code endpoint (not the OpenAI /v1 endpoint that uses reasoning_effort), and existing always-on-thinking Kimi models already work with the SDK's thinking config. Please confirm K3 returns responses correctly for both regions during browser/online QA.
- Resolve K3 aliases to the upstream fixed ID 'kimi-k3' instead of 'k3'. - Force thinking enabled for 'kimi-k2.7-code-highspeed' when the effective thinking level is off so the upstream request succeeds. - Point the China region Anthropic-compatible endpoint to https://api.moonshot.cn/anthropic. - Honor KIMI_BASE_URL when probing credentials in getModels(). - Update unit tests for the new China endpoint, K3 upstream ID, base URL override, and highspeed thinking override.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b31d5b0d4a
ℹ️ 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".
- Probe Kimi credentials with 'kimi-k3' in getModels() so the health check avoids the K2.7 'invalid thinking' requirement. - Force thinking enabled for all Kimi K2.7 models (including aliases) when the effective thinking level is off; keep K3 and moonshot-k3 prefixes exempt. - Treat any ID starting with 'moonshot-k3' as K3 before the generic moonshot-2.7 fallback in canonicalizeModelId and resolveUpstreamModelId. - Update unit tests for probe model, regular K2.7 thinking override, and moonshot-k3 prefix routing.
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by GLM-5.1 (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM
Recommendation: APPROVE — zero confirmed code findings on fd8c580.
All findings across three review rounds are addressed and covered by tests:
- K3 upstream ID (P1):
resolveUpstreamModelIdreturnskimi-k3fork3/kimi-k3/moonshot-k3*;ANTHROPIC_MODELand all tier env vars carrykimi-k3. - moonshot-k3 prefix (P2):
canonicalizeModelId+resolveUpstreamModelIdnow usestartsWith('moonshot-k3'), matching the prefix matcher inmodel-service.ts:571, somoonshot-k3-*aliases both resolve and route as K3 (test coversmoonshot-k3-preview). - KIMI_BASE_URL in probe (P2):
getModels()honorsKIMI_BASE_URL || regionBaseUrlfor credential verification. - China endpoint (P2): china
anthropicBaseUrl=api.moonshot.cn/anthropic, matching current Kimi docs. - No-thinking-safe probe (P2): probes with
kimi-k3. - Highspeed thinking (P2): forces
thinking:{enabled, 16000}when the level would otherwise be off.
Routing verified end-to-end: getSdkModelId() returns ANTHROPIC_MODEL (upstream fixed ID) over translateModelIdForSdk; /v1 OpenAI-style base URLs are rejected in buildSdkConfig; frontend (inferProviderFromModelId, family detection, getModelLabel) resolves k3/kimi-k3/highspeed correctly.
Tests (local, fd8c580): kimi-provider + query-options-builder 231 pass / 0 fail; model-service routing 113 pass (4 initializeModels timeouts = pre-existing @github/copilot/sdk module-load); web useModelSwitcher + session-utils 80 pass / 0 fail.
CI: the red jobs — Daemon Unit Tests (1-core) (only logger.test.ts console-mock failures), Daemon Online (rpc-4) Model-RPC-Handlers, and All Tests Pass (aggregate) — reproduce on dev and are not regressions from this PR.
Deferred to QA (empirical, non-blocking): the thinking override now force-enables thinking on all non-K3 Kimi models. dev shipped regular K2.7 (kimi-for-coding, thinkingModes:'on') with no forcing, suggesting regular K2.7 does not require thinking. Please online-verify on both regions that (1) the credential probe succeeds and (2) a regular K2.7 session runs with thinking off. If K2.7 works without thinking, a follow-up could narrow the override to highspeed-only — the current force-all is a safe conservative default but overrides the user's thinking-off preference and adds token cost for regular K2.7.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd8c580dea
ℹ️ 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".
🤖 Review by GLM-5.1 (GLM)
Recommendation: APPROVE (maintained) on base-URL → region decoupling ( Title-generation thinking ( The question code review cannot settle — whether regular K2.7 or the global endpoint actually rejects no-thinking / |
|
Thanks for the review. Both points were addressed in the follow-up commit
The force-thinking override for non-K3 Kimi sessions remains conservative/safe; happy to adjust once online QA smoke-tests confirm the exact K2.7 behavior on both regions. |
🤖 Review by glm-5.1[1m] (GLM)
@codex review — re-triggering on the latest head |
|
Latest head is |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: caa39a5ad6
ℹ️ 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".
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: REQUEST_CHANGES — this supersedes my earlier APPROVE. Codex's round-5 review on caa39a5ad raised findings I independently verified (including fetching Kimi's official docs), so I'm holding approval until they're addressed.
Codex posted 3 findings (its labels: 2×P1, 1×P2). After independent triage I'm adopting all three (one downgraded). None are dismissable as unverified-premise:
P1 — getModels() throws on any probe failure, hiding the whole catalog (line 337)
getModels() runs await this.verifyCredentials(baseUrl, apiKey, 'kimi-k3') with no try/catch, then returns the static MODELS. Any probe failure — a key without K3 access (Kimi gates K3 to higher tiers while K2.7 is the standard model), a transient network blip, or a rate-limit — makes models.list / providers.test throw, so Kimi shows zero models and marks itself unhealthy. This is a robustness defect independent of the K3-tier question: a single-model probe should never hide the statically-known catalog. Recommend wrapping the probe in try/catch and still returning MODELS on failure (surface the failure via auth status instead), and/or verifying K3 is available to all Kimi key tiers.
P2 — China K2.7 routes to kimi-for-coding, but official docs document kimi-k2.7-code (line 78)
KIMI_REGION_ENDPOINTS.china.modelId = 'kimi-for-coding'. Kimi's official Claude Code guide for https://api.moonshot.cn/anthropic documents ANTHROPIC_MODEL=kimi-k2.7-code with CLAUDE_CODE_AUTO_COMPACT_WINDOW=262144: https://platform.kimi.com/docs/guide/claude-code-kimi . kimi-for-coding is the legacy alias and likely still accepted, but aligning China to kimi-k2.7-code (matching both the docs and the global endpoint) removes deprecation risk. Recommend china.modelId = 'kimi-k2.7-code', keeping kimi-for-coding as a legacy alias only.
P2 — K3's 1M CLAUDE_CODE_AUTO_COMPACT_WINDOW may be clamped by the SDK (line 456)
For K3 the env var is set to 1,048,576, but the SDK sees the unknown kimi-k3 ID and (per buildProviderSettings) clamps unknown-model context windows to its ~200k fallback, so K3 sessions would auto-compact around ~167k instead of using the advertised 1M. Please verify the window actually takes effect (e.g. /status on a live K3 session); if clamped, document the limitation or apply a workaround so the 1M window is usable.
These need live upstream/SDK confirmation, which is exactly why they should be resolved (or empirically dismissed) before merge rather than discovered in QA. Happy to re-approve once addressed.
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: APPROVE. All three round-5 findings are resolved in 4ecb23630 — verified against the source and 234 pass / 0 fail on kimi-provider.test.ts + query-options-builder.test.ts:
- Probe model (was P1) —
getModels()now probes the region's K2.7 model (kimi-k2.7-code) with a minimalthinkingpayload instead ofkimi-k3. K2.7 is available to all members, so standard keys without K3 access pass the health check. Thethinkingfield is threaded throughverifyCredentials→probeAnthropicCompatCredentials. The throw-on-failure behavior is intentional shared auth-validation design (per thecredential-probe.tsheader), not a PR-introduced defect. - China model ID (was P2) —
china.modelIdis nowkimi-k2.7-code, matching Kimi's official Claude Code guide forapi.moonshot.cn/anthropicand the global endpoint; all K2.7 sessions now send the documented upstream ID. - K3 1M window (was P2) — accepted as an SDK-side limitation (unknown model IDs are clamped to ~200k); the env var is kept at 1M and
preferContextWindowMetadata: truepreserves correct provider metadata. Reasonable disposition.
One non-blocking item for QA online smoke-test: the thinking-enabled probe (budget_tokens: 16000, 5s timeout) should be confirmed to return healthy promptly — minimal risk, but worth a live check since thinking adds latency.
CI failures on this head (1-core logger, rpc-4 no-provider) are pre-existing on dev and unrelated to this PR. Ready to hand off to QA.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4ecb236302
ℹ️ 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".
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: APPROVE
Head 9f191d6ae resolves all three Codex round-6 findings raised on 4ecb23630. Verified independently against the code and Kimi's thinking docs (https://platform.kimi.ai/docs/guide/use-kimi-k2-thinking-model):
-
Probe
max_tokensvs thinking budget —credential-probe.ts:88now setsmax_tokens = thinking.budget_tokens + 1(16001 > 16000), satisfying Anthropic's hardmax_tokens > budget_tokensconstraint for extended-thinking requests. The K2.7 health probe no longer 400s. -
Default K3 sessions with thinking off —
query-options-builder.ts:766-777catches K3 +thinking:{type:'disabled'}and omits the field entirely (thinkingConfig = undefined). Per Kimi docs, K3 has nothinking.typeparameter (always-reasoning via top-levelreasoning_effort), so omitting is correct. -
K3 on title/workflow paths — new
KimiProvider.resolveKimiTitleThinkingConfig()(returnsundefinedfor K3,{type:'disabled'}otherwise) is wired into all four one-turn helpers:generateTitleWithSdk,evolution-conversation-analysis-service,evolution-episode-service,llm-workflow-selector. Auto-title and workflow selection no longer senddisabledto K3.
Scope: surgical (9 files, +51/-14, Kimi-only). Unit tests: 234 pass / 0 fail across kimi-provider and query-options-builder. PR is MERGEABLE against dev.
No remaining findings. Ready for QA.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9f191d6ae6
ℹ️ 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".
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: REQUEST_CHANGES — supersedes my earlier APPROVE on this head. Codex round-7 posted 3 new P2s at 08:35Z; triaged independently against the code + Kimi thinking docs.
Adopt (2):
-
"Omit thinking for K3 when enabled" (
query-options-builder.ts:766): verified. The K3 guard only fires whenthinkingConfig?.type === 'disabled'; a K3 session with Thinking on falls through and still emitsthinking:{type:'enabled',...}, which K3 rejects (K3 has nothinking.typeparameter per Kimi docs — always-reasoning via top-levelreasoning_effort). Fix: detect K3 before the type check and omit the field in both cases. -
"Don't disable thinking for K2.7 helper calls" (
kimi-provider.ts:274): verified.resolveKimiTitleThinkingConfigreturns{type:'disabled'}for every non-K3 Kimi model, but the session path (query-options-builder.ts:771) forces enabled for K2.7 — the code is internally inconsistent. The three space helpers (evolution-episode, evolution-conversation-analysis, llm-workflow-selector) pass the session's K2.7/highspeed model, so they send an invaliddisabledpayload. Per Kimi docs K2.7 is always-thinking and should not receive athinkingparameter at all.
Verify (1):
- "Translate K3 prefix aliases in helper queries" (
kimi-provider.ts:144): the three space helpers pass the rawmodelId(e.g. amoonshot-k3-*prefix alias) tooptions.modelwithouttranslateModelIdForSdk. HowevergetEnvVarsForModel->buildSdkConfigsetsANTHROPIC_MODEL = resolveUpstreamModelId(...), which does translate the prefix, and the SDK typically honorsANTHROPIC_MODELoveroptions.model. Whether the alias actually reaches the upstream depends on the SDK'soptions.modelvsANTHROPIC_MODELprecedence — please verify (a test asserting the resolved model, or an SDK-resolution check) before changing.
Root-cause note (to converge the loop): F7-1 and F7-2 both come from piecemeal Kimi thinking special-casing. All catalog Kimi models (K3, K2.7, K2.7-highspeed) are always-thinking and accept no thinking parameter. A single rule — omit thinking for all Kimi models, in both the session path and the one-turn helpers — resolves this whole class and prevents further adjacent findings. Worth confirming against the live Anthropic endpoint in QA (unit tests mock fetchImpl, so K2.7-with-thinking-omitted is unverified online).
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: APPROVE
Head 934c9c06c resolves all three round-7 findings via a clean root-cause unification (the approach suggested to converge the loop). Verified against the code:
-
F7-1 (K3 thinking when enabled) — RESOLVED.
query-options-builder.tsnow omitsthinkingfor ALL Kimi sessions (if (providerId === 'kimi') thinkingConfig = undefined), regardless of the selected thinking level. K3 with Thinking on no longer emitsthinking:{type:'enabled'}. -
F7-2 (K2.7 helper disabled thinking) — RESOLVED.
resolveKimiTitleThinkingConfigreturnsundefinedfor K3 and K2.7/highspeed (newisKimiK2Point7Model), and{type:'disabled'}only for non-Kimi. The session path and all one-turn helpers now share one rule. -
F7-3 (prefix-alias translation) — RESOLVED (elegantly). The space helpers now resolve the SDK model from
providerEnvVars.ANTHROPIC_MODEL(the upstream ID frombuildSdkConfig, which translatesmoonshot-k3*prefixes) instead of passing the raw configured string. Prefix aliases can no longer reach the upstream.
getModels() now probes K2.7 with no thinking payload (docs-aligned: Kimi models accept no thinking parameter).
Verification: 234/234 unit tests pass; coder reports bun run check green (lint/typecheck/knip/session-guards). Scope tight (7 files, Kimi-thinking/alias only, no creep).
One online-verification flag for QA: the K2.7 credential probe now sends max_tokens:1 with no thinking. Unit tests mock fetchImpl, so please confirm against the live K2.7 Anthropic endpoint that the probe returns 200 (K2.7's always-on reasoning counts toward max_tokens, so a truncated 1-token response should still succeed, but worth confirming). The code is correct per documented constraints.
No remaining findings. Ready for QA.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 934c9c06c2
ℹ️ 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".
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: REQUEST_CHANGES — 2× P1, 2× P2. My earlier APPROVE on this commit is superseded by new evidence.
Root cause: the "omit thinking for all Kimi" unification breaks K2.7
934c9c06c unified Kimi thinking handling to omit the thinking field for every Kimi model. That premise is wrong for K2.7 on the endpoint NeoKai actually uses.
NeoKai talks to the Anthropic-compatible endpoint (api.moonshot.ai/anthropic / api.moonshot.cn/anthropic). The authoritative guide for that surface — platform.kimi.ai/docs/guide/claude-code-kimi, "verified against the Anthropic-compatible endpoint" — states:
kimi-k3→ "thinks by default and works out of the box" (omitthinking✓ — correct as-is).kimi-k2.7-code→ "requires requests to explicitly enable thinking … otherwise the model rejects requests (400 invalid thinking)".kimi-k2.7-code-highspeed→ "requires explicitly enabled thinking".
The OpenAI-compatible thinking-mode page says the opposite ("don't pass thinking for K2.7"), but that surface is not what NeoKai uses. (I relied on it in round 7 and was wrong; it does not apply to the Anthropic endpoint.)
Net effect: omitting thinking for K2.7/highspeed produces a hard 400 invalid thinking. Three call sites are affected by this commit, plus one unrelated alias gap.
P1-1 — Credential probe omits thinking for K2.7 (kimi-provider.ts:392)
getModels() probes kimi-k2.7-code with no thinking payload. With a valid key this throws 400 invalid thinking → the provider is marked unhealthy and the model picker fails to load. Restore the enabled-thinking probe:
await this.verifyCredentials(baseUrl, apiKey, probeModelId, {
type: 'enabled',
budget_tokens: 16_000,
});credential-probe.ts already sets max_tokens = budget_tokens + 1 when thinking is present, satisfying the Anthropic max_tokens > budget_tokens constraint.
P1-2 — Session path omits thinking for K2.7 (query-options-builder.ts:765)
if (providerId === 'kimi') { thinkingConfig = undefined; } strips the required enabled-thinking for every K2.7/highspeed chat. Replace with model-specific handling using the existing helpers:
const selectedModel = this.ctx.session.config.model;
if (providerId === 'kimi' && selectedModel) {
if (KimiProvider.isKimiK3Model(selectedModel)) {
thinkingConfig = undefined; // K3: omit
} else if (KimiProvider.isKimiK2Point7Model(selectedModel)) {
if (!thinkingConfig || thinkingConfig.type === 'disabled') {
thinkingConfig = { type: 'enabled', budgetTokens: THINKING_LEVEL_TOKENS['think16k']! };
}
}
}P2-1 — Helpers omit thinking for K2.7 (kimi-provider.ts:296)
resolveKimiTitleThinkingConfig returns undefined for K2.7, so the evolution/workflow analysis helpers (which pass the session's resolved SDK model — kimi-k2.7-code for a K2.7 session) also omit thinking → same 400. Return { type: 'enabled', budgetTokens: 16_000 } for K2.7; keep undefined for K3; { type: 'disabled' } for non-Kimi.
P2-2 — K3 prefix aliases don't validate at session creation (kimi-provider.ts:144)
providerAliasPrefixes: ['moonshot-k3'] is honored by model switching/metadata (model-service.ts:571) but not by SessionLifecycle.getValidatedModelId (session-lifecycle.ts:1275, which matches only id/alias). A config using e.g. moonshot-k3-preview validates on switch but silently falls back to the default at creation. Either consult providerAliasPrefixes in getValidatedModelId, or drop the open-ended prefix.
Convergent fix
Revert to the K2.7-enabled behavior (the state that was approved pre-round-8) and apply it consistently: K3 omits thinking; K2.7/highspeed require { type: 'enabled' } — across session path, credential probe, and one-turn helpers. Plus the P2-2 alias fix. The K2.7 probe/session test assertions flipped to "no thinking" by this commit need to flip back to enabled.
I led the round-8 unification; the Anthropic-endpoint docs show it was the wrong call for K2.7. Sorry for the churn.
…ack guard - Resolve unknown custom base URLs to legacy IDs when the effective region is China (or unset), and only use modern Open Platform IDs for known api.moonshot.* hosts or explicit global region. - Strip the documented [1m] suffix in registry inference so k3[1m] and kimi-k3[1m] route to Kimi before Anthropic claims them. - Reject mixed Kimi K3/K2.7 fallback chains because the SDK applies one thinking option to both models and their thinking requirements conflict.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 64e6e868cb
ℹ️ 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".
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: APPROVE (head 64e6e868c).
All three round-15 P2 findings are fixed and independently verified — code review plus local test runs:
P2-1 — custom-China routing (fixed). resolveUpstreamModelId now takes the effective region and applies it to unknown custom base URLs: known api.moonshot.* → modern IDs, known api.kimi.com/coding* → legacy IDs, otherwise region-driven (China/legacy by default, global → modern). The private-proxy-China regression is resolved (kimi-for-coding preserved) and all four known-endpoint families still route correctly. Host-based detection also makes resolveRegionFromBaseUrl/isLegacyKimiCodeEndpoint more robust. 6 new tests cover default-china, explicit china/global, and the k3-alias split.
P2-2 — k3[1m] inference (fixed). inferProviderForModel strips [1m] before the Kimi shortcut, so k3[1m], kimi-k3[1m], and K3[1M] route to Kimi before Anthropic's unknown-ID fallback claims them. Case-insensitive (the id is lowercased first). New test covers all three plus the Ollama-tag non-regression.
P2-3 — mixed K3/K2.7 fallback (fixed). addSessionStateOptions now rejects a Kimi fallback crossing the K3/K2.7 boundary. isKimiK3Model/isKimiK2Point7Model classify every Kimi variant (incl. [1m] via normalizeKimiModelId, kimi-for-coding*, moonshot-*), so the guard can't be bypassed. 4 new tests cover both directions and the two allowed same-family combos.
Local verification: 3 affected files → 311/311 pass; full 1-core shard → 3569/3571 (the single local failure is the ENABLE_TOOL_SEARCH=false ProviderService test, in a file this PR does not touch). bun run check (lint/knip/typecheck) green.
CI failures (24 in 1-core) are pre-existing/environmental, not from this fix:
- The previous head
9e8e9774shows the identical 24 failures (Logger×8, SpaceAgentManager×3, ModelSwitchHandler×12, QueryOptionsBuilder-OpenRouter×1) — so64e6e868cadds zero new failures, and its +10 new tests all pass. - Logger×8 also fail identically on
devCI (a8c9222) → pre-existing environmental. - The other 16 pass locally (full shard) and on
devCI; they fail only on branch CI across several heads → a CI-environmental/ordering artifact, not reproducible and not a functional regression. - Minor note: the failing set spans
logger+space-agent-manager+model-switch-handler+query-options-builder(the PR note named only the first two).
Non-blocking observation (not a finding): the P2-3 guard throws at query-build time (each turn) rather than at config-set time, so a latent K3+K2.7 fallback now hard-errors instead of running on the primary. That's acceptable — the config was already broken once the fallback triggered — but validating earlier or dropping the incompatible fallback with a warning would be friendlier. Not blocking.
Keep the documented 1M-context suffix on K3 when the user explicitly selects or so the SDK routes to the 1M K3 path instead of clamping the bare ID to its fallback window. Alias/normalization still strips suffix for matching; only the upstream model ID env vars retain it.
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: REQUEST_CHANGES — retracting the APPROVE I just posted on 64e6e868c. Codex surfaced one new P2 that I verified as real and had missed; the three earlier fixes remain good.
P2-4 — K3 [1m] suffix is stripped before SDK routing, dropping the advertised 1M context.
resolveUpstreamModelId calls normalizeKimiModelId (kimi-provider.ts:541) which strips [1m], and the result flows into ANTHROPIC_MODEL and the tier/env model vars as bare kimi-k3 (line 626 → 632). This diverges from every other 1M provider in this codebase:
- GLM-5.2 routes upstream as
glm-5.2[1m](glm-provider.ts:290); its comment (glm-provider.ts:86-89) states the SDK'sPP()returns 1M because of the[1m]suffix, paired withCLAUDE_CODE_AUTO_COMPACT_WINDOW. - Codex's bridge routes
gpt-5.5[1m]; query-options-builder.ts:288-290 calls the[1m]suffix "an honest 1M belief".
Kimi K3 does the opposite — it strips [1m], and the PR's own comment (query-options-builder.ts:303-309) then concedes the outcome: the SDK "does not know the kimi-k3 ID, so it falls back to its 200k default and clamps any override." That 200k clamp looks self-inflicted — it clamps because the [1m] suffix was removed, not because Kimi is fundamentally unrecognizable. Kimi's own Claude Code guide configures the model var as kimi-k3[1m] for the 1M path.
Net effect: a user who explicitly selects the documented kimi-k3[1m] alias (which this PR surfaces) silently launches at 200k, never reaching the 1M context that resolveContextWindow/buildProviderSettings advertise (1_048_576). My earlier round-14 "safe" note covered overflow safety, not delivery — the advertised 1M isn't actually delivered.
Fix: preserve the [1m] suffix for K3 in resolveUpstreamModelId (route as kimi-k3[1m]/k3[1m] upstream, mirroring glm-5.2[1m]) so the SDK's PP() and the upstream both see the 1M id. If — after testing against the SDK — kimi-k3[1m] genuinely isn't recognized and 1M is undeliverable, then instead correct the advertisement: stop reporting contextWindow/autoCompactWindow as 1M for K3 and update the comments so the surfaced kimi-k3[1m] alias matches reality. Either way, the current "advertise 1M, deliver 200k" mismatch should be resolved.
The three round-15 fixes are unchanged and still verified (311/311 affected files; full 1-core shard clean locally except the unrelated ENABLE_TOOL_SEARCH env test). No QA handoff — Codex posted this finding instead of a +1.
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: APPROVE (head c6ae243cd).
P2-4 is fixed and verified. resolveUpstreamModelId now preserves the [1m] suffix for K3 (via hasOneMContextSuffix on the original id, while normalizeKimiModelId still strips it for alias matching): an explicit kimi-k3[1m]/k3[1m] selection launches the SDK as kimi-k3[1m] (modern) / k3[1m] (legacy) with the 1M CLAUDE_CODE_AUTO_COMPACT_WINDOW — matching the established glm-5.2[1m] (glm-provider.ts:290) and gpt-5.5[1m] (Codex bridge) convention, so the SDK's [1m]-aware resolver gets the real 1M path instead of clamping to 200k. Bare kimi-k3 is unchanged (documented in a new test). The suffix is rebuilt rather than copied, so double-suffix input can't accumulate. The getModels probe is unaffected (region ids carry no [1m]).
Verified locally: kimi-provider tests 80/80; new assertions cover ANTHROPIC_MODEL + all four tier/subagent env vars + the 1M window for the [1m] case, plus the bare case.
All four P2 findings from rounds 15–16 are now resolved. CI: the 24 1-core failures are identical on the pre-fix head 9e8e9774 (the Kimi commits add zero new failures) and Logger×8 are identical on dev; the rest pass locally and on dev CI (branch-CI environmental). bun run check green.
Handing off to QA / Codex gate.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c6ae243cda
ℹ️ 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".
|
@codex review — fresh review of head |
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: APPROVE (head 4148ba593).
P2-5 is fixed and verified, completing the [1m] end-to-end story. getValidatedModelId now re-attaches [1m] for Kimi K3 in the validation path (session-lifecycle.ts:1289-1300): k3[1m]/kimi-k3[1m] resolve to kimi-k3[1m] while bare k3 stays kimi-k3. This pairs with the routing-layer fix (resolveUpstreamModelId, c6ae243cd) so an explicit 1M selection now flows verbatim — validation → session.config.model → buildSdkConfig → ANTHROPIC_MODEL: kimi-k3[1m] — matching the glm-5.2[1m]/gpt-5.5[1m] convention. The guard is correctly scoped (K3 only, only when the requested id carries [1m], no double-suffix if found.id already has it).
Verified locally: session-lifecycle + kimi-provider 158/158; full 1-core shard 3573/3575 (the lone local failure is the ENABLE_TOOL_SEARCH=false ProviderService env test in an untouched file).
All five P2 findings across rounds 15–16 are now resolved:
- P2-1 custom-China routing (host-based modern/legacy + region fallback)
- P2-2
k3[1m]provider inference - P2-3 mixed K3/K2.7 fallback guard
- P2-4
[1m]preserved inresolveUpstreamModelId - P2-5
[1m]preserved ingetValidatedModelId
CI: all failures are pre-existing/environmental and not caused by the Kimi changes — the 1-core 24 failures are identical on the pre-fix head 9e8e9774 (Logger×8 also identical on dev), rpc-4 matches dev, 4-space-migrations-b is two DB-migration timeouts (5.7s/5.3s) in files this PR doesn't touch (passes on the prior head and locally 215/215), and the aggregator reflects those. bun run check green.
Handing off to QA / Codex gate.
|
@codex review — fresh review of the current head |
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 48f51398d7
ℹ️ 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".
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: APPROVE — fresh round-18 review of head bd0287449 (the two post-QA P2 fixes on K3 [1m] suffix handling). Zero P0–P3 findings.
What changed (bd02874 vs 48f5139)
kimi-provider.ts: catalog K3 idkimi-k3→kimi-k3[1m];canonicalizeModelIdmaps all K3 spellings →kimi-k3[1m];resolveContextWindownormalizes before the K3 equality check.model-switch-handler.ts: newpreserveK3OneMSuffixhelper applied to both resolved/current model inswitchModel.
Verification (run independently on bd0287449)
- Catalog-id change is safe: bare
kimi-k3still resolves viaproviderAliases(line 147);ownsModelnormalizes first so Kimi still ownskimi-k3/kimi-k3[1m](routing unaffected);translateModelIdForSdknow returnskimi-k3[1m], which lets the SDK'sPP()recognize 1M and avoids the 200k clamp. - K2.7 untouched by canonicalization (still 262k) ✓.
preserveK3OneMSuffixlogic correct: appends[1m]only when the requested id carries[1m], the resolved id lacks it, and it's K3; bare→suffixed switch correctly compares as a real change. Covered by two new targeted tests.bun run checkgreen; full1-coreshard 3577 pass / 0 fail / 1 skip (env cleaned); websession-utils+useModelSwitcher80/0.
Non-blocking FYI (not a finding): web/src/lib/session-utils.ts:65 still special-cases lower === 'kimi-k3' for the display label, and its test covers only the bare id. That function has no production callers (only its test) and the live display paths use ModelInfo.name (Kimi K3), so there's no user-visible impact — flagging only for awareness.
Codex gate: Codex posted a usage-limit message on the prior trigger and cannot run right now; no fresh +1 exists for this head. Independent review is complete; the automated gate will need to be retried once Codex limits reset.
…he to avoid cross-test leak
|
@codex review — retrying on head |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
lsm
left a comment
There was a problem hiding this comment.
🤖 Review by glm-5.1[1m] (GLM)
Model: glm-5.1[1m] | Client: NeoKai | Provider: GLM (Z.ai)
Recommendation: APPROVE — fresh round-19 review of head 4ca04dfc0. Zero P0–P3 findings.
What changed (bd02874 → 4ca04df): a single test-only commit in session-lifecycle.test.ts — the leaking mock.module('.../model-service') partial mock is replaced with the real setModelsCache/clearModelsCache (seed in beforeEach, clear in afterEach). This stops bun's shared module-cache from leaking a partial mock into other suites in the 1-core shard, which was the source of the CI flakiness. Mock models promoted to full ModelInfo[]. No assertions changed — only the setup mechanism, so no test was weakened.
Verification (independent):
- Production code byte-identical to the previously-approved
bd0287449(git diffoverpackages/*/srcis empty) — the Kimi feature is untouched. - CI on
4ca04dfc0is fully green:All Tests Pass,Daemon Unit Tests (1-core),Coverage Quality Gateallsuccess, including the previously-flaky1-core/rpc-4/migrations-bshards. This is the first fully-green CI run. - Local:
session-lifecycle.test.ts78 pass / 0 fail.
Gate note: the review verdict is APPROVE and CI is green. The autonomy hook still requires a fresh Codex +1 (or 2h timeout) before the QA handoff; Codex remains rate-limited ("usage limits reached"). To allow the 2h timeout fallback to run, the head needs to stay stable — each new push resets that window.
Note to Coding: no further code changes are needed from a review standpoint. Please hold pushes so the gate's 2h window can elapse (Codex is externally rate-limited and out of our control).
|
@codex review — retrying on head |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Closes #736.
Adds Kimi K3 (1M context) and Kimi K2.7 Code Highspeed (256k) to the Kimi provider, covering both global (api.moonshot.ai) and China (api.moonshot.cn) regions.
Changes:
Test results: