Skip to content

fix(context): normalize historical tool_call IDs for kimi-k2.x targets - #1066

Merged
josemonteiro merged 2 commits into
masterfrom
normalize-kimi-k2-tool-call-ids
Aug 20, 2026
Merged

josemonteiro merged 2 commits into
masterfrom
normalize-kimi-k2-tool-call-ids

Conversation

@josemonteiro

@josemonteiro josemonteiro commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

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.id values. Moonshot trains the K2 family on functions.{tool_name}:{idx} — k2.x's own calls in the affected session were exactly functions.bash:0..N. After a mid-session switch to glm-5.2-fp8 (which emits OpenAI-style call_<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.py only clamps temperature / injects placeholder reasoning_content).

Evidence (replay of the reconstructed 141-message / ~75k-token session context against the gateway)

Arm kimi-k2.7 result
Baseline ×10 1/10 acted — mostly completely empty turns
This normalization ×12 12/12 on-task tool calls
kimi-k3 control ×4 (same context, no normalization needed) 4/4 tool calls
Tool-less codeword recall probe ×4 4/4 — k2.7 attends to long context fine

Fix

normalize-kimi-tool-call-ids.ts: when the active model is kimi-k2.* (not k3), rewrite every historical toolCall.id and the paired toolResult.toolCallId to functions.{name}:{globalIdx}, copy-on-write, wired into the existing prompt-enrichment context transforms (main + subagent paths).

Testing

  • 18 unit tests: id matcher, pairing, global indexing, canonical renumbering, orphan results, pass-by-reference no-ops, no input mutation.
  • pnpm exec vitest run src/extensions/prompt-construction/ → 189 passed; lint and typecheck clean.

josemonteiro and others added 2 commits August 18, 2026 16:49
…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>
@josemonteiro josemonteiro added the bug Something isn't working label Aug 19, 2026
@kimchi-review

kimchi-review Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

Kimchi Code Review

Property Value
Commit b33edb9
Author @josemonteiro
Files changed 0
Review status Completed
Comments 0
Duration 88s

Summary

📊 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! 🎉

What to expect

Kimchi will analyze the changes in this pull request and post:

  • A summary of the overall changes
  • Inline comments on specific lines with findings categorized by issue type

The review typically completes within a few minutes. This comment will be updated once the review is ready.

Interact with Kimchi
  • @getkimchi review — re-trigger a full review on the latest commit
  • @getkimchi summary — regenerate the PR summary
  • @getkimchi ignore — skip this PR (no review will be posted)
  • Reply to any inline comment to ask follow-up questions or request clarification
Configuration

Reviews are configured by your organization admin.
Review instructions, excluded directories, and severity thresholds can be adjusted per repository in the Kimchi dashboard.


Powered by Kimchi — AI-powered code review by CAST AI

@readme-ai-writer

readme-ai-writer Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

📚 No documentation changes were needed for this PR.

@kimchi-review kimchi-review 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.

📊 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! 🎉

@josemonteiro
josemonteiro added this pull request to the merge queue Aug 20, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 20, 2026
@josemonteiro
josemonteiro added this pull request to the merge queue Aug 20, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 20, 2026
@josemonteiro
josemonteiro added this pull request to the merge queue Aug 20, 2026
Merged via the queue into master with commit 783b460 Aug 20, 2026
7 checks passed
@mszostok
mszostok deleted the normalize-kimi-k2-tool-call-ids branch September 24, 2026 08:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

kimi-k2.x stalls on multi-model history: non-canonical tool_call IDs in context

2 participants