MoonshotAI / MoonshotAI/kimi-code
Thinking text doubled when server mirrors reasoning deltas into both `reasoning_content` and `reasoning`
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 53m
- Merged PRs (30d)
- 350
Description
Summary
When an OpenAI-compatible server mirrors each reasoning delta into both delta.reasoning_content and delta.reasoning (identical text in the same chunk), the openai provider adapter appends both copies. Result: the thinking chain is rendered word-by-word doubled in the TUI, and the doubled text is also written into the session log.
This is a client-side handling gap, not a server bug: many harness-compatible servers deliberately emit reasoning twice (once per field name) so that clients reading either field work. A client that consumes both fields silently corrupts the reasoning display for every such endpoint.
Environment
- Kimi Code CLI 2.0.1 (Windows 11)
- Custom model pointing to an OpenAI-compatible server on the LAN (mlx-vlm 0.7.0,
Server: mlx_vlm/0.7.0header)
[providers."local-qwen"]
type = "openai"
base_url = "http://192.168.50.243:1919"
api_key = "test"
[models."qwen3.8-flash-next-4bit"]
provider = "local-qwen"
model = "models/Qwen3.8-Flash-Next-4bit"
max_context_size = 262144
capabilities = [ "thinking", "image_in", "tool_use" ]
support_efforts = [ "low", "medium", "xhigh" ]
default_effort = "xhigh"
What it looks like
The thinking panel renders every token twice:
TheThe user user greeted greeted me me in in Chinese Chinese,, so so I I should should respond respond with with a a brief brief greeting greeting in in return return..
The final answer text (content) is unaffected — only the reasoning chain is doubled.
Evidence
Raw SSE captured directly from the server with curl — the same delta text arrives under two field names in every chunk:
data: {"choices":[{"index":0,"delta":{"role":"assistant","content":null,
"reasoning_content":"The","reasoning":"The", "...": "..."}}]}
data: {"choices":[{"index":0,"delta":{"role":"assistant","content":null,
"reasoning_content":" user","reasoning":" user", "...": "..."}}]}
Kimi Code then records two content.part think entries per token in wire.jsonl, one per field:
{"type":"content.part",...,"part":{"type":"think","think":" greeted","reasoningKey":"reasoning_content"}}
{"type":"content.part",...,"part":{"type":"think","think":" greeted","reasoningKey":"reasoning"}}
In one test turn: 40 parts with "reasoningKey":"reasoning_content" + 40 identical parts with "reasoningKey":"reasoning" — the accumulated reasoning string is exactly twice its natural length.
Workaround tried: reasoning_key
Setting reasoning_key = "reasoning_content" on the model entry does not prevent the doubling: after pinning it, the session log still contained both keys (40 + 40). reasoning_key appears to add a non-standard field name to auto-detection rather than restrict the adapter to one field.
Expected / suggested behavior
When a chunk carries identical text in both reasoning_content and reasoning, the text should be consumed once. Any of:
- Dedupe identical delta content between the two fields (e.g. prefer
reasoning_contentwhenreasoningrepeats it); or - Make
reasoning_keya hard pin — when set, read only that field; or - Treat "both fields present and equal in the same chunk" as one occurrence at the accumulate/normalize layer, before display and context storage.
Impact
- Thinking display is unreadable and twice as long.
- Doubled reasoning is written into session context; if thinking is kept in context (
thinking.keep), this also wastes tokens.
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
Start by tracing the openai provider adapter's handling of reasoning_content, reasoning, and the reasoning_key option, then follow where think parts enter the accumulation or normalization layer. Reproduce the paired SSE deltas and verify that identical reasoning is emitted once in the TUI and session log while content remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100