From 09bcf5a9370e8bc60e1d0a784c360b9721fc0256 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Thu, 11 Jun 2026 22:27:39 -0500 Subject: [PATCH] fix(desktop): move tool-row copy control into expanded body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-row copy control lived in the header's trailing slot as a 24px button that depended on a `group-hover/tool-row` group that exists nowhere in the tree. It therefore stayed `opacity-0` yet remained clickable — an invisible hit-target straddling the disclosure caret and duration, making the caret hard to click without firing a copy. Move copy into the expanded body's top-right (matching the code-block convention) where it can't fight the caret for the right edge, and make it actually visible (subtle at rest, full on hover/focus). The header right edge now belongs solely to the duration label + caret. Tradeoff: copy is only reachable once a row is expanded; rows with no expandable body no longer surface a copy control. --- .../components/assistant-ui/tool-fallback.tsx | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/components/assistant-ui/tool-fallback.tsx b/apps/desktop/src/components/assistant-ui/tool-fallback.tsx index 391510f71bf..b5d65b5571e 100644 --- a/apps/desktop/src/components/assistant-ui/tool-fallback.tsx +++ b/apps/desktop/src/components/assistant-ui/tool-fallback.tsx @@ -279,11 +279,14 @@ function ToolEntry({ part }: ToolEntryProps) { const copyAction = useMemo(() => toolCopyPayload(part, view), [part, view]) + // The header trailing slot only carries the live duration timer while the + // tool is running. The copy control used to live here too, but an + // `opacity-0` (yet still clickable) button straddling the caret/duration made + // the disclosure caret hard to hit. Copy now lives in the expanded body's + // top-right, where it can't fight the caret for the right edge. const trailing = isPending && !embedded ? ( - ) : !isPending && copyAction.text ? ( - ) : undefined return ( @@ -322,7 +325,18 @@ function ToolEntry({ part }: ToolEntryProps) { {isPending && } {open && ( -
+
+ {copyAction.text && ( + + )} {!embedded && view.previewTarget && isPreviewableTarget(view.previewTarget) && ( )}