@agent-inspect/mcp-server 4.3.0 → 5.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.
- package/dist/index.cjs +1176 -1035
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1176 -1035
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import os from 'os';
|
|
|
7
7
|
import 'nanoid';
|
|
8
8
|
import 'chalk';
|
|
9
9
|
import 'fs';
|
|
10
|
+
import 'url';
|
|
10
11
|
|
|
11
12
|
// packages/mcp-server/src/index.ts
|
|
12
13
|
|
|
@@ -70,6 +71,9 @@ function isTraceEvent(value) {
|
|
|
70
71
|
case "step_completed": {
|
|
71
72
|
return typeof value.runId === "string" && typeof value.stepId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
|
|
72
73
|
}
|
|
74
|
+
case "outcome_observed": {
|
|
75
|
+
return typeof value.runId === "string" && typeof value.outcomeId === "string" && typeof value.name === "string" && typeof value.expectation === "string" && (value.status === "passed" || value.status === "failed" || value.status === "unknown" || value.status === "skipped") && typeof value.observedAt === "number";
|
|
76
|
+
}
|
|
73
77
|
default:
|
|
74
78
|
return false;
|
|
75
79
|
}
|
|
@@ -87,7 +91,8 @@ var INSPECT_KINDS = [
|
|
|
87
91
|
"RESULT",
|
|
88
92
|
"ERROR",
|
|
89
93
|
"LOGIC",
|
|
90
|
-
"LOG"
|
|
94
|
+
"LOG",
|
|
95
|
+
"OUTCOME"
|
|
91
96
|
];
|
|
92
97
|
var ATTRIBUTION_CONFIDENCES = [
|
|
93
98
|
"explicit",
|
|
@@ -379,6 +384,32 @@ function fromLegacyStepCompleted(event) {
|
|
|
379
384
|
if (error) out.error = error;
|
|
380
385
|
return out;
|
|
381
386
|
}
|
|
387
|
+
function fromLegacyOutcomeObserved(event) {
|
|
388
|
+
const attrs = event.attributes ?? {};
|
|
389
|
+
const observedAtRaw = attrs.observedAt;
|
|
390
|
+
const observedAt = typeof observedAtRaw === "string" ? Date.parse(observedAtRaw) : typeof observedAtRaw === "number" && Number.isFinite(observedAtRaw) ? observedAtRaw : resolveTimes(event).timestamp;
|
|
391
|
+
const status = attrs.outcomeStatus;
|
|
392
|
+
const out = {
|
|
393
|
+
schemaVersion: "0.1",
|
|
394
|
+
event: "outcome_observed",
|
|
395
|
+
timestamp: observedAt,
|
|
396
|
+
runId: event.runId,
|
|
397
|
+
outcomeId: typeof attrs.outcomeId === "string" ? attrs.outcomeId : event.eventId,
|
|
398
|
+
name: event.name,
|
|
399
|
+
expectation: typeof attrs.expectation === "string" ? attrs.expectation : event.name,
|
|
400
|
+
status: status === "passed" || status === "failed" || status === "unknown" || status === "skipped" ? status : "unknown",
|
|
401
|
+
observedAt
|
|
402
|
+
};
|
|
403
|
+
if (event.parentId !== void 0) out.parentId = event.parentId;
|
|
404
|
+
if (typeof attrs.method === "string") out.method = attrs.method;
|
|
405
|
+
if (attrs.actual !== void 0) out.actual = attrs.actual;
|
|
406
|
+
if (event.outputSummary !== void 0) out.actual = event.outputSummary;
|
|
407
|
+
if (attrs.evidence !== void 0) out.evidence = attrs.evidence;
|
|
408
|
+
return out;
|
|
409
|
+
}
|
|
410
|
+
function fromNativeOutcome(event) {
|
|
411
|
+
return [fromLegacyOutcomeObserved(event)];
|
|
412
|
+
}
|
|
382
413
|
function fromNativeRun(event) {
|
|
383
414
|
const { timestamp, startTime, endTime } = resolveTimes(event);
|
|
384
415
|
const runStatus = mapPersistedStatusToRunStatus(event.status);
|
|
@@ -466,9 +497,13 @@ function persistedInspectEventToTraceEvents(event) {
|
|
|
466
497
|
if (legacyEvent === "run_completed") return [fromLegacyRunCompleted(event)];
|
|
467
498
|
if (legacyEvent === "step_started") return [fromLegacyStepStarted(event)];
|
|
468
499
|
if (legacyEvent === "step_completed") return [fromLegacyStepCompleted(event)];
|
|
500
|
+
if (legacyEvent === "outcome_observed") return [fromLegacyOutcomeObserved(event)];
|
|
469
501
|
if (event.kind === "RUN") {
|
|
470
502
|
return fromNativeRun(event);
|
|
471
503
|
}
|
|
504
|
+
if (event.kind === "OUTCOME") {
|
|
505
|
+
return fromNativeOutcome(event);
|
|
506
|
+
}
|
|
472
507
|
return fromNativeStep(event);
|
|
473
508
|
}
|
|
474
509
|
function persistedInspectEventsToTraceEvents(events, options) {
|
|
@@ -703,6 +738,9 @@ function validateEvent(event) {
|
|
|
703
738
|
case "step_completed": {
|
|
704
739
|
return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
705
740
|
}
|
|
741
|
+
case "outcome_observed": {
|
|
742
|
+
return nonEmptyString(event.runId) && nonEmptyString(event.outcomeId) && nonEmptyString(event.name) && nonEmptyString(event.expectation) && (event.status === "passed" || event.status === "failed" || event.status === "unknown" || event.status === "skipped") && finiteNumber(event.observedAt);
|
|
743
|
+
}
|
|
706
744
|
default:
|
|
707
745
|
return false;
|
|
708
746
|
}
|
|
@@ -722,6 +760,55 @@ async function readTraceEventsFromFile(filePath) {
|
|
|
722
760
|
|
|
723
761
|
// packages/core/src/context.ts
|
|
724
762
|
new AsyncLocalStorage();
|
|
763
|
+
|
|
764
|
+
// packages/core/src/outcomes/types.ts
|
|
765
|
+
var OBSERVED_OUTCOME_STATUSES = [
|
|
766
|
+
"passed",
|
|
767
|
+
"failed",
|
|
768
|
+
"unknown",
|
|
769
|
+
"skipped"
|
|
770
|
+
];
|
|
771
|
+
var OUTCOME_LEGACY_EVENT = "outcome_observed";
|
|
772
|
+
|
|
773
|
+
// packages/core/src/outcomes/validate.ts
|
|
774
|
+
function parseObservedOutcomeStatus(value) {
|
|
775
|
+
const trimmed = value.trim().toLowerCase();
|
|
776
|
+
if (OBSERVED_OUTCOME_STATUSES.includes(trimmed)) {
|
|
777
|
+
return trimmed;
|
|
778
|
+
}
|
|
779
|
+
throw new Error(
|
|
780
|
+
`Unsupported observation status "${value}". Use passed, failed, unknown, or skipped.`
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// packages/core/src/outcomes/extract.ts
|
|
785
|
+
function fromOutcomeObservedEvent(event) {
|
|
786
|
+
return {
|
|
787
|
+
outcomeId: event.outcomeId,
|
|
788
|
+
runId: event.runId,
|
|
789
|
+
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
790
|
+
name: event.name,
|
|
791
|
+
expectation: event.expectation,
|
|
792
|
+
status: event.status,
|
|
793
|
+
...event.method !== void 0 ? { method: event.method } : {},
|
|
794
|
+
...event.actual !== void 0 ? { actual: event.actual } : {},
|
|
795
|
+
...event.evidence !== void 0 ? { evidence: event.evidence } : {},
|
|
796
|
+
observedAt: event.observedAt
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
function extractOutcomesFromTraceEvents(events) {
|
|
800
|
+
const out = [];
|
|
801
|
+
for (const event of events) {
|
|
802
|
+
if (event.event === OUTCOME_LEGACY_EVENT) {
|
|
803
|
+
out.push(fromOutcomeObservedEvent(event));
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return out.sort((a, b) => a.observedAt - b.observedAt || a.name.localeCompare(b.name));
|
|
807
|
+
}
|
|
808
|
+
function parseObservationFilter(value) {
|
|
809
|
+
if (value === void 0 || value.trim() === "") return void 0;
|
|
810
|
+
return parseObservedOutcomeStatus(value);
|
|
811
|
+
}
|
|
725
812
|
function resolveTraceDir(options = {}) {
|
|
726
813
|
if (typeof options.dir === "string" && options.dir.trim() !== "") {
|
|
727
814
|
return options.dir.trim();
|
|
@@ -1069,8 +1156,9 @@ async function searchTraces(metas, options) {
|
|
|
1069
1156
|
}
|
|
1070
1157
|
const limit = options.limit;
|
|
1071
1158
|
const sessionId = options.session?.trim();
|
|
1159
|
+
const observationStatus = parseObservationFilter(options.observation);
|
|
1072
1160
|
const hasContentFilter = Boolean(
|
|
1073
|
-
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
|
|
1161
|
+
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter || observationStatus
|
|
1074
1162
|
);
|
|
1075
1163
|
const results = [];
|
|
1076
1164
|
const sessionLabel = sessionId && sessionId !== "" ? sessionId : void 0;
|
|
@@ -1115,6 +1203,22 @@ async function searchTraces(metas, options) {
|
|
|
1115
1203
|
statusFilter: options.status
|
|
1116
1204
|
});
|
|
1117
1205
|
results.push(...stepMatches);
|
|
1206
|
+
if (observationStatus) {
|
|
1207
|
+
const outcomes = extractOutcomesFromTraceEvents(events);
|
|
1208
|
+
const matched = outcomes.filter((outcome) => outcome.status === observationStatus);
|
|
1209
|
+
for (const outcome of matched) {
|
|
1210
|
+
results.push({
|
|
1211
|
+
runId: m.runId,
|
|
1212
|
+
runName: m.name,
|
|
1213
|
+
runStatus: m.status,
|
|
1214
|
+
stepName: outcome.name,
|
|
1215
|
+
timestamp: outcome.observedAt,
|
|
1216
|
+
matchReason: `observation status=${outcome.status}`,
|
|
1217
|
+
matchedFields: ["outcome.status", "outcome.name"],
|
|
1218
|
+
filePath: m.filePath
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1118
1222
|
}
|
|
1119
1223
|
results.sort((a, b) => {
|
|
1120
1224
|
const ta = a.timestamp ?? 0;
|
|
@@ -1421,7 +1525,7 @@ function summarize(findings, diagnostics) {
|
|
|
1421
1525
|
errors: diagnostics.filter((item) => item.severity === "error").length
|
|
1422
1526
|
};
|
|
1423
1527
|
}
|
|
1424
|
-
function eventEvidence(event,
|
|
1528
|
+
function eventEvidence(event, path12) {
|
|
1425
1529
|
return {
|
|
1426
1530
|
runId: event.runId,
|
|
1427
1531
|
eventId: event.eventId,
|
|
@@ -1532,926 +1636,474 @@ function runTraceChecks(input, options = {}) {
|
|
|
1532
1636
|
};
|
|
1533
1637
|
}
|
|
1534
1638
|
|
|
1535
|
-
// packages/core/src/
|
|
1536
|
-
function
|
|
1537
|
-
|
|
1538
|
-
if ("outputPreview" in meta) return meta.outputPreview;
|
|
1539
|
-
if ("resultPreview" in meta) return meta.resultPreview;
|
|
1540
|
-
return void 0;
|
|
1639
|
+
// packages/core/src/persisted/token-usage.ts
|
|
1640
|
+
function isRecord5(value) {
|
|
1641
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1541
1642
|
}
|
|
1542
|
-
function
|
|
1543
|
-
|
|
1544
|
-
return s;
|
|
1643
|
+
function nonNegativeFinite(value) {
|
|
1644
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
1545
1645
|
}
|
|
1546
|
-
function
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
const
|
|
1552
|
-
const
|
|
1553
|
-
const
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
if (lastCompleted === void 0) runStatus = "running";
|
|
1557
|
-
else runStatus = lastCompleted.status;
|
|
1558
|
-
const durationMs = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
1559
|
-
const steps = /* @__PURE__ */ new Map();
|
|
1560
|
-
let order = 0;
|
|
1561
|
-
for (const e of events) {
|
|
1562
|
-
if (e.event !== "step_started") continue;
|
|
1563
|
-
const s = e;
|
|
1564
|
-
const meta = s.metadata ? { ...s.metadata } : void 0;
|
|
1565
|
-
steps.set(s.stepId, {
|
|
1566
|
-
id: s.stepId,
|
|
1567
|
-
parentId: s.parentId,
|
|
1568
|
-
name: s.name,
|
|
1569
|
-
type: s.type,
|
|
1570
|
-
order: order++,
|
|
1571
|
-
timestamp: s.timestamp,
|
|
1572
|
-
metadata: meta
|
|
1573
|
-
});
|
|
1574
|
-
}
|
|
1575
|
-
for (const e of events) {
|
|
1576
|
-
if (e.event !== "step_completed") continue;
|
|
1577
|
-
const acc = steps.get(e.stepId);
|
|
1578
|
-
if (!acc) continue;
|
|
1579
|
-
acc.status = e.status;
|
|
1580
|
-
acc.durationMs = e.durationMs;
|
|
1581
|
-
if (e.error?.message) acc.errorMsg = e.error.message;
|
|
1582
|
-
const extra = e;
|
|
1583
|
-
if (extra.metadata !== void 0 && typeof extra.metadata === "object") {
|
|
1584
|
-
acc.metadata = { ...acc.metadata ?? {}, ...extra.metadata };
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
const nodes = /* @__PURE__ */ new Map();
|
|
1588
|
-
for (const acc of steps.values()) {
|
|
1589
|
-
let meta = acc.metadata ? { ...acc.metadata } : void 0;
|
|
1590
|
-
if (acc.parentId !== void 0 && !steps.has(acc.parentId)) {
|
|
1591
|
-
meta = { ...meta ?? {}, agent_inspect_diff_parent_missing: true };
|
|
1592
|
-
}
|
|
1593
|
-
const outputPreview = extractOutputPreview(meta);
|
|
1594
|
-
const sc = {
|
|
1595
|
-
id: acc.id,
|
|
1596
|
-
name: acc.name,
|
|
1597
|
-
type: acc.type,
|
|
1598
|
-
status: mapStepStatus(acc.status),
|
|
1599
|
-
durationMs: acc.durationMs,
|
|
1600
|
-
error: acc.errorMsg,
|
|
1601
|
-
metadata: meta && Object.keys(meta).length > 0 ? meta : void 0,
|
|
1602
|
-
outputPreview,
|
|
1603
|
-
children: []
|
|
1604
|
-
};
|
|
1605
|
-
nodes.set(acc.id, sc);
|
|
1606
|
-
}
|
|
1607
|
-
const roots = [];
|
|
1608
|
-
const sortByOrder = (a, b) => {
|
|
1609
|
-
const oa = steps.get(a.id)?.order ?? 0;
|
|
1610
|
-
const ob = steps.get(b.id)?.order ?? 0;
|
|
1611
|
-
return oa - ob;
|
|
1612
|
-
};
|
|
1613
|
-
for (const acc of steps.values()) {
|
|
1614
|
-
const node = nodes.get(acc.id);
|
|
1615
|
-
if (acc.parentId !== void 0 && nodes.has(acc.parentId)) {
|
|
1616
|
-
nodes.get(acc.parentId).children.push(node);
|
|
1617
|
-
} else {
|
|
1618
|
-
roots.push(node);
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
roots.sort(sortByOrder);
|
|
1622
|
-
for (const n of nodes.values()) {
|
|
1623
|
-
n.children.sort(sortByOrder);
|
|
1646
|
+
function normalizeTokenUsage(value) {
|
|
1647
|
+
if (!isRecord5(value)) return void 0;
|
|
1648
|
+
const input = nonNegativeFinite(value.input);
|
|
1649
|
+
const output = nonNegativeFinite(value.output);
|
|
1650
|
+
const suppliedTotal = nonNegativeFinite(value.total);
|
|
1651
|
+
const cached = nonNegativeFinite(value.cached);
|
|
1652
|
+
const derivedTotal = input !== void 0 && output !== void 0 && Number.isFinite(input + output) ? input + output : void 0;
|
|
1653
|
+
const total = suppliedTotal ?? derivedTotal;
|
|
1654
|
+
if (input === void 0 && output === void 0 && total === void 0 && cached === void 0) {
|
|
1655
|
+
return void 0;
|
|
1624
1656
|
}
|
|
1625
1657
|
return {
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
steps: roots
|
|
1658
|
+
...input !== void 0 ? { input } : {},
|
|
1659
|
+
...output !== void 0 ? { output } : {},
|
|
1660
|
+
...total !== void 0 ? { total } : {},
|
|
1661
|
+
...cached !== void 0 ? { cached } : {}
|
|
1631
1662
|
};
|
|
1632
1663
|
}
|
|
1633
1664
|
|
|
1634
|
-
// packages/core/src/
|
|
1635
|
-
|
|
1636
|
-
"
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1665
|
+
// packages/core/src/persisted/from-trace-event.ts
|
|
1666
|
+
function sanitizeIdPart(value) {
|
|
1667
|
+
return value.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1668
|
+
}
|
|
1669
|
+
function nodeIdForEvent(event) {
|
|
1670
|
+
switch (event.event) {
|
|
1671
|
+
case "run_started":
|
|
1672
|
+
case "run_completed":
|
|
1673
|
+
return event.runId;
|
|
1674
|
+
case "step_started":
|
|
1675
|
+
case "step_completed":
|
|
1676
|
+
return event.stepId;
|
|
1677
|
+
case "outcome_observed":
|
|
1678
|
+
return event.outcomeId;
|
|
1679
|
+
default:
|
|
1680
|
+
return "unknown";
|
|
1648
1681
|
}
|
|
1649
|
-
return false;
|
|
1650
1682
|
}
|
|
1651
|
-
function
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1683
|
+
function createPersistedEventId(event, eventIndex) {
|
|
1684
|
+
const runId = sanitizeIdPart(event.runId);
|
|
1685
|
+
const ev = sanitizeIdPart(event.event);
|
|
1686
|
+
const node = sanitizeIdPart(nodeIdForEvent(event));
|
|
1687
|
+
return `manual:${runId}:${ev}:${node}:${eventIndex}`;
|
|
1688
|
+
}
|
|
1689
|
+
function toIsoTimestamp(ms) {
|
|
1690
|
+
if (typeof ms !== "number" || !Number.isFinite(ms)) {
|
|
1691
|
+
return { iso: (/* @__PURE__ */ new Date(0)).toISOString(), invalidTimestamp: true };
|
|
1659
1692
|
}
|
|
1660
|
-
return
|
|
1693
|
+
return { iso: new Date(ms).toISOString(), invalidTimestamp: false };
|
|
1661
1694
|
}
|
|
1662
|
-
function
|
|
1663
|
-
return
|
|
1695
|
+
function buildSource(options) {
|
|
1696
|
+
return {
|
|
1697
|
+
type: "manual",
|
|
1698
|
+
name: options?.sourceName ?? "trace-event",
|
|
1699
|
+
version: options?.sourceVersion ?? "0.1"
|
|
1700
|
+
};
|
|
1664
1701
|
}
|
|
1665
|
-
function
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1702
|
+
function mapStepTypeToInspectKind(type) {
|
|
1703
|
+
switch (type) {
|
|
1704
|
+
case "run":
|
|
1705
|
+
return "RUN";
|
|
1706
|
+
case "llm":
|
|
1707
|
+
return "LLM";
|
|
1708
|
+
case "tool":
|
|
1709
|
+
return "TOOL";
|
|
1710
|
+
case "decision":
|
|
1711
|
+
return "DECISION";
|
|
1712
|
+
case "logic":
|
|
1713
|
+
case "state":
|
|
1714
|
+
case "custom":
|
|
1715
|
+
return "LOGIC";
|
|
1716
|
+
default:
|
|
1717
|
+
return "LOGIC";
|
|
1672
1718
|
}
|
|
1673
|
-
return out;
|
|
1674
1719
|
}
|
|
1675
|
-
function
|
|
1676
|
-
|
|
1677
|
-
return pretty === true ? JSON.stringify(sorted, null, 2) : JSON.stringify(sorted);
|
|
1720
|
+
function mapRunOrStepStatus(status) {
|
|
1721
|
+
return status === "success" ? "ok" : "error";
|
|
1678
1722
|
}
|
|
1679
|
-
function
|
|
1680
|
-
if (
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1723
|
+
function mapErrorInfo(error) {
|
|
1724
|
+
if (!error?.message) {
|
|
1725
|
+
return {};
|
|
1726
|
+
}
|
|
1727
|
+
const out = {
|
|
1728
|
+
persisted: {
|
|
1729
|
+
message: error.message,
|
|
1730
|
+
name: "Error"
|
|
1687
1731
|
}
|
|
1688
|
-
|
|
1689
|
-
|
|
1732
|
+
};
|
|
1733
|
+
if (typeof error.stack === "string" && error.stack.length > 0) {
|
|
1734
|
+
out.errorStack = error.stack;
|
|
1690
1735
|
}
|
|
1691
1736
|
return out;
|
|
1692
1737
|
}
|
|
1693
|
-
function
|
|
1694
|
-
|
|
1695
|
-
return typeof value === "string" ? safeString(value, maxLen) : value;
|
|
1696
|
-
}
|
|
1697
|
-
if (Array.isArray(value)) {
|
|
1698
|
-
const arr = value.slice(0, 20).map((x) => compactValue(x, maxLen));
|
|
1699
|
-
if (value.length > 20) arr.push(`\u2026(+${value.length - 20} more)`);
|
|
1700
|
-
return arr;
|
|
1701
|
-
}
|
|
1702
|
-
const o = value;
|
|
1703
|
-
const inner = {};
|
|
1704
|
-
for (const k of Object.keys(o)) {
|
|
1705
|
-
if (shouldRedactKey(k)) inner[k] = "[REDACTED]";
|
|
1706
|
-
else inner[k] = compactValue(o[k], maxLen);
|
|
1707
|
-
}
|
|
1708
|
-
return inner;
|
|
1738
|
+
function mapTokenUsageFromMetadata(metadata) {
|
|
1739
|
+
return normalizeTokenUsage(metadata?.tokens);
|
|
1709
1740
|
}
|
|
1710
|
-
function
|
|
1711
|
-
const out =
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
out
|
|
1715
|
-
if (n.children.length > 0) walk(n.children);
|
|
1741
|
+
function compactAttributes(entries) {
|
|
1742
|
+
const out = {};
|
|
1743
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
1744
|
+
if (value !== void 0) {
|
|
1745
|
+
out[key] = value;
|
|
1716
1746
|
}
|
|
1717
1747
|
}
|
|
1718
|
-
|
|
1719
|
-
return out;
|
|
1720
|
-
}
|
|
1721
|
-
|
|
1722
|
-
// packages/core/src/diff/engine.ts
|
|
1723
|
-
var DEFAULT_THRESHOLD_MS = 0;
|
|
1724
|
-
function pathSeg(step, index) {
|
|
1725
|
-
return { index, name: step.name, stepId: step.id };
|
|
1726
|
-
}
|
|
1727
|
-
function buildPath(segments) {
|
|
1728
|
-
return { path: [...segments] };
|
|
1748
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
1729
1749
|
}
|
|
1730
|
-
function
|
|
1731
|
-
const
|
|
1732
|
-
const
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
const
|
|
1738
|
-
|
|
1739
|
-
|
|
1750
|
+
function traceEventToPersistedInspectEvent(event, options) {
|
|
1751
|
+
const eventIndex = options?.eventIndex ?? 0;
|
|
1752
|
+
const eventId = createPersistedEventId(event, eventIndex);
|
|
1753
|
+
const source = buildSource(options);
|
|
1754
|
+
const tsMain = toIsoTimestamp(event.timestamp);
|
|
1755
|
+
switch (event.event) {
|
|
1756
|
+
case "run_started": {
|
|
1757
|
+
const tsStart = toIsoTimestamp(event.startTime);
|
|
1758
|
+
const correlation = extractCorrelationMetadata(event.metadata);
|
|
1759
|
+
const attributes = compactAttributes({
|
|
1760
|
+
legacyEvent: "run_started",
|
|
1761
|
+
metadata: event.metadata !== void 0 ? { ...event.metadata } : void 0,
|
|
1762
|
+
correlationId: correlation?.correlationId,
|
|
1763
|
+
requestId: correlation?.requestId,
|
|
1764
|
+
decisionId: correlation?.decisionId,
|
|
1765
|
+
groupId: correlation?.groupId,
|
|
1766
|
+
invalidTimestamp: tsMain.invalidTimestamp || tsStart.invalidTimestamp ? true : void 0
|
|
1767
|
+
});
|
|
1768
|
+
return {
|
|
1769
|
+
schemaVersion: "0.2",
|
|
1770
|
+
eventId,
|
|
1771
|
+
runId: event.runId,
|
|
1772
|
+
kind: "RUN",
|
|
1773
|
+
name: event.name,
|
|
1774
|
+
status: "running",
|
|
1775
|
+
timestamp: tsMain.iso,
|
|
1776
|
+
startedAt: tsStart.iso,
|
|
1777
|
+
confidence: "explicit",
|
|
1778
|
+
source,
|
|
1779
|
+
attributes
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
case "run_completed": {
|
|
1783
|
+
const tsEnd = toIsoTimestamp(event.endTime);
|
|
1784
|
+
const { persisted: error, errorStack } = mapErrorInfo(event.error);
|
|
1785
|
+
const attributes = compactAttributes({
|
|
1786
|
+
legacyEvent: "run_completed",
|
|
1787
|
+
errorStack,
|
|
1788
|
+
invalidTimestamp: tsMain.invalidTimestamp || tsEnd.invalidTimestamp ? true : void 0
|
|
1789
|
+
});
|
|
1790
|
+
return {
|
|
1791
|
+
schemaVersion: "0.2",
|
|
1792
|
+
eventId,
|
|
1793
|
+
runId: event.runId,
|
|
1794
|
+
kind: "RUN",
|
|
1795
|
+
name: "run",
|
|
1796
|
+
status: mapRunOrStepStatus(event.status),
|
|
1797
|
+
timestamp: tsMain.iso,
|
|
1798
|
+
endedAt: tsEnd.iso,
|
|
1799
|
+
durationMs: event.durationMs,
|
|
1800
|
+
confidence: "explicit",
|
|
1801
|
+
source,
|
|
1802
|
+
attributes,
|
|
1803
|
+
error
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1806
|
+
case "step_started": {
|
|
1807
|
+
const tsStart = toIsoTimestamp(event.startTime);
|
|
1808
|
+
const tokenUsage = mapTokenUsageFromMetadata(event.metadata);
|
|
1809
|
+
const attributes = compactAttributes({
|
|
1810
|
+
legacyEvent: "step_started",
|
|
1811
|
+
stepId: event.stepId,
|
|
1812
|
+
stepType: event.type,
|
|
1813
|
+
metadata: event.metadata !== void 0 ? { ...event.metadata } : void 0,
|
|
1814
|
+
invalidTimestamp: tsMain.invalidTimestamp || tsStart.invalidTimestamp ? true : void 0
|
|
1815
|
+
});
|
|
1816
|
+
const out = {
|
|
1817
|
+
schemaVersion: "0.2",
|
|
1818
|
+
eventId,
|
|
1819
|
+
runId: event.runId,
|
|
1820
|
+
kind: mapStepTypeToInspectKind(event.type),
|
|
1821
|
+
name: event.name,
|
|
1822
|
+
status: "running",
|
|
1823
|
+
timestamp: tsMain.iso,
|
|
1824
|
+
startedAt: tsStart.iso,
|
|
1825
|
+
confidence: "explicit",
|
|
1826
|
+
source,
|
|
1827
|
+
attributes
|
|
1828
|
+
};
|
|
1829
|
+
if (event.parentId !== void 0) {
|
|
1830
|
+
out.parentId = event.parentId;
|
|
1831
|
+
}
|
|
1832
|
+
if (tokenUsage !== void 0) {
|
|
1833
|
+
out.tokenUsage = tokenUsage;
|
|
1740
1834
|
}
|
|
1835
|
+
return out;
|
|
1741
1836
|
}
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1837
|
+
case "step_completed": {
|
|
1838
|
+
const tsEnd = toIsoTimestamp(event.endTime);
|
|
1839
|
+
const { persisted: error, errorStack } = mapErrorInfo(event.error);
|
|
1840
|
+
const attributes = compactAttributes({
|
|
1841
|
+
legacyEvent: "step_completed",
|
|
1842
|
+
stepId: event.stepId,
|
|
1843
|
+
errorStack,
|
|
1844
|
+
invalidTimestamp: tsMain.invalidTimestamp || tsEnd.invalidTimestamp ? true : void 0
|
|
1845
|
+
});
|
|
1846
|
+
return {
|
|
1847
|
+
schemaVersion: "0.2",
|
|
1848
|
+
eventId,
|
|
1849
|
+
runId: event.runId,
|
|
1850
|
+
kind: "LOGIC",
|
|
1851
|
+
name: event.stepId,
|
|
1852
|
+
status: mapRunOrStepStatus(event.status),
|
|
1853
|
+
timestamp: tsMain.iso,
|
|
1854
|
+
endedAt: tsEnd.iso,
|
|
1855
|
+
durationMs: event.durationMs,
|
|
1856
|
+
confidence: "explicit",
|
|
1857
|
+
source,
|
|
1858
|
+
attributes,
|
|
1859
|
+
error
|
|
1860
|
+
};
|
|
1746
1861
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1862
|
+
case "outcome_observed": {
|
|
1863
|
+
const tsObserved = toIsoTimestamp(event.observedAt);
|
|
1864
|
+
const attributes = compactAttributes({
|
|
1865
|
+
legacyEvent: "outcome_observed",
|
|
1866
|
+
outcomeId: event.outcomeId,
|
|
1867
|
+
outcomeStatus: event.status,
|
|
1868
|
+
expectation: event.expectation,
|
|
1869
|
+
method: event.method,
|
|
1870
|
+
actual: event.actual,
|
|
1871
|
+
evidence: event.evidence,
|
|
1872
|
+
observedAt: tsObserved.iso,
|
|
1873
|
+
invalidTimestamp: tsMain.invalidTimestamp || tsObserved.invalidTimestamp ? true : void 0
|
|
1874
|
+
});
|
|
1875
|
+
const out = {
|
|
1876
|
+
schemaVersion: "0.2",
|
|
1877
|
+
eventId,
|
|
1878
|
+
runId: event.runId,
|
|
1879
|
+
kind: "OUTCOME",
|
|
1880
|
+
name: event.name,
|
|
1881
|
+
status: event.status === "failed" ? "error" : "ok",
|
|
1882
|
+
timestamp: tsMain.iso,
|
|
1883
|
+
confidence: "explicit",
|
|
1884
|
+
source,
|
|
1885
|
+
attributes
|
|
1886
|
+
};
|
|
1887
|
+
if (event.parentId !== void 0) {
|
|
1888
|
+
out.parentId = event.parentId;
|
|
1889
|
+
}
|
|
1890
|
+
if (event.actual !== void 0) {
|
|
1891
|
+
out.outputSummary = event.actual;
|
|
1892
|
+
}
|
|
1893
|
+
return out;
|
|
1752
1894
|
}
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
pairs.push([void 0, R]);
|
|
1895
|
+
default: {
|
|
1896
|
+
const _exhaustive = event;
|
|
1897
|
+
throw new Error(`Unsupported trace event: ${_exhaustive.event}`);
|
|
1757
1898
|
}
|
|
1758
1899
|
}
|
|
1759
|
-
return pairs;
|
|
1760
1900
|
}
|
|
1761
|
-
function
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
severity: "warning",
|
|
1777
|
-
message: "Step type differs",
|
|
1778
|
-
path: path8,
|
|
1779
|
-
left: L.type,
|
|
1780
|
-
right: R.type
|
|
1781
|
-
});
|
|
1782
|
-
}
|
|
1783
|
-
if ((L.status ?? "") !== (R.status ?? "")) {
|
|
1784
|
-
out.push({
|
|
1785
|
-
kind: "step-status",
|
|
1786
|
-
severity: "warning",
|
|
1787
|
-
message: "Step status differs",
|
|
1788
|
-
path: path8,
|
|
1789
|
-
left: L.status,
|
|
1790
|
-
right: R.status
|
|
1791
|
-
});
|
|
1901
|
+
function traceEventsToPersistedInspectEvents(events, options) {
|
|
1902
|
+
return events.map(
|
|
1903
|
+
(event, index) => traceEventToPersistedInspectEvent(event, { ...options, eventIndex: index })
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
// packages/core/src/logs/tree-builder.ts
|
|
1908
|
+
function inc(map, key) {
|
|
1909
|
+
map[key] = (map[key] ?? 0) + 1;
|
|
1910
|
+
}
|
|
1911
|
+
function computeRunStatus(events) {
|
|
1912
|
+
let hasRunning = false;
|
|
1913
|
+
for (const e of events) {
|
|
1914
|
+
if (e.status === "error") return "error";
|
|
1915
|
+
if (e.status === "running") hasRunning = true;
|
|
1792
1916
|
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
message: "Step error message differs",
|
|
1800
|
-
path: path8,
|
|
1801
|
-
left: le || void 0,
|
|
1802
|
-
right: re || void 0
|
|
1803
|
-
});
|
|
1917
|
+
if (hasRunning) return "running";
|
|
1918
|
+
return "ok";
|
|
1919
|
+
}
|
|
1920
|
+
var TreeBuilder = class {
|
|
1921
|
+
constructor(options) {
|
|
1922
|
+
void options?.config;
|
|
1804
1923
|
}
|
|
1805
|
-
|
|
1806
|
-
const
|
|
1807
|
-
const
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
if (ld === void 0 && rd === void 0) differs = false;
|
|
1811
|
-
else if (ld === void 0 || rd === void 0) differs = true;
|
|
1812
|
-
else differs = Math.abs(ld - rd) > th;
|
|
1813
|
-
if (differs) {
|
|
1814
|
-
out.push({
|
|
1815
|
-
kind: "duration",
|
|
1816
|
-
severity: "info",
|
|
1817
|
-
message: "Step duration differs",
|
|
1818
|
-
path: path8,
|
|
1819
|
-
left: ld,
|
|
1820
|
-
right: rd
|
|
1821
|
-
});
|
|
1924
|
+
build(events) {
|
|
1925
|
+
const byRun = /* @__PURE__ */ new Map();
|
|
1926
|
+
for (const e of events) {
|
|
1927
|
+
if (!byRun.has(e.runId)) byRun.set(e.runId, []);
|
|
1928
|
+
byRun.get(e.runId).push(e);
|
|
1822
1929
|
}
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
message: `Step only in left run: ${lch.name}`,
|
|
1861
|
-
path: buildPath([...segments, pathSeg(lch, ci)]),
|
|
1862
|
-
left: lch.id,
|
|
1863
|
-
right: void 0
|
|
1864
|
-
});
|
|
1865
|
-
} else if (rch !== void 0) {
|
|
1930
|
+
const out = [];
|
|
1931
|
+
for (const [runId, runEvents] of byRun.entries()) {
|
|
1932
|
+
const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
|
|
1933
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
1934
|
+
for (const e of sorted) {
|
|
1935
|
+
nodes.set(e.eventId, { event: e, children: [], depth: 0 });
|
|
1936
|
+
}
|
|
1937
|
+
const roots = [];
|
|
1938
|
+
for (const node of nodes.values()) {
|
|
1939
|
+
const parentId = node.event.parentId;
|
|
1940
|
+
if (parentId && nodes.has(parentId)) {
|
|
1941
|
+
nodes.get(parentId).children.push(node);
|
|
1942
|
+
} else {
|
|
1943
|
+
roots.push(node);
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
const assignDepth = (n, depth) => {
|
|
1947
|
+
n.depth = depth;
|
|
1948
|
+
for (const c of n.children) assignDepth(c, depth + 1);
|
|
1949
|
+
};
|
|
1950
|
+
for (const r of roots) assignDepth(r, 0);
|
|
1951
|
+
const confidenceBreakdown = {
|
|
1952
|
+
explicit: 0,
|
|
1953
|
+
correlated: 0,
|
|
1954
|
+
heuristic: 0,
|
|
1955
|
+
unknown: 0
|
|
1956
|
+
};
|
|
1957
|
+
const kinds = {};
|
|
1958
|
+
for (const e of sorted) {
|
|
1959
|
+
inc(confidenceBreakdown, e.confidence);
|
|
1960
|
+
kinds[e.kind] = (kinds[e.kind] ?? 0) + 1;
|
|
1961
|
+
}
|
|
1962
|
+
const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
|
|
1963
|
+
const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
|
|
1964
|
+
const status = computeRunStatus(sorted);
|
|
1965
|
+
const durationMs = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
|
|
1966
|
+
const name = sorted.find((e) => e.kind === "RUN")?.name;
|
|
1866
1967
|
out.push({
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1968
|
+
runId,
|
|
1969
|
+
name,
|
|
1970
|
+
status,
|
|
1971
|
+
startedAt,
|
|
1972
|
+
endedAt: status === "running" ? void 0 : endedAt,
|
|
1973
|
+
durationMs,
|
|
1974
|
+
children: roots,
|
|
1975
|
+
metadata: {
|
|
1976
|
+
totalEvents: sorted.length,
|
|
1977
|
+
confidenceBreakdown,
|
|
1978
|
+
kinds
|
|
1979
|
+
}
|
|
1873
1980
|
});
|
|
1874
1981
|
}
|
|
1875
|
-
|
|
1982
|
+
out.sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0));
|
|
1983
|
+
return out;
|
|
1984
|
+
}
|
|
1985
|
+
};
|
|
1986
|
+
|
|
1987
|
+
// packages/core/src/persisted/to-inspect-event.ts
|
|
1988
|
+
function compactAttributes2(entries) {
|
|
1989
|
+
const out = {};
|
|
1990
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
1991
|
+
if (value !== void 0) {
|
|
1992
|
+
out[key] = value;
|
|
1993
|
+
}
|
|
1876
1994
|
}
|
|
1995
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
1877
1996
|
}
|
|
1878
|
-
function
|
|
1997
|
+
function parseIsoToMs3(iso) {
|
|
1998
|
+
const parsed = Date.parse(iso);
|
|
1999
|
+
if (!Number.isFinite(parsed)) {
|
|
2000
|
+
return { ms: 0, invalidTimestamp: true };
|
|
2001
|
+
}
|
|
2002
|
+
return { ms: parsed, invalidTimestamp: false };
|
|
2003
|
+
}
|
|
2004
|
+
function mapPersistedSourceToInspect(event) {
|
|
2005
|
+
const attrs = event.attributes ?? {};
|
|
2006
|
+
const sourceName = event.source.name;
|
|
2007
|
+
if (sourceName === "pino") {
|
|
2008
|
+
return {
|
|
2009
|
+
type: "pino",
|
|
2010
|
+
file: typeof attrs.sourceFile === "string" ? attrs.sourceFile : void 0,
|
|
2011
|
+
line: typeof attrs.sourceLine === "number" ? attrs.sourceLine : void 0
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
2014
|
+
if (sourceName === "winston") {
|
|
2015
|
+
return {
|
|
2016
|
+
type: "winston",
|
|
2017
|
+
file: typeof attrs.sourceFile === "string" ? attrs.sourceFile : void 0,
|
|
2018
|
+
line: typeof attrs.sourceLine === "number" ? attrs.sourceLine : void 0
|
|
2019
|
+
};
|
|
2020
|
+
}
|
|
2021
|
+
const mapType = (t) => {
|
|
2022
|
+
switch (t) {
|
|
2023
|
+
case "manual":
|
|
2024
|
+
return "manual";
|
|
2025
|
+
case "json-log":
|
|
2026
|
+
return "json-log";
|
|
2027
|
+
case "log4js":
|
|
2028
|
+
return "log4js";
|
|
2029
|
+
case "adapter":
|
|
2030
|
+
case "ai-sdk":
|
|
2031
|
+
case "otel":
|
|
2032
|
+
return "adapter";
|
|
2033
|
+
default:
|
|
2034
|
+
return "json-log";
|
|
2035
|
+
}
|
|
2036
|
+
};
|
|
1879
2037
|
return {
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
check: "all"
|
|
2038
|
+
type: mapType(event.source.type),
|
|
2039
|
+
file: typeof attrs.sourceFile === "string" ? attrs.sourceFile : void 0,
|
|
2040
|
+
line: typeof attrs.sourceLine === "number" ? attrs.sourceLine : void 0
|
|
1884
2041
|
};
|
|
1885
2042
|
}
|
|
1886
|
-
function
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
const merged = mergeDiffDefaults();
|
|
1891
|
-
const opts = {
|
|
1892
|
-
ignoreDuration: merged.ignoreDuration,
|
|
1893
|
-
durationThresholdMs: merged.durationThresholdMs
|
|
1894
|
-
};
|
|
1895
|
-
const raw = [];
|
|
1896
|
-
if ((left.status ?? "") !== (right.status ?? "")) {
|
|
1897
|
-
raw.push({
|
|
1898
|
-
kind: "run-status",
|
|
1899
|
-
severity: "warning",
|
|
1900
|
-
message: "Run completion status differs",
|
|
1901
|
-
left: left.status,
|
|
1902
|
-
right: right.status
|
|
1903
|
-
});
|
|
2043
|
+
function buildInspectAttributes(event) {
|
|
2044
|
+
const attrs = event.attributes !== void 0 ? { ...event.attributes } : {};
|
|
2045
|
+
if (event.inputSummary !== void 0) {
|
|
2046
|
+
attrs.inputSummary = event.inputSummary;
|
|
1904
2047
|
}
|
|
1905
|
-
{
|
|
1906
|
-
|
|
1907
|
-
const rd = right.durationMs;
|
|
1908
|
-
const th = merged.durationThresholdMs;
|
|
1909
|
-
let differs = false;
|
|
1910
|
-
if (ld === void 0 && rd === void 0) differs = false;
|
|
1911
|
-
else if (ld === void 0 || rd === void 0) differs = true;
|
|
1912
|
-
else differs = Math.abs(ld - rd) > th;
|
|
1913
|
-
if (differs) {
|
|
1914
|
-
raw.push({
|
|
1915
|
-
kind: "duration",
|
|
1916
|
-
severity: "info",
|
|
1917
|
-
message: "Run duration differs",
|
|
1918
|
-
left: ld,
|
|
1919
|
-
right: rd
|
|
1920
|
-
});
|
|
1921
|
-
}
|
|
2048
|
+
if (event.outputSummary !== void 0) {
|
|
2049
|
+
attrs.outputSummary = event.outputSummary;
|
|
1922
2050
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
raw.push({
|
|
1931
|
-
kind: "step-removed",
|
|
1932
|
-
severity: "warning",
|
|
1933
|
-
message: `Step only in left run: ${ls.name}`,
|
|
1934
|
-
path: buildPath([pathSeg(ls, idx)]),
|
|
1935
|
-
left: ls.id,
|
|
1936
|
-
right: void 0
|
|
1937
|
-
});
|
|
1938
|
-
idx += 1;
|
|
1939
|
-
} else if (rs !== void 0) {
|
|
1940
|
-
raw.push({
|
|
1941
|
-
kind: "step-added",
|
|
1942
|
-
severity: "warning",
|
|
1943
|
-
message: `Step only in right run: ${rs.name}`,
|
|
1944
|
-
path: buildPath([pathSeg(rs, idx)]),
|
|
1945
|
-
left: void 0,
|
|
1946
|
-
right: rs.id
|
|
1947
|
-
});
|
|
1948
|
-
idx += 1;
|
|
2051
|
+
if (event.error) {
|
|
2052
|
+
if (event.error.name !== void 0) {
|
|
2053
|
+
attrs.errorName = event.error.name;
|
|
2054
|
+
}
|
|
2055
|
+
attrs.errorMessage = event.error.message;
|
|
2056
|
+
if (event.error.code !== void 0) {
|
|
2057
|
+
attrs.errorCode = event.error.code;
|
|
1949
2058
|
}
|
|
1950
2059
|
}
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
let warnings = 0;
|
|
1954
|
-
let info = 0;
|
|
1955
|
-
for (const d of differences) {
|
|
1956
|
-
if (d.severity === "error") errors += 1;
|
|
1957
|
-
else if (d.severity === "warning") warnings += 1;
|
|
1958
|
-
else info += 1;
|
|
2060
|
+
if (event.tokenUsage) {
|
|
2061
|
+
attrs.tokens = { ...event.tokenUsage };
|
|
1959
2062
|
}
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
kind: "first-divergence",
|
|
1963
|
-
severity: firstVisible.severity,
|
|
1964
|
-
message: `First divergence: ${firstVisible.message}`,
|
|
1965
|
-
path: firstVisible.path,
|
|
1966
|
-
left: firstVisible.left,
|
|
1967
|
-
right: firstVisible.right
|
|
1968
|
-
} : void 0;
|
|
1969
|
-
const summary = {
|
|
1970
|
-
leftRunId: left.runId,
|
|
1971
|
-
rightRunId: right.runId,
|
|
1972
|
-
totalDifferences: differences.length,
|
|
1973
|
-
errors,
|
|
1974
|
-
warnings,
|
|
1975
|
-
info,
|
|
1976
|
-
firstDivergence
|
|
1977
|
-
};
|
|
1978
|
-
return { summary, differences };
|
|
1979
|
-
}
|
|
1980
|
-
|
|
1981
|
-
// packages/core/src/exporters/markdown-exporter.ts
|
|
1982
|
-
function renderTreeAscii(nodes, indent = "") {
|
|
1983
|
-
const lines = [];
|
|
1984
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
1985
|
-
const n = nodes[i];
|
|
1986
|
-
const last = i === nodes.length - 1;
|
|
1987
|
-
const branch = last ? "\u2514\u2500 " : "\u251C\u2500 ";
|
|
1988
|
-
const ev = n.event;
|
|
1989
|
-
const status = ev.status ?? "?";
|
|
1990
|
-
const dur = ev.durationMs !== void 0 && Number.isFinite(ev.durationMs) ? `${ev.durationMs}ms` : "-";
|
|
1991
|
-
lines.push(`${indent}${branch}${escapeMarkdown(ev.name)} [${ev.kind}] ${status} (${dur})`);
|
|
1992
|
-
const nextIndent = indent + (last ? " " : "\u2502 ");
|
|
1993
|
-
if (n.children.length > 0) {
|
|
1994
|
-
const childStr = renderTreeAscii(n.children, nextIndent);
|
|
1995
|
-
if (childStr.length > 0) lines.push(childStr);
|
|
1996
|
-
}
|
|
1997
|
-
}
|
|
1998
|
-
return lines.join("\n");
|
|
1999
|
-
}
|
|
2000
|
-
function exportMarkdown(tree, options) {
|
|
2001
|
-
const warnings = [];
|
|
2002
|
-
const includeMetadata = options?.includeMetadata ?? true;
|
|
2003
|
-
const includeAttributes = options?.includeAttributes ?? false;
|
|
2004
|
-
const includeErrors = options?.includeErrors ?? true;
|
|
2005
|
-
const maxLen = options?.maxAttributeLength ?? 500;
|
|
2006
|
-
const titleName = tree.name ?? tree.runId;
|
|
2007
|
-
const lines = [];
|
|
2008
|
-
lines.push(`# AgentInspect Run: ${escapeMarkdown(titleName)}`);
|
|
2009
|
-
lines.push("");
|
|
2010
|
-
lines.push("Generated locally by AgentInspect. Review for sensitive data before sharing.");
|
|
2011
|
-
lines.push("");
|
|
2012
|
-
if (includeMetadata) {
|
|
2013
|
-
lines.push("## Summary");
|
|
2014
|
-
lines.push("");
|
|
2015
|
-
lines.push(`- **runId**: ${escapeMarkdown(tree.runId)}`);
|
|
2016
|
-
if (tree.name !== void 0) lines.push(`- **name**: ${escapeMarkdown(tree.name)}`);
|
|
2017
|
-
lines.push(`- **status**: ${escapeMarkdown(String(tree.status ?? "unknown"))}`);
|
|
2018
|
-
lines.push(
|
|
2019
|
-
`- **durationMs**: ${tree.durationMs !== void 0 ? escapeMarkdown(String(tree.durationMs)) : "-"}`
|
|
2020
|
-
);
|
|
2021
|
-
lines.push(
|
|
2022
|
-
`- **startedAt**: ${tree.startedAt !== void 0 ? escapeMarkdown(String(tree.startedAt)) : "-"}`
|
|
2023
|
-
);
|
|
2024
|
-
lines.push(
|
|
2025
|
-
`- **endedAt**: ${tree.endedAt !== void 0 ? escapeMarkdown(String(tree.endedAt)) : "-"}`
|
|
2026
|
-
);
|
|
2027
|
-
lines.push(`- **totalEvents**: ${tree.metadata.totalEvents}`);
|
|
2028
|
-
lines.push("");
|
|
2029
|
-
lines.push("### Confidence breakdown");
|
|
2030
|
-
lines.push("");
|
|
2031
|
-
lines.push("| bucket | count |");
|
|
2032
|
-
lines.push("| --- | --- |");
|
|
2033
|
-
for (const k of Object.keys(tree.metadata.confidenceBreakdown).sort()) {
|
|
2034
|
-
const key = k;
|
|
2035
|
-
lines.push(
|
|
2036
|
-
`| ${escapeMarkdown(key)} | ${tree.metadata.confidenceBreakdown[key]} |`
|
|
2037
|
-
);
|
|
2038
|
-
}
|
|
2039
|
-
lines.push("");
|
|
2040
|
-
lines.push("### Kind breakdown");
|
|
2041
|
-
lines.push("");
|
|
2042
|
-
lines.push("| kind | count |");
|
|
2043
|
-
lines.push("| --- | --- |");
|
|
2044
|
-
for (const k of Object.keys(tree.metadata.kinds).sort()) {
|
|
2045
|
-
const key = k;
|
|
2046
|
-
const c = tree.metadata.kinds[key];
|
|
2047
|
-
if (c > 0) lines.push(`| ${escapeMarkdown(key)} | ${c} |`);
|
|
2048
|
-
}
|
|
2049
|
-
lines.push("");
|
|
2063
|
+
if (event.source.type === "ai-sdk" || event.source.type === "otel") {
|
|
2064
|
+
attrs.originalSourceType = event.source.type;
|
|
2050
2065
|
}
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
lines.push("```text");
|
|
2054
|
-
lines.push(
|
|
2055
|
-
tree.children.length > 0 ? renderTreeAscii(tree.children) : "(no steps)"
|
|
2056
|
-
);
|
|
2057
|
-
lines.push("```");
|
|
2058
|
-
lines.push("");
|
|
2059
|
-
const flat = flattenTree(tree);
|
|
2060
|
-
const errors = flat.filter((n) => n.event.status === "error");
|
|
2061
|
-
if (includeErrors && errors.length > 0) {
|
|
2062
|
-
lines.push("## Errors");
|
|
2063
|
-
lines.push("");
|
|
2064
|
-
for (const n of errors) {
|
|
2065
|
-
const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString(
|
|
2066
|
-
n.event.attributes.error.message,
|
|
2067
|
-
maxLen
|
|
2068
|
-
) : "";
|
|
2069
|
-
lines.push(
|
|
2070
|
-
`- **${escapeMarkdown(n.event.name)}** (${escapeMarkdown(n.event.eventId)}): ${escapeMarkdown(msg || "error")}`
|
|
2071
|
-
);
|
|
2072
|
-
}
|
|
2073
|
-
lines.push("");
|
|
2066
|
+
if (event.source.name !== void 0) {
|
|
2067
|
+
attrs.sourceName = event.source.name;
|
|
2074
2068
|
}
|
|
2075
|
-
if (
|
|
2076
|
-
|
|
2077
|
-
lines.push("");
|
|
2078
|
-
for (const n of flat) {
|
|
2079
|
-
if (!n.event.attributes || Object.keys(n.event.attributes).length === 0) continue;
|
|
2080
|
-
const compact = compactAttributes(n.event.attributes, {
|
|
2081
|
-
maxLength: maxLen});
|
|
2082
|
-
lines.push(`### ${escapeMarkdown(n.event.name)}`);
|
|
2083
|
-
lines.push("");
|
|
2084
|
-
lines.push("```json");
|
|
2085
|
-
lines.push(stableJson(compact, true));
|
|
2086
|
-
lines.push("```");
|
|
2087
|
-
lines.push("");
|
|
2088
|
-
}
|
|
2089
|
-
warnings.push(
|
|
2090
|
-
"Attributes may still contain sensitive data; review exports before sharing."
|
|
2091
|
-
);
|
|
2069
|
+
if (event.source.version !== void 0) {
|
|
2070
|
+
attrs.sourceVersion = event.source.version;
|
|
2092
2071
|
}
|
|
2093
|
-
return
|
|
2094
|
-
format: "markdown",
|
|
2095
|
-
content: lines.join("\n"),
|
|
2096
|
-
contentType: "text/markdown",
|
|
2097
|
-
fileExtension: ".md",
|
|
2098
|
-
warnings
|
|
2099
|
-
};
|
|
2100
|
-
}
|
|
2101
|
-
|
|
2102
|
-
// packages/core/src/persisted/token-usage.ts
|
|
2103
|
-
function isRecord5(value) {
|
|
2104
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2105
|
-
}
|
|
2106
|
-
function nonNegativeFinite(value) {
|
|
2107
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
2072
|
+
return attrs;
|
|
2108
2073
|
}
|
|
2109
|
-
function
|
|
2110
|
-
if (!
|
|
2111
|
-
|
|
2112
|
-
const output = nonNegativeFinite(value.output);
|
|
2113
|
-
const suppliedTotal = nonNegativeFinite(value.total);
|
|
2114
|
-
const cached = nonNegativeFinite(value.cached);
|
|
2115
|
-
const derivedTotal = input !== void 0 && output !== void 0 && Number.isFinite(input + output) ? input + output : void 0;
|
|
2116
|
-
const total = suppliedTotal ?? derivedTotal;
|
|
2117
|
-
if (input === void 0 && output === void 0 && total === void 0 && cached === void 0) {
|
|
2118
|
-
return void 0;
|
|
2074
|
+
function persistedInspectEventToInspectEvent(event) {
|
|
2075
|
+
if (!isPersistedInspectEvent(event)) {
|
|
2076
|
+
throw new Error("Invalid PersistedInspectEvent: failed isPersistedInspectEvent");
|
|
2119
2077
|
}
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
...cached !== void 0 ? { cached } : {}
|
|
2125
|
-
};
|
|
2126
|
-
}
|
|
2127
|
-
|
|
2128
|
-
// packages/core/src/persisted/from-trace-event.ts
|
|
2129
|
-
function sanitizeIdPart(value) {
|
|
2130
|
-
return value.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2131
|
-
}
|
|
2132
|
-
function nodeIdForEvent(event) {
|
|
2133
|
-
switch (event.event) {
|
|
2134
|
-
case "run_started":
|
|
2135
|
-
case "run_completed":
|
|
2136
|
-
return event.runId;
|
|
2137
|
-
case "step_started":
|
|
2138
|
-
case "step_completed":
|
|
2139
|
-
return event.stepId;
|
|
2140
|
-
default:
|
|
2141
|
-
return "unknown";
|
|
2078
|
+
const ts = parseIsoToMs3(event.timestamp);
|
|
2079
|
+
const attrs = buildInspectAttributes(event);
|
|
2080
|
+
if (ts.invalidTimestamp) {
|
|
2081
|
+
attrs.invalidTimestamp = true;
|
|
2142
2082
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
return `manual:${runId}:${ev}:${node}:${eventIndex}`;
|
|
2149
|
-
}
|
|
2150
|
-
function toIsoTimestamp(ms) {
|
|
2151
|
-
if (typeof ms !== "number" || !Number.isFinite(ms)) {
|
|
2152
|
-
return { iso: (/* @__PURE__ */ new Date(0)).toISOString(), invalidTimestamp: true };
|
|
2083
|
+
let status;
|
|
2084
|
+
if (event.status === "running" || event.status === "ok" || event.status === "error") {
|
|
2085
|
+
status = event.status;
|
|
2086
|
+
} else if (event.status === "unknown") {
|
|
2087
|
+
attrs.persistedStatus = "unknown";
|
|
2153
2088
|
}
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2089
|
+
const out = {
|
|
2090
|
+
eventId: event.eventId,
|
|
2091
|
+
runId: event.runId,
|
|
2092
|
+
name: event.name,
|
|
2093
|
+
kind: event.kind,
|
|
2094
|
+
timestamp: ts.ms,
|
|
2095
|
+
confidence: event.confidence,
|
|
2096
|
+
source: mapPersistedSourceToInspect(event),
|
|
2097
|
+
attributes: compactAttributes2(attrs)
|
|
2161
2098
|
};
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
switch (type) {
|
|
2165
|
-
case "run":
|
|
2166
|
-
return "RUN";
|
|
2167
|
-
case "llm":
|
|
2168
|
-
return "LLM";
|
|
2169
|
-
case "tool":
|
|
2170
|
-
return "TOOL";
|
|
2171
|
-
case "decision":
|
|
2172
|
-
return "DECISION";
|
|
2173
|
-
case "logic":
|
|
2174
|
-
case "state":
|
|
2175
|
-
case "custom":
|
|
2176
|
-
return "LOGIC";
|
|
2177
|
-
default:
|
|
2178
|
-
return "LOGIC";
|
|
2099
|
+
if (event.parentId !== void 0) {
|
|
2100
|
+
out.parentId = event.parentId;
|
|
2179
2101
|
}
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
return status === "success" ? "ok" : "error";
|
|
2183
|
-
}
|
|
2184
|
-
function mapErrorInfo(error) {
|
|
2185
|
-
if (!error?.message) {
|
|
2186
|
-
return {};
|
|
2102
|
+
if (status !== void 0) {
|
|
2103
|
+
out.status = status;
|
|
2187
2104
|
}
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
message: error.message,
|
|
2191
|
-
name: "Error"
|
|
2192
|
-
}
|
|
2193
|
-
};
|
|
2194
|
-
if (typeof error.stack === "string" && error.stack.length > 0) {
|
|
2195
|
-
out.errorStack = error.stack;
|
|
2196
|
-
}
|
|
2197
|
-
return out;
|
|
2198
|
-
}
|
|
2199
|
-
function mapTokenUsageFromMetadata(metadata) {
|
|
2200
|
-
return normalizeTokenUsage(metadata?.tokens);
|
|
2201
|
-
}
|
|
2202
|
-
function compactAttributes2(entries) {
|
|
2203
|
-
const out = {};
|
|
2204
|
-
for (const [key, value] of Object.entries(entries)) {
|
|
2205
|
-
if (value !== void 0) {
|
|
2206
|
-
out[key] = value;
|
|
2207
|
-
}
|
|
2208
|
-
}
|
|
2209
|
-
return Object.keys(out).length > 0 ? out : void 0;
|
|
2210
|
-
}
|
|
2211
|
-
function traceEventToPersistedInspectEvent(event, options) {
|
|
2212
|
-
const eventIndex = options?.eventIndex ?? 0;
|
|
2213
|
-
const eventId = createPersistedEventId(event, eventIndex);
|
|
2214
|
-
const source = buildSource(options);
|
|
2215
|
-
const tsMain = toIsoTimestamp(event.timestamp);
|
|
2216
|
-
switch (event.event) {
|
|
2217
|
-
case "run_started": {
|
|
2218
|
-
const tsStart = toIsoTimestamp(event.startTime);
|
|
2219
|
-
const correlation = extractCorrelationMetadata(event.metadata);
|
|
2220
|
-
const attributes = compactAttributes2({
|
|
2221
|
-
legacyEvent: "run_started",
|
|
2222
|
-
metadata: event.metadata !== void 0 ? { ...event.metadata } : void 0,
|
|
2223
|
-
correlationId: correlation?.correlationId,
|
|
2224
|
-
requestId: correlation?.requestId,
|
|
2225
|
-
decisionId: correlation?.decisionId,
|
|
2226
|
-
groupId: correlation?.groupId,
|
|
2227
|
-
invalidTimestamp: tsMain.invalidTimestamp || tsStart.invalidTimestamp ? true : void 0
|
|
2228
|
-
});
|
|
2229
|
-
return {
|
|
2230
|
-
schemaVersion: "0.2",
|
|
2231
|
-
eventId,
|
|
2232
|
-
runId: event.runId,
|
|
2233
|
-
kind: "RUN",
|
|
2234
|
-
name: event.name,
|
|
2235
|
-
status: "running",
|
|
2236
|
-
timestamp: tsMain.iso,
|
|
2237
|
-
startedAt: tsStart.iso,
|
|
2238
|
-
confidence: "explicit",
|
|
2239
|
-
source,
|
|
2240
|
-
attributes
|
|
2241
|
-
};
|
|
2242
|
-
}
|
|
2243
|
-
case "run_completed": {
|
|
2244
|
-
const tsEnd = toIsoTimestamp(event.endTime);
|
|
2245
|
-
const { persisted: error, errorStack } = mapErrorInfo(event.error);
|
|
2246
|
-
const attributes = compactAttributes2({
|
|
2247
|
-
legacyEvent: "run_completed",
|
|
2248
|
-
errorStack,
|
|
2249
|
-
invalidTimestamp: tsMain.invalidTimestamp || tsEnd.invalidTimestamp ? true : void 0
|
|
2250
|
-
});
|
|
2251
|
-
return {
|
|
2252
|
-
schemaVersion: "0.2",
|
|
2253
|
-
eventId,
|
|
2254
|
-
runId: event.runId,
|
|
2255
|
-
kind: "RUN",
|
|
2256
|
-
name: "run",
|
|
2257
|
-
status: mapRunOrStepStatus(event.status),
|
|
2258
|
-
timestamp: tsMain.iso,
|
|
2259
|
-
endedAt: tsEnd.iso,
|
|
2260
|
-
durationMs: event.durationMs,
|
|
2261
|
-
confidence: "explicit",
|
|
2262
|
-
source,
|
|
2263
|
-
attributes,
|
|
2264
|
-
error
|
|
2265
|
-
};
|
|
2266
|
-
}
|
|
2267
|
-
case "step_started": {
|
|
2268
|
-
const tsStart = toIsoTimestamp(event.startTime);
|
|
2269
|
-
const tokenUsage = mapTokenUsageFromMetadata(event.metadata);
|
|
2270
|
-
const attributes = compactAttributes2({
|
|
2271
|
-
legacyEvent: "step_started",
|
|
2272
|
-
stepId: event.stepId,
|
|
2273
|
-
stepType: event.type,
|
|
2274
|
-
metadata: event.metadata !== void 0 ? { ...event.metadata } : void 0,
|
|
2275
|
-
invalidTimestamp: tsMain.invalidTimestamp || tsStart.invalidTimestamp ? true : void 0
|
|
2276
|
-
});
|
|
2277
|
-
const out = {
|
|
2278
|
-
schemaVersion: "0.2",
|
|
2279
|
-
eventId,
|
|
2280
|
-
runId: event.runId,
|
|
2281
|
-
kind: mapStepTypeToInspectKind(event.type),
|
|
2282
|
-
name: event.name,
|
|
2283
|
-
status: "running",
|
|
2284
|
-
timestamp: tsMain.iso,
|
|
2285
|
-
startedAt: tsStart.iso,
|
|
2286
|
-
confidence: "explicit",
|
|
2287
|
-
source,
|
|
2288
|
-
attributes
|
|
2289
|
-
};
|
|
2290
|
-
if (event.parentId !== void 0) {
|
|
2291
|
-
out.parentId = event.parentId;
|
|
2292
|
-
}
|
|
2293
|
-
if (tokenUsage !== void 0) {
|
|
2294
|
-
out.tokenUsage = tokenUsage;
|
|
2295
|
-
}
|
|
2296
|
-
return out;
|
|
2297
|
-
}
|
|
2298
|
-
case "step_completed": {
|
|
2299
|
-
const tsEnd = toIsoTimestamp(event.endTime);
|
|
2300
|
-
const { persisted: error, errorStack } = mapErrorInfo(event.error);
|
|
2301
|
-
const attributes = compactAttributes2({
|
|
2302
|
-
legacyEvent: "step_completed",
|
|
2303
|
-
stepId: event.stepId,
|
|
2304
|
-
errorStack,
|
|
2305
|
-
invalidTimestamp: tsMain.invalidTimestamp || tsEnd.invalidTimestamp ? true : void 0
|
|
2306
|
-
});
|
|
2307
|
-
return {
|
|
2308
|
-
schemaVersion: "0.2",
|
|
2309
|
-
eventId,
|
|
2310
|
-
runId: event.runId,
|
|
2311
|
-
kind: "LOGIC",
|
|
2312
|
-
name: event.stepId,
|
|
2313
|
-
status: mapRunOrStepStatus(event.status),
|
|
2314
|
-
timestamp: tsMain.iso,
|
|
2315
|
-
endedAt: tsEnd.iso,
|
|
2316
|
-
durationMs: event.durationMs,
|
|
2317
|
-
confidence: "explicit",
|
|
2318
|
-
source,
|
|
2319
|
-
attributes,
|
|
2320
|
-
error
|
|
2321
|
-
};
|
|
2322
|
-
}
|
|
2323
|
-
default: {
|
|
2324
|
-
const _exhaustive = event;
|
|
2325
|
-
throw new Error(`Unsupported trace event: ${_exhaustive.event}`);
|
|
2326
|
-
}
|
|
2327
|
-
}
|
|
2328
|
-
}
|
|
2329
|
-
function traceEventsToPersistedInspectEvents(events, options) {
|
|
2330
|
-
return events.map(
|
|
2331
|
-
(event, index) => traceEventToPersistedInspectEvent(event, { ...options, eventIndex: index })
|
|
2332
|
-
);
|
|
2333
|
-
}
|
|
2334
|
-
|
|
2335
|
-
// packages/core/src/persisted/to-inspect-event.ts
|
|
2336
|
-
function compactAttributes3(entries) {
|
|
2337
|
-
const out = {};
|
|
2338
|
-
for (const [key, value] of Object.entries(entries)) {
|
|
2339
|
-
if (value !== void 0) {
|
|
2340
|
-
out[key] = value;
|
|
2341
|
-
}
|
|
2342
|
-
}
|
|
2343
|
-
return Object.keys(out).length > 0 ? out : void 0;
|
|
2344
|
-
}
|
|
2345
|
-
function parseIsoToMs3(iso) {
|
|
2346
|
-
const parsed = Date.parse(iso);
|
|
2347
|
-
if (!Number.isFinite(parsed)) {
|
|
2348
|
-
return { ms: 0, invalidTimestamp: true };
|
|
2349
|
-
}
|
|
2350
|
-
return { ms: parsed, invalidTimestamp: false };
|
|
2351
|
-
}
|
|
2352
|
-
function mapPersistedSourceToInspect(event) {
|
|
2353
|
-
const attrs = event.attributes ?? {};
|
|
2354
|
-
const sourceName = event.source.name;
|
|
2355
|
-
if (sourceName === "pino") {
|
|
2356
|
-
return {
|
|
2357
|
-
type: "pino",
|
|
2358
|
-
file: typeof attrs.sourceFile === "string" ? attrs.sourceFile : void 0,
|
|
2359
|
-
line: typeof attrs.sourceLine === "number" ? attrs.sourceLine : void 0
|
|
2360
|
-
};
|
|
2361
|
-
}
|
|
2362
|
-
if (sourceName === "winston") {
|
|
2363
|
-
return {
|
|
2364
|
-
type: "winston",
|
|
2365
|
-
file: typeof attrs.sourceFile === "string" ? attrs.sourceFile : void 0,
|
|
2366
|
-
line: typeof attrs.sourceLine === "number" ? attrs.sourceLine : void 0
|
|
2367
|
-
};
|
|
2368
|
-
}
|
|
2369
|
-
const mapType = (t) => {
|
|
2370
|
-
switch (t) {
|
|
2371
|
-
case "manual":
|
|
2372
|
-
return "manual";
|
|
2373
|
-
case "json-log":
|
|
2374
|
-
return "json-log";
|
|
2375
|
-
case "log4js":
|
|
2376
|
-
return "log4js";
|
|
2377
|
-
case "adapter":
|
|
2378
|
-
case "ai-sdk":
|
|
2379
|
-
case "otel":
|
|
2380
|
-
return "adapter";
|
|
2381
|
-
default:
|
|
2382
|
-
return "json-log";
|
|
2383
|
-
}
|
|
2384
|
-
};
|
|
2385
|
-
return {
|
|
2386
|
-
type: mapType(event.source.type),
|
|
2387
|
-
file: typeof attrs.sourceFile === "string" ? attrs.sourceFile : void 0,
|
|
2388
|
-
line: typeof attrs.sourceLine === "number" ? attrs.sourceLine : void 0
|
|
2389
|
-
};
|
|
2390
|
-
}
|
|
2391
|
-
function buildInspectAttributes(event) {
|
|
2392
|
-
const attrs = event.attributes !== void 0 ? { ...event.attributes } : {};
|
|
2393
|
-
if (event.inputSummary !== void 0) {
|
|
2394
|
-
attrs.inputSummary = event.inputSummary;
|
|
2395
|
-
}
|
|
2396
|
-
if (event.outputSummary !== void 0) {
|
|
2397
|
-
attrs.outputSummary = event.outputSummary;
|
|
2398
|
-
}
|
|
2399
|
-
if (event.error) {
|
|
2400
|
-
if (event.error.name !== void 0) {
|
|
2401
|
-
attrs.errorName = event.error.name;
|
|
2402
|
-
}
|
|
2403
|
-
attrs.errorMessage = event.error.message;
|
|
2404
|
-
if (event.error.code !== void 0) {
|
|
2405
|
-
attrs.errorCode = event.error.code;
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
if (event.tokenUsage) {
|
|
2409
|
-
attrs.tokens = { ...event.tokenUsage };
|
|
2410
|
-
}
|
|
2411
|
-
if (event.source.type === "ai-sdk" || event.source.type === "otel") {
|
|
2412
|
-
attrs.originalSourceType = event.source.type;
|
|
2413
|
-
}
|
|
2414
|
-
if (event.source.name !== void 0) {
|
|
2415
|
-
attrs.sourceName = event.source.name;
|
|
2416
|
-
}
|
|
2417
|
-
if (event.source.version !== void 0) {
|
|
2418
|
-
attrs.sourceVersion = event.source.version;
|
|
2419
|
-
}
|
|
2420
|
-
return attrs;
|
|
2421
|
-
}
|
|
2422
|
-
function persistedInspectEventToInspectEvent(event) {
|
|
2423
|
-
if (!isPersistedInspectEvent(event)) {
|
|
2424
|
-
throw new Error("Invalid PersistedInspectEvent: failed isPersistedInspectEvent");
|
|
2425
|
-
}
|
|
2426
|
-
const ts = parseIsoToMs3(event.timestamp);
|
|
2427
|
-
const attrs = buildInspectAttributes(event);
|
|
2428
|
-
if (ts.invalidTimestamp) {
|
|
2429
|
-
attrs.invalidTimestamp = true;
|
|
2430
|
-
}
|
|
2431
|
-
let status;
|
|
2432
|
-
if (event.status === "running" || event.status === "ok" || event.status === "error") {
|
|
2433
|
-
status = event.status;
|
|
2434
|
-
} else if (event.status === "unknown") {
|
|
2435
|
-
attrs.persistedStatus = "unknown";
|
|
2436
|
-
}
|
|
2437
|
-
const out = {
|
|
2438
|
-
eventId: event.eventId,
|
|
2439
|
-
runId: event.runId,
|
|
2440
|
-
name: event.name,
|
|
2441
|
-
kind: event.kind,
|
|
2442
|
-
timestamp: ts.ms,
|
|
2443
|
-
confidence: event.confidence,
|
|
2444
|
-
source: mapPersistedSourceToInspect(event),
|
|
2445
|
-
attributes: compactAttributes3(attrs)
|
|
2446
|
-
};
|
|
2447
|
-
if (event.parentId !== void 0) {
|
|
2448
|
-
out.parentId = event.parentId;
|
|
2449
|
-
}
|
|
2450
|
-
if (status !== void 0) {
|
|
2451
|
-
out.status = status;
|
|
2452
|
-
}
|
|
2453
|
-
if (event.durationMs !== void 0 && Number.isFinite(event.durationMs) && event.durationMs >= 0) {
|
|
2454
|
-
out.durationMs = event.durationMs;
|
|
2105
|
+
if (event.durationMs !== void 0 && Number.isFinite(event.durationMs) && event.durationMs >= 0) {
|
|
2106
|
+
out.durationMs = event.durationMs;
|
|
2455
2107
|
}
|
|
2456
2108
|
return out;
|
|
2457
2109
|
}
|
|
@@ -2470,93 +2122,15 @@ function persistedInspectEventsToInspectEvents(events, options) {
|
|
|
2470
2122
|
return out;
|
|
2471
2123
|
}
|
|
2472
2124
|
|
|
2473
|
-
// packages/core/src/
|
|
2474
|
-
function
|
|
2475
|
-
|
|
2125
|
+
// packages/core/src/persisted/tree-bridge.ts
|
|
2126
|
+
function persistedInspectEventsToRunTrees(events, options) {
|
|
2127
|
+
const inspectEvents = persistedInspectEventsToInspectEvents(events, {
|
|
2128
|
+
skipInvalid: options?.skipInvalid
|
|
2129
|
+
});
|
|
2130
|
+
return new TreeBuilder().build(inspectEvents);
|
|
2476
2131
|
}
|
|
2477
|
-
function computeRunStatus(events) {
|
|
2478
|
-
let hasRunning = false;
|
|
2479
|
-
for (const e of events) {
|
|
2480
|
-
if (e.status === "error") return "error";
|
|
2481
|
-
if (e.status === "running") hasRunning = true;
|
|
2482
|
-
}
|
|
2483
|
-
if (hasRunning) return "running";
|
|
2484
|
-
return "ok";
|
|
2485
|
-
}
|
|
2486
|
-
var TreeBuilder = class {
|
|
2487
|
-
constructor(options) {
|
|
2488
|
-
void options?.config;
|
|
2489
|
-
}
|
|
2490
|
-
build(events) {
|
|
2491
|
-
const byRun = /* @__PURE__ */ new Map();
|
|
2492
|
-
for (const e of events) {
|
|
2493
|
-
if (!byRun.has(e.runId)) byRun.set(e.runId, []);
|
|
2494
|
-
byRun.get(e.runId).push(e);
|
|
2495
|
-
}
|
|
2496
|
-
const out = [];
|
|
2497
|
-
for (const [runId, runEvents] of byRun.entries()) {
|
|
2498
|
-
const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
|
|
2499
|
-
const nodes = /* @__PURE__ */ new Map();
|
|
2500
|
-
for (const e of sorted) {
|
|
2501
|
-
nodes.set(e.eventId, { event: e, children: [], depth: 0 });
|
|
2502
|
-
}
|
|
2503
|
-
const roots = [];
|
|
2504
|
-
for (const node of nodes.values()) {
|
|
2505
|
-
const parentId = node.event.parentId;
|
|
2506
|
-
if (parentId && nodes.has(parentId)) {
|
|
2507
|
-
nodes.get(parentId).children.push(node);
|
|
2508
|
-
} else {
|
|
2509
|
-
roots.push(node);
|
|
2510
|
-
}
|
|
2511
|
-
}
|
|
2512
|
-
const assignDepth = (n, depth) => {
|
|
2513
|
-
n.depth = depth;
|
|
2514
|
-
for (const c of n.children) assignDepth(c, depth + 1);
|
|
2515
|
-
};
|
|
2516
|
-
for (const r of roots) assignDepth(r, 0);
|
|
2517
|
-
const confidenceBreakdown = {
|
|
2518
|
-
explicit: 0,
|
|
2519
|
-
correlated: 0,
|
|
2520
|
-
heuristic: 0,
|
|
2521
|
-
unknown: 0
|
|
2522
|
-
};
|
|
2523
|
-
const kinds = {};
|
|
2524
|
-
for (const e of sorted) {
|
|
2525
|
-
inc(confidenceBreakdown, e.confidence);
|
|
2526
|
-
kinds[e.kind] = (kinds[e.kind] ?? 0) + 1;
|
|
2527
|
-
}
|
|
2528
|
-
const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
|
|
2529
|
-
const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
|
|
2530
|
-
const status = computeRunStatus(sorted);
|
|
2531
|
-
const durationMs = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
|
|
2532
|
-
const name = sorted.find((e) => e.kind === "RUN")?.name;
|
|
2533
|
-
out.push({
|
|
2534
|
-
runId,
|
|
2535
|
-
name,
|
|
2536
|
-
status,
|
|
2537
|
-
startedAt,
|
|
2538
|
-
endedAt: status === "running" ? void 0 : endedAt,
|
|
2539
|
-
durationMs,
|
|
2540
|
-
children: roots,
|
|
2541
|
-
metadata: {
|
|
2542
|
-
totalEvents: sorted.length,
|
|
2543
|
-
confidenceBreakdown,
|
|
2544
|
-
kinds
|
|
2545
|
-
}
|
|
2546
|
-
});
|
|
2547
|
-
}
|
|
2548
|
-
out.sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0));
|
|
2549
|
-
return out;
|
|
2550
|
-
}
|
|
2551
|
-
};
|
|
2552
2132
|
|
|
2553
|
-
// packages/core/src/
|
|
2554
|
-
function persistedInspectEventsToRunTrees(events, options) {
|
|
2555
|
-
const inspectEvents = persistedInspectEventsToInspectEvents(events, {
|
|
2556
|
-
skipInvalid: options?.skipInvalid
|
|
2557
|
-
});
|
|
2558
|
-
return new TreeBuilder().build(inspectEvents);
|
|
2559
|
-
}
|
|
2133
|
+
// packages/core/src/readers/index.ts
|
|
2560
2134
|
var DEFAULT_MAX_TRACE_INPUT_BYTES = 10 * 1024 * 1024;
|
|
2561
2135
|
var MIN_DETECTION_CONFIDENCE = 0.5;
|
|
2562
2136
|
var AMBIGUOUS_CONFIDENCE_DELTA = 0.05;
|
|
@@ -3049,7 +2623,7 @@ function sanitizeOpenInferenceAttributes(attributes, pathPrefix) {
|
|
|
3049
2623
|
function mapOpenInferenceKind(span, attributes, pathPrefix) {
|
|
3050
2624
|
const warnings = [];
|
|
3051
2625
|
const agentInspectKind = attributes["agent_inspect.kind"];
|
|
3052
|
-
if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
|
|
2626
|
+
if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG" || agentInspectKind === "OUTCOME") {
|
|
3053
2627
|
return { kind: agentInspectKind, warnings };
|
|
3054
2628
|
}
|
|
3055
2629
|
const rawKind = readStringField(span, ["kind", "span_kind", "spanKind"]) ?? (typeof attributes["openinference.span.kind"] === "string" ? attributes["openinference.span.kind"] : void 0);
|
|
@@ -3570,7 +3144,7 @@ function mapOtlpStatus(status) {
|
|
|
3570
3144
|
function readOtlpKind(attributes, pathPrefix) {
|
|
3571
3145
|
const warnings = [];
|
|
3572
3146
|
const agentInspectKind = attributes["agent_inspect.kind"];
|
|
3573
|
-
if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
|
|
3147
|
+
if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG" || agentInspectKind === "OUTCOME") {
|
|
3574
3148
|
return { kind: agentInspectKind, warnings };
|
|
3575
3149
|
}
|
|
3576
3150
|
const operation = attributes["gen_ai.operation.name"];
|
|
@@ -4034,100 +3608,667 @@ async function detectTraceFormat(input, options = {}) {
|
|
|
4034
3608
|
});
|
|
4035
3609
|
}
|
|
4036
3610
|
}
|
|
4037
|
-
const sorted = sortCandidates(
|
|
4038
|
-
candidates.filter((candidate) => candidate.confidence >= MIN_DETECTION_CONFIDENCE)
|
|
4039
|
-
);
|
|
4040
|
-
const candidateWarnings = collectWarnings(sorted);
|
|
4041
|
-
const lowConfidenceWarnings = candidates.length > sorted.length ? [
|
|
4042
|
-
{
|
|
4043
|
-
code: "low_confidence_candidates",
|
|
4044
|
-
message: `Ignored ${candidates.length - sorted.length} low-confidence format candidate(s).`,
|
|
4045
|
-
severity: "info"
|
|
3611
|
+
const sorted = sortCandidates(
|
|
3612
|
+
candidates.filter((candidate) => candidate.confidence >= MIN_DETECTION_CONFIDENCE)
|
|
3613
|
+
);
|
|
3614
|
+
const candidateWarnings = collectWarnings(sorted);
|
|
3615
|
+
const lowConfidenceWarnings = candidates.length > sorted.length ? [
|
|
3616
|
+
{
|
|
3617
|
+
code: "low_confidence_candidates",
|
|
3618
|
+
message: `Ignored ${candidates.length - sorted.length} low-confidence format candidate(s).`,
|
|
3619
|
+
severity: "info"
|
|
3620
|
+
}
|
|
3621
|
+
] : [];
|
|
3622
|
+
const allWarnings = dedupeWarnings([
|
|
3623
|
+
...warnings,
|
|
3624
|
+
...candidateWarnings,
|
|
3625
|
+
...lowConfidenceWarnings
|
|
3626
|
+
]);
|
|
3627
|
+
if (sorted.length === 0) {
|
|
3628
|
+
return {
|
|
3629
|
+
status: "unsupported",
|
|
3630
|
+
candidates: [],
|
|
3631
|
+
warnings: allWarnings
|
|
3632
|
+
};
|
|
3633
|
+
}
|
|
3634
|
+
const [best, second] = sorted;
|
|
3635
|
+
if (second !== void 0 && best.confidence - second.confidence <= AMBIGUOUS_CONFIDENCE_DELTA) {
|
|
3636
|
+
return {
|
|
3637
|
+
status: "ambiguous",
|
|
3638
|
+
candidates: sorted,
|
|
3639
|
+
warnings: [
|
|
3640
|
+
...allWarnings,
|
|
3641
|
+
{
|
|
3642
|
+
code: "ambiguous_format_candidates",
|
|
3643
|
+
message: `Top trace format candidates are within ${AMBIGUOUS_CONFIDENCE_DELTA} confidence.`,
|
|
3644
|
+
severity: "warning"
|
|
3645
|
+
}
|
|
3646
|
+
]
|
|
3647
|
+
};
|
|
3648
|
+
}
|
|
3649
|
+
return {
|
|
3650
|
+
status: "detected",
|
|
3651
|
+
format: best.format,
|
|
3652
|
+
candidates: sorted,
|
|
3653
|
+
warnings: allWarnings
|
|
3654
|
+
};
|
|
3655
|
+
}
|
|
3656
|
+
async function readTrace(input, options = {}) {
|
|
3657
|
+
const readers = options.readers ?? DEFAULT_TRACE_READERS;
|
|
3658
|
+
const detection = await detectTraceFormat(input, options);
|
|
3659
|
+
if (detection.status === "unsupported" || detection.format === void 0) {
|
|
3660
|
+
throw new TraceReadError(
|
|
3661
|
+
"unsupported_format",
|
|
3662
|
+
"No trace reader could detect the input format.",
|
|
3663
|
+
detection.warnings
|
|
3664
|
+
);
|
|
3665
|
+
}
|
|
3666
|
+
if (detection.status === "ambiguous") {
|
|
3667
|
+
throw new TraceReadError(
|
|
3668
|
+
"ambiguous_format",
|
|
3669
|
+
"Multiple trace readers matched the input with equal confidence.",
|
|
3670
|
+
detection.warnings
|
|
3671
|
+
);
|
|
3672
|
+
}
|
|
3673
|
+
const reader = findReaderByFormat(detection.format, readers);
|
|
3674
|
+
if (!reader) {
|
|
3675
|
+
throw new TraceReadError(
|
|
3676
|
+
"unsupported_format",
|
|
3677
|
+
`No trace reader is registered for format "${detection.format}".`,
|
|
3678
|
+
detection.warnings
|
|
3679
|
+
);
|
|
3680
|
+
}
|
|
3681
|
+
try {
|
|
3682
|
+
const result = await reader.read(input, { format: detection.format });
|
|
3683
|
+
return {
|
|
3684
|
+
...result,
|
|
3685
|
+
format: result.format || detection.format,
|
|
3686
|
+
warnings: [...detection.warnings, ...result.warnings]
|
|
3687
|
+
};
|
|
3688
|
+
} catch (error) {
|
|
3689
|
+
if (error instanceof TraceReadError) {
|
|
3690
|
+
throw new TraceReadError(
|
|
3691
|
+
error.code,
|
|
3692
|
+
error.message,
|
|
3693
|
+
dedupeWarnings([...detection.warnings, ...error.warnings])
|
|
3694
|
+
);
|
|
3695
|
+
}
|
|
3696
|
+
throw new TraceReadError(
|
|
3697
|
+
"reader_failed",
|
|
3698
|
+
error instanceof Error && error.message.trim() !== "" ? error.message : `Trace reader "${reader.format}" failed.`,
|
|
3699
|
+
detection.warnings
|
|
3700
|
+
);
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
function openTrace(input, options = {}) {
|
|
3704
|
+
return readTrace(input, options);
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3707
|
+
// packages/core/src/diff/comparable.ts
|
|
3708
|
+
function extractOutputPreview(meta) {
|
|
3709
|
+
if (meta === void 0) return void 0;
|
|
3710
|
+
if ("outputPreview" in meta) return meta.outputPreview;
|
|
3711
|
+
if ("resultPreview" in meta) return meta.resultPreview;
|
|
3712
|
+
return void 0;
|
|
3713
|
+
}
|
|
3714
|
+
function mapStepStatus(s) {
|
|
3715
|
+
if (s === void 0) return "running";
|
|
3716
|
+
return s;
|
|
3717
|
+
}
|
|
3718
|
+
function manualTraceEventsToComparableRun(events) {
|
|
3719
|
+
const started = events.find((e) => e.event === "run_started");
|
|
3720
|
+
if (!started || started.event !== "run_started") {
|
|
3721
|
+
throw new Error("Invalid trace: missing run_started");
|
|
3722
|
+
}
|
|
3723
|
+
const rs = started;
|
|
3724
|
+
const runId = rs.runId;
|
|
3725
|
+
const completedAll = events.filter((e) => e.event === "run_completed");
|
|
3726
|
+
const lastCompleted = completedAll[completedAll.length - 1];
|
|
3727
|
+
let runStatus;
|
|
3728
|
+
if (lastCompleted === void 0) runStatus = "running";
|
|
3729
|
+
else runStatus = lastCompleted.status;
|
|
3730
|
+
const durationMs = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
3731
|
+
const steps = /* @__PURE__ */ new Map();
|
|
3732
|
+
let order = 0;
|
|
3733
|
+
for (const e of events) {
|
|
3734
|
+
if (e.event !== "step_started") continue;
|
|
3735
|
+
const s = e;
|
|
3736
|
+
const meta = s.metadata ? { ...s.metadata } : void 0;
|
|
3737
|
+
steps.set(s.stepId, {
|
|
3738
|
+
id: s.stepId,
|
|
3739
|
+
parentId: s.parentId,
|
|
3740
|
+
name: s.name,
|
|
3741
|
+
type: s.type,
|
|
3742
|
+
order: order++,
|
|
3743
|
+
timestamp: s.timestamp,
|
|
3744
|
+
metadata: meta
|
|
3745
|
+
});
|
|
3746
|
+
}
|
|
3747
|
+
for (const e of events) {
|
|
3748
|
+
if (e.event !== "step_completed") continue;
|
|
3749
|
+
const acc = steps.get(e.stepId);
|
|
3750
|
+
if (!acc) continue;
|
|
3751
|
+
acc.status = e.status;
|
|
3752
|
+
acc.durationMs = e.durationMs;
|
|
3753
|
+
if (e.error?.message) acc.errorMsg = e.error.message;
|
|
3754
|
+
const extra = e;
|
|
3755
|
+
if (extra.metadata !== void 0 && typeof extra.metadata === "object") {
|
|
3756
|
+
acc.metadata = { ...acc.metadata ?? {}, ...extra.metadata };
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
3760
|
+
for (const acc of steps.values()) {
|
|
3761
|
+
let meta = acc.metadata ? { ...acc.metadata } : void 0;
|
|
3762
|
+
if (acc.parentId !== void 0 && !steps.has(acc.parentId)) {
|
|
3763
|
+
meta = { ...meta ?? {}, agent_inspect_diff_parent_missing: true };
|
|
3764
|
+
}
|
|
3765
|
+
const outputPreview = extractOutputPreview(meta);
|
|
3766
|
+
const sc = {
|
|
3767
|
+
id: acc.id,
|
|
3768
|
+
name: acc.name,
|
|
3769
|
+
type: acc.type,
|
|
3770
|
+
status: mapStepStatus(acc.status),
|
|
3771
|
+
durationMs: acc.durationMs,
|
|
3772
|
+
error: acc.errorMsg,
|
|
3773
|
+
metadata: meta && Object.keys(meta).length > 0 ? meta : void 0,
|
|
3774
|
+
outputPreview,
|
|
3775
|
+
children: []
|
|
3776
|
+
};
|
|
3777
|
+
nodes.set(acc.id, sc);
|
|
3778
|
+
}
|
|
3779
|
+
const roots = [];
|
|
3780
|
+
const sortByOrder = (a, b) => {
|
|
3781
|
+
const oa = steps.get(a.id)?.order ?? 0;
|
|
3782
|
+
const ob = steps.get(b.id)?.order ?? 0;
|
|
3783
|
+
return oa - ob;
|
|
3784
|
+
};
|
|
3785
|
+
for (const acc of steps.values()) {
|
|
3786
|
+
const node = nodes.get(acc.id);
|
|
3787
|
+
if (acc.parentId !== void 0 && nodes.has(acc.parentId)) {
|
|
3788
|
+
nodes.get(acc.parentId).children.push(node);
|
|
3789
|
+
} else {
|
|
3790
|
+
roots.push(node);
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3793
|
+
roots.sort(sortByOrder);
|
|
3794
|
+
for (const n of nodes.values()) {
|
|
3795
|
+
n.children.sort(sortByOrder);
|
|
3796
|
+
}
|
|
3797
|
+
return {
|
|
3798
|
+
runId,
|
|
3799
|
+
name: rs.name,
|
|
3800
|
+
status: runStatus,
|
|
3801
|
+
durationMs,
|
|
3802
|
+
steps: roots
|
|
3803
|
+
};
|
|
3804
|
+
}
|
|
3805
|
+
|
|
3806
|
+
// packages/core/src/exporters/helpers.ts
|
|
3807
|
+
var REDACT_SUBSTRINGS = [
|
|
3808
|
+
"authorization",
|
|
3809
|
+
"cookie",
|
|
3810
|
+
"token",
|
|
3811
|
+
"apikey",
|
|
3812
|
+
"password",
|
|
3813
|
+
"secret",
|
|
3814
|
+
"email"
|
|
3815
|
+
];
|
|
3816
|
+
function shouldRedactKey(key) {
|
|
3817
|
+
const k = key.toLowerCase();
|
|
3818
|
+
for (const s of REDACT_SUBSTRINGS) {
|
|
3819
|
+
if (k.includes(s)) return true;
|
|
3820
|
+
}
|
|
3821
|
+
return false;
|
|
3822
|
+
}
|
|
3823
|
+
function safeString(value, maxLength) {
|
|
3824
|
+
if (value === null || value === void 0) return "";
|
|
3825
|
+
let s;
|
|
3826
|
+
if (typeof value === "string") s = value;
|
|
3827
|
+
else if (typeof value === "number" || typeof value === "boolean") s = String(value);
|
|
3828
|
+
else s = stableJson(value, false);
|
|
3829
|
+
if (maxLength !== void 0 && maxLength >= 0 && s.length > maxLength) {
|
|
3830
|
+
return `${s.slice(0, maxLength)}\u2026`;
|
|
3831
|
+
}
|
|
3832
|
+
return s;
|
|
3833
|
+
}
|
|
3834
|
+
function escapeMarkdown(value) {
|
|
3835
|
+
return value.replace(/\|/g, "\\|").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n/g, " ");
|
|
3836
|
+
}
|
|
3837
|
+
function sortKeysDeep(input) {
|
|
3838
|
+
if (input === null || typeof input !== "object") return input;
|
|
3839
|
+
if (Array.isArray(input)) return input.map(sortKeysDeep);
|
|
3840
|
+
const o = input;
|
|
3841
|
+
const out = {};
|
|
3842
|
+
for (const k of Object.keys(o).sort()) {
|
|
3843
|
+
out[k] = sortKeysDeep(o[k]);
|
|
3844
|
+
}
|
|
3845
|
+
return out;
|
|
3846
|
+
}
|
|
3847
|
+
function stableJson(value, pretty) {
|
|
3848
|
+
const sorted = sortKeysDeep(value);
|
|
3849
|
+
return pretty === true ? JSON.stringify(sorted, null, 2) : JSON.stringify(sorted);
|
|
3850
|
+
}
|
|
3851
|
+
function compactAttributes3(attrs, options) {
|
|
3852
|
+
if (attrs === void 0) return {};
|
|
3853
|
+
const maxLen = options?.maxLength ?? 500;
|
|
3854
|
+
const out = {};
|
|
3855
|
+
for (const key of Object.keys(attrs).sort()) {
|
|
3856
|
+
if (shouldRedactKey(key)) {
|
|
3857
|
+
out[key] = "[REDACTED]";
|
|
3858
|
+
continue;
|
|
3859
|
+
}
|
|
3860
|
+
const v = attrs[key];
|
|
3861
|
+
out[key] = compactValue(v, maxLen);
|
|
3862
|
+
}
|
|
3863
|
+
return out;
|
|
3864
|
+
}
|
|
3865
|
+
function compactValue(value, maxLen, redacted) {
|
|
3866
|
+
if (value === null || typeof value !== "object") {
|
|
3867
|
+
return typeof value === "string" ? safeString(value, maxLen) : value;
|
|
3868
|
+
}
|
|
3869
|
+
if (Array.isArray(value)) {
|
|
3870
|
+
const arr = value.slice(0, 20).map((x) => compactValue(x, maxLen));
|
|
3871
|
+
if (value.length > 20) arr.push(`\u2026(+${value.length - 20} more)`);
|
|
3872
|
+
return arr;
|
|
3873
|
+
}
|
|
3874
|
+
const o = value;
|
|
3875
|
+
const inner = {};
|
|
3876
|
+
for (const k of Object.keys(o)) {
|
|
3877
|
+
if (shouldRedactKey(k)) inner[k] = "[REDACTED]";
|
|
3878
|
+
else inner[k] = compactValue(o[k], maxLen);
|
|
3879
|
+
}
|
|
3880
|
+
return inner;
|
|
3881
|
+
}
|
|
3882
|
+
function flattenTree(tree) {
|
|
3883
|
+
const out = [];
|
|
3884
|
+
function walk(nodes) {
|
|
3885
|
+
for (const n of nodes) {
|
|
3886
|
+
out.push(n);
|
|
3887
|
+
if (n.children.length > 0) walk(n.children);
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
walk(tree.children);
|
|
3891
|
+
return out;
|
|
3892
|
+
}
|
|
3893
|
+
|
|
3894
|
+
// packages/core/src/diff/engine.ts
|
|
3895
|
+
var DEFAULT_THRESHOLD_MS = 0;
|
|
3896
|
+
function pathSeg(step, index) {
|
|
3897
|
+
return { index, name: step.name, stepId: step.id };
|
|
3898
|
+
}
|
|
3899
|
+
function buildPath(segments) {
|
|
3900
|
+
return { path: [...segments] };
|
|
3901
|
+
}
|
|
3902
|
+
function pairSteps(left, right) {
|
|
3903
|
+
const usedRight = /* @__PURE__ */ new Set();
|
|
3904
|
+
const pairs = [];
|
|
3905
|
+
for (let i = 0; i < left.length; i++) {
|
|
3906
|
+
const L = left[i];
|
|
3907
|
+
let R = right.find((r) => !usedRight.has(r.id) && r.id === L.id);
|
|
3908
|
+
if (R === void 0 && i < right.length && !usedRight.has(right[i].id)) {
|
|
3909
|
+
const cand = right[i];
|
|
3910
|
+
if (cand.name === L.name && (cand.type ?? "") === (L.type ?? "")) {
|
|
3911
|
+
R = cand;
|
|
3912
|
+
}
|
|
3913
|
+
}
|
|
3914
|
+
if (R === void 0) {
|
|
3915
|
+
R = right.find(
|
|
3916
|
+
(r) => !usedRight.has(r.id) && r.name === L.name && (r.type ?? "") === (L.type ?? "")
|
|
3917
|
+
);
|
|
3918
|
+
}
|
|
3919
|
+
if (R !== void 0) {
|
|
3920
|
+
usedRight.add(R.id);
|
|
3921
|
+
pairs.push([L, R]);
|
|
3922
|
+
} else {
|
|
3923
|
+
pairs.push([L, void 0]);
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3926
|
+
for (const R of right) {
|
|
3927
|
+
if (!usedRight.has(R.id)) {
|
|
3928
|
+
pairs.push([void 0, R]);
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
return pairs;
|
|
3932
|
+
}
|
|
3933
|
+
function compareLeafSteps(L, R, segments, opts, out) {
|
|
3934
|
+
const path12 = buildPath(segments);
|
|
3935
|
+
if (L.name !== R.name) {
|
|
3936
|
+
out.push({
|
|
3937
|
+
kind: "structure",
|
|
3938
|
+
severity: "warning",
|
|
3939
|
+
message: "Step name differs",
|
|
3940
|
+
path: path12,
|
|
3941
|
+
left: L.name,
|
|
3942
|
+
right: R.name
|
|
3943
|
+
});
|
|
3944
|
+
}
|
|
3945
|
+
if ((L.type ?? "") !== (R.type ?? "")) {
|
|
3946
|
+
out.push({
|
|
3947
|
+
kind: "step-type",
|
|
3948
|
+
severity: "warning",
|
|
3949
|
+
message: "Step type differs",
|
|
3950
|
+
path: path12,
|
|
3951
|
+
left: L.type,
|
|
3952
|
+
right: R.type
|
|
3953
|
+
});
|
|
3954
|
+
}
|
|
3955
|
+
if ((L.status ?? "") !== (R.status ?? "")) {
|
|
3956
|
+
out.push({
|
|
3957
|
+
kind: "step-status",
|
|
3958
|
+
severity: "warning",
|
|
3959
|
+
message: "Step status differs",
|
|
3960
|
+
path: path12,
|
|
3961
|
+
left: L.status,
|
|
3962
|
+
right: R.status
|
|
3963
|
+
});
|
|
3964
|
+
}
|
|
3965
|
+
const le = L.error ?? "";
|
|
3966
|
+
const re = R.error ?? "";
|
|
3967
|
+
if (le !== re) {
|
|
3968
|
+
out.push({
|
|
3969
|
+
kind: "error",
|
|
3970
|
+
severity: "error",
|
|
3971
|
+
message: "Step error message differs",
|
|
3972
|
+
path: path12,
|
|
3973
|
+
left: le || void 0,
|
|
3974
|
+
right: re || void 0
|
|
3975
|
+
});
|
|
3976
|
+
}
|
|
3977
|
+
if (!opts.ignoreDuration) {
|
|
3978
|
+
const ld = L.durationMs;
|
|
3979
|
+
const rd = R.durationMs;
|
|
3980
|
+
const th = opts.durationThresholdMs;
|
|
3981
|
+
let differs = false;
|
|
3982
|
+
if (ld === void 0 && rd === void 0) differs = false;
|
|
3983
|
+
else if (ld === void 0 || rd === void 0) differs = true;
|
|
3984
|
+
else differs = Math.abs(ld - rd) > th;
|
|
3985
|
+
if (differs) {
|
|
3986
|
+
out.push({
|
|
3987
|
+
kind: "duration",
|
|
3988
|
+
severity: "info",
|
|
3989
|
+
message: "Step duration differs",
|
|
3990
|
+
path: path12,
|
|
3991
|
+
left: ld,
|
|
3992
|
+
right: rd
|
|
3993
|
+
});
|
|
3994
|
+
}
|
|
3995
|
+
}
|
|
3996
|
+
const lm = stableJson(L.metadata ?? {});
|
|
3997
|
+
const rm = stableJson(R.metadata ?? {});
|
|
3998
|
+
if (lm !== rm) {
|
|
3999
|
+
out.push({
|
|
4000
|
+
kind: "metadata",
|
|
4001
|
+
severity: "info",
|
|
4002
|
+
message: "Step metadata differs",
|
|
4003
|
+
path: path12,
|
|
4004
|
+
left: L.metadata,
|
|
4005
|
+
right: R.metadata
|
|
4006
|
+
});
|
|
4007
|
+
}
|
|
4008
|
+
const lo = stableJson(L.outputPreview ?? null);
|
|
4009
|
+
const ro = stableJson(R.outputPreview ?? null);
|
|
4010
|
+
if (lo !== ro) {
|
|
4011
|
+
out.push({
|
|
4012
|
+
kind: "output",
|
|
4013
|
+
severity: "info",
|
|
4014
|
+
message: "Output preview differs",
|
|
4015
|
+
path: path12,
|
|
4016
|
+
left: L.outputPreview,
|
|
4017
|
+
right: R.outputPreview
|
|
4018
|
+
});
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
function compareRecursive(L, R, segments, opts, out) {
|
|
4022
|
+
compareLeafSteps(L, R, segments, opts, out);
|
|
4023
|
+
const pairs = pairSteps(L.children, R.children);
|
|
4024
|
+
let ci = 0;
|
|
4025
|
+
for (const [lch, rch] of pairs) {
|
|
4026
|
+
if (lch !== void 0 && rch !== void 0) {
|
|
4027
|
+
compareRecursive(lch, rch, [...segments, pathSeg(lch, ci)], opts, out);
|
|
4028
|
+
} else if (lch !== void 0) {
|
|
4029
|
+
out.push({
|
|
4030
|
+
kind: "step-removed",
|
|
4031
|
+
severity: "warning",
|
|
4032
|
+
message: `Step only in left run: ${lch.name}`,
|
|
4033
|
+
path: buildPath([...segments, pathSeg(lch, ci)]),
|
|
4034
|
+
left: lch.id,
|
|
4035
|
+
right: void 0
|
|
4036
|
+
});
|
|
4037
|
+
} else if (rch !== void 0) {
|
|
4038
|
+
out.push({
|
|
4039
|
+
kind: "step-added",
|
|
4040
|
+
severity: "warning",
|
|
4041
|
+
message: `Step only in right run: ${rch.name}`,
|
|
4042
|
+
path: buildPath([...segments, pathSeg(rch, ci)]),
|
|
4043
|
+
left: void 0,
|
|
4044
|
+
right: rch.id
|
|
4045
|
+
});
|
|
4046
|
+
}
|
|
4047
|
+
ci += 1;
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
function mergeDiffDefaults(options) {
|
|
4051
|
+
return {
|
|
4052
|
+
ignoreDuration: false,
|
|
4053
|
+
durationThresholdMs: DEFAULT_THRESHOLD_MS,
|
|
4054
|
+
focus: "all",
|
|
4055
|
+
check: "all"
|
|
4056
|
+
};
|
|
4057
|
+
}
|
|
4058
|
+
function kindMatchesFilter(kind, merged) {
|
|
4059
|
+
return true;
|
|
4060
|
+
}
|
|
4061
|
+
function diffRuns(left, right, options) {
|
|
4062
|
+
const merged = mergeDiffDefaults();
|
|
4063
|
+
const opts = {
|
|
4064
|
+
ignoreDuration: merged.ignoreDuration,
|
|
4065
|
+
durationThresholdMs: merged.durationThresholdMs
|
|
4066
|
+
};
|
|
4067
|
+
const raw = [];
|
|
4068
|
+
if ((left.status ?? "") !== (right.status ?? "")) {
|
|
4069
|
+
raw.push({
|
|
4070
|
+
kind: "run-status",
|
|
4071
|
+
severity: "warning",
|
|
4072
|
+
message: "Run completion status differs",
|
|
4073
|
+
left: left.status,
|
|
4074
|
+
right: right.status
|
|
4075
|
+
});
|
|
4076
|
+
}
|
|
4077
|
+
{
|
|
4078
|
+
const ld = left.durationMs;
|
|
4079
|
+
const rd = right.durationMs;
|
|
4080
|
+
const th = merged.durationThresholdMs;
|
|
4081
|
+
let differs = false;
|
|
4082
|
+
if (ld === void 0 && rd === void 0) differs = false;
|
|
4083
|
+
else if (ld === void 0 || rd === void 0) differs = true;
|
|
4084
|
+
else differs = Math.abs(ld - rd) > th;
|
|
4085
|
+
if (differs) {
|
|
4086
|
+
raw.push({
|
|
4087
|
+
kind: "duration",
|
|
4088
|
+
severity: "info",
|
|
4089
|
+
message: "Run duration differs",
|
|
4090
|
+
left: ld,
|
|
4091
|
+
right: rd
|
|
4092
|
+
});
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
const pairs = pairSteps(left.steps, right.steps);
|
|
4096
|
+
let idx = 0;
|
|
4097
|
+
for (const [ls, rs] of pairs) {
|
|
4098
|
+
if (ls !== void 0 && rs !== void 0) {
|
|
4099
|
+
compareRecursive(ls, rs, [pathSeg(ls, idx)], opts, raw);
|
|
4100
|
+
idx += 1;
|
|
4101
|
+
} else if (ls !== void 0) {
|
|
4102
|
+
raw.push({
|
|
4103
|
+
kind: "step-removed",
|
|
4104
|
+
severity: "warning",
|
|
4105
|
+
message: `Step only in left run: ${ls.name}`,
|
|
4106
|
+
path: buildPath([pathSeg(ls, idx)]),
|
|
4107
|
+
left: ls.id,
|
|
4108
|
+
right: void 0
|
|
4109
|
+
});
|
|
4110
|
+
idx += 1;
|
|
4111
|
+
} else if (rs !== void 0) {
|
|
4112
|
+
raw.push({
|
|
4113
|
+
kind: "step-added",
|
|
4114
|
+
severity: "warning",
|
|
4115
|
+
message: `Step only in right run: ${rs.name}`,
|
|
4116
|
+
path: buildPath([pathSeg(rs, idx)]),
|
|
4117
|
+
left: void 0,
|
|
4118
|
+
right: rs.id
|
|
4119
|
+
});
|
|
4120
|
+
idx += 1;
|
|
4046
4121
|
}
|
|
4047
|
-
] : [];
|
|
4048
|
-
const allWarnings = dedupeWarnings([
|
|
4049
|
-
...warnings,
|
|
4050
|
-
...candidateWarnings,
|
|
4051
|
-
...lowConfidenceWarnings
|
|
4052
|
-
]);
|
|
4053
|
-
if (sorted.length === 0) {
|
|
4054
|
-
return {
|
|
4055
|
-
status: "unsupported",
|
|
4056
|
-
candidates: [],
|
|
4057
|
-
warnings: allWarnings
|
|
4058
|
-
};
|
|
4059
4122
|
}
|
|
4060
|
-
const
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
code: "ambiguous_format_candidates",
|
|
4069
|
-
message: `Top trace format candidates are within ${AMBIGUOUS_CONFIDENCE_DELTA} confidence.`,
|
|
4070
|
-
severity: "warning"
|
|
4071
|
-
}
|
|
4072
|
-
]
|
|
4073
|
-
};
|
|
4123
|
+
const differences = raw.filter((d) => kindMatchesFilter(d.kind));
|
|
4124
|
+
let errors = 0;
|
|
4125
|
+
let warnings = 0;
|
|
4126
|
+
let info = 0;
|
|
4127
|
+
for (const d of differences) {
|
|
4128
|
+
if (d.severity === "error") errors += 1;
|
|
4129
|
+
else if (d.severity === "warning") warnings += 1;
|
|
4130
|
+
else info += 1;
|
|
4074
4131
|
}
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4132
|
+
const firstVisible = differences[0];
|
|
4133
|
+
const firstDivergence = firstVisible !== void 0 ? {
|
|
4134
|
+
kind: "first-divergence",
|
|
4135
|
+
severity: firstVisible.severity,
|
|
4136
|
+
message: `First divergence: ${firstVisible.message}`,
|
|
4137
|
+
path: firstVisible.path,
|
|
4138
|
+
left: firstVisible.left,
|
|
4139
|
+
right: firstVisible.right
|
|
4140
|
+
} : void 0;
|
|
4141
|
+
const summary = {
|
|
4142
|
+
leftRunId: left.runId,
|
|
4143
|
+
rightRunId: right.runId,
|
|
4144
|
+
totalDifferences: differences.length,
|
|
4145
|
+
errors,
|
|
4146
|
+
warnings,
|
|
4147
|
+
info,
|
|
4148
|
+
firstDivergence
|
|
4080
4149
|
};
|
|
4150
|
+
return { summary, differences };
|
|
4081
4151
|
}
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4152
|
+
|
|
4153
|
+
// packages/core/src/exporters/markdown-exporter.ts
|
|
4154
|
+
function renderTreeAscii(nodes, indent = "") {
|
|
4155
|
+
const lines = [];
|
|
4156
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
4157
|
+
const n = nodes[i];
|
|
4158
|
+
const last = i === nodes.length - 1;
|
|
4159
|
+
const branch = last ? "\u2514\u2500 " : "\u251C\u2500 ";
|
|
4160
|
+
const ev = n.event;
|
|
4161
|
+
const status = ev.status ?? "?";
|
|
4162
|
+
const dur = ev.durationMs !== void 0 && Number.isFinite(ev.durationMs) ? `${ev.durationMs}ms` : "-";
|
|
4163
|
+
lines.push(`${indent}${branch}${escapeMarkdown(ev.name)} [${ev.kind}] ${status} (${dur})`);
|
|
4164
|
+
const nextIndent = indent + (last ? " " : "\u2502 ");
|
|
4165
|
+
if (n.children.length > 0) {
|
|
4166
|
+
const childStr = renderTreeAscii(n.children, nextIndent);
|
|
4167
|
+
if (childStr.length > 0) lines.push(childStr);
|
|
4168
|
+
}
|
|
4091
4169
|
}
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4170
|
+
return lines.join("\n");
|
|
4171
|
+
}
|
|
4172
|
+
function exportMarkdown(tree, options) {
|
|
4173
|
+
const warnings = [];
|
|
4174
|
+
const includeMetadata = options?.includeMetadata ?? true;
|
|
4175
|
+
const includeAttributes = options?.includeAttributes ?? false;
|
|
4176
|
+
const includeErrors = options?.includeErrors ?? true;
|
|
4177
|
+
const maxLen = options?.maxAttributeLength ?? 500;
|
|
4178
|
+
const titleName = tree.name ?? tree.runId;
|
|
4179
|
+
const lines = [];
|
|
4180
|
+
lines.push(`# AgentInspect Run: ${escapeMarkdown(titleName)}`);
|
|
4181
|
+
lines.push("");
|
|
4182
|
+
lines.push("Generated locally by AgentInspect. Review for sensitive data before sharing.");
|
|
4183
|
+
lines.push("");
|
|
4184
|
+
if (includeMetadata) {
|
|
4185
|
+
lines.push("## Summary");
|
|
4186
|
+
lines.push("");
|
|
4187
|
+
lines.push(`- **runId**: ${escapeMarkdown(tree.runId)}`);
|
|
4188
|
+
if (tree.name !== void 0) lines.push(`- **name**: ${escapeMarkdown(tree.name)}`);
|
|
4189
|
+
lines.push(`- **status**: ${escapeMarkdown(String(tree.status ?? "unknown"))}`);
|
|
4190
|
+
lines.push(
|
|
4191
|
+
`- **durationMs**: ${tree.durationMs !== void 0 ? escapeMarkdown(String(tree.durationMs)) : "-"}`
|
|
4097
4192
|
);
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
"
|
|
4103
|
-
`No trace reader is registered for format "${detection.format}".`,
|
|
4104
|
-
detection.warnings
|
|
4193
|
+
lines.push(
|
|
4194
|
+
`- **startedAt**: ${tree.startedAt !== void 0 ? escapeMarkdown(String(tree.startedAt)) : "-"}`
|
|
4195
|
+
);
|
|
4196
|
+
lines.push(
|
|
4197
|
+
`- **endedAt**: ${tree.endedAt !== void 0 ? escapeMarkdown(String(tree.endedAt)) : "-"}`
|
|
4105
4198
|
);
|
|
4199
|
+
lines.push(`- **totalEvents**: ${tree.metadata.totalEvents}`);
|
|
4200
|
+
lines.push("");
|
|
4201
|
+
lines.push("### Confidence breakdown");
|
|
4202
|
+
lines.push("");
|
|
4203
|
+
lines.push("| bucket | count |");
|
|
4204
|
+
lines.push("| --- | --- |");
|
|
4205
|
+
for (const k of Object.keys(tree.metadata.confidenceBreakdown).sort()) {
|
|
4206
|
+
const key = k;
|
|
4207
|
+
lines.push(
|
|
4208
|
+
`| ${escapeMarkdown(key)} | ${tree.metadata.confidenceBreakdown[key]} |`
|
|
4209
|
+
);
|
|
4210
|
+
}
|
|
4211
|
+
lines.push("");
|
|
4212
|
+
lines.push("### Kind breakdown");
|
|
4213
|
+
lines.push("");
|
|
4214
|
+
lines.push("| kind | count |");
|
|
4215
|
+
lines.push("| --- | --- |");
|
|
4216
|
+
for (const k of Object.keys(tree.metadata.kinds).sort()) {
|
|
4217
|
+
const key = k;
|
|
4218
|
+
const c = tree.metadata.kinds[key];
|
|
4219
|
+
if (c > 0) lines.push(`| ${escapeMarkdown(key)} | ${c} |`);
|
|
4220
|
+
}
|
|
4221
|
+
lines.push("");
|
|
4106
4222
|
}
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4223
|
+
lines.push("## Execution tree");
|
|
4224
|
+
lines.push("");
|
|
4225
|
+
lines.push("```text");
|
|
4226
|
+
lines.push(
|
|
4227
|
+
tree.children.length > 0 ? renderTreeAscii(tree.children) : "(no steps)"
|
|
4228
|
+
);
|
|
4229
|
+
lines.push("```");
|
|
4230
|
+
lines.push("");
|
|
4231
|
+
const flat = flattenTree(tree);
|
|
4232
|
+
const errors = flat.filter((n) => n.event.status === "error");
|
|
4233
|
+
if (includeErrors && errors.length > 0) {
|
|
4234
|
+
lines.push("## Errors");
|
|
4235
|
+
lines.push("");
|
|
4236
|
+
for (const n of errors) {
|
|
4237
|
+
const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString(
|
|
4238
|
+
n.event.attributes.error.message,
|
|
4239
|
+
maxLen
|
|
4240
|
+
) : "";
|
|
4241
|
+
lines.push(
|
|
4242
|
+
`- **${escapeMarkdown(n.event.name)}** (${escapeMarkdown(n.event.eventId)}): ${escapeMarkdown(msg || "error")}`
|
|
4120
4243
|
);
|
|
4121
4244
|
}
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4245
|
+
lines.push("");
|
|
4246
|
+
}
|
|
4247
|
+
if (includeAttributes) {
|
|
4248
|
+
lines.push("## Attributes (bounded)");
|
|
4249
|
+
lines.push("");
|
|
4250
|
+
for (const n of flat) {
|
|
4251
|
+
if (!n.event.attributes || Object.keys(n.event.attributes).length === 0) continue;
|
|
4252
|
+
const compact = compactAttributes3(n.event.attributes, {
|
|
4253
|
+
maxLength: maxLen});
|
|
4254
|
+
lines.push(`### ${escapeMarkdown(n.event.name)}`);
|
|
4255
|
+
lines.push("");
|
|
4256
|
+
lines.push("```json");
|
|
4257
|
+
lines.push(stableJson(compact, true));
|
|
4258
|
+
lines.push("```");
|
|
4259
|
+
lines.push("");
|
|
4260
|
+
}
|
|
4261
|
+
warnings.push(
|
|
4262
|
+
"Attributes may still contain sensitive data; review exports before sharing."
|
|
4126
4263
|
);
|
|
4127
4264
|
}
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4265
|
+
return {
|
|
4266
|
+
format: "markdown",
|
|
4267
|
+
content: lines.join("\n"),
|
|
4268
|
+
contentType: "text/markdown",
|
|
4269
|
+
fileExtension: ".md",
|
|
4270
|
+
warnings
|
|
4271
|
+
};
|
|
4131
4272
|
}
|
|
4132
4273
|
|
|
4133
4274
|
// packages/mcp-server/src/tools.ts
|