23 / 37 · Agents
Agent status
One pill that always answers: what is it doing, and for how long.
Refactoring composer0s
Installation
npx shadcn@latest add "@assistant-ui/elements-agent-status"
Usage
import { AgentStatus } from "@/components/elements/agent-status";
<AgentStatus state="working" label="Editing composer.tsx" elapsed="8s" />Props
state*AgentStateVisual mode of the pill: working, waiting, or done with a check.
label*stringShort status line describing what the agent is doing.
elapsedstringElapsed time shown in mono when provided.
classNamestringExtra classes merged onto the root.
Source
agent-status.tsx"use client";
import { CheckIcon, PauseIcon, RotateCcwIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { ghostButton, mono, paper } from "./surfaces";
export type AgentState = "working" | "waiting" | "done";
export interface StatusStep {
state: AgentState;
label: string;
}
export function AgentStatus({
state,
label,
elapsed,
className,
}: {
state: AgentState;
label: string;
elapsed?: string;
className?: string;
}) {
return (
<div
className={cn(
paper,
"flex items-center gap-2.5 rounded-full py-1.5 ps-3.5 pe-1.5",
className,
)}
>
{state === "done" ? (
<CheckIcon aria-hidden className="size-3 shrink-0 text-emerald-500" />
) : (
<span
aria-hidden
className={cn(
"size-1.5 shrink-0 rounded-full motion-reduce:animate-none",
state === "working"
? "animate-pulse bg-blue-500 dark:bg-blue-400"
: "bg-foreground/25 animate-pulse",
)}
/>
)}
<span
key={label}
className="fade-in blur-in-[2px] animate-in max-w-44 truncate text-xs duration-300 motion-reduce:animate-none"
>
{label}
</span>
{elapsed !== undefined && state !== "done" && (
<span className={cn(mono, "text-foreground/30 tabular-nums")}>
{elapsed}
</span>
)}
<button
type="button"
aria-label={state === "done" ? "Run again" : "Pause agent"}
className={cn(ghostButton, "size-6")}
>
{state === "done" ? (
<RotateCcwIcon className="size-3" />
) : (
<PauseIcon className="size-3" />
)}
</button>
</div>
);
}