Relationship Explorer

How things connect, as an interactive graph you can pan, zoom and select from. Hierarchies, dependencies, cause and effect, networks.

Pattern

≈ 1,944 tokens per use (tool 914 · guidance 326 · typical payload 704)How token costs are estimated

Example: Relationship Explorer

Show the org chart under Dana.

Engineering under Dana Whitfield

Engineering under Dana Whitfield: 18 nodes and 17 links, drawn as a tree.

Dana Whitfield, VP Engineering, Engineering
Lee Okafor, Director, Platform
Marcus Hale, Eng manager, Developer tools
Sofia Brandt, Director, Product eng
Rosa Delgado, Eng manager, Mobile
Noah Fischer, Staff engineer, Product eng
Ahmed Saleh, Director, Data
Grace Kim, Head of security, Security
Ravi Patel, Security engineer, Security
  • Reports to

When to use

  • The answer is how things connect: an org chart, what depends on a service, what caused a metric to move, how companies or people are linked.
  • There are more links than a sentence or a list can carry, roughly 5 to 60 nodes.

When not to use

  • Things happen in order over time. Use a Timeline.
  • It's a plain list or a ranking with no links between items. Use a list or a Data Table.
  • There are only two or three nodes. Say it in a sentence.
  • The links are guesses. Only draw relationships that come from data.

How the agent should use it

  • Take nodes, links and health from tool results. Never invent a link.
  • Pick the layout for the shape of the data: tree when each node has one parent (org charts, folders), flow when links have a direction (dependencies, causes, pipelines), network for undirected connections (up to 40 nodes).
  • Use edge kinds so arrows read right: depends-on points at the dependency, reports-to points at the manager, causes points at the effect, blocks points at what's blocked, related has no arrow.
  • Set focusId to the node the user asked about; it starts selected, with its neighbours highlighted. Set rootId to the top of a tree.
  • Label cause-and-effect links with the evidence, such as "+38% errors". Keep labels short; long ones are cut on the canvas and shown in full on hover.
  • Only set selectable when the user's choice changes what you do next. On explain, explain that node and its links.
  • Lifecycle: for live data such as service health, set fetchedAt (and staleAfterMs) on the call so the Renderer marks it stale. Use supersede when you redraw the same graph with fresh data. expiresAt isn't needed.

Layouts

LayoutAlgorithmNotes
treeTidy tree (Reingold–Tilford, simplified): subtrees are packed so their outlines clear each other, and parents sit centred over their childrenfrom is the parent, except for reports-to, where to is. Three levels show; deeper subtrees start folded with a "+N" count, and focusing a deep node opens its branch. Several roots sit side by side; extra links that aren't part of the tree are drawn straight
flowLayered (Sugiyama-lite): longest-path layers from the sources, four barycenter sweeps to reduce crossings, curved edges through one waypoint per skipped layerA link that closes a loop is drawn dashed, running backwards, with a "Loop, drawn backwards" legend entry. rootId decides where reading starts, and so which link in a loop runs backwards
networkSmall force layout: a seeded start, a fixed number of iterations, then rotated to the card's long axis and nudged so no two nodes overlapThe same data always lands in the same place. Over 40 nodes it's drawn as a flow, with a note

Every layout is deterministic and lives in relationship-explorer-utils.ts, with no dependencies. direction sets which way trees and flows grow. Leave it out and they grow right, except that a flow in a card narrower than 560px is laid out both ways and keeps whichever is shown larger. Setting direction turns that off.

Reading the graph

  • Nodes show the label, the sublabel and kind, and health as an icon with a word ("Critical"). Text that doesn't fit is cut with an ellipsis; hovering shows it in full.
  • Edges are styled by kind, so they read without color: depends-on and plain links are solid arrows, causes is a thicker arrow, blocks is dashed, reports-to is a line without an arrow, and related is dotted. strength (0–1) makes a link thicker. The legend is one compact row under the graph and lists only the kinds and health states in the data. The only other text under the graph is a short data note when something wasn't drawn (over the node limit, unknown ids).
  • Selecting a node (click, tap or keyboard) keeps it and its neighbours at full strength and dims the rest. The panel under the graph shows its detail, its links grouped by meaning ("Depends on", "Used by", "Caused by"…) as buttons that move the selection, and an Open link when url is http(s).
  • Pan by dragging. Zoom with the buttons, Ctrl or ⌘ + scroll, or a pinch. A plain scroll wheel keeps scrolling the page. Fit zooms out to the whole graph.
  • The first view stays readable: the whole graph shows if it fits at 75% zoom or more. If it doesn't, the view starts at 75%, centred on focusId (or the root, or the first node), and you pan or press Fit for the overview. The canvas is as tall as the content at that zoom, between 280 and 520px. The view follows the stream and opened subtrees until you pan or zoom.
  • Problems are shown, not dropped: links to ids that aren't in nodes are listed under the graph, and so are nodes past the limit of 60.

Accessibility

The canvas is hidden from assistive tech. A visually hidden structure mirrors it and is the keyboard path:

  • Tree layout: a role="tree" with tree items (level, position and expanded state). Up and Down move, Right opens a branch or moves into it, Left closes it or moves to the parent, Home and End jump, Enter toggles a branch.
  • Flow and network: a role="listbox"; each option reads the node and its links, such as "Auth service, Identity team, service, Critical. Depends on Notifications, Users DB, Token cache and 1 more. Used by Admin console, API gateway, Orders and 3 more."

Selection follows focus, so moving through the list highlights the node on the canvas, draws a focus ring around it, and pans it into view. A short key hint shows over the canvas while the list has focus. Health is always an icon plus a word, never color alone, and transitions follow prefers-reduced-motion.

Installation

npx shadcn@latest add https://your-site.com/r/relationship-explorer.json

Usage

app/api/chat/route.ts
import { tool } from "ai"
import { relationshipExplorerTool } from "@/components/genui/relationship-explorer.schema"

const tools = {
  [relationshipExplorerTool.name]: tool({
    description: relationshipExplorerTool.description,
    inputSchema: relationshipExplorerTool.inputSchema,
  }),
}

Without selectable the graph is the whole answer, so give the tool an execute that returns immediately. With it, the detail panel adds Choose and Explain this, and the agent receives one of:

{ action: "select", nodeId: "auth" }
{ action: "explain", nodeId: "auth" }

With LangGraph

Push it from a graph node with ui.push({ name: "show_relationships", props: { toolCallId, ...args } }, { message }), and render the thread's UI messages with the Renderer.

Restoring from history

Pass the stored tool output as result. The explorer selects that node, shows what was sent, and never calls onResult again. Panning, zooming and browsing still work:

<RelationshipExplorer
  {...part.input}
  result={part.state === "output-available" ? part.output : undefined}
/>

Schema

PropTypeNotes
titlestring?
layout"tree" | "flow" | "network"
nodes{ id, label, sublabel?, kind?, health?, detail?, url? }[]1–60. Data-bound. kind: free text, up to 24 characters. health: ok, warning, critical, unknown. url: http(s) only
edges{ from, to, label?, kind?, strength? }[]Up to 200. Data-bound. kind: depends-on, reports-to, causes, related, blocks; omit for a plain arrow. strength 0–1
rootIdstring?Tree: the top node. Flow: where reading starts
focusIdstring?Selected at first
direction"down" | "right"Trees and flows. Omit it to grow right, with narrow cards choosing for flows
selectablebooleanAdds Choose and Explain this. Default false

Host props: status (streaming, ready, submitted), onResult, result and className.

Source

On this page