From e174126049c0d695ed42f216a986e88ed4ffca8a Mon Sep 17 00:00:00 2001 From: danielhanchen Date: Tue, 19 May 2026 14:27:12 +0000 Subject: [PATCH] studio/frontend: surface activity during between-tool gap A probe with Qwen3.6-27B UD-Q4_K_XL + Think+Search+Code on "Create a Python game" reproduced the user-reported "chat looks frozen" symptom: after the model emitted a one-line intent ("I'll create... Let me build it:"), neither GeneratingIndicator nor the existing RunningToolIndicator showed for ~10+ seconds while the model was choosing its first tool. GeneratingIndicator hides once content.length > 0 and the prior RunningToolIndicator only fires when a specific tool-call part has status == 'running'. Between those two phases (model writing tool-call decision tokens) the UI went silent and the only sign that work was in flight was the Stop button. Extend RunningToolIndicator to also fall back to a generic 'Working...' when the message status is still 'running' and at least one part has been emitted but no tool-call is currently running. The pulsing dot and aria-live region are unchanged; only the inner text differs. --- .../src/components/assistant-ui/thread.tsx | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/studio/frontend/src/components/assistant-ui/thread.tsx b/studio/frontend/src/components/assistant-ui/thread.tsx index 57e6c6ffb9..a7425df114 100644 --- a/studio/frontend/src/components/assistant-ui/thread.tsx +++ b/studio/frontend/src/components/assistant-ui/thread.tsx @@ -1016,23 +1016,37 @@ const CancelledIndicator: FC = () => { ); }; -// Pins the running tool's name to the bottom of the assistant bubble -// so activity stays visible after the tool group scrolls off-screen. +// Pins activity to the bottom of the assistant bubble so the chat +// doesn't look frozen during the gap between "model wrote intent" and +// "tool actually invoked", or between back-to-back tool calls. +// - When a tool-call part is currently `running`, shows the tool name. +// - When the message is still streaming but no tool is mid-execution +// (e.g. model is generating the tool-call decision tokens, or has +// just rendered the lead-in text "Let me build it:"), falls back to +// a neutral "Working..." so the user sees that work is still happening. const RunningToolIndicator: FC = () => { - const running = useAuiState(({ message }) => { + const state = useAuiState(({ message }) => { if (message.status?.type !== "running") return null; const parts = message.parts; + // Most recent running tool wins, if any. for (let i = parts.length - 1; i >= 0; i -= 1) { const p = parts[i] as | { type?: string; toolName?: string; status?: { type?: string } } | undefined; if (p?.type === "tool-call" && p.status?.type === "running") { - return p.toolName ?? "tool"; + return { kind: "tool" as const, name: p.toolName ?? "tool" }; } } + // No tool currently running, but message itself is still streaming. + // GeneratingIndicator only shows while content.length === 0, so once + // any text has rendered we lose its dots. Surface a generic "Working..." + // so the chat doesn't go silent between phases. + if (parts.length > 0) { + return { kind: "working" as const }; + } return null; }); - if (!running) return null; + if (!state) return null; return (
{ aria-hidden className="aui-running-tool-indicator-dot inline-block size-2 animate-pulse rounded-full bg-muted-foreground/60" /> - - Running {running}... - + {state.kind === "tool" ? ( + + Running {state.name}... + + ) : ( + Working... + )}
); };