MoonshotAI / MoonshotAI/kimi-code
Managed k3 stream emits corrupted tool names with literal '?' fragments; engine should validate unknown tool names
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 53m
- Merged PRs (30d)
- 350
Description
Summary
Since ~Aug 24, tool calls over managed:kimi-code (k3) intermittently arrive with corrupted names streamed in fragments — e.g. mcp__linear__list_issu?list_issues (a literal ?, 0x3F, mid-name). The engine rejects them (Tool "..." not found), the model retries the identical garbage, and the turn stalls.
This is distinct from #3220's parser defect: there, the client dropped name fragments; here, the bytes arriving from the API are themselves malformed — verified by reassembling the stream with a patched parser and hex-dumping the recorded tool call. The corruption is on the wire, not introduced client-side.
Environment
- kimi 0.36.0 (released Aug 13) and a source build of main @ 41f1eae (0.38.0); Windows 11
- Provider
managed:kimi-code, model k3, thinking effort high - MCP: 8 servers, ~130 tools; failures observed on the Linear http server (55 tools, long shared
mcp__linear__prefix)
Evidence
Session wire (~/.kimi-code/sessions/<wd>/<session>/agents/main/wire.jsonl):
{"type":"tool.call","name":"mcp__linear__list_issu?list_issues","args":{}}
{"type":"tool.call","name":"mcp__linear__get_issu?get_issue","args":{}}
- The
?is a literal 0x3F byte, not a rendering artifact (od hex-dump verified). - The model's reasoning immediately before one retry read: "Typo in tool name. Use mcp__linear__list_issues." — it then emitted the same corrupted name again. The intent is correct; the serialization is broken.
- First occurrence Aug 24 across all sessions; none in months of prior history on the same client version. #3220 (independent reporter, macOS, 0.38.0) was opened the same day — consistent with a serving-side change around Aug 23–24, not a client regression.
- Matches the vLLM K3 deployment note quoted in #3220: K3 occasionally emits a tool-call format its own parser does not expect.
Why this needs a server-side fix
No client parser can reconstruct intent from bytes that are wrong at the source. The model clearly intends mcp__linear__list_issues; the stream delivers mcp__linear__list_issu?list_issues.
What the client could still do (proposal)
Even with a server fix, the engine currently treats these as ordinary tool results (Tool "..." not found) and burns the step budget until the turn dies. Two complementary guards, aligned with #3220's "Suggested handling":
- Classify an unknown-tool-name call as a retryable step failure so
loopControl.maxAttemptsPerStepengages, instead of silently advancing. - Optionally, constrained name recovery: when a name is unknown, sanitize it (split on non-
[A-Za-z0-9_]) and rewrite to a catalog tool only on a unique match — exact segment, then_-bounded suffix, then prefix, in that priority. Ambiguous or unmatched names keep the current rejection. In local testing this rescued every corrupted call observed (list_issu?list_issues→list_issues,get_issu?get_issue→get_issue) while correctly rejecting ambiguous truncations (list_issualone matches 3 catalog tools → rejected).
I have both the #3220 parser patch and this recovery guard implemented with unit tests in a local fork (suites green, typecheck/lint clean) and can contribute either under an /approve. Per the contributing guide, behavior changes are maintainer-gated — so treat this as the discussion issue first.
Reproduction
With a large MCP catalog (Linear's 55-tool http server makes it frequent), start a fresh session and ask the agent to list or review Linear issues. Intermittent — but when it triggers, it repeats within the session. Happy to attach a kimi export debug zip if useful.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Begin with the recorded wire.jsonl session data under ~/.kimi-code/sessions/.../agents/main/wire.jsonl and reproduce the failure using a large MCP catalog. Then inspect the engine's unknown-tool handling and loopControl.maxAttemptsPerStep behavior, comparing the proposed guards with #3220. Done means the malformed-name case no longer stalls a turn and the recovery behavior remains safe for ambiguous or unmatched names.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend-api-design, cli
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100