Skip to content

[codex] keep completed assistant copy actions visible - #4107

Open
maxwellyoung wants to merge 1 commit into
pingdotgg:mainfrom
maxwellyoung:codex/fix-assistant-copy-button-visibility
Open

[codex] keep completed assistant copy actions visible#4107
maxwellyoung wants to merge 1 commit into
pingdotgg:mainfrom
maxwellyoung:codex/fix-assistant-copy-button-visibility

Conversation

@maxwellyoung

@maxwellyoung maxwellyoung commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Fixes #4046

Problem

The completed assistant-message footer is hidden with opacity-0 until its row is hovered or focused. When someone selects response text and moves outside the row, the footer fades out and the copy action disappears before it can be used. The same hover dependency also makes the action undiscoverable on non-hover inputs.

Root cause

AssistantTimelineRow correctly limits copy controls to eligible completed assistant messages through the existing copy-state logic, but the containing footer adds a second presentation constraint: hover-only opacity. That constraint hides an otherwise valid action based on pointer position.

Fix

  • Keep the footer for eligible completed assistant messages visible.
  • Preserve the existing state logic that omits the action for streaming, empty, and non-terminal assistant messages.
  • Add a regression test proving that the completed assistant copy action is rendered without hover-dependent opacity.

Validation

  • pnpm --filter @t3tools/web test -- src/components/chat/MessagesTimeline.test.tsx — 151 files and 1,318 tests passed
  • vp check — passes with 10 existing warnings outside this diff
  • vp run typecheck
  • git diff --check

Visual verification

The issue recording demonstrates the before-state: the completed-message footer disappears after the pointer leaves the assistant row.

The after-state below was captured from the full local app with the pointer moved away from the assistant row. The copy action and timestamp remain visible; the footer's computed opacity is 1.

Completed assistant footer remains visible

Web/shared impact

This changes only the presentation of the completed assistant-message footer in the web/desktop chat timeline. Message state, copy behavior, streaming behavior, server communication, native mobile code, and shared contracts are unchanged.

Migration/deploy impact

None. There are no schema, migration, API, auth, session, realtime transport, or deployment configuration changes.

Post-deploy smoke check

  1. Complete an assistant response.
  2. Select some response text and move the pointer outside the message row.
  3. Confirm the footer and copy action remain visible and usable.
  4. Confirm streaming and non-terminal assistant messages still omit the copy action.

Note

Keep completed assistant message copy actions persistently visible

Previously, the assistant message footer (copy link button and timestamp) was hidden behind hover/focus opacity transitions. The footer in AssistantTimelineRow now renders with full opacity when showAssistantMeta is true, removing the opacity-0 and hover/focus classes. A data-assistant-message-footer="persistent" attribute is added to the wrapper div to reflect this behavior change.

Macroscope summarized 89af03c.


Note

Low Risk
Presentation-only change in the web chat timeline; copy eligibility and server behavior are unchanged.

Overview
Fixes #4046 by changing how the completed assistant-message footer is shown in AssistantTimelineRow.

When showAssistantMeta is true, the footer (copy link and timestamp) no longer uses opacity-0 with group-hover / focus-within transitions. It stays visible so copy stays usable after selecting text and moving the pointer away, and on inputs without hover. Eligibility is unchanged—streaming and non-terminal assistant rows still omit this footer via existing timeline logic.

A data-assistant-message-footer="persistent" marker tags the footer for tests. MessagesTimeline.test.tsx adds buildAssistantTimelineEntry and asserts the copy control is present and not paired with hover-only opacity-0.

Reviewed by Cursor Bugbot for commit 89af03c. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions github-actions Bot added the vouch:unvouched PR author is not yet trusted in the VOUCHED list. label Jul 17, 2026
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 93cff6da-3b63-40dc-95db-d56d25549f11

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the size:XS 0-9 changed lines (additions + deletions). label Jul 17, 2026
@maxwellyoung
maxwellyoung marked this pull request as ready for review July 17, 2026 22:41
@macroscopeapp

macroscopeapp Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved

This is a minor UI adjustment that makes assistant message copy actions always visible instead of requiring hover. The change is limited to CSS classes with proper test coverage and no runtime logic changes.

You can customize Macroscope's approvability policy. Learn more.

@juliusmarminge
juliusmarminge force-pushed the codex/fix-assistant-copy-button-visibility branch from 1479e5d to 89af03c Compare August 15, 2026 11:02

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small follow-ups on the assistant footer visibility change: an orphaned group/assistant marker and an assertion that cannot fail.

Posted via Macroscope — UI Consistency

Comment on lines +1127 to +1130
<div
className="mt-1.5 flex items-center gap-2 text-xs tabular-nums"
data-assistant-message-footer="persistent"
>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropping group-hover/assistant:opacity-100 here leaves the group/assistant marker on the row wrapper (line 935) with no consumer anywhere in the repo, so the row still advertises a hover group that nothing reacts to. Consider removing that marker in the same change so hover ownership stays truthful.

-        row.kind === "message" && row.message.role === "assistant" ? "group/assistant" : null,

Posted via Macroscope — UI Consistency


expect(markup).toContain('aria-label="Copy link"');
expect(markup).toContain('data-assistant-message-footer="persistent"');
expect(markup).not.toMatch(/data-assistant-message-footer="persistent"[^>]*opacity-0/);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guard can never fail: React emits className before the data attribute, so the rendered tag is <div class="mt-1.5 ..." data-assistant-message-footer="persistent"> and opacity-0 can never appear after the marker within the same tag. If the hover-gating classes were reintroduced, this assertion would still pass. Matching the whole tag keeps the guard meaningful.

Suggested change
expect(markup).not.toMatch(/data-assistant-message-footer="persistent"[^>]*opacity-0/);
expect(markup).not.toMatch(/<div[^>]*opacity-0[^>]*data-assistant-message-footer="persistent"/);

Posted via Macroscope — UI Consistency

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

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: copy button goes invisible

1 participant