Repository navigation
fix(context): normalize historical tool_call IDs for kimi-k2.x targets - #1066
Conversation
…witch
When the user switches models via the UI picker, /model, or cycling,
the new model should get a fresh tool-calling budget. Reset the
session-level continuation nudge latch and the empty-turn nudge cycle
budget on user-initiated model switches ("set" and "cycle"), while
preserving pending delegation counts and excluding session restore
("restore").
Includes regression tests for:
- pending delegation count surviving resetForModelSwitch
- EmptyTurnNudge.resetForModelSwitch
- source "cycle" triggering the reset
Co-Authored-By: Kimchi <noreply@kimchi.dev>
kimi-k2.x models abandon turns (immediate end-of-turn, no content) when
conversation history carries non-canonical tool_call IDs, e.g. OpenAI-style
call_* IDs left behind after a mid-session model switch. Moonshot trains the
K2 family on the canonical functions.{name}:{idx} format and k2.x deployments
are strict about it (MoonshotAI/Kimi-K2#128, vllm-project/vllm#50782).
The hosted Moonshot gateway rewrites IDs server-side; the LiteLLM gateway
kimchi routes through does not.
Measured on a reconstructed 141-message / ~75k-token session context:
kimi-k2.7 acted in 1/10 trials with mismatched IDs and 12/12 after
normalizing them.
Rewrite every historical toolCall.id and the paired toolResult.toolCallId to
functions.{name}:{idx} with a global index when the active model is
kimi-k2.*. Wired into the prompt-enrichment context handlers (main agent and
subagent paths), following the existing copy-on-write transform convention.
Closes #1063
Co-Authored-By: Kimchi <noreply@kimchi.dev>
Kimchi Code Review
Summary📊 Review Score: 89/100 (overall code quality — 0 lowest, 100 highest) 🧪 Tests: yes — Comprehensive tests cover the new No significant issues found. LGTM! 🎉 What to expectKimchi will analyze the changes in this pull request and post:
The review typically completes within a few minutes. This comment will be updated once the review is ready. Interact with Kimchi
ConfigurationReviews are configured by your organization admin. Powered by Kimchi — AI-powered code review by CAST AI |
|
📚 No documentation changes were needed for this PR. |
There was a problem hiding this comment.
📊 Review Score: 89/100 (overall code quality — 0 lowest, 100 highest)
⏱️ Estimated effort to review: 2/5 (1 = trivial, 5 = very complex)
🧪 Tests: yes — Comprehensive tests cover the new resetForModelSwitch behavior on both nudge classes, Kimi K2 model detection, tool-call ID normalization edge cases (no-op, rewrite, global indexing, already-canonical IDs, orphan results, by-reference pass-through), and the integration behavior in prompt-enrichment.ts for set/cycle/restore model-select sources.
No significant issues found. LGTM! 🎉
Closes #1063
Root cause
kimi-k2.x models abandon turns (immediate end-of-turn with zero content) when conversation history carries non-canonical
tool_call.idvalues. Moonshot trains the K2 family onfunctions.{tool_name}:{idx}— k2.x's own calls in the affected session were exactlyfunctions.bash:0..N. After a mid-session switch to glm-5.2-fp8 (which emits OpenAI-stylecall_<hex>), the history goes off-distribution and the model goes silent. Corroborated upstream: MoonshotAI/Kimi-K2#128, vllm#50782, and Kimi-K2 tool_call_guidance.Moonshot's hosted gateway rewrites IDs server-side; our LiteLLM gateway does not (verified: litellm mainline has no Kimi-side ID rewriting — the unrelated strict-provider PR BerriAI/litellm#22318 was closed unmerged, and
moonshot/chat/transformation.pyonly clamps temperature / injects placeholderreasoning_content).Evidence (replay of the reconstructed 141-message / ~75k-token session context against the gateway)
Fix
normalize-kimi-tool-call-ids.ts: when the active model iskimi-k2.*(not k3), rewrite every historicaltoolCall.idand the pairedtoolResult.toolCallIdtofunctions.{name}:{globalIdx}, copy-on-write, wired into the existing prompt-enrichmentcontexttransforms (main + subagent paths).Testing
pnpm exec vitest run src/extensions/prompt-construction/→ 189 passed; lint and typecheck clean.