MoonshotAI / MoonshotAI/kimi-code
[kimi-web] Reloaded transcript renders each streamed text chunk on its own line (newline-join + pre-wrap)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 53m
- Merged PRs (30d)
- 350
Description
What version of Kimi Code is running?
0.31.1
Which open platform/subscription were you using?
Third-party OpenAI-compatible provider (custom base_url), not a Kimi subscription.
Which model were you using?
qwen3.8-max-preview — but this is provider-agnostic; any endpoint that streams small text chunks can trigger it.
What platform is your computer?
Linux 7.0.0-28-generic x86_64 x86_64
What issue are you seeing?
In the web UI (kimi-web), when a session is re-rendered from history — page refresh, switching to another session and back, or reopening the UI — assistant responses that were streamed in small chunks render with every chunk on its own line. The same response looked correct (continuous paragraphs) while streaming live.
Example of the history view after reload:
你好!
我的
上下文里没有直接暴露
session
ID,不过我可以
到
环境里找找看
。
The underlying wire.jsonl data is intact — concatenating the session's text parts in order reproduces the original, correct text exactly. Only the historical rendering is broken.
What steps can reproduce the bug?
- Configure an OpenAI-compatible provider whose streaming API emits small text chunks (e.g. Alibaba DashScope compatible-mode).
- In kimi-web, send any prompt and watch the answer stream in — it renders fine.
- Refresh the page, or switch to another session and back.
- The same answer is now fragmented into one line per streamed chunk.
Root cause (from the v0.31.1 source):
- Live path coalesces deltas with no separator:
apps/kimi-web/src/api/daemon/agentEventProjector.ts:402(last.text += delta), and skips empty deltas (if (!delta) break;at :768/:800). - History path maps transcript parts 1:1 (
apps/kimi-web/src/api/daemon/mappers.ts:193) and merges consecutive text parts with a hard newline:apps/kimi-web/src/composables/messagesToTurns.ts:645(last.text += '\n' + c.text). - Text blocks render with
white-space: pre-wrap(apps/kimi-web/src/components/chat/ChatPane.vue:882), so every inserted\nbecomes a visible line break. - Endpoints that stream in small chunks produce many
content.partrecords per message, so every chunk ends up on its own line.
What is the expected behavior?
History re-render shows the same continuous text as the live view — consecutive streamed text fragments should be merged without inserting newlines (matching the live path's += delta behavior).
Additional information
- This likely also explains intermittent "large blank areas / extra blank lines" seen with some OpenAI-compatible endpoints: whitespace-only text chunks get newline-joined and render as blank lines.
- Suggested fix: drop the
'\n'inmessagesToTurns.ts:645(merge with''), or coalesce adjacent same-type parts upstream in the transcript projection so the renderer receives one text part per logical paragraph.
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 at apps/kimi-web/src/composables/messagesToTurns.ts:645 and compare its history merge with apps/kimi-web/src/api/daemon/agentEventProjector.ts:402. Reproduce the issue by reloading a session with streamed chunks, then verify that consecutive text fragments remain continuous and match the live view without added line breaks.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100