@tangle-network/agent-eval 0.73.0 → 0.74.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/dist/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "@tangle-network/agent-eval — wire protocol",
5
- "version": "0.73.0",
5
+ "version": "0.74.0",
6
6
  "description": "HTTP and stdio RPC interface to agent-eval. The TypeScript runtime is the source of truth; this spec is the contract that cross-language clients (Python, Rust, Go) generate from.\n\nWire-protocol version: 1.0.0. Bumps on breaking changes to request/response schemas.",
7
7
  "contact": {
8
8
  "name": "Tangle Network",
@@ -0,0 +1,91 @@
1
+ import { S as Span } from '../schema-m0gsnbt3.js';
2
+
3
+ /**
4
+ * Storyboard — compile a raw agent trace into a small set of meaningful scenes,
5
+ * then render them as a shareable replay.
6
+ *
7
+ * Span[] → SemanticEvent[] → Storyboard{scenes} → { markdown | html }
8
+ *
9
+ * The trace is the source of truth; the storyboard is the IR; markdown/html
10
+ * (and, in a consumer package, Remotion/MP4) are compiled targets. Everything
11
+ * here is PURE — same spans in, same bytes out (no clock/random) — so a run's
12
+ * replay is deterministic and diffable. The semantic reducer is rules-based:
13
+ * an LLM pass can refine titles later, but the structure does not depend on
14
+ * one. Renderers that need a browser (Remotion, React) live in consumers; this
15
+ * module only emits strings.
16
+ */
17
+
18
+ /** What the agent meaningfully did — the compressed vocabulary the storyboard
19
+ * is built from (the spec's semantic layer). */
20
+ type SemanticKind = 'understood_task' | 'reasoned' | 'ran_command' | 'read_file' | 'edited_code' | 'searched' | 'used_browser' | 'called_tool' | 'evaluated' | 'observed_failure' | 'completed';
21
+ interface SemanticEvent {
22
+ kind: SemanticKind;
23
+ /** One-line headline (the ticket/scene title). */
24
+ title: string;
25
+ /** Short human summary. */
26
+ summary: string;
27
+ /** Span ids backing this moment — the evidence trail. */
28
+ evidenceSpanIds: string[];
29
+ /** 1 (noise) … 5 (pivotal: failures, edits). Drives selection + duration. */
30
+ importance: 1 | 2 | 3 | 4 | 5;
31
+ startTs: number;
32
+ endTs: number;
33
+ }
34
+ interface ReduceOptions {
35
+ /** Collapse adjacent same-kind moments into one (e.g. 6 file reads → one
36
+ * "explored N files"). Default true — this is the compression that takes a
37
+ * 4000-event run down to dozens of moments. */
38
+ collapseAdjacent?: boolean;
39
+ }
40
+ /**
41
+ * Reduce a span tree into the meaningful moments a viewer cares about. Spans
42
+ * are sorted by start time; each is classified, then adjacent same-kind
43
+ * moments collapse into one (the compression step). A failure always stands
44
+ * alone (importance 5) so it never gets folded into the noise around it.
45
+ */
46
+ declare function reduceToSemanticEvents(spans: readonly Span[], opts?: ReduceOptions): SemanticEvent[];
47
+ type SceneType = 'title_card' | 'reasoning' | 'terminal' | 'file' | 'diff' | 'search' | 'browser' | 'tool' | 'eval' | 'error' | 'summary';
48
+ interface Scene {
49
+ sceneType: SceneType;
50
+ title: string;
51
+ narration: string;
52
+ durationMs: number;
53
+ /** Span ids behind the scene — the click-through evidence. */
54
+ evidenceSpanIds: string[];
55
+ }
56
+ interface Storyboard {
57
+ title: string;
58
+ /** Sum of scene durations — the replay length. */
59
+ totalMs: number;
60
+ scenes: Scene[];
61
+ }
62
+ interface CompileOptions {
63
+ /** Headline for the title card. Default "Agent run". */
64
+ title?: string;
65
+ /** Max action scenes between the title + summary cards. Default 16. */
66
+ maxScenes?: number;
67
+ }
68
+ /**
69
+ * Select the moments worth showing and lay them out as scenes. Every failure
70
+ * (importance 5) and edit (4) is always kept — those are the story; the rest
71
+ * fill the budget by importance, then everything is re-sorted to chronological
72
+ * order so the replay reads forward in time. A title card opens and a summary
73
+ * card closes.
74
+ */
75
+ declare function compileStoryboard(events: readonly SemanticEvent[], opts?: CompileOptions): Storyboard;
76
+ /** Render the storyboard as a Markdown timeline — the human-readable shot list. */
77
+ declare function renderStoryboardMarkdown(storyboard: Storyboard): string;
78
+ interface HtmlRenderOptions {
79
+ /** Document title + on-page heading. Defaults to the storyboard title. */
80
+ title?: string;
81
+ }
82
+ /**
83
+ * Render the storyboard as a self-contained, auto-playing HTML replay — one
84
+ * shareable file, no build step, no external assets. Each scene animates in
85
+ * for its duration with a progress bar; controls let a viewer scrub. This is
86
+ * the "free clip" a run produces; an MP4 is the same storyboard fed to Remotion
87
+ * in a consumer package.
88
+ */
89
+ declare function renderStoryboardHtml(storyboard: Storyboard, opts?: HtmlRenderOptions): string;
90
+
91
+ export { type CompileOptions, type HtmlRenderOptions, type ReduceOptions, type Scene, type SceneType, type SemanticEvent, type SemanticKind, type Storyboard, compileStoryboard, reduceToSemanticEvents, renderStoryboardHtml, renderStoryboardMarkdown };
@@ -0,0 +1,304 @@
1
+ import "../chunk-PZ5AY32C.js";
2
+
3
+ // src/storyboard/index.ts
4
+ function toolLabel(span) {
5
+ if (span.kind === "tool") {
6
+ const tn = span.toolName;
7
+ const arg = typeof span.args === "string" ? span.args : span.args && typeof span.args === "object" ? Object.values(span.args).find((v) => typeof v === "string") : void 0;
8
+ return typeof arg === "string" && arg.length > 0 ? `${tn}: ${truncate(arg, 60)}` : tn;
9
+ }
10
+ return span.name;
11
+ }
12
+ function classify(span) {
13
+ if (span.status === "error" || span.error) {
14
+ return { kind: "observed_failure", importance: 5, label: span.error ?? span.name };
15
+ }
16
+ if (span.kind === "llm" || span.kind === "agent") {
17
+ return { kind: "reasoned", importance: 2, label: span.name };
18
+ }
19
+ if (span.kind === "judge") {
20
+ return { kind: "evaluated", importance: 2, label: span.name };
21
+ }
22
+ if (span.kind === "retrieval") {
23
+ return { kind: "searched", importance: 2, label: span.name };
24
+ }
25
+ if (span.kind === "sandbox") {
26
+ return { kind: "ran_command", importance: 3, label: span.name };
27
+ }
28
+ if (span.kind === "tool") {
29
+ const tn = span.toolName.toLowerCase();
30
+ const label = toolLabel(span);
31
+ if (/shell|exec|bash|\brun\b|terminal|command/.test(tn)) {
32
+ return { kind: "ran_command", importance: 3, label };
33
+ }
34
+ if (/edit|write|patch|apply|str_replace|create.*file|save/.test(tn)) {
35
+ return { kind: "edited_code", importance: 4, label };
36
+ }
37
+ if (/read|\bcat\b|open|view|get.*file|load/.test(tn)) {
38
+ return { kind: "read_file", importance: 2, label };
39
+ }
40
+ if (/search|grep|find|glob|query/.test(tn)) {
41
+ return { kind: "searched", importance: 2, label };
42
+ }
43
+ if (/browser|playwright|click|navigate|goto|screenshot|page/.test(tn)) {
44
+ return { kind: "used_browser", importance: 3, label };
45
+ }
46
+ return { kind: "called_tool", importance: 3, label };
47
+ }
48
+ return { kind: "called_tool", importance: 2, label: span.name };
49
+ }
50
+ var KIND_VERB = {
51
+ understood_task: "Received the task",
52
+ reasoned: "Reasoned",
53
+ ran_command: "Ran a command",
54
+ read_file: "Read files",
55
+ edited_code: "Edited code",
56
+ searched: "Searched",
57
+ used_browser: "Drove the browser",
58
+ called_tool: "Used a tool",
59
+ evaluated: "Evaluated the result",
60
+ observed_failure: "Hit a failure",
61
+ completed: "Finished"
62
+ };
63
+ function reduceToSemanticEvents(spans, opts = {}) {
64
+ const collapse = opts.collapseAdjacent ?? true;
65
+ const ordered = [...spans].sort((a, b) => a.startedAt - b.startedAt);
66
+ const raw = ordered.map((s) => {
67
+ const c = classify(s);
68
+ return {
69
+ kind: c.kind,
70
+ title: c.label,
71
+ summary: `${KIND_VERB[c.kind]} \u2014 ${c.label}`,
72
+ evidenceSpanIds: [s.spanId],
73
+ importance: c.importance,
74
+ startTs: s.startedAt,
75
+ endTs: s.endedAt ?? s.startedAt
76
+ };
77
+ });
78
+ if (!collapse) return raw;
79
+ const merged = [];
80
+ for (const ev of raw) {
81
+ const prev = merged[merged.length - 1];
82
+ if (prev && prev.kind === ev.kind && ev.kind !== "observed_failure") {
83
+ prev.evidenceSpanIds.push(...ev.evidenceSpanIds);
84
+ prev.endTs = Math.max(prev.endTs, ev.endTs);
85
+ const n = prev.evidenceSpanIds.length;
86
+ prev.title = `${KIND_VERB[ev.kind]} (${n}\xD7)`;
87
+ prev.summary = `${KIND_VERB[ev.kind]} ${n} time${n === 1 ? "" : "s"} \u2014 latest: ${ev.title}`;
88
+ } else {
89
+ merged.push({ ...ev, evidenceSpanIds: [...ev.evidenceSpanIds] });
90
+ }
91
+ }
92
+ return merged;
93
+ }
94
+ var KIND_TO_SCENE = {
95
+ understood_task: "title_card",
96
+ reasoned: "reasoning",
97
+ ran_command: "terminal",
98
+ read_file: "file",
99
+ edited_code: "diff",
100
+ searched: "search",
101
+ used_browser: "browser",
102
+ called_tool: "tool",
103
+ evaluated: "eval",
104
+ observed_failure: "error",
105
+ completed: "summary"
106
+ };
107
+ var DURATION_BY_IMPORTANCE = {
108
+ 1: 2500,
109
+ 2: 3e3,
110
+ 3: 4e3,
111
+ 4: 5e3,
112
+ 5: 6e3
113
+ };
114
+ function compileStoryboard(events, opts = {}) {
115
+ const title = opts.title ?? "Agent run";
116
+ const maxScenes = opts.maxScenes ?? 16;
117
+ const indexed = events.map((ev, i) => ({ ev, i }));
118
+ const mustKeep = indexed.filter(({ ev }) => ev.importance >= 4);
119
+ const rest = indexed.filter(({ ev }) => ev.importance < 4).sort((a, b) => b.ev.importance - a.ev.importance || a.i - b.i);
120
+ const budget = Math.max(0, maxScenes - mustKeep.length);
121
+ const selected = [...mustKeep, ...rest.slice(0, budget)].sort((a, b) => a.i - b.i);
122
+ const actionScenes = selected.map(({ ev }) => ({
123
+ sceneType: KIND_TO_SCENE[ev.kind],
124
+ title: ev.title,
125
+ narration: ev.summary,
126
+ durationMs: DURATION_BY_IMPORTANCE[ev.importance],
127
+ evidenceSpanIds: ev.evidenceSpanIds
128
+ }));
129
+ const failures = events.filter((e) => e.kind === "observed_failure").length;
130
+ const edits = events.filter((e) => e.kind === "edited_code").length;
131
+ const commands = events.filter((e) => e.kind === "ran_command").length;
132
+ const summaryNarration = `${events.length} moments \xB7 ${commands} command${commands === 1 ? "" : "s"} \xB7 ${edits} edit${edits === 1 ? "" : "s"} \xB7 ${failures} failure${failures === 1 ? "" : "s"}`;
133
+ const scenes = [
134
+ {
135
+ sceneType: "title_card",
136
+ title,
137
+ narration: "The agent receives its task.",
138
+ durationMs: 3e3,
139
+ evidenceSpanIds: []
140
+ },
141
+ ...actionScenes,
142
+ {
143
+ sceneType: "summary",
144
+ title: failures > 0 ? "Finished \u2014 with failures" : "Finished",
145
+ narration: summaryNarration,
146
+ durationMs: 4e3,
147
+ evidenceSpanIds: []
148
+ }
149
+ ];
150
+ return { title, totalMs: scenes.reduce((s, sc) => s + sc.durationMs, 0), scenes };
151
+ }
152
+ var SCENE_ICON = {
153
+ title_card: "\u{1F3AC}",
154
+ reasoning: "\u{1F9E0}",
155
+ terminal: "\u2328\uFE0F",
156
+ file: "\u{1F4C4}",
157
+ diff: "\u270F\uFE0F",
158
+ search: "\u{1F50E}",
159
+ browser: "\u{1F310}",
160
+ tool: "\u{1F527}",
161
+ eval: "\u2696\uFE0F",
162
+ error: "\u274C",
163
+ summary: "\u{1F3C1}"
164
+ };
165
+ function mmss(ms) {
166
+ const s = Math.round(ms / 1e3);
167
+ return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
168
+ }
169
+ function truncate(s, max) {
170
+ return s.length <= max ? s : `${s.slice(0, Math.max(0, max - 1))}\u2026`;
171
+ }
172
+ function escapeHtml(s) {
173
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
174
+ }
175
+ function renderStoryboardMarkdown(storyboard) {
176
+ const out = [
177
+ `# \u{1F3AC} ${storyboard.title}`,
178
+ "",
179
+ `_${storyboard.scenes.length} scenes \xB7 ${mmss(storyboard.totalMs)} replay_`,
180
+ ""
181
+ ];
182
+ let elapsed = 0;
183
+ for (const sc of storyboard.scenes) {
184
+ out.push(`### [${mmss(elapsed)}] ${SCENE_ICON[sc.sceneType]} ${sc.title}`);
185
+ out.push("");
186
+ out.push(sc.narration);
187
+ if (sc.evidenceSpanIds.length > 0) {
188
+ out.push("");
189
+ out.push(
190
+ `_evidence: ${sc.evidenceSpanIds.length} span(s) \u2014 ${sc.evidenceSpanIds.slice(0, 6).join(", ")}_`
191
+ );
192
+ }
193
+ out.push("");
194
+ elapsed += sc.durationMs;
195
+ }
196
+ return out.join("\n");
197
+ }
198
+ function renderStoryboardHtml(storyboard, opts = {}) {
199
+ const docTitle = opts.title ?? storyboard.title;
200
+ const scenesJson = JSON.stringify(
201
+ storyboard.scenes.map((s) => ({
202
+ icon: SCENE_ICON[s.sceneType],
203
+ type: s.sceneType,
204
+ title: s.title,
205
+ narration: s.narration,
206
+ durationMs: s.durationMs,
207
+ evidence: s.evidenceSpanIds.length
208
+ }))
209
+ );
210
+ return `<!doctype html>
211
+ <html lang="en">
212
+ <head>
213
+ <meta charset="utf-8" />
214
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
215
+ <title>${escapeHtml(docTitle)}</title>
216
+ <style>
217
+ :root { color-scheme: dark; }
218
+ * { box-sizing: border-box; }
219
+ body { margin: 0; font: 16px/1.5 ui-sans-serif, system-ui, -apple-system, sans-serif;
220
+ background: #0b0f17; color: #e6edf3; display: flex; min-height: 100vh; align-items: center; justify-content: center; }
221
+ .stage { width: min(820px, 94vw); }
222
+ h1 { font-size: 1.1rem; font-weight: 600; color: #9aa7b5; margin: 0 0 14px; letter-spacing: .02em; }
223
+ .card { background: #111824; border: 1px solid #1e2a3a; border-radius: 14px; padding: 28px 30px;
224
+ min-height: 230px; box-shadow: 0 12px 40px rgba(0,0,0,.45); position: relative; overflow: hidden; }
225
+ .card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--accent, #3b82f6); }
226
+ .icon { font-size: 2.6rem; line-height: 1; }
227
+ .title { font-size: 1.5rem; font-weight: 650; margin: 14px 0 8px; }
228
+ .narration { color: #b6c2cf; font-size: 1.05rem; }
229
+ .meta { position: absolute; bottom: 16px; right: 22px; color: #5b6b7d; font-size: .8rem; }
230
+ .type-error { --accent: #ef4444; } .type-diff { --accent: #22c55e; } .type-terminal { --accent: #eab308; }
231
+ .type-browser { --accent: #06b6d4; } .type-summary { --accent: #a855f7; } .type-title_card { --accent: #3b82f6; }
232
+ .scene-enter { animation: pop .45s cubic-bezier(.2,.7,.3,1.2); }
233
+ @keyframes pop { from { opacity: 0; transform: translateY(10px) scale(.985); } to { opacity: 1; transform: none; } }
234
+ .bar { height: 4px; background: #1e2a3a; border-radius: 4px; margin-top: 16px; overflow: hidden; }
235
+ .bar > i { display: block; height: 100%; width: 0; background: var(--accent, #3b82f6); transition: width .1s linear; }
236
+ .controls { display: flex; gap: 10px; align-items: center; margin-top: 14px; color: #8b98a6; font-size: .85rem; }
237
+ button { background: #1b2636; color: #e6edf3; border: 1px solid #2a3a4f; border-radius: 8px;
238
+ padding: 6px 12px; cursor: pointer; font: inherit; }
239
+ button:hover { background: #243349; }
240
+ .dots { display: flex; gap: 5px; margin-left: auto; }
241
+ .dot { width: 7px; height: 7px; border-radius: 50%; background: #2a3a4f; cursor: pointer; }
242
+ .dot.on { background: var(--accent, #3b82f6); }
243
+ </style>
244
+ </head>
245
+ <body>
246
+ <div class="stage">
247
+ <h1>\u{1F3AC} ${escapeHtml(docTitle)}</h1>
248
+ <div class="card" id="card">
249
+ <div class="icon" id="icon"></div>
250
+ <div class="title" id="title"></div>
251
+ <div class="narration" id="narration"></div>
252
+ <div class="meta" id="meta"></div>
253
+ <div class="bar"><i id="fill"></i></div>
254
+ </div>
255
+ <div class="controls">
256
+ <button id="playPause">\u23F8 Pause</button>
257
+ <button id="prev">\u25C0 Prev</button>
258
+ <button id="next">Next \u25B6</button>
259
+ <span id="counter"></span>
260
+ <span class="dots" id="dots"></span>
261
+ </div>
262
+ </div>
263
+ <script>
264
+ const SCENES = ${scenesJson};
265
+ let i = 0, playing = true, raf = 0, start = 0;
266
+ const card = document.getElementById('card'), counter = document.getElementById('counter');
267
+ const dotsEl = document.getElementById('dots');
268
+ SCENES.forEach((_, k) => { const d = document.createElement('span'); d.className = 'dot'; d.onclick = () => go(k); dotsEl.appendChild(d); });
269
+ function paint() {
270
+ const s = SCENES[i];
271
+ card.className = 'card scene-enter type-' + s.type;
272
+ document.getElementById('icon').textContent = s.icon;
273
+ document.getElementById('title').textContent = s.title;
274
+ document.getElementById('narration').textContent = s.narration;
275
+ document.getElementById('meta').textContent = s.evidence ? (s.evidence + ' span' + (s.evidence === 1 ? '' : 's')) : '';
276
+ counter.textContent = (i + 1) + ' / ' + SCENES.length;
277
+ [...dotsEl.children].forEach((d, k) => d.className = 'dot' + (k === i ? ' on' : ''));
278
+ void card.offsetWidth;
279
+ }
280
+ function tick(t) {
281
+ if (!start) start = t;
282
+ const s = SCENES[i], p = Math.min(1, (t - start) / s.durationMs);
283
+ document.getElementById('fill').style.width = (p * 100) + '%';
284
+ if (p >= 1) { if (i < SCENES.length - 1) { go(i + 1); } else { playing = false; updateBtn(); return; } }
285
+ if (playing) raf = requestAnimationFrame(tick);
286
+ }
287
+ function go(n) { i = Math.max(0, Math.min(SCENES.length - 1, n)); start = 0; cancelAnimationFrame(raf); paint(); if (playing) raf = requestAnimationFrame(tick); }
288
+ function updateBtn() { document.getElementById('playPause').textContent = playing ? '\u23F8 Pause' : '\u25B6 Play'; }
289
+ document.getElementById('playPause').onclick = () => { playing = !playing; updateBtn(); start = 0; if (playing) raf = requestAnimationFrame(tick); else cancelAnimationFrame(raf); };
290
+ document.getElementById('next').onclick = () => go(i + 1);
291
+ document.getElementById('prev').onclick = () => go(i - 1);
292
+ paint(); raf = requestAnimationFrame(tick);
293
+ </script>
294
+ </body>
295
+ </html>
296
+ `;
297
+ }
298
+ export {
299
+ compileStoryboard,
300
+ reduceToSemanticEvents,
301
+ renderStoryboardHtml,
302
+ renderStoryboardMarkdown
303
+ };
304
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storyboard/index.ts"],"sourcesContent":["/**\n * Storyboard — compile a raw agent trace into a small set of meaningful scenes,\n * then render them as a shareable replay.\n *\n * Span[] → SemanticEvent[] → Storyboard{scenes} → { markdown | html }\n *\n * The trace is the source of truth; the storyboard is the IR; markdown/html\n * (and, in a consumer package, Remotion/MP4) are compiled targets. Everything\n * here is PURE — same spans in, same bytes out (no clock/random) — so a run's\n * replay is deterministic and diffable. The semantic reducer is rules-based:\n * an LLM pass can refine titles later, but the structure does not depend on\n * one. Renderers that need a browser (Remotion, React) live in consumers; this\n * module only emits strings.\n */\n\nimport type { Span } from '../trace/schema'\n\n/** What the agent meaningfully did — the compressed vocabulary the storyboard\n * is built from (the spec's semantic layer). */\nexport type SemanticKind =\n | 'understood_task'\n | 'reasoned'\n | 'ran_command'\n | 'read_file'\n | 'edited_code'\n | 'searched'\n | 'used_browser'\n | 'called_tool'\n | 'evaluated'\n | 'observed_failure'\n | 'completed'\n\nexport interface SemanticEvent {\n kind: SemanticKind\n /** One-line headline (the ticket/scene title). */\n title: string\n /** Short human summary. */\n summary: string\n /** Span ids backing this moment — the evidence trail. */\n evidenceSpanIds: string[]\n /** 1 (noise) … 5 (pivotal: failures, edits). Drives selection + duration. */\n importance: 1 | 2 | 3 | 4 | 5\n startTs: number\n endTs: number\n}\n\nexport interface ReduceOptions {\n /** Collapse adjacent same-kind moments into one (e.g. 6 file reads → one\n * \"explored N files\"). Default true — this is the compression that takes a\n * 4000-event run down to dozens of moments. */\n collapseAdjacent?: boolean\n}\n\ninterface Classified {\n kind: SemanticKind\n importance: 1 | 2 | 3 | 4 | 5\n /** A short label for the span's action (e.g. the command, the file). */\n label: string\n}\n\nfunction toolLabel(span: Span): string {\n if (span.kind === 'tool') {\n const tn = span.toolName\n const arg =\n typeof span.args === 'string'\n ? span.args\n : span.args && typeof span.args === 'object'\n ? Object.values(span.args as Record<string, unknown>).find((v) => typeof v === 'string')\n : undefined\n return typeof arg === 'string' && arg.length > 0 ? `${tn}: ${truncate(arg, 60)}` : tn\n }\n return span.name\n}\n\nfunction classify(span: Span): Classified {\n // A failed span is pivotal regardless of what it was doing.\n if (span.status === 'error' || span.error) {\n return { kind: 'observed_failure', importance: 5, label: span.error ?? span.name }\n }\n if (span.kind === 'llm' || span.kind === 'agent') {\n return { kind: 'reasoned', importance: 2, label: span.name }\n }\n if (span.kind === 'judge') {\n return { kind: 'evaluated', importance: 2, label: span.name }\n }\n if (span.kind === 'retrieval') {\n return { kind: 'searched', importance: 2, label: span.name }\n }\n if (span.kind === 'sandbox') {\n return { kind: 'ran_command', importance: 3, label: span.name }\n }\n if (span.kind === 'tool') {\n const tn = span.toolName.toLowerCase()\n const label = toolLabel(span)\n if (/shell|exec|bash|\\brun\\b|terminal|command/.test(tn)) {\n return { kind: 'ran_command', importance: 3, label }\n }\n if (/edit|write|patch|apply|str_replace|create.*file|save/.test(tn)) {\n return { kind: 'edited_code', importance: 4, label }\n }\n if (/read|\\bcat\\b|open|view|get.*file|load/.test(tn)) {\n return { kind: 'read_file', importance: 2, label }\n }\n if (/search|grep|find|glob|query/.test(tn)) {\n return { kind: 'searched', importance: 2, label }\n }\n if (/browser|playwright|click|navigate|goto|screenshot|page/.test(tn)) {\n return { kind: 'used_browser', importance: 3, label }\n }\n return { kind: 'called_tool', importance: 3, label }\n }\n return { kind: 'called_tool', importance: 2, label: span.name }\n}\n\nconst KIND_VERB: Record<SemanticKind, string> = {\n understood_task: 'Received the task',\n reasoned: 'Reasoned',\n ran_command: 'Ran a command',\n read_file: 'Read files',\n edited_code: 'Edited code',\n searched: 'Searched',\n used_browser: 'Drove the browser',\n called_tool: 'Used a tool',\n evaluated: 'Evaluated the result',\n observed_failure: 'Hit a failure',\n completed: 'Finished',\n}\n\n/**\n * Reduce a span tree into the meaningful moments a viewer cares about. Spans\n * are sorted by start time; each is classified, then adjacent same-kind\n * moments collapse into one (the compression step). A failure always stands\n * alone (importance 5) so it never gets folded into the noise around it.\n */\nexport function reduceToSemanticEvents(\n spans: readonly Span[],\n opts: ReduceOptions = {},\n): SemanticEvent[] {\n const collapse = opts.collapseAdjacent ?? true\n const ordered = [...spans].sort((a, b) => a.startedAt - b.startedAt)\n const raw: SemanticEvent[] = ordered.map((s) => {\n const c = classify(s)\n return {\n kind: c.kind,\n title: c.label,\n summary: `${KIND_VERB[c.kind]} — ${c.label}`,\n evidenceSpanIds: [s.spanId],\n importance: c.importance,\n startTs: s.startedAt,\n endTs: s.endedAt ?? s.startedAt,\n }\n })\n if (!collapse) return raw\n\n const merged: SemanticEvent[] = []\n for (const ev of raw) {\n const prev = merged[merged.length - 1]\n // Never fold a failure, and never fold across kinds.\n if (prev && prev.kind === ev.kind && ev.kind !== 'observed_failure') {\n prev.evidenceSpanIds.push(...ev.evidenceSpanIds)\n prev.endTs = Math.max(prev.endTs, ev.endTs)\n const n = prev.evidenceSpanIds.length\n prev.title = `${KIND_VERB[ev.kind]} (${n}×)`\n prev.summary = `${KIND_VERB[ev.kind]} ${n} time${n === 1 ? '' : 's'} — latest: ${ev.title}`\n } else {\n merged.push({ ...ev, evidenceSpanIds: [...ev.evidenceSpanIds] })\n }\n }\n return merged\n}\n\n// ── Storyboard ────────────────────────────────────────────────────────────\n\nexport type SceneType =\n | 'title_card'\n | 'reasoning'\n | 'terminal'\n | 'file'\n | 'diff'\n | 'search'\n | 'browser'\n | 'tool'\n | 'eval'\n | 'error'\n | 'summary'\n\nexport interface Scene {\n sceneType: SceneType\n title: string\n narration: string\n durationMs: number\n /** Span ids behind the scene — the click-through evidence. */\n evidenceSpanIds: string[]\n}\n\nexport interface Storyboard {\n title: string\n /** Sum of scene durations — the replay length. */\n totalMs: number\n scenes: Scene[]\n}\n\nexport interface CompileOptions {\n /** Headline for the title card. Default \"Agent run\". */\n title?: string\n /** Max action scenes between the title + summary cards. Default 16. */\n maxScenes?: number\n}\n\nconst KIND_TO_SCENE: Record<SemanticKind, SceneType> = {\n understood_task: 'title_card',\n reasoned: 'reasoning',\n ran_command: 'terminal',\n read_file: 'file',\n edited_code: 'diff',\n searched: 'search',\n used_browser: 'browser',\n called_tool: 'tool',\n evaluated: 'eval',\n observed_failure: 'error',\n completed: 'summary',\n}\n\n// Pivotal moments earn longer screen time.\nconst DURATION_BY_IMPORTANCE: Record<1 | 2 | 3 | 4 | 5, number> = {\n 1: 2500,\n 2: 3000,\n 3: 4000,\n 4: 5000,\n 5: 6000,\n}\n\n/**\n * Select the moments worth showing and lay them out as scenes. Every failure\n * (importance 5) and edit (4) is always kept — those are the story; the rest\n * fill the budget by importance, then everything is re-sorted to chronological\n * order so the replay reads forward in time. A title card opens and a summary\n * card closes.\n */\nexport function compileStoryboard(\n events: readonly SemanticEvent[],\n opts: CompileOptions = {},\n): Storyboard {\n const title = opts.title ?? 'Agent run'\n const maxScenes = opts.maxScenes ?? 16\n\n const indexed = events.map((ev, i) => ({ ev, i }))\n const mustKeep = indexed.filter(({ ev }) => ev.importance >= 4)\n const rest = indexed\n .filter(({ ev }) => ev.importance < 4)\n .sort((a, b) => b.ev.importance - a.ev.importance || a.i - b.i)\n const budget = Math.max(0, maxScenes - mustKeep.length)\n const selected = [...mustKeep, ...rest.slice(0, budget)].sort((a, b) => a.i - b.i)\n\n const actionScenes: Scene[] = selected.map(({ ev }) => ({\n sceneType: KIND_TO_SCENE[ev.kind],\n title: ev.title,\n narration: ev.summary,\n durationMs: DURATION_BY_IMPORTANCE[ev.importance],\n evidenceSpanIds: ev.evidenceSpanIds,\n }))\n\n const failures = events.filter((e) => e.kind === 'observed_failure').length\n const edits = events.filter((e) => e.kind === 'edited_code').length\n const commands = events.filter((e) => e.kind === 'ran_command').length\n const summaryNarration =\n `${events.length} moments · ${commands} command${commands === 1 ? '' : 's'} · ` +\n `${edits} edit${edits === 1 ? '' : 's'} · ${failures} failure${failures === 1 ? '' : 's'}`\n\n const scenes: Scene[] = [\n {\n sceneType: 'title_card',\n title,\n narration: 'The agent receives its task.',\n durationMs: 3000,\n evidenceSpanIds: [],\n },\n ...actionScenes,\n {\n sceneType: 'summary',\n title: failures > 0 ? 'Finished — with failures' : 'Finished',\n narration: summaryNarration,\n durationMs: 4000,\n evidenceSpanIds: [],\n },\n ]\n return { title, totalMs: scenes.reduce((s, sc) => s + sc.durationMs, 0), scenes }\n}\n\n// ── Renderers (pure string out) ─────────────────────────────────────────────\n\nconst SCENE_ICON: Record<SceneType, string> = {\n title_card: '🎬',\n reasoning: '🧠',\n terminal: '⌨️',\n file: '📄',\n diff: '✏️',\n search: '🔎',\n browser: '🌐',\n tool: '🔧',\n eval: '⚖️',\n error: '❌',\n summary: '🏁',\n}\n\nfunction mmss(ms: number): string {\n const s = Math.round(ms / 1000)\n return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, '0')}`\n}\n\nfunction truncate(s: string, max: number): string {\n return s.length <= max ? s : `${s.slice(0, Math.max(0, max - 1))}…`\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\n/** Render the storyboard as a Markdown timeline — the human-readable shot list. */\nexport function renderStoryboardMarkdown(storyboard: Storyboard): string {\n const out: string[] = [\n `# 🎬 ${storyboard.title}`,\n '',\n `_${storyboard.scenes.length} scenes · ${mmss(storyboard.totalMs)} replay_`,\n '',\n ]\n let elapsed = 0\n for (const sc of storyboard.scenes) {\n out.push(`### [${mmss(elapsed)}] ${SCENE_ICON[sc.sceneType]} ${sc.title}`)\n out.push('')\n out.push(sc.narration)\n if (sc.evidenceSpanIds.length > 0) {\n out.push('')\n out.push(\n `_evidence: ${sc.evidenceSpanIds.length} span(s) — ${sc.evidenceSpanIds.slice(0, 6).join(', ')}_`,\n )\n }\n out.push('')\n elapsed += sc.durationMs\n }\n return out.join('\\n')\n}\n\nexport interface HtmlRenderOptions {\n /** Document title + on-page heading. Defaults to the storyboard title. */\n title?: string\n}\n\n/**\n * Render the storyboard as a self-contained, auto-playing HTML replay — one\n * shareable file, no build step, no external assets. Each scene animates in\n * for its duration with a progress bar; controls let a viewer scrub. This is\n * the \"free clip\" a run produces; an MP4 is the same storyboard fed to Remotion\n * in a consumer package.\n */\nexport function renderStoryboardHtml(storyboard: Storyboard, opts: HtmlRenderOptions = {}): string {\n const docTitle = opts.title ?? storyboard.title\n const scenesJson = JSON.stringify(\n storyboard.scenes.map((s) => ({\n icon: SCENE_ICON[s.sceneType],\n type: s.sceneType,\n title: s.title,\n narration: s.narration,\n durationMs: s.durationMs,\n evidence: s.evidenceSpanIds.length,\n })),\n )\n // Inline everything; the JS player is tiny and dependency-free.\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>${escapeHtml(docTitle)}</title>\n<style>\n :root { color-scheme: dark; }\n * { box-sizing: border-box; }\n body { margin: 0; font: 16px/1.5 ui-sans-serif, system-ui, -apple-system, sans-serif;\n background: #0b0f17; color: #e6edf3; display: flex; min-height: 100vh; align-items: center; justify-content: center; }\n .stage { width: min(820px, 94vw); }\n h1 { font-size: 1.1rem; font-weight: 600; color: #9aa7b5; margin: 0 0 14px; letter-spacing: .02em; }\n .card { background: #111824; border: 1px solid #1e2a3a; border-radius: 14px; padding: 28px 30px;\n min-height: 230px; box-shadow: 0 12px 40px rgba(0,0,0,.45); position: relative; overflow: hidden; }\n .card::before { content: \"\"; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--accent, #3b82f6); }\n .icon { font-size: 2.6rem; line-height: 1; }\n .title { font-size: 1.5rem; font-weight: 650; margin: 14px 0 8px; }\n .narration { color: #b6c2cf; font-size: 1.05rem; }\n .meta { position: absolute; bottom: 16px; right: 22px; color: #5b6b7d; font-size: .8rem; }\n .type-error { --accent: #ef4444; } .type-diff { --accent: #22c55e; } .type-terminal { --accent: #eab308; }\n .type-browser { --accent: #06b6d4; } .type-summary { --accent: #a855f7; } .type-title_card { --accent: #3b82f6; }\n .scene-enter { animation: pop .45s cubic-bezier(.2,.7,.3,1.2); }\n @keyframes pop { from { opacity: 0; transform: translateY(10px) scale(.985); } to { opacity: 1; transform: none; } }\n .bar { height: 4px; background: #1e2a3a; border-radius: 4px; margin-top: 16px; overflow: hidden; }\n .bar > i { display: block; height: 100%; width: 0; background: var(--accent, #3b82f6); transition: width .1s linear; }\n .controls { display: flex; gap: 10px; align-items: center; margin-top: 14px; color: #8b98a6; font-size: .85rem; }\n button { background: #1b2636; color: #e6edf3; border: 1px solid #2a3a4f; border-radius: 8px;\n padding: 6px 12px; cursor: pointer; font: inherit; }\n button:hover { background: #243349; }\n .dots { display: flex; gap: 5px; margin-left: auto; }\n .dot { width: 7px; height: 7px; border-radius: 50%; background: #2a3a4f; cursor: pointer; }\n .dot.on { background: var(--accent, #3b82f6); }\n</style>\n</head>\n<body>\n<div class=\"stage\">\n <h1>🎬 ${escapeHtml(docTitle)}</h1>\n <div class=\"card\" id=\"card\">\n <div class=\"icon\" id=\"icon\"></div>\n <div class=\"title\" id=\"title\"></div>\n <div class=\"narration\" id=\"narration\"></div>\n <div class=\"meta\" id=\"meta\"></div>\n <div class=\"bar\"><i id=\"fill\"></i></div>\n </div>\n <div class=\"controls\">\n <button id=\"playPause\">⏸ Pause</button>\n <button id=\"prev\">◀ Prev</button>\n <button id=\"next\">Next ▶</button>\n <span id=\"counter\"></span>\n <span class=\"dots\" id=\"dots\"></span>\n </div>\n</div>\n<script>\n const SCENES = ${scenesJson};\n let i = 0, playing = true, raf = 0, start = 0;\n const card = document.getElementById('card'), counter = document.getElementById('counter');\n const dotsEl = document.getElementById('dots');\n SCENES.forEach((_, k) => { const d = document.createElement('span'); d.className = 'dot'; d.onclick = () => go(k); dotsEl.appendChild(d); });\n function paint() {\n const s = SCENES[i];\n card.className = 'card scene-enter type-' + s.type;\n document.getElementById('icon').textContent = s.icon;\n document.getElementById('title').textContent = s.title;\n document.getElementById('narration').textContent = s.narration;\n document.getElementById('meta').textContent = s.evidence ? (s.evidence + ' span' + (s.evidence === 1 ? '' : 's')) : '';\n counter.textContent = (i + 1) + ' / ' + SCENES.length;\n [...dotsEl.children].forEach((d, k) => d.className = 'dot' + (k === i ? ' on' : ''));\n void card.offsetWidth;\n }\n function tick(t) {\n if (!start) start = t;\n const s = SCENES[i], p = Math.min(1, (t - start) / s.durationMs);\n document.getElementById('fill').style.width = (p * 100) + '%';\n if (p >= 1) { if (i < SCENES.length - 1) { go(i + 1); } else { playing = false; updateBtn(); return; } }\n if (playing) raf = requestAnimationFrame(tick);\n }\n function go(n) { i = Math.max(0, Math.min(SCENES.length - 1, n)); start = 0; cancelAnimationFrame(raf); paint(); if (playing) raf = requestAnimationFrame(tick); }\n function updateBtn() { document.getElementById('playPause').textContent = playing ? '⏸ Pause' : '▶ Play'; }\n document.getElementById('playPause').onclick = () => { playing = !playing; updateBtn(); start = 0; if (playing) raf = requestAnimationFrame(tick); else cancelAnimationFrame(raf); };\n document.getElementById('next').onclick = () => go(i + 1);\n document.getElementById('prev').onclick = () => go(i - 1);\n paint(); raf = requestAnimationFrame(tick);\n</script>\n</body>\n</html>\n`\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-eval",
3
- "version": "0.73.0",
3
+ "version": "0.74.0",
4
4
  "description": "Substrate for self-improving agents: traces, verifiable rewards, preferences, GEPA / reflective mutation, auto-research, replay, sequential anytime-valid stats, and release gates.",
5
5
  "homepage": "https://github.com/tangle-network/agent-eval#readme",
6
6
  "repository": {
@@ -109,6 +109,11 @@
109
109
  "import": "./dist/campaign/index.js",
110
110
  "default": "./dist/campaign/index.js"
111
111
  },
112
+ "./storyboard": {
113
+ "types": "./dist/storyboard/index.d.ts",
114
+ "import": "./dist/storyboard/index.js",
115
+ "default": "./dist/storyboard/index.js"
116
+ },
112
117
  "./workflow": {
113
118
  "types": "./dist/workflow/index.d.ts",
114
119
  "import": "./dist/workflow/index.js",