MoonshotAI / MoonshotAI/kimi-code
Web transcript renders duplicated lines: full message plus leftover stream chunks after a turn ends
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 53m
- Merged PRs (30d)
- 350
Description
Symptom
In the web composer, once a turn completes, an assistant message can render as the full reply followed by fragments of the same reply repeated as extra lines (e.g. the full text, then , here's one, :, \n\nWhy do programmers, … one per stream chunk).
Repro
Any session whose model stream interleaves non-text parts between text deltas — e.g. an OpenAI-compatible provider that sends a reasoning_content key (even empty) on every chunk, which makes _convertStreamResponse yield a think part per chunk so text parts are never merged. Then:
- The wire gets one
content.partrecord per text delta. - The live projection keeps a single text frame per step, updated with the accumulated text.
- After
turn.ended, the heal pass (healTurnOpsinpackages/kap-server/src/services/transcript/transcriptService.ts) re-reads the cold snapshot — which has one text frame per delta — and merges it into the live store. The dedup is per-frameId: coldf2collides with the live consolidated frame and is skipped, but coldf3…fN(the remaining deltas) have no live counterpart and are appended verbatim. - The web UI renders every text frame as its own paragraph → full text + duplicated fragments. The same merge runs at attach-time backfill, so reopened sessions show it too.
Observed on a real session's GET /api/v1/sessions/<id>/transcript: final step frames were f1 thinking, f2 = full accumulated text, then f3…f8 = deltas[1..6] verbatim. Intermediate steps inspected before the heal debounce only show the single live frame, which is why this appears specifically on ended turns.
Expected
One consolidated text frame per step after heal, same as intermediate steps.
Fix
PR follows: teach healTurnOps to skip a snapshot text/thinking frame when any same-kind, same-role live frame in the step already contains its text.
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 in packages/kap-server/src/services/transcript/transcriptService.ts at healTurnOps and trace how snapshot text and thinking frames are merged with live frames. Reproduce a completed turn with interleaved non-text stream parts, then verify that ended turns and attach-time backfills retain one consolidated text frame per step without duplicated web paragraphs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100