Agent chat: Claude Code desktop's action rows under prompts and answers

Merged
TE
16d ago
+939-504

Stacked on #22658. Merge that one first; until then this diff also shows #22658's commits. The commits that belong to this PR are the last two: 97f5886 (tests) and 1629c8c (fix).

Problem

The action rows under messages don't match Claude Code desktop.

  • Under a prompt you get a lone bookmark icon on hover.
  • Under an answer, "4:48 PM ⧉ ↻ ⌄ ⤴" sits at the column's far right, away from the text it belongs to.

Change

  • Under a prompt (right-aligned under the bubble, UserBubble.tsx): the row is the prompt's age ("1 hour ago", with the exact time on hover, from Intl.RelativeTimeFormat in the pane's language), ✓✓ once delivered (not while pending), then Copy, Edit, Fork and Bookmark.
    • Edit and Fork show only where the chat can fork through the turn before the prompt. Fork forks there, as Edit's resend does.
    • Bookmark is now one item in the row instead of a lone icon.
  • Under an answer: the row moves to the left under the text, in Claude's order: time, Copy, Retry ⌄, Fork.
    • turnActionsPlacement now defaults to left in the web view and in Swift (AgentPaneTunables.turnActionsPlacement default .left). Debug "right" keeps the old right edge.
  • Visibility: the latest prompt's row and the last turn's row are always shown. Older ones show on hover or keyboard focus, as in Claude. VirtualTranscript marks data-last-prompt the way it already marks data-last-turn.
  • This overrides an earlier Leo decision for prompts. On 2026-10-13 Leo asked for one hover action per row (the hover-actions experiment). This PR deliberately shows Claude's full row for prompts, per the GUI-push brief from 2026-10-20. Other rows (queued prompts, channel messages) are unchanged.
  • Default change (the defaults guard will ask for a call owner): agentPane.debug.turnActionsPlacement goes from right to left.
  • #22340 overlaps. It is ownerless and also left-aligns the answer footer; this PR covers that part, plus the prompt row and the visibility rule. #22340's spinner fix is not included here.

Screenshots (gallery agent-pane.transcript/conversation; before = #22658 head, after = this branch)

Under a prompt (the latest prompt, no hover)

BeforeAfter
beforeafter

Under an answer

BeforeAfter
beforeafter

The Claude Code desktop reference isn't attached yet. I found no public screenshot of these rows, and capturing Leo's own Claude window would publish his chats. It will go here once one is supplied.

Verification

  • New test/user-message-actions.test.tsx:
    • the row reads "1 hour ago · Delivered · Copy · Edit · Fork from here", and Fork forks through the turn before the prompt;
    • a pending prompt has no ticks and no Fork;
    • relative time in en and de, including a time ahead of the minute clock reading "now".
  • Updated edit-resend, turn-actions-placement and agent-pane-merge-restore to the new defaults. These 11 tests and the conversation suites pass locally.
  • No local typecheck or Swift build on this Mac (a hook blocks tsc, and Mac builds are CI-only). CI covers both.
  • Localization: one new key, message.delivered, in all 21 locales. The relative time and absolute time come from Intl.

Agent session: cosmic-gray

🤖 Generated with Claude Code