agent-inspect 1.8.0 → 2.0.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +146 -23
  3. package/docs/ADAPTER-CONFORMANCE.md +1 -1
  4. package/docs/ADAPTERS.md +41 -6
  5. package/docs/API.md +123 -36
  6. package/docs/CLI.md +75 -11
  7. package/docs/EXPORTS.md +1 -1
  8. package/docs/GETTING-STARTED.md +72 -16
  9. package/docs/KNOWN-ISSUES.md +8 -3
  10. package/docs/LIMITATIONS.md +6 -6
  11. package/docs/LOG-TO-TREE-QUICKSTART.md +1 -2
  12. package/docs/MIGRATION.md +67 -0
  13. package/docs/SCHEMA.md +29 -12
  14. package/package.json +2 -2
  15. package/packages/cli/dist/index.cjs +7604 -7660
  16. package/packages/cli/dist/index.cjs.map +1 -1
  17. package/packages/cli/dist/index.mjs +7604 -7660
  18. package/packages/cli/dist/index.mjs.map +1 -1
  19. package/packages/core/dist/advanced.cjs +2047 -26
  20. package/packages/core/dist/advanced.cjs.map +1 -1
  21. package/packages/core/dist/advanced.d.cts +346 -196
  22. package/packages/core/dist/advanced.d.ts +346 -196
  23. package/packages/core/dist/advanced.mjs +628 -5
  24. package/packages/core/dist/advanced.mjs.map +1 -1
  25. package/packages/core/dist/checks.d.cts +1 -1
  26. package/packages/core/dist/checks.d.ts +1 -1
  27. package/packages/core/dist/chunk-2ZXEMWGK.mjs +549 -0
  28. package/packages/core/dist/chunk-2ZXEMWGK.mjs.map +1 -0
  29. package/packages/core/dist/{chunk-57S5D6HR.mjs → chunk-4JVGFNQH.mjs} +50 -6
  30. package/packages/core/dist/chunk-4JVGFNQH.mjs.map +1 -0
  31. package/packages/core/dist/{chunk-6QSLZCBJ.mjs → chunk-A4V2H3YU.mjs} +329 -163
  32. package/packages/core/dist/chunk-A4V2H3YU.mjs.map +1 -0
  33. package/packages/core/dist/{chunk-74XZ6N7Q.mjs → chunk-IZBJAZGF.mjs} +12 -4
  34. package/packages/core/dist/chunk-IZBJAZGF.mjs.map +1 -0
  35. package/packages/core/dist/{chunk-VTIB5MDK.mjs → chunk-NQZPZ2FN.mjs} +15 -10
  36. package/packages/core/dist/chunk-NQZPZ2FN.mjs.map +1 -0
  37. package/packages/core/dist/{chunk-TZISEVLQ.mjs → chunk-XUNJMAPD.mjs} +3 -3
  38. package/packages/core/dist/{chunk-TZISEVLQ.mjs.map → chunk-XUNJMAPD.mjs.map} +1 -1
  39. package/packages/core/dist/context-CSKnzpXR.d.cts +177 -0
  40. package/packages/core/dist/context-yv2VSDQF.d.ts +177 -0
  41. package/packages/core/dist/diff.d.cts +2 -2
  42. package/packages/core/dist/diff.d.ts +2 -2
  43. package/packages/core/dist/diff.mjs +473 -3
  44. package/packages/core/dist/diff.mjs.map +1 -1
  45. package/packages/core/dist/exporters.cjs +691 -0
  46. package/packages/core/dist/exporters.cjs.map +1 -1
  47. package/packages/core/dist/exporters.d.cts +24 -3
  48. package/packages/core/dist/exporters.d.ts +24 -3
  49. package/packages/core/dist/exporters.mjs +1113 -3
  50. package/packages/core/dist/exporters.mjs.map +1 -1
  51. package/packages/core/dist/index.cjs +1385 -8022
  52. package/packages/core/dist/index.cjs.map +1 -1
  53. package/packages/core/dist/index.d.cts +8 -313
  54. package/packages/core/dist/index.d.ts +8 -313
  55. package/packages/core/dist/index.mjs +18 -1331
  56. package/packages/core/dist/index.mjs.map +1 -1
  57. package/packages/core/dist/{log-config-DanPV3P9.d.cts → log-config-8aE5Kxtr.d.cts} +1 -1
  58. package/packages/core/dist/{log-config-BPHS4Sds.d.ts → log-config-DVimQJho.d.ts} +1 -1
  59. package/packages/core/dist/logs.d.cts +2 -2
  60. package/packages/core/dist/logs.d.ts +2 -2
  61. package/packages/core/dist/logs.mjs +785 -2
  62. package/packages/core/dist/logs.mjs.map +1 -1
  63. package/packages/core/dist/{persisted-inspect-event-Cw7TeYGr.d.ts → persisted-inspect-event-D-WpXeZX.d.ts} +14 -5
  64. package/packages/core/dist/{persisted-inspect-event-DHPfzUd8.d.cts → persisted-inspect-event-DHcHPUKv.d.cts} +14 -5
  65. package/packages/core/dist/persisted.cjs +11 -1
  66. package/packages/core/dist/persisted.cjs.map +1 -1
  67. package/packages/core/dist/persisted.d.cts +4 -4
  68. package/packages/core/dist/persisted.d.ts +4 -4
  69. package/packages/core/dist/persisted.mjs +150 -3
  70. package/packages/core/dist/persisted.mjs.map +1 -1
  71. package/packages/core/dist/readers.cjs +27 -10
  72. package/packages/core/dist/readers.cjs.map +1 -1
  73. package/packages/core/dist/readers.d.cts +1 -1
  74. package/packages/core/dist/readers.d.ts +1 -1
  75. package/packages/core/dist/readers.mjs +1580 -4
  76. package/packages/core/dist/readers.mjs.map +1 -1
  77. package/packages/core/dist/{types-Ap9uMdx_.d.ts → types-D-Y1kOU-.d.ts} +2 -2
  78. package/packages/core/dist/{types-B2-BU5CS.d.cts → types-DgMN3qow.d.cts} +2 -2
  79. package/packages/core/dist/writers.cjs +49 -3
  80. package/packages/core/dist/writers.cjs.map +1 -1
  81. package/packages/core/dist/writers.d.cts +1 -1
  82. package/packages/core/dist/writers.d.ts +1 -1
  83. package/packages/core/dist/writers.mjs +341 -4
  84. package/packages/core/dist/writers.mjs.map +1 -1
  85. package/packages/core/dist/chunk-57S5D6HR.mjs.map +0 -1
  86. package/packages/core/dist/chunk-6QSLZCBJ.mjs.map +0 -1
  87. package/packages/core/dist/chunk-6SZPTECC.mjs +0 -342
  88. package/packages/core/dist/chunk-6SZPTECC.mjs.map +0 -1
  89. package/packages/core/dist/chunk-74XZ6N7Q.mjs.map +0 -1
  90. package/packages/core/dist/chunk-HR7G62IE.mjs +0 -785
  91. package/packages/core/dist/chunk-HR7G62IE.mjs.map +0 -1
  92. package/packages/core/dist/chunk-TFLPUZ56.mjs +0 -1571
  93. package/packages/core/dist/chunk-TFLPUZ56.mjs.map +0 -1
  94. package/packages/core/dist/chunk-U2BGPESY.mjs +0 -150
  95. package/packages/core/dist/chunk-U2BGPESY.mjs.map +0 -1
  96. package/packages/core/dist/chunk-VTIB5MDK.mjs.map +0 -1
  97. package/packages/core/dist/chunk-Y56BPA3B.mjs +0 -990
  98. package/packages/core/dist/chunk-Y56BPA3B.mjs.map +0 -1
  99. package/packages/core/dist/chunk-YWAOOXLR.mjs +0 -475
  100. package/packages/core/dist/chunk-YWAOOXLR.mjs.map +0 -1
@@ -1,1326 +1,13 @@
1
- import { getCurrentContext, getCurrentDepth, getParentStepId, getTraceSafetyFromContext, runWithStepContext, runWithContext, printStepStart, printStepComplete, printError, printFailedAt, printRunStart, printRunComplete } from './chunk-6QSLZCBJ.mjs';
2
- export { MAX_TERMINAL_DEPTH, MAX_TERMINAL_NAME_LENGTH, TERMINAL_INDENT, createInspector, createInspectorRuntime, formatTerminalName, getCurrentContext, getCurrentCorrelationMetadata, getCurrentDepth, getCurrentRunId, getCurrentRunName, getCurrentStepId, getIndent, getParentStepId, getTraceDirFromContext, getTraceSafetyFromContext, hasActiveContext, isSilentContext, printError, printFailedAt, printRunComplete, printRunStart, printStepComplete, printStepStart, renderErrorLine, renderRunSummary, renderStepLine, runWithContext, runWithStepContext } from './chunk-6QSLZCBJ.mjs';
3
- export { inspectEventToPersistedInspectEvent, inspectEventsToPersistedInspectEvents } from './chunk-U2BGPESY.mjs';
4
- export { DEFAULT_LOG_INGEST_CONFIG, EventNormalizer, JsonLogParser, LiveLogAccumulator, Log4jsParser, loadLogIngestConfig, matchMapping, mergeLogIngestConfig, parseLogLine, parseLogsToTrees, renderRunTree, renderRunTrees, wildcardMatch } from './chunk-HR7G62IE.mjs';
5
- import { redactTraceEventsForReport, exportMarkdown, exportHtml, manualTraceEventsToRunTree, redactRunTreeForExport } from './chunk-Y56BPA3B.mjs';
6
- export { EXPORT_PAYLOAD_VERSION, exportHtml, exportMarkdown, exportOpenInference, exportOtlpJson, exportRunTree, manualTraceEventsToRunTree, mergeExportDefaults, redactRunTreeForExport, validateExport, validateExportContent } from './chunk-Y56BPA3B.mjs';
7
- export { diffRuns, diffTraceEvents, manualTraceEventsToComparableRun, renderRunDiff } from './chunk-YWAOOXLR.mjs';
1
+ import { getCurrentContext, getCurrentDepth, getParentStepId, getTraceSafetyFromContext, runWithStepContext, printStepStart, printStepComplete, printError, printFailedAt, inspectRun } from './chunk-A4V2H3YU.mjs';
2
+ export { createInspector, getCurrentCorrelationMetadata, inspectRun, maybeInspectRun } from './chunk-A4V2H3YU.mjs';
8
3
  import './chunk-BT7CATSD.mjs';
9
- import { escapeMarkdown, escapeHtml } from './chunk-HY7H3CQM.mjs';
10
- export { compactAttributes, escapeHtml, escapeMarkdown, flattenTree, safeString, stableJson, summarizeTree } from './chunk-HY7H3CQM.mjs';
11
- export { bufferedFileWriter, compositeWriter, fileWriter, memoryWriter, nullWriter } from './chunk-6SZPTECC.mjs';
12
- import { readTraceEventsFromFile, resolveTraceSafetyOptions, prepareTraceEventForDisk, writeTraceEvent, initializeTraceFile } from './chunk-57S5D6HR.mjs';
13
- export { DEFAULT_MAX_EVENT_BYTES, DEFAULT_MAX_METADATA_VALUE_LENGTH, DEFAULT_MAX_PREVIEW_LENGTH, getRunIdFromTraceFileName, initializeTraceFile, listTraceFiles, prepareMetadataForDisk, prepareTraceEventForDisk, readTraceEvents, readTraceFile, resolveTraceSafetyOptions, serializeEvent, validateEvent, writeTraceEvent } from './chunk-57S5D6HR.mjs';
14
- export { resolveRedactionProfile } from './chunk-EDTQHZPM.mjs';
15
- export { DEFAULT_REDACT_KEYS, Redactor } from './chunk-VU6O5QAH.mjs';
16
- export { DEFAULT_TRACE_READERS, TraceReadError, agentInspectJsonlReader, detectTraceFormat, openTrace, readTrace } from './chunk-TFLPUZ56.mjs';
17
- export { persistedInspectEventToInspectEvent, persistedInspectEventsToInspectEvents, persistedInspectEventsToRunTrees, traceEventToPersistedInspectEvent, traceEventsToPersistedInspectEvents, traceEventsToPersistedRunTrees } from './chunk-TZISEVLQ.mjs';
18
- import { buildRunStartedMetadata } from './chunk-S4YWKV4G.mjs';
19
- export { TreeBuilder } from './chunk-E5F2LQCX.mjs';
20
- import { warn, createStepId, formatError, truncateName, getDefaultTraceDir, parseTraceJsonl, parseDuration, formatTimestamp, formatDuration, isTraceEvent, createRunId, getTraceFilePath } from './chunk-VTIB5MDK.mjs';
21
- export { DEFAULT_TRACE_DIR_NAME, FALLBACK_TRACE_DIR, MAX_NAME_LENGTH, RUNS_DIR_NAME, createRunId, createStepId, ensureTraceDir, formatDuration, formatError, formatTimestamp, getDefaultTraceDir, getTraceFilePath, isStepStatus, isStepType, isTraceEvent, parseDuration, parseTraceJsonl, truncateName, unknownTraceFormatMessage, warn } from './chunk-VTIB5MDK.mjs';
22
- export { isPersistedInspectEvent, persistedInspectEventToTraceEvents, persistedInspectEventsToTraceEvents } from './chunk-74XZ6N7Q.mjs';
4
+ import { prepareTraceEventForDisk, writeTraceEvent } from './chunk-4JVGFNQH.mjs';
5
+ import './chunk-EDTQHZPM.mjs';
6
+ import './chunk-VU6O5QAH.mjs';
7
+ import './chunk-S4YWKV4G.mjs';
8
+ import { warn, createStepId, formatError, truncateName } from './chunk-NQZPZ2FN.mjs';
9
+ import './chunk-IZBJAZGF.mjs';
23
10
  import './chunk-7TGZLWEE.mjs';
24
- import { readdir, stat, readFile } from 'fs/promises';
25
- import path from 'path';
26
- import { createReadStream } from 'fs';
27
- import { createInterface } from 'readline';
28
-
29
- function resolveTraceDir(options = {}) {
30
- if (typeof options.dir === "string" && options.dir.trim() !== "") {
31
- return options.dir.trim();
32
- }
33
- const envDir = process.env.AGENT_INSPECT_TRACE_DIR;
34
- if (typeof envDir === "string" && envDir.trim() !== "") {
35
- return envDir.trim();
36
- }
37
- return getDefaultTraceDir();
38
- }
39
- var TraceDirectory = class {
40
- #dir;
41
- constructor(options = {}) {
42
- this.#dir = resolveTraceDir(options);
43
- }
44
- getPath(filename) {
45
- return filename ? path.join(this.#dir, filename) : this.#dir;
46
- }
47
- async list() {
48
- try {
49
- const files = await readdir(this.#dir);
50
- return files.filter((f) => f.endsWith(".jsonl"));
51
- } catch (e) {
52
- if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
53
- return [];
54
- }
55
- throw e;
56
- }
57
- }
58
- async getFileStats(filename) {
59
- return await stat(this.getPath(filename));
60
- }
61
- };
62
- function isFiniteNumber(v) {
63
- return typeof v === "number" && Number.isFinite(v);
64
- }
65
- function parseIsoToMs(value) {
66
- if (value === void 0) return void 0;
67
- const parsed = Date.parse(value);
68
- return Number.isFinite(parsed) ? parsed : void 0;
69
- }
70
- async function extractMetadata(filePath, _quickScan) {
71
- const stats = await stat(filePath);
72
- let runIdFromFile = path.basename(filePath);
73
- if (runIdFromFile.endsWith(".jsonl")) {
74
- runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
75
- }
76
- const raw = await readFile(filePath, "utf-8");
77
- const parsedTrace = parseTraceJsonl(raw, { warnings: false });
78
- let runId;
79
- let name;
80
- let startedAt;
81
- let endedAt;
82
- let explicitDurationMs;
83
- let hasRunStarted = false;
84
- let hasRunCompleted = false;
85
- let runCompletedStatus;
86
- let anyStepError = false;
87
- const anyKnownEvent = parsedTrace.sourceEventCount > 0;
88
- let persistedStatus;
89
- const persistedRun = parsedTrace.persisted.find(
90
- (event) => event.kind === "RUN"
91
- );
92
- if (persistedRun) {
93
- runId = persistedRun.runId;
94
- if (persistedRun.name.trim() !== "") {
95
- name = persistedRun.name;
96
- }
97
- startedAt = parseIsoToMs(persistedRun.startedAt) ?? parseIsoToMs(persistedRun.timestamp);
98
- endedAt = parseIsoToMs(persistedRun.endedAt);
99
- if (isFiniteNumber(persistedRun.durationMs)) {
100
- explicitDurationMs = persistedRun.durationMs;
101
- if (endedAt === void 0 && startedAt !== void 0) {
102
- endedAt = startedAt + persistedRun.durationMs;
103
- }
104
- }
105
- if (persistedRun.status === "ok") persistedStatus = "success";
106
- else if (persistedRun.status === "error") persistedStatus = "error";
107
- else if (persistedRun.status === "running") persistedStatus = "running";
108
- else if (persistedRun.status === "unknown") persistedStatus = "unknown";
109
- } else {
110
- runId = parsedTrace.persisted[0]?.runId;
111
- }
112
- for (const e of parsedTrace.events) {
113
- if (runId === void 0 && typeof e.runId === "string") {
114
- runId = e.runId;
115
- }
116
- if (e.event === "run_started") {
117
- hasRunStarted = true;
118
- const rs = e;
119
- if (typeof rs.name === "string" && rs.name.trim() !== "") {
120
- name = rs.name;
121
- }
122
- if (isFiniteNumber(rs.startTime)) {
123
- startedAt = rs.startTime;
124
- } else if (isFiniteNumber(rs.timestamp)) {
125
- startedAt = rs.timestamp;
126
- }
127
- }
128
- if (e.event === "run_completed") {
129
- hasRunCompleted = true;
130
- const rc = e;
131
- runCompletedStatus = rc.status;
132
- if (isFiniteNumber(rc.endTime)) endedAt = rc.endTime;
133
- else if (isFiniteNumber(rc.timestamp)) endedAt = rc.timestamp;
134
- if (isFiniteNumber(rc.durationMs)) explicitDurationMs = rc.durationMs;
135
- }
136
- if (e.event === "step_completed") {
137
- const sc = e;
138
- if (sc.status === "error") {
139
- anyStepError = true;
140
- }
141
- }
142
- }
143
- const resolvedRunId = runId ?? runIdFromFile;
144
- let status = "unknown";
145
- if (hasRunCompleted && (runCompletedStatus === "success" || runCompletedStatus === "error")) {
146
- status = runCompletedStatus;
147
- } else if (anyStepError) {
148
- status = "error";
149
- } else if (persistedStatus !== void 0) {
150
- status = persistedStatus;
151
- } else if (hasRunStarted && !hasRunCompleted) {
152
- status = "running";
153
- } else if (anyKnownEvent) {
154
- status = "unknown";
155
- } else {
156
- status = "unknown";
157
- }
158
- const durationMs = explicitDurationMs ?? (startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt ? endedAt - startedAt : void 0);
159
- return {
160
- runId: resolvedRunId,
161
- name,
162
- status,
163
- startedAt,
164
- endedAt,
165
- durationMs,
166
- eventCount: parsedTrace.sourceEventCount,
167
- filePath,
168
- fileSize: stats.size,
169
- createdAt: stats.birthtime
170
- };
171
- }
172
- function isNonNegativeFiniteNumber(value) {
173
- return typeof value === "number" && Number.isFinite(value) && value >= 0;
174
- }
175
- function buildRunSummary(events) {
176
- const started = events.find(
177
- (e) => e.event === "run_started"
178
- );
179
- const completed = events.filter(
180
- (e) => e.event === "run_completed"
181
- );
182
- const lastCompleted = completed[completed.length - 1];
183
- const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
184
- const name = typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0;
185
- const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
186
- const durationMs = lastCompleted && isFiniteNumber(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
187
- started && isFiniteNumber(started.startTime) ? started.startTime : void 0;
188
- const steps = /* @__PURE__ */ new Map();
189
- for (const e of events) {
190
- if (e.event === "step_started") {
191
- const s = e;
192
- steps.set(s.stepId, {
193
- type: s.type,
194
- name: s.name,
195
- status: "running",
196
- parentId: s.parentId,
197
- tokensInput: isNonNegativeFiniteNumber(s.metadata?.tokens?.input) ? s.metadata.tokens.input : void 0,
198
- tokensOutput: isNonNegativeFiniteNumber(s.metadata?.tokens?.output) ? s.metadata.tokens.output : void 0,
199
- tokensTotal: isNonNegativeFiniteNumber(s.metadata?.tokens?.total) ? s.metadata.tokens.total : void 0,
200
- tokensCached: isNonNegativeFiniteNumber(s.metadata?.tokens?.cached) ? s.metadata.tokens.cached : void 0
201
- });
202
- }
203
- }
204
- for (const e of events) {
205
- if (e.event === "step_completed") {
206
- const c = e;
207
- const existing = steps.get(c.stepId);
208
- if (!existing) continue;
209
- existing.status = c.status;
210
- existing.durationMs = c.durationMs;
211
- }
212
- }
213
- let totalSteps = 0;
214
- let llmSteps = 0;
215
- let toolSteps = 0;
216
- let logicSteps = 0;
217
- let errorSteps = 0;
218
- let maxDepth = 0;
219
- let longestStep;
220
- let totalTokensInput = 0;
221
- let totalTokensOutput = 0;
222
- let totalTokensTotal = 0;
223
- let totalTokensCached = 0;
224
- let tokenBearingSteps = 0;
225
- let stepsWithKnownTotal = 0;
226
- let hasCachedTokens = false;
227
- const depthCache = /* @__PURE__ */ new Map();
228
- const computeDepth = (stepId) => {
229
- const cached = depthCache.get(stepId);
230
- if (cached !== void 0) return cached;
231
- const node = steps.get(stepId);
232
- if (!node) return 0;
233
- const parent = node.parentId;
234
- if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
235
- depthCache.set(stepId, 0);
236
- return 0;
237
- }
238
- const d = Math.min(1e3, computeDepth(parent) + 1);
239
- depthCache.set(stepId, d);
240
- return d;
241
- };
242
- for (const [id, s] of steps.entries()) {
243
- totalSteps += 1;
244
- if (s.type === "llm") llmSteps += 1;
245
- else if (s.type === "tool") toolSteps += 1;
246
- else logicSteps += 1;
247
- if (s.status === "error") errorSteps += 1;
248
- const depth = computeDepth(id);
249
- if (depth > maxDepth) maxDepth = depth;
250
- if (typeof s.durationMs === "number" && Number.isFinite(s.durationMs)) {
251
- if (!longestStep || s.durationMs > longestStep.durationMs) {
252
- longestStep = { name: s.name, durationMs: s.durationMs, type: s.type };
253
- }
254
- }
255
- if (s.tokensInput !== void 0 || s.tokensOutput !== void 0 || s.tokensTotal !== void 0 || s.tokensCached !== void 0) {
256
- tokenBearingSteps += 1;
257
- if (s.tokensInput !== void 0) totalTokensInput += s.tokensInput;
258
- if (s.tokensOutput !== void 0) totalTokensOutput += s.tokensOutput;
259
- if (s.tokensTotal !== void 0) {
260
- totalTokensTotal += s.tokensTotal;
261
- stepsWithKnownTotal += 1;
262
- } else if (s.tokensInput !== void 0 && s.tokensOutput !== void 0) {
263
- totalTokensTotal += s.tokensInput + s.tokensOutput;
264
- stepsWithKnownTotal += 1;
265
- }
266
- if (s.tokensCached !== void 0) {
267
- totalTokensCached += s.tokensCached;
268
- hasCachedTokens = true;
269
- }
270
- }
271
- }
272
- const summary = {
273
- runId,
274
- name,
275
- status,
276
- durationMs,
277
- totalSteps,
278
- llmSteps,
279
- toolSteps,
280
- logicSteps,
281
- errorSteps,
282
- maxDepth,
283
- ...longestStep ? { longestStep } : {},
284
- ...tokenBearingSteps > 0 ? {
285
- totalTokens: {
286
- input: totalTokensInput,
287
- output: totalTokensOutput,
288
- ...stepsWithKnownTotal === tokenBearingSteps ? { total: totalTokensTotal } : {},
289
- ...hasCachedTokens ? { cached: totalTokensCached } : {}
290
- }
291
- } : {}
292
- };
293
- return summary;
294
- }
295
-
296
- // packages/core/src/trace-filter.ts
297
- function toLower(s) {
298
- return typeof s === "string" ? s.toLowerCase() : "";
299
- }
300
- function filterTraces(traces, options) {
301
- const input = [...traces];
302
- let out = input.filter((t) => {
303
- if (options.status && t.status !== options.status) return false;
304
- if (options.name) {
305
- const q = options.name.toLowerCase();
306
- const hay = `${toLower(t.name)} ${toLower(t.runId)}`;
307
- if (!hay.includes(q)) return false;
308
- }
309
- if (options.since) {
310
- const windowMs = parseDuration(options.since);
311
- const cutoff = Date.now() - windowMs;
312
- const started = typeof t.startedAt === "number" ? t.startedAt : void 0;
313
- const basis = started ?? t.createdAt.getTime();
314
- if (!Number.isFinite(basis) || basis < cutoff) return false;
315
- }
316
- return true;
317
- });
318
- out.sort((a, b) => {
319
- const aTime = (typeof a.startedAt === "number" ? a.startedAt : void 0) ?? a.createdAt.getTime();
320
- const bTime = (typeof b.startedAt === "number" ? b.startedAt : void 0) ?? b.createdAt.getTime();
321
- return bTime - aTime;
322
- });
323
- if (typeof options.limit === "number" && Number.isFinite(options.limit)) {
324
- const n = Math.max(0, Math.floor(options.limit));
325
- out = out.slice(0, n);
326
- }
327
- return out;
328
- }
329
-
330
- // packages/core/src/timeline.ts
331
- function finite(n) {
332
- return typeof n === "number" && Number.isFinite(n);
333
- }
334
- function pickStreamingMeta(metadata) {
335
- if (!metadata || typeof metadata !== "object") return void 0;
336
- const chunkCount = metadata.chunkCount;
337
- const streamDurationMs = metadata.streamDurationMs;
338
- const streamedCharCount = metadata.streamedCharCount;
339
- if (!finite(chunkCount) && !finite(streamDurationMs) && !finite(streamedCharCount)) {
340
- return void 0;
341
- }
342
- return {
343
- ...finite(chunkCount) ? { chunkCount } : {},
344
- ...finite(streamDurationMs) ? { streamDurationMs } : {},
345
- ...finite(streamedCharCount) ? { streamedCharCount } : {}
346
- };
347
- }
348
- function pickCorrelation(metadata) {
349
- if (!metadata || typeof metadata !== "object") return void 0;
350
- const out = {};
351
- for (const key of [
352
- "correlationId",
353
- "requestId",
354
- "decisionId",
355
- "groupId"
356
- ]) {
357
- const v = metadata[key];
358
- if (typeof v === "string" && v.trim() !== "") {
359
- out[key] = v;
360
- }
361
- }
362
- return Object.keys(out).length > 0 ? out : void 0;
363
- }
364
- function buildRunTimeline(events, options = {}) {
365
- const started = events.find(
366
- (e) => e.event === "run_started"
367
- );
368
- const completed = events.filter(
369
- (e) => e.event === "run_completed"
370
- );
371
- const lastCompleted = completed[completed.length - 1];
372
- const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
373
- const runStart = started && finite(started.startTime) ? started.startTime : started && finite(started.timestamp) ? started.timestamp : void 0;
374
- const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
375
- const steps = /* @__PURE__ */ new Map();
376
- for (const e of events) {
377
- if (e.event === "step_started") {
378
- const s = e;
379
- steps.set(s.stepId, {
380
- name: s.name,
381
- type: s.type,
382
- parentId: s.parentId,
383
- startedAt: finite(s.startTime) ? s.startTime : s.timestamp,
384
- status: "running",
385
- metadata: s.metadata
386
- });
387
- }
388
- }
389
- for (const e of events) {
390
- if (e.event !== "step_completed") continue;
391
- const c = e;
392
- const node = steps.get(c.stepId);
393
- if (!node) continue;
394
- node.status = c.status;
395
- if (finite(c.durationMs)) node.durationMs = c.durationMs;
396
- }
397
- const depthCache = /* @__PURE__ */ new Map();
398
- const computeDepth = (stepId) => {
399
- const cached = depthCache.get(stepId);
400
- if (cached !== void 0) return cached;
401
- const node = steps.get(stepId);
402
- if (!node) return 0;
403
- const parent = node.parentId;
404
- if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
405
- depthCache.set(stepId, 0);
406
- return 0;
407
- }
408
- const d = Math.min(1e3, computeDepth(parent) + 1);
409
- depthCache.set(stepId, d);
410
- return d;
411
- };
412
- const entries = [];
413
- for (const [stepId, s] of steps.entries()) {
414
- const offsetMs = runStart !== void 0 && finite(s.startedAt) ? Math.max(0, s.startedAt - runStart) : 0;
415
- entries.push({
416
- stepId,
417
- name: s.name,
418
- type: s.type,
419
- status: s.status,
420
- depth: computeDepth(stepId),
421
- startedAt: s.startedAt,
422
- offsetMs,
423
- durationMs: s.durationMs,
424
- isError: s.status === "error",
425
- streaming: pickStreamingMeta(s.metadata)
426
- });
427
- }
428
- entries.sort((a, b) => a.startedAt - b.startedAt);
429
- const slowTopN = options.slowTopN ?? 3;
430
- if (options.focus === "slow" && entries.length > 0) {
431
- const ranked = [...entries].filter((e) => finite(e.durationMs)).sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
432
- const slowIds = new Set(
433
- ranked.slice(0, slowTopN).map((e) => e.stepId)
434
- );
435
- for (const e of entries) {
436
- if (slowIds.has(e.stepId)) e.slow = true;
437
- }
438
- }
439
- return {
440
- runId,
441
- name: typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0,
442
- status,
443
- startedAt: runStart,
444
- endedAt: lastCompleted && finite(lastCompleted.endTime) ? lastCompleted.endTime : void 0,
445
- durationMs: lastCompleted && finite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0,
446
- correlation: pickCorrelation(
447
- started?.metadata
448
- ),
449
- entries
450
- };
451
- }
452
- function renderTimeline(timeline, options = {}) {
453
- const lines = [];
454
- lines.push(`Timeline: ${timeline.name ?? timeline.runId}`);
455
- lines.push(`Run ID: ${timeline.runId}`);
456
- lines.push(`Status: ${timeline.status}`);
457
- if (timeline.startedAt !== void 0) {
458
- lines.push(`Started: ${formatTimestamp(timeline.startedAt)}`);
459
- }
460
- if (timeline.durationMs !== void 0) {
461
- lines.push(`Duration: ${formatDuration(timeline.durationMs)}`);
462
- }
463
- if (timeline.correlation) {
464
- const parts = Object.entries(timeline.correlation).filter(([, v]) => typeof v === "string").map(([k, v]) => `${k}=${v}`);
465
- if (parts.length > 0) {
466
- lines.push(`Correlation: ${parts.join(", ")}`);
467
- }
468
- }
469
- lines.push("");
470
- lines.push("Steps (chronological):");
471
- const show = timeline.entries.filter((e) => {
472
- if (options.focus === "slow") return e.slow === true;
473
- return true;
474
- });
475
- if (show.length === 0) {
476
- lines.push(
477
- options.focus === "slow" ? "(no steps with duration for slow focus)" : "(no steps)"
478
- );
479
- return lines.join("\n");
480
- }
481
- for (const e of show) {
482
- const prefix = e.slow ? "[slow] " : "";
483
- const typeTag = e.type === "llm" ? "llm" : e.type === "tool" ? "tool" : e.type;
484
- const dur = e.durationMs !== void 0 ? formatDuration(e.durationMs) : "-";
485
- const err = e.isError ? " error" : "";
486
- const off = formatDuration(e.offsetMs);
487
- let line = `${prefix}+${off} ${typeTag}:${e.name} (${dur})${err}`;
488
- if (e.streaming?.chunkCount !== void 0) {
489
- line += ` chunks=${e.streaming.chunkCount}`;
490
- }
491
- if (e.streaming?.streamDurationMs !== void 0) {
492
- line += ` stream=${formatDuration(e.streaming.streamDurationMs)}`;
493
- }
494
- lines.push(line);
495
- }
496
- return lines.join("\n");
497
- }
498
-
499
- // packages/core/src/what.ts
500
- function pickCorrelation2(metadata) {
501
- if (!metadata) return void 0;
502
- const out = {};
503
- for (const key of [
504
- "correlationId",
505
- "requestId",
506
- "decisionId",
507
- "groupId"
508
- ]) {
509
- const value = metadata[key];
510
- if (typeof value === "string" && value.trim() !== "") {
511
- out[key] = value;
512
- }
513
- }
514
- return Object.keys(out).length > 0 ? out : void 0;
515
- }
516
- function stepMixLine(summary) {
517
- const parts = [];
518
- if (summary.llmSteps > 0) parts.push(`${summary.llmSteps} LLM`);
519
- if (summary.toolSteps > 0) parts.push(`${summary.toolSteps} tool`);
520
- if (summary.logicSteps > 0) parts.push(`${summary.logicSteps} logic`);
521
- return parts.length > 0 ? parts.join(", ") : "none";
522
- }
523
- function outcomeLine(summary) {
524
- if (summary.status === "success") {
525
- return summary.errorSteps > 0 ? "Completed with step errors recorded." : "Completed successfully.";
526
- }
527
- if (summary.status === "error") {
528
- if (summary.failedStepNames.length > 0) {
529
- const names = summary.failedStepNames.slice(0, 3).join(", ");
530
- const suffix = summary.failedStepNames.length > 3 ? ` (+${summary.failedStepNames.length - 3} more)` : "";
531
- return `Failed at step(s): ${names}${suffix}.`;
532
- }
533
- if (summary.runErrorMessage) {
534
- return `Run failed: ${summary.runErrorMessage}`;
535
- }
536
- return "Run failed.";
537
- }
538
- if (summary.status === "running") {
539
- return "Run is still in progress (no run_completed).";
540
- }
541
- return "Outcome unknown \u2014 inspect events may be incomplete.";
542
- }
543
- function buildRunWhatSummary(events) {
544
- const base = buildRunSummary(events);
545
- const started = events.find(
546
- (e) => e.event === "run_started"
547
- );
548
- const completed = events.filter(
549
- (e) => e.event === "run_completed"
550
- );
551
- const lastCompleted = completed[completed.length - 1];
552
- const failedStepNames = [];
553
- const stepNames = /* @__PURE__ */ new Map();
554
- for (const e of events) {
555
- if (e.event === "step_started") {
556
- const s = e;
557
- stepNames.set(s.stepId, s.name);
558
- }
559
- }
560
- for (const e of events) {
561
- if (e.event === "step_completed") {
562
- const sc = e;
563
- if (sc.status === "error") {
564
- failedStepNames.push(stepNames.get(sc.stepId) ?? sc.stepId);
565
- }
566
- }
567
- }
568
- return {
569
- runId: base.runId,
570
- name: base.name,
571
- status: base.status,
572
- durationMs: base.durationMs,
573
- totalSteps: base.totalSteps,
574
- llmSteps: base.llmSteps,
575
- toolSteps: base.toolSteps,
576
- logicSteps: base.logicSteps,
577
- errorSteps: base.errorSteps,
578
- maxDepth: base.maxDepth,
579
- longestStep: base.longestStep,
580
- totalTokens: base.totalTokens,
581
- correlation: pickCorrelation2(started?.metadata),
582
- failedStepNames,
583
- runErrorMessage: lastCompleted?.error?.message
584
- };
585
- }
586
- function renderRunWhat(summary, options = {}) {
587
- const showCorrelation = options.correlation !== false;
588
- const lines = [];
589
- const label = summary.name ?? summary.runId;
590
- lines.push(`What: ${label}`);
591
- const duration = summary.durationMs !== void 0 ? formatDuration(summary.durationMs) : "\u2014";
592
- lines.push(
593
- `Status: ${summary.status} \xB7 Duration: ${duration} \xB7 Steps: ${summary.totalSteps} (${stepMixLine(summary)})`
594
- );
595
- if (summary.totalTokens) {
596
- const tokenParts = [
597
- `${summary.totalTokens.input} in`,
598
- `${summary.totalTokens.output} out`
599
- ];
600
- if (summary.totalTokens.total !== void 0) {
601
- tokenParts.push(`${summary.totalTokens.total} total`);
602
- }
603
- if (summary.totalTokens.cached !== void 0) {
604
- tokenParts.push(`${summary.totalTokens.cached} cached`);
605
- }
606
- lines.push(`Tokens: ${tokenParts.join(" / ")}`);
607
- }
608
- if (showCorrelation && summary.correlation) {
609
- const parts = [];
610
- if (summary.correlation.correlationId) {
611
- parts.push(`correlationId=${summary.correlation.correlationId}`);
612
- }
613
- if (summary.correlation.requestId) {
614
- parts.push(`requestId=${summary.correlation.requestId}`);
615
- }
616
- if (summary.correlation.decisionId) {
617
- parts.push(`decisionId=${summary.correlation.decisionId}`);
618
- }
619
- if (summary.correlation.groupId) {
620
- parts.push(`groupId=${summary.correlation.groupId}`);
621
- }
622
- if (parts.length > 0) {
623
- lines.push(`Correlation: ${parts.join(", ")}`);
624
- }
625
- }
626
- lines.push(`Outcome: ${outcomeLine(summary)}`);
627
- if (summary.longestStep && summary.totalSteps > 0) {
628
- lines.push(
629
- `Slowest: ${summary.longestStep.name} (${formatDuration(summary.longestStep.durationMs)}, ${summary.longestStep.type})`
630
- );
631
- }
632
- if (summary.maxDepth > 0) {
633
- lines.push(`Max depth: ${summary.maxDepth}`);
634
- }
635
- return lines.join("\n");
636
- }
637
-
638
- // packages/core/src/report.ts
639
- function resolveTree(events, profile) {
640
- const tree = manualTraceEventsToRunTree(events);
641
- return profile === "local" ? tree : redactRunTreeForExport(tree, { redactionProfile: profile });
642
- }
643
- function tailMarkdownSection(content, heading) {
644
- const marker = `## ${heading}`;
645
- const idx = content.indexOf(marker);
646
- if (idx < 0) return "";
647
- return content.slice(idx).trimEnd();
648
- }
649
- function extractHtmlFragment(content, start, end) {
650
- const startIdx = content.indexOf(start);
651
- if (startIdx < 0) return "";
652
- const endIdx = content.indexOf(end, startIdx + start.length);
653
- if (endIdx < 0) return content.slice(startIdx);
654
- return content.slice(startIdx, endIdx);
655
- }
656
- var REPORT_HTML_CSS = `
657
- body{font-family:system-ui,sans-serif;line-height:1.5;margin:1.5rem;max-width:960px;color:#111}
658
- h1{font-size:1.35rem}
659
- h2{font-size:1.1rem;margin-top:1.5rem}
660
- pre{white-space:pre-wrap;background:#f8f8f8;padding:0.75rem;overflow:auto;font-size:0.9rem}
661
- ul.tree{list-style:none;padding-left:1rem}
662
- ul.tree.nested{padding-left:1.25rem;border-left:1px solid #ddd;margin:0.25rem 0}
663
- .nm{font-weight:600}
664
- .meta{color:#555;font-size:0.9rem}
665
- footer{margin-top:2rem;font-size:0.85rem;color:#555}
666
- `.trim();
667
- function buildRunReport(events, options) {
668
- const profile = options.redactionProfile ?? "local";
669
- const safeEvents = redactTraceEventsForReport(events, {
670
- redactionProfile: profile
671
- });
672
- const whatSummary = buildRunWhatSummary(safeEvents);
673
- const whatText = renderRunWhat(whatSummary, {
674
- correlation: options.correlation !== false
675
- });
676
- const timelineText = renderTimeline(buildRunTimeline(safeEvents));
677
- const tree = resolveTree(safeEvents, profile);
678
- const exportOpts = {
679
- includeMetadata: false,
680
- includeAttributes: options.includeAttributes === true,
681
- includeErrors: options.includeErrors !== false,
682
- redacted: true,
683
- redactionProfile: profile,
684
- maxAttributeLength: 500
685
- };
686
- if (options.format === "markdown") {
687
- const treeMd = exportMarkdown(tree, exportOpts);
688
- const tail = tailMarkdownSection(treeMd.content, "Execution tree");
689
- const title2 = escapeMarkdown(whatSummary.name ?? whatSummary.runId);
690
- const lines = [
691
- `# AgentInspect Report: ${title2}`,
692
- "",
693
- "Generated locally by AgentInspect. Review for sensitive data before sharing.",
694
- "",
695
- "## What happened",
696
- "",
697
- "```text",
698
- whatText,
699
- "```",
700
- "",
701
- "## Timeline",
702
- "",
703
- "```text",
704
- timelineText,
705
- "```",
706
- ""
707
- ];
708
- if (tail) {
709
- lines.push(tail, "");
710
- } else {
711
- lines.push("## Execution tree", "", "(no steps)", "");
712
- }
713
- return {
714
- format: "markdown",
715
- content: lines.join("\n"),
716
- contentType: "text/markdown",
717
- fileExtension: ".md"
718
- };
719
- }
720
- const treeHtml = exportHtml(tree, exportOpts);
721
- const title = escapeHtml(whatSummary.name ?? whatSummary.runId);
722
- const treeSection = extractHtmlFragment(
723
- treeHtml.content,
724
- '<section class="tree">',
725
- "</section>"
726
- );
727
- const errorsSection = treeHtml.content.includes("<h2>Errors</h2>") ? extractHtmlFragment(treeHtml.content, "<h2>Errors</h2>", "<footer>") : "";
728
- const attrsSection = treeHtml.content.includes("<h2>Attributes (bounded)</h2>") ? extractHtmlFragment(
729
- treeHtml.content,
730
- "<h2>Attributes (bounded)</h2>",
731
- "<footer>"
732
- ) : "";
733
- const html = `<!doctype html>
734
- <html lang="en">
735
- <head>
736
- <meta charset="utf-8"/>
737
- <meta name="viewport" content="width=device-width, initial-scale=1"/>
738
- <title>AgentInspect Report: ${title}</title>
739
- <style>${REPORT_HTML_CSS}</style>
740
- </head>
741
- <body>
742
- <header><h1>AgentInspect Report: ${title}</h1></header>
743
- <p class="note">Generated locally by AgentInspect. Review for sensitive data before sharing.</p>
744
- <section class="what"><h2>What happened</h2><pre>${escapeHtml(whatText)}</pre></section>
745
- <section class="timeline"><h2>Timeline</h2><pre>${escapeHtml(timelineText)}</pre></section>
746
- ${treeSection || '<section class="tree"><h2>Execution tree</h2><p>No steps recorded.</p></section>'}
747
- ${errorsSection}
748
- ${attrsSection}
749
- <footer>Generated locally by AgentInspect. Review for sensitive data before sharing.</footer>
750
- </body>
751
- </html>`;
752
- return {
753
- format: "html",
754
- content: html,
755
- contentType: "text/html",
756
- fileExtension: ".html"
757
- };
758
- }
759
-
760
- // packages/core/src/stats.ts
761
- function percentile(sorted, p) {
762
- if (sorted.length === 0) return void 0;
763
- const idx = Math.min(
764
- sorted.length - 1,
765
- Math.max(0, Math.ceil(p / 100 * sorted.length) - 1)
766
- );
767
- return sorted[idx];
768
- }
769
- async function readRunStartedMetadata(filePath) {
770
- try {
771
- const events = await readTraceEventsFromFile(filePath);
772
- for (const event of events) {
773
- if (event.event !== "run_started") continue;
774
- const rs = event;
775
- if (rs.metadata && typeof rs.metadata === "object") {
776
- return rs.metadata;
777
- }
778
- return void 0;
779
- }
780
- } catch {
781
- }
782
- return void 0;
783
- }
784
- function metaMatchesCorrelation(metadata, correlationId, groupId) {
785
- if (correlationId) {
786
- const v = metadata?.correlationId;
787
- if (typeof v !== "string" || v !== correlationId) return false;
788
- }
789
- if (groupId) {
790
- const v = metadata?.groupId;
791
- if (typeof v !== "string" || v !== groupId) return false;
792
- }
793
- return true;
794
- }
795
- async function buildTraceStats(metas, options) {
796
- let filtered = filterTraces(metas, { since: options.since });
797
- if (options.correlationId || options.groupId) {
798
- const next = [];
799
- for (const m of filtered) {
800
- const md = await readRunStartedMetadata(m.filePath);
801
- if (metaMatchesCorrelation(md, options.correlationId, options.groupId)) {
802
- next.push(m);
803
- }
804
- }
805
- filtered = next;
806
- }
807
- let successCount = 0;
808
- let errorCount = 0;
809
- let runningCount = 0;
810
- let unknownCount = 0;
811
- const durations = [];
812
- let totalSteps = 0;
813
- let totalLlmSteps = 0;
814
- let totalToolSteps = 0;
815
- let totalErrorSteps = 0;
816
- const slowestRuns = [];
817
- const slowestSteps = [];
818
- for (const m of filtered) {
819
- if (m.status === "success") successCount += 1;
820
- else if (m.status === "error") errorCount += 1;
821
- else if (m.status === "running") runningCount += 1;
822
- else unknownCount += 1;
823
- if (typeof m.durationMs === "number" && Number.isFinite(m.durationMs) && m.durationMs >= 0) {
824
- durations.push(m.durationMs);
825
- slowestRuns.push({
826
- runId: m.runId,
827
- name: m.name,
828
- durationMs: m.durationMs,
829
- status: m.status
830
- });
831
- }
832
- try {
833
- const events = await readTraceEventsFromFile(m.filePath);
834
- if (events.length === 0) continue;
835
- const summary = buildRunSummary(events);
836
- totalSteps += summary.totalSteps;
837
- totalLlmSteps += summary.llmSteps;
838
- totalToolSteps += summary.toolSteps;
839
- totalErrorSteps += summary.errorSteps;
840
- const steps = collectCompletedSteps(events, m.runId);
841
- for (const s of steps) {
842
- slowestSteps.push(s);
843
- }
844
- } catch {
845
- }
846
- }
847
- slowestRuns.sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
848
- slowestSteps.sort((a, b) => b.durationMs - a.durationMs);
849
- const runLimit = options.slowRunLimit ?? 5;
850
- const stepLimit = options.slowStepLimit ?? 5;
851
- const sortedDur = [...durations].sort((a, b) => a - b);
852
- const totalRuns = filtered.length;
853
- const errorRate = totalRuns > 0 ? errorCount / totalRuns : 0;
854
- const sumDur = durations.reduce((a, b) => a + b, 0);
855
- return {
856
- traceDir: options.traceDir,
857
- ...options.since ? { since: options.since } : {},
858
- ...options.correlationId ? { correlationId: options.correlationId } : {},
859
- ...options.groupId ? { groupId: options.groupId } : {},
860
- totalRuns,
861
- successCount,
862
- errorCount,
863
- runningCount,
864
- unknownCount,
865
- errorRate,
866
- duration: {
867
- ...sortedDur.length > 0 ? {
868
- minMs: sortedDur[0],
869
- maxMs: sortedDur[sortedDur.length - 1],
870
- avgMs: sumDur / sortedDur.length,
871
- p50Ms: percentile(sortedDur, 50),
872
- p95Ms: percentile(sortedDur, 95)
873
- } : {}
874
- },
875
- totalSteps,
876
- avgStepsPerRun: totalRuns > 0 ? totalSteps / totalRuns : 0,
877
- totalLlmSteps,
878
- totalToolSteps,
879
- totalErrorSteps,
880
- slowestRuns: slowestRuns.slice(0, runLimit),
881
- slowestSteps: slowestSteps.slice(0, stepLimit)
882
- };
883
- }
884
- function collectCompletedSteps(events, runId) {
885
- const started = /* @__PURE__ */ new Map();
886
- const out = [];
887
- for (const e of events) {
888
- if (e.event === "step_started") {
889
- const s = e;
890
- started.set(s.stepId, { name: s.name, type: s.type });
891
- }
892
- if (e.event === "step_completed") {
893
- const c = e;
894
- if (c.status !== "success" && c.status !== "error") continue;
895
- if (typeof c.durationMs !== "number" || !Number.isFinite(c.durationMs)) {
896
- continue;
897
- }
898
- const meta = started.get(c.stepId);
899
- out.push({
900
- runId,
901
- stepName: meta?.name ?? c.stepId,
902
- stepType: meta?.type ?? "logic",
903
- durationMs: c.durationMs
904
- });
905
- }
906
- }
907
- return out;
908
- }
909
- function renderTraceStats(stats) {
910
- const lines = [];
911
- lines.push("Trace stats (local)");
912
- lines.push(`Directory: ${stats.traceDir}`);
913
- if (stats.since) lines.push(`Since: ${stats.since}`);
914
- if (stats.correlationId) lines.push(`Correlation ID: ${stats.correlationId}`);
915
- if (stats.groupId) lines.push(`Group ID: ${stats.groupId}`);
916
- lines.push("");
917
- lines.push(`Runs: ${stats.totalRuns}`);
918
- lines.push(
919
- ` success: ${stats.successCount} error: ${stats.errorCount} running: ${stats.runningCount} unknown: ${stats.unknownCount}`
920
- );
921
- lines.push(`Error rate: ${(stats.errorRate * 100).toFixed(1)}%`);
922
- if (stats.duration.avgMs !== void 0) {
923
- lines.push(
924
- `Duration: min ${formatDuration(stats.duration.minMs ?? 0)} | avg ${formatDuration(stats.duration.avgMs)} | p50 ${formatDuration(stats.duration.p50Ms ?? 0)} | p95 ${formatDuration(stats.duration.p95Ms ?? 0)} | max ${formatDuration(stats.duration.maxMs ?? 0)}`
925
- );
926
- }
927
- lines.push("");
928
- lines.push(`Steps: ${stats.totalSteps} (avg ${stats.avgStepsPerRun.toFixed(1)} per run)`);
929
- lines.push(
930
- ` LLM: ${stats.totalLlmSteps} tool: ${stats.totalToolSteps} errors: ${stats.totalErrorSteps}`
931
- );
932
- if (stats.slowestRuns.length > 0) {
933
- lines.push("");
934
- lines.push("Slowest runs:");
935
- for (const r of stats.slowestRuns) {
936
- lines.push(
937
- ` ${r.runId} | ${r.name ?? "-"} | ${formatDuration(r.durationMs ?? 0)} | ${r.status}`
938
- );
939
- }
940
- }
941
- if (stats.slowestSteps.length > 0) {
942
- lines.push("");
943
- lines.push("Slowest steps:");
944
- for (const s of stats.slowestSteps) {
945
- lines.push(
946
- ` ${s.runId} | ${s.stepType}:${s.stepName} | ${formatDuration(s.durationMs)}`
947
- );
948
- }
949
- }
950
- return lines.join("\n");
951
- }
952
-
953
- // packages/core/src/search.ts
954
- function parseDurationFilter(expr) {
955
- const raw = expr.trim();
956
- const m = raw.match(/^(>=|<=|>|<)\s*(.+)$/);
957
- if (!m) {
958
- throw new Error(
959
- `Invalid --duration "${expr}". Use forms like >5s, >=500ms, <2m.`
960
- );
961
- }
962
- const op = m[1];
963
- const ms = parseDuration(m[2].trim());
964
- return { op, ms };
965
- }
966
- function durationMatches(valueMs, filter) {
967
- if (valueMs === void 0 || !Number.isFinite(valueMs)) return false;
968
- switch (filter.op) {
969
- case ">":
970
- return valueMs > filter.ms;
971
- case ">=":
972
- return valueMs >= filter.ms;
973
- case "<":
974
- return valueMs < filter.ms;
975
- case "<=":
976
- return valueMs <= filter.ms;
977
- default:
978
- return false;
979
- }
980
- }
981
- function normalizeStepTypeFilter(kind, type) {
982
- const v = (kind ?? type)?.trim().toLowerCase();
983
- return v && v !== "" ? v : void 0;
984
- }
985
- function nameMatches(hay, needle) {
986
- return hay.toLowerCase().includes(needle.toLowerCase());
987
- }
988
- async function searchTraces(metas, options) {
989
- let filtered = filterTraces(metas, { since: options.since });
990
- const stepTypeFilter = normalizeStepTypeFilter(options.kind, options.type);
991
- const nameQuery = options.name?.trim();
992
- const toolQuery = options.tool?.trim();
993
- let durationFilter;
994
- if (options.duration) {
995
- durationFilter = parseDurationFilter(options.duration);
996
- }
997
- const limit = options.limit ?? 50;
998
- const hasContentFilter = Boolean(
999
- options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
1000
- );
1001
- const results = [];
1002
- if (!hasContentFilter) {
1003
- for (const m of filtered) {
1004
- results.push({
1005
- runId: m.runId,
1006
- runName: m.name,
1007
- runStatus: m.status,
1008
- timestamp: m.startedAt,
1009
- durationMs: m.durationMs,
1010
- matchReason: "trace in directory",
1011
- matchedFields: ["run"],
1012
- filePath: m.filePath
1013
- });
1014
- }
1015
- return results.slice(0, limit);
1016
- }
1017
- for (const m of filtered) {
1018
- if (options.status && m.status !== options.status) continue;
1019
- let events = [];
1020
- try {
1021
- events = await readTraceEventsFromFile(m.filePath);
1022
- } catch {
1023
- continue;
1024
- }
1025
- if (events.length === 0) continue;
1026
- const runMatches = matchRunLevel(m, {
1027
- stepTypeFilter,
1028
- nameQuery,
1029
- toolQuery,
1030
- durationFilter,
1031
- statusFilter: options.status
1032
- });
1033
- results.push(...runMatches);
1034
- const stepMatches = matchStepLevel(m, events, {
1035
- stepTypeFilter,
1036
- nameQuery,
1037
- toolQuery,
1038
- durationFilter,
1039
- statusFilter: options.status
1040
- });
1041
- results.push(...stepMatches);
1042
- }
1043
- results.sort((a, b) => {
1044
- const ta = a.timestamp ?? 0;
1045
- const tb = b.timestamp ?? 0;
1046
- if (ta !== tb) return ta - tb;
1047
- const runCmp = a.runId.localeCompare(b.runId);
1048
- if (runCmp !== 0) return runCmp;
1049
- return (a.stepName ?? "").localeCompare(b.stepName ?? "");
1050
- });
1051
- return results.slice(0, limit);
1052
- }
1053
- function matchRunLevel(m, opts) {
1054
- if (opts.stepTypeFilter || opts.toolQuery) return [];
1055
- const out = [];
1056
- const fields = [];
1057
- if (opts.statusFilter && m.status === opts.statusFilter) {
1058
- fields.push("run.status");
1059
- }
1060
- if (opts.nameQuery && nameMatches(m.name ?? m.runId, opts.nameQuery)) {
1061
- fields.push("run.name");
1062
- }
1063
- if (opts.durationFilter && durationMatches(m.durationMs, opts.durationFilter)) {
1064
- fields.push("run.durationMs");
1065
- }
1066
- if (fields.length === 0) return out;
1067
- out.push({
1068
- runId: m.runId,
1069
- runName: m.name,
1070
- runStatus: m.status,
1071
- timestamp: m.startedAt,
1072
- durationMs: m.durationMs,
1073
- matchReason: `run match: ${fields.join(", ")}`,
1074
- matchedFields: fields,
1075
- filePath: m.filePath
1076
- });
1077
- return out;
1078
- }
1079
- function matchStepLevel(m, events, opts) {
1080
- const out = [];
1081
- const started = /* @__PURE__ */ new Map();
1082
- for (const e of events) {
1083
- if (e.event === "step_started") {
1084
- started.set(e.stepId, e);
1085
- }
1086
- }
1087
- for (const e of events) {
1088
- if (e.event !== "step_completed") continue;
1089
- const c = e;
1090
- const s = started.get(c.stepId);
1091
- if (!s) continue;
1092
- const fields = [];
1093
- const stepType = s.type;
1094
- if (opts.stepTypeFilter && stepType !== opts.stepTypeFilter) {
1095
- continue;
1096
- }
1097
- const hasStepFilters = opts.stepTypeFilter || opts.nameQuery || opts.toolQuery || opts.durationFilter || opts.statusFilter === "error" || opts.statusFilter === "success";
1098
- if (!hasStepFilters) continue;
1099
- if (opts.statusFilter === "error" && c.status === "error") {
1100
- fields.push("step.status");
1101
- } else if (opts.statusFilter === "success" && c.status === "success") {
1102
- fields.push("step.status");
1103
- } else if (opts.statusFilter === "error" || opts.statusFilter === "success") {
1104
- continue;
1105
- }
1106
- if (opts.nameQuery) {
1107
- if (!nameMatches(s.name, opts.nameQuery)) continue;
1108
- fields.push("step.name");
1109
- }
1110
- if (opts.toolQuery) {
1111
- const toolName = typeof s.metadata?.toolName === "string" ? s.metadata.toolName : s.name;
1112
- if (!nameMatches(toolName, opts.toolQuery)) continue;
1113
- fields.push("step.tool");
1114
- }
1115
- if (opts.durationFilter) {
1116
- if (!durationMatches(c.durationMs, opts.durationFilter)) continue;
1117
- fields.push("step.durationMs");
1118
- }
1119
- if (opts.stepTypeFilter) {
1120
- fields.push("step.type");
1121
- }
1122
- if (fields.length === 0) continue;
1123
- out.push({
1124
- runId: m.runId,
1125
- runName: m.name,
1126
- runStatus: m.status,
1127
- stepId: c.stepId,
1128
- stepName: s.name,
1129
- stepType,
1130
- timestamp: s.startTime ?? s.timestamp,
1131
- durationMs: c.durationMs,
1132
- matchReason: `step match: ${fields.join(", ")}`,
1133
- matchedFields: fields,
1134
- filePath: m.filePath
1135
- });
1136
- }
1137
- return out;
1138
- }
1139
- async function loadTraceMetadataList(_traceDir, fileNames, getPath) {
1140
- const metas = [];
1141
- for (const fileName of fileNames) {
1142
- try {
1143
- const filePath = getPath(fileName);
1144
- const meta = await extractMetadata(filePath);
1145
- metas.push(meta);
1146
- } catch {
1147
- }
1148
- }
1149
- return metas;
1150
- }
1151
- var KNOWN_EVENTS = /* @__PURE__ */ new Set([
1152
- "run_started",
1153
- "run_completed",
1154
- "step_started",
1155
- "step_completed"
1156
- ]);
1157
- function isRecord(value) {
1158
- return typeof value === "object" && value !== null && !Array.isArray(value);
1159
- }
1160
- function safeParse(line) {
1161
- try {
1162
- return JSON.parse(line);
1163
- } catch {
1164
- return void 0;
1165
- }
1166
- }
1167
- async function isAgentInspectTrace(filePath) {
1168
- try {
1169
- const rl = createInterface({
1170
- input: createReadStream(filePath, { encoding: "utf8" }),
1171
- crlfDelay: Infinity
1172
- });
1173
- let checked = 0;
1174
- for await (const line of rl) {
1175
- const trimmed = line.trim();
1176
- if (trimmed === "") continue;
1177
- const parsed = safeParse(trimmed);
1178
- if (!parsed) continue;
1179
- if (!isRecord(parsed)) continue;
1180
- checked += 1;
1181
- if (isTraceEvent(parsed)) return true;
1182
- const ev = parsed.event;
1183
- const runId = parsed.runId;
1184
- if (typeof ev === "string" && KNOWN_EVENTS.has(ev) && typeof runId === "string") {
1185
- return true;
1186
- }
1187
- if (checked >= 20) break;
1188
- }
1189
- return false;
1190
- } catch {
1191
- return false;
1192
- }
1193
- }
1194
-
1195
- // packages/core/src/inspect-run.ts
1196
- function normalizeRunName(name) {
1197
- if (typeof name !== "string" || name.trim() === "") {
1198
- return "unnamed-run";
1199
- }
1200
- return truncateName(name.trim(), 100);
1201
- }
1202
- async function safeInstrumentation(label, op) {
1203
- try {
1204
- await Promise.resolve(op());
1205
- } catch (e) {
1206
- warn(`inspectRun: ${label}`, e);
1207
- }
1208
- }
1209
- async function inspectRun(name, fn, options) {
1210
- if (typeof fn !== "function") {
1211
- throw new TypeError("inspectRun requires `fn` to be a function");
1212
- }
1213
- if (options?.enabled === false) {
1214
- return Promise.resolve(fn());
1215
- }
1216
- const runName = normalizeRunName(name);
1217
- const runId = createRunId();
1218
- const traceDir = resolveTraceDir({ dir: options?.traceDir });
1219
- const traceSafety = resolveTraceSafetyOptions(options);
1220
- const runMetadata = buildRunStartedMetadata(options);
1221
- const context = {
1222
- runId,
1223
- runName,
1224
- traceDir,
1225
- silent: options?.silent ?? false,
1226
- metadata: runMetadata
1227
- };
1228
- return runWithContext(context, async () => {
1229
- const startTime = Date.now();
1230
- let traceFilePath;
1231
- await safeInstrumentation("initializeTraceFile", async () => {
1232
- traceFilePath = await initializeTraceFile(runId, traceDir);
1233
- });
1234
- await safeInstrumentation("writeTraceEvent(run_started)", async () => {
1235
- const started = {
1236
- schemaVersion: "0.1",
1237
- event: "run_started",
1238
- timestamp: startTime,
1239
- runId,
1240
- name: runName,
1241
- startTime,
1242
- ...runMetadata !== void 0 ? { metadata: runMetadata } : {}
1243
- };
1244
- await writeTraceEvent(
1245
- prepareTraceEventForDisk(started, traceSafety),
1246
- traceDir
1247
- );
1248
- });
1249
- await safeInstrumentation("printRunStart", () => {
1250
- printRunStart(runId, runName);
1251
- });
1252
- let result;
1253
- try {
1254
- result = await Promise.resolve(fn());
1255
- } catch (userError) {
1256
- const endTime2 = Date.now();
1257
- const durationMs2 = endTime2 - startTime;
1258
- const formatted = formatError(userError);
1259
- const printPath2 = traceFilePath ?? getTraceFilePath(runId, traceDir);
1260
- await safeInstrumentation("writeTraceEvent(run_completed error)", async () => {
1261
- const completed = {
1262
- schemaVersion: "0.1",
1263
- event: "run_completed",
1264
- timestamp: endTime2,
1265
- runId,
1266
- status: "error",
1267
- endTime: endTime2,
1268
- durationMs: durationMs2,
1269
- error: formatted
1270
- };
1271
- await writeTraceEvent(
1272
- prepareTraceEventForDisk(completed, traceSafety),
1273
- traceDir
1274
- );
1275
- });
1276
- await safeInstrumentation("printRunComplete(error)", () => {
1277
- printRunComplete(runName, runId, durationMs2, "error", printPath2);
1278
- });
1279
- throw userError;
1280
- }
1281
- const endTime = Date.now();
1282
- const durationMs = endTime - startTime;
1283
- const printPath = traceFilePath ?? getTraceFilePath(runId, traceDir);
1284
- await safeInstrumentation("writeTraceEvent(run_completed success)", async () => {
1285
- const completed = {
1286
- schemaVersion: "0.1",
1287
- event: "run_completed",
1288
- timestamp: endTime,
1289
- runId,
1290
- status: "success",
1291
- endTime,
1292
- durationMs
1293
- };
1294
- await writeTraceEvent(
1295
- prepareTraceEventForDisk(completed, traceSafety),
1296
- traceDir
1297
- );
1298
- });
1299
- await safeInstrumentation("printRunComplete(success)", () => {
1300
- printRunComplete(runName, runId, durationMs, "success", printPath);
1301
- });
1302
- return result;
1303
- }, traceSafety);
1304
- }
1305
-
1306
- // packages/core/src/maybe-inspect-run.ts
1307
- var ENABLED_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on", "enabled"]);
1308
- function isAgentInspectEnabled(value) {
1309
- if (value === void 0) return false;
1310
- const normalized = value.trim().toLowerCase();
1311
- if (normalized === "") return false;
1312
- return ENABLED_ENV_VALUES.has(normalized);
1313
- }
1314
- async function maybeInspectRun(name, fn, options) {
1315
- if (typeof fn !== "function") {
1316
- throw new TypeError("maybeInspectRun requires `fn` to be a function");
1317
- }
1318
- const enabled = options?.enabled !== void 0 ? options.enabled : isAgentInspectEnabled(process.env.AGENT_INSPECT);
1319
- if (!enabled) {
1320
- return Promise.resolve(fn());
1321
- }
1322
- return inspectRun(name, fn, options);
1323
- }
1324
11
 
1325
12
  // packages/core/src/step.ts
1326
13
  function normalizeStepName(name) {
@@ -1329,7 +16,7 @@ function normalizeStepName(name) {
1329
16
  }
1330
17
  return truncateName(name.trim(), 100);
1331
18
  }
1332
- async function safeInstrumentation2(label, op) {
19
+ async function safeInstrumentation(label, op) {
1333
20
  try {
1334
21
  await Promise.resolve(op());
1335
22
  } catch (e) {
@@ -1353,7 +40,7 @@ async function stepImpl(name, fn, options) {
1353
40
  const metadata = options?.metadata;
1354
41
  const traceSafety = getTraceSafetyFromContext();
1355
42
  const startTime = Date.now();
1356
- await safeInstrumentation2("writeTraceEvent(step_started)", async () => {
43
+ await safeInstrumentation("writeTraceEvent(step_started)", async () => {
1357
44
  const started = {
1358
45
  schemaVersion: "0.1",
1359
46
  event: "step_started",
@@ -1369,7 +56,7 @@ async function stepImpl(name, fn, options) {
1369
56
  const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(started, traceSafety) : started;
1370
57
  await writeTraceEvent(safe, context.traceDir);
1371
58
  });
1372
- await safeInstrumentation2("printStepStart", () => {
59
+ await safeInstrumentation("printStepStart", () => {
1373
60
  printStepStart(stepName, renderDepth);
1374
61
  });
1375
62
  let result;
@@ -1381,7 +68,7 @@ async function stepImpl(name, fn, options) {
1381
68
  const endTime2 = Date.now();
1382
69
  const durationMs2 = endTime2 - startTime;
1383
70
  const formatted = formatError(userError);
1384
- await safeInstrumentation2("writeTraceEvent(step_completed error)", async () => {
71
+ await safeInstrumentation("writeTraceEvent(step_completed error)", async () => {
1385
72
  const completed = {
1386
73
  schemaVersion: "0.1",
1387
74
  event: "step_completed",
@@ -1396,20 +83,20 @@ async function stepImpl(name, fn, options) {
1396
83
  const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
1397
84
  await writeTraceEvent(safe, context.traceDir);
1398
85
  });
1399
- await safeInstrumentation2("printStepComplete(error)", () => {
86
+ await safeInstrumentation("printStepComplete(error)", () => {
1400
87
  printStepComplete(stepName, durationMs2, "error", renderDepth);
1401
88
  });
1402
- await safeInstrumentation2("printError", () => {
89
+ await safeInstrumentation("printError", () => {
1403
90
  printError(formatted, renderDepth);
1404
91
  });
1405
- await safeInstrumentation2("printFailedAt", () => {
92
+ await safeInstrumentation("printFailedAt", () => {
1406
93
  printFailedAt(stepName);
1407
94
  });
1408
95
  throw userError;
1409
96
  }
1410
97
  const endTime = Date.now();
1411
98
  const durationMs = endTime - startTime;
1412
- await safeInstrumentation2("writeTraceEvent(step_completed success)", async () => {
99
+ await safeInstrumentation("writeTraceEvent(step_completed success)", async () => {
1413
100
  const completed = {
1414
101
  schemaVersion: "0.1",
1415
102
  event: "step_completed",
@@ -1423,7 +110,7 @@ async function stepImpl(name, fn, options) {
1423
110
  const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
1424
111
  await writeTraceEvent(safe, context.traceDir);
1425
112
  });
1426
- await safeInstrumentation2("printStepComplete(success)", () => {
113
+ await safeInstrumentation("printStepComplete(success)", () => {
1427
114
  printStepComplete(stepName, durationMs, "success", renderDepth);
1428
115
  });
1429
116
  return result;
@@ -1521,6 +208,6 @@ function observe(agent, options) {
1521
208
  }
1522
209
  }
1523
210
 
1524
- export { TraceDirectory, buildRunReport, buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildTraceStats, extractMetadata, filterTraces, inspectRun, isAgentInspectEnabled, isAgentInspectTrace, loadTraceMetadataList, maybeInspectRun, observe, parseDurationFilter, renderRunWhat, renderTimeline, renderTraceStats, resolveTraceDir, searchTraces, step };
211
+ export { observe, step };
1525
212
  //# sourceMappingURL=index.mjs.map
1526
213
  //# sourceMappingURL=index.mjs.map