22 / 37 · Agents
Subagent list
Parallel workers with their own progress, models, and completions.
Explore the runtimehaiku
Fix composer typessonnet
Write regression testssonnet
Installation
npx shadcn@latest add "@assistant-ui/elements-subagent-list"
Usage
import { SubagentList } from "@/components/elements/subagent-list";
<SubagentList
agents={[{ name: "Researcher", model: "Sonnet" }]}
completedCount={0}
progress={[40]}
showSummary={false}
summaryAgent={{ name: "Summarizer", model: "Haiku" }}
/>Props
agents*readonly SubagentItem[]Parallel workers shown as cards with name and model.
completedCount*numberHow many agents from the start are marked complete.
progress*readonly number[]Per-agent progress widths used while a worker is still running.
showSummary*booleanWhen true the summary agent card is revealed under the list.
summaryAgent*SubagentItemAgent shown in the summary card once showSummary is true.
classNamestringExtra classes merged onto the root.
Source
subagent-list.tsx"use client";
import { CheckIcon, Loader2Icon } from "lucide-react";
import { cn } from "@/lib/utils";
import { mono, paper } from "./surfaces";
export interface SubagentItem {
name: string;
model: string;
}
export function SubagentList({
agents,
completedCount,
progress,
showSummary,
summaryAgent,
className,
}: {
agents: readonly SubagentItem[];
completedCount: number;
progress: readonly number[];
showSummary: boolean;
summaryAgent: SubagentItem;
className?: string;
}) {
return (
<div
className={cn(
"flex min-h-[14.5rem] w-full max-w-xs flex-col gap-2",
className,
)}
>
{agents.map((agent, index) => {
const done = index < completedCount;
const width = progress[index] ?? 0;
return (
<div
key={agent.name}
className={cn(
paper,
"flex flex-col gap-2 rounded-2xl px-3.5 py-2.5",
)}
>
<div className="flex items-center gap-2">
{done ? (
<CheckIcon className="fade-in zoom-in-90 animate-in size-3.5 shrink-0 text-emerald-500 duration-200" />
) : (
<Loader2Icon className="text-foreground/35 size-3.5 shrink-0 animate-spin motion-reduce:animate-none" />
)}
<span className="flex-1 truncate text-[13.5px]">
{agent.name}
</span>
<span className={cn(mono, "text-foreground/35")}>
{agent.model}
</span>
</div>
<span className="bg-foreground/[0.06] h-[3px] w-full overflow-hidden rounded-full">
<span
className={cn(
"block h-full rounded-full transition-[width] duration-700",
done ? "bg-emerald-500/70" : "bg-foreground/60",
)}
style={{ width: `${width}%` }}
/>
</span>
</div>
);
})}
{showSummary && (
<div
className={cn(
paper,
"fade-in slide-in-from-bottom-2 animate-in flex flex-col gap-2 rounded-2xl px-3.5 py-2.5 duration-300",
)}
>
<div className="flex items-center gap-2">
<Loader2Icon className="text-foreground/35 size-3.5 shrink-0 animate-spin motion-reduce:animate-none" />
<span className="flex-1 truncate text-[13.5px]">
{summaryAgent.name}
</span>
<span className={cn(mono, "text-foreground/35")}>
{summaryAgent.model}
</span>
</div>
<span className="bg-foreground/[0.06] h-[3px] w-full overflow-hidden rounded-full">
<span
className="bg-foreground/60 block h-full rounded-full transition-[width] duration-700"
style={{ width: "42%" }}
/>
</span>
</div>
)}
</div>
);
}