agentfootprint-lens 0.7.0 → 0.9.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.
@@ -1,321 +1,3 @@
1
- // src/core/LiveTimelineBuilder.ts
2
- var LiveTimelineBuilder = class {
3
- constructor() {
4
- this.turns = [];
5
- this.currentTurn = null;
6
- /**
7
- * The most-recently-started iteration. Stays bound through the entire
8
- * iteration lifecycle — llm_start opens it, llm_end ends the LLM phase
9
- * but the iter stays current so subsequent `tool_start` / `tool_end`
10
- * events (which fire AFTER llm_end in the agent loop) still attach to
11
- * it. Cleared only on `commitCurrentTurn()` / `reset()`.
12
- */
13
- this.currentIter = null;
14
- /**
15
- * True between an iteration's `llm_start` and its `llm_end`. Drives
16
- * context-injection routing: events emitted while the LLM phase is
17
- * active belong to THIS iteration's prompt; events emitted after
18
- * `llm_end` belong to the NEXT iteration (they shape its context).
19
- * Tool start/end ignore this flag — they always attach to the
20
- * most-recent iter regardless of LLM phase.
21
- */
22
- this.llmPhaseActive = false;
23
- this.toolByCallId = /* @__PURE__ */ new Map();
24
- this.messages = [];
25
- this.finalDecision = {};
26
- /** Context injections that fired BEFORE this turn's first llm_start —
27
- * they shape iteration 1's context. Flushed onto iteration 1 at its
28
- * llm_start. Reset at turn_start so each turn accumulates its own. */
29
- this.pendingPreIterInjections = [];
30
- }
31
- /**
32
- * Begin a new turn. Call this BEFORE `agent.run(userPrompt)` so the
33
- * user's prompt appears alongside the iterations it produced. Safe to
34
- * call even mid-conversation — it closes the previous turn cleanly.
35
- */
36
- startTurn(userPrompt) {
37
- if (this.currentTurn) this.commitCurrentTurn();
38
- this.currentTurn = {
39
- index: this.turns.length,
40
- userPrompt,
41
- iterations: [],
42
- finalContent: "",
43
- totalInputTokens: 0,
44
- totalOutputTokens: 0,
45
- totalDurationMs: 0,
46
- startMs: Date.now()
47
- };
48
- this.pendingPreIterInjections = [];
49
- this.messages.push({ role: "user", content: userPrompt });
50
- }
51
- /**
52
- * Optional — attach the system prompt so MessagesPanel can render it
53
- * in the collapsible preamble. Usually set once at agent construction.
54
- */
55
- setSystemPrompt(prompt) {
56
- this.systemPrompt = prompt;
57
- }
58
- /**
59
- * Feed one agent stream event. Safe to call for unknown events; we
60
- * ignore anything we don't recognize.
61
- */
62
- ingest(event) {
63
- const e = event;
64
- if (!e || typeof e.type !== "string") return;
65
- switch (e.type) {
66
- case "turn_start":
67
- case "agentfootprint.agent.turn_start": {
68
- const userMessage = e.userMessage ?? "";
69
- this.startTurn(userMessage);
70
- return;
71
- }
72
- case "llm_start":
73
- case "agentfootprint.stream.llm_start":
74
- this.onLLMStart(e);
75
- return;
76
- case "llm_end":
77
- case "agentfootprint.stream.llm_end":
78
- this.onLLMEnd(e);
79
- return;
80
- case "tool_start":
81
- case "agentfootprint.stream.tool_start":
82
- this.onToolStart(e);
83
- return;
84
- case "tool_end":
85
- case "agentfootprint.stream.tool_end":
86
- this.onToolEnd(e);
87
- return;
88
- case "turn_end":
89
- case "agentfootprint.agent.turn_complete":
90
- this.commitCurrentTurn();
91
- return;
92
- default:
93
- if (typeof e.type === "string" && e.type.startsWith("agentfootprint.context.")) {
94
- this.onContextInjection(e.type, e);
95
- }
96
- return;
97
- }
98
- }
99
- /**
100
- * Route a context-engineering event to the iteration it shaped.
101
- *
102
- * Routing rule: the `llmPhaseActive` flag (true between this iter's
103
- * llm_start and llm_end) decides. While active, the event shaped THIS
104
- * iter's prompt → attach directly. While inactive (between llm_end
105
- * and the next llm_start, or before the first llm_start), the event
106
- * is preparing context for the NEXT iter → queue on
107
- * `pendingPreIterInjections`, flushed onto the next iter at its
108
- * llm_start. Tool events do not gate on this flag — they bind to the
109
- * most-recent iter unconditionally.
110
- */
111
- onContextInjection(rawName, e) {
112
- if (!this.currentTurn) return;
113
- const injection = buildInjection(rawName, e);
114
- if (!injection) return;
115
- if (this.currentIter && this.llmPhaseActive) {
116
- this.currentIter.contextInjections.push(injection);
117
- } else {
118
- this.pendingPreIterInjections.push(injection);
119
- }
120
- }
121
- onLLMStart(e) {
122
- if (!this.currentTurn) return;
123
- const iterNum = e.iteration ?? this.currentTurn.iterations.length + 1;
124
- const carriedInjections = this.pendingPreIterInjections;
125
- this.pendingPreIterInjections = [];
126
- this.currentIter = {
127
- index: iterNum,
128
- assistantContent: "",
129
- toolCalls: [],
130
- decisionAtStart: {},
131
- visibleTools: [],
132
- startMs: Date.now(),
133
- // Freeze the message count here so "What Neo saw" can reproduce
134
- // the context window at this exact iteration later.
135
- messagesSentCount: this.messages.length,
136
- contextInjections: carriedInjections
137
- };
138
- this.currentTurn.iterations.push(this.currentIter);
139
- this.llmPhaseActive = true;
140
- }
141
- onLLMEnd(e) {
142
- if (!this.currentIter || !this.currentTurn) return;
143
- this.currentIter.assistantContent = e.content ?? this.currentIter.assistantContent;
144
- if (e.model) this.currentIter.model = e.model;
145
- if (e.usage?.inputTokens !== void 0) this.currentIter.inputTokens = e.usage.inputTokens;
146
- if (e.usage?.outputTokens !== void 0) this.currentIter.outputTokens = e.usage.outputTokens;
147
- if (e.stopReason) this.currentIter.stopReason = e.stopReason;
148
- this.currentIter.durationMs = e.durationMs ?? Date.now() - this.currentIter.startMs;
149
- this.currentTurn.totalInputTokens += this.currentIter.inputTokens ?? 0;
150
- this.currentTurn.totalOutputTokens += this.currentIter.outputTokens ?? 0;
151
- this.currentTurn.totalDurationMs += this.currentIter.durationMs ?? 0;
152
- if (this.currentIter.assistantContent) {
153
- this.messages.push({ role: "assistant", content: this.currentIter.assistantContent });
154
- }
155
- if ((e.toolCallCount ?? 0) === 0) {
156
- this.currentTurn.finalContent = this.currentIter.assistantContent;
157
- }
158
- this.llmPhaseActive = false;
159
- }
160
- onToolStart(e) {
161
- if (!this.currentIter || !this.currentTurn) return;
162
- const tool = {
163
- id: e.toolCallId ?? `tool-${this.currentIter.toolCalls.length}`,
164
- name: e.toolName ?? "unknown",
165
- arguments: e.args ?? {},
166
- result: "",
167
- iterationIndex: this.currentIter.index,
168
- turnIndex: this.currentTurn.index,
169
- startMs: Date.now()
170
- };
171
- this.currentIter.toolCalls.push(tool);
172
- this.toolByCallId.set(tool.id, tool);
173
- }
174
- onToolEnd(e) {
175
- const tool = this.toolByCallId.get(e.toolCallId ?? "");
176
- if (!tool) return;
177
- const r = e.result;
178
- if (typeof r === "string") {
179
- tool.result = r;
180
- } else if (r && typeof r === "object") {
181
- tool.result = r.content ?? "";
182
- if (r.error === true) tool.error = true;
183
- }
184
- tool.durationMs = e.durationMs ?? Date.now() - tool.startMs;
185
- this.messages.push({ role: "tool", content: tool.result, toolCallId: tool.id });
186
- }
187
- commitCurrentTurn() {
188
- if (!this.currentTurn) return;
189
- this.turns.push(this.currentTurn);
190
- this.currentTurn = null;
191
- this.currentIter = null;
192
- this.llmPhaseActive = false;
193
- }
194
- /**
195
- * Snapshot the current state as an immutable `AgentTimeline`. Safe to
196
- * call at any point — mid-run gives you the partial state so Lens can
197
- * live-update.
198
- */
199
- getTimeline() {
200
- const allTurns = [...this.turns];
201
- if (this.currentTurn) allTurns.push(this.currentTurn);
202
- const tools = [];
203
- const frozenTurns = allTurns.map((t) => {
204
- const turnInjections = [];
205
- const turnLedger = {};
206
- const iterations = t.iterations.map((i) => {
207
- const tcs = i.toolCalls.map((tc) => ({ ...tc }));
208
- tools.push(...tcs);
209
- const contextInjections = i.contextInjections.map(
210
- (ci) => ({ ...ci })
211
- );
212
- const contextLedger = {};
213
- for (const ci of contextInjections) {
214
- const d = ci.deltaCount;
215
- if (!d) continue;
216
- for (const [key, val] of Object.entries(d)) {
217
- if (typeof val === "number") {
218
- const prev = typeof contextLedger[key] === "number" ? contextLedger[key] : 0;
219
- contextLedger[key] = prev + val;
220
- const prevTurn = typeof turnLedger[key] === "number" ? turnLedger[key] : 0;
221
- turnLedger[key] = prevTurn + val;
222
- } else if (typeof val === "boolean") {
223
- contextLedger[key] = contextLedger[key] === true || val;
224
- turnLedger[key] = turnLedger[key] === true || val;
225
- }
226
- }
227
- }
228
- turnInjections.push(...contextInjections);
229
- return {
230
- ...i,
231
- toolCalls: tcs,
232
- contextInjections,
233
- contextLedger
234
- };
235
- });
236
- return {
237
- ...t,
238
- iterations,
239
- contextInjections: turnInjections,
240
- contextLedger: turnLedger
241
- };
242
- });
243
- return {
244
- turns: frozenTurns,
245
- messages: [...this.messages],
246
- tools,
247
- finalDecision: { ...this.finalDecision },
248
- rawSnapshot: null
249
- };
250
- }
251
- /**
252
- * Fold in a final `decision` scope after the run — useful when
253
- * the consumer wants the Decision Ribbon (phase-2) to reflect the
254
- * post-run state. Safe no-op during the run itself.
255
- */
256
- setFinalDecision(decision) {
257
- this.finalDecision = decision;
258
- }
259
- /** Get the optional system prompt for the Messages preamble. */
260
- getSystemPrompt() {
261
- return this.systemPrompt;
262
- }
263
- /** Wipe state. Useful when the consumer starts a fresh conversation. */
264
- reset() {
265
- this.turns = [];
266
- this.currentTurn = null;
267
- this.currentIter = null;
268
- this.llmPhaseActive = false;
269
- this.toolByCallId.clear();
270
- this.messages = [];
271
- this.finalDecision = {};
272
- this.pendingPreIterInjections = [];
273
- }
274
- };
275
- function buildInjection(name, e) {
276
- const suffix = name.slice("agentfootprint.context.".length);
277
- const payload = e.payload;
278
- const data = payload && typeof payload === "object" ? payload : e ?? {};
279
- const role = typeof data.role === "string" ? data.role : void 0;
280
- const targetIndex = typeof data.targetIndex === "number" ? data.targetIndex : void 0;
281
- const deltaCount = data.deltaCount && typeof data.deltaCount === "object" ? data.deltaCount : void 0;
282
- const enrich = (base) => ({
283
- ...base,
284
- ...role !== void 0 && { role },
285
- ...targetIndex !== void 0 && { targetIndex },
286
- ...deltaCount !== void 0 && { deltaCount },
287
- payload: data
288
- });
289
- switch (suffix) {
290
- case "rag.chunks": {
291
- const chunkCount = Number(data.chunkCount ?? 0);
292
- const topScore = typeof data.topScore === "number" ? data.topScore : void 0;
293
- const label = chunkCount > 0 ? `${chunkCount} chunk${chunkCount === 1 ? "" : "s"}${topScore !== void 0 ? ` \xB7 top ${topScore.toFixed(2)}` : ""}` : "0 chunks";
294
- return enrich({ source: "rag", slot: "messages", label });
295
- }
296
- case "skill.activated": {
297
- const skillId = String(data.skillId ?? "skill");
298
- return enrich({ source: "skill", slot: "system-prompt", label: skillId });
299
- }
300
- case "memory.injected": {
301
- const count = Number(data.count ?? 0);
302
- const label = count > 0 ? `memory \xB7 ${count} msg${count === 1 ? "" : "s"}` : "memory";
303
- return enrich({ source: "memory", slot: "messages", label });
304
- }
305
- case "instructions.fired": {
306
- const count = Number(data.count ?? (Array.isArray(data.ids) ? data.ids.length : 1));
307
- const label = `${count} instruction${count === 1 ? "" : "s"}`;
308
- return enrich({ source: "instructions", slot: "system-prompt", label });
309
- }
310
- default:
311
- return enrich({
312
- source: suffix.split(".")[0] || "context",
313
- slot: "messages",
314
- label: suffix
315
- });
316
- }
317
- }
318
-
319
1
  // src/core/fromAgentSnapshot.ts
320
2
  function fromAgentSnapshot(runtime) {
321
3
  const shared = runtime?.sharedState ?? {};
@@ -328,7 +10,10 @@ function fromAgentSnapshot(runtime) {
328
10
  const toolResolves = extractToolResolves(commitLog);
329
11
  const turns = assembleTurns(messages, llmCalls, toolExecs, instructionEvals, toolResolves);
330
12
  const allTools = turns.flatMap((t) => t.iterations.flatMap((i) => i.toolCalls));
13
+ const agentName = typeof runtime?.agentName === "string" && runtime.agentName || typeof runtime?.name === "string" && runtime.name || "Agent";
14
+ const agentId = typeof runtime?.agentId === "string" && runtime.agentId || "snapshot-import";
331
15
  return {
16
+ agent: { id: agentId, name: agentName },
332
17
  turns,
333
18
  messages,
334
19
  tools: allTools,
@@ -491,7 +176,7 @@ function assembleTurns(messages, llmCalls, toolExecs, instructionEvals, toolReso
491
176
  visibleTools: visible?.visibleTools ?? [],
492
177
  // Post-process path (snapshot-import — no live emit stream) has no
493
178
  // way to reconstruct context-injection timing. Leave empty; the
494
- // live path via LiveTimelineBuilder fills these in naturally.
179
+ // live path via agentTimeline() recorder fills these in naturally.
495
180
  contextInjections: [],
496
181
  contextLedger: {}
497
182
  };
@@ -525,7 +210,7 @@ function finalizeTurn(t) {
525
210
  totalDurationMs,
526
211
  // Post-process snapshot path has no live emit timing, so the
527
212
  // turn-level context fields stay empty here too — the live
528
- // LiveTimelineBuilder path is the one that captures injections.
213
+ // live recorder path is the one that captures injections.
529
214
  contextInjections: [],
530
215
  contextLedger: {}
531
216
  };
@@ -685,8 +370,7 @@ function truncate(s, max) {
685
370
  }
686
371
 
687
372
  export {
688
- LiveTimelineBuilder,
689
373
  fromAgentSnapshot,
690
374
  deriveStages
691
375
  };
692
- //# sourceMappingURL=chunk-3N4WQXQP.js.map
376
+ //# sourceMappingURL=chunk-R4XZ5FX5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/fromAgentSnapshot.ts","../src/core/deriveStages.ts"],"sourcesContent":["/**\n * fromAgentSnapshot — turn an agentfootprint runtimeSnapshot into the\n * agent-shaped AgentTimeline Lens renders against.\n *\n * ─────────────────────────────────────────────────────────────────────────\n * The raw snapshot is flowchart-shaped (stages, commitLog, subflowResults).\n * Lens needs agent-shape: turns[] → iterations[] → {messages, toolCalls,\n * decision, tokens, latency, visibleTools}. That's what this file does.\n *\n * Derivation strategy (all sources already present — no library change\n * needed):\n * • `sharedState.messages[]` — canonical conversation\n * • `commitLog` entries for `call-llm` / `streaming-call-llm` — per-iter\n * LLM request+response (model, tokens, duration, stop reason)\n * • `commitLog` entries for `execute-tool-calls` — per-iter tool outputs\n * and decision updates\n * • `sf-instructions-to-llm` snapshots — matched instruction ids +\n * injection counts per iter\n * • `sf-tools` snapshots — tool list visible to the LLM that iter\n *\n * Turn boundaries are inferred by walking `messages[]` and grouping\n * everything between user messages into one turn. Iteration boundaries\n * are the LLM call events within a turn.\n * ─────────────────────────────────────────────────────────────────────────\n */\n\nimport type {\n AgentIteration,\n AgentMessage,\n AgentTimeline,\n AgentToolInvocation,\n AgentTurn,\n} from \"./types\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnySnapshot = any;\n\nexport function fromAgentSnapshot(runtime: AnySnapshot): AgentTimeline {\n const shared = runtime?.sharedState ?? {};\n const rawMessages: RawMessage[] = shared.messages ?? [];\n const messages = rawMessages.map(normalizeMessage);\n\n const commitLog = Array.isArray(runtime?.commitLog) ? runtime.commitLog : [];\n const llmCalls = extractLLMCalls(commitLog);\n const toolExecs = extractToolExecutions(commitLog);\n const instructionEvals = extractInstructionEvals(commitLog);\n const toolResolves = extractToolResolves(commitLog);\n\n const turns = assembleTurns(messages, llmCalls, toolExecs, instructionEvals, toolResolves);\n const allTools = turns.flatMap((t) => t.iterations.flatMap((i) => i.toolCalls));\n\n // Snapshot-import path: derive the agent identity from snapshot\n // metadata when available, defaulting to a sensible label otherwise.\n // Live recorder paths populate this from `agentTimeline({ name })`\n // directly; this fallback covers replay/import scenarios.\n const agentName =\n (typeof runtime?.agentName === \"string\" && runtime.agentName) ||\n (typeof runtime?.name === \"string\" && runtime.name) ||\n \"Agent\";\n const agentId =\n (typeof runtime?.agentId === \"string\" && runtime.agentId) || \"snapshot-import\";\n\n return {\n agent: { id: agentId, name: agentName },\n turns,\n messages,\n tools: allTools,\n finalDecision: (shared.decision as Record<string, unknown>) ?? {},\n rawSnapshot: runtime,\n };\n}\n\n// ── Normalize ─────────────────────────────────────────────────────────\n\ninterface RawMessage {\n role: string;\n content: string | unknown;\n toolCalls?: Array<{ id: string; name: string; arguments: Record<string, unknown> }>;\n toolCallId?: string;\n}\n\nfunction normalizeMessage(m: RawMessage): AgentMessage {\n const role = ((): AgentMessage[\"role\"] => {\n if (m.role === \"system\" || m.role === \"user\" || m.role === \"assistant\" || m.role === \"tool\")\n return m.role;\n return \"user\";\n })();\n const content = typeof m.content === \"string\" ? m.content : JSON.stringify(m.content);\n return {\n role,\n content,\n ...(m.toolCalls?.length ? { toolCalls: m.toolCalls } : {}),\n ...(m.toolCallId ? { toolCallId: m.toolCallId } : {}),\n };\n}\n\n// ── Extract from commitLog ────────────────────────────────────────────\n\ninterface RawCommit {\n stageId?: string;\n stage?: string;\n runtimeStageId?: string;\n updates?: Record<string, unknown>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n trace?: any;\n}\n\ninterface LLMCall {\n iterationIndex: number;\n model?: string;\n inputTokens?: number;\n outputTokens?: number;\n durationMs?: number;\n stopReason?: string;\n assistantContent: string;\n toolCallsRequested: Array<{ id: string; name: string; arguments: Record<string, unknown> }>;\n}\n\nfunction extractLLMCalls(commitLog: RawCommit[]): LLMCall[] {\n const out: LLMCall[] = [];\n let iter = 0;\n for (const entry of commitLog) {\n const id = entry.stageId ?? \"\";\n if (id !== \"call-llm\" && id !== \"streaming-call-llm\") continue;\n iter++;\n const u = (entry.updates ?? {}) as Record<string, unknown>;\n const rawResponse =\n (u[\"adapterRawResponse\"] as Record<string, unknown> | undefined) ??\n (u[\"llmResponse\"] as Record<string, unknown> | undefined);\n const usage = rawResponse?.usage as\n | { inputTokens?: number; outputTokens?: number }\n | undefined;\n out.push({\n iterationIndex: iter,\n model: rawResponse?.model as string | undefined,\n inputTokens: usage?.inputTokens,\n outputTokens: usage?.outputTokens,\n durationMs: (u[\"callDurationMs\"] as number | undefined) ?? undefined,\n stopReason: rawResponse?.stopReason as string | undefined,\n assistantContent: (rawResponse?.content as string | undefined) ?? \"\",\n toolCallsRequested:\n (rawResponse?.toolCalls as LLMCall[\"toolCallsRequested\"] | undefined) ?? [],\n });\n }\n return out;\n}\n\ninterface ToolExec {\n iterationIndex: number;\n toolCalls: AgentToolInvocation[];\n}\n\nfunction extractToolExecutions(commitLog: RawCommit[]): ToolExec[] {\n const out: ToolExec[] = [];\n let iter = 0;\n for (const entry of commitLog) {\n const id = entry.stageId ?? \"\";\n if (id !== \"execute-tool-calls\") continue;\n iter++;\n const u = (entry.updates ?? {}) as Record<string, unknown>;\n // agentfootprint stores parsed tool calls + their results via\n // tool-start / tool-end emit events + the tool-role messages appended\n // to `messages`. Simplest stable derivation: walk messages right\n // after this commit and collect the tool-result entries.\n // For v0.1 we emit the tool call stubs; full resolution happens at\n // the assembler step where we have both sides in hand.\n const rawCalls = u[\"toolCalls\"] as LLMCall[\"toolCallsRequested\"] | undefined;\n const stubs: AgentToolInvocation[] = (rawCalls ?? []).map((c) => ({\n id: c.id,\n name: c.name,\n arguments: c.arguments ?? {},\n result: \"\", // filled in during assembly\n iterationIndex: iter,\n turnIndex: 0, // reassigned during assembly\n decisionUpdate: u[\"updatedDecision\"] as Record<string, unknown> | undefined,\n }));\n out.push({ iterationIndex: iter, toolCalls: stubs });\n }\n return out;\n}\n\ninterface InstructionEval {\n iterationIndex: number;\n matchedInstructions?: string[];\n promptInjectionCount: number;\n toolInjectionCount: number;\n}\n\nfunction extractInstructionEvals(commitLog: RawCommit[]): InstructionEval[] {\n const out: InstructionEval[] = [];\n let iter = 0;\n for (const entry of commitLog) {\n const id = entry.stageId ?? \"\";\n if (id !== \"evaluate-instructions\") continue;\n iter++;\n const u = (entry.updates ?? {}) as Record<string, unknown>;\n const matchedRaw = u[\"matchedInstructions\"];\n const matched = parseMatched(matchedRaw);\n const promptInj = Array.isArray(u[\"promptInjections\"]) ? u[\"promptInjections\"].length : 0;\n const toolInj = Array.isArray(u[\"toolInjections\"]) ? u[\"toolInjections\"].length : 0;\n out.push({\n iterationIndex: iter,\n ...(matched.length > 0 && { matchedInstructions: matched }),\n promptInjectionCount: promptInj,\n toolInjectionCount: toolInj,\n });\n }\n return out;\n}\n\nfunction parseMatched(v: unknown): string[] {\n if (!v) return [];\n if (Array.isArray(v)) return v.filter((x) => typeof x === \"string\");\n if (typeof v === \"string\") {\n // format: \"N matched: id1, id2, id3...\"\n const m = v.match(/:\\s*(.+)/);\n if (!m) return [];\n return m[1]\n .split(\",\")\n .map((s) => s.trim().replace(/\\.{3}$/, \"\"))\n .filter(Boolean);\n }\n return [];\n}\n\ninterface ToolResolve {\n iterationIndex: number;\n visibleTools: string[];\n}\n\nfunction extractToolResolves(commitLog: RawCommit[]): ToolResolve[] {\n const out: ToolResolve[] = [];\n let iter = 0;\n for (const entry of commitLog) {\n const id = entry.stageId ?? \"\";\n if (id !== \"resolve-tools\") continue;\n iter++;\n const u = (entry.updates ?? {}) as Record<string, unknown>;\n const descs = u[\"toolDescriptions\"] as Array<{ name: string }> | undefined;\n out.push({\n iterationIndex: iter,\n visibleTools: (descs ?? []).map((d) => d.name),\n });\n }\n return out;\n}\n\n// ── Assemble turns ────────────────────────────────────────────────────\n\nfunction assembleTurns(\n messages: AgentMessage[],\n llmCalls: LLMCall[],\n toolExecs: ToolExec[],\n instructionEvals: InstructionEval[],\n toolResolves: ToolResolve[],\n): AgentTurn[] {\n // Build a per-iteration map (flat across turns) then split by turn.\n // For a fresh agent instance, iter counts restart every turn — but\n // because commitLog is cumulative, iter numbers across commitLog are\n // monotonically increasing over the whole execution. So we group\n // iterations by the message boundary they fall in.\n //\n // Algorithm: walk messages in order. Each user message starts a new\n // turn. Each assistant message that has toolCalls (or is the final)\n // consumes the next LLM call from llmCalls. Tool-role messages that\n // follow bind to the most recent assistant message's toolCalls.\n\n const turns: AgentTurn[] = [];\n let currentTurn: {\n index: number;\n userPrompt: string;\n iterations: AgentIteration[];\n finalContent: string;\n } | null = null;\n let llmIdx = 0;\n const toolExecByIter = new Map(toolExecs.map((t) => [t.iterationIndex, t]));\n const instrByIter = new Map(instructionEvals.map((i) => [i.iterationIndex, i]));\n const visibleByIter = new Map(toolResolves.map((t) => [t.iterationIndex, t]));\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n if (currentTurn) turns.push(finalizeTurn(currentTurn));\n currentTurn = {\n index: turns.length,\n userPrompt: msg.content,\n iterations: [],\n finalContent: \"\",\n };\n continue;\n }\n if (!currentTurn) continue; // skip system prompt + anything before first user\n\n if (msg.role === \"assistant\") {\n const call = llmCalls[llmIdx];\n llmIdx++;\n const iterIndex = call?.iterationIndex ?? currentTurn.iterations.length + 1;\n const exec = toolExecByIter.get(iterIndex);\n const instr = instrByIter.get(iterIndex);\n const visible = visibleByIter.get(iterIndex);\n\n const toolCalls: AgentToolInvocation[] = (exec?.toolCalls ?? []).map((tc) => ({\n ...tc,\n turnIndex: currentTurn!.index,\n }));\n\n // For the post-process fallback path we can't know the precise\n // messages-at-iter-start, so approximate it as \"all messages\n // currently accumulated in this turn before this iter\" — close\n // enough for imported traces where we don't have emit timing.\n const msgsBefore = messages.indexOf(msg);\n const iteration: AgentIteration = {\n index: iterIndex,\n messagesSentCount: msgsBefore >= 0 ? msgsBefore : 0,\n ...(call?.model && { model: call.model }),\n ...(call?.inputTokens !== undefined && { inputTokens: call.inputTokens }),\n ...(call?.outputTokens !== undefined && { outputTokens: call.outputTokens }),\n ...(call?.durationMs !== undefined && { durationMs: call.durationMs }),\n ...(call?.stopReason && { stopReason: call.stopReason }),\n assistantContent: call?.assistantContent ?? msg.content,\n toolCalls,\n decisionAtStart: {}, // TODO(phase-2): derive from pre-iter commit\n ...(instr?.matchedInstructions && { matchedInstructions: instr.matchedInstructions }),\n visibleTools: visible?.visibleTools ?? [],\n // Post-process path (snapshot-import — no live emit stream) has no\n // way to reconstruct context-injection timing. Leave empty; the\n // live path via agentTimeline() recorder fills these in naturally.\n contextInjections: [],\n contextLedger: {},\n };\n\n currentTurn.iterations.push(iteration);\n if (!toolCalls.length) currentTurn.finalContent = iteration.assistantContent;\n continue;\n }\n\n if (msg.role === \"tool\" && msg.toolCallId) {\n // Bind the result string back to the matching tool invocation in\n // the latest iteration.\n const iter = currentTurn.iterations[currentTurn.iterations.length - 1];\n if (!iter) continue;\n const idx = iter.toolCalls.findIndex((tc) => tc.id === msg.toolCallId);\n if (idx < 0) continue;\n const updated = { ...iter.toolCalls[idx], result: msg.content };\n // Rewrite via mutation — iter is readonly at the type level but we\n // own this intermediate structure during assembly.\n (iter.toolCalls as AgentToolInvocation[])[idx] = updated;\n }\n }\n\n if (currentTurn) turns.push(finalizeTurn(currentTurn));\n return turns;\n}\n\nfunction finalizeTurn(t: {\n index: number;\n userPrompt: string;\n iterations: AgentIteration[];\n finalContent: string;\n}): AgentTurn {\n const totalInputTokens = t.iterations.reduce((s, i) => s + (i.inputTokens ?? 0), 0);\n const totalOutputTokens = t.iterations.reduce((s, i) => s + (i.outputTokens ?? 0), 0);\n const totalDurationMs = t.iterations.reduce((s, i) => s + (i.durationMs ?? 0), 0);\n return {\n index: t.index,\n userPrompt: t.userPrompt,\n iterations: t.iterations,\n finalContent: t.finalContent,\n totalInputTokens,\n totalOutputTokens,\n totalDurationMs,\n // Post-process snapshot path has no live emit timing, so the\n // turn-level context fields stay empty here too — the live\n // live recorder path is the one that captures injections.\n contextInjections: [],\n contextLedger: {},\n };\n}\n","/**\n * deriveStages — turn an `AgentTimeline` into an ordered list of\n * \"stages\" (edges in the node flowchart).\n *\n * Each stage is one directed edge between two of the four nodes:\n *\n * USER ──── message ────▶ AGENT ──── tool call ────▶ TOOL\n * ▲ │ ▲ │\n * └──── final answer ────┘ └── activation ── SKILL │\n * ▲ │\n * └── tool result ──┘\n *\n * Grounding rule from the spec: every stage maps to one of the three\n * LLM primitives (System Prompt · Message · Tool). Skills aren't a\n * fourth primitive — they're a *bracket* wrapping whichever primitive\n * they use to reach the LLM. So the SKILL node is optional and only\n * shows when a skill activation actually happens.\n *\n * Derivation is pure: given the same timeline you always get the same\n * stage sequence. Safe to re-run on every render; live updates simply\n * append new stages as new events arrive.\n */\nimport type { AgentTimeline, AgentToolInvocation } from \"./types\";\n\nexport type StageNodeId = \"user\" | \"agent\" | \"tool\" | \"skill\";\n\n/** Which of the three LLM primitives this stage touches. */\nexport type StagePrimitive = \"message\" | \"tool\" | \"system-prompt\";\n\n/**\n * Which of the three Agent-input channels this stage MUTATED.\n * Drives the per-port highlight inside the Agent node. A single stage\n * can touch multiple — e.g. a `read_skill` return simultaneously adds\n * a tool-role message, grows the System Prompt (skill body injected),\n * and surfaces new Tools (autoActivate-gated tools go live).\n */\nexport interface StageMutations {\n /** A message appended to the conversation this step. */\n readonly messages?: boolean;\n /** The System Prompt sent on the NEXT LLM call changed this step. */\n readonly systemPrompt?: boolean;\n /** The Tools list sent on the NEXT LLM call changed this step. */\n readonly tools?: boolean;\n /** Count of tools added this step (when known). */\n readonly toolsAdded?: number;\n /** Count of tools removed this step (when known). */\n readonly toolsRemoved?: number;\n /** System-prompt delta in characters (when known). */\n readonly systemPromptDeltaChars?: number;\n /**\n * Actual text that was appended to the System Prompt this step —\n * e.g. the skill body delivered by a `read_skill` return. Captured\n * at the moment we know it (the return stage) and propagated via\n * `pending` to the stage that's attributed with the mutation. This\n * is what lets the mutation drill-down show the real diff instead\n * of an \"isn't captured\" placeholder.\n */\n readonly systemPromptAdded?: string;\n /** Skill id that activated this step (from `read_skill` args). */\n readonly activatedSkillId?: string;\n /** Names of tools that came online as a result of this step. */\n readonly toolsAddedList?: readonly string[];\n}\n\nexport interface Stage {\n /** 0-based stage index across the whole run. */\n readonly index: number;\n /** Source node. */\n readonly from: StageNodeId;\n /** Destination node. */\n readonly to: StageNodeId;\n /** Human-friendly one-line description (appears on the edge). */\n readonly label: string;\n /** Which LLM primitive carries this stage — for vocabulary grounding. */\n readonly primitive: StagePrimitive;\n /**\n * What CHANGED on the Agent's three input channels (System Prompt,\n * Messages, Tools) when this stage fired. Per-port highlights on\n * the Agent node read from here.\n */\n readonly mutations: StageMutations;\n /**\n * Which turn + iteration this stage belongs to. Lets the UI jump\n * the Messages panel to the same moment when a stage is clicked.\n */\n readonly turnIndex: number;\n readonly iterIndex?: number;\n /**\n * Secondary node that should ALSO light up for this stage. Used when\n * a skill activation is a bracket over another primitive — e.g. a\n * `read_skill` tool call lights both TOOL (primary) and SKILL\n * (secondary). `undefined` for non-bracketed stages.\n */\n readonly alsoLights?: StageNodeId;\n /** Tool or skill name, when applicable. */\n readonly toolName?: string;\n /**\n * If this stage belongs to a round that fired MULTIPLE tool calls\n * concurrently (LLM emitted them in one response), the total count.\n * `undefined` for single-tool rounds. Drives the \"parallel N\" badge\n * on the Tool node so users can see \"this isn't a single tool call\n * — three are happening at the same logical step\" without reading\n * the commentary.\n */\n readonly parallelCount?: number;\n /**\n * What *kind* of tool this is from the user's mental model:\n * • \"skill\" — a skill-management tool (list_skills / read_skill).\n * • \"ask-human\" — a clarification-from-user tool.\n * • undefined — a regular data/action tool.\n * Lets UI labels render as `Tool (Skill)` / `Tool (Ask user)` /\n * just `Tool` while the underlying edges still flow Agent ↔ Tool.\n */\n readonly toolKind?: \"skill\" | \"ask-human\";\n /** Token usage attributed to this stage (if LLM call). */\n readonly tokens?: { readonly input?: number; readonly output?: number };\n /** Wall-clock duration in ms (if the source event provided it). */\n readonly durationMs?: number;\n}\n\nexport function deriveStages(timeline: AgentTimeline): Stage[] {\n const stages: Stage[] = [];\n let idx = 0;\n const push = (s: Omit<Stage, \"index\">) => {\n stages.push({ ...s, index: idx++ });\n };\n\n // Mutations that were PROMISED by a prior stage but only take\n // effect on the NEXT outgoing LLM call. The canonical case is\n // `read_skill`: the return leg appends a tool-role Message, but\n // System Prompt + Tools injections only land when the NEXT\n // iteration starts (via autoActivate + AgentInstruction.activeWhen).\n // We hold them here and merge into the next `agent → …` edge we\n // emit, then clear.\n let pending: StageMutations | null = null;\n const consumePending = (base: StageMutations): StageMutations => {\n if (!pending) return base;\n const merged: StageMutations = { ...base, ...pending };\n pending = null;\n return merged;\n };\n\n for (const turn of timeline.turns) {\n // 1. USER → AGENT: the prompt. Mutates Messages only, plus any\n // pending mutations promised from a prior turn's last stage.\n push({\n from: \"user\",\n to: \"agent\",\n label: truncate(turn.userPrompt, 60),\n primitive: \"message\",\n turnIndex: turn.index,\n mutations: consumePending({ messages: true }),\n });\n\n for (const iter of turn.iterations) {\n // A round with > 1 tool call means the LLM fired all of them\n // concurrently (parallel fanout). Carry that count onto each\n // tool stage so UIs can annotate \"parallel N\" without having to\n // walk sibling stages.\n const parallelCount = iter.toolCalls.length > 1 ? iter.toolCalls.length : undefined;\n for (const tc of iter.toolCalls) {\n const kind = classifyTool(tc);\n if (kind === \"skill-management\") {\n // Outgoing: Agent → Tool (the LLM making the skill call).\n // This is an LLM-outgoing edge, so pending mutations from a\n // *prior* read_skill — if any — surface here.\n push({\n from: \"agent\",\n to: \"tool\",\n alsoLights: \"skill\",\n label: skillManagementLabel(tc),\n primitive: \"tool\",\n turnIndex: turn.index,\n iterIndex: iter.index,\n toolName: tc.name,\n toolKind: \"skill\",\n mutations: consumePending({ messages: true }),\n });\n // Return leg: only a tool-role Message is added RIGHT NOW.\n // SP + Tools mutations caused by read_skill take effect on\n // the NEXT outgoing LLM call (autoActivate fires at the\n // start of the next iteration, not here). Defer them via\n // `pending` so they appear on the correct edge.\n const isReadSkill = tc.name === \"read_skill\";\n push({\n from: \"tool\",\n to: \"agent\",\n alsoLights: \"skill\",\n label: isReadSkill\n ? `Skill body delivered (+${tc.result.length} chars) — will activate next step`\n : `Skills list (${countSkills(tc.result)} skills)`,\n primitive: \"tool\",\n turnIndex: turn.index,\n iterIndex: iter.index,\n toolName: tc.name,\n toolKind: \"skill\",\n mutations: { messages: true },\n });\n if (isReadSkill) {\n const spDelta = tc.result.length;\n const activatedSkillId =\n (tc.arguments?.id as string | undefined) ?? undefined;\n pending = {\n systemPrompt: true,\n tools: true,\n systemPromptDeltaChars: spDelta,\n // Stash the ACTUAL content that just entered the System\n // Prompt + the skill id that activated. These ride along\n // `pending` and land on the next outgoing LLM edge where\n // the mutation is attributed, so the UI can render a\n // real diff instead of a \"not captured\" placeholder.\n systemPromptAdded: tc.result,\n ...(activatedSkillId ? { activatedSkillId } : {}),\n };\n }\n } else if (kind === \"ask-human\") {\n push({\n from: \"agent\",\n to: \"user\",\n label: askHumanLabel(tc),\n primitive: \"message\",\n turnIndex: turn.index,\n iterIndex: iter.index,\n toolName: tc.name,\n toolKind: \"ask-human\",\n mutations: consumePending({ messages: true }),\n });\n } else {\n // Regular tool. Outgoing edge is the LLM's next call — so\n // it consumes any pending mutations from a prior read_skill.\n push({\n from: \"agent\",\n to: \"tool\",\n label: `Called ${tc.name}`,\n primitive: \"tool\",\n turnIndex: turn.index,\n iterIndex: iter.index,\n toolName: tc.name,\n ...(parallelCount ? { parallelCount } : {}),\n mutations: consumePending({ messages: true }),\n });\n push({\n from: \"tool\",\n to: \"agent\",\n label: truncate(tc.result, 80),\n primitive: \"tool\",\n turnIndex: turn.index,\n iterIndex: iter.index,\n toolName: tc.name,\n ...(parallelCount ? { parallelCount } : {}),\n mutations: { messages: true },\n });\n }\n }\n }\n\n // Final AGENT → USER: last LLM call's output. Also consumes\n // pending (in case the very last iteration before Finalize was\n // a read_skill — unusual, but possible).\n //\n // Attach this stage to the LAST iter of the turn so the\n // \"ready to answer\" round (which has no tool calls, and would\n // otherwise produce no stages) gets a valid stage range. Without\n // this the range map is missing a key for that round and UIs\n // fall back to defaults — e.g. the commentary's \"active/past/\n // future\" dimming would get confused and mark the final round\n // active regardless of slider position.\n if (turn.finalContent) {\n const lastIter = turn.iterations[turn.iterations.length - 1];\n push({\n from: \"agent\",\n to: \"user\",\n label: truncate(turn.finalContent, 80),\n primitive: \"message\",\n turnIndex: turn.index,\n ...(lastIter ? { iterIndex: lastIter.index } : {}),\n mutations: consumePending({ messages: true }),\n });\n }\n }\n\n return stages;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────\n\ntype ToolKind = \"skill-management\" | \"ask-human\" | \"regular\";\n\nfunction classifyTool(tc: AgentToolInvocation): ToolKind {\n if (tc.name === \"list_skills\" || tc.name === \"read_skill\") return \"skill-management\";\n if (tc.name === \"ask_human\" || tc.name === \"ask_user\") return \"ask-human\";\n return \"regular\";\n}\n\nfunction skillManagementLabel(tc: AgentToolInvocation): string {\n if (tc.name === \"list_skills\") return \"Asked what skills are available\";\n if (tc.name === \"read_skill\") {\n const id = (tc.arguments?.id as string | undefined) ?? \"?\";\n return `Activated the \"${id}\" skill`;\n }\n return `Called ${tc.name}`;\n}\n\nfunction askHumanLabel(tc: AgentToolInvocation): string {\n const q = (tc.arguments?.question as string | undefined) ?? \"\";\n return q ? `Asked user: ${truncate(q, 50)}` : \"Asked user for clarification\";\n}\n\nfunction countSkills(result: string): number {\n try {\n const parsed = JSON.parse(result);\n if (Array.isArray(parsed?.skills)) return parsed.skills.length;\n if (Array.isArray(parsed)) return parsed.length;\n } catch {\n /* fall through */\n }\n return 0;\n}\n\nfunction truncate(s: string, max: number): string {\n const one = s.replace(/\\s+/g, \" \").trim();\n return one.length <= max ? one : one.slice(0, max - 1).trim() + \"…\";\n}\n"],"mappings":"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","names":[]}