agent-inspect 1.9.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +27 -10
- package/docs/ADAPTER-CONFORMANCE.md +1 -1
- package/docs/ADAPTERS.md +4 -0
- package/docs/API.md +76 -35
- package/docs/CLI.md +129 -11
- package/docs/COMPARE.md +5 -4
- package/docs/EXPORTS.md +1 -1
- package/docs/GETTING-STARTED.md +26 -7
- package/docs/KNOWN-ISSUES.md +15 -3
- package/docs/LIMITATIONS.md +9 -7
- package/docs/MIGRATION.md +8 -8
- package/docs/SCHEMA.md +29 -12
- package/package.json +2 -2
- package/packages/cli/dist/index.cjs +9808 -8624
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +9807 -8623
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/advanced.cjs +2047 -26
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +346 -196
- package/packages/core/dist/advanced.d.ts +346 -196
- package/packages/core/dist/advanced.mjs +628 -5
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/checks.d.cts +1 -1
- package/packages/core/dist/checks.d.ts +1 -1
- package/packages/core/dist/chunk-2ZXEMWGK.mjs +549 -0
- package/packages/core/dist/chunk-2ZXEMWGK.mjs.map +1 -0
- package/packages/core/dist/{chunk-57S5D6HR.mjs → chunk-4JVGFNQH.mjs} +50 -6
- package/packages/core/dist/chunk-4JVGFNQH.mjs.map +1 -0
- package/packages/core/dist/{chunk-6QSLZCBJ.mjs → chunk-A4V2H3YU.mjs} +329 -163
- package/packages/core/dist/chunk-A4V2H3YU.mjs.map +1 -0
- package/packages/core/dist/{chunk-74XZ6N7Q.mjs → chunk-IZBJAZGF.mjs} +12 -4
- package/packages/core/dist/chunk-IZBJAZGF.mjs.map +1 -0
- package/packages/core/dist/{chunk-VTIB5MDK.mjs → chunk-NQZPZ2FN.mjs} +15 -10
- package/packages/core/dist/chunk-NQZPZ2FN.mjs.map +1 -0
- package/packages/core/dist/{chunk-TZISEVLQ.mjs → chunk-XUNJMAPD.mjs} +3 -3
- package/packages/core/dist/{chunk-TZISEVLQ.mjs.map → chunk-XUNJMAPD.mjs.map} +1 -1
- package/packages/core/dist/context-CSKnzpXR.d.cts +177 -0
- package/packages/core/dist/context-yv2VSDQF.d.ts +177 -0
- package/packages/core/dist/diff.d.cts +2 -2
- package/packages/core/dist/diff.d.ts +2 -2
- package/packages/core/dist/diff.mjs +473 -3
- package/packages/core/dist/diff.mjs.map +1 -1
- package/packages/core/dist/exporters.cjs +691 -0
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.d.cts +24 -3
- package/packages/core/dist/exporters.d.ts +24 -3
- package/packages/core/dist/exporters.mjs +1113 -3
- package/packages/core/dist/exporters.mjs.map +1 -1
- package/packages/core/dist/index.cjs +1385 -8168
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.d.cts +8 -350
- package/packages/core/dist/index.d.ts +8 -350
- package/packages/core/dist/index.mjs +18 -1478
- package/packages/core/dist/index.mjs.map +1 -1
- package/packages/core/dist/{log-config-DanPV3P9.d.cts → log-config-8aE5Kxtr.d.cts} +1 -1
- package/packages/core/dist/{log-config-BPHS4Sds.d.ts → log-config-DVimQJho.d.ts} +1 -1
- package/packages/core/dist/logs.d.cts +2 -2
- package/packages/core/dist/logs.d.ts +2 -2
- package/packages/core/dist/logs.mjs +785 -2
- package/packages/core/dist/logs.mjs.map +1 -1
- package/packages/core/dist/{persisted-inspect-event-Cw7TeYGr.d.ts → persisted-inspect-event-D-WpXeZX.d.ts} +14 -5
- package/packages/core/dist/{persisted-inspect-event-DHPfzUd8.d.cts → persisted-inspect-event-DHcHPUKv.d.cts} +14 -5
- package/packages/core/dist/persisted.cjs +11 -1
- package/packages/core/dist/persisted.cjs.map +1 -1
- package/packages/core/dist/persisted.d.cts +4 -4
- package/packages/core/dist/persisted.d.ts +4 -4
- package/packages/core/dist/persisted.mjs +150 -3
- package/packages/core/dist/persisted.mjs.map +1 -1
- package/packages/core/dist/readers.cjs +27 -10
- package/packages/core/dist/readers.cjs.map +1 -1
- package/packages/core/dist/readers.d.cts +1 -1
- package/packages/core/dist/readers.d.ts +1 -1
- package/packages/core/dist/readers.mjs +1580 -4
- package/packages/core/dist/readers.mjs.map +1 -1
- package/packages/core/dist/{types-Ap9uMdx_.d.ts → types-D-Y1kOU-.d.ts} +2 -2
- package/packages/core/dist/{types-B2-BU5CS.d.cts → types-DgMN3qow.d.cts} +2 -2
- package/packages/core/dist/writers.cjs +49 -3
- package/packages/core/dist/writers.cjs.map +1 -1
- package/packages/core/dist/writers.d.cts +1 -1
- package/packages/core/dist/writers.d.ts +1 -1
- package/packages/core/dist/writers.mjs +341 -4
- package/packages/core/dist/writers.mjs.map +1 -1
- package/packages/core/dist/chunk-57S5D6HR.mjs.map +0 -1
- package/packages/core/dist/chunk-6QSLZCBJ.mjs.map +0 -1
- package/packages/core/dist/chunk-6SZPTECC.mjs +0 -342
- package/packages/core/dist/chunk-6SZPTECC.mjs.map +0 -1
- package/packages/core/dist/chunk-74XZ6N7Q.mjs.map +0 -1
- package/packages/core/dist/chunk-HR7G62IE.mjs +0 -785
- package/packages/core/dist/chunk-HR7G62IE.mjs.map +0 -1
- package/packages/core/dist/chunk-TFLPUZ56.mjs +0 -1571
- package/packages/core/dist/chunk-TFLPUZ56.mjs.map +0 -1
- package/packages/core/dist/chunk-U2BGPESY.mjs +0 -150
- package/packages/core/dist/chunk-U2BGPESY.mjs.map +0 -1
- package/packages/core/dist/chunk-VTIB5MDK.mjs.map +0 -1
- package/packages/core/dist/chunk-Y56BPA3B.mjs +0 -990
- package/packages/core/dist/chunk-Y56BPA3B.mjs.map +0 -1
- package/packages/core/dist/chunk-YWAOOXLR.mjs +0 -475
- package/packages/core/dist/chunk-YWAOOXLR.mjs.map +0 -1
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var crypto = require('crypto');
|
|
4
|
+
require('fs/promises');
|
|
5
|
+
var os = require('os');
|
|
6
|
+
var path = require('path');
|
|
4
7
|
|
|
5
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
9
|
|
|
7
10
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
11
|
+
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
12
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
8
13
|
|
|
9
14
|
// packages/core/src/exporters/types.ts
|
|
10
15
|
var EXPORT_PAYLOAD_VERSION = "0.1.2";
|
|
@@ -282,6 +287,89 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
|
|
|
282
287
|
}
|
|
283
288
|
return bounded;
|
|
284
289
|
}
|
|
290
|
+
function redactErrorInfo(error, redactor, maxMetadataValueLength, maxPreviewLength) {
|
|
291
|
+
if (error === void 0) return void 0;
|
|
292
|
+
const record = redactEventAttributes(
|
|
293
|
+
{ error },
|
|
294
|
+
redactor,
|
|
295
|
+
maxMetadataValueLength,
|
|
296
|
+
maxPreviewLength
|
|
297
|
+
);
|
|
298
|
+
const redacted = record?.error;
|
|
299
|
+
if (!isRecord2(redacted) || typeof redacted.message !== "string") {
|
|
300
|
+
return void 0;
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
message: redacted.message,
|
|
304
|
+
...typeof redacted.stack === "string" ? { stack: redacted.stack } : {}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function redactTraceEventsForReport(events, options) {
|
|
308
|
+
const profile = options?.redactionProfile ?? "local";
|
|
309
|
+
if (profile === "local") {
|
|
310
|
+
return deepClone(events);
|
|
311
|
+
}
|
|
312
|
+
const resolved = resolveRedactionProfile(profile);
|
|
313
|
+
const { maxMetadataValueLength, maxPreviewLength } = applyProfileMetadataCaps(
|
|
314
|
+
2e3,
|
|
315
|
+
500,
|
|
316
|
+
resolved
|
|
317
|
+
);
|
|
318
|
+
const redactor = new Redactor({ extraKeys: resolved.extraKeys });
|
|
319
|
+
return events.map((event) => {
|
|
320
|
+
switch (event.event) {
|
|
321
|
+
case "run_started":
|
|
322
|
+
return {
|
|
323
|
+
...event,
|
|
324
|
+
name: truncateStringForProfile(
|
|
325
|
+
event.name,
|
|
326
|
+
"name",
|
|
327
|
+
maxMetadataValueLength,
|
|
328
|
+
maxPreviewLength
|
|
329
|
+
),
|
|
330
|
+
...event.metadata !== void 0 ? {
|
|
331
|
+
metadata: redactEventAttributes(
|
|
332
|
+
event.metadata,
|
|
333
|
+
redactor,
|
|
334
|
+
maxMetadataValueLength,
|
|
335
|
+
maxPreviewLength
|
|
336
|
+
)
|
|
337
|
+
} : {}
|
|
338
|
+
};
|
|
339
|
+
case "step_started":
|
|
340
|
+
return {
|
|
341
|
+
...event,
|
|
342
|
+
name: truncateStringForProfile(
|
|
343
|
+
event.name,
|
|
344
|
+
"name",
|
|
345
|
+
maxMetadataValueLength,
|
|
346
|
+
maxPreviewLength
|
|
347
|
+
),
|
|
348
|
+
...event.metadata !== void 0 ? {
|
|
349
|
+
metadata: redactEventAttributes(
|
|
350
|
+
event.metadata,
|
|
351
|
+
redactor,
|
|
352
|
+
maxMetadataValueLength,
|
|
353
|
+
maxPreviewLength
|
|
354
|
+
)
|
|
355
|
+
} : {}
|
|
356
|
+
};
|
|
357
|
+
case "run_completed":
|
|
358
|
+
case "step_completed":
|
|
359
|
+
return {
|
|
360
|
+
...event,
|
|
361
|
+
...event.error !== void 0 ? {
|
|
362
|
+
error: redactErrorInfo(
|
|
363
|
+
event.error,
|
|
364
|
+
redactor,
|
|
365
|
+
maxMetadataValueLength,
|
|
366
|
+
maxPreviewLength
|
|
367
|
+
)
|
|
368
|
+
} : {}
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
}
|
|
285
373
|
function redactRunTreeForExport(tree, options) {
|
|
286
374
|
const profile = options?.redactionProfile ?? "local";
|
|
287
375
|
if (profile === "local") {
|
|
@@ -1206,7 +1294,610 @@ function validateExport(result) {
|
|
|
1206
1294
|
};
|
|
1207
1295
|
}
|
|
1208
1296
|
|
|
1297
|
+
// packages/core/src/utils/duration.ts
|
|
1298
|
+
function formatDuration(ms) {
|
|
1299
|
+
if (!Number.isFinite(ms)) {
|
|
1300
|
+
return "0ms";
|
|
1301
|
+
}
|
|
1302
|
+
if (ms < 0) {
|
|
1303
|
+
throw new Error(`formatDuration: ms must be non-negative (got ${ms})`);
|
|
1304
|
+
}
|
|
1305
|
+
if (ms < 1e3) {
|
|
1306
|
+
return `${Math.floor(ms)}ms`;
|
|
1307
|
+
}
|
|
1308
|
+
if (ms < 6e4) {
|
|
1309
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
1310
|
+
}
|
|
1311
|
+
if (ms < 36e5) {
|
|
1312
|
+
return `${(ms / 6e4).toFixed(1)}m`;
|
|
1313
|
+
}
|
|
1314
|
+
return `${(ms / 36e5).toFixed(1)}h`;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
// packages/core/src/utils.ts
|
|
1318
|
+
var RUNS_DIR_NAME = "runs";
|
|
1319
|
+
path__default.default.join(
|
|
1320
|
+
os__default.default.tmpdir(),
|
|
1321
|
+
"agent-inspect",
|
|
1322
|
+
RUNS_DIR_NAME
|
|
1323
|
+
);
|
|
1324
|
+
function formatDuration2(ms) {
|
|
1325
|
+
return formatDuration(ms);
|
|
1326
|
+
}
|
|
1327
|
+
function formatTimestamp(timestamp) {
|
|
1328
|
+
if (!Number.isFinite(timestamp)) {
|
|
1329
|
+
return "Invalid date";
|
|
1330
|
+
}
|
|
1331
|
+
const d = new Date(timestamp);
|
|
1332
|
+
if (Number.isNaN(d.getTime())) {
|
|
1333
|
+
return "Invalid date";
|
|
1334
|
+
}
|
|
1335
|
+
const y = d.getFullYear();
|
|
1336
|
+
const mo = String(d.getMonth() + 1).padStart(2, "0");
|
|
1337
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
1338
|
+
const h = String(d.getHours()).padStart(2, "0");
|
|
1339
|
+
const min = String(d.getMinutes()).padStart(2, "0");
|
|
1340
|
+
const s = String(d.getSeconds()).padStart(2, "0");
|
|
1341
|
+
return `${y}-${mo}-${day} ${h}:${min}:${s}`;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
// packages/core/src/timeline.ts
|
|
1345
|
+
function finite(n) {
|
|
1346
|
+
return typeof n === "number" && Number.isFinite(n);
|
|
1347
|
+
}
|
|
1348
|
+
function pickStreamingMeta(metadata) {
|
|
1349
|
+
if (!metadata || typeof metadata !== "object") return void 0;
|
|
1350
|
+
const chunkCount = metadata.chunkCount;
|
|
1351
|
+
const streamDurationMs = metadata.streamDurationMs;
|
|
1352
|
+
const streamedCharCount = metadata.streamedCharCount;
|
|
1353
|
+
if (!finite(chunkCount) && !finite(streamDurationMs) && !finite(streamedCharCount)) {
|
|
1354
|
+
return void 0;
|
|
1355
|
+
}
|
|
1356
|
+
return {
|
|
1357
|
+
...finite(chunkCount) ? { chunkCount } : {},
|
|
1358
|
+
...finite(streamDurationMs) ? { streamDurationMs } : {},
|
|
1359
|
+
...finite(streamedCharCount) ? { streamedCharCount } : {}
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1362
|
+
function pickCorrelation(metadata) {
|
|
1363
|
+
if (!metadata || typeof metadata !== "object") return void 0;
|
|
1364
|
+
const out = {};
|
|
1365
|
+
for (const key of [
|
|
1366
|
+
"correlationId",
|
|
1367
|
+
"requestId",
|
|
1368
|
+
"decisionId",
|
|
1369
|
+
"groupId"
|
|
1370
|
+
]) {
|
|
1371
|
+
const v = metadata[key];
|
|
1372
|
+
if (typeof v === "string" && v.trim() !== "") {
|
|
1373
|
+
out[key] = v;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
1377
|
+
}
|
|
1378
|
+
function buildRunTimeline(events, options = {}) {
|
|
1379
|
+
const started = events.find(
|
|
1380
|
+
(e) => e.event === "run_started"
|
|
1381
|
+
);
|
|
1382
|
+
const completed = events.filter(
|
|
1383
|
+
(e) => e.event === "run_completed"
|
|
1384
|
+
);
|
|
1385
|
+
const lastCompleted = completed[completed.length - 1];
|
|
1386
|
+
const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
|
|
1387
|
+
const runStart = started && finite(started.startTime) ? started.startTime : started && finite(started.timestamp) ? started.timestamp : void 0;
|
|
1388
|
+
const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
|
|
1389
|
+
const steps = /* @__PURE__ */ new Map();
|
|
1390
|
+
for (const e of events) {
|
|
1391
|
+
if (e.event === "step_started") {
|
|
1392
|
+
const s = e;
|
|
1393
|
+
steps.set(s.stepId, {
|
|
1394
|
+
name: s.name,
|
|
1395
|
+
type: s.type,
|
|
1396
|
+
parentId: s.parentId,
|
|
1397
|
+
startedAt: finite(s.startTime) ? s.startTime : s.timestamp,
|
|
1398
|
+
status: "running",
|
|
1399
|
+
metadata: s.metadata
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
for (const e of events) {
|
|
1404
|
+
if (e.event !== "step_completed") continue;
|
|
1405
|
+
const c = e;
|
|
1406
|
+
const node = steps.get(c.stepId);
|
|
1407
|
+
if (!node) continue;
|
|
1408
|
+
node.status = c.status;
|
|
1409
|
+
if (finite(c.durationMs)) node.durationMs = c.durationMs;
|
|
1410
|
+
}
|
|
1411
|
+
const depthCache = /* @__PURE__ */ new Map();
|
|
1412
|
+
const computeDepth = (stepId) => {
|
|
1413
|
+
const cached = depthCache.get(stepId);
|
|
1414
|
+
if (cached !== void 0) return cached;
|
|
1415
|
+
const node = steps.get(stepId);
|
|
1416
|
+
if (!node) return 0;
|
|
1417
|
+
const parent = node.parentId;
|
|
1418
|
+
if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
|
|
1419
|
+
depthCache.set(stepId, 0);
|
|
1420
|
+
return 0;
|
|
1421
|
+
}
|
|
1422
|
+
const d = Math.min(1e3, computeDepth(parent) + 1);
|
|
1423
|
+
depthCache.set(stepId, d);
|
|
1424
|
+
return d;
|
|
1425
|
+
};
|
|
1426
|
+
const entries = [];
|
|
1427
|
+
for (const [stepId, s] of steps.entries()) {
|
|
1428
|
+
const offsetMs = runStart !== void 0 && finite(s.startedAt) ? Math.max(0, s.startedAt - runStart) : 0;
|
|
1429
|
+
entries.push({
|
|
1430
|
+
stepId,
|
|
1431
|
+
name: s.name,
|
|
1432
|
+
type: s.type,
|
|
1433
|
+
status: s.status,
|
|
1434
|
+
depth: computeDepth(stepId),
|
|
1435
|
+
startedAt: s.startedAt,
|
|
1436
|
+
offsetMs,
|
|
1437
|
+
durationMs: s.durationMs,
|
|
1438
|
+
isError: s.status === "error",
|
|
1439
|
+
streaming: pickStreamingMeta(s.metadata)
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
entries.sort((a, b) => a.startedAt - b.startedAt);
|
|
1443
|
+
const slowTopN = options.slowTopN ?? 3;
|
|
1444
|
+
if (options.focus === "slow" && entries.length > 0) {
|
|
1445
|
+
const ranked = [...entries].filter((e) => finite(e.durationMs)).sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
|
|
1446
|
+
const slowIds = new Set(
|
|
1447
|
+
ranked.slice(0, slowTopN).map((e) => e.stepId)
|
|
1448
|
+
);
|
|
1449
|
+
for (const e of entries) {
|
|
1450
|
+
if (slowIds.has(e.stepId)) e.slow = true;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
return {
|
|
1454
|
+
runId,
|
|
1455
|
+
name: typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0,
|
|
1456
|
+
status,
|
|
1457
|
+
startedAt: runStart,
|
|
1458
|
+
endedAt: lastCompleted && finite(lastCompleted.endTime) ? lastCompleted.endTime : void 0,
|
|
1459
|
+
durationMs: lastCompleted && finite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0,
|
|
1460
|
+
correlation: pickCorrelation(
|
|
1461
|
+
started?.metadata
|
|
1462
|
+
),
|
|
1463
|
+
entries
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
function renderTimeline(timeline, options = {}) {
|
|
1467
|
+
const lines = [];
|
|
1468
|
+
lines.push(`Timeline: ${timeline.name ?? timeline.runId}`);
|
|
1469
|
+
lines.push(`Run ID: ${timeline.runId}`);
|
|
1470
|
+
lines.push(`Status: ${timeline.status}`);
|
|
1471
|
+
if (timeline.startedAt !== void 0) {
|
|
1472
|
+
lines.push(`Started: ${formatTimestamp(timeline.startedAt)}`);
|
|
1473
|
+
}
|
|
1474
|
+
if (timeline.durationMs !== void 0) {
|
|
1475
|
+
lines.push(`Duration: ${formatDuration2(timeline.durationMs)}`);
|
|
1476
|
+
}
|
|
1477
|
+
if (timeline.correlation) {
|
|
1478
|
+
const parts = Object.entries(timeline.correlation).filter(([, v]) => typeof v === "string").map(([k, v]) => `${k}=${v}`);
|
|
1479
|
+
if (parts.length > 0) {
|
|
1480
|
+
lines.push(`Correlation: ${parts.join(", ")}`);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
lines.push("");
|
|
1484
|
+
lines.push("Steps (chronological):");
|
|
1485
|
+
const show = timeline.entries.filter((e) => {
|
|
1486
|
+
if (options.focus === "slow") return e.slow === true;
|
|
1487
|
+
return true;
|
|
1488
|
+
});
|
|
1489
|
+
if (show.length === 0) {
|
|
1490
|
+
lines.push(
|
|
1491
|
+
options.focus === "slow" ? "(no steps with duration for slow focus)" : "(no steps)"
|
|
1492
|
+
);
|
|
1493
|
+
return lines.join("\n");
|
|
1494
|
+
}
|
|
1495
|
+
for (const e of show) {
|
|
1496
|
+
const prefix = e.slow ? "[slow] " : "";
|
|
1497
|
+
const typeTag = e.type === "llm" ? "llm" : e.type === "tool" ? "tool" : e.type;
|
|
1498
|
+
const dur = e.durationMs !== void 0 ? formatDuration2(e.durationMs) : "-";
|
|
1499
|
+
const err = e.isError ? " error" : "";
|
|
1500
|
+
const off = formatDuration2(e.offsetMs);
|
|
1501
|
+
let line = `${prefix}+${off} ${typeTag}:${e.name} (${dur})${err}`;
|
|
1502
|
+
if (e.streaming?.chunkCount !== void 0) {
|
|
1503
|
+
line += ` chunks=${e.streaming.chunkCount}`;
|
|
1504
|
+
}
|
|
1505
|
+
if (e.streaming?.streamDurationMs !== void 0) {
|
|
1506
|
+
line += ` stream=${formatDuration2(e.streaming.streamDurationMs)}`;
|
|
1507
|
+
}
|
|
1508
|
+
lines.push(line);
|
|
1509
|
+
}
|
|
1510
|
+
return lines.join("\n");
|
|
1511
|
+
}
|
|
1512
|
+
function isFiniteNumber(v) {
|
|
1513
|
+
return typeof v === "number" && Number.isFinite(v);
|
|
1514
|
+
}
|
|
1515
|
+
function isNonNegativeFiniteNumber(value) {
|
|
1516
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
1517
|
+
}
|
|
1518
|
+
function buildRunSummary(events) {
|
|
1519
|
+
const started = events.find(
|
|
1520
|
+
(e) => e.event === "run_started"
|
|
1521
|
+
);
|
|
1522
|
+
const completed = events.filter(
|
|
1523
|
+
(e) => e.event === "run_completed"
|
|
1524
|
+
);
|
|
1525
|
+
const lastCompleted = completed[completed.length - 1];
|
|
1526
|
+
const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
|
|
1527
|
+
const name = typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0;
|
|
1528
|
+
const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
|
|
1529
|
+
const durationMs = lastCompleted && isFiniteNumber(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
1530
|
+
started && isFiniteNumber(started.startTime) ? started.startTime : void 0;
|
|
1531
|
+
const steps = /* @__PURE__ */ new Map();
|
|
1532
|
+
for (const e of events) {
|
|
1533
|
+
if (e.event === "step_started") {
|
|
1534
|
+
const s = e;
|
|
1535
|
+
steps.set(s.stepId, {
|
|
1536
|
+
type: s.type,
|
|
1537
|
+
name: s.name,
|
|
1538
|
+
status: "running",
|
|
1539
|
+
parentId: s.parentId,
|
|
1540
|
+
tokensInput: isNonNegativeFiniteNumber(s.metadata?.tokens?.input) ? s.metadata.tokens.input : void 0,
|
|
1541
|
+
tokensOutput: isNonNegativeFiniteNumber(s.metadata?.tokens?.output) ? s.metadata.tokens.output : void 0,
|
|
1542
|
+
tokensTotal: isNonNegativeFiniteNumber(s.metadata?.tokens?.total) ? s.metadata.tokens.total : void 0,
|
|
1543
|
+
tokensCached: isNonNegativeFiniteNumber(s.metadata?.tokens?.cached) ? s.metadata.tokens.cached : void 0
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
for (const e of events) {
|
|
1548
|
+
if (e.event === "step_completed") {
|
|
1549
|
+
const c = e;
|
|
1550
|
+
const existing = steps.get(c.stepId);
|
|
1551
|
+
if (!existing) continue;
|
|
1552
|
+
existing.status = c.status;
|
|
1553
|
+
existing.durationMs = c.durationMs;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
let totalSteps = 0;
|
|
1557
|
+
let llmSteps = 0;
|
|
1558
|
+
let toolSteps = 0;
|
|
1559
|
+
let logicSteps = 0;
|
|
1560
|
+
let errorSteps = 0;
|
|
1561
|
+
let maxDepth = 0;
|
|
1562
|
+
let longestStep;
|
|
1563
|
+
let totalTokensInput = 0;
|
|
1564
|
+
let totalTokensOutput = 0;
|
|
1565
|
+
let totalTokensTotal = 0;
|
|
1566
|
+
let totalTokensCached = 0;
|
|
1567
|
+
let tokenBearingSteps = 0;
|
|
1568
|
+
let stepsWithKnownTotal = 0;
|
|
1569
|
+
let hasCachedTokens = false;
|
|
1570
|
+
const depthCache = /* @__PURE__ */ new Map();
|
|
1571
|
+
const computeDepth = (stepId) => {
|
|
1572
|
+
const cached = depthCache.get(stepId);
|
|
1573
|
+
if (cached !== void 0) return cached;
|
|
1574
|
+
const node = steps.get(stepId);
|
|
1575
|
+
if (!node) return 0;
|
|
1576
|
+
const parent = node.parentId;
|
|
1577
|
+
if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
|
|
1578
|
+
depthCache.set(stepId, 0);
|
|
1579
|
+
return 0;
|
|
1580
|
+
}
|
|
1581
|
+
const d = Math.min(1e3, computeDepth(parent) + 1);
|
|
1582
|
+
depthCache.set(stepId, d);
|
|
1583
|
+
return d;
|
|
1584
|
+
};
|
|
1585
|
+
for (const [id, s] of steps.entries()) {
|
|
1586
|
+
totalSteps += 1;
|
|
1587
|
+
if (s.type === "llm") llmSteps += 1;
|
|
1588
|
+
else if (s.type === "tool") toolSteps += 1;
|
|
1589
|
+
else logicSteps += 1;
|
|
1590
|
+
if (s.status === "error") errorSteps += 1;
|
|
1591
|
+
const depth = computeDepth(id);
|
|
1592
|
+
if (depth > maxDepth) maxDepth = depth;
|
|
1593
|
+
if (typeof s.durationMs === "number" && Number.isFinite(s.durationMs)) {
|
|
1594
|
+
if (!longestStep || s.durationMs > longestStep.durationMs) {
|
|
1595
|
+
longestStep = { name: s.name, durationMs: s.durationMs, type: s.type };
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
if (s.tokensInput !== void 0 || s.tokensOutput !== void 0 || s.tokensTotal !== void 0 || s.tokensCached !== void 0) {
|
|
1599
|
+
tokenBearingSteps += 1;
|
|
1600
|
+
if (s.tokensInput !== void 0) totalTokensInput += s.tokensInput;
|
|
1601
|
+
if (s.tokensOutput !== void 0) totalTokensOutput += s.tokensOutput;
|
|
1602
|
+
if (s.tokensTotal !== void 0) {
|
|
1603
|
+
totalTokensTotal += s.tokensTotal;
|
|
1604
|
+
stepsWithKnownTotal += 1;
|
|
1605
|
+
} else if (s.tokensInput !== void 0 && s.tokensOutput !== void 0) {
|
|
1606
|
+
totalTokensTotal += s.tokensInput + s.tokensOutput;
|
|
1607
|
+
stepsWithKnownTotal += 1;
|
|
1608
|
+
}
|
|
1609
|
+
if (s.tokensCached !== void 0) {
|
|
1610
|
+
totalTokensCached += s.tokensCached;
|
|
1611
|
+
hasCachedTokens = true;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
const summary = {
|
|
1616
|
+
runId,
|
|
1617
|
+
name,
|
|
1618
|
+
status,
|
|
1619
|
+
durationMs,
|
|
1620
|
+
totalSteps,
|
|
1621
|
+
llmSteps,
|
|
1622
|
+
toolSteps,
|
|
1623
|
+
logicSteps,
|
|
1624
|
+
errorSteps,
|
|
1625
|
+
maxDepth,
|
|
1626
|
+
...longestStep ? { longestStep } : {},
|
|
1627
|
+
...tokenBearingSteps > 0 ? {
|
|
1628
|
+
totalTokens: {
|
|
1629
|
+
input: totalTokensInput,
|
|
1630
|
+
output: totalTokensOutput,
|
|
1631
|
+
...stepsWithKnownTotal === tokenBearingSteps ? { total: totalTokensTotal } : {},
|
|
1632
|
+
...hasCachedTokens ? { cached: totalTokensCached } : {}
|
|
1633
|
+
}
|
|
1634
|
+
} : {}
|
|
1635
|
+
};
|
|
1636
|
+
return summary;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// packages/core/src/what.ts
|
|
1640
|
+
function pickCorrelation2(metadata) {
|
|
1641
|
+
if (!metadata) return void 0;
|
|
1642
|
+
const out = {};
|
|
1643
|
+
for (const key of [
|
|
1644
|
+
"correlationId",
|
|
1645
|
+
"requestId",
|
|
1646
|
+
"decisionId",
|
|
1647
|
+
"groupId"
|
|
1648
|
+
]) {
|
|
1649
|
+
const value = metadata[key];
|
|
1650
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
1651
|
+
out[key] = value;
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
1655
|
+
}
|
|
1656
|
+
function stepMixLine(summary) {
|
|
1657
|
+
const parts = [];
|
|
1658
|
+
if (summary.llmSteps > 0) parts.push(`${summary.llmSteps} LLM`);
|
|
1659
|
+
if (summary.toolSteps > 0) parts.push(`${summary.toolSteps} tool`);
|
|
1660
|
+
if (summary.logicSteps > 0) parts.push(`${summary.logicSteps} logic`);
|
|
1661
|
+
return parts.length > 0 ? parts.join(", ") : "none";
|
|
1662
|
+
}
|
|
1663
|
+
function outcomeLine(summary) {
|
|
1664
|
+
if (summary.status === "success") {
|
|
1665
|
+
return summary.errorSteps > 0 ? "Completed with step errors recorded." : "Completed successfully.";
|
|
1666
|
+
}
|
|
1667
|
+
if (summary.status === "error") {
|
|
1668
|
+
if (summary.failedStepNames.length > 0) {
|
|
1669
|
+
const names = summary.failedStepNames.slice(0, 3).join(", ");
|
|
1670
|
+
const suffix = summary.failedStepNames.length > 3 ? ` (+${summary.failedStepNames.length - 3} more)` : "";
|
|
1671
|
+
return `Failed at step(s): ${names}${suffix}.`;
|
|
1672
|
+
}
|
|
1673
|
+
if (summary.runErrorMessage) {
|
|
1674
|
+
return `Run failed: ${summary.runErrorMessage}`;
|
|
1675
|
+
}
|
|
1676
|
+
return "Run failed.";
|
|
1677
|
+
}
|
|
1678
|
+
if (summary.status === "running") {
|
|
1679
|
+
return "Run is still in progress (no run_completed).";
|
|
1680
|
+
}
|
|
1681
|
+
return "Outcome unknown \u2014 inspect events may be incomplete.";
|
|
1682
|
+
}
|
|
1683
|
+
function buildRunWhatSummary(events) {
|
|
1684
|
+
const base = buildRunSummary(events);
|
|
1685
|
+
const started = events.find(
|
|
1686
|
+
(e) => e.event === "run_started"
|
|
1687
|
+
);
|
|
1688
|
+
const completed = events.filter(
|
|
1689
|
+
(e) => e.event === "run_completed"
|
|
1690
|
+
);
|
|
1691
|
+
const lastCompleted = completed[completed.length - 1];
|
|
1692
|
+
const failedStepNames = [];
|
|
1693
|
+
const stepNames = /* @__PURE__ */ new Map();
|
|
1694
|
+
for (const e of events) {
|
|
1695
|
+
if (e.event === "step_started") {
|
|
1696
|
+
const s = e;
|
|
1697
|
+
stepNames.set(s.stepId, s.name);
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
for (const e of events) {
|
|
1701
|
+
if (e.event === "step_completed") {
|
|
1702
|
+
const sc = e;
|
|
1703
|
+
if (sc.status === "error") {
|
|
1704
|
+
failedStepNames.push(stepNames.get(sc.stepId) ?? sc.stepId);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
return {
|
|
1709
|
+
runId: base.runId,
|
|
1710
|
+
name: base.name,
|
|
1711
|
+
status: base.status,
|
|
1712
|
+
durationMs: base.durationMs,
|
|
1713
|
+
totalSteps: base.totalSteps,
|
|
1714
|
+
llmSteps: base.llmSteps,
|
|
1715
|
+
toolSteps: base.toolSteps,
|
|
1716
|
+
logicSteps: base.logicSteps,
|
|
1717
|
+
errorSteps: base.errorSteps,
|
|
1718
|
+
maxDepth: base.maxDepth,
|
|
1719
|
+
longestStep: base.longestStep,
|
|
1720
|
+
totalTokens: base.totalTokens,
|
|
1721
|
+
correlation: pickCorrelation2(started?.metadata),
|
|
1722
|
+
failedStepNames,
|
|
1723
|
+
runErrorMessage: lastCompleted?.error?.message
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
function renderRunWhat(summary, options = {}) {
|
|
1727
|
+
const showCorrelation = options.correlation !== false;
|
|
1728
|
+
const lines = [];
|
|
1729
|
+
const label = summary.name ?? summary.runId;
|
|
1730
|
+
lines.push(`What: ${label}`);
|
|
1731
|
+
const duration = summary.durationMs !== void 0 ? formatDuration2(summary.durationMs) : "\u2014";
|
|
1732
|
+
lines.push(
|
|
1733
|
+
`Status: ${summary.status} \xB7 Duration: ${duration} \xB7 Steps: ${summary.totalSteps} (${stepMixLine(summary)})`
|
|
1734
|
+
);
|
|
1735
|
+
if (summary.totalTokens) {
|
|
1736
|
+
const tokenParts = [
|
|
1737
|
+
`${summary.totalTokens.input} in`,
|
|
1738
|
+
`${summary.totalTokens.output} out`
|
|
1739
|
+
];
|
|
1740
|
+
if (summary.totalTokens.total !== void 0) {
|
|
1741
|
+
tokenParts.push(`${summary.totalTokens.total} total`);
|
|
1742
|
+
}
|
|
1743
|
+
if (summary.totalTokens.cached !== void 0) {
|
|
1744
|
+
tokenParts.push(`${summary.totalTokens.cached} cached`);
|
|
1745
|
+
}
|
|
1746
|
+
lines.push(`Tokens: ${tokenParts.join(" / ")}`);
|
|
1747
|
+
}
|
|
1748
|
+
if (showCorrelation && summary.correlation) {
|
|
1749
|
+
const parts = [];
|
|
1750
|
+
if (summary.correlation.correlationId) {
|
|
1751
|
+
parts.push(`correlationId=${summary.correlation.correlationId}`);
|
|
1752
|
+
}
|
|
1753
|
+
if (summary.correlation.requestId) {
|
|
1754
|
+
parts.push(`requestId=${summary.correlation.requestId}`);
|
|
1755
|
+
}
|
|
1756
|
+
if (summary.correlation.decisionId) {
|
|
1757
|
+
parts.push(`decisionId=${summary.correlation.decisionId}`);
|
|
1758
|
+
}
|
|
1759
|
+
if (summary.correlation.groupId) {
|
|
1760
|
+
parts.push(`groupId=${summary.correlation.groupId}`);
|
|
1761
|
+
}
|
|
1762
|
+
if (parts.length > 0) {
|
|
1763
|
+
lines.push(`Correlation: ${parts.join(", ")}`);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
lines.push(`Outcome: ${outcomeLine(summary)}`);
|
|
1767
|
+
if (summary.longestStep && summary.totalSteps > 0) {
|
|
1768
|
+
lines.push(
|
|
1769
|
+
`Slowest: ${summary.longestStep.name} (${formatDuration2(summary.longestStep.durationMs)}, ${summary.longestStep.type})`
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
if (summary.maxDepth > 0) {
|
|
1773
|
+
lines.push(`Max depth: ${summary.maxDepth}`);
|
|
1774
|
+
}
|
|
1775
|
+
return lines.join("\n");
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
// packages/core/src/report.ts
|
|
1779
|
+
function resolveTree(events, profile) {
|
|
1780
|
+
const tree = manualTraceEventsToRunTree(events);
|
|
1781
|
+
return profile === "local" ? tree : redactRunTreeForExport(tree, { redactionProfile: profile });
|
|
1782
|
+
}
|
|
1783
|
+
function tailMarkdownSection(content, heading) {
|
|
1784
|
+
const marker = `## ${heading}`;
|
|
1785
|
+
const idx = content.indexOf(marker);
|
|
1786
|
+
if (idx < 0) return "";
|
|
1787
|
+
return content.slice(idx).trimEnd();
|
|
1788
|
+
}
|
|
1789
|
+
function extractHtmlFragment(content, start, end) {
|
|
1790
|
+
const startIdx = content.indexOf(start);
|
|
1791
|
+
if (startIdx < 0) return "";
|
|
1792
|
+
const endIdx = content.indexOf(end, startIdx + start.length);
|
|
1793
|
+
if (endIdx < 0) return content.slice(startIdx);
|
|
1794
|
+
return content.slice(startIdx, endIdx);
|
|
1795
|
+
}
|
|
1796
|
+
var REPORT_HTML_CSS = `
|
|
1797
|
+
body{font-family:system-ui,sans-serif;line-height:1.5;margin:1.5rem;max-width:960px;color:#111}
|
|
1798
|
+
h1{font-size:1.35rem}
|
|
1799
|
+
h2{font-size:1.1rem;margin-top:1.5rem}
|
|
1800
|
+
pre{white-space:pre-wrap;background:#f8f8f8;padding:0.75rem;overflow:auto;font-size:0.9rem}
|
|
1801
|
+
ul.tree{list-style:none;padding-left:1rem}
|
|
1802
|
+
ul.tree.nested{padding-left:1.25rem;border-left:1px solid #ddd;margin:0.25rem 0}
|
|
1803
|
+
.nm{font-weight:600}
|
|
1804
|
+
.meta{color:#555;font-size:0.9rem}
|
|
1805
|
+
footer{margin-top:2rem;font-size:0.85rem;color:#555}
|
|
1806
|
+
`.trim();
|
|
1807
|
+
function buildRunReport(events, options) {
|
|
1808
|
+
const profile = options.redactionProfile ?? "local";
|
|
1809
|
+
const safeEvents = redactTraceEventsForReport(events, {
|
|
1810
|
+
redactionProfile: profile
|
|
1811
|
+
});
|
|
1812
|
+
const whatSummary = buildRunWhatSummary(safeEvents);
|
|
1813
|
+
const whatText = renderRunWhat(whatSummary, {
|
|
1814
|
+
correlation: options.correlation !== false
|
|
1815
|
+
});
|
|
1816
|
+
const timelineText = renderTimeline(buildRunTimeline(safeEvents));
|
|
1817
|
+
const tree = resolveTree(safeEvents, profile);
|
|
1818
|
+
const exportOpts = {
|
|
1819
|
+
includeMetadata: false,
|
|
1820
|
+
includeAttributes: options.includeAttributes === true,
|
|
1821
|
+
includeErrors: options.includeErrors !== false,
|
|
1822
|
+
redacted: true,
|
|
1823
|
+
maxAttributeLength: 500
|
|
1824
|
+
};
|
|
1825
|
+
if (options.format === "markdown") {
|
|
1826
|
+
const treeMd = exportMarkdown(tree, exportOpts);
|
|
1827
|
+
const tail = tailMarkdownSection(treeMd.content, "Execution tree");
|
|
1828
|
+
const title2 = escapeMarkdown(whatSummary.name ?? whatSummary.runId);
|
|
1829
|
+
const lines = [
|
|
1830
|
+
`# AgentInspect Report: ${title2}`,
|
|
1831
|
+
"",
|
|
1832
|
+
"Generated locally by AgentInspect. Review for sensitive data before sharing.",
|
|
1833
|
+
"",
|
|
1834
|
+
"## What happened",
|
|
1835
|
+
"",
|
|
1836
|
+
"```text",
|
|
1837
|
+
whatText,
|
|
1838
|
+
"```",
|
|
1839
|
+
"",
|
|
1840
|
+
"## Timeline",
|
|
1841
|
+
"",
|
|
1842
|
+
"```text",
|
|
1843
|
+
timelineText,
|
|
1844
|
+
"```",
|
|
1845
|
+
""
|
|
1846
|
+
];
|
|
1847
|
+
if (tail) {
|
|
1848
|
+
lines.push(tail, "");
|
|
1849
|
+
} else {
|
|
1850
|
+
lines.push("## Execution tree", "", "(no steps)", "");
|
|
1851
|
+
}
|
|
1852
|
+
return {
|
|
1853
|
+
format: "markdown",
|
|
1854
|
+
content: lines.join("\n"),
|
|
1855
|
+
contentType: "text/markdown",
|
|
1856
|
+
fileExtension: ".md"
|
|
1857
|
+
};
|
|
1858
|
+
}
|
|
1859
|
+
const treeHtml = exportHtml(tree, exportOpts);
|
|
1860
|
+
const title = escapeHtml(whatSummary.name ?? whatSummary.runId);
|
|
1861
|
+
const treeSection = extractHtmlFragment(
|
|
1862
|
+
treeHtml.content,
|
|
1863
|
+
'<section class="tree">',
|
|
1864
|
+
"</section>"
|
|
1865
|
+
);
|
|
1866
|
+
const errorsSection = treeHtml.content.includes("<h2>Errors</h2>") ? extractHtmlFragment(treeHtml.content, "<h2>Errors</h2>", "<footer>") : "";
|
|
1867
|
+
const attrsSection = treeHtml.content.includes("<h2>Attributes (bounded)</h2>") ? extractHtmlFragment(
|
|
1868
|
+
treeHtml.content,
|
|
1869
|
+
"<h2>Attributes (bounded)</h2>",
|
|
1870
|
+
"<footer>"
|
|
1871
|
+
) : "";
|
|
1872
|
+
const html = `<!doctype html>
|
|
1873
|
+
<html lang="en">
|
|
1874
|
+
<head>
|
|
1875
|
+
<meta charset="utf-8"/>
|
|
1876
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
1877
|
+
<title>AgentInspect Report: ${title}</title>
|
|
1878
|
+
<style>${REPORT_HTML_CSS}</style>
|
|
1879
|
+
</head>
|
|
1880
|
+
<body>
|
|
1881
|
+
<header><h1>AgentInspect Report: ${title}</h1></header>
|
|
1882
|
+
<p class="note">Generated locally by AgentInspect. Review for sensitive data before sharing.</p>
|
|
1883
|
+
<section class="what"><h2>What happened</h2><pre>${escapeHtml(whatText)}</pre></section>
|
|
1884
|
+
<section class="timeline"><h2>Timeline</h2><pre>${escapeHtml(timelineText)}</pre></section>
|
|
1885
|
+
${treeSection || '<section class="tree"><h2>Execution tree</h2><p>No steps recorded.</p></section>'}
|
|
1886
|
+
${errorsSection}
|
|
1887
|
+
${attrsSection}
|
|
1888
|
+
<footer>Generated locally by AgentInspect. Review for sensitive data before sharing.</footer>
|
|
1889
|
+
</body>
|
|
1890
|
+
</html>`;
|
|
1891
|
+
return {
|
|
1892
|
+
format: "html",
|
|
1893
|
+
content: html,
|
|
1894
|
+
contentType: "text/html",
|
|
1895
|
+
fileExtension: ".html"
|
|
1896
|
+
};
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1209
1899
|
exports.EXPORT_PAYLOAD_VERSION = EXPORT_PAYLOAD_VERSION;
|
|
1900
|
+
exports.buildRunReport = buildRunReport;
|
|
1210
1901
|
exports.compactAttributes = compactAttributes;
|
|
1211
1902
|
exports.escapeHtml = escapeHtml;
|
|
1212
1903
|
exports.escapeMarkdown = escapeMarkdown;
|