agentfootprint-lens 0.14.0 → 0.14.2

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.
@@ -0,0 +1,230 @@
1
+ // src/v2/core/copyForLLM.ts
2
+ function buildLLMText(args) {
3
+ const {
4
+ recorder,
5
+ stepGraph,
6
+ boundaryRollups,
7
+ humanizer,
8
+ appName = "Chatbot",
9
+ viewState
10
+ } = args;
11
+ const summary = recorder.selectSummary();
12
+ const log = recorder.selectEventLog();
13
+ const sections = [];
14
+ sections.push("# Run Summary\n");
15
+ sections.push(`- **Status:** ${summary.status}`);
16
+ if (summary.durationMs !== void 0) {
17
+ sections.push(`- **Duration:** ${formatMs(summary.durationMs)}`);
18
+ }
19
+ if (summary.llmCallCount > 0) sections.push(`- **LLM calls:** ${summary.llmCallCount}`);
20
+ if (summary.toolCallCount > 0) sections.push(`- **Tool calls:** ${summary.toolCallCount}`);
21
+ if (summary.iterationCount > 0) sections.push(`- **Iterations:** ${summary.iterationCount}`);
22
+ if (summary.totalTokens.input > 0 || summary.totalTokens.output > 0) {
23
+ sections.push(
24
+ `- **Tokens:** ${summary.totalTokens.input} in / ${summary.totalTokens.output} out`
25
+ );
26
+ }
27
+ if (summary.totalUsd !== void 0) sections.push(`- **Estimated cost:** $${summary.totalUsd.toFixed(4)}`);
28
+ if (summary.permissionDenials > 0) sections.push(`- **Permission denials:** ${summary.permissionDenials}`);
29
+ if (summary.paused) sections.push(`- **Paused:** yes`);
30
+ if (viewState) {
31
+ sections.push("\n# Current View State (at copy time)\n");
32
+ if (viewState.focusStep !== void 0 && viewState.totalSteps !== void 0) {
33
+ sections.push(`- **Slider position:** ${viewState.focusStep + 1} / ${viewState.totalSteps}`);
34
+ }
35
+ if (viewState.isLive !== void 0) {
36
+ sections.push(`- **Live (auto-advancing):** ${viewState.isLive ? "yes" : "no"}`);
37
+ }
38
+ if (viewState.mode) sections.push(`- **Mode:** ${viewState.mode}`);
39
+ if (viewState.drillPath && viewState.drillPath.length > 0) {
40
+ sections.push(`- **Drill path:** ${viewState.drillPath.join(" / ")}`);
41
+ }
42
+ if (viewState.currentStep) {
43
+ const cs = viewState.currentStep;
44
+ const parts = [];
45
+ if (cs.label) parts.push(cs.label);
46
+ if (cs.kind) parts.push(`(\`${cs.kind}\`)`);
47
+ if (cs.iterationIndex !== void 0) parts.push(`iter #${cs.iterationIndex}`);
48
+ sections.push(`- **Current step:** ${parts.join(" ")}`);
49
+ if (cs.runtimeStageId) sections.push(` - runtimeStageId: \`${cs.runtimeStageId}\``);
50
+ if (cs.subflowPath && cs.subflowPath.length > 1) {
51
+ sections.push(` - subflowPath: ${cs.subflowPath.slice(1).join(" \u2192 ")}`);
52
+ }
53
+ }
54
+ if (viewState.visibleStepsCount !== void 0) {
55
+ sections.push(`- **Visible steps:** ${viewState.visibleStepsCount}`);
56
+ }
57
+ if (viewState.focusedEventSeq !== void 0) {
58
+ sections.push(`- **Focused event seq:** ${viewState.focusedEventSeq}`);
59
+ }
60
+ if (viewState.touched && viewState.touched.length > 0) {
61
+ sections.push(`- **Touched actors:** ${viewState.touched.join(", ")}`);
62
+ }
63
+ if (viewState.activeEdgeKey) {
64
+ sections.push(`- **Active edge:** \`${viewState.activeEdgeKey}\``);
65
+ }
66
+ }
67
+ if (boundaryRollups && boundaryRollups.length > 0) {
68
+ sections.push("\n# Per-Boundary Rollups\n");
69
+ for (const r of boundaryRollups) {
70
+ const kind = r.primitiveKind ?? "Boundary";
71
+ sections.push(`## ${r.label} (${kind}) \u2014 \`${r.runtimeStageId}\``);
72
+ if (r.tokens.input > 0 || r.tokens.output > 0) {
73
+ sections.push(`- Tokens: ${r.tokens.input} in / ${r.tokens.output} out`);
74
+ }
75
+ const counters = [];
76
+ if (r.llmCalls > 0) counters.push(`LLM calls: ${r.llmCalls}`);
77
+ if (r.toolCalls > 0) counters.push(`Tool calls: ${r.toolCalls}`);
78
+ if (r.iterations > 0) counters.push(`Iterations: ${r.iterations}`);
79
+ if (counters.length > 0) sections.push(`- ${counters.join(" \xB7 ")}`);
80
+ sections.push(
81
+ `- Duration: ${r.durationMs !== void 0 ? formatMs(r.durationMs) : "(in flight)"}`
82
+ );
83
+ sections.push("");
84
+ }
85
+ }
86
+ if (stepGraph && stepGraph.nodes.length > 0) {
87
+ sections.push("\n# Steps\n");
88
+ stepGraph.nodes.forEach((n, i) => {
89
+ sections.push(formatStep(i + 1, n));
90
+ });
91
+ }
92
+ if (log.length > 0) {
93
+ sections.push("\n# Commentary\n");
94
+ sections.push("```");
95
+ for (const entry of log) {
96
+ const line = humanizer ? humanizer(entry.event) : `[${entry.event.type}]`;
97
+ if (line === null) continue;
98
+ const t = `+${Math.round(entry.runOffsetMs)}ms`.padEnd(10);
99
+ sections.push(`${t} ${line.replace(/\{\{appName\}\}/g, appName)}`);
100
+ }
101
+ sections.push("```");
102
+ }
103
+ return sections.join("\n");
104
+ }
105
+ var LIBRARY_INTERNAL_FIELDS = /* @__PURE__ */ new Set([
106
+ "systemPromptInjections",
107
+ "messagesInjections",
108
+ "toolsInjections",
109
+ "cumTokensInput",
110
+ "cumTokensOutput",
111
+ "cumEstimatedUsd",
112
+ "costBudgetHit",
113
+ "iteration"
114
+ ]);
115
+ function compactBoundaryPayload(value) {
116
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return value;
117
+ const out = {};
118
+ for (const [k, v] of Object.entries(value)) {
119
+ if (LIBRARY_INTERNAL_FIELDS.has(k)) continue;
120
+ out[k] = v;
121
+ }
122
+ return out;
123
+ }
124
+ function formatStep(index, n) {
125
+ const lines = [];
126
+ const headerSuffix = n.iterationIndex !== void 0 ? ` (iter ${n.iterationIndex})` : "";
127
+ const kindLabel = formatKindLabel(n);
128
+ lines.push(`## ${index}. ${n.label} \u2014 ${kindLabel}${headerSuffix}`);
129
+ if (n.runtimeStageId) lines.push(`runtimeStageId: \`${n.runtimeStageId}\``);
130
+ if (n.subflowPath.length > 1) {
131
+ lines.push(`Path: ${n.subflowPath.slice(1).join(" \u2192 ")}`);
132
+ }
133
+ const dur = duration(n);
134
+ if (dur !== void 0 && dur > 0) lines.push(`Duration: ${formatMs(dur)}`);
135
+ if (n.tokens) lines.push(`Tokens: ${n.tokens.in} in / ${n.tokens.out} out`);
136
+ if (n.llmModel) lines.push(`Model: ${n.llmModel}`);
137
+ if (n.toolName) lines.push(`Tool: \`${n.toolName}\``);
138
+ if (n.slotUpdated) lines.push(`Slot updated: \`${n.slotUpdated}\``);
139
+ if (n.entryPayload !== void 0) {
140
+ lines.push("\n**Boundary input** (inputMapper result):");
141
+ lines.push("```json");
142
+ lines.push(safeJson(compactBoundaryPayload(n.entryPayload)));
143
+ lines.push("```");
144
+ }
145
+ if (n.exitPayload !== void 0) {
146
+ lines.push("\n**Boundary output** (outputMapper result):");
147
+ lines.push("```json");
148
+ lines.push(safeJson(compactBoundaryPayload(n.exitPayload)));
149
+ lines.push("```");
150
+ }
151
+ if (n.assistantText) {
152
+ const heading = n.kind === "llm->user" ? "Final answer" : "LLM's reasoning";
153
+ lines.push(`
154
+ **${heading}:**`);
155
+ lines.push("```");
156
+ lines.push(n.assistantText);
157
+ lines.push("```");
158
+ }
159
+ if (n.toolArgs !== void 0) {
160
+ lines.push("\n**Tool input (args):**");
161
+ lines.push("```json");
162
+ lines.push(safeJson(n.toolArgs));
163
+ lines.push("```");
164
+ }
165
+ if (n.toolResult !== void 0) {
166
+ lines.push("\n**Tool result sent to LLM:**");
167
+ lines.push("```json");
168
+ lines.push(safeJson(n.toolResult));
169
+ lines.push("```");
170
+ }
171
+ if (n.injections && n.injections.length > 0) {
172
+ lines.push("\n**Context injections:**");
173
+ for (const inj of n.injections) {
174
+ const id = inj.sourceId ? `:${inj.sourceId}` : "";
175
+ const role = inj.asRole ? ` (as ${inj.asRole})` : "";
176
+ const summary = inj.contentSummary ? ` \u2014 ${inj.contentSummary}` : "";
177
+ lines.push(`- [${inj.slot}] ${inj.source}${id}${role}${summary}`);
178
+ }
179
+ }
180
+ lines.push("");
181
+ return lines.join("\n");
182
+ }
183
+ function formatKindLabel(n) {
184
+ switch (n.kind) {
185
+ case "subflow":
186
+ return n.primitiveKind ? `${n.primitiveKind} boundary` : "subflow boundary";
187
+ case "user->llm":
188
+ return "user \u2192 llm";
189
+ case "llm->tool":
190
+ return "llm \u2192 tool";
191
+ case "tool->llm":
192
+ return "tool \u2192 llm";
193
+ case "llm->user":
194
+ return "llm \u2192 user (final answer)";
195
+ case "fork-branch":
196
+ return "parallel branch";
197
+ case "decision-branch":
198
+ return "decision branch";
199
+ default:
200
+ return n.kind;
201
+ }
202
+ }
203
+ function duration(n) {
204
+ if (typeof n.startOffsetMs === "number" && typeof n.endOffsetMs === "number") {
205
+ return n.endOffsetMs - n.startOffsetMs;
206
+ }
207
+ return void 0;
208
+ }
209
+ function formatMs(ms) {
210
+ if (ms < 1e3) return `${Math.round(ms)}ms`;
211
+ if (ms < 1e4) return `${(ms / 1e3).toFixed(1)}s`;
212
+ return `${(ms / 1e3).toFixed(1)}s`;
213
+ }
214
+ function safeJson(value) {
215
+ try {
216
+ const s = JSON.stringify(value, null, 2);
217
+ if (s.length > 4e3) {
218
+ return s.slice(0, 4e3) + `
219
+ ... (truncated; ${s.length - 4e3} chars)`;
220
+ }
221
+ return s;
222
+ } catch {
223
+ return String(value);
224
+ }
225
+ }
226
+
227
+ export {
228
+ buildLLMText
229
+ };
230
+ //# sourceMappingURL=chunk-UGDBHWTE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/v2/core/copyForLLM.ts"],"sourcesContent":["/**\n * `buildLLMText(recorder, stepGraph)` — assembles a single Markdown\n * blob describing the entire run, ready to paste into a chat (Claude,\n * ChatGPT) for debugging assistance.\n *\n * Design parallel to footprint-explainable-ui's NarrativePanel \"Copy\n * for LLM\" — same audience (a developer asking an LLM \"why did this\n * happen?\"), same shape (run summary + per-step payloads + per-\n * boundary rollups + commentary). Lens-specific because the data\n * sources are the StepGraph + BoundaryRecorder + LensRecorder\n * (extends SequenceRecorder<EventLogEntry>), not the footprintjs\n * narrative entries.\n *\n * Sections produced (in order):\n *\n * 1. Run Summary — status, duration, totals\n * 2. Per-Boundary Rollups — one block per Agent / LLMCall /\n * Sequence / etc. (multi-agent runs\n * benefit most; single-Agent runs\n * print one block)\n * 3. Steps — every visible StepNode with its\n * payload (assistantText / toolArgs\n * / toolResult / final answer /\n * boundary entry+exit payloads)\n * 4. Commentary — humanized per-event lines (one\n * per emitted event, time-stamped)\n *\n * Pure projection — no DOM, no clipboard. The caller (Lens.tsx) wires\n * the result to navigator.clipboard.writeText().\n */\n\nimport type { StepGraph, StepNode, BoundaryAggregate } from 'agentfootprint';\nimport type { LensRecorder } from './LensRecorder.js';\nimport type { Humanizer } from './humanizer.js';\n\nexport interface BuildLLMTextArgs {\n readonly recorder: LensRecorder;\n readonly stepGraph?: StepGraph;\n /** Optional per-boundary rollups (from\n * `BoundaryRecorder.aggregateAllBoundaries`). When provided, the\n * output includes a \"Per-Boundary Rollups\" section keyed by\n * runtimeStageId. */\n readonly boundaryRollups?: readonly BoundaryAggregate[];\n /** Humanizer used to render the Commentary section. Defaults to a\n * bare `[type]` formatter when not supplied. */\n readonly humanizer?: Humanizer;\n /** App name woven into commentary lines. Default: `'Chatbot'`. */\n readonly appName?: string;\n /** Optional snapshot of the consumer's current view state — slider\n * position, focused step, drill path, etc. When provided, output\n * includes a \"Current View State\" section so an LLM (or human\n * reviewer) can diagnose slider-sync / focus / drill issues from\n * the paste alone. */\n readonly viewState?: ViewStateSnapshot;\n}\n\n/** Snapshot of the Lens render state at copy time. All fields optional\n * — pass whichever the consumer can cheaply provide. */\nexport interface ViewStateSnapshot {\n /** Slider position (0-based step index). */\n readonly focusStep?: number;\n /** Total number of steps in the slider. */\n readonly totalSteps?: number;\n /** Live or paused (autoAdvance state). */\n readonly isLive?: boolean;\n /** Drill-down path (`[]` = top-level). */\n readonly drillPath?: readonly string[];\n /** `'top-level'` or `'drill-down'`. */\n readonly mode?: 'top-level' | 'drill-down';\n /** Currently-focused StepNode at the slider position. */\n readonly currentStep?: {\n readonly label?: string;\n readonly kind?: string;\n readonly runtimeStageId?: string;\n readonly subflowPath?: readonly string[];\n readonly iterationIndex?: number;\n };\n /** Number of visible steps at the current slider position. */\n readonly visibleStepsCount?: number;\n /** Resolved event-log seq the slider currently anchors to. */\n readonly focusedEventSeq?: number;\n /** Which actor lanes are \"lit\" at the current slider position\n * (e.g. `['user', 'llm', 'tool']`). */\n readonly touched?: readonly string[];\n /** Active edge key (the edge highlighted as \"current\"). */\n readonly activeEdgeKey?: string;\n}\n\n/** Build the full LLM-ready Markdown blob for the current run. */\nexport function buildLLMText(args: BuildLLMTextArgs): string {\n const {\n recorder,\n stepGraph,\n boundaryRollups,\n humanizer,\n appName = 'Chatbot',\n viewState,\n } = args;\n const summary = recorder.selectSummary();\n const log = recorder.selectEventLog();\n\n const sections: string[] = [];\n\n // ── 1. Run Summary ────────────────────────────────────────────\n // Adaptive — rows are only emitted when their value is meaningful.\n // Avoids \"Iterations: 0\" / \"Tool calls: 0\" noise on Sequence-of-\n // LLMCalls runs that don't have ReAct iterations or tools.\n sections.push('# Run Summary\\n');\n sections.push(`- **Status:** ${summary.status}`);\n if (summary.durationMs !== undefined) {\n sections.push(`- **Duration:** ${formatMs(summary.durationMs)}`);\n }\n if (summary.llmCallCount > 0) sections.push(`- **LLM calls:** ${summary.llmCallCount}`);\n if (summary.toolCallCount > 0) sections.push(`- **Tool calls:** ${summary.toolCallCount}`);\n if (summary.iterationCount > 0) sections.push(`- **Iterations:** ${summary.iterationCount}`);\n if (summary.totalTokens.input > 0 || summary.totalTokens.output > 0) {\n sections.push(\n `- **Tokens:** ${summary.totalTokens.input} in / ${summary.totalTokens.output} out`,\n );\n }\n if (summary.totalUsd !== undefined) sections.push(`- **Estimated cost:** $${summary.totalUsd.toFixed(4)}`);\n if (summary.permissionDenials > 0) sections.push(`- **Permission denials:** ${summary.permissionDenials}`);\n if (summary.paused) sections.push(`- **Paused:** yes`);\n\n // ── 1.5. Current View State (debug aid) ──────────────────────\n // Snapshot of slider / focus / drill state at copy time. Helps an\n // LLM reviewer (or human poring over the paste) diagnose\n // \"slider doesn't sync with the chart\" / \"drill is stuck\" /\n // \"edge highlight wrong\" without needing live access to the UI.\n if (viewState) {\n sections.push('\\n# Current View State (at copy time)\\n');\n if (viewState.focusStep !== undefined && viewState.totalSteps !== undefined) {\n sections.push(`- **Slider position:** ${viewState.focusStep + 1} / ${viewState.totalSteps}`);\n }\n if (viewState.isLive !== undefined) {\n sections.push(`- **Live (auto-advancing):** ${viewState.isLive ? 'yes' : 'no'}`);\n }\n if (viewState.mode) sections.push(`- **Mode:** ${viewState.mode}`);\n if (viewState.drillPath && viewState.drillPath.length > 0) {\n sections.push(`- **Drill path:** ${viewState.drillPath.join(' / ')}`);\n }\n if (viewState.currentStep) {\n const cs = viewState.currentStep;\n const parts: string[] = [];\n if (cs.label) parts.push(cs.label);\n if (cs.kind) parts.push(`(\\`${cs.kind}\\`)`);\n if (cs.iterationIndex !== undefined) parts.push(`iter #${cs.iterationIndex}`);\n sections.push(`- **Current step:** ${parts.join(' ')}`);\n if (cs.runtimeStageId) sections.push(` - runtimeStageId: \\`${cs.runtimeStageId}\\``);\n if (cs.subflowPath && cs.subflowPath.length > 1) {\n sections.push(` - subflowPath: ${cs.subflowPath.slice(1).join(' → ')}`);\n }\n }\n if (viewState.visibleStepsCount !== undefined) {\n sections.push(`- **Visible steps:** ${viewState.visibleStepsCount}`);\n }\n if (viewState.focusedEventSeq !== undefined) {\n sections.push(`- **Focused event seq:** ${viewState.focusedEventSeq}`);\n }\n if (viewState.touched && viewState.touched.length > 0) {\n sections.push(`- **Touched actors:** ${viewState.touched.join(', ')}`);\n }\n if (viewState.activeEdgeKey) {\n sections.push(`- **Active edge:** \\`${viewState.activeEdgeKey}\\``);\n }\n }\n\n // ── 2. Per-Boundary Rollups ──────────────────────────────────\n if (boundaryRollups && boundaryRollups.length > 0) {\n sections.push('\\n# Per-Boundary Rollups\\n');\n for (const r of boundaryRollups) {\n const kind = r.primitiveKind ?? 'Boundary';\n sections.push(`## ${r.label} (${kind}) — \\`${r.runtimeStageId}\\``);\n if (r.tokens.input > 0 || r.tokens.output > 0) {\n sections.push(`- Tokens: ${r.tokens.input} in / ${r.tokens.output} out`);\n }\n const counters: string[] = [];\n if (r.llmCalls > 0) counters.push(`LLM calls: ${r.llmCalls}`);\n if (r.toolCalls > 0) counters.push(`Tool calls: ${r.toolCalls}`);\n if (r.iterations > 0) counters.push(`Iterations: ${r.iterations}`);\n if (counters.length > 0) sections.push(`- ${counters.join(' · ')}`);\n sections.push(\n `- Duration: ${r.durationMs !== undefined ? formatMs(r.durationMs) : '(in flight)'}`,\n );\n sections.push('');\n }\n }\n\n // ── 3. Steps (every StepNode with payload) ───────────────────\n if (stepGraph && stepGraph.nodes.length > 0) {\n sections.push('\\n# Steps\\n');\n stepGraph.nodes.forEach((n, i) => {\n sections.push(formatStep(i + 1, n));\n });\n }\n\n // ── 4. Commentary (humanized per-event lines) ────────────────\n if (log.length > 0) {\n sections.push('\\n# Commentary\\n');\n sections.push('```');\n for (const entry of log) {\n const line = humanizer ? humanizer(entry.event) : `[${entry.event.type}]`;\n if (line === null) continue;\n const t = `+${Math.round(entry.runOffsetMs)}ms`.padEnd(10);\n sections.push(`${t} ${line.replace(/\\{\\{appName\\}\\}/g, appName)}`);\n }\n sections.push('```');\n }\n\n return sections.join('\\n');\n}\n\n// ─── Boundary-payload filtering ──────────────────────────────────\n//\n// LLMCall's outputMapper merges the entire scope state into the boundary\n// output, including library-internal accounting fields. For Copy-for-LLM\n// purposes those fields are noise — they're already represented in\n// other sections (Tokens line on the LLM step, Context Injections, etc.)\n// and pasting them inflates the document by ~80% with redundant info.\nconst LIBRARY_INTERNAL_FIELDS = new Set([\n 'systemPromptInjections',\n 'messagesInjections',\n 'toolsInjections',\n 'cumTokensInput',\n 'cumTokensOutput',\n 'cumEstimatedUsd',\n 'costBudgetHit',\n 'iteration',\n]);\n\nfunction compactBoundaryPayload(value: unknown): unknown {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return value;\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (LIBRARY_INTERNAL_FIELDS.has(k)) continue;\n out[k] = v;\n }\n return out;\n}\n\n// ─── Step formatter ──────────────────────────────────────────────\n\nfunction formatStep(index: number, n: StepNode): string {\n const lines: string[] = [];\n const headerSuffix = n.iterationIndex !== undefined ? ` (iter ${n.iterationIndex})` : '';\n const kindLabel = formatKindLabel(n);\n lines.push(`## ${index}. ${n.label} — ${kindLabel}${headerSuffix}`);\n if (n.runtimeStageId) lines.push(`runtimeStageId: \\`${n.runtimeStageId}\\``);\n if (n.subflowPath.length > 1) {\n lines.push(`Path: ${n.subflowPath.slice(1).join(' → ')}`);\n }\n\n const dur = duration(n);\n // Hide 0ms duration on closing markers (`llm → user` is a delivery\n // marker, not a separate execution — duration is naturally 0).\n if (dur !== undefined && dur > 0) lines.push(`Duration: ${formatMs(dur)}`);\n if (n.tokens) lines.push(`Tokens: ${n.tokens.in} in / ${n.tokens.out} out`);\n if (n.llmModel) lines.push(`Model: ${n.llmModel}`);\n if (n.toolName) lines.push(`Tool: \\`${n.toolName}\\``);\n if (n.slotUpdated) lines.push(`Slot updated: \\`${n.slotUpdated}\\``);\n\n // Per-kind payload sections — same set of fields the right-pane\n // NodeDetailPanel renders.\n if (n.entryPayload !== undefined) {\n lines.push('\\n**Boundary input** (inputMapper result):');\n lines.push('```json');\n lines.push(safeJson(compactBoundaryPayload(n.entryPayload)));\n lines.push('```');\n }\n if (n.exitPayload !== undefined) {\n lines.push('\\n**Boundary output** (outputMapper result):');\n lines.push('```json');\n lines.push(safeJson(compactBoundaryPayload(n.exitPayload)));\n lines.push('```');\n }\n if (n.assistantText) {\n const heading =\n n.kind === 'llm->user' ? 'Final answer' : \"LLM's reasoning\";\n lines.push(`\\n**${heading}:**`);\n lines.push('```');\n lines.push(n.assistantText);\n lines.push('```');\n }\n if (n.toolArgs !== undefined) {\n lines.push('\\n**Tool input (args):**');\n lines.push('```json');\n lines.push(safeJson(n.toolArgs));\n lines.push('```');\n }\n if (n.toolResult !== undefined) {\n lines.push('\\n**Tool result sent to LLM:**');\n lines.push('```json');\n lines.push(safeJson(n.toolResult));\n lines.push('```');\n }\n\n // Engineered injections (filtered to non-baseline sources by callers\n // typically — but here we include all so the LLM has full context).\n if (n.injections && n.injections.length > 0) {\n lines.push('\\n**Context injections:**');\n for (const inj of n.injections) {\n const id = inj.sourceId ? `:${inj.sourceId}` : '';\n const role = inj.asRole ? ` (as ${inj.asRole})` : '';\n const summary = inj.contentSummary ? ` — ${inj.contentSummary}` : '';\n lines.push(`- [${inj.slot}] ${inj.source}${id}${role}${summary}`);\n }\n }\n\n lines.push(''); // trailing blank line between steps\n return lines.join('\\n');\n}\n\nfunction formatKindLabel(n: StepNode): string {\n switch (n.kind) {\n case 'subflow':\n return n.primitiveKind ? `${n.primitiveKind} boundary` : 'subflow boundary';\n case 'user->llm':\n return 'user → llm';\n case 'llm->tool':\n return 'llm → tool';\n case 'tool->llm':\n return 'tool → llm';\n case 'llm->user':\n return 'llm → user (final answer)';\n case 'fork-branch':\n return 'parallel branch';\n case 'decision-branch':\n return 'decision branch';\n default:\n return n.kind;\n }\n}\n\nfunction duration(n: StepNode): number | undefined {\n if (typeof n.startOffsetMs === 'number' && typeof n.endOffsetMs === 'number') {\n return n.endOffsetMs - n.startOffsetMs;\n }\n return undefined;\n}\n\nfunction formatMs(ms: number): string {\n if (ms < 1000) return `${Math.round(ms)}ms`;\n if (ms < 10_000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction safeJson(value: unknown): string {\n try {\n const s = JSON.stringify(value, null, 2);\n if (s.length > 4000) {\n return s.slice(0, 4000) + `\\n... (truncated; ${s.length - 4000} chars)`;\n }\n return s;\n } catch {\n return String(value);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,7 @@
1
+ import {
2
+ buildLLMText
3
+ } from "./chunk-UGDBHWTE.js";
4
+ export {
5
+ buildLLMText
6
+ };
7
+ //# sourceMappingURL=copyForLLM-RAWCSUDW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/core.cjs CHANGED
@@ -824,7 +824,14 @@ function selectContextEngineeringInjections(injections) {
824
824
 
825
825
  // src/v2/core/copyForLLM.ts
826
826
  function buildLLMText(args) {
827
- const { recorder, stepGraph, boundaryRollups, humanizer, appName = "Chatbot" } = args;
827
+ const {
828
+ recorder,
829
+ stepGraph,
830
+ boundaryRollups,
831
+ humanizer,
832
+ appName = "Chatbot",
833
+ viewState
834
+ } = args;
828
835
  const summary = recorder.selectSummary();
829
836
  const log = recorder.selectEventLog();
830
837
  const sections = [];
@@ -844,6 +851,43 @@ function buildLLMText(args) {
844
851
  if (summary.totalUsd !== void 0) sections.push(`- **Estimated cost:** $${summary.totalUsd.toFixed(4)}`);
845
852
  if (summary.permissionDenials > 0) sections.push(`- **Permission denials:** ${summary.permissionDenials}`);
846
853
  if (summary.paused) sections.push(`- **Paused:** yes`);
854
+ if (viewState) {
855
+ sections.push("\n# Current View State (at copy time)\n");
856
+ if (viewState.focusStep !== void 0 && viewState.totalSteps !== void 0) {
857
+ sections.push(`- **Slider position:** ${viewState.focusStep + 1} / ${viewState.totalSteps}`);
858
+ }
859
+ if (viewState.isLive !== void 0) {
860
+ sections.push(`- **Live (auto-advancing):** ${viewState.isLive ? "yes" : "no"}`);
861
+ }
862
+ if (viewState.mode) sections.push(`- **Mode:** ${viewState.mode}`);
863
+ if (viewState.drillPath && viewState.drillPath.length > 0) {
864
+ sections.push(`- **Drill path:** ${viewState.drillPath.join(" / ")}`);
865
+ }
866
+ if (viewState.currentStep) {
867
+ const cs = viewState.currentStep;
868
+ const parts = [];
869
+ if (cs.label) parts.push(cs.label);
870
+ if (cs.kind) parts.push(`(\`${cs.kind}\`)`);
871
+ if (cs.iterationIndex !== void 0) parts.push(`iter #${cs.iterationIndex}`);
872
+ sections.push(`- **Current step:** ${parts.join(" ")}`);
873
+ if (cs.runtimeStageId) sections.push(` - runtimeStageId: \`${cs.runtimeStageId}\``);
874
+ if (cs.subflowPath && cs.subflowPath.length > 1) {
875
+ sections.push(` - subflowPath: ${cs.subflowPath.slice(1).join(" \u2192 ")}`);
876
+ }
877
+ }
878
+ if (viewState.visibleStepsCount !== void 0) {
879
+ sections.push(`- **Visible steps:** ${viewState.visibleStepsCount}`);
880
+ }
881
+ if (viewState.focusedEventSeq !== void 0) {
882
+ sections.push(`- **Focused event seq:** ${viewState.focusedEventSeq}`);
883
+ }
884
+ if (viewState.touched && viewState.touched.length > 0) {
885
+ sections.push(`- **Touched actors:** ${viewState.touched.join(", ")}`);
886
+ }
887
+ if (viewState.activeEdgeKey) {
888
+ sections.push(`- **Active edge:** \`${viewState.activeEdgeKey}\``);
889
+ }
890
+ }
847
891
  if (boundaryRollups && boundaryRollups.length > 0) {
848
892
  sections.push("\n# Per-Boundary Rollups\n");
849
893
  for (const r of boundaryRollups) {