affectUI › Components › Agents

Agent Fleet

Several agents side by side – each card sums up its sub-agents, and a click opens its tree to the right while the last one folds back into its card.

Part of affectUI Pro. Install: npx shadcn@latest add https://www.affectui.com/r/agent-fleet.json · Import from @/components/ui/agent-fleet

When to use

  • Several agents working at the same time – a launch, the support queue, a release – each with sub-agents of its own
  • Seeing at a glance which agent needs you, which one failed and what the whole fleet costs – without every tree open at once
  • A fleet overview on a dashboard: one tree open, the others folded to a single card

When not to use

  • One run with one orchestrator – use Agent Tree
  • When things happened, in time order – use Agent Lanes
  • Handing tasks to agents yourself – use Delegate Board

Usage

import { AgentFleet, type FleetAgent } from "@/components/ui/agent-fleet";

const fleet: FleetAgent[] = [
  {
    id: "launch", name: "Launch lead", model: "Opus 5.5", task: "Launch the new pricing page",
    status: "running", cost: 0.42, started: Date.now() - 840_000,
    children: [
      { id: "research", name: "Researcher", task: "Compare five competitors", status: "done", cost: 0.31, started: Date.now() - 780_000, ended: Date.now() - 360_000 },
      { id: "copy", name: "Writer", task: "Write the plan copy", status: "waiting", cost: 0.18, started: Date.now() - 720_000 },
    ],
  },
  { id: "support", name: "Support lead", task: "Answer the open tickets", status: "running", cost: 0.12, started: Date.now() - 1_560_000 },
];

export function Fleet() {
  return <AgentFleet agents={fleet} onSelect={(agent) => openLog(agent.id)} />;
}

Props

NameTypeDefaultDescription
agentsFleetAgent[]{ id, name, task, model?, avatar?, tools?, status, steps?, cost?, started?, ended?, children? } – the main agents, each with its sub-agents; pass them again whenever something changes; tools are small marks shown as overlapping tiles before the task
stepsFleetStep[]Per sub-agent, { title, status?, tool?, took? } – the tasks it worked through; a click on its card opens them in a small window
status"queued" | "running" | "waiting" | "done" | "failed" | "stopped"Per agent – "waiting" reads "Needs you"; queued and stopped sub-agents and their connectors are muted
costnumberPer agent, its own cost – a main agent shows its whole branch, the bar the whole fleet
open / defaultOpenstring | nullthe first agentId of the main agent whose tree is open, controlled or uncontrolled – null folds them all
onOpenChange(id: string | null) => voidAn agent was opened – or folded with a second click
ask / errorstringPer sub-agent – what a waiting one needs you to decide, and what went wrong for a failed one; shown at the top of its window above Approve and Reject, or Retry and Dismiss
onResolve(agent, action: "approve" | "reject" | "retry" | "dismiss") => voidAn answer for a sub-agent that needs you or failed – update its status in your data; without it, those cards get no Answer or Resolve button
onSelect(agent: FleetAgent) => voidA click on a sub-agent – makes the sub-agent cards clickable; one with steps opens its tasks window as well
nownumberDate.now()The clock for running times – without it the cards tick every second while an agent runs
formatCost(amount: number) => stringdollars, e.g. "$0.42"Formats every cost
titlestring"Agents"Heading of the bar
classNamestringExtra class on the root

Keyboard

  • ↑ / ↓: Moves between the main agents
  • Home / End: Jumps to the first or the last main agent
  • Enter / Space: On a main agent: opens its tree, or folds it when it's open – on a sub-agent: opens or closes its tasks window
  • Tab: Moves on into the open tree's cards – those with steps, an answer to give or onSelect; in an answer window, Approve or Retry has focus and Tab reaches the other
  • Esc: Closes the tasks window and puts focus back on its card

Accessibility

  • Every main agent is a button with aria-expanded, pointing at the open tree with aria-controls
  • The open tree is a tree labelled "Sub-agents of …"; every sub-agent is a treeitem labelled with its name and status
  • The totals in the bar – agents, running, needs you, cost – are announced politely when they change
  • Status is never color alone: every card spells it out, and the phrase under each main agent says what the ring shows
  • The small Answer or Resolve button on a card is a pointer shortcut – keyboard users open the same window from the card itself
  • A sub-agent with steps, or one that needs you or failed, has aria-haspopup and aria-expanded; its tasks window is a dialog labelled "Tasks of …", closed by Esc or a click elsewhere

Responsive

  • Wide enough for the column, a gap and the deepest tree, the tree opens to the right of the column
  • Narrower, the tree opens under its card and pushes the agents below down – and folds back up before the next one opens
  • Every card has a fixed height – one line of task, one line of numbers – so nothing jumps when a status changes
  • Dark mode built in: switches when an ancestor (usually <html>) has the class dark or data-theme="dark"

Requirements

  • React 19

Related

  • Agent Tree – Who started whom – an orchestrator and its sub-agents as a live tree, with status, cost and time on every card, costs rolling up each branch, and branches that fold to one line
  • Agent Lanes – Where every agent is right now – a live timeline with a lane per agent, tasks growing into “now”, hand-offs drawn between agents and approvals right on the block
  • Agent Monitor – One agent at work, as a card – its current step with a clock and the bill so far, a time strip and the finished steps with the logo of each tool, a click on any of them for the details; the exact command when it needs your OK; folds into a small bar with the tools it has used
  • Delegate Board – Hand work to your agents by dragging it onto them – each agent previews its new “busy until” time, or switch to Auto and every new task goes to whoever is free first