Compare commits

...

1 Commits

Author SHA1 Message Date
Ethan Dickson 0fc37494be feat(site/ai-elements): add background process indicator to execute tool
Show a LayersIcon with a "Running in background" tooltip on execute
tool calls that returned a background_process_id. The icon sits in
the header controls area next to the spinner/copy button and is
always visible (not hover-gated) since it conveys meaningful status.

Detection is purely derived from the existing result payload — no
polling or new state management required.
2026-03-26 11:53:18 +00:00
3 changed files with 34 additions and 1 deletions
@@ -51,6 +51,21 @@ export const ExecuteSuccess: Story = {
},
};
export const ExecuteBackgrounded: Story = {
args: {
result: {
output: "",
background_process_id: "proc-abc-123",
},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(canvas.getByText("$ git fetch origin")).toBeTruthy();
// The layers icon should be present as the background indicator.
expect(canvasElement.querySelector(".lucide-layers")).not.toBeNull();
},
};
export const ExecuteAuthRequired: Story = {
args: {
result: {
@@ -3,6 +3,7 @@ import {
ChevronDownIcon,
CircleAlertIcon,
ExternalLinkIcon,
LayersIcon,
LoaderIcon,
TriangleAlertIcon,
} from "lucide-react";
@@ -12,6 +13,11 @@ import { cn } from "utils/cn";
import { Button } from "#/components/Button/Button";
import { CopyButton } from "#/components/CopyButton/CopyButton";
import { ScrollArea } from "#/components/ScrollArea/ScrollArea";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "#/components/Tooltip/Tooltip";
import {
BORDER_BG_STYLE,
COLLAPSED_OUTPUT_HEIGHT,
@@ -28,7 +34,8 @@ export const ExecuteTool: React.FC<{
output: string;
status: ToolStatus;
isError: boolean;
}> = ({ command, output, status }) => {
isBackgrounded?: boolean;
}> = ({ command, output, status, isBackgrounded = false }) => {
const [expanded, setExpanded] = useState(false);
const outputRef = useRef<HTMLPreElement | null>(null);
const hasOutput = output.length > 0;
@@ -60,6 +67,14 @@ export const ExecuteTool: React.FC<{
{isRunning && (
<LoaderIcon className="h-3.5 w-3.5 shrink-0 animate-spin motion-reduce:animate-none text-content-secondary" />
)}
{isBackgrounded && !isRunning && (
<Tooltip>
<TooltipTrigger asChild>
<LayersIcon className="h-3.5 w-3.5 shrink-0 text-content-secondary" />
</TooltipTrigger>
<TooltipContent>Running in background</TooltipContent>
</Tooltip>
)}
<span className="opacity-0 transition-opacity group-hover/exec:opacity-100">
<CopyButton text={command} label="Copy command" />
</span>
@@ -102,6 +102,8 @@ const ExecuteRenderer: FC<ToolRendererProps> = ({
rec ? asString(rec.provider_type).trim() : "",
);
const backgroundProcessId = rec ? asString(rec.background_process_id) : "";
if (authRequired && authenticateURL) {
return (
<ExecuteAuthRequiredTool
@@ -118,6 +120,7 @@ const ExecuteRenderer: FC<ToolRendererProps> = ({
output={output}
status={status}
isError={isError}
isBackgrounded={backgroundProcessId.length > 0}
/>
);
};