@tangle-network/sandbox-ui 3.0.1 → 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-CSNpZ-pj.js → ResearchReport-D1TFmldm.js} +2 -1
  3. package/dist/{VirtualList-DLh2JE0F.js → VirtualList-DcSGbEtA.js} +122 -67
  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-Ct_MZeZC.js → record-C-EUpK-n.js} +3 -2
  10. package/dist/record.js +1 -1
  11. package/dist/report-viewer.js +96 -96
  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-B_IXAIgg.js → tree-data-rg5voiY8.js} +1 -1
  21. package/dist/{AgentTree-CJRVpgPq.js → use-follow-tail-DZFn7QDO.js} +144 -385
  22. package/dist/vault-tree.js +1 -1
  23. package/dist/{workspace-CAdAoNmW.js → workspace-CJD7oOEa.js} +1 -1
  24. package/dist/{workspace-files-pane-C0PeY6rY.js → workspace-files-pane-D24G7H_Z.js} +1 -1
  25. package/dist/workspace-viewer.js +9265 -8896
  26. package/dist/workspace.js +2 -2
  27. package/package.json +5 -4
  28. package/dist/use-follow-tail-Ht7fZGQQ.js +0 -1
@@ -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-Ht7fZGQQ.js";
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 { useMemo, useReducer, useRef, useState } from "react";
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 { InlineThinkingItem, runStatus } from "@tangle-network/ui/run";
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 at = Date.parse(row.at);
79
- const { event } = row;
80
- const last = next[next.length - 1];
81
- if (event.kind === "text" && event.text) {
82
- if (last?.kind === "message" && last.role === "assistant" && !last.sealed) next[next.length - 1] = {
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
- content: last.content + event.text
97
+ text: last.text + event.text
85
98
  };
86
99
  else next.push({
87
- id: `m-${row.seq}`,
88
- at,
89
- kind: "message",
90
- role: "assistant",
91
- content: event.text
100
+ ...base,
101
+ kind: "reasoning",
102
+ text: event.text
92
103
  });
93
- } else if (event.kind === "user" && event.text) next.push({
94
- id: `u-${row.seq}`,
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 (event.kind === "notice" && event.text) {
101
- if (event.provenance === "delegated-input") next.push({
102
- id: `u-${row.seq}`,
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
- id: `n-${row.seq}`,
118
- at,
119
+ ...base,
119
120
  kind: "notice",
120
121
  text: event.text
121
122
  });
122
- } else if (event.kind === "reasoning" && event.text) {
123
- if (last?.kind === "reasoning") next[next.length - 1] = {
124
- ...last,
125
- text: last.text + event.text
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
- id: `r-${row.seq}`,
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: toolType(event.toolName),
142
- label: event.toolName ?? "tool",
143
- status: "running",
144
- detail: toolText(event.args)
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.kind === "tool-result") {
148
- const index = next.findIndex((entry) => entry.kind === "tool" && entry.call.id === event.toolCallId);
149
- const entry = next[index];
150
- if (entry?.kind === "tool") next[index] = {
151
- ...entry,
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
- function reduce(state, action) {
164
- switch (action.type) {
165
- case "reset": return {
166
- generation: action.generation,
167
- entries: [],
168
- lastSeq: 0,
169
- alive: true
170
- };
171
- case "rows": {
172
- const base = action.generation !== void 0 && action.generation !== state.generation ? {
173
- entries: [],
174
- lastSeq: 0
175
- } : state;
176
- const fresh = action.rows.filter((row) => row.seq > base.lastSeq);
177
- return {
178
- generation: action.generation ?? state.generation,
179
- entries: foldAgentRows(base.entries, fresh),
180
- lastSeq: fresh.reduce((max, row) => Math.max(max, row.seq), base.lastSeq),
181
- alive: action.alive ?? state.alive,
182
- error: void 0
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
- case "end": return {
186
- ...state,
187
- alive: false,
188
- error: void 0
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
- case "error": return {
191
- ...state,
192
- error: action.message
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
- case "unreachable": return {
195
- ...state,
196
- error: "The agent stream is unreachable; the viewer may be closed."
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
- * Follow one agent's message stream over Server-Sent Events: `rows`, `reset` and `end` events, reconnecting with
202
- * `?after=<lastSeq>` when the server closes the connection, so a long turn streams without gaps or repeats.
203
- */
204
- function useAgentStream(url, openEventSource) {
205
- const [state, dispatch] = useReducer(reduce, {
206
- entries: [],
207
- lastSeq: 0,
208
- alive: false
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: () => cursor.current.lastSeq,
214
- onStart: () => {
215
- cursor.current = { lastSeq: 0 };
216
- dispatch({ type: "reset" });
217
- },
313
+ after: () => current.current.lastSeq,
218
314
  onLiveChange: (live) => {
219
- if (!live) dispatch({ type: "unreachable" });
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
- const data = JSON.parse(message.data);
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
- dispatch({
239
- type: "error",
240
- message: String(cause)
325
+ update({
326
+ ...current.current,
327
+ error: String(cause)
241
328
  });
242
329
  }
243
330
  },
244
331
  reset: (message) => {
245
332
  try {
246
- const { generation } = JSON.parse(message.data);
247
- cursor.current = {
248
- lastSeq: 0,
249
- generation
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
- dispatch({
257
- type: "error",
258
- message: String(cause)
340
+ update({
341
+ ...current.current,
342
+ error: String(cause)
259
343
  });
260
344
  }
261
345
  },
262
- end: () => dispatch({ type: "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
- return state;
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(NotTimeIndexed, { label: "Conversation" })
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-DLh2JE0F.js";
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";