Observability
Tool Call Graph
An agent fanned out to the tools it calls — calls, latency and error rate per edge, with the hottest path picked out.
1 variantMIT
Preview
Tool call graph
triage-l · v14 · last 24 h · 11,857 calls
triage-l · v14
agent · 3.1k runs
- Calls / run
- 3.8
- Tool share of latency
- 63%
- Retries
- 173 · 1.5%
- Hot path
- refund.create → email.send
Highest call volume: crm.lookup
Installation
Copies the component into components/ui and installs its dependencies and theme tokens.
pnpm dlx shadcn@latest add https://tuffui.com/r/tool-call-graph.jsonUsage
Pass your own data and wire the callbacks to your agent runtime.
import { ToolCallGraph } from "@/components/ui/tool-call-graph";
export function AgentTools({ agent, window }: { agent: Agent; window: ToolStats[] }) {
const calls = window.reduce((sum, t) => sum + t.calls, 0);
return (
<ToolCallGraph
subtitle={`${agent.name} · ${agent.version} · last 24 h · ${calls.toLocaleString()} calls`}
agent={{ label: `${agent.name} · ${agent.version}`, meta: `agent · ${agent.runs} runs` }}
tools={window.map((t) => ({
id: t.tool,
label: t.tool, // "refund.create"
calls: t.calls,
p50Ms: t.p50,
errorRate: t.failed / t.calls, // 0…1
retries: t.retries,
}))}
stats={[
{ label: "Calls / run", value: (calls / agent.runs).toFixed(1) },
{ label: "Hot path", value: "refund.create → email.send", accent: true },
]}
onSelect={(id) => openToolTraces(id)}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| agent* | { label: string; meta?: string } | — | The caller drawn on the left. `meta` is a short second line, e.g. run count. Narrow cards show only its icon. |
| tools* | ToolCallNode[] | — | One node per tool, drawn top to bottom in array order. The order never changes with the metric, so nodes stay put while edges re-weigh. |
| metric | "calls" | "latency" | "errors" | — | Controlled metric. Edge width and opacity scale with it, against the tool with the most of it. |
| defaultMetric | "calls" | "latency" | "errors" | "calls" | Starting metric when uncontrolled. |
| onMetricChange | (metric: ToolCallMetric) => void | — | Called when the Calls / Latency / Errors switch changes. |
| highlight | string | null | top tool for the metric | Tool to pick out with a tinted node and a flowing edge. Left out, it follows the metric; `null` turns it off. |
| errorThreshold | number | 0.02 | Error rate from which a tool reads as failing: red dot, red error chip, and a red pick in the Errors view. |
| title | string | "Tool call graph" | Header title. |
| subtitle | string | "<agent> · <calls> calls" | Secondary line under the title. |
| stats | ToolCallStat[] | calls, error rate, retries | Footer row. Pass `[]` to hide it. `accent` draws a value in the accent colour, e.g. a hot path. |
| formatLatency | (ms: number) => string | "212 ms" / "1.8 s" | Formats p50 latency on the nodes. |
| onSelect | (id: string) => void | — | Called when a tool node is clicked or pressed. Hover and focus highlight the node's edge on their own. |
| className | string | — | Extra classes for the root element. |
type ToolCallNode = {
id: string;
label: string; // tool name
calls: number; // calls in the window
p50Ms: number; // median latency, ms
errorRate: number; // 0…1
retries?: number;
};
type ToolCallStat = {
label: string;
value: ReactNode;
accent?: boolean;
};