@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.
- package/dist/AgentTree-D4d06rfH.js +293 -0
- package/dist/{ResearchReport-vqefUbVp.js → ResearchReport-D1TFmldm.js} +2 -1
- package/dist/{VirtualList-CMynqkkh.js → VirtualList-DcSGbEtA.js} +28 -1
- package/dist/{index-gXcuwPOX.d.ts → index-Bv2iiZaN.d.ts} +135 -2
- package/dist/{index-YU_b9xCK.d.ts → index-CHA38az4.d.ts} +3 -61
- package/dist/index.d.ts +3 -3
- package/dist/index.js +9 -8
- package/dist/record/ResearchReport.js +1 -1
- package/dist/{record-B_4XWfUz.js → record-C-EUpK-n.js} +3 -2
- package/dist/record.js +1 -1
- package/dist/report-viewer.js +80 -80
- package/dist/run/live.js +2 -2
- package/dist/run/record.d.ts +2 -2
- package/dist/run/record.js +5 -4
- package/dist/run.d.ts +3 -3
- package/dist/run.js +6 -5
- package/dist/runtime-viewer/{AgentGraphCanvas-DGq7_u8--WPFPgd72.js → AgentGraphCanvas-DGq7_u8--C6yDfIUT.js} +67 -67
- package/dist/runtime-viewer/{latest-events-CRq9sGkK-YFXUh9qO.js → latest-events-CRq9sGkK-CfoBl1dP.js} +215 -209
- package/dist/{trace-workspace-BiJbv9WQ.js → trace-workspace-B634-EcA.js} +287 -201
- package/dist/{tree-data-9D309DqD.js → tree-data-rg5voiY8.js} +1 -1
- package/dist/{AgentTree-Cju8jn51.js → use-follow-tail-DZFn7QDO.js} +144 -385
- package/dist/vault-tree.js +1 -1
- package/dist/{workspace-BrS_rHWN.js → workspace-CJD7oOEa.js} +1 -1
- package/dist/{workspace-files-pane-Di_rn4FL.js → workspace-files-pane-D24G7H_Z.js} +1 -1
- package/dist/workspace-viewer.js +9970 -9624
- package/dist/workspace.js +2 -2
- package/package.json +5 -4
- 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 {
|
|
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
|
-
|
|
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-
|
|
3
|
+
import "./index-Bv2iiZaN.js";
|
|
4
4
|
import { ReactNode } from "react";
|
|
5
|
-
import { ApprovalCard, ApprovalCardProps, ApprovalDiffFile, ApprovalDiffSummary, ApprovalPlanStep, ExpandedToolDetail, ExpandedToolDetailProps, FeedSegment, InlineThinkingItem
|
|
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 {
|
|
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 };
|