agentfootprint-lens 0.13.2 → 0.14.1
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/chunk-BJFB2MQC.js +186 -0
- package/dist/chunk-BJFB2MQC.js.map +1 -0
- package/dist/chunk-SCGY3UEL.js +165 -0
- package/dist/chunk-SCGY3UEL.js.map +1 -0
- package/dist/chunk-UGDBHWTE.js +230 -0
- package/dist/chunk-UGDBHWTE.js.map +1 -0
- package/dist/chunk-WVLJ356X.js +809 -0
- package/dist/chunk-WVLJ356X.js.map +1 -0
- package/dist/chunk-ZHG36QPA.js +165 -0
- package/dist/chunk-ZHG36QPA.js.map +1 -0
- package/dist/copyForLLM-6FZVBNO5.js +7 -0
- package/dist/copyForLLM-6FZVBNO5.js.map +1 -0
- package/dist/copyForLLM-BSX6JXTL.js +7 -0
- package/dist/copyForLLM-BSX6JXTL.js.map +1 -0
- package/dist/copyForLLM-CAOTBMG5.js +7 -0
- package/dist/copyForLLM-CAOTBMG5.js.map +1 -0
- package/dist/copyForLLM-RAWCSUDW.js +7 -0
- package/dist/copyForLLM-RAWCSUDW.js.map +1 -0
- package/dist/core.cjs +228 -0
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +87 -2
- package/dist/core.d.ts +87 -2
- package/dist/core.js +5 -1
- package/dist/index.cjs +835 -150
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -2
- package/dist/index.d.ts +48 -2
- package/dist/index.js +589 -147
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// src/v2/core/copyForLLM.ts
|
|
2
|
+
function buildLLMText(args) {
|
|
3
|
+
const { recorder, stepGraph, boundaryRollups, humanizer, appName = "Chatbot" } = args;
|
|
4
|
+
const summary = recorder.selectSummary();
|
|
5
|
+
const log = recorder.selectEventLog();
|
|
6
|
+
const sections = [];
|
|
7
|
+
sections.push("# Run Summary\n");
|
|
8
|
+
sections.push(`- **Status:** ${summary.status}`);
|
|
9
|
+
if (summary.durationMs !== void 0) {
|
|
10
|
+
sections.push(`- **Duration:** ${formatMs(summary.durationMs)}`);
|
|
11
|
+
}
|
|
12
|
+
if (summary.llmCallCount > 0) sections.push(`- **LLM calls:** ${summary.llmCallCount}`);
|
|
13
|
+
if (summary.toolCallCount > 0) sections.push(`- **Tool calls:** ${summary.toolCallCount}`);
|
|
14
|
+
if (summary.iterationCount > 0) sections.push(`- **Iterations:** ${summary.iterationCount}`);
|
|
15
|
+
if (summary.totalTokens.input > 0 || summary.totalTokens.output > 0) {
|
|
16
|
+
sections.push(
|
|
17
|
+
`- **Tokens:** ${summary.totalTokens.input} in / ${summary.totalTokens.output} out`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
if (summary.totalUsd !== void 0) sections.push(`- **Estimated cost:** $${summary.totalUsd.toFixed(4)}`);
|
|
21
|
+
if (summary.permissionDenials > 0) sections.push(`- **Permission denials:** ${summary.permissionDenials}`);
|
|
22
|
+
if (summary.paused) sections.push(`- **Paused:** yes`);
|
|
23
|
+
if (boundaryRollups && boundaryRollups.length > 0) {
|
|
24
|
+
sections.push("\n# Per-Boundary Rollups\n");
|
|
25
|
+
for (const r of boundaryRollups) {
|
|
26
|
+
const kind = r.primitiveKind ?? "Boundary";
|
|
27
|
+
sections.push(`## ${r.label} (${kind}) \u2014 \`${r.runtimeStageId}\``);
|
|
28
|
+
if (r.tokens.input > 0 || r.tokens.output > 0) {
|
|
29
|
+
sections.push(`- Tokens: ${r.tokens.input} in / ${r.tokens.output} out`);
|
|
30
|
+
}
|
|
31
|
+
const counters = [];
|
|
32
|
+
if (r.llmCalls > 0) counters.push(`LLM calls: ${r.llmCalls}`);
|
|
33
|
+
if (r.toolCalls > 0) counters.push(`Tool calls: ${r.toolCalls}`);
|
|
34
|
+
if (r.iterations > 0) counters.push(`Iterations: ${r.iterations}`);
|
|
35
|
+
if (counters.length > 0) sections.push(`- ${counters.join(" \xB7 ")}`);
|
|
36
|
+
sections.push(
|
|
37
|
+
`- Duration: ${r.durationMs !== void 0 ? formatMs(r.durationMs) : "(in flight)"}`
|
|
38
|
+
);
|
|
39
|
+
sections.push("");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (stepGraph && stepGraph.nodes.length > 0) {
|
|
43
|
+
sections.push("\n# Steps\n");
|
|
44
|
+
stepGraph.nodes.forEach((n, i) => {
|
|
45
|
+
sections.push(formatStep(i + 1, n));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (log.length > 0) {
|
|
49
|
+
sections.push("\n# Commentary\n");
|
|
50
|
+
sections.push("```");
|
|
51
|
+
for (const entry of log) {
|
|
52
|
+
const line = humanizer ? humanizer(entry.event) : `[${entry.event.type}]`;
|
|
53
|
+
if (line === null) continue;
|
|
54
|
+
const t = `+${Math.round(entry.runOffsetMs)}ms`.padEnd(10);
|
|
55
|
+
sections.push(`${t} ${line.replace(/\{\{appName\}\}/g, appName)}`);
|
|
56
|
+
}
|
|
57
|
+
sections.push("```");
|
|
58
|
+
}
|
|
59
|
+
return sections.join("\n");
|
|
60
|
+
}
|
|
61
|
+
var LIBRARY_INTERNAL_FIELDS = /* @__PURE__ */ new Set([
|
|
62
|
+
"systemPromptInjections",
|
|
63
|
+
"messagesInjections",
|
|
64
|
+
"toolsInjections",
|
|
65
|
+
"cumTokensInput",
|
|
66
|
+
"cumTokensOutput",
|
|
67
|
+
"cumEstimatedUsd",
|
|
68
|
+
"costBudgetHit",
|
|
69
|
+
"iteration"
|
|
70
|
+
]);
|
|
71
|
+
function compactBoundaryPayload(value) {
|
|
72
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return value;
|
|
73
|
+
const out = {};
|
|
74
|
+
for (const [k, v] of Object.entries(value)) {
|
|
75
|
+
if (LIBRARY_INTERNAL_FIELDS.has(k)) continue;
|
|
76
|
+
out[k] = v;
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
function formatStep(index, n) {
|
|
81
|
+
const lines = [];
|
|
82
|
+
const headerSuffix = n.iterationIndex !== void 0 ? ` (iter ${n.iterationIndex})` : "";
|
|
83
|
+
const kindLabel = formatKindLabel(n);
|
|
84
|
+
lines.push(`## ${index}. ${n.label} \u2014 ${kindLabel}${headerSuffix}`);
|
|
85
|
+
if (n.runtimeStageId) lines.push(`runtimeStageId: \`${n.runtimeStageId}\``);
|
|
86
|
+
if (n.subflowPath.length > 1) {
|
|
87
|
+
lines.push(`Path: ${n.subflowPath.slice(1).join(" \u2192 ")}`);
|
|
88
|
+
}
|
|
89
|
+
const dur = duration(n);
|
|
90
|
+
if (dur !== void 0 && dur > 0) lines.push(`Duration: ${formatMs(dur)}`);
|
|
91
|
+
if (n.tokens) lines.push(`Tokens: ${n.tokens.in} in / ${n.tokens.out} out`);
|
|
92
|
+
if (n.llmModel) lines.push(`Model: ${n.llmModel}`);
|
|
93
|
+
if (n.toolName) lines.push(`Tool: \`${n.toolName}\``);
|
|
94
|
+
if (n.slotUpdated) lines.push(`Slot updated: \`${n.slotUpdated}\``);
|
|
95
|
+
if (n.entryPayload !== void 0) {
|
|
96
|
+
lines.push("\n**Boundary input** (inputMapper result):");
|
|
97
|
+
lines.push("```json");
|
|
98
|
+
lines.push(safeJson(compactBoundaryPayload(n.entryPayload)));
|
|
99
|
+
lines.push("```");
|
|
100
|
+
}
|
|
101
|
+
if (n.exitPayload !== void 0) {
|
|
102
|
+
lines.push("\n**Boundary output** (outputMapper result):");
|
|
103
|
+
lines.push("```json");
|
|
104
|
+
lines.push(safeJson(compactBoundaryPayload(n.exitPayload)));
|
|
105
|
+
lines.push("```");
|
|
106
|
+
}
|
|
107
|
+
if (n.assistantText) {
|
|
108
|
+
const heading = n.kind === "llm->user" ? "Final answer" : "LLM's reasoning";
|
|
109
|
+
lines.push(`
|
|
110
|
+
**${heading}:**`);
|
|
111
|
+
lines.push("```");
|
|
112
|
+
lines.push(n.assistantText);
|
|
113
|
+
lines.push("```");
|
|
114
|
+
}
|
|
115
|
+
if (n.toolArgs !== void 0) {
|
|
116
|
+
lines.push("\n**Tool input (args):**");
|
|
117
|
+
lines.push("```json");
|
|
118
|
+
lines.push(safeJson(n.toolArgs));
|
|
119
|
+
lines.push("```");
|
|
120
|
+
}
|
|
121
|
+
if (n.toolResult !== void 0) {
|
|
122
|
+
lines.push("\n**Tool result sent to LLM:**");
|
|
123
|
+
lines.push("```json");
|
|
124
|
+
lines.push(safeJson(n.toolResult));
|
|
125
|
+
lines.push("```");
|
|
126
|
+
}
|
|
127
|
+
if (n.injections && n.injections.length > 0) {
|
|
128
|
+
lines.push("\n**Context injections:**");
|
|
129
|
+
for (const inj of n.injections) {
|
|
130
|
+
const id = inj.sourceId ? `:${inj.sourceId}` : "";
|
|
131
|
+
const role = inj.asRole ? ` (as ${inj.asRole})` : "";
|
|
132
|
+
const summary = inj.contentSummary ? ` \u2014 ${inj.contentSummary}` : "";
|
|
133
|
+
lines.push(`- [${inj.slot}] ${inj.source}${id}${role}${summary}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
lines.push("");
|
|
137
|
+
return lines.join("\n");
|
|
138
|
+
}
|
|
139
|
+
function formatKindLabel(n) {
|
|
140
|
+
switch (n.kind) {
|
|
141
|
+
case "subflow":
|
|
142
|
+
return n.primitiveKind ? `${n.primitiveKind} boundary` : "subflow boundary";
|
|
143
|
+
case "user->llm":
|
|
144
|
+
return "user \u2192 llm";
|
|
145
|
+
case "llm->tool":
|
|
146
|
+
return "llm \u2192 tool";
|
|
147
|
+
case "tool->llm":
|
|
148
|
+
return "tool \u2192 llm";
|
|
149
|
+
case "llm->user":
|
|
150
|
+
return "llm \u2192 user (final answer)";
|
|
151
|
+
case "fork-branch":
|
|
152
|
+
return "parallel branch";
|
|
153
|
+
case "decision-branch":
|
|
154
|
+
return "decision branch";
|
|
155
|
+
default:
|
|
156
|
+
return n.kind;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function duration(n) {
|
|
160
|
+
if (typeof n.startOffsetMs === "number" && typeof n.endOffsetMs === "number") {
|
|
161
|
+
return n.endOffsetMs - n.startOffsetMs;
|
|
162
|
+
}
|
|
163
|
+
return void 0;
|
|
164
|
+
}
|
|
165
|
+
function formatMs(ms) {
|
|
166
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
167
|
+
if (ms < 1e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
168
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
169
|
+
}
|
|
170
|
+
function safeJson(value) {
|
|
171
|
+
try {
|
|
172
|
+
const s = JSON.stringify(value, null, 2);
|
|
173
|
+
if (s.length > 4e3) {
|
|
174
|
+
return s.slice(0, 4e3) + `
|
|
175
|
+
... (truncated; ${s.length - 4e3} chars)`;
|
|
176
|
+
}
|
|
177
|
+
return s;
|
|
178
|
+
} catch {
|
|
179
|
+
return String(value);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export {
|
|
184
|
+
buildLLMText
|
|
185
|
+
};
|
|
186
|
+
//# sourceMappingURL=chunk-BJFB2MQC.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}\n\n/** Build the full LLM-ready Markdown blob for the current run. */\nexport function buildLLMText(args: BuildLLMTextArgs): string {\n const { recorder, stepGraph, boundaryRollups, humanizer, appName = 'Chatbot' } = 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 // ── 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,165 @@
|
|
|
1
|
+
// src/v2/core/copyForLLM.ts
|
|
2
|
+
function buildLLMText(args) {
|
|
3
|
+
const { recorder, stepGraph, boundaryRollups, humanizer, appName = "Chatbot" } = args;
|
|
4
|
+
const summary = recorder.selectSummary();
|
|
5
|
+
const log = recorder.selectEventLog();
|
|
6
|
+
const sections = [];
|
|
7
|
+
sections.push("# Run Summary\n");
|
|
8
|
+
sections.push(`- **Status:** ${summary.status}`);
|
|
9
|
+
if (summary.durationMs !== void 0) {
|
|
10
|
+
sections.push(`- **Duration:** ${formatMs(summary.durationMs)}`);
|
|
11
|
+
}
|
|
12
|
+
sections.push(`- **LLM calls:** ${summary.llmCallCount}`);
|
|
13
|
+
sections.push(`- **Tool calls:** ${summary.toolCallCount}`);
|
|
14
|
+
sections.push(`- **Iterations:** ${summary.iterationCount}`);
|
|
15
|
+
sections.push(
|
|
16
|
+
`- **Tokens:** ${summary.totalTokens.input} in / ${summary.totalTokens.output} out`
|
|
17
|
+
);
|
|
18
|
+
if (summary.totalUsd !== void 0) sections.push(`- **Estimated cost:** $${summary.totalUsd.toFixed(4)}`);
|
|
19
|
+
if (summary.permissionDenials > 0) sections.push(`- **Permission denials:** ${summary.permissionDenials}`);
|
|
20
|
+
if (summary.paused) sections.push(`- **Paused:** yes`);
|
|
21
|
+
if (boundaryRollups && boundaryRollups.length > 0) {
|
|
22
|
+
sections.push("\n# Per-Boundary Rollups\n");
|
|
23
|
+
sections.push(
|
|
24
|
+
"One block per primitive boundary (Agent / LLMCall / Sequence / etc.). Use `runtimeStageId` to correlate with the Steps section below.\n"
|
|
25
|
+
);
|
|
26
|
+
for (const r of boundaryRollups) {
|
|
27
|
+
const kind = r.primitiveKind ?? "Boundary";
|
|
28
|
+
sections.push(`## ${r.label} (${kind}) \u2014 \`${r.runtimeStageId}\``);
|
|
29
|
+
sections.push(`- Tokens: ${r.tokens.input} in / ${r.tokens.output} out`);
|
|
30
|
+
sections.push(`- LLM calls: ${r.llmCalls} \xB7 Tool calls: ${r.toolCalls} \xB7 Iterations: ${r.iterations}`);
|
|
31
|
+
if (r.durationMs !== void 0) sections.push(`- Duration: ${formatMs(r.durationMs)}`);
|
|
32
|
+
else sections.push(`- Duration: (in flight)`);
|
|
33
|
+
sections.push("");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (stepGraph && stepGraph.nodes.length > 0) {
|
|
37
|
+
sections.push("\n# Steps\n");
|
|
38
|
+
sections.push(
|
|
39
|
+
"One numbered entry per visible scrubbable step. Boundary nodes carry inputMapper/outputMapper payloads; ReAct kinds carry the LLM reasoning, tool args, and tool result that crossed the bracket.\n"
|
|
40
|
+
);
|
|
41
|
+
stepGraph.nodes.forEach((n, i) => {
|
|
42
|
+
sections.push(formatStep(i + 1, n));
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
if (log.length > 0) {
|
|
46
|
+
sections.push("\n# Commentary\n");
|
|
47
|
+
sections.push("One line per emitted event (humanized). Time offsets are ms from run start.\n");
|
|
48
|
+
sections.push("```");
|
|
49
|
+
for (const entry of log) {
|
|
50
|
+
const line = humanizer ? humanizer(entry.event) : `[${entry.event.type}]`;
|
|
51
|
+
if (line === null) continue;
|
|
52
|
+
const t = `+${Math.round(entry.runOffsetMs)}ms`.padEnd(10);
|
|
53
|
+
sections.push(`${t} ${line.replace(/\{\{appName\}\}/g, appName)}`);
|
|
54
|
+
}
|
|
55
|
+
sections.push("```");
|
|
56
|
+
}
|
|
57
|
+
return sections.join("\n");
|
|
58
|
+
}
|
|
59
|
+
function formatStep(index, n) {
|
|
60
|
+
const lines = [];
|
|
61
|
+
const headerSuffix = n.iterationIndex !== void 0 ? ` (iter ${n.iterationIndex})` : "";
|
|
62
|
+
const kindLabel = formatKindLabel(n);
|
|
63
|
+
lines.push(`## ${index}. ${n.label} \u2014 ${kindLabel}${headerSuffix}`);
|
|
64
|
+
if (n.runtimeStageId) lines.push(`runtimeStageId: \`${n.runtimeStageId}\``);
|
|
65
|
+
if (n.subflowPath.length > 1) {
|
|
66
|
+
lines.push(`Path: ${n.subflowPath.slice(1).join(" \u2192 ")}`);
|
|
67
|
+
}
|
|
68
|
+
const dur = duration(n);
|
|
69
|
+
if (dur !== void 0) lines.push(`Duration: ${formatMs(dur)}`);
|
|
70
|
+
if (n.tokens) lines.push(`Tokens: ${n.tokens.input} in / ${n.tokens.output} out`);
|
|
71
|
+
if (n.llmModel) lines.push(`Model: ${n.llmModel}`);
|
|
72
|
+
if (n.toolName) lines.push(`Tool: \`${n.toolName}\``);
|
|
73
|
+
if (n.slotUpdated) lines.push(`Slot updated: \`${n.slotUpdated}\``);
|
|
74
|
+
if (n.entryPayload !== void 0) {
|
|
75
|
+
lines.push("\n**Boundary input** (inputMapper result):");
|
|
76
|
+
lines.push("```json");
|
|
77
|
+
lines.push(safeJson(n.entryPayload));
|
|
78
|
+
lines.push("```");
|
|
79
|
+
}
|
|
80
|
+
if (n.exitPayload !== void 0) {
|
|
81
|
+
lines.push("\n**Boundary output** (outputMapper result):");
|
|
82
|
+
lines.push("```json");
|
|
83
|
+
lines.push(safeJson(n.exitPayload));
|
|
84
|
+
lines.push("```");
|
|
85
|
+
}
|
|
86
|
+
if (n.assistantText) {
|
|
87
|
+
const heading = n.kind === "llm->user" ? "Final answer" : "LLM's reasoning";
|
|
88
|
+
lines.push(`
|
|
89
|
+
**${heading}:**`);
|
|
90
|
+
lines.push("```");
|
|
91
|
+
lines.push(n.assistantText);
|
|
92
|
+
lines.push("```");
|
|
93
|
+
}
|
|
94
|
+
if (n.toolArgs !== void 0) {
|
|
95
|
+
lines.push("\n**Tool input (args):**");
|
|
96
|
+
lines.push("```json");
|
|
97
|
+
lines.push(safeJson(n.toolArgs));
|
|
98
|
+
lines.push("```");
|
|
99
|
+
}
|
|
100
|
+
if (n.toolResult !== void 0) {
|
|
101
|
+
lines.push("\n**Tool result sent to LLM:**");
|
|
102
|
+
lines.push("```json");
|
|
103
|
+
lines.push(safeJson(n.toolResult));
|
|
104
|
+
lines.push("```");
|
|
105
|
+
}
|
|
106
|
+
if (n.injections && n.injections.length > 0) {
|
|
107
|
+
lines.push("\n**Context injections:**");
|
|
108
|
+
for (const inj of n.injections) {
|
|
109
|
+
const id = inj.sourceId ? `:${inj.sourceId}` : "";
|
|
110
|
+
const role = inj.asRole ? ` (as ${inj.asRole})` : "";
|
|
111
|
+
const summary = inj.contentSummary ? ` \u2014 ${inj.contentSummary}` : "";
|
|
112
|
+
lines.push(`- [${inj.slot}] ${inj.source}${id}${role}${summary}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
lines.push("");
|
|
116
|
+
return lines.join("\n");
|
|
117
|
+
}
|
|
118
|
+
function formatKindLabel(n) {
|
|
119
|
+
switch (n.kind) {
|
|
120
|
+
case "subflow":
|
|
121
|
+
return n.primitiveKind ? `${n.primitiveKind} boundary` : "subflow boundary";
|
|
122
|
+
case "user->llm":
|
|
123
|
+
return "user \u2192 llm";
|
|
124
|
+
case "llm->tool":
|
|
125
|
+
return "llm \u2192 tool";
|
|
126
|
+
case "tool->llm":
|
|
127
|
+
return "tool \u2192 llm";
|
|
128
|
+
case "llm->user":
|
|
129
|
+
return "llm \u2192 user (final answer)";
|
|
130
|
+
case "fork-branch":
|
|
131
|
+
return "parallel branch";
|
|
132
|
+
case "decision-branch":
|
|
133
|
+
return "decision branch";
|
|
134
|
+
default:
|
|
135
|
+
return n.kind;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function duration(n) {
|
|
139
|
+
if (typeof n.startOffsetMs === "number" && typeof n.endOffsetMs === "number") {
|
|
140
|
+
return n.endOffsetMs - n.startOffsetMs;
|
|
141
|
+
}
|
|
142
|
+
return void 0;
|
|
143
|
+
}
|
|
144
|
+
function formatMs(ms) {
|
|
145
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
146
|
+
if (ms < 1e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
147
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
148
|
+
}
|
|
149
|
+
function safeJson(value) {
|
|
150
|
+
try {
|
|
151
|
+
const s = JSON.stringify(value, null, 2);
|
|
152
|
+
if (s.length > 4e3) {
|
|
153
|
+
return s.slice(0, 4e3) + `
|
|
154
|
+
... (truncated; ${s.length - 4e3} chars)`;
|
|
155
|
+
}
|
|
156
|
+
return s;
|
|
157
|
+
} catch {
|
|
158
|
+
return String(value);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export {
|
|
163
|
+
buildLLMText
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=chunk-SCGY3UEL.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}\n\n/** Build the full LLM-ready Markdown blob for the current run. */\nexport function buildLLMText(args: BuildLLMTextArgs): string {\n const { recorder, stepGraph, boundaryRollups, humanizer, appName = 'Chatbot' } = args;\n const summary = recorder.selectSummary();\n const log = recorder.selectEventLog();\n\n const sections: string[] = [];\n\n // ── 1. Run Summary ────────────────────────────────────────────\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 sections.push(`- **LLM calls:** ${summary.llmCallCount}`);\n sections.push(`- **Tool calls:** ${summary.toolCallCount}`);\n sections.push(`- **Iterations:** ${summary.iterationCount}`);\n sections.push(\n `- **Tokens:** ${summary.totalTokens.input} in / ${summary.totalTokens.output} out`,\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 // ── 2. Per-Boundary Rollups ──────────────────────────────────\n if (boundaryRollups && boundaryRollups.length > 0) {\n sections.push('\\n# Per-Boundary Rollups\\n');\n sections.push(\n 'One block per primitive boundary (Agent / LLMCall / Sequence / etc.). Use `runtimeStageId` to correlate with the Steps section below.\\n',\n );\n for (const r of boundaryRollups) {\n const kind = r.primitiveKind ?? 'Boundary';\n sections.push(`## ${r.label} (${kind}) — \\`${r.runtimeStageId}\\``);\n sections.push(`- Tokens: ${r.tokens.input} in / ${r.tokens.output} out`);\n sections.push(`- LLM calls: ${r.llmCalls} · Tool calls: ${r.toolCalls} · Iterations: ${r.iterations}`);\n if (r.durationMs !== undefined) sections.push(`- Duration: ${formatMs(r.durationMs)}`);\n else sections.push(`- Duration: (in flight)`);\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 sections.push(\n 'One numbered entry per visible scrubbable step. Boundary nodes carry inputMapper/outputMapper payloads; ReAct kinds carry the LLM reasoning, tool args, and tool result that crossed the bracket.\\n',\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('One line per emitted event (humanized). Time offsets are ms from run start.\\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// ─── 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 if (dur !== undefined) lines.push(`Duration: ${formatMs(dur)}`);\n if (n.tokens) lines.push(`Tokens: ${n.tokens.input} in / ${n.tokens.output} 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(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(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,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
|