Skip to content

fix(chat): dedupe duplicate assistant bubbles and align continuation bubbles#501

Merged
shanselman merged 2 commits into
openclaw:masterfrom
kenehong:kenehong/fix-duplicate-assistant-bubble
May 22, 2026
Merged

fix(chat): dedupe duplicate assistant bubbles and align continuation bubbles#501
shanselman merged 2 commits into
openclaw:masterfrom
kenehong:kenehong/fix-duplicate-assistant-bubble

Conversation

@kenehong
Copy link
Copy Markdown
Contributor

@kenehong kenehong commented May 21, 2026

Problem

image

Screenshot bug: in the chat surface, the same assistant text could render twice in a row, and continuation assistant bubbles in a same-sender burst were indented ~36 px further left than the first bubble in the burst.

Fixes

A. Rendering — OpenClawChatTimeline.RenderAssistantEntry

  • Reserve a 36×36 spacer for continuation assistant entries so the bubble's left edge stays aligned with the first entry in the burst. Matches the user-burst path above and the tool-burst path below, all of which already reserve the slot.
  • bubbleRow margin and footer leftInset now depend only on showAssistAvatar (not showAssistAvatar && showAvatar), so the slot inset is consistent whether the avatar is drawn or hidden as a spacer.

B. Reducer — ChatTimelineReducer.UpsertAssistant

  • Added an identical-text dedupe safety net: if the most recent Assistant entry within the same turn (i.e. before any User boundary) has byte-equal text to the incoming message, collapse them. Catches duplicate ChatMessageEvent emissions from the gateway regardless of the ReconcilePrevious flag.
  • On merge, restore ActiveAssistantId to the merged entry so subsequent deltas/messages do not split into a new bubble.

Tests

New reducer tests:

  • DuplicateFinalAssistant_IdenticalText_DedupesWithoutReconcileFlag — reproduces the screenshot bug.
  • SubsequentAssistant_DifferentText_AfterTurnEnd_CreatesNewEntry — guards against over-aggressive dedupe in a new turn.

Validation

  • ./build.ps1 — all projects succeeded.
  • OpenClaw.Shared.Tests — 1869 passed, 28 skipped.
  • OpenClaw.Tray.Tests — 1193 passed.
  • Verified visually in Debug → Chat Explorations (Fake provider has d5/d6 continuation-bubble case).

…bubbles

Two related fixes for the screenshot bug where the same assistant text rendered twice in a row and continuation bubbles were indented left of the first bubble.

Rendering (OpenClawChatTimeline.RenderAssistantEntry):

- Reserve a 36x36 spacer for continuation assistant entries so the bubble's left edge stays aligned with the first entry in the burst (matches the user-burst path above and the tool-burst path below).

- bubbleRow margin and footer leftInset now depend only on showAssistAvatar, so the slot is consistently inset regardless of whether the avatar is actually drawn.

Reducer (ChatTimelineReducer.UpsertAssistant):

- Added an identical-text dedupe safety net: if the most recent Assistant entry within the same turn (i.e. before any User boundary) has byte-equal text to the incoming message, collapse them. This catches duplicate ChatMessageEvent emissions from the gateway regardless of the ReconcilePrevious flag.

- On merge, restore ActiveAssistantId to the merged entry so subsequent deltas/messages do not split into a new bubble.

Tests:

- DuplicateFinalAssistant_IdenticalText_DedupesWithoutReconcileFlag

- SubsequentAssistant_DifferentText_AfterTurnEnd_CreatesNewEntry

Validation: build.ps1, Shared.Tests (1869 passed / 28 skipped), Tray.Tests (1193 passed).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kenehong kenehong force-pushed the kenehong/fix-duplicate-assistant-bubble branch from 758a0e9 to 4231fea Compare May 21, 2026 22:21
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
shanselman added a commit that referenced this pull request May 22, 2026
Includes PRs #498, #500, #501, #502, and #503.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@shanselman shanselman merged commit cc8c9e5 into openclaw:master May 22, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants