@tangle-network/charts 2.0.13 → 2.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,491 @@
1
+ import { D as statusMeta, O as createLucideIcon, T as RunStatusIcon } from "./flow-waterfall-model-DvrgPLGS.js";
2
+ import { T as fmtEventTime, d as loadElk, v as tokenMilliseconds, x as useRunNow } from "./graph-style-fealnLLn.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { createContext, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
5
+ //#region node_modules/lucide-react/dist/esm/icons/bot.mjs
6
+ /**
7
+ * @license lucide-react v1.63.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */
12
+ const __iconData$1 = {
13
+ name: "bot",
14
+ size: 24,
15
+ node: [
16
+ ["path", {
17
+ d: "M12 8V4H8",
18
+ key: "hb8ula"
19
+ }],
20
+ ["rect", {
21
+ width: "16",
22
+ height: "12",
23
+ x: "4",
24
+ y: "8",
25
+ rx: "2",
26
+ key: "enze0r"
27
+ }],
28
+ ["path", {
29
+ d: "M2 14h2",
30
+ key: "vft8re"
31
+ }],
32
+ ["path", {
33
+ d: "M20 14h2",
34
+ key: "4cs60a"
35
+ }],
36
+ ["path", {
37
+ d: "M15 13v2",
38
+ key: "1xurst"
39
+ }],
40
+ ["path", {
41
+ d: "M9 13v2",
42
+ key: "rq6x2g"
43
+ }]
44
+ ]
45
+ };
46
+ __iconData$1.node;
47
+ const Bot = createLucideIcon(__iconData$1);
48
+ //#endregion
49
+ //#region node_modules/lucide-react/dist/esm/icons/wrench.mjs
50
+ /**
51
+ * @license lucide-react v1.63.0 - ISC
52
+ *
53
+ * This source code is licensed under the ISC license.
54
+ * See the LICENSE file in the root directory of this source tree.
55
+ */
56
+ const __iconData = {
57
+ name: "wrench",
58
+ size: 24,
59
+ node: [["path", {
60
+ d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z",
61
+ key: "1ngwbx"
62
+ }]]
63
+ };
64
+ __iconData.node;
65
+ const Wrench = createLucideIcon(__iconData);
66
+ //#endregion
67
+ //#region src/react/agent-graph/marks.tsx
68
+ const Marks = createContext({});
69
+ const GraphMarksProvider = Marks.Provider;
70
+ function AgentMark({ agent, layout, size }) {
71
+ const { renderAgentMark } = useContext(Marks);
72
+ return agent && renderAgentMark ? renderAgentMark(agent, layout, size) : /* @__PURE__ */ jsx(Bot, {
73
+ size: layout === "tree" ? size : 16,
74
+ "aria-hidden": true
75
+ });
76
+ }
77
+ function ToolMark({ tool, label, size }) {
78
+ const { renderToolMark } = useContext(Marks);
79
+ return renderToolMark ? renderToolMark(tool, label, size) : /* @__PURE__ */ jsx(Wrench, {
80
+ size: size * .4,
81
+ "aria-hidden": true
82
+ });
83
+ }
84
+ //#endregion
85
+ //#region src/react/agent-graph/agent-graph-layout.ts
86
+ /** Every agent card's size. Fixed, so a status or turn update never moves a card. */
87
+ const AGENT_CARD = {
88
+ width: 240,
89
+ height: 88
90
+ };
91
+ /** A live card: room for the header, a two-line thinking line and the last three events. Fixed for the same reason. */
92
+ const LIVE_AGENT_CARD = {
93
+ width: 296,
94
+ height: 164
95
+ };
96
+ /** A parent with at least this many leaf workers draws them as a grid. */
97
+ const GRID_MIN_LEAVES = 4;
98
+ const GRID_GAP = 10;
99
+ const FRAME_PAD = 12;
100
+ /** The manager stays with its workers instead of reserving an otherwise empty tree layer. */
101
+ const FRAME_CAPTION = 80;
102
+ const LAYER_GAP = 56;
103
+ const SIBLING_GAP = 24;
104
+ function buildAgentTopology(nodes, edges) {
105
+ const ids = /* @__PURE__ */ new Set();
106
+ const agentIds = [];
107
+ for (const n of nodes) {
108
+ if (ids.has(n.id)) continue;
109
+ ids.add(n.id);
110
+ agentIds.push(n.id);
111
+ }
112
+ const seen = /* @__PURE__ */ new Set();
113
+ const spawns = [];
114
+ const children = /* @__PURE__ */ new Map();
115
+ const parentCount = /* @__PURE__ */ new Map();
116
+ for (const e of edges) {
117
+ if (e.kind !== "spawn" || e.from === e.to) continue;
118
+ if (!ids.has(e.from) || !ids.has(e.to)) continue;
119
+ const key = `${e.from}\u0000${e.to}`;
120
+ if (seen.has(key)) continue;
121
+ seen.add(key);
122
+ spawns.push({
123
+ from: e.from,
124
+ to: e.to
125
+ });
126
+ children.set(e.from, [...children.get(e.from) ?? [], e.to]);
127
+ parentCount.set(e.to, (parentCount.get(e.to) ?? 0) + 1);
128
+ }
129
+ const groups = [];
130
+ const groupOf = /* @__PURE__ */ new Map();
131
+ for (const parentId of agentIds) {
132
+ const leaves = (children.get(parentId) ?? []).filter((c) => !children.has(c) && parentCount.get(c) === 1);
133
+ if (leaves.length < 4) continue;
134
+ const id = `agent-group:${parentId}`;
135
+ groups.push({
136
+ id,
137
+ parentId,
138
+ memberIds: leaves
139
+ });
140
+ for (const leaf of leaves) groupOf.set(leaf, id);
141
+ }
142
+ return {
143
+ key: JSON.stringify([agentIds, spawns.map((s) => [s.from, s.to])]),
144
+ agentIds,
145
+ spawns,
146
+ groups,
147
+ groupOf
148
+ };
149
+ }
150
+ function gridSize(members, columns, card, collapsed = false) {
151
+ if (collapsed) return {
152
+ width: card.width + 24,
153
+ height: 80
154
+ };
155
+ const cols = Math.max(1, Math.min(columns, members));
156
+ const rows = Math.ceil(members / cols);
157
+ return {
158
+ width: cols * card.width + (cols - 1) * GRID_GAP + 24,
159
+ height: 80 + rows * card.height + (rows - 1) * GRID_GAP + FRAME_PAD
160
+ };
161
+ }
162
+ /** The boxes the layouter places: each ungrouped agent, and each grid as one block. */
163
+ function layoutUnits(topology, columns, card, collapsed) {
164
+ const units = [];
165
+ const ownerGroup = new Map(topology.groups.map((group) => [group.parentId, group.id]));
166
+ for (const id of topology.agentIds) if (!topology.groupOf.has(id) && !ownerGroup.has(id)) units.push({
167
+ id,
168
+ width: card.width,
169
+ height: card.height
170
+ });
171
+ for (const g of topology.groups) units.push({
172
+ id: g.id,
173
+ ...gridSize(g.memberIds.length, columns, card, collapsed.has(g.id))
174
+ });
175
+ const unitOf = (id) => topology.groupOf.get(id) ?? ownerGroup.get(id) ?? id;
176
+ const seen = /* @__PURE__ */ new Set();
177
+ const links = [];
178
+ for (const s of topology.spawns) {
179
+ const from = unitOf(s.from);
180
+ const to = unitOf(s.to);
181
+ const key = `${from}\u0000${to}`;
182
+ if (from === to || seen.has(key)) continue;
183
+ seen.add(key);
184
+ links.push({
185
+ from,
186
+ to
187
+ });
188
+ }
189
+ return {
190
+ units,
191
+ links
192
+ };
193
+ }
194
+ async function placeWithElk(units, links, direction) {
195
+ const elk = await loadElk();
196
+ if (!elk) return null;
197
+ const graph = {
198
+ id: "root",
199
+ layoutOptions: {
200
+ "elk.algorithm": "layered",
201
+ "elk.direction": direction === "LR" ? "RIGHT" : "DOWN",
202
+ "elk.layered.considerModelOrder.strategy": "NODES_AND_EDGES",
203
+ "elk.layered.nodePlacement.strategy": "BRANDES_KOEPF",
204
+ "elk.layered.nodePlacement.bk.fixedAlignment": "BALANCED",
205
+ "elk.layered.spacing.nodeNodeBetweenLayers": String(LAYER_GAP),
206
+ "elk.spacing.nodeNode": String(SIBLING_GAP),
207
+ "elk.spacing.componentComponent": String(48),
208
+ "elk.separateConnectedComponents": "true",
209
+ "elk.padding": "[top=0,left=0,bottom=0,right=0]"
210
+ },
211
+ children: units.map((u) => ({
212
+ id: u.id,
213
+ width: u.width,
214
+ height: u.height
215
+ })),
216
+ edges: links.map((l, i) => ({
217
+ id: `e${i}`,
218
+ sources: [l.from],
219
+ targets: [l.to]
220
+ }))
221
+ };
222
+ try {
223
+ const out = await elk.layout(graph);
224
+ const at = /* @__PURE__ */ new Map();
225
+ for (const c of out.children ?? []) at.set(c.id, {
226
+ x: c.x ?? 0,
227
+ y: c.y ?? 0
228
+ });
229
+ return at;
230
+ } catch {
231
+ return null;
232
+ }
233
+ }
234
+ /** Without ELK: one row (TB) or column (LR) per spawn depth, each centred. */
235
+ function placeByDepth(units, links, direction) {
236
+ const parents = /* @__PURE__ */ new Map();
237
+ for (const l of links) parents.set(l.to, [...parents.get(l.to) ?? [], l.from]);
238
+ const depth = /* @__PURE__ */ new Map();
239
+ const depthOf = (id, path) => {
240
+ const known = depth.get(id);
241
+ if (known !== void 0) return known;
242
+ if (path.has(id)) return 0;
243
+ path.add(id);
244
+ const d = Math.max(-1, ...(parents.get(id) ?? []).map((p) => depthOf(p, path))) + 1;
245
+ path.delete(id);
246
+ depth.set(id, d);
247
+ return d;
248
+ };
249
+ const layers = [];
250
+ for (const u of units) (layers[depthOf(u.id, /* @__PURE__ */ new Set())] ??= []).push(u);
251
+ const along = (u) => direction === "TB" ? u.width : u.height;
252
+ const across = (u) => direction === "TB" ? u.height : u.width;
253
+ const extents = layers.map((l) => l.reduce((sum, u) => sum + along(u), 0) + (l.length - 1) * SIBLING_GAP);
254
+ const widest = Math.max(...extents);
255
+ const at = /* @__PURE__ */ new Map();
256
+ let offset = 0;
257
+ layers.forEach((layer, i) => {
258
+ let cursor = (widest - extents[i]) / 2;
259
+ for (const u of layer) {
260
+ at.set(u.id, direction === "TB" ? {
261
+ x: cursor,
262
+ y: offset
263
+ } : {
264
+ x: offset,
265
+ y: cursor
266
+ });
267
+ cursor += along(u) + SIBLING_GAP;
268
+ }
269
+ offset += Math.max(...layer.map(across)) + LAYER_GAP;
270
+ });
271
+ return at;
272
+ }
273
+ /** Lay the run out with every grid `columns` wide. */
274
+ async function layoutAgents(topology, direction, columns, card = AGENT_CARD, collapsed = /* @__PURE__ */ new Set()) {
275
+ const { units, links } = layoutUnits(topology, columns, card, collapsed);
276
+ const placed = await placeWithElk(units, links, direction) ?? placeByDepth(units, links, direction);
277
+ const positions = /* @__PURE__ */ new Map();
278
+ const frames = [];
279
+ let width = 0;
280
+ let height = 0;
281
+ for (const u of units) {
282
+ const p = placed.get(u.id) ?? {
283
+ x: 0,
284
+ y: 0
285
+ };
286
+ width = Math.max(width, p.x + u.width);
287
+ height = Math.max(height, p.y + u.height);
288
+ positions.set(u.id, p);
289
+ }
290
+ for (const g of topology.groups) {
291
+ const origin = positions.get(g.id) ?? {
292
+ x: 0,
293
+ y: 0
294
+ };
295
+ positions.delete(g.id);
296
+ const closed = collapsed.has(g.id);
297
+ const size = gridSize(g.memberIds.length, columns, card, closed);
298
+ frames.push({
299
+ group: g,
300
+ ...origin,
301
+ ...size,
302
+ collapsed: closed
303
+ });
304
+ positions.set(g.parentId, {
305
+ x: origin.x + FRAME_PAD,
306
+ y: origin.y + 8
307
+ });
308
+ if (closed) continue;
309
+ const cols = Math.max(1, Math.min(columns, g.memberIds.length));
310
+ g.memberIds.forEach((id, i) => {
311
+ positions.set(id, {
312
+ x: origin.x + FRAME_PAD + i % cols * (card.width + GRID_GAP),
313
+ y: origin.y + 80 + Math.floor(i / cols) * (card.height + GRID_GAP)
314
+ });
315
+ });
316
+ }
317
+ return {
318
+ columns,
319
+ positions,
320
+ frames,
321
+ width,
322
+ height
323
+ };
324
+ }
325
+ //#endregion
326
+ //#region src/react/agent-graph/latest-events.tsx
327
+ function EventRow({ entry, now, onSelect }) {
328
+ const meta = statusMeta(entry.observed ? entry.status : "unknown"), age = fmtEventTime(entry.at, now);
329
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("button", {
330
+ type: "button",
331
+ disabled: !onSelect,
332
+ onClick: () => onSelect?.(entry),
333
+ title: entry.name + ": " + entry.label,
334
+ children: [
335
+ /* @__PURE__ */ jsx("span", {
336
+ className: "ag-latest-dot",
337
+ style: {
338
+ background: entry.observed ? "var(" + meta.token + ")" : "transparent",
339
+ border: entry.observed ? void 0 : "1.5px solid var(" + meta.token + ")"
340
+ },
341
+ "aria-hidden": true
342
+ }),
343
+ /* @__PURE__ */ jsx("strong", { children: entry.name }),
344
+ entry.observed && /* @__PURE__ */ jsxs("span", {
345
+ className: "ag-latest-state",
346
+ style: { color: "var(" + meta.token + ")" },
347
+ children: [entry.status !== "running" && /* @__PURE__ */ jsx(RunStatusIcon, {
348
+ status: entry.status,
349
+ size: 14,
350
+ "aria-hidden": true
351
+ }), meta.label]
352
+ }),
353
+ /* @__PURE__ */ jsx("span", {
354
+ className: "ag-latest-label",
355
+ children: entry.label
356
+ }),
357
+ /* @__PURE__ */ jsxs("time", { children: [
358
+ entry.observed ? "Observed " : "",
359
+ age,
360
+ age !== "now" && age !== "—" ? " ago" : ""
361
+ ] })
362
+ ]
363
+ }) });
364
+ }
365
+ /** Recorded events and locally observed state changes. Hover or focus holds the reading position. */
366
+ function LatestEvents({ agents, n = 5, now, live = now === void 0, selectedId, onSelect }) {
367
+ const clock = useRunNow(now), limit = Number.isFinite(n) ? Math.max(1, Math.trunc(n)) : 5;
368
+ const latest = useMemo(() => agents.flatMap((agent) => (agent.events ?? []).map((event) => ({
369
+ id: agent.id + ":" + event.id,
370
+ agentId: agent.id,
371
+ name: agent.label,
372
+ label: event.label,
373
+ at: event.at,
374
+ status: agent.status
375
+ }))).sort((a, b) => (Number.isFinite(b.at) ? b.at : -Infinity) - (Number.isFinite(a.at) ? a.at : -Infinity) || a.id.localeCompare(b.id)).slice(0, limit), [agents, limit]);
376
+ const [rows, setRows] = useState(latest), [pins, setPins] = useState([]), [announcement, setAnnouncement] = useState("");
377
+ const [hovered, setHovered] = useState(false), [focused, setFocused] = useState(false), paused = hovered || focused;
378
+ const source = useRef(latest), pending = useRef(void 0);
379
+ const announce = useRef(void 0), messages = useRef(/* @__PURE__ */ new Map());
380
+ source.current = latest;
381
+ const previous = useRef(new Map(agents.map((agent) => [agent.id, agent.status])));
382
+ useEffect(() => {
383
+ const changes = agents.filter((agent) => previous.current.has(agent.id) && previous.current.get(agent.id) !== agent.status).map((agent) => ({
384
+ id: agent.id + ":status:" + clock,
385
+ agentId: agent.id,
386
+ name: agent.label,
387
+ status: agent.status,
388
+ label: agent.result ?? agent.turn ?? "Status changed",
389
+ at: clock,
390
+ observed: true
391
+ }));
392
+ previous.current = new Map(agents.map((agent) => [agent.id, agent.status]));
393
+ if (!live) {
394
+ setPins((old) => old.length ? [] : old);
395
+ messages.current.clear();
396
+ clearTimeout(announce.current);
397
+ announce.current = void 0;
398
+ return;
399
+ }
400
+ const ids = new Set(agents.map((agent) => agent.id));
401
+ setPins((old) => {
402
+ const next = [...changes, ...old.filter((entry) => ids.has(entry.agentId) && !changes.some((change) => change.agentId === entry.agentId))].slice(0, limit);
403
+ return !changes.length && next.length === old.length ? old : next;
404
+ });
405
+ if (!changes.length) return;
406
+ for (const entry of changes) messages.current.set(entry.agentId, entry.name + ": " + statusMeta(entry.status).label);
407
+ if (announce.current === void 0) announce.current = setTimeout(() => {
408
+ setAnnouncement([...messages.current.values()].join("; "));
409
+ messages.current.clear();
410
+ announce.current = void 0;
411
+ }, tokenMilliseconds("--duration-ambient"));
412
+ }, [
413
+ agents,
414
+ clock,
415
+ limit,
416
+ live
417
+ ]);
418
+ useEffect(() => {
419
+ if (selectedId) setPins((old) => old.filter((entry) => entry.agentId !== selectedId));
420
+ }, [selectedId]);
421
+ useEffect(() => {
422
+ if (paused) {
423
+ clearTimeout(pending.current);
424
+ pending.current = void 0;
425
+ return;
426
+ }
427
+ if (pending.current === void 0) pending.current = setTimeout(() => {
428
+ setRows(source.current);
429
+ pending.current = void 0;
430
+ }, tokenMilliseconds("--duration-ambient") / 2);
431
+ }, [latest, paused]);
432
+ useEffect(() => () => {
433
+ clearTimeout(pending.current);
434
+ clearTimeout(announce.current);
435
+ }, []);
436
+ const current = [...pins, ...rows.filter((entry) => !pins.some((pin) => pin.agentId === entry.agentId))].slice(0, limit);
437
+ const held = useRef(current);
438
+ useLayoutEffect(() => {
439
+ if (!paused) held.current = current;
440
+ }, [current, paused]);
441
+ const visible = paused ? held.current : current;
442
+ const refresh = () => {
443
+ setRows([...source.current]);
444
+ held.current = [...pins, ...source.current.filter((entry) => !pins.some((pin) => pin.agentId === entry.agentId))].slice(0, limit);
445
+ };
446
+ return /* @__PURE__ */ jsxs("section", {
447
+ className: "ag-latest",
448
+ "aria-label": "Latest activity",
449
+ tabIndex: 0,
450
+ onPointerEnter: () => setHovered(true),
451
+ onPointerLeave: () => setHovered(false),
452
+ onFocusCapture: () => setFocused(true),
453
+ onBlurCapture: (event) => {
454
+ if (!event.currentTarget.contains(event.relatedTarget)) setFocused(false);
455
+ },
456
+ children: [
457
+ /* @__PURE__ */ jsxs("header", { children: [
458
+ /* @__PURE__ */ jsx("strong", { children: "Latest activity" }),
459
+ /* @__PURE__ */ jsx("span", { children: paused ? "Paused while reading" : "Recorded events · age" }),
460
+ paused && /* @__PURE__ */ jsx("button", {
461
+ type: "button",
462
+ onClick: refresh,
463
+ children: "Show latest"
464
+ })
465
+ ] }),
466
+ /* @__PURE__ */ jsx("ol", {
467
+ tabIndex: 0,
468
+ "aria-label": "Recorded activity events",
469
+ children: visible.length ? visible.map((entry) => /* @__PURE__ */ jsx(EventRow, {
470
+ entry,
471
+ now: clock,
472
+ onSelect: onSelect ? (item) => {
473
+ setPins((old) => old.filter((pin) => pin.agentId !== item.agentId));
474
+ onSelect(item.agentId);
475
+ } : void 0
476
+ }, entry.id)) : /* @__PURE__ */ jsx("li", {
477
+ className: "ag-latest-empty",
478
+ children: "No activity events were reported."
479
+ })
480
+ }),
481
+ /* @__PURE__ */ jsx("span", {
482
+ className: "sr-only",
483
+ role: "status",
484
+ "aria-live": "polite",
485
+ children: announcement
486
+ })
487
+ ]
488
+ });
489
+ }
490
+ //#endregion
491
+ export { LIVE_AGENT_CARD as a, AgentMark as c, Wrench as d, GRID_MIN_LEAVES as i, GraphMarksProvider as l, AGENT_CARD as n, buildAgentTopology as o, FRAME_CAPTION as r, layoutAgents as s, LatestEvents as t, ToolMark as u };
@@ -0,0 +1,7 @@
1
+ //#region src/react/agent-graph/motion.ts
2
+ /** Brand owns complete duration/easing roles. Keep properties explicit. */
3
+ const MOTION_CONTROL = "[transition:color_var(--motion-control),background-color_var(--motion-control),border-color_var(--motion-control),box-shadow_var(--motion-control),transform_var(--motion-control),scale_var(--motion-control),opacity_var(--motion-control)] motion-reduce:transition-none";
4
+ /** Technical floating surfaces may change opacity/transform, never layout. */
5
+ const MOTION_SURFACE = "[transition:opacity_var(--motion-surface),transform_var(--motion-surface)] motion-reduce:transition-none";
6
+ //#endregion
7
+ export { MOTION_SURFACE as n, MOTION_CONTROL as t };
@@ -0,0 +1,157 @@
1
+ import { A as AGENT_CARD, B as AgentLeafGroup, C as shortModel, D as fmtEventTime, E as fmtDuration, F as AgentGraphEdgeKind, G as LIVE_AGENT_CARD, H as CardSize, I as AgentGraphEvent, K as buildAgentTopology, L as AgentGraphNode, M as AgentGraphActivity, N as AgentGraphDirection, O as fmtTokenTotal, P as AgentGraphEdge, R as AgentGraphStatus, S as parseActionPath, T as fmtCost, U as FRAME_CAPTION, V as AgentTopology, W as GRID_MIN_LEAVES, _ as useRunNow, a as RESTING_SHADOW, b as actionPathLabel, c as motionAllowed, d as agentQuietActivity, f as ambientStyle, g as useMotionAllowed, h as useAttention, i as RESTING_BORDER, j as AgentFrame, k as fmtTokens, l as useColorMode, m as tokenMilliseconds, n as GraphErrorBoundary, o as edgeColor, p as syncAmbient, q as layoutAgents, r as retryImport, s as SELECTION_OUTLINE, t as loadElk, u as activityTiming, v as ActionPathParts, w as clampPreview, x as humanizeIdentifier, y as LeadCase, z as AgentLayout } from "../../elk-loader-CrLO557o.js";
2
+ import { ReactNode } from "react";
3
+ //#region src/react/agent-graph/agent-hub-layout.d.ts
4
+ /** A tool or service an agent calls: drawn as an outer node with its brand mark. */
5
+ export interface AgentGraphTool {
6
+ id: string;
7
+ label: string;
8
+ /** Brand id for `ProviderIcon` ("github", "slack", "postgres"…). */
9
+ provider?: string | null;
10
+ /** One line under the name in its popover, e.g. "Postgres, read-only". */
11
+ detail?: string | null;
12
+ }
13
+ export type AgentGraphCallKind = "call" | "answer" | "needs-you" | "failed";
14
+ /** One recorded call between two nodes ("you", an agent id or a tool id). */
15
+ export interface AgentGraphCall {
16
+ id: string;
17
+ from: string;
18
+ to: string;
19
+ kind: AgentGraphCallKind;
20
+ /** What was asked or answered, one line. */
21
+ label?: string | null;
22
+ /** Epoch ms. */
23
+ startedAt: number;
24
+ /** Absent while it runs. */
25
+ durationMs?: number | null;
26
+ }
27
+ /** The id the "You" node takes in `calls`. */
28
+ export declare const YOU_ID = "you";
29
+ export type HubNodeKind = "you" | "hub" | "agent" | "tool";
30
+ export interface HubNodePlacement {
31
+ id: string;
32
+ kind: HubNodeKind;
33
+ /** Grid cell; the hub is (0, 0). */
34
+ col: number;
35
+ row: number;
36
+ }
37
+ export interface HubLink {
38
+ from: string;
39
+ to: string;
40
+ }
41
+ export interface HubMetrics {
42
+ cellX: number;
43
+ cellY: number;
44
+ tile: number;
45
+ hubTile: number;
46
+ /** Room under a tile for its two label lines. */
47
+ label: number;
48
+ }
49
+ export declare const HUB_METRICS: HubMetrics;
50
+ /** The orchestrator: the agent nobody spawned, else the first. */
51
+ export declare function hubAgentId(nodes: readonly AgentGraphNode[], edges: readonly AgentGraphEdge[]): string | undefined;
52
+ export interface HubLayout {
53
+ placements: HubNodePlacement[];
54
+ links: HubLink[];
55
+ minCol: number;
56
+ maxCol: number;
57
+ minRow: number;
58
+ maxRow: number;
59
+ }
60
+ /**
61
+ * Place every node on the grid. Agents take ring cells in order; each tool takes
62
+ * the first free cell outward from the first agent that called it (beside, then
63
+ * above or below, then diagonal), so it sits next to its user.
64
+ */
65
+ export declare function layoutHub(input: {
66
+ nodes: readonly AgentGraphNode[];
67
+ edges: readonly AgentGraphEdge[];
68
+ tools: readonly AgentGraphTool[];
69
+ calls: readonly AgentGraphCall[];
70
+ you: boolean;
71
+ }): HubLayout;
72
+ export interface Point {
73
+ x: number;
74
+ y: number;
75
+ }
76
+ export interface HubBounds {
77
+ left: number;
78
+ right: number;
79
+ top: number;
80
+ bottom: number;
81
+ }
82
+ /**
83
+ * A short rounded Manhattan route around tile and label bounds. Departure lanes
84
+ * separate parallel calls; the path length keeps finite trips at a consistent speed.
85
+ */
86
+ export declare function orthogonalPath(a: Point, b: Point, verticalFirst: boolean, lane?: number, radius?: number, obstacles?: readonly HubBounds[]): {
87
+ d: string;
88
+ length: number;
89
+ };
90
+ //#endregion
91
+ //#region src/react/agent-graph/marks.d.ts
92
+ /** Identity comes from the host; the diagram never guesses a provider or model mark. */
93
+ interface GraphMarks {
94
+ renderAgentMark?: (agent: AgentGraphNode, layout: "tree" | "hub", size: number) => ReactNode;
95
+ renderToolMark?: (tool: AgentGraphTool | undefined, label: string, size: number) => ReactNode;
96
+ }
97
+ //#endregion
98
+ //#region src/react/agent-graph/AgentGraph.d.ts
99
+ export interface AgentGraphProps extends GraphMarks {
100
+ nodes: readonly AgentGraphNode[];
101
+ /** `spawn` edges shape the tree; `message` and `delegation` edges are drawn
102
+ * over it as dashed curves and never move a card. */
103
+ edges: readonly AgentGraphEdge[];
104
+ selectedId?: string | null;
105
+ onSelect?: (id: string) => void;
106
+ /** Tree direction. Default `TB` (root at the top). */
107
+ direction?: AgentGraphDirection;
108
+ /** Sizes the canvas; the graph fills it. Give it a height. */
109
+ className?: string;
110
+ /** Shown instead of the canvas when there are no agents. */
111
+ emptyState?: ReactNode;
112
+ /**
113
+ * `tree` (default) lays out a spawn tree of cards for large runs. `hub` draws
114
+ * the run around its orchestrator: You, the agents, the tools they call, and
115
+ * each call travelling along its edge in its kind's colour.
116
+ */
117
+ layout?: "tree" | "hub";
118
+ /** Hub tools/services. Omit unreported inventory; [] records no tools. */
119
+ tools?: readonly AgentGraphTool[];
120
+ /** Hub calls, newest last. Omit unreported history; [] records no calls. They colour edges and fill popovers. */
121
+ calls?: readonly AgentGraphCall[];
122
+ /** Hub layout: draw the person who asked as "You". */
123
+ you?: {
124
+ label?: string;
125
+ summary?: string;
126
+ } | boolean;
127
+ /** Hub layout and live cards: epoch ms to draw at (a replay position); defaults to now, ticking. */
128
+ now?: number;
129
+ /** Hub layout: the header title. Default "Agent graph". */
130
+ title?: ReactNode;
131
+ /**
132
+ * Tree layout: readable task summaries, the latest three events and model/accounting details. Desktop slots stay
133
+ * fixed through status updates; completed results compact while failures retain their evidence. Phones preserve
134
+ * their initial attention order. Only the running dot breathes; commands update without routine sliding.
135
+ */
136
+ live?: boolean;
137
+ /** Optional host tool identity for a recorded event. */
138
+ renderEventIcon?: (event: AgentGraphEvent) => ReactNode;
139
+ /** Live tree activity; false when a shared workspace already supplies its strip. */
140
+ showLatestEvents?: boolean;
141
+ }
142
+ export declare function AgentGraph(props: AgentGraphProps): import("react").JSX.Element;
143
+ //#endregion
144
+ //#region src/react/agent-graph/latest-events.d.ts
145
+ export interface LatestEventsProps {
146
+ agents: readonly AgentGraphNode[];
147
+ n?: number;
148
+ now?: number;
149
+ /** Observe incoming status changes. Disable when scrubbing a trace without an epoch. */
150
+ live?: boolean;
151
+ selectedId?: string | null;
152
+ onSelect?: (id: string) => void;
153
+ }
154
+ /** Recorded events and locally observed state changes. Hover or focus holds the reading position. */
155
+ export declare function LatestEvents({ agents, n, now, live, selectedId, onSelect }: LatestEventsProps): import("react").JSX.Element;
156
+ //#endregion
157
+ export { AGENT_CARD, ActionPathParts, AgentFrame, AgentGraphActivity, AgentGraphDirection, AgentGraphEdge, AgentGraphEdgeKind, AgentGraphEvent, AgentGraphNode, AgentGraphStatus, AgentLayout, AgentLeafGroup, AgentTopology, CardSize, FRAME_CAPTION, GRID_MIN_LEAVES, GraphErrorBoundary, type GraphMarks, LIVE_AGENT_CARD, LeadCase, RESTING_BORDER, RESTING_SHADOW, SELECTION_OUTLINE, actionPathLabel, activityTiming, agentQuietActivity, ambientStyle, buildAgentTopology, clampPreview, edgeColor, fmtCost, fmtDuration, fmtEventTime, fmtTokenTotal, fmtTokens, humanizeIdentifier, layoutAgents, loadElk, motionAllowed, parseActionPath, retryImport, shortModel, syncAmbient, tokenMilliseconds, useAttention, useColorMode, useMotionAllowed, useRunNow };