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":{}}
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.maxAttemptsPerStep engages, 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_issu alone 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.
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
managed:kimi-code, model k3, thinking effort highmcp__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":{}}?is a literal 0x3F byte, not a rendering artifact (od hex-dump verified).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 deliversmcp__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":loopControl.maxAttemptsPerStepengages, instead of silently advancing.[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 exportdebug zip if useful.