@abstractframework/monitor-flow 0.1.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 ADDED
@@ -0,0 +1,67 @@
1
+ # @abstractuic/monitor-flow
2
+
3
+ React components to inspect **agent execution cycles** (think → act → observe) from per-effect trace records.
4
+
5
+ ## What you get
6
+
7
+ Authoritative exports live in `monitor-flow/src/index.ts`:
8
+
9
+ - `AgentCyclesPanel` (+ types `TraceItem`, `TraceStep`)
10
+ - `JsonViewer`
11
+ - `build_agent_trace` (+ `LedgerRecordItem`, `StepRecordLike`)
12
+
13
+ ## Peer dependencies
14
+
15
+ Declared in `monitor-flow/package.json`:
16
+
17
+ - `react@^18`, `react-dom@^18`
18
+
19
+ ## Install
20
+
21
+ - Workspace: add a dependency on `@abstractuic/monitor-flow`
22
+ - npm (once published): `npm i @abstractuic/monitor-flow`
23
+
24
+ ## Expected data
25
+
26
+ `AgentCyclesPanel` expects `TraceItem[]` (see `monitor-flow/src/AgentCyclesPanel.tsx`):
27
+
28
+ ```ts
29
+ type TraceItem = {
30
+ id: string;
31
+ runId: string;
32
+ nodeId: string;
33
+ ts?: string;
34
+ status: string;
35
+ step: Record<string, unknown>;
36
+ };
37
+ ```
38
+
39
+ Cycles start whenever `step.effect.type === "llm_call"` (see the cycle builder in `monitor-flow/src/AgentCyclesPanel.tsx`).
40
+
41
+ ## Usage
42
+
43
+ If you already have `TraceItem[]`, pass it directly:
44
+
45
+ ```tsx
46
+ import { AgentCyclesPanel } from "@abstractuic/monitor-flow";
47
+
48
+ <AgentCyclesPanel items={items} />;
49
+ ```
50
+
51
+ If you have “ledger-like” records, adapt them with `build_agent_trace`:
52
+
53
+ ```tsx
54
+ import { AgentCyclesPanel, build_agent_trace } from "@abstractuic/monitor-flow";
55
+
56
+ const { items } = build_agent_trace(ledgerItems, { run_id: "run_123" });
57
+ <AgentCyclesPanel items={items} />;
58
+ ```
59
+
60
+ ## Styling
61
+
62
+ The panel imports `monitor-flow/src/agent_cycles.css` and uses shared UI token CSS variables where present (see `@abstractuic/ui-kit/src/theme.css`).
63
+
64
+ ## Related docs
65
+
66
+ - Getting started: [`docs/getting-started.md`](../docs/getting-started.md)
67
+ - Architecture: [`docs/architecture.md`](../docs/architecture.md)
@@ -0,0 +1,20 @@
1
+ import "./agent_cycles.css";
2
+ export type TraceStep = Record<string, unknown>;
3
+ export type TraceItem = {
4
+ id: string;
5
+ runId: string;
6
+ nodeId: string;
7
+ ts?: string;
8
+ status: string;
9
+ step: TraceStep;
10
+ };
11
+ export type AgentCyclesPanelProps = {
12
+ items: TraceItem[];
13
+ subRunId?: string | null;
14
+ title?: string;
15
+ subtitle?: string;
16
+ onOpenSubRun?: () => void;
17
+ defaultOpenLatest?: boolean;
18
+ };
19
+ export declare function AgentCyclesPanel({ items: items_in, subRunId, title, subtitle, onOpenSubRun, defaultOpenLatest }: AgentCyclesPanelProps): React.ReactElement | null;
20
+ //# sourceMappingURL=AgentCyclesPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentCyclesPanel.d.ts","sourceRoot":"","sources":["../src/AgentCyclesPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAI5B,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AA8BF,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AA8gBF,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,iBAAwB,EAAE,EAAE,qBAAqB,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CA+JzK"}
@@ -0,0 +1,548 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from "react";
3
+ import "./agent_cycles.css";
4
+ import { JsonViewer } from "./JsonViewer";
5
+ import { Markdown } from "./Markdown";
6
+ async function copy_text(text) {
7
+ const value = String(text || "");
8
+ if (!value)
9
+ return;
10
+ try {
11
+ await navigator.clipboard.writeText(value);
12
+ }
13
+ catch {
14
+ const el = document.createElement("textarea");
15
+ el.value = value;
16
+ document.body.appendChild(el);
17
+ el.select();
18
+ document.execCommand("copy");
19
+ document.body.removeChild(el);
20
+ }
21
+ }
22
+ function as_record(value) {
23
+ if (!value || typeof value !== "object")
24
+ return null;
25
+ return value;
26
+ }
27
+ function clamp_inline(text, max_len) {
28
+ const value = String(text || "").replace(/\s+/g, " ").trim();
29
+ if (!value)
30
+ return "";
31
+ if (value.length <= max_len)
32
+ return value;
33
+ return `${value.slice(0, Math.max(0, max_len - 1)).trimEnd()}…`;
34
+ }
35
+ function as_llm_message(value) {
36
+ const obj = as_record(value);
37
+ if (!obj)
38
+ return null;
39
+ const role = typeof obj.role === "string" ? String(obj.role).trim() : "";
40
+ const content = typeof obj.content === "string" ? String(obj.content) : "";
41
+ if (!role || content === "")
42
+ return null;
43
+ const name = typeof obj.name === "string" ? String(obj.name).trim() : "";
44
+ return { role, content, name: name || undefined };
45
+ }
46
+ function as_llm_messages(value) {
47
+ if (Array.isArray(value)) {
48
+ if (value.length === 0)
49
+ return null;
50
+ const out = [];
51
+ for (const item of value) {
52
+ const msg = as_llm_message(item);
53
+ if (!msg)
54
+ return null;
55
+ out.push(msg);
56
+ }
57
+ return out;
58
+ }
59
+ const single = as_llm_message(value);
60
+ return single ? [single] : null;
61
+ }
62
+ function try_parse_json_container(text) {
63
+ const trimmed = String(text || "").trim();
64
+ if (!trimmed)
65
+ return null;
66
+ const starts = trimmed[0];
67
+ const ends = trimmed[trimmed.length - 1];
68
+ const looks_like_container = (starts === "{" && ends === "}") || (starts === "[" && ends === "]");
69
+ if (!looks_like_container)
70
+ return null;
71
+ try {
72
+ const parsed = JSON.parse(trimmed);
73
+ if (parsed && typeof parsed === "object")
74
+ return parsed;
75
+ if (Array.isArray(parsed))
76
+ return parsed;
77
+ return null;
78
+ }
79
+ catch {
80
+ return null;
81
+ }
82
+ }
83
+ function looks_like_markdown(text) {
84
+ const s = String(text || "");
85
+ if (!s.trim())
86
+ return false;
87
+ if (s.includes("```"))
88
+ return true;
89
+ if (/\n\s*#{1,3}\s+/.test(s))
90
+ return true;
91
+ if (/\n\s*[-*]\s+/.test(s))
92
+ return true;
93
+ if (/\n\s*\d+[\.\)]\s+/.test(s))
94
+ return true;
95
+ if (s.includes("**"))
96
+ return true;
97
+ if (s.includes("`"))
98
+ return true;
99
+ return false;
100
+ }
101
+ function AutoText({ text }) {
102
+ const raw = String(text || "");
103
+ const parsed = try_parse_json_container(raw);
104
+ if (parsed !== null)
105
+ return _jsx(JsonViewer, { value: parsed });
106
+ const trimmed = raw.trim();
107
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
108
+ return _jsx("pre", { className: "run-details-output", children: raw || "(none)" });
109
+ }
110
+ if (raw.includes("\n") || looks_like_markdown(raw)) {
111
+ return (_jsx("div", { className: "run-details-output", children: _jsx(Markdown, { text: raw }) }));
112
+ }
113
+ return _jsx("pre", { className: "run-details-output", children: raw || "(none)" });
114
+ }
115
+ function AutoValue({ value }) {
116
+ if (value == null)
117
+ return _jsx("pre", { className: "run-details-output", children: "(none)" });
118
+ const messages = as_llm_messages(value);
119
+ if (messages) {
120
+ return (_jsx("div", { className: "mf-msg-list", children: messages.map((m, idx) => (_jsxs("div", { className: "mf-msg", children: [_jsxs("div", { className: "mf-msg-meta", children: [_jsx("span", { className: `mf-msg-role ${m.role}`, children: m.role }), m.name ? _jsx("span", { className: "mf-msg-name", children: m.name }) : null] }), _jsx("div", { className: "mf-msg-content", children: _jsx(AutoText, { text: m.content }) })] }, `${m.role}:${idx}`))) }));
121
+ }
122
+ if (typeof value === "string")
123
+ return _jsx(AutoText, { text: value });
124
+ return _jsx(JsonViewer, { value: value });
125
+ }
126
+ function effect_of(step) {
127
+ const effect = step.effect;
128
+ if (!effect || typeof effect !== "object")
129
+ return null;
130
+ return effect;
131
+ }
132
+ function effect_type_of(step) {
133
+ const effect = effect_of(step);
134
+ const t = effect && typeof effect.type === "string" ? effect.type : "";
135
+ return t || "effect";
136
+ }
137
+ function payload_of(step) {
138
+ const effect = effect_of(step);
139
+ const payload = effect?.payload;
140
+ if (!payload || typeof payload !== "object")
141
+ return null;
142
+ return payload;
143
+ }
144
+ function result_of(step) {
145
+ const r = step.result;
146
+ if (!r || typeof r !== "object")
147
+ return null;
148
+ return r;
149
+ }
150
+ function tool_results_for_step(step) {
151
+ const t = effect_type_of(step);
152
+ if (t !== "tool_calls")
153
+ return [];
154
+ const res = result_of(step);
155
+ const raw = res && Array.isArray(res.results) ? res.results : null;
156
+ if (!raw)
157
+ return [];
158
+ const out = [];
159
+ for (const r of raw) {
160
+ const ro = as_record(r);
161
+ if (!ro)
162
+ continue;
163
+ const name = typeof ro.name === "string" ? ro.name.trim() : "";
164
+ if (!name)
165
+ continue;
166
+ out.push({
167
+ call_id: typeof ro.call_id === "string" ? ro.call_id : undefined,
168
+ name,
169
+ success: Boolean(ro.success),
170
+ output: ro.output,
171
+ error: ro.error,
172
+ });
173
+ }
174
+ return out;
175
+ }
176
+ function tool_calls_for_step(step) {
177
+ const t = effect_type_of(step);
178
+ if (t !== "tool_calls")
179
+ return [];
180
+ const payload = payload_of(step);
181
+ const raw = payload && Array.isArray(payload.tool_calls) ? payload.tool_calls : null;
182
+ if (!raw)
183
+ return [];
184
+ const out = [];
185
+ for (const c of raw) {
186
+ const co = as_record(c);
187
+ if (!co)
188
+ continue;
189
+ const name = typeof co.name === "string" ? co.name.trim() : "";
190
+ if (!name)
191
+ continue;
192
+ const args = as_record(co.args) || as_record(co.arguments) || {};
193
+ out.push({
194
+ call_id: typeof co.call_id === "string" ? co.call_id : undefined,
195
+ name,
196
+ args,
197
+ });
198
+ }
199
+ return out;
200
+ }
201
+ function error_text_of(step) {
202
+ const err = step.error;
203
+ if (typeof err === "string")
204
+ return err.trim();
205
+ const ro = as_record(err);
206
+ if (ro) {
207
+ const msg = typeof ro.message === "string" ? ro.message.trim() : "";
208
+ const stack = typeof ro.stack === "string" ? ro.stack.trim() : "";
209
+ return msg || stack || "";
210
+ }
211
+ return "";
212
+ }
213
+ function reasoning_text_of_result(res) {
214
+ if (!res)
215
+ return "";
216
+ const raw = res.reasoning;
217
+ if (typeof raw === "string")
218
+ return raw.trim();
219
+ const rr = as_record(raw);
220
+ const txt = rr && typeof rr.text === "string" ? rr.text.trim() : "";
221
+ return txt;
222
+ }
223
+ function preview_for_step(step) {
224
+ const t = effect_type_of(step);
225
+ const payload = payload_of(step);
226
+ const res = result_of(step);
227
+ const clamp = (text, max_len) => {
228
+ const value = String(text || "").replace(/\s+/g, " ").trim();
229
+ if (!value)
230
+ return "";
231
+ if (value.length <= max_len)
232
+ return value;
233
+ return `${value.slice(0, Math.max(0, max_len - 1)).trimEnd()}…`;
234
+ };
235
+ if (t === "llm_call") {
236
+ const content = res?.content;
237
+ const text = typeof content === "string" ? content.replace(/\s+/g, " ").trim() : "";
238
+ const reasoning = reasoning_text_of_result(res);
239
+ const tool_calls = Array.isArray(res?.tool_calls) ? res.tool_calls : null;
240
+ const has_tool_calls = Boolean(tool_calls && tool_calls.length > 0);
241
+ const preferred = has_tool_calls ? reasoning || text : text || reasoning;
242
+ return clamp(preferred, 220);
243
+ }
244
+ if (t === "tool_calls") {
245
+ const results = res && Array.isArray(res.results) ? res.results : null;
246
+ if (!results)
247
+ return "";
248
+ const failed = results.filter((r) => as_record(r)?.success === false);
249
+ if (failed.length > 0)
250
+ return `${failed.length} tool call(s) failed`;
251
+ return `${results.length} tool call(s) executed`;
252
+ }
253
+ if (t === "ask_user") {
254
+ const prompt = payload && typeof payload.prompt === "string" ? String(payload.prompt).trim() : "";
255
+ return prompt;
256
+ }
257
+ return "";
258
+ }
259
+ function effective_status_for_item(item) {
260
+ const status = typeof item.status === "string" ? item.status : "unknown";
261
+ if (status === "failed")
262
+ return "failed";
263
+ const errs = error_text_of(item.step);
264
+ if (errs)
265
+ return "failed";
266
+ return status;
267
+ }
268
+ function combine_status(items) {
269
+ const statuses = items.map((i) => effective_status_for_item(i));
270
+ if (statuses.some((s) => s === "failed"))
271
+ return "failed";
272
+ if (statuses.some((s) => s === "waiting"))
273
+ return "waiting";
274
+ if (statuses.some((s) => s === "running"))
275
+ return "running";
276
+ return "completed";
277
+ }
278
+ function visible_tabs(tabs) {
279
+ return tabs.filter((t) => !t.hidden);
280
+ }
281
+ function tabs_for_step(step) {
282
+ const t = effect_type_of(step);
283
+ const errs = error_text_of(step);
284
+ if (t === "llm_call") {
285
+ return visible_tabs([
286
+ { id: "system", label: "System" },
287
+ { id: "user", label: "User" },
288
+ { id: "tools", label: "Tools" },
289
+ { id: "response", label: "Response" },
290
+ { id: "reasoning", label: "Reasoning" },
291
+ { id: "errors", label: "Errors", hidden: !errs },
292
+ { id: "raw", label: "Raw" },
293
+ ]);
294
+ }
295
+ if (t === "tool_calls") {
296
+ return visible_tabs([
297
+ { id: "tools", label: "Tools" },
298
+ { id: "errors", label: "Errors", hidden: !errs },
299
+ { id: "raw", label: "Raw" },
300
+ ]);
301
+ }
302
+ return visible_tabs([
303
+ { id: "errors", label: "Errors", hidden: !errs },
304
+ { id: "raw", label: "Raw" },
305
+ ]);
306
+ }
307
+ function default_tab_for_step(step) {
308
+ const t = effect_type_of(step);
309
+ if (t === "llm_call")
310
+ return "user";
311
+ if (t === "tool_calls")
312
+ return "tools";
313
+ if (error_text_of(step))
314
+ return "errors";
315
+ return "raw";
316
+ }
317
+ function tool_defs_from_think_step(step) {
318
+ const out = new Map();
319
+ const payload = payload_of(step);
320
+ const tools = payload && Array.isArray(payload.tools) ? payload.tools : null;
321
+ if (!tools)
322
+ return out;
323
+ for (const t of tools) {
324
+ const to = as_record(t);
325
+ if (!to)
326
+ continue;
327
+ const name = typeof to.name === "string" ? to.name.trim() : "";
328
+ if (!name)
329
+ continue;
330
+ const params = Array.isArray(to.parameters) ? to.parameters : [];
331
+ const args = params
332
+ .map((p) => {
333
+ const po = as_record(p);
334
+ const id = po && typeof po.id === "string" ? po.id.trim() : "";
335
+ return id || "";
336
+ })
337
+ .filter(Boolean);
338
+ out.set(name, args);
339
+ }
340
+ return out;
341
+ }
342
+ function format_tool_signature(name, args, param_order) {
343
+ const keys = Object.keys(args || {});
344
+ const ordered = param_order && param_order.length ? param_order.filter((k) => keys.includes(k)) : [];
345
+ const rest = keys.filter((k) => !ordered.includes(k)).sort();
346
+ const all = [...ordered, ...rest];
347
+ const parts = all.slice(0, 5).map((k) => {
348
+ const v = args[k];
349
+ if (typeof v === "string")
350
+ return `${k}=${JSON.stringify(clamp_inline(v, 42))}`;
351
+ if (typeof v === "number" || typeof v === "boolean")
352
+ return `${k}=${String(v)}`;
353
+ if (v == null)
354
+ return `${k}=null`;
355
+ return `${k}=${clamp_inline(JSON.stringify(v), 42)}`;
356
+ });
357
+ return `${name}(${parts.join(", ")}${all.length > 5 ? ", …" : ""})`;
358
+ }
359
+ function trace_step_time_label(item) {
360
+ const ts = item.ts ? String(item.ts) : "";
361
+ if (!ts)
362
+ return "";
363
+ try {
364
+ const d = new Date(ts);
365
+ const s = Number.isFinite(d.getTime()) ? d.toLocaleTimeString() : "";
366
+ return s;
367
+ }
368
+ catch {
369
+ return "";
370
+ }
371
+ }
372
+ function TraceStepCard({ item, label, toolDefs }) {
373
+ const step = item.step;
374
+ const kind = effect_type_of(step);
375
+ const tabs = tabs_for_step(step);
376
+ const default_tab = default_tab_for_step(step);
377
+ const [tab, set_tab] = useState(default_tab);
378
+ const payload = payload_of(step);
379
+ const res = result_of(step);
380
+ const errs = error_text_of(step);
381
+ const time_label = trace_step_time_label(item);
382
+ const node = item.nodeId ? String(item.nodeId) : "";
383
+ const run = item.runId ? String(item.runId) : "";
384
+ const tool_calls = kind === "tool_calls" ? tool_calls_for_step(step) : [];
385
+ const tool_results = kind === "tool_calls" ? tool_results_for_step(step) : [];
386
+ const tool_sigs = tool_calls.map((tc) => format_tool_signature(tc.name, tc.args, toolDefs.get(tc.name) || null));
387
+ const output_for_tab = () => {
388
+ if (tab === "raw")
389
+ return step;
390
+ if (tab === "errors")
391
+ return errs || null;
392
+ if (kind === "llm_call") {
393
+ const p = payload || {};
394
+ const system_prompt = typeof p.system_prompt === "string" ? String(p.system_prompt) : "";
395
+ const prompt = typeof p.prompt === "string" ? String(p.prompt) : "";
396
+ // Prefer the *effective* provider-visible message list when available (includes runtime injections
397
+ // like session attachments + tool activity). Fall back to the raw payload.
398
+ const meta = as_record(res?.metadata);
399
+ const obs = meta ? as_record(meta._runtime_observability) : null;
400
+ const obs_kwargs = obs ? as_record(obs.llm_generate_kwargs) : null;
401
+ const obs_messages = obs_kwargs && Array.isArray(obs_kwargs.messages) ? obs_kwargs.messages : null;
402
+ const preq = meta ? as_record(meta._provider_request) : null;
403
+ const preq_payload = preq ? as_record(preq.payload) : null;
404
+ const preq_messages = preq_payload && Array.isArray(preq_payload.messages) ? preq_payload.messages : null;
405
+ const raw_payload_messages = Array.isArray(p.messages) ? p.messages : [];
406
+ const raw_messages = obs_messages || preq_messages || raw_payload_messages;
407
+ const system = raw_messages.filter((m) => String(m?.role || "").trim() === "system");
408
+ // "User" tab is strictly the user prompt/messages (never assistant/tool output).
409
+ const user = raw_messages.filter((m) => String(m?.role || "").trim() === "user");
410
+ if (tab === "system") {
411
+ const out = [];
412
+ const sp = system_prompt.trim();
413
+ const dup_system_prompt = Boolean(sp) &&
414
+ system.some((m) => typeof m?.content === "string" && String(m.content).trim() === sp);
415
+ if (sp && !dup_system_prompt)
416
+ out.push({ role: "system", name: "system_prompt", content: system_prompt });
417
+ out.push(...system);
418
+ return out;
419
+ }
420
+ if (tab === "user") {
421
+ const out = [];
422
+ const pr = prompt.trim();
423
+ const dup_prompt = Boolean(pr) &&
424
+ user.some((m) => typeof m?.content === "string" && String(m.content).trim() === pr);
425
+ if (pr && !dup_prompt)
426
+ out.push({ role: "user", name: "prompt", content: prompt });
427
+ out.push(...user);
428
+ return out;
429
+ }
430
+ if (tab === "tools")
431
+ return p.tools || [];
432
+ if (tab === "response") {
433
+ const content = res?.content;
434
+ if (typeof content === "string" && content.trim())
435
+ return content;
436
+ const out = res?.output;
437
+ if (out !== undefined)
438
+ return out;
439
+ const tool_calls = Array.isArray(res?.tool_calls) ? res.tool_calls : null;
440
+ if (tool_calls && tool_calls.length)
441
+ return { tool_calls };
442
+ return res;
443
+ }
444
+ if (tab === "reasoning")
445
+ return reasoning_text_of_result(res) || null;
446
+ }
447
+ if (kind === "tool_calls") {
448
+ if (tab === "tools")
449
+ return { tool_calls, tool_signatures: tool_sigs, results: tool_results };
450
+ }
451
+ return step;
452
+ };
453
+ const output = output_for_tab();
454
+ const preview = preview_for_step(step);
455
+ const status = effective_status_for_item(item);
456
+ const badge = status === "completed" ? "OK" : status === "failed" ? "ERROR" : status === "waiting" ? "WAITING" : status.toUpperCase();
457
+ return (_jsxs("details", { className: `agent-trace-entry ${status}`, open: false, children: [_jsxs("summary", { className: "agent-trace-summary", children: [_jsx("span", { className: `agent-trace-status ${status}`, children: badge }), _jsx("span", { className: "agent-cycle-stage", children: label }), _jsx("span", { className: "agent-trace-kind", children: kind }), time_label ? _jsx("span", { className: "agent-trace-node", children: time_label }) : null, node ? _jsx("span", { className: "agent-trace-node", children: node }) : null, run ? _jsx("span", { className: "agent-trace-run", children: run }) : null] }), preview ? _jsx("div", { className: "agent-trace-preview", children: preview }) : null, _jsxs("div", { className: "agent-trace-body", children: [_jsx("div", { className: "agent-trace-tabs", children: tabs.map((t) => (_jsx("button", { type: "button", className: `agent-trace-tab ${t.id === tab ? "active" : ""}`, onClick: () => set_tab(t.id), children: t.label }, t.id))) }), _jsx(AutoValue, { value: output })] })] }));
458
+ }
459
+ function ObserveCard({ acts }) {
460
+ const all = acts.flatMap((a) => tool_results_for_step(a.step));
461
+ const failed = all.filter((r) => r.success === false);
462
+ const header = failed.length ? `${failed.length} error(s)` : all.length ? `${all.length} tool result(s)` : "(none)";
463
+ const status = failed.length ? "failed" : "completed";
464
+ return (_jsxs("details", { className: `agent-trace-entry ${status}`, open: false, children: [_jsxs("summary", { className: "agent-trace-summary", children: [_jsx("span", { className: `agent-trace-status ${status}`, children: failed.length ? "ERROR" : "OK" }), _jsx("span", { className: "agent-cycle-stage", children: "observe" }), _jsx("span", { className: "agent-trace-kind", children: "OBSERVATIONS" }), _jsx("span", { className: "agent-trace-preview-inline", children: header })] }), _jsx("div", { className: "agent-observe-body", children: all.length === 0 ? (_jsx("div", { className: "agent-observe-empty", children: "(no tool results)" })) : (_jsx("div", { className: "agent-observe-results", children: all.map((r, idx) => {
465
+ const st = r.success ? "completed" : "failed";
466
+ const badge = r.success ? "OK" : "ERROR";
467
+ const output = r.success ? r.output : r.error ?? r.output;
468
+ return (_jsxs("details", { className: `agent-observe-result ${st}`, open: false, children: [_jsxs("summary", { className: "agent-observe-summary", children: [_jsx("span", { className: `agent-trace-status ${st}`, children: badge }), _jsx("span", { className: "agent-observe-name", children: r.name }), r.call_id ? _jsx("span", { className: "agent-observe-callid", children: r.call_id }) : null] }), _jsx(AutoValue, { value: output })] }, `${r.name}:${r.call_id || ""}:${idx}`));
469
+ }) })) })] }));
470
+ }
471
+ export function AgentCyclesPanel({ items: items_in, subRunId, title, subtitle, onOpenSubRun, defaultOpenLatest = true }) {
472
+ const items = useMemo(() => {
473
+ const next = Array.isArray(items_in) ? items_in.slice() : [];
474
+ next.sort((a, b) => {
475
+ const ta = a.ts ? new Date(a.ts).getTime() : NaN;
476
+ const tb = b.ts ? new Date(b.ts).getTime() : NaN;
477
+ if (Number.isFinite(ta) && Number.isFinite(tb))
478
+ return ta - tb;
479
+ return 0;
480
+ });
481
+ return next;
482
+ }, [items_in]);
483
+ const cycles = useMemo(() => {
484
+ const out = [];
485
+ let current = null;
486
+ let idx = 0;
487
+ for (const item of items) {
488
+ const kind = effect_type_of(item.step);
489
+ if (kind === "llm_call") {
490
+ idx += 1;
491
+ current = {
492
+ id: `cycle:${item.runId}:${idx}:${item.ts || ""}`,
493
+ index: idx,
494
+ items: [item],
495
+ think: item,
496
+ acts: [],
497
+ others: [],
498
+ status: effective_status_for_item(item),
499
+ ts: item.ts,
500
+ };
501
+ out.push(current);
502
+ continue;
503
+ }
504
+ if (!current) {
505
+ idx += 1;
506
+ current = {
507
+ id: `cycle:${item.runId}:${idx}:${item.ts || ""}`,
508
+ index: idx,
509
+ items: [],
510
+ think: null,
511
+ acts: [],
512
+ others: [],
513
+ status: effective_status_for_item(item),
514
+ ts: item.ts,
515
+ };
516
+ out.push(current);
517
+ }
518
+ current.items.push(item);
519
+ if (kind === "tool_calls")
520
+ current.acts.push(item);
521
+ else
522
+ current.others.push(item);
523
+ current.status = combine_status(current.items);
524
+ }
525
+ return out;
526
+ }, [items]);
527
+ const title_text = typeof title === "string" && title.trim() ? title.trim() : "Agent calls";
528
+ const subtitle_text = typeof subtitle === "string" && subtitle.trim() ? subtitle.trim() : "Live per-effect trace (LLM/tool calls).";
529
+ const sub_run_id = typeof subRunId === "string" ? subRunId.trim() : "";
530
+ return (_jsxs("div", { className: "agent-trace-panel", children: [_jsxs("div", { className: "agent-trace-header", children: [_jsx("div", { className: "agent-trace-title", children: title_text }), _jsxs("div", { className: "agent-trace-subtitle", children: [subtitle_text, sub_run_id ? (_jsxs("span", { className: "agent-trace-subrun", children: [" ", "sub_run_id: ", sub_run_id, _jsx("button", { type: "button", className: "agent-trace-copy", onClick: (e) => {
531
+ e.stopPropagation();
532
+ void copy_text(sub_run_id);
533
+ }, title: `Copy sub_run_id: ${sub_run_id}`, "aria-label": "Copy sub run id", children: "\u29C9" }), onOpenSubRun ? (_jsx("button", { type: "button", className: "agent-trace-open", onClick: (e) => {
534
+ e.stopPropagation();
535
+ onOpenSubRun();
536
+ }, title: "Open sub-run", children: "Open" })) : null] })) : null] })] }), items.length === 0 ? (_jsx("div", { className: "agent-trace-empty", children: "No trace entries yet." })) : (_jsxs("div", { className: "agent-cycle-list", children: [_jsxs("div", { className: "agent-cycle-meta", children: [cycles.length, " cycle(s)"] }), cycles.map((c) => {
537
+ const status_raw = c.status;
538
+ const status_label = status_raw === "completed" ? "OK" : status_raw === "failed" ? "ERROR" : status_raw === "waiting" ? "WAITING" : status_raw.toUpperCase();
539
+ const status_icon = status_raw === "completed" ? "✓" : status_raw === "failed" ? "✗" : "";
540
+ const status_text = status_icon ? `${status_icon} ${status_label}` : status_label;
541
+ const think_preview = c.think ? preview_for_step(c.think.step) : "";
542
+ const tool_defs = c.think ? tool_defs_from_think_step(c.think.step) : new Map();
543
+ const cycle_tool_calls = c.acts.flatMap((a) => tool_calls_for_step(a.step));
544
+ const cycle_tool_sigs = cycle_tool_calls.map((tc) => format_tool_signature(tc.name, tc.args, tool_defs.get(tc.name) || null));
545
+ const open_by_default = defaultOpenLatest && c.index === cycles.length;
546
+ return (_jsxs("details", { className: `agent-cycle ${status_raw}`, open: open_by_default, children: [_jsxs("summary", { className: "agent-cycle-summary", children: [_jsx("span", { className: `agent-trace-status ${status_raw}`, children: status_text }), _jsx("span", { className: "agent-cycle-label", children: "cycle" }), _jsxs("span", { className: "agent-cycle-index", children: ["#", c.index] }), cycle_tool_sigs.length ? (_jsxs("span", { className: "agent-trace-badges", children: [cycle_tool_sigs.slice(0, 3).map((sig) => (_jsx("span", { className: "run-metric-badge metric-tool", title: sig, children: clamp_inline(sig, 62) }, sig))), cycle_tool_sigs.length > 3 ? _jsxs("span", { className: "run-metric-badge metric-tool", children: ["+", cycle_tool_sigs.length - 3] }) : null] })) : null, _jsx("span", { className: "agent-cycle-spacer" }), think_preview ? _jsx("span", { className: "agent-cycle-preview", children: think_preview }) : null] }), _jsxs("div", { className: "agent-cycle-body", children: [c.think ? _jsx(TraceStepCard, { item: c.think, label: "think", toolDefs: tool_defs }) : null, c.acts.map((a) => (_jsx(TraceStepCard, { item: a, label: "act", toolDefs: tool_defs }, a.id))), _jsx(ObserveCard, { acts: c.acts }), c.others.length ? (_jsxs("div", { className: "agent-cycle-others", children: [_jsx("div", { className: "agent-cycle-others-title", children: "other" }), c.others.map((o) => (_jsx(TraceStepCard, { item: o, label: "other", toolDefs: tool_defs }, o.id)))] })) : null] })] }, c.id));
547
+ })] }))] }));
548
+ }
@@ -0,0 +1,7 @@
1
+ export declare function JsonViewer(props: {
2
+ value: unknown;
3
+ className?: string;
4
+ collapseAfterDepth?: number;
5
+ showCopy?: boolean;
6
+ }): React.ReactElement;
7
+ //# sourceMappingURL=JsonViewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonViewer.d.ts","sourceRoot":"","sources":["../src/JsonViewer.tsx"],"names":[],"mappings":"AAkKA,wBAAgB,UAAU,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CA2B7I"}