affectUI › Components › Agents

Agent Graph

Agents and the tools they call as a living network – a pulse along the link for every call and its answer, busy links growing thicker, agents that breathe while they work and turn amber when they need you.

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

When to use

  • A live overview of a multi-agent system: which agents run, which tools and data sources they call, and how busy each link is
  • Spotting at a glance who waits for you, which call failed and where the traffic (and the cost) goes
  • A hero or status view next to a log or a chat – click a node to see what it does and its latest calls

When not to use

  • Who started whom, with status and cost per sub-agent – use Agent Tree
  • When things happened, in time order – use Agent Lanes
  • One agent's single tool call in detail – use Tool Call Card
  • Graphs with dozens of agents – the orbits are made for a handful of agents and up to a dozen tools

Usage

import { AgentGraph, type GraphNode, type GraphCall } from "@/components/ui/agent-graph";

const nodes: GraphNode[] = [
  { id: "lead", kind: "agent", name: "Orchestrator", detail: "Opus 5.5", status: "working", lead: true },
  { id: "research", kind: "agent", name: "Researcher", detail: "Sonnet 5.5", status: "working", cost: 0.12 },
  { id: "web", kind: "tool", name: "Web search", short: "Search" },
  { id: "notion", kind: "tool", name: "Notion", icon: <NotionLogo /> },
  { id: "you", kind: "user", name: "You" },
];

// Newest last – every new id sends a pulse; when "pending" turns "ok" or "error" the answer travels back
const calls: GraphCall[] = [
  { id: "c1", from: "lead", to: "research", at: Date.now() - 4000, status: "pending", label: "Compare pricing" },
  { id: "c2", from: "research", to: "web", at: Date.now() - 900, status: "ok", ms: 820, label: "pricing linear.app" },
];

export function Live() {
  return <AgentGraph nodes={nodes} calls={calls} edges={[["you", "lead"], ["research", "notion"]]} />;
}

Props

NameTypeDefaultDescription
nodesGraphNode[]{ id, name, kind, short?, icon?, detail?, status?, doing?, cost?, lead? } – every agent, tool and user; pass the whole list each time, ids keep nodes in place and new ids grow in
kind"agent" | "tool" | "user"Per node – agents sit on the inner orbit (the lead in the middle), tools and you on the outer one, each turned towards the agents it talks to
status"idle" | "working" | "waiting" | "error" | "done"Per node – working agents breathe, waiting turns amber ("Needs you"), error red; waiting and error also show a chip in the bar
shortstringPer node – a shorter label for narrow containers, e.g. "Search"
iconReactNodePer node – a logo or mark; defaults to the initials (a person for the user)
detail / doingstringPer node – the model or what a tool is (under the agent's name and in its card), and what it is doing right now (in its card)
costnumberPer node – what it has cost so far; the bar sums all nodes
leadbooleanfirst agentPer node – the agent in the middle
callsGraphCall[][]{ id, from, to, at, status?, label?, ms? } – recent calls, newest last. A new id sends a pulse from → to; when its status turns "ok" the answer travels back as a hollow dot, "error" comes back red and flashes the link. Calls also create the links they need
edges[string, string][][]Links that are always there, even before their first call
nownumberDate.now()The clock for calls per minute and link heat – without it the graph ticks every second
heatWindownumber20000How far back (ms) calls count towards a link's thickness – the busiest link is about 4px, a quiet one 1.25px
onSelect(node: GraphNode | null) => voidA node was clicked (its card opens) – null when the card closes
heightnumberfits the widthFixed height of the graph in px – by default 0.6 × the width (360–520px) when wide, 1.2 × when narrow
formatCost(amount: number) => stringdollars, e.g. "$0.42"Formats every cost
titlestring"Agent graph"Heading of the bar
classNamestringExtra class on the root

Keyboard

  • Tab: Moves between the nodes (and the "needs you" / "failed" chips); a focused node lights up its neighbourhood
  • Enter / Space: Opens or closes the focused node's card
  • Esc: Closes the card and returns focus to its node

Accessibility

  • Every node is a button labelled with its name, kind, status, what it does and its calls in the last minute; aria-expanded tells whether its card is open
  • The card is a dialog; its close button takes focus, Esc closes it
  • A visually hidden list gives the same picture as text: every node, its status, whom it called how often in the last minute and its cost
  • "needs you" and "failed" chips sit in a polite live region, so a waiting or failed agent is announced
  • Status is never color alone: waiting and failed agents get a badge (clock, exclamation mark) and a text line under the name

Responsive

  • The width is measured with a ResizeObserver and the whole layout is computed from it – orbits, node sizes and label room
  • Below 520px the graph turns taller than wide, nodes get smaller, labels use their short names, the model line is left out and the card docks to the bottom of the graph
  • Labels and the outer orbit always stay inside the panel – nothing is cut off and nothing scrolls sideways, down to 320px
  • 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
  • Tool Call Card – An agent's tool call in one line – live timer, status and summary, folds open to highlighted arguments and result with copy, retry on errors and a group that sums them up
  • Integration Picker – Integrations page of a command menu – search, a list of services and the picked one with its connection on two tiles

Guides