@tangle-network/sandbox-ui 3.0.2 → 4.0.0
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/README.md +0 -47
- 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/globals.css +12 -3
- 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-CQGMhSg0.d.ts → index-Z6RCpkmT.d.ts} +16 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.js +10 -10
- 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/styles.css +12 -3
- 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/{workbench-Z9wbei53.js → workbench-DWQ0pm9w.js} +311 -2
- package/dist/workbench.d.ts +2 -2
- package/dist/workbench.js +2 -2
- 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 -8
- package/dist/connections-DymjzHe_.js +0 -179
- package/dist/connections.d.ts +0 -2
- package/dist/connections.js +0 -1
- package/dist/index-DLX35YAa.d.ts +0 -59
- package/dist/use-follow-tail-Ht7fZGQQ.js +0 -1
package/dist/styles.css
CHANGED
|
@@ -3968,6 +3968,18 @@
|
|
|
3968
3968
|
.text-\[var\(--surface-warning-text\)\] {
|
|
3969
3969
|
color: var(--surface-warning-text);
|
|
3970
3970
|
}
|
|
3971
|
+
.text-\[var\(--syntax-function\,currentColor\)\] {
|
|
3972
|
+
color: var(--syntax-function,currentColor);
|
|
3973
|
+
}
|
|
3974
|
+
.text-\[var\(--syntax-keyword\,currentColor\)\] {
|
|
3975
|
+
color: var(--syntax-keyword,currentColor);
|
|
3976
|
+
}
|
|
3977
|
+
.text-\[var\(--syntax-number\,currentColor\)\] {
|
|
3978
|
+
color: var(--syntax-number,currentColor);
|
|
3979
|
+
}
|
|
3980
|
+
.text-\[var\(--syntax-string\,currentColor\)\] {
|
|
3981
|
+
color: var(--syntax-string,currentColor);
|
|
3982
|
+
}
|
|
3971
3983
|
.text-\[var\(--text-dim\)\] {
|
|
3972
3984
|
color: var(--text-dim);
|
|
3973
3985
|
}
|
|
@@ -5991,9 +6003,6 @@
|
|
|
5991
6003
|
text-overflow: ellipsis;
|
|
5992
6004
|
white-space: nowrap;
|
|
5993
6005
|
}
|
|
5994
|
-
.sm\:p-4 {
|
|
5995
|
-
padding: calc(var(--spacing) * 4);
|
|
5996
|
-
}
|
|
5997
6006
|
.sm\:p-5 {
|
|
5998
6007
|
padding: calc(var(--spacing) * 5);
|
|
5999
6008
|
}
|
|
@@ -2,13 +2,13 @@ import { t as cn } from "./utils-BER_bdgE.js";
|
|
|
2
2
|
import { i as modelBrandFor, t as ModelBrandStack } from "./model-brand-BQlarCIo.js";
|
|
3
3
|
import { t as ProviderIcon } from "./provider-logo-CPKRPHcS.js";
|
|
4
4
|
import { t as AgentGraph$1 } from "./AgentGraph-BGWx9hhS.js";
|
|
5
|
-
import { t as useFollowTail } from "./use-follow-tail-
|
|
5
|
+
import { s as timelineItems, t as useFollowTail } from "./use-follow-tail-DZFn7QDO.js";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import {
|
|
7
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
8
8
|
import { X } from "lucide-react";
|
|
9
9
|
import { activityTiming, ambientStyle, syncAmbient } from "@tangle-network/charts/react/agent-graph/presentation";
|
|
10
10
|
import { AgentTimeline } from "@tangle-network/ui/chat";
|
|
11
|
-
import {
|
|
11
|
+
import { runStatus } from "@tangle-network/ui/run";
|
|
12
12
|
import { FlowWaterfall, toolGlyph } from "@tangle-network/charts/react";
|
|
13
13
|
import { LatestEvents } from "@tangle-network/charts/react/agent-graph";
|
|
14
14
|
import { useEventStream } from "@tangle-network/ui/hooks";
|
|
@@ -42,6 +42,16 @@ function TraceWaterfall({ renderIcon = traceSpanMark, ...props }) {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
// src/run/agent-stream.ts
|
|
45
|
+
const textOf = (value) => value == null ? void 0 : typeof value === "string" ? value : JSON.stringify(value);
|
|
46
|
+
const failed = (value) => typeof value === "object" && value !== null && ("error" in value || value.is_error === true || value.isError === true);
|
|
47
|
+
const recorded = (text) => {
|
|
48
|
+
try {
|
|
49
|
+
const value = JSON.parse(text);
|
|
50
|
+
return value && typeof value === "object" ? `\`\`\`json\n${text}\n\`\`\`` : text;
|
|
51
|
+
} catch {
|
|
52
|
+
return text;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
45
55
|
const TOOL_TYPES = /* @__PURE__ */ new Set([
|
|
46
56
|
"bash",
|
|
47
57
|
"read",
|
|
@@ -54,215 +64,330 @@ const TOOL_TYPES = /* @__PURE__ */ new Set([
|
|
|
54
64
|
"inspect",
|
|
55
65
|
"audit"
|
|
56
66
|
]);
|
|
57
|
-
const toolType = (name) => {
|
|
58
|
-
const key = (name ?? "").toLowerCase();
|
|
59
|
-
return TOOL_TYPES.has(key) ? key : "unknown";
|
|
60
|
-
};
|
|
61
|
-
const toolText = (value) => {
|
|
62
|
-
if (value === void 0 || value === null) return void 0;
|
|
63
|
-
return typeof value === "string" ? value : JSON.stringify(value);
|
|
64
|
-
};
|
|
65
|
-
const failed = (result) => typeof result === "object" && result !== null && ("error" in result || result.is_error === true);
|
|
66
|
-
const recorded = (text) => {
|
|
67
|
-
try {
|
|
68
|
-
const value = JSON.parse(text);
|
|
69
|
-
return typeof value === "object" && value !== null ? `\`\`\`json\n${text}\n\`\`\`` : text;
|
|
70
|
-
} catch {
|
|
71
|
-
return text;
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
/** Fold stream rows into transcript entries: text of one turn merges, a tool call becomes a row its result completes. */
|
|
75
67
|
function foldAgentRows(entries, rows) {
|
|
76
68
|
const next = [...entries];
|
|
77
69
|
for (const row of rows) {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
70
|
+
const event = row.event;
|
|
71
|
+
if (!event) continue;
|
|
72
|
+
const at = Date.parse(row.at ?? ""), scope = JSON.stringify([row.stream ?? null, row.attempt ?? null]);
|
|
73
|
+
const base = {
|
|
74
|
+
id: event.id ?? `${scope}:${row.seq}`,
|
|
75
|
+
at,
|
|
76
|
+
scope,
|
|
77
|
+
attempt: row.attempt,
|
|
78
|
+
provenance: event.provenance,
|
|
79
|
+
isError: event.isError
|
|
80
|
+
}, last = next.at(-1);
|
|
81
|
+
const kind = event.kind.replaceAll("_", "-").replace(/-delta$/, "");
|
|
82
|
+
if ((kind === "text" || kind === "reasoning") && event.text) {
|
|
83
|
+
if (kind === "text") {
|
|
84
|
+
if (last?.kind === "message" && last.role === "assistant" && !last.sealed && last.scope === scope && !event.sealed) next[next.length - 1] = {
|
|
85
|
+
...last,
|
|
86
|
+
content: last.content + event.text
|
|
87
|
+
};
|
|
88
|
+
else next.push({
|
|
89
|
+
...base,
|
|
90
|
+
kind: "message",
|
|
91
|
+
role: "assistant",
|
|
92
|
+
content: event.text,
|
|
93
|
+
sealed: event.sealed ? true : void 0
|
|
94
|
+
});
|
|
95
|
+
} else if (last?.kind === "reasoning" && last.scope === scope) next[next.length - 1] = {
|
|
83
96
|
...last,
|
|
84
|
-
|
|
97
|
+
text: last.text + event.text
|
|
85
98
|
};
|
|
86
99
|
else next.push({
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
role: "assistant",
|
|
91
|
-
content: event.text
|
|
100
|
+
...base,
|
|
101
|
+
kind: "reasoning",
|
|
102
|
+
text: event.text
|
|
92
103
|
});
|
|
93
|
-
} else if (
|
|
94
|
-
|
|
95
|
-
at,
|
|
104
|
+
} else if (kind === "user" && event.text) next.push({
|
|
105
|
+
...base,
|
|
96
106
|
kind: "message",
|
|
97
107
|
role: "user",
|
|
98
108
|
content: event.text
|
|
99
109
|
});
|
|
100
|
-
else if (
|
|
101
|
-
if (event.provenance === "delegated-input") next.push({
|
|
102
|
-
|
|
103
|
-
at,
|
|
110
|
+
else if (kind === "notice" && event.text) {
|
|
111
|
+
if (event.provenance === "delegated-input" || event.provenance === "recorded-result") next.push({
|
|
112
|
+
...base,
|
|
104
113
|
kind: "message",
|
|
105
|
-
role: "user",
|
|
106
|
-
content: recorded(event.text)
|
|
107
|
-
});
|
|
108
|
-
else if (event.provenance === "recorded-result") next.push({
|
|
109
|
-
id: `m-${row.seq}`,
|
|
110
|
-
at,
|
|
111
|
-
kind: "message",
|
|
112
|
-
role: "assistant",
|
|
114
|
+
role: event.provenance === "delegated-input" ? "user" : "assistant",
|
|
113
115
|
content: recorded(event.text),
|
|
114
116
|
sealed: true
|
|
115
117
|
});
|
|
116
118
|
else next.push({
|
|
117
|
-
|
|
118
|
-
at,
|
|
119
|
+
...base,
|
|
119
120
|
kind: "notice",
|
|
120
121
|
text: event.text
|
|
121
122
|
});
|
|
122
|
-
} else if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
} else if (kind === "tool-call" || kind === "tool-result") {
|
|
124
|
+
const id = JSON.stringify([
|
|
125
|
+
row.stream ?? null,
|
|
126
|
+
row.attempt ?? null,
|
|
127
|
+
event.toolCallId ?? row.seq
|
|
128
|
+
]);
|
|
129
|
+
const index = next.findIndex((entry) => entry.kind === "tool" && entry.call.id === id), prior = next[index];
|
|
130
|
+
if (kind === "tool-call") {
|
|
131
|
+
const name = event.toolName ?? "tool", type = name.toLowerCase();
|
|
132
|
+
next.push({
|
|
133
|
+
...base,
|
|
134
|
+
id,
|
|
135
|
+
kind: "tool",
|
|
136
|
+
name,
|
|
137
|
+
input: event.args,
|
|
138
|
+
call: {
|
|
139
|
+
id,
|
|
140
|
+
type: TOOL_TYPES.has(type) ? type : "unknown",
|
|
141
|
+
label: name,
|
|
142
|
+
status: "running",
|
|
143
|
+
detail: textOf(event.args)
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
} else if (prior?.kind === "tool") next[index] = {
|
|
147
|
+
...prior,
|
|
148
|
+
costUsd: event.costUsd ?? prior.costUsd,
|
|
149
|
+
call: {
|
|
150
|
+
...prior.call,
|
|
151
|
+
status: event.isError || failed(event.result) ? "error" : "success",
|
|
152
|
+
output: textOf(event.result),
|
|
153
|
+
...event.durationMs !== void 0 ? { duration: event.durationMs } : event.atBasis !== "carried" && Number.isFinite(at) && Number.isFinite(prior.at) ? { duration: Math.max(0, at - prior.at) } : {}
|
|
154
|
+
}
|
|
126
155
|
};
|
|
127
156
|
else next.push({
|
|
128
|
-
|
|
129
|
-
at,
|
|
130
|
-
kind: "reasoning",
|
|
131
|
-
text: event.text
|
|
132
|
-
});
|
|
133
|
-
} else if (event.kind === "tool-call") {
|
|
134
|
-
const id = event.toolCallId ?? `t-${row.seq}`;
|
|
135
|
-
next.push({
|
|
157
|
+
...base,
|
|
136
158
|
id,
|
|
137
|
-
at,
|
|
138
159
|
kind: "tool",
|
|
139
160
|
call: {
|
|
140
161
|
id,
|
|
141
|
-
type:
|
|
142
|
-
label: event.toolName ?? "
|
|
143
|
-
status: "
|
|
144
|
-
|
|
162
|
+
type: "unknown",
|
|
163
|
+
label: event.toolName ?? "Tool result",
|
|
164
|
+
status: event.isError || failed(event.result) ? "error" : "success",
|
|
165
|
+
output: textOf(event.result)
|
|
145
166
|
}
|
|
146
167
|
});
|
|
147
|
-
} else if (event.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
call: {
|
|
153
|
-
...entry.call,
|
|
154
|
-
status: failed(event.result) ? "error" : "success",
|
|
155
|
-
output: toolText(event.result),
|
|
156
|
-
duration: Math.max(0, at - entry.at)
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
}
|
|
168
|
+
} else if (event.text) next.push({
|
|
169
|
+
...base,
|
|
170
|
+
kind: "notice",
|
|
171
|
+
text: event.text
|
|
172
|
+
});
|
|
160
173
|
}
|
|
161
174
|
return next;
|
|
162
175
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
176
|
+
const empty = (identity, history) => ({
|
|
177
|
+
identity,
|
|
178
|
+
rows: [],
|
|
179
|
+
first: null,
|
|
180
|
+
lastSeq: -1,
|
|
181
|
+
alive: !!identity && (history?.alive ?? true),
|
|
182
|
+
ended: false,
|
|
183
|
+
loading: !!history,
|
|
184
|
+
ready: !history,
|
|
185
|
+
earlier: false,
|
|
186
|
+
more: false,
|
|
187
|
+
reading: false
|
|
188
|
+
});
|
|
189
|
+
function receive(prior, page, direction, fromHead) {
|
|
190
|
+
if (!Array.isArray(page.events)) throw new Error("Invalid agent rows stream");
|
|
191
|
+
const fresh = direction === "tail" || direction === "head" || page.reset || page.generation !== void 0 && page.generation !== prior.generation;
|
|
192
|
+
const merged = fresh ? page.events : direction === "before" ? [...page.events, ...prior.rows] : [...prior.rows, ...page.events];
|
|
193
|
+
let rows = [...new Map(merged.map((row) => [row.seq, row])).values()].sort((a, b) => a.seq - b.seq);
|
|
194
|
+
const trimmed = rows.length > 2e3;
|
|
195
|
+
if (trimmed) rows = prior.reading ? rows.slice(0, 2e3) : rows.slice(-2e3);
|
|
196
|
+
const first = fresh ? page.firstSeq ?? rows[0]?.seq ?? null : direction === "before" ? page.firstSeq ?? prior.first : trimmed && !prior.reading ? rows[0]?.seq ?? prior.first : prior.first;
|
|
197
|
+
const lastSeq = fresh ? page.lastSeq ?? rows.at(-1)?.seq ?? -1 : direction === "before" ? prior.lastSeq : page.lastSeq ?? rows.at(-1)?.seq ?? prior.lastSeq;
|
|
198
|
+
return {
|
|
199
|
+
...prior,
|
|
200
|
+
rows,
|
|
201
|
+
first,
|
|
202
|
+
lastSeq,
|
|
203
|
+
generation: page.generation ?? prior.generation,
|
|
204
|
+
alive: page.alive ?? prior.alive,
|
|
205
|
+
ended: page.alive === false,
|
|
206
|
+
loading: false,
|
|
207
|
+
ready: true,
|
|
208
|
+
error: void 0,
|
|
209
|
+
earlier: trimmed && direction !== "before" || (direction !== "after" || fresh ? page.hasEarlier ?? (first !== null && first > 0) : prior.earlier),
|
|
210
|
+
more: direction === "before" ? prior.more : fromHead && !!page.hasMore
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async function readPage(url, direction, before, signal) {
|
|
214
|
+
const query = new URL(url, location.href), cursor = direction === "head" ? 200 : direction === "after" ? before.lastSeq : direction === "before" ? before.first : null;
|
|
215
|
+
query.searchParams.set("limit", "200");
|
|
216
|
+
if (cursor !== null && cursor >= 0) query.searchParams.set(direction === "head" ? "before" : direction, String(cursor));
|
|
217
|
+
if (before.generation !== void 0 && cursor !== null) query.searchParams.set("generation", String(before.generation));
|
|
218
|
+
const response = await fetch(query, {
|
|
219
|
+
credentials: "same-origin",
|
|
220
|
+
signal
|
|
221
|
+
});
|
|
222
|
+
if (!response.ok) throw new Error(`Transcript unavailable (HTTP ${response.status})`);
|
|
223
|
+
return response.json();
|
|
224
|
+
}
|
|
225
|
+
function useAgentWindow(url, history) {
|
|
226
|
+
const identity = url ? JSON.stringify([url, history?.url]) : void 0;
|
|
227
|
+
const [stored, put] = useState(() => empty(identity, history)), current = useRef(stored);
|
|
228
|
+
const state = stored.identity === identity ? stored : empty(identity, history);
|
|
229
|
+
const [head, begin] = useState(), [revision, reload] = useState(0);
|
|
230
|
+
const beginning = identity !== void 0 && head === identity;
|
|
231
|
+
const pageReader = useRef(() => {}), previous = useRef({
|
|
232
|
+
identity,
|
|
233
|
+
alive: history?.alive
|
|
234
|
+
});
|
|
235
|
+
const update = (value) => {
|
|
236
|
+
if (value.identity === identity) {
|
|
237
|
+
current.current = value;
|
|
238
|
+
put(value);
|
|
184
239
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
240
|
+
};
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
const retain = previous.current.identity === identity && previous.current.alive && history?.alive === false;
|
|
243
|
+
previous.current = {
|
|
244
|
+
identity,
|
|
245
|
+
alive: history?.alive
|
|
189
246
|
};
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
247
|
+
if (!retain) update(empty(identity, history));
|
|
248
|
+
if (!url || !history) return;
|
|
249
|
+
const controller = new AbortController(), fromHead = beginning || !history.alive && !retain;
|
|
250
|
+
let cancelled = false, pending = false;
|
|
251
|
+
const load = async (direction) => {
|
|
252
|
+
if (cancelled || pending) return;
|
|
253
|
+
pending = true;
|
|
254
|
+
const cursor = current.current.lastSeq;
|
|
255
|
+
try {
|
|
256
|
+
const page = await readPage(history.url, direction, current.current, controller.signal);
|
|
257
|
+
if (cancelled) return;
|
|
258
|
+
if (direction === "head" && !page.events.length) {
|
|
259
|
+
queueMicrotask(() => void load("tail"));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
update(receive(current.current, page, direction, fromHead));
|
|
263
|
+
if (!fromHead && direction !== "before" && !history.alive && page.hasMore && current.current.lastSeq !== cursor) queueMicrotask(() => void load("after"));
|
|
264
|
+
} catch (cause) {
|
|
265
|
+
if (!cancelled && !controller.signal.aborted) update({
|
|
266
|
+
...current.current,
|
|
267
|
+
loading: false,
|
|
268
|
+
error: cause instanceof Error ? cause.message : String(cause)
|
|
269
|
+
});
|
|
270
|
+
} finally {
|
|
271
|
+
pending = false;
|
|
272
|
+
}
|
|
193
273
|
};
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
274
|
+
pageReader.current = (direction) => {
|
|
275
|
+
if (direction === "before") update({
|
|
276
|
+
...current.current,
|
|
277
|
+
reading: true
|
|
278
|
+
});
|
|
279
|
+
load(direction);
|
|
197
280
|
};
|
|
198
|
-
|
|
281
|
+
load(retain && current.current.lastSeq >= 0 ? "after" : fromHead ? "head" : "tail");
|
|
282
|
+
return () => {
|
|
283
|
+
cancelled = true;
|
|
284
|
+
controller.abort();
|
|
285
|
+
pageReader.current = () => {};
|
|
286
|
+
};
|
|
287
|
+
}, [
|
|
288
|
+
identity,
|
|
289
|
+
history?.alive,
|
|
290
|
+
beginning,
|
|
291
|
+
revision
|
|
292
|
+
]);
|
|
293
|
+
return {
|
|
294
|
+
state,
|
|
295
|
+
current,
|
|
296
|
+
update,
|
|
297
|
+
beginning,
|
|
298
|
+
begin,
|
|
299
|
+
reload,
|
|
300
|
+
pageReader
|
|
301
|
+
};
|
|
199
302
|
}
|
|
200
|
-
/**
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
});
|
|
210
|
-
const cursor = useRef({ lastSeq: 0 });
|
|
211
|
-
useEventStream(url, {
|
|
303
|
+
/** Same named SSE lifecycle for every consumer; the actual history endpoint owns bounded bootstrap/pages. */
|
|
304
|
+
function useAgentStream(url, openEventSource, history) {
|
|
305
|
+
const { state, current, update, beginning, begin, reload, pageReader } = useAgentWindow(url, history);
|
|
306
|
+
const streamUrl = useCallback(() => {
|
|
307
|
+
const target = new URL(url, location.href);
|
|
308
|
+
if (history && current.current.generation !== void 0) target.searchParams.set("generation", String(current.current.generation));
|
|
309
|
+
return target.toString();
|
|
310
|
+
}, [url, !!history]);
|
|
311
|
+
useEventStream(!url || history && (!state.ready || state.ended || state.reading || beginning || !history.alive) ? void 0 : streamUrl, {
|
|
212
312
|
opener: openEventSource,
|
|
213
|
-
after: () =>
|
|
214
|
-
onStart: () => {
|
|
215
|
-
cursor.current = { lastSeq: 0 };
|
|
216
|
-
dispatch({ type: "reset" });
|
|
217
|
-
},
|
|
313
|
+
after: () => current.current.lastSeq,
|
|
218
314
|
onLiveChange: (live) => {
|
|
219
|
-
if (!live)
|
|
315
|
+
if (!live && !current.current.ended) update({
|
|
316
|
+
...current.current,
|
|
317
|
+
error: current.current.error ?? "The agent stream is unreachable; the viewer may be closed."
|
|
318
|
+
});
|
|
220
319
|
},
|
|
221
320
|
events: {
|
|
222
321
|
rows: (message) => {
|
|
223
322
|
try {
|
|
224
|
-
|
|
225
|
-
if (!Array.isArray(data.events)) throw new Error("Invalid agent rows stream");
|
|
226
|
-
if (data.generation !== void 0 && data.generation !== cursor.current.generation) cursor.current = {
|
|
227
|
-
lastSeq: 0,
|
|
228
|
-
generation: data.generation
|
|
229
|
-
};
|
|
230
|
-
cursor.current.lastSeq = Math.max(cursor.current.lastSeq, data.lastSeq ?? 0, ...data.events.map((row) => row.seq));
|
|
231
|
-
dispatch({
|
|
232
|
-
type: "rows",
|
|
233
|
-
generation: data.generation,
|
|
234
|
-
rows: data.events,
|
|
235
|
-
alive: data.alive
|
|
236
|
-
});
|
|
323
|
+
update(receive(current.current, JSON.parse(message.data), "after", false));
|
|
237
324
|
} catch (cause) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
325
|
+
update({
|
|
326
|
+
...current.current,
|
|
327
|
+
error: String(cause)
|
|
241
328
|
});
|
|
242
329
|
}
|
|
243
330
|
},
|
|
244
331
|
reset: (message) => {
|
|
245
332
|
try {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
dispatch({
|
|
252
|
-
type: "reset",
|
|
253
|
-
generation
|
|
333
|
+
update({
|
|
334
|
+
...empty(state.identity, history),
|
|
335
|
+
generation: JSON.parse(message.data).generation,
|
|
336
|
+
ready: true,
|
|
337
|
+
loading: false
|
|
254
338
|
});
|
|
255
339
|
} catch (cause) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
340
|
+
update({
|
|
341
|
+
...current.current,
|
|
342
|
+
error: String(cause)
|
|
259
343
|
});
|
|
260
344
|
}
|
|
261
345
|
},
|
|
262
|
-
end: () =>
|
|
346
|
+
end: () => update({
|
|
347
|
+
...current.current,
|
|
348
|
+
alive: false,
|
|
349
|
+
ended: true,
|
|
350
|
+
loading: false,
|
|
351
|
+
error: void 0
|
|
352
|
+
}),
|
|
353
|
+
unavailable: () => update({
|
|
354
|
+
...current.current,
|
|
355
|
+
error: "Live updates are temporarily unavailable"
|
|
356
|
+
})
|
|
263
357
|
}
|
|
264
358
|
});
|
|
265
|
-
|
|
359
|
+
let entries = [], error = state.error;
|
|
360
|
+
try {
|
|
361
|
+
entries = foldAgentRows([], history?.projectRows?.(state.rows) ?? state.rows);
|
|
362
|
+
} catch (cause) {
|
|
363
|
+
error = cause instanceof Error ? cause.message : String(cause);
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
generation: state.generation,
|
|
367
|
+
entries,
|
|
368
|
+
lastSeq: state.lastSeq,
|
|
369
|
+
alive: state.alive,
|
|
370
|
+
error,
|
|
371
|
+
...history ? { history: {
|
|
372
|
+
loading: state.loading,
|
|
373
|
+
earlier: state.earlier,
|
|
374
|
+
more: state.more,
|
|
375
|
+
reading: state.reading,
|
|
376
|
+
beginning,
|
|
377
|
+
emptyTail: state.ended && !state.rows.length && state.first === null && state.lastSeq < 0,
|
|
378
|
+
older: () => {
|
|
379
|
+
if (current.current.identity === state.identity) pageReader.current("before");
|
|
380
|
+
},
|
|
381
|
+
newer: () => {
|
|
382
|
+
if (current.current.identity === state.identity) pageReader.current("after");
|
|
383
|
+
},
|
|
384
|
+
latest: () => {
|
|
385
|
+
begin(void 0);
|
|
386
|
+
reload((value) => value + 1);
|
|
387
|
+
},
|
|
388
|
+
beginningPage: () => begin(state.identity)
|
|
389
|
+
} } : {}
|
|
390
|
+
};
|
|
266
391
|
}
|
|
267
392
|
// src/run/trace-workspace.tsx
|
|
268
393
|
/** The agent that owns a span: the span itself when it is an agent, else its nearest agent ancestor. */
|
|
@@ -352,48 +477,6 @@ function agentGraphAt(spans, byId, at, epoch, cards, extraEdges = []) {
|
|
|
352
477
|
edges
|
|
353
478
|
};
|
|
354
479
|
}
|
|
355
|
-
function timelineItems(entries, streaming) {
|
|
356
|
-
return entries.map((entry, index) => {
|
|
357
|
-
if (entry.kind === "message") return {
|
|
358
|
-
id: entry.id,
|
|
359
|
-
kind: "message",
|
|
360
|
-
role: entry.role,
|
|
361
|
-
content: entry.content,
|
|
362
|
-
isStreaming: streaming && index === entries.length - 1
|
|
363
|
-
};
|
|
364
|
-
if (entry.kind === "tool") return {
|
|
365
|
-
id: entry.id,
|
|
366
|
-
kind: "tool",
|
|
367
|
-
call: entry.call
|
|
368
|
-
};
|
|
369
|
-
if (entry.kind === "notice") return {
|
|
370
|
-
id: entry.id,
|
|
371
|
-
kind: "custom",
|
|
372
|
-
content: /* @__PURE__ */ jsx("p", {
|
|
373
|
-
className: "text-xs text-muted-foreground",
|
|
374
|
-
children: entry.text
|
|
375
|
-
})
|
|
376
|
-
};
|
|
377
|
-
return {
|
|
378
|
-
id: entry.id,
|
|
379
|
-
kind: "custom",
|
|
380
|
-
content: /* @__PURE__ */ jsx(InlineThinkingItem, {
|
|
381
|
-
part: {
|
|
382
|
-
type: "reasoning",
|
|
383
|
-
text: entry.text
|
|
384
|
-
},
|
|
385
|
-
defaultOpen: false,
|
|
386
|
-
openWhileActive: false
|
|
387
|
-
})
|
|
388
|
-
};
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
function NotTimeIndexed({ label }) {
|
|
392
|
-
return /* @__PURE__ */ jsxs("p", {
|
|
393
|
-
className: "p-4 text-sm text-muted-foreground",
|
|
394
|
-
children: [label, ": not time-indexed"]
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
480
|
/**
|
|
398
481
|
* The run workspace: the agent timeline and span waterfall over one clock, the selected agent's conversation
|
|
399
482
|
* streaming in a right-hand drawer, and the page's code workspace and scoreboard following the time cursor. Scrubbing is time travel:
|
|
@@ -585,7 +668,10 @@ function TraceWorkspace({ trace, streamUrl, openEventSource, events, onTimeChang
|
|
|
585
668
|
className: "p-4 text-sm text-muted-foreground",
|
|
586
669
|
children: stream.error ?? "No messages yet."
|
|
587
670
|
})
|
|
588
|
-
}) : /* @__PURE__ */ jsx(
|
|
671
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
672
|
+
className: "p-4 text-sm text-muted-foreground",
|
|
673
|
+
children: "Conversation: not time-indexed"
|
|
674
|
+
})
|
|
589
675
|
}),
|
|
590
676
|
unseen && /* @__PURE__ */ jsx("button", {
|
|
591
677
|
type: "button",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as revealInScroller } from "./reveal-in-scroller-CzKwuqCG.js";
|
|
2
|
-
import { t as VirtualList } from "./VirtualList-
|
|
2
|
+
import { t as VirtualList } from "./VirtualList-DcSGbEtA.js";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { BookOpen, Braces, ChevronRight, File, FileCode, FileCog, FileImage, FileLock, FileSpreadsheet, FileTerminal, FileText, Folder, FolderOpen, GitBranch, Package, Scale } from "lucide-react";
|