From 601c1f16cb9bddcac2291283536e2fb6ab96a896 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Tue, 14 Jul 2026 21:01:59 -0400 Subject: [PATCH] fix(desktop): keep clarify prompts out of tool overflow Treat clarify as a hard boundary for bounded tool runs so interactive forms remain fully visible and usable. --- .../components/assistant-ui/tool/fallback.test.ts | 13 +++++++++++++ .../src/components/assistant-ui/tool/fallback.tsx | 14 +++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 apps/desktop/src/components/assistant-ui/tool/fallback.test.ts diff --git a/apps/desktop/src/components/assistant-ui/tool/fallback.test.ts b/apps/desktop/src/components/assistant-ui/tool/fallback.test.ts new file mode 100644 index 000000000000..008e701b23cf --- /dev/null +++ b/apps/desktop/src/components/assistant-ui/tool/fallback.test.ts @@ -0,0 +1,13 @@ +import { describe, expect, it } from 'vitest' + +import { shouldBoundToolGroup } from './fallback' + +describe('shouldBoundToolGroup', () => { + it('bounds long runs of ordinary tool calls', () => { + expect(shouldBoundToolGroup(3, false)).toBe(true) + }) + + it('never bounds a run containing clarify', () => { + expect(shouldBoundToolGroup(3, true)).toBe(false) + }) +}) diff --git a/apps/desktop/src/components/assistant-ui/tool/fallback.tsx b/apps/desktop/src/components/assistant-ui/tool/fallback.tsx index a501b7c9ee0e..f40ff7693f50 100644 --- a/apps/desktop/src/components/assistant-ui/tool/fallback.tsx +++ b/apps/desktop/src/components/assistant-ui/tool/fallback.tsx @@ -611,6 +611,10 @@ function ToolEntry({ part }: ToolEntryProps) { // auto-scrolling window; fewer than this stays a plain inline stack. const TOOL_GROUP_SCROLL_THRESHOLD = 3 +export function shouldBoundToolGroup(childCount: number, containsClarify: boolean) { + return childCount >= TOOL_GROUP_SCROLL_THRESHOLD && !containsClarify +} + // Pin-to-bottom + top-fade for the bounded tool window. Pins the newest row on // growth (a call lands or a row expands) unless the user scrolled up, and fades // the top edge once anything sits above it. Mirrors ThinkingDisclosure's live @@ -678,13 +682,21 @@ function useToolWindow(enabled: boolean) { */ export const ToolGroupSlot: FC> = ({ children, + endIndex, startIndex }) => { const messageId = useAuiState(s => s.message.id) const messageRunning = useAuiState(selectMessageRunning) + + const containsClarify = useAuiState(s => + s.message.parts + .slice(Math.max(0, startIndex), endIndex + 1) + .some(part => part.type === 'tool-call' && part.toolName === 'clarify') + ) + const enterRef = useEnterAnimation(messageRunning, `tool-group:${messageId}:${startIndex}`) - const bounded = Children.count(children) >= TOOL_GROUP_SCROLL_THRESHOLD + const bounded = shouldBoundToolGroup(Children.count(children), containsClarify) const { contentRef, faded, onScroll, scrollRef } = useToolWindow(bounded) return (