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.
This commit is contained in:
parent
bede230999
commit
e174126049
1 changed files with 26 additions and 8 deletions
|
|
@ -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 (
|
||||
<div
|
||||
data-slot="running-tool-indicator"
|
||||
|
|
@ -1043,9 +1057,13 @@ const RunningToolIndicator: FC = () => {
|
|||
aria-hidden
|
||||
className="aui-running-tool-indicator-dot inline-block size-2 animate-pulse rounded-full bg-muted-foreground/60"
|
||||
/>
|
||||
<span>
|
||||
Running <span className="font-mono text-xs">{running}</span>...
|
||||
</span>
|
||||
{state.kind === "tool" ? (
|
||||
<span>
|
||||
Running <span className="font-mono text-xs">{state.name}</span>...
|
||||
</span>
|
||||
) : (
|
||||
<span>Working...</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue