Skip to content

Assistant response can appear twice in a long TUI transcript #426

Description

@alejandro-ao

Summary

In a long TUI session, the final assistant response appeared twice in the transcript, with one copy directly above the other.

This was observed once and could not be reproduced afterward, including with copied long-session fixtures. The session data contains only one persisted copy of the assistant response, so the symptom appears to be presentation-only rather than session corruption or duplicate provider output.

Affected session

  • Session ID: daf7e5f695fb4c0ca3dd25ac52cff3ac
  • Session name: Vultr Serverless Document Ranking
  • Tau version at observation: 0.2.3
  • Assistant entry inspected: 88a84f137ace4b799d8c1b33e2e0e77e

The active branch projected to roughly 367 transcript items, exceeding the TUI's 200-item mounted window. The affected response contained both thinking and text blocks, so it used structured assistant finalization.

Observed behavior

The completed assistant response was visibly rendered twice in the transcript.

Expected behavior

Each completed assistant response should remain visible exactly once throughout streaming, finalization, redraws, and transcript-window paging.

Investigation

The durable JSONL contains the affected assistant response once. The normal session event pipeline also appears to yield one assistant MessageEndEvent.

One concrete transient was reproduced independently: TranscriptView._redraw() schedules remove_children() and immediately mounts replacement widgets. Textual prunes removed children asynchronously, so old and replacement rows can coexist in the DOM for a frame.

The relevant areas are:

  • src/tau_coding/tui/app.py: assistant MessageEndEvent handling and structured finalization
  • src/tau_coding/tui/widgets.py: TranscriptView._redraw() and finish_structured_assistant_message()
  • Long-transcript windowing introduced in commit 4d7c9824

A duplicate assistant row was not reproduced by replaying a synthetic long transcript with thinking and text, nor while manually testing copied long sessions.

Direction tested

Draft PR #424 tried hiding stale transcript rows before Textual completed asynchronous pruning. The initial approach touched every mounted row and appeared to make long sessions less smooth. It was narrowed to the trailing visible boundary row, but the original reported symptom still could not be reproduced, so the PR was closed rather than merging an unvalidated workaround.

Suggested next steps

  • Add temporary diagnostics around assistant finalization and transcript reconciliation:
    • assistant message/event identity
    • canonical ChatItem identities
    • mounted widget identities
    • transcript window bounds
    • active streaming widget identities
  • Assert or log when multiple visible widgets represent the same canonical assistant item.
  • Capture whether a full redraw, structured finalization, window shift, resize, or duplicate end event immediately preceded the symptom.
  • Prefer an awaited or serialized DOM reconciliation if asynchronous pruning is confirmed as the cause, rather than applying visibility changes across the transcript window.

Reproduction status

Not currently reproducible. Keep this issue open for additional reports or diagnostics from a future occurrence.

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