fix(webui): align thinking and tool trace affordances

Tool trace groups are supporting details, so default them to collapsed.
Match the Thinking bubble's expanded body to the tool trace affordance by
using the same grouped header and animated fade/slide body treatment.

Update MessageBubble tests to assert tool traces start collapsed and expand
on click.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Xubin Ren 2026-05-13 07:58:24 +00:00
parent 521aaa5ecf
commit c7ec5d3b75
2 changed files with 10 additions and 8 deletions

View File

@ -386,14 +386,14 @@ interface TraceGroupProps {
/**
* Collapsible group of tool-call / progress breadcrumbs. Defaults to
* expanded for discoverability; a single click on the header folds the
* group down to a one-line summary so it never dominates the thread.
* collapsed because tool traces are supporting evidence, not the answer.
* A single click expands the exact calls when the user wants details.
*/
function TraceGroup({ message, animClass }: TraceGroupProps) {
const { t } = useTranslation();
const lines = message.traces ?? [message.content];
const count = lines.length;
const [open, setOpen] = useState(true);
const [open, setOpen] = useState(false);
return (
<div className={cn("w-full", animClass)}>
<button
@ -471,7 +471,7 @@ function ReasoningBubble({ text, streaming }: ReasoningBubbleProps) {
type="button"
onClick={onToggle}
className={cn(
"flex w-full items-center gap-2 rounded-md px-2 py-1.5",
"group flex w-full items-center gap-2 rounded-md px-2 py-1.5",
"text-xs text-muted-foreground transition-colors hover:bg-muted/45",
streaming && "reasoning-shimmer",
)}
@ -498,7 +498,8 @@ function ReasoningBubble({ text, streaming }: ReasoningBubbleProps) {
{open && text.length > 0 && (
<div
className={cn(
"mt-1 whitespace-pre-wrap break-words border-l border-muted-foreground/20 pl-3",
"mt-1 space-y-0.5 whitespace-pre-wrap break-words border-l border-muted-foreground/20 pl-3",
"animate-in fade-in-0 slide-in-from-top-1 duration-200",
"text-[12.5px] italic leading-relaxed text-muted-foreground/85",
)}
>

View File

@ -72,11 +72,12 @@ describe("MessageBubble", () => {
render(<MessageBubble message={message} />);
const toggle = screen.getByRole("button", { name: /used 2 tools/i });
expect(screen.getByText('weather("get")')).toBeInTheDocument();
expect(screen.getByText('search "hk weather"')).toBeInTheDocument();
expect(screen.queryByText('weather("get")')).not.toBeInTheDocument();
expect(screen.queryByText('search "hk weather"')).not.toBeInTheDocument();
fireEvent.click(toggle);
expect(screen.queryByText('weather("get")')).not.toBeInTheDocument();
expect(screen.getByText('weather("get")')).toBeInTheDocument();
expect(screen.getByText('search "hk weather"')).toBeInTheDocument();
});
it("renders video media as an inline player", () => {