@tangle-network/sandbox-ui 3.0.2 → 3.0.3

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.
Files changed (28) hide show
  1. package/dist/AgentTree-D4d06rfH.js +293 -0
  2. package/dist/{ResearchReport-vqefUbVp.js → ResearchReport-D1TFmldm.js} +2 -1
  3. package/dist/{VirtualList-CMynqkkh.js → VirtualList-DcSGbEtA.js} +28 -1
  4. package/dist/{index-gXcuwPOX.d.ts → index-Bv2iiZaN.d.ts} +135 -2
  5. package/dist/{index-YU_b9xCK.d.ts → index-CHA38az4.d.ts} +3 -61
  6. package/dist/index.d.ts +3 -3
  7. package/dist/index.js +9 -8
  8. package/dist/record/ResearchReport.js +1 -1
  9. package/dist/{record-B_4XWfUz.js → record-C-EUpK-n.js} +3 -2
  10. package/dist/record.js +1 -1
  11. package/dist/report-viewer.js +80 -80
  12. package/dist/run/live.js +2 -2
  13. package/dist/run/record.d.ts +2 -2
  14. package/dist/run/record.js +5 -4
  15. package/dist/run.d.ts +3 -3
  16. package/dist/run.js +6 -5
  17. package/dist/runtime-viewer/{AgentGraphCanvas-DGq7_u8--WPFPgd72.js → AgentGraphCanvas-DGq7_u8--C6yDfIUT.js} +67 -67
  18. package/dist/runtime-viewer/{latest-events-CRq9sGkK-YFXUh9qO.js → latest-events-CRq9sGkK-CfoBl1dP.js} +215 -209
  19. package/dist/{trace-workspace-BiJbv9WQ.js → trace-workspace-B634-EcA.js} +287 -201
  20. package/dist/{tree-data-9D309DqD.js → tree-data-rg5voiY8.js} +1 -1
  21. package/dist/{AgentTree-Cju8jn51.js → use-follow-tail-DZFn7QDO.js} +144 -385
  22. package/dist/vault-tree.js +1 -1
  23. package/dist/{workspace-BrS_rHWN.js → workspace-CJD7oOEa.js} +1 -1
  24. package/dist/{workspace-files-pane-Di_rn4FL.js → workspace-files-pane-D24G7H_Z.js} +1 -1
  25. package/dist/workspace-viewer.js +9970 -9624
  26. package/dist/workspace.js +2 -2
  27. package/package.json +5 -4
  28. package/dist/use-follow-tail-Ht7fZGQQ.js +0 -1
@@ -0,0 +1,293 @@
1
+ import { t as VirtualList } from "./VirtualList-DcSGbEtA.js";
2
+ import { C as ms, D as toolKey, E as textOf, T as roleOf, a as isLifecycle, c as anchorsOf, d as collapseIdleTurns, f as collapsePolls, g as eventMatches, h as callsOf, l as answeredBy, m as thinkingMarkers, n as ConversationRowView, o as rowItems, p as quietThinking, t as useFollowTail, u as collapseHollowTurns } from "./use-follow-tail-DZFn7QDO.js";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
+ import { AgentTimelineColumn, agentTimelineStepKind } from "@tangle-network/ui/chat/agent-timeline";
6
+ import { RunStatusIcon, runStatus, statusMeta } from "@tangle-network/ui/run/status-meta";
7
+ // src/run/record/Conversation.tsx
8
+ function Conversation({ index, actor, cutoff, query, category, selected, openSource, flags, onFlag, lifecycle = false, live = false, follow = live, opening }) {
9
+ const [opened, setOpened] = useState(() => {
10
+ const at = anchorsOf(index.events);
11
+ return new Set(index.events.filter((event) => event.detail.promptKind === "initial").map((event) => `prompt:${at.get(event.id) ?? event.id}`));
12
+ });
13
+ const scroll = useRef(null);
14
+ const anchors = useMemo(() => anchorsOf(index.events), [index]);
15
+ const anchor = useCallback((event) => anchors.get(event.id) ?? event.id, [anchors]);
16
+ const opener = (event) => openSource ? (sha256) => openSource(sha256, event) : void 0;
17
+ const setOpen = (key, open) => setOpened((current) => {
18
+ if (current.has(key) === open) return current;
19
+ const next = new Set(current);
20
+ if (open) next.add(key);
21
+ else next.delete(key);
22
+ return next;
23
+ });
24
+ const paired = (event, call) => {
25
+ const key = toolKey(event.node, call.id);
26
+ return index.calls.get(key)?.length === 1 ? index.results.get(key) ?? [] : [];
27
+ };
28
+ const target = useMemo(() => {
29
+ if (!selected) return void 0;
30
+ const event = index.byEvent.get(selected);
31
+ if (event?.detail.toolCallId !== void 0) {
32
+ const calls = index.calls.get(toolKey(event.node, event.detail.toolCallId));
33
+ if (calls?.length === 1) return calls[0].event.id;
34
+ }
35
+ return selected;
36
+ }, [selected, index]);
37
+ const items = useMemo(() => (index.byActor.get(actor) ?? []).filter((event) => {
38
+ if (ms(event.at) > cutoff) return false;
39
+ if (event.id === target) return true;
40
+ if (isLifecycle(event)) return lifecycle && eventMatches(event, index, query, category);
41
+ if (event.detail.toolCallId !== void 0) {
42
+ const matching = index.calls.get(toolKey(event.node, event.detail.toolCallId));
43
+ if (matching?.length === 1 && ms(matching[0].event.at) <= cutoff) return false;
44
+ }
45
+ const calls = callsOf(event);
46
+ if (!(event.detail.role || textOf(event) || event.detail.reasoning || event.detail.responseStatus === "error" || calls.length)) return false;
47
+ if (event.detail.role === "assistant" && !textOf(event) && !event.detail.reasoning && !calls.length && event.detail.responseStatus !== "error" && !event.detail.contentOmitted && (!thinkingMarkers(event.detail).length || quietThinking(event.detail))) return false;
48
+ if (eventMatches(event, index, query, category)) return true;
49
+ return calls.some((call) => {
50
+ const key = toolKey(event.node, call.id);
51
+ return index.calls.get(key)?.length === 1 && (index.results.get(key) ?? []).some((result) => ms(result.at) <= cutoff && eventMatches(result, index, query, category));
52
+ });
53
+ }), [
54
+ index,
55
+ actor,
56
+ cutoff,
57
+ query,
58
+ category,
59
+ lifecycle,
60
+ target
61
+ ]);
62
+ const shown = useMemo(() => {
63
+ if (!opening?.text || query || category !== "all" || items.some((event) => event.detail.role === "user" && event.detail.promptKind !== "steering")) return items;
64
+ const first = items[0]?.at ?? opening.at;
65
+ return [{
66
+ id: `${actor}:opening`,
67
+ node: actor,
68
+ at: first < opening.at ? first : opening.at,
69
+ kind: "message",
70
+ category: "other",
71
+ label: "prompt",
72
+ detail: {
73
+ role: "user",
74
+ publicText: opening.text,
75
+ promptKind: "initial"
76
+ }
77
+ }, ...items];
78
+ }, [
79
+ items,
80
+ opening,
81
+ actor,
82
+ query,
83
+ category
84
+ ]);
85
+ const rows = useMemo(() => collapseIdleTurns(collapseHollowTurns(collapsePolls(shown, {
86
+ callsOf,
87
+ answered: (event, id) => answeredBy(index.results.get(toolKey(event.node, id))),
88
+ keyOf: anchor
89
+ }), {
90
+ callsOf,
91
+ captured: (event, id) => (index.results.get(toolKey(event.node, id)) ?? []).some((result) => textOf(result)),
92
+ keyOf: anchor
93
+ }), callsOf), [
94
+ shown,
95
+ index,
96
+ anchor
97
+ ]);
98
+ const thinkingSpan = useMemo(() => {
99
+ const spans = /* @__PURE__ */ new Map();
100
+ let previous = null;
101
+ for (const event of index.byActor.get(actor) ?? []) {
102
+ const at = ms(event.at);
103
+ if (previous !== null && Number.isFinite(at) && thinkingMarkers(event.detail).length) spans.set(event.id, Math.max(0, at - previous));
104
+ if (Number.isFinite(at)) previous = at;
105
+ }
106
+ return spans;
107
+ }, [index, actor]);
108
+ const rowOf = useMemo(() => new Map(rows.flatMap((row) => (row.kind === "event" ? [row.event] : row.events).map((event) => [event.id, row.key]))), [rows]);
109
+ const retained = (index.byActor.get(actor) ?? []).some((item) => !isLifecycle(item) && (item.detail.role || textOf(item) || callsOf(item).length));
110
+ const tail = rows.at(-1), event = tail?.kind === "event" ? tail.event : tail?.events.at(-1);
111
+ const { following } = useFollowTail(scroll, {
112
+ identity: actor,
113
+ content: rows,
114
+ follow,
115
+ target
116
+ });
117
+ useEffect(() => {
118
+ if (!selected) return;
119
+ const event = index.byEvent.get(selected);
120
+ if (!event) return;
121
+ const keys = [`prompt:${anchor(event)}`, `reasoning:${anchor(event)}`];
122
+ if (event.detail.toolCallId !== void 0) for (const match of index.calls.get(toolKey(event.node, event.detail.toolCallId)) ?? []) keys.push(`tool:${anchor(match.event)}:${match.call.id}`, rowOf.get(match.event.id) ?? "");
123
+ for (const call of callsOf(event)) keys.push(`tool:${anchor(event)}:${call.id}`);
124
+ const row = rowOf.get(selected);
125
+ if (row?.startsWith("polls:")) keys.push(row);
126
+ setOpened((current) => /* @__PURE__ */ new Set([...current, ...keys.filter(Boolean)]));
127
+ }, [selected, index]);
128
+ const flagMarks = (event) => {
129
+ const marks = flags?.get(event.id);
130
+ if (!marks?.length) return null;
131
+ return /* @__PURE__ */ jsx("span", {
132
+ className: "event-flags",
133
+ children: marks.map((flag) => /* @__PURE__ */ jsx("button", {
134
+ type: "button",
135
+ className: `event-flag polarity-${flag.polarity}`,
136
+ title: flag.title,
137
+ "data-flag": flag.dimension,
138
+ onClick: () => onFlag?.(flag, event),
139
+ children: flag.dimension
140
+ }, `${flag.dimension}:${flag.label}`))
141
+ });
142
+ };
143
+ const keyOf = useCallback((row) => row.key, []);
144
+ const estimate = useCallback((row) => {
145
+ if (row.kind !== "event") return 36;
146
+ if (isLifecycle(row.event)) return 26;
147
+ return !textOf(row.event) && callsOf(row.event).length ? 16 + 36 * callsOf(row.event).length : 96;
148
+ }, []);
149
+ const context = {
150
+ index,
151
+ cutoff,
152
+ selected,
153
+ opened,
154
+ anchor,
155
+ opener,
156
+ setOpen,
157
+ flagMarks,
158
+ paired,
159
+ thinkingSpan,
160
+ flags,
161
+ live
162
+ };
163
+ const itemsOf = useMemo(() => rows.map((row) => rowItems(row, context)), [
164
+ rows,
165
+ opened,
166
+ cutoff,
167
+ selected,
168
+ live,
169
+ index,
170
+ thinkingSpan
171
+ ]);
172
+ const turns = useMemo(() => {
173
+ let previous;
174
+ return rows.map((row) => {
175
+ const event = row.kind === "event" ? row.event : row.events[0];
176
+ const turn = event.detail.role === "assistant" && !isLifecycle(event) && (!previous || previous.detail.role === "user" || (event.detail.attempt !== void 0 ? event.detail.attempt !== previous.detail.attempt : ms(event.at) - ms(previous.at) > 12e4));
177
+ previous = row.kind === "event" ? event : row.events.at(-1);
178
+ return turn;
179
+ });
180
+ }, [rows]);
181
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", {
182
+ className: "record-conversation conversation-scroll",
183
+ "data-chat": true,
184
+ ref: scroll,
185
+ tabIndex: 0,
186
+ "aria-label": "Scrollable retained conversation",
187
+ children: [!rows.length && /* @__PURE__ */ jsx("p", {
188
+ className: "chat-empty",
189
+ children: query || category !== "all" ? "No messages match this filter." : retained ? "No messages at the selected time." : "Conversation not retained. Its absence does not mean the agent did no work."
190
+ }), /* @__PURE__ */ jsx(AgentTimelineColumn, {
191
+ className: "ar-chat",
192
+ children: /* @__PURE__ */ jsx(VirtualList, {
193
+ items: rows,
194
+ keyOf,
195
+ render: (row, i) => /* @__PURE__ */ jsx(ConversationRowView, {
196
+ row,
197
+ items: itemsOf[i] ?? [],
198
+ previous: i && itemsOf[i - 1]?.length ? agentTimelineStepKind(itemsOf[i - 1].at(-1)) : void 0,
199
+ turn: turns[i],
200
+ context
201
+ }),
202
+ scroller: scroll,
203
+ target: target ? rowOf.get(target) : void 0,
204
+ estimate,
205
+ arrival: live ? {
206
+ identity: actor,
207
+ id: event?.id,
208
+ key: tail?.key,
209
+ following
210
+ } : void 0
211
+ })
212
+ })]
213
+ }) });
214
+ }
215
+ // src/run/record/AgentTree.tsx
216
+ /** Retained identity and recorded time define the hierarchy; labels never join sessions or invent parents. */
217
+ function AgentTree({ index, actor, cutoff, select }) {
218
+ const roots = useMemo(() => {
219
+ const nodes = index.actors.filter((node) => node.kind !== "finding");
220
+ const byId = new Map(nodes.map((node) => [node.id, node]));
221
+ const children = /* @__PURE__ */ new Map();
222
+ for (const node of nodes) {
223
+ if (!node.parent) continue;
224
+ const parent = index.canonical(node.parent), siblings = children.get(parent) ?? [];
225
+ siblings.push(node);
226
+ children.set(parent, siblings);
227
+ }
228
+ const visited = /* @__PURE__ */ new Set();
229
+ const visit = (node) => {
230
+ if (visited.has(node.id)) return [];
231
+ visited.add(node.id);
232
+ return [{
233
+ node,
234
+ children: (children.get(node.id) ?? []).flatMap(visit)
235
+ }];
236
+ };
237
+ const roots = nodes.filter((node) => !node.parent || !byId.has(index.canonical(node.parent))).flatMap(visit);
238
+ for (const node of nodes) roots.push(...visit(node));
239
+ return roots;
240
+ }, [index]);
241
+ const renderNodes = (entries, nested = false) => /* @__PURE__ */ jsx("ul", {
242
+ className: nested ? "m-0 ml-3 list-none border-l border-border pl-2" : "m-0 grid list-none gap-1 p-0",
243
+ children: entries.map(({ node, children }) => {
244
+ const firstEvent = index.byActor.get(node.id)?.[0];
245
+ const begin = node.start ? ms(node.start) : firstEvent ? ms(firstEvent.at) : void 0;
246
+ const future = begin !== void 0 && begin > cutoff, pending = typeof node.end === "string" && ms(node.end) > cutoff;
247
+ const status = runStatus(future || pending ? "unknown" : node.status ?? "unknown");
248
+ const state = future ? "Not yet started" : pending ? "Not yet settled" : statusMeta(status).label;
249
+ return /* @__PURE__ */ jsxs("li", {
250
+ className: "min-w-0",
251
+ children: [/* @__PURE__ */ jsxs("button", {
252
+ type: "button",
253
+ className: "flex w-full min-w-0 items-start gap-2 rounded border border-transparent px-2 py-1.5 text-left text-sm text-foreground hover:border-border focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring aria-pressed:border-border aria-pressed:bg-muted data-[future]:opacity-55",
254
+ "aria-label": "Read " + roleOf(node) + " " + node.label + " conversation. " + state + ".",
255
+ "aria-pressed": actor === node.id,
256
+ "data-node": node.id,
257
+ "data-future": future ? "" : void 0,
258
+ title: node.label + (node.assignment ? " · " + node.assignment : "") + " · " + state,
259
+ onClick: () => select(node.id),
260
+ children: [/* @__PURE__ */ jsx(RunStatusIcon, {
261
+ status,
262
+ className: "mt-0.5 size-3.5 shrink-0",
263
+ "aria-hidden": true
264
+ }), /* @__PURE__ */ jsxs("span", {
265
+ className: "grid min-w-0 gap-0.5 break-words",
266
+ children: [/* @__PURE__ */ jsx("span", {
267
+ className: "font-semibold",
268
+ children: node.label
269
+ }), /* @__PURE__ */ jsxs("span", {
270
+ className: "text-muted-foreground",
271
+ children: [
272
+ roleOf(node),
273
+ " · ",
274
+ state
275
+ ]
276
+ })]
277
+ })]
278
+ }), children.length > 0 && renderNodes(children, true)]
279
+ }, node.id);
280
+ })
281
+ });
282
+ return /* @__PURE__ */ jsx("div", {
283
+ className: "record-agent-tree max-h-80 overflow-auto px-2 py-2",
284
+ "data-graph": true,
285
+ role: "group",
286
+ "aria-label": "Recorded agent hierarchy. Select an agent to read its conversation.",
287
+ children: roots.length ? renderNodes(roots) : /* @__PURE__ */ jsx("p", {
288
+ className: "text-sm text-muted-foreground",
289
+ children: "No agent topology was retained."
290
+ })
291
+ });
292
+ }
293
+ export { Conversation as n, AgentTree as t };
@@ -1,4 +1,5 @@
1
- import { a as fmt, c as modelIdentity, d as recordFlowTrace, f as roleOf, h as utcTime, i as eventSource, m as toolKey, n as Conversation, o as indexRecord, p as textOf, r as eventMatches, s as interval, t as AgentTree, u as ms } from "./AgentTree-Cju8jn51.js";
1
+ import { C as ms, D as toolKey, E as textOf, O as utcTime, T as roleOf, _ as eventSource, b as interval, g as eventMatches, v as fmt, w as recordFlowTrace, x as modelIdentity, y as indexRecord } from "./use-follow-tail-DZFn7QDO.js";
2
+ import { n as Conversation, t as AgentTree } from "./AgentTree-D4d06rfH.js";
2
3
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@tangle-network/ui/primitives";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
  import { createContext, memo, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
@@ -159,13 +159,40 @@ function useSettleTarget(scroller, { target, align, items, keyOf, offsets, origi
159
159
  offsets
160
160
  ]);
161
161
  }
162
+ /** Animate a new followed row once; measurements and reader-state updates keep the same arrival identity. */
163
+ function useArrival(scroller, rows, arrival) {
164
+ const identity = arrival?.identity;
165
+ const prior = useRef({
166
+ identity,
167
+ id: arrival?.id
168
+ });
169
+ useLayoutEffect(() => {
170
+ const animate = prior.current.identity === identity && !!prior.current.id && prior.current.id !== arrival?.id;
171
+ prior.current = {
172
+ identity,
173
+ id: arrival?.id
174
+ };
175
+ if (!animate || !arrival?.key || !arrival.following.current) return;
176
+ const frame = requestAnimationFrame(() => {
177
+ const element = scroller.current, row = rows.current.get(arrival.key)?.firstElementChild;
178
+ if (!element || !row || !arrival.following.current) return;
179
+ const style = getComputedStyle(element), value = style.getPropertyValue("--duration-stream").trim(), duration = parseFloat(value) * (value.endsWith("ms") ? 1 : 1e3);
180
+ if (duration > 0 && !matchMedia("(prefers-reduced-motion: reduce)").matches) row.animate([{ opacity: 0 }, { opacity: 1 }], {
181
+ duration,
182
+ easing: style.getPropertyValue("--ease-expo").trim() || "linear"
183
+ });
184
+ });
185
+ return () => cancelAnimationFrame(frame);
186
+ }, [identity, arrival?.id]);
187
+ }
162
188
  /**
163
189
  * Renders only the rows near the viewport of `scroller`. Row heights are measured as they render; unmeasured
164
190
  * rows use `estimate`. Spacers keep the scroll height, so the browser's scroll anchoring holds the reading place.
165
191
  */
166
- function VirtualList({ items, keyOf, render, scroller, estimate = 96, overscan = 900, target, origin, targetAlign = "start", virtualize = true, keepMounted }) {
192
+ function VirtualList({ items, keyOf, render, scroller, estimate = 96, overscan = 900, target, origin, targetAlign = "start", virtualize = true, keepMounted, arrival }) {
167
193
  const { heights, rows, version, bind } = useMeasuredHeights();
168
194
  const { viewport, originTop } = useViewport(scroller, origin);
195
+ useArrival(scroller, rows, arrival);
169
196
  const offsets = useMemo(() => {
170
197
  const result = new Float64Array(items.length + 1);
171
198
  const guess = typeof estimate === "function" ? estimate : () => estimate;
@@ -1,5 +1,116 @@
1
+ import { t as AgentStreamOpener } from "./event-stream-DNEbvx4s.js";
1
2
  import { ReactNode, RefObject } from "react";
3
+ import { ToolCallData } from "@tangle-network/ui/run";
2
4
  import { FlowTrace, formatCompact as fmt, formatSpanDuration as interval, formatUtcTime as utcTime } from "@tangle-network/charts";
5
+ import { AgentTimelineItem, AgentTimelineStepKind } from "@tangle-network/ui/chat/agent-timeline";
6
+ /** One normalized stream row; bounded producer pages also carry opaque native frames. */
7
+ interface AgentStreamRow {
8
+ seq: number;
9
+ at: string;
10
+ stream?: string;
11
+ attempt?: number;
12
+ event: {
13
+ kind: "text" | "reasoning" | "tool-call" | "tool-result" | "user" | "notice" | (string & {});
14
+ text?: string;
15
+ provenance?: string;
16
+ toolCallId?: string;
17
+ toolName?: string;
18
+ args?: unknown;
19
+ result?: unknown;
20
+ isError?: boolean;
21
+ atBasis?: string;
22
+ durationMs?: number;
23
+ costUsd?: number;
24
+ id?: string;
25
+ sealed?: boolean;
26
+ };
27
+ }
28
+ type AgentTranscriptEntry = {
29
+ id: string;
30
+ at: number;
31
+ scope?: string;
32
+ attempt?: number;
33
+ provenance?: string;
34
+ isError?: boolean;
35
+ kind: "message";
36
+ role: "assistant" | "user";
37
+ content: string;
38
+ sealed?: true;
39
+ } | {
40
+ id: string;
41
+ at: number;
42
+ scope?: string;
43
+ attempt?: number;
44
+ provenance?: string;
45
+ isError?: boolean;
46
+ kind: "reasoning";
47
+ text: string;
48
+ } | {
49
+ id: string;
50
+ at: number;
51
+ scope?: string;
52
+ attempt?: number;
53
+ provenance?: string;
54
+ isError?: boolean;
55
+ kind: "tool";
56
+ call: ToolCallData;
57
+ name?: string;
58
+ input?: unknown;
59
+ costUsd?: number;
60
+ } | {
61
+ id: string;
62
+ at: number;
63
+ scope?: string;
64
+ attempt?: number;
65
+ provenance?: string;
66
+ isError?: boolean;
67
+ kind: "notice";
68
+ text: string;
69
+ };
70
+ type ProducerRow = Partial<AgentStreamRow> & Pick<AgentStreamRow, "seq"> & {
71
+ type?: string;
72
+ data?: unknown;
73
+ };
74
+ interface AgentStreamPage {
75
+ generation?: string | number;
76
+ events: ProducerRow[];
77
+ firstSeq?: number | null;
78
+ lastSeq?: number | null;
79
+ hasEarlier?: boolean;
80
+ hasMore?: boolean;
81
+ alive?: boolean;
82
+ reset?: boolean;
83
+ }
84
+ /** The actual producer's bounded history. Core projection is product-owned, never a parser in the SDK. */
85
+ interface AgentStreamHistory {
86
+ url: string;
87
+ alive: boolean;
88
+ projectRows?: (rows: readonly ProducerRow[]) => readonly ProducerRow[];
89
+ }
90
+ interface AgentStreamState {
91
+ generation?: string | number;
92
+ entries: AgentTranscriptEntry[];
93
+ lastSeq: number;
94
+ alive: boolean;
95
+ error?: string;
96
+ history?: {
97
+ loading: boolean;
98
+ earlier: boolean;
99
+ more: boolean;
100
+ reading: boolean;
101
+ beginning: boolean;
102
+ emptyTail: boolean;
103
+ older(): void;
104
+ newer(): void;
105
+ latest(): void;
106
+ beginningPage(): void;
107
+ };
108
+ }
109
+ /** One fold for live entries; attempt/session identity prevents repeated native call IDs from crossing turns. */
110
+ declare function foldAgentRows(entries: AgentTranscriptEntry[], rows: readonly AgentStreamRow[]): AgentTranscriptEntry[];
111
+ declare function foldAgentRows(entries: AgentTranscriptEntry[], rows: readonly ProducerRow[]): AgentTranscriptEntry[];
112
+ /** Same named SSE lifecycle for every consumer; the actual history endpoint owns bounded bootstrap/pages. */
113
+ declare function useAgentStream(url: string | undefined, openEventSource?: AgentStreamOpener, history?: AgentStreamHistory): AgentStreamState;
3
114
  /** Presentation inputs, not a wire schema. Producers validate retained data before rendering it. */
4
115
  interface ConversationNode {
5
116
  id: string;
@@ -189,7 +300,7 @@ declare function withPrompts<T extends ConversationRecord>(record: T): T;
189
300
  * Renders only the rows near the viewport of `scroller`. Row heights are measured as they render; unmeasured
190
301
  * rows use `estimate`. Spacers keep the scroll height, so the browser's scroll anchoring holds the reading place.
191
302
  */
192
- declare function VirtualList<T>({ items, keyOf, render, scroller, estimate, overscan, target, origin, targetAlign, virtualize, keepMounted }: {
303
+ declare function VirtualList<T>({ items, keyOf, render, scroller, estimate, overscan, target, origin, targetAlign, virtualize, keepMounted, arrival }: {
193
304
  items: readonly T[];
194
305
  keyOf: (item: T) => string;
195
306
  render: (item: T, index: number) => ReactNode;
@@ -206,6 +317,13 @@ declare function VirtualList<T>({ items, keyOf, render, scroller, estimate, over
206
317
  virtualize?: boolean;
207
318
  /** Keep one roving tab stop mounted when the reader scrolls away from it. */
208
319
  keepMounted?: string;
320
+ /** Animate a new followed row using the shared Brand motion tokens. */
321
+ arrival?: {
322
+ identity: unknown;
323
+ id?: string;
324
+ key?: string;
325
+ following: RefObject<boolean>;
326
+ };
209
327
  }): import("react").JSX.Element;
210
328
  /** Retained identity and recorded time define the hierarchy; labels never join sessions or invent parents. */
211
329
  declare function AgentTree({ index, actor, cutoff, select }: {
@@ -214,4 +332,19 @@ declare function AgentTree({ index, actor, cutoff, select }: {
214
332
  cutoff: number;
215
333
  select: (id: string) => void;
216
334
  }): import("react").JSX.Element;
217
- export { ConversationProps as a, ToolCall as c, recordFlowTrace as d, ConversationEvent as f, Conversation as i, indexRecord as l, ConversationRecord as m, VirtualList as n, EventFlag as o, ConversationNode as p, withPrompts as r, RecordIndex as s, AgentTree as t, model_d_exports as u };
335
+ declare function ToolStep({ item, previous }: {
336
+ item: Extract<AgentTimelineItem, {
337
+ kind: 'tool';
338
+ }>;
339
+ previous?: AgentTimelineStepKind;
340
+ }): import("react").JSX.Element;
341
+ /** The same prompt control for retained and streamed turns; opening state belongs to the reader. */
342
+ declare function PromptMore({ text, id, opened, setOpen }: {
343
+ text: string;
344
+ id: string;
345
+ opened: ReadonlySet<string>;
346
+ setOpen: (id: string, open: boolean) => void;
347
+ }): import("react").JSX.Element | null;
348
+ /** Live values use the same canonical items and tool presentation as retained conversations. */
349
+ declare function timelineItems(entries: readonly AgentTranscriptEntry[], streaming: boolean, opened?: ReadonlySet<string>): AgentTimelineItem[];
350
+ export { foldAgentRows as C, AgentTranscriptEntry as S, ConversationRecord as _, VirtualList as a, AgentStreamRow as b, ConversationProps as c, ToolCall as d, indexRecord as f, ConversationNode as g, ConversationEvent as h, AgentTree as i, EventFlag as l, recordFlowTrace as m, ToolStep as n, withPrompts as o, model_d_exports as p, timelineItems as r, Conversation as s, PromptMore as t, RecordIndex as u, AgentStreamHistory as v, useAgentStream as w, AgentStreamState as x, AgentStreamPage as y };
@@ -1,8 +1,8 @@
1
1
  import { l as AgentGraphNode, u as AgentGraphProps$1 } from "./AgentGraph-P7l-jZwo.js";
2
2
  import { t as AgentStreamOpener } from "./event-stream-DNEbvx4s.js";
3
- import "./index-gXcuwPOX.js";
3
+ import "./index-Bv2iiZaN.js";
4
4
  import { ReactNode } from "react";
5
- import { ApprovalCard, ApprovalCardProps, ApprovalDiffFile, ApprovalDiffSummary, ApprovalPlanStep, ExpandedToolDetail, ExpandedToolDetailProps, FeedSegment, InlineThinkingItem as InlineThinkingItem$1, InlineThinkingItemProps, InlineToolItem, InlineToolItemProps, LiveDuration, RunGroup, RunGroupProps, RunPhase, RunPhaseList, RunRowShell, RunRowShellProps, RunRowStatus, RunRowStatusDot, RunStatus, RunStatusIcon as RunStatusIcon$1, RunStatusIconProps, StatusMeta, TaskList, TaskListItem, TaskListProps, TaskStatus, ToolCallData, ToolCallData as ToolCallData$1, ToolCallFeed, ToolCallFeedProps, ToolCallStatus, ToolCallType, isOpen, parseToolEvent, runStatus as runStatus$1, showsTaskPriority, statusMeta as statusMeta$1, taskProgress, taskStatus } from "@tangle-network/ui/run";
5
+ import { ApprovalCard, ApprovalCardProps, ApprovalDiffFile, ApprovalDiffSummary, ApprovalPlanStep, ExpandedToolDetail, ExpandedToolDetailProps, FeedSegment, InlineThinkingItem, InlineThinkingItemProps, InlineToolItem, InlineToolItemProps, LiveDuration, RunGroup, RunGroupProps, RunPhase, RunPhaseList, RunRowShell, RunRowShellProps, RunRowStatus, RunRowStatusDot, RunStatus, RunStatusIcon as RunStatusIcon$1, RunStatusIconProps, StatusMeta, TaskList, TaskListItem, TaskListProps, TaskStatus, ToolCallData as ToolCallData$1, ToolCallFeed, ToolCallFeedProps, ToolCallStatus, ToolCallType, isOpen, parseToolEvent, runStatus as runStatus$1, showsTaskPriority, statusMeta as statusMeta$1, taskProgress, taskStatus } from "@tangle-network/ui/run";
6
6
  import { FlowWaterfallProps } from "@tangle-network/charts/react";
7
7
  import { LatestEvents, LatestEventsProps } from "@tangle-network/charts/react/agent-graph";
8
8
  import { FlowMarker, FlowSpan, FlowTrace } from "@tangle-network/charts";
@@ -15,64 +15,6 @@ type TraceWaterfallProps = FlowWaterfallProps;
15
15
  * `traces convert` contract. Import `@tangle-network/charts/react/flow-waterfall.css` once.
16
16
  */
17
17
  declare function TraceWaterfall({ renderIcon, ...props }: TraceWaterfallProps): import("react").JSX.Element;
18
- /** One row of an agent's message stream (tangle-tools `/api/discovery/runs/<run>/agents/<agent>/stream`). */
19
- interface AgentStreamRow {
20
- seq: number;
21
- /** ISO time the event happened. */
22
- at: string;
23
- stream?: string;
24
- attempt?: number;
25
- event: {
26
- kind: "text" | "reasoning" | "tool-call" | "tool-result" | "user" | "notice" | (string & {});
27
- text?: string;
28
- /** A notice's origin: the agent's `delegated-input`, its `recorded-result`, or a capture fact such as `capture-unavailable`. */
29
- provenance?: string;
30
- toolCallId?: string;
31
- toolName?: string;
32
- args?: unknown;
33
- result?: unknown;
34
- };
35
- }
36
- /** A transcript entry with the time it began, so a time cursor can show the conversation as of any moment. */
37
- type AgentTranscriptEntry = {
38
- id: string;
39
- at: number;
40
- kind: "message";
41
- role: "assistant" | "user";
42
- content: string;
43
- sealed?: true;
44
- } | {
45
- id: string;
46
- at: number;
47
- kind: "reasoning";
48
- text: string;
49
- } | {
50
- id: string;
51
- at: number;
52
- kind: "tool";
53
- call: ToolCallData;
54
- } | {
55
- id: string;
56
- at: number;
57
- kind: "notice";
58
- text: string;
59
- };
60
- interface AgentStreamState {
61
- generation?: string | number;
62
- entries: AgentTranscriptEntry[];
63
- lastSeq: number;
64
- /** The agent is still producing output. */
65
- alive: boolean;
66
- /** Why the stream shows nothing new; a reconnect that delivers rows clears it. */
67
- error?: string;
68
- }
69
- /** Fold stream rows into transcript entries: text of one turn merges, a tool call becomes a row its result completes. */
70
- declare function foldAgentRows(entries: AgentTranscriptEntry[], rows: readonly AgentStreamRow[]): AgentTranscriptEntry[];
71
- /**
72
- * Follow one agent's message stream over Server-Sent Events: `rows`, `reset` and `end` events, reconnecting with
73
- * `?after=<lastSeq>` when the server closes the connection, so a long turn streams without gaps or repeats.
74
- */
75
- declare function useAgentStream(url: string | undefined, openEventSource?: AgentStreamOpener): AgentStreamState;
76
18
  /** A moment on the run's event track: a release, a check verdict, a spawn, a crash or a steer. */
77
19
  interface TraceEvent extends FlowMarker {}
78
20
  interface TraceWorkspaceProps extends Omit<TraceWaterfallProps, "trace" | "markers" | "onSelect" | "onTimeChange" | "selectedId" | "onDeselect" | "graph" | "latestEvents"> {
@@ -114,4 +56,4 @@ interface TraceWorkspaceProps extends Omit<TraceWaterfallProps, "trace" | "marke
114
56
  * every panel shows what was true at the cursor, and the conversation shows what had been said by then.
115
57
  */
116
58
  declare function TraceWorkspace({ trace, streamUrl, openEventSource, events, onTimeChange, files, scoreboard, selectedAgentId, conversationOpen, onSelectAgent, agentCards, agentGraph, className, ...waterfall }: TraceWorkspaceProps): import("react").JSX.Element;
117
- export { TraceWaterfallProps as $, ToolCallData$1 as A, taskProgress as B, RunStatusIcon$1 as C, TaskListItem as D, TaskList as E, isOpen as F, TraceWorkspace as G, LatestEvents as H, parseToolEvent as I, AgentStreamState as J, TraceWorkspaceProps as K, runStatus$1 as L, ToolCallFeedProps as M, ToolCallStatus as N, TaskListProps as O, ToolCallType as P, TraceWaterfall as Q, showsTaskPriority as R, RunStatus as S, StatusMeta as T, LatestEventsProps as U, taskStatus as V, TraceEvent as W, foldAgentRows as X, AgentTranscriptEntry as Y, useAgentStream as Z, RunPhaseList as _, ApprovalPlanStep as a, RunRowStatus as b, FeedSegment as c, InlineToolItem as d, traceSpanMark as et, InlineToolItemProps as f, RunPhase as g, RunGroupProps as h, ApprovalDiffSummary as i, ToolCallFeed as j, TaskStatus as k, InlineThinkingItem$1 as l, RunGroup as m, ApprovalCardProps as n, ExpandedToolDetail as o, LiveDuration as p, AgentStreamRow as q, ApprovalDiffFile as r, ExpandedToolDetailProps as s, ApprovalCard as t, InlineThinkingItemProps as u, RunRowShell as v, RunStatusIconProps as w, RunRowStatusDot as x, RunRowShellProps as y, statusMeta$1 as z };
59
+ export { ToolCallData$1 as A, taskProgress as B, RunStatusIcon$1 as C, TaskListItem as D, TaskList as E, isOpen as F, TraceWorkspace as G, LatestEvents as H, parseToolEvent as I, TraceWaterfallProps as J, TraceWorkspaceProps as K, runStatus$1 as L, ToolCallFeedProps as M, ToolCallStatus as N, TaskListProps as O, ToolCallType as P, showsTaskPriority as R, RunStatus as S, StatusMeta as T, LatestEventsProps as U, taskStatus as V, TraceEvent as W, traceSpanMark as Y, RunPhaseList as _, ApprovalPlanStep as a, RunRowStatus as b, FeedSegment as c, InlineToolItem as d, InlineToolItemProps as f, RunPhase as g, RunGroupProps as h, ApprovalDiffSummary as i, ToolCallFeed as j, TaskStatus as k, InlineThinkingItem as l, RunGroup as m, ApprovalCardProps as n, ExpandedToolDetail as o, LiveDuration as p, TraceWaterfall as q, ApprovalDiffFile as r, ExpandedToolDetailProps as s, ApprovalCard as t, InlineThinkingItemProps as u, RunRowShell as v, RunStatusIconProps as w, RunRowStatusDot as x, RunRowShellProps as y, statusMeta$1 as z };