agent chat: every reply keeps its action row, whatever follows it

Merged
TE
7d ago
+632-71

Every finished assistant reply keeps its action row (Copy, Pin, Read aloud, More, its age) whenever something follows it: a steer, another agent's message, a "Sent message to …" row or a tool row. A steer waiting for the agent gets Copy too.

Leo, 2026-10-29: "i feel like im frequently missing the copy/whatever buttons on these steers... but claude code allows those buttons in these situations. let's have those"

Why it was missing

A reply's only action row was its turn's footer (TurnFooter). The footer comes at the turn's end and copies only the final answer. A steer, an incoming message, a sent-message row or a tool row continues the turn, so a reply before one of them had no row at all. Incoming lines already had Copy (ReceivedActions). A waiting steer had only Send now and āœ•.

Fix

  • model.ts: hasReplyActions(row, next) decides each reply from the row drawn after it. A finished reply with text gets its row unless one of these holds:

    • nothing follows it yet;
    • the row after it is its turn's footer, which serves it;
    • it sits right over the running line that the footer replaces (isBeforeFooter).

    So the turn's end moves nothing above it. The layout's row edge key carries the flag, which makes the height cache and re-placement notice when a later row arrives. turns.ts is unchanged, so no turn-wide pass runs per token.

  • App.tsx: each drawn row gets the flag in O(1):

    • RowFrame takes replyActions, compares it in its memo, and re-measures when it changes;
    • drawn heights carry the flag, both from the frame and from the resize observer;
    • placement drops a drawn height whose flag no longer matches, and re-places from the last reply whose flag changed.
  • MessageActions.tsx: a new ReplyActions row (Copy, Pin, Read aloud, More, age) in the footer's cv-turn-actions look, drawn by MessageRow. It has no Fork, because assistant rows carry no seq.

  • CSS: the row's space is always kept and it shows on hover or keyboard focus, as the other action rows do, so nothing jumps on hover. The estimate is 28 px: a 4 px gap plus a 24 px row.

  • PendingSteer.tsx: a waiting steer shows Copy after Send now and āœ•. Send now still leads the action row.

Visible change: a reply that now has the row is 28 px taller even when not hovered.

Gallery

agent-pane.reply-actions has four versions, each hovered so its row shows: after-steer, after-incoming, after-sent and steer-waiting. The before/after stills come from the gallery advisory run on this PR.

Tests

Observed / Not run

  • Observed: the runs above.
  • Not run: gallery stills (they come from the advisory run). No native build is needed, because the change is webview-only.

Changelog

Fixed: A reply followed by a steer, another agent's message or a sent message keeps its Copy, Pin and Read aloud buttons, and a waiting steer can be copied.

Agent session: agent session

šŸ¤– Generated with Claude Code