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