Skip to content

Web transcript renders duplicated lines: full message plus leftover stream chunks after a turn ends #3387

Description

@StephenZhang-hash

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:

  1. The wire gets one content.part record per text delta.
  2. The live projection keeps a single text frame per step, updated with the accumulated text.
  3. After turn.ended, the heal pass (healTurnOps in packages/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: cold f2 collides with the live consolidated frame and is skipped, but cold f3…fN (the remaining deltas) have no live counterpart and are appended verbatim.
  4. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions