agent-inspect 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/CHANGELOG.md +12 -0
- package/docs/API.md +3 -0
- package/docs/CLI.md +37 -0
- package/docs/SCHEMA.md +27 -1
- package/package.json +1 -1
- package/packages/cli/dist/chunk-TB45H3QT.mjs +7881 -0
- package/packages/cli/dist/chunk-TB45H3QT.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +10461 -9188
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +2619 -5688
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-YFMPWEIS.mjs → src-ZRFSYML6.mjs} +3 -3
- package/packages/cli/dist/{src-YFMPWEIS.mjs.map → src-ZRFSYML6.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +3410 -21
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +147 -9
- package/packages/core/dist/advanced.d.ts +147 -9
- package/packages/core/dist/advanced.mjs +603 -20
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/checks.cjs +117 -18
- package/packages/core/dist/checks.cjs.map +1 -1
- package/packages/core/dist/checks.d.cts +11 -3
- package/packages/core/dist/checks.d.ts +11 -3
- package/packages/core/dist/checks.mjs +7 -1612
- package/packages/core/dist/checks.mjs.map +1 -1
- package/packages/core/dist/{chunk-2ZXEMWGK.mjs → chunk-3USJVBLA.mjs} +3 -3
- package/packages/core/dist/{chunk-2ZXEMWGK.mjs.map → chunk-3USJVBLA.mjs.map} +1 -1
- package/packages/core/dist/{chunk-HY7H3CQM.mjs → chunk-CAWPF22J.mjs} +4 -3
- package/packages/core/dist/chunk-CAWPF22J.mjs.map +1 -0
- package/packages/core/dist/{chunk-XUNJMAPD.mjs → chunk-KNYL56KZ.mjs} +38 -3
- package/packages/core/dist/chunk-KNYL56KZ.mjs.map +1 -0
- package/packages/core/dist/{chunk-IZBJAZGF.mjs → chunk-P366CCL2.mjs} +34 -3
- package/packages/core/dist/chunk-P366CCL2.mjs.map +1 -0
- package/packages/core/dist/chunk-QLYOCCEF.mjs +1650 -0
- package/packages/core/dist/chunk-QLYOCCEF.mjs.map +1 -0
- package/packages/core/dist/{chunk-4JVGFNQH.mjs → chunk-ULCGIRTC.mjs} +95 -8
- package/packages/core/dist/chunk-ULCGIRTC.mjs.map +1 -0
- package/packages/core/dist/chunk-VFO76UH3.mjs +228 -0
- package/packages/core/dist/chunk-VFO76UH3.mjs.map +1 -0
- package/packages/core/dist/{chunk-NQZPZ2FN.mjs → chunk-WRE4CNPF.mjs} +6 -3
- package/packages/core/dist/chunk-WRE4CNPF.mjs.map +1 -0
- package/packages/core/dist/chunk-X2FLDF7M.mjs +1581 -0
- package/packages/core/dist/chunk-X2FLDF7M.mjs.map +1 -0
- package/packages/core/dist/{chunk-A4V2H3YU.mjs → chunk-ZWA5RWMV.mjs} +40 -4
- package/packages/core/dist/chunk-ZWA5RWMV.mjs.map +1 -0
- package/packages/core/dist/{context-DjY-jvQk.d.cts → context-BbfkMYjz.d.cts} +5 -3
- package/packages/core/dist/{context-BDZmi53V.d.ts → context-Cp8NRbBX.d.ts} +5 -3
- package/packages/core/dist/diff.cjs.map +1 -1
- package/packages/core/dist/diff.d.cts +3 -3
- package/packages/core/dist/diff.d.ts +3 -3
- package/packages/core/dist/diff.mjs +1 -1
- package/packages/core/dist/exporters.cjs +137 -1
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.d.cts +6 -3
- package/packages/core/dist/exporters.d.ts +6 -3
- package/packages/core/dist/exporters.mjs +71 -6
- package/packages/core/dist/exporters.mjs.map +1 -1
- package/packages/core/dist/index.cjs +181 -6
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.d.cts +14 -7
- package/packages/core/dist/index.d.ts +14 -7
- package/packages/core/dist/index.mjs +51 -7
- package/packages/core/dist/index.mjs.map +1 -1
- package/packages/core/dist/{inspect-event-CYAV7Hxm.d.cts → inspect-event-IqwOHbGo.d.cts} +1 -1
- package/packages/core/dist/{inspect-event-CYAV7Hxm.d.ts → inspect-event-IqwOHbGo.d.ts} +1 -1
- package/packages/core/dist/{log-config-BNQ9UTmP.d.cts → log-config-CW8w5YQ9.d.cts} +1 -1
- package/packages/core/dist/{log-config-D3Yp1SZN.d.ts → log-config-SRA4xTp8.d.ts} +1 -1
- package/packages/core/dist/logs.d.cts +3 -3
- package/packages/core/dist/logs.d.ts +3 -3
- package/packages/core/dist/{persisted-inspect-event-BLvb0jSX.d.ts → persisted-inspect-event-DruwqARZ.d.ts} +1 -1
- package/packages/core/dist/{persisted-inspect-event-D5SjBz9b.d.cts → persisted-inspect-event-Gd-W8vB7.d.cts} +1 -1
- package/packages/core/dist/persisted.cjs +67 -1
- package/packages/core/dist/persisted.cjs.map +1 -1
- package/packages/core/dist/persisted.d.cts +5 -5
- package/packages/core/dist/persisted.d.ts +5 -5
- package/packages/core/dist/persisted.mjs +3 -3
- package/packages/core/dist/readers.cjs +72 -3
- package/packages/core/dist/readers.cjs.map +1 -1
- package/packages/core/dist/readers.d.cts +2 -2
- package/packages/core/dist/readers.d.ts +2 -2
- package/packages/core/dist/readers.mjs +4 -1580
- package/packages/core/dist/readers.mjs.map +1 -1
- package/packages/core/dist/{types-CQun9LW6.d.ts → types-B1X87dUW.d.cts} +16 -2
- package/packages/core/dist/{types-C-llnPH0.d.cts → types-BVkjSd0q.d.ts} +16 -2
- package/packages/core/dist/types-CvsKGweN.d.cts +12 -0
- package/packages/core/dist/types-CvsKGweN.d.ts +12 -0
- package/packages/core/dist/writers.cjs +2 -1
- package/packages/core/dist/writers.cjs.map +1 -1
- package/packages/core/dist/writers.d.cts +2 -2
- package/packages/core/dist/writers.d.ts +2 -2
- package/packages/core/dist/writers.mjs +3 -4
- package/packages/core/dist/writers.mjs.map +1 -1
- package/packages/cli/dist/chunk-BS5LSKZ3.mjs +0 -3671
- package/packages/cli/dist/chunk-BS5LSKZ3.mjs.map +0 -1
- package/packages/core/dist/chunk-4JVGFNQH.mjs.map +0 -1
- package/packages/core/dist/chunk-A4V2H3YU.mjs.map +0 -1
- package/packages/core/dist/chunk-EDTQHZPM.mjs +0 -88
- package/packages/core/dist/chunk-EDTQHZPM.mjs.map +0 -1
- package/packages/core/dist/chunk-HY7H3CQM.mjs.map +0 -1
- package/packages/core/dist/chunk-IZBJAZGF.mjs.map +0 -1
- package/packages/core/dist/chunk-NQZPZ2FN.mjs.map +0 -1
- package/packages/core/dist/chunk-XUNJMAPD.mjs.map +0 -1
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { runTraceChecks, createRunStatusRule, createToolUsageRule, createRunDurationRule, createLlmUsageRule, createObservedOutcomeRule } from './chunk-QLYOCCEF.mjs';
|
|
2
|
+
export { MAX_TERMINAL_DEPTH, MAX_TERMINAL_NAME_LENGTH, TERMINAL_INDENT, TraceDirectory, createInspector, createInspectorRuntime, formatTerminalName, getCurrentContext, getCurrentCorrelationMetadata, getCurrentDepth, getCurrentRunId, getCurrentRunName, getCurrentStepId, getIndent, getParentStepId, getTraceDirFromContext, getTraceSafetyFromContext, hasActiveContext, isAgentInspectEnabled, isSilentContext, maybeInspectRun, printError, printFailedAt, printRunComplete, printRunStart, printStepComplete, printStepStart, renderErrorLine, renderRunSummary, renderStepLine, resolveTraceDir, runWithContext, runWithStepContext } from './chunk-ZWA5RWMV.mjs';
|
|
3
|
+
import { buildRunSummary, extractMetadata } from './chunk-3USJVBLA.mjs';
|
|
4
|
+
export { buildRunSummary, buildRunTimeline, buildRunWhatSummary, extractMetadata, renderRunWhat, renderTimeline } from './chunk-3USJVBLA.mjs';
|
|
5
|
+
import { parseObservationFilter, extractOutcomesFromTraceEvents, extractOutcomesFromPersistedEvents } from './chunk-VFO76UH3.mjs';
|
|
4
6
|
import './chunk-BT7CATSD.mjs';
|
|
5
|
-
import { readTraceEventsFromFile } from './chunk-
|
|
6
|
-
export { DEFAULT_MAX_EVENT_BYTES, DEFAULT_MAX_METADATA_VALUE_LENGTH, DEFAULT_MAX_PREVIEW_LENGTH, getRunIdFromTraceFileName, initializeTraceFile, listTraceFiles, prepareMetadataForDisk, prepareTraceEventForDisk, readTraceEvents, readTraceFile, resolveTraceSafetyOptions, serializeEvent, validateEvent, writeTraceEvent } from './chunk-
|
|
7
|
-
import { resolveRedactionProfile } from './chunk-EDTQHZPM.mjs';
|
|
8
|
-
export { resolveRedactionProfile } from './chunk-EDTQHZPM.mjs';
|
|
7
|
+
import { resolveRedactionProfile, readTraceEventsFromFile } from './chunk-ULCGIRTC.mjs';
|
|
8
|
+
export { DEFAULT_MAX_EVENT_BYTES, DEFAULT_MAX_METADATA_VALUE_LENGTH, DEFAULT_MAX_PREVIEW_LENGTH, getRunIdFromTraceFileName, initializeTraceFile, listTraceFiles, prepareMetadataForDisk, prepareTraceEventForDisk, readTraceEvents, readTraceFile, resolveRedactionProfile, resolveTraceSafetyOptions, serializeEvent, validateEvent, writeTraceEvent } from './chunk-ULCGIRTC.mjs';
|
|
9
9
|
import { Redactor } from './chunk-VU6O5QAH.mjs';
|
|
10
|
+
import { openTrace } from './chunk-X2FLDF7M.mjs';
|
|
11
|
+
import './chunk-KNYL56KZ.mjs';
|
|
10
12
|
import './chunk-S4YWKV4G.mjs';
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
import './chunk-E5F2LQCX.mjs';
|
|
14
|
+
import { parseDuration, formatDuration, isTraceEvent, getTraceFilePath } from './chunk-WRE4CNPF.mjs';
|
|
15
|
+
export { DEFAULT_TRACE_DIR_NAME, FALLBACK_TRACE_DIR, MAX_NAME_LENGTH, RUNS_DIR_NAME, createRunId, createStepId, ensureTraceDir, formatDuration, formatError, formatTimestamp, getDefaultTraceDir, getTraceFilePath, isStepStatus, isStepType, isTraceEvent, parseDuration, parseTraceJsonl, truncateName, unknownTraceFormatMessage, warn } from './chunk-WRE4CNPF.mjs';
|
|
16
|
+
import './chunk-P366CCL2.mjs';
|
|
14
17
|
import './chunk-7TGZLWEE.mjs';
|
|
15
18
|
import { createReadStream } from 'fs';
|
|
16
19
|
import { createInterface } from 'readline';
|
|
17
|
-
import
|
|
20
|
+
import path3 from 'path';
|
|
21
|
+
import { access, readFile } from 'fs/promises';
|
|
22
|
+
import { pathToFileURL } from 'url';
|
|
18
23
|
|
|
19
24
|
// packages/core/src/trace-filter.ts
|
|
20
25
|
function toLower(s) {
|
|
@@ -434,8 +439,9 @@ async function searchTraces(metas, options) {
|
|
|
434
439
|
}
|
|
435
440
|
const limit = options.limit ?? 50;
|
|
436
441
|
const sessionId = options.session?.trim();
|
|
442
|
+
const observationStatus = parseObservationFilter(options.observation);
|
|
437
443
|
const hasContentFilter = Boolean(
|
|
438
|
-
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
|
|
444
|
+
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter || observationStatus
|
|
439
445
|
);
|
|
440
446
|
const results = [];
|
|
441
447
|
const sessionLabel = sessionId && sessionId !== "" ? sessionId : void 0;
|
|
@@ -480,6 +486,22 @@ async function searchTraces(metas, options) {
|
|
|
480
486
|
statusFilter: options.status
|
|
481
487
|
});
|
|
482
488
|
results.push(...stepMatches);
|
|
489
|
+
if (observationStatus) {
|
|
490
|
+
const outcomes = extractOutcomesFromTraceEvents(events);
|
|
491
|
+
const matched = outcomes.filter((outcome) => outcome.status === observationStatus);
|
|
492
|
+
for (const outcome of matched) {
|
|
493
|
+
results.push({
|
|
494
|
+
runId: m.runId,
|
|
495
|
+
runName: m.name,
|
|
496
|
+
runStatus: m.status,
|
|
497
|
+
stepName: outcome.name,
|
|
498
|
+
timestamp: outcome.observedAt,
|
|
499
|
+
matchReason: `observation status=${outcome.status}`,
|
|
500
|
+
matchedFields: ["outcome.status", "outcome.name"],
|
|
501
|
+
filePath: m.filePath
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
483
505
|
}
|
|
484
506
|
results.sort((a, b) => {
|
|
485
507
|
const ta = a.timestamp ?? 0;
|
|
@@ -868,9 +890,10 @@ function buildActivitySummary(index, options = {}) {
|
|
|
868
890
|
entries
|
|
869
891
|
};
|
|
870
892
|
}
|
|
871
|
-
function renderActivitySummaryHuman(summary) {
|
|
893
|
+
function renderActivitySummaryHuman(summary, options) {
|
|
872
894
|
const lines = [];
|
|
873
|
-
const
|
|
895
|
+
const nowMs = options?.nowMs ?? Date.now();
|
|
896
|
+
const todayStart = new Date(nowMs);
|
|
874
897
|
todayStart.setHours(0, 0, 0, 0);
|
|
875
898
|
const todayMs = todayStart.getTime();
|
|
876
899
|
const today = summary.entries.filter(
|
|
@@ -1301,12 +1324,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
1301
1324
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
1302
1325
|
);
|
|
1303
1326
|
const ordered = [...runs].sort(compareRuns);
|
|
1304
|
-
const
|
|
1327
|
+
const path6 = [];
|
|
1305
1328
|
const visited = /* @__PURE__ */ new Set();
|
|
1306
1329
|
const pushRun = (run, confidence, source) => {
|
|
1307
1330
|
if (visited.has(run.runId)) return;
|
|
1308
1331
|
visited.add(run.runId);
|
|
1309
|
-
|
|
1332
|
+
path6.push({
|
|
1310
1333
|
runId: run.runId,
|
|
1311
1334
|
name: run.name,
|
|
1312
1335
|
startedAt: run.startedAt,
|
|
@@ -1331,7 +1354,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
1331
1354
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
1332
1355
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
1333
1356
|
}
|
|
1334
|
-
return
|
|
1357
|
+
return path6;
|
|
1335
1358
|
}
|
|
1336
1359
|
function metaRunIdMatches(run, token, runById) {
|
|
1337
1360
|
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -1623,7 +1646,7 @@ function normalizeBundleOutputPath(out) {
|
|
|
1623
1646
|
if (trimmed === "") {
|
|
1624
1647
|
throw new Error("--out requires a non-empty path.");
|
|
1625
1648
|
}
|
|
1626
|
-
const resolved =
|
|
1649
|
+
const resolved = path3.resolve(trimmed);
|
|
1627
1650
|
if (resolved.toLowerCase().endsWith(".zip")) {
|
|
1628
1651
|
return resolved.slice(0, -4);
|
|
1629
1652
|
}
|
|
@@ -1632,9 +1655,569 @@ function normalizeBundleOutputPath(out) {
|
|
|
1632
1655
|
function defaultBundleOutputPath(runIds) {
|
|
1633
1656
|
const label = runIds.length === 1 ? runIds[0] : `multi-${runIds.length}`;
|
|
1634
1657
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1635
|
-
return
|
|
1658
|
+
return path3.resolve(`agent-inspect-bundle-${label}-${stamp}`);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
// packages/core/src/suite/types.ts
|
|
1662
|
+
var DEFAULT_SUITE_CONFIG_NAMES = [
|
|
1663
|
+
"agent-inspect.suite.json",
|
|
1664
|
+
"agent-inspect.suite.js",
|
|
1665
|
+
"agent-inspect.suite.mjs",
|
|
1666
|
+
"agent-inspect.suite.cjs"
|
|
1667
|
+
];
|
|
1668
|
+
var DEFAULT_SUITE_ARTIFACTS_DIR = ".agent-inspect/suite-runs";
|
|
1669
|
+
function diagnostic(code, message, severity = "error", caseId) {
|
|
1670
|
+
return { code, message, severity, ...caseId !== void 0 ? { caseId } : {} };
|
|
1671
|
+
}
|
|
1672
|
+
function asString(value, label) {
|
|
1673
|
+
if (value === void 0) return void 0;
|
|
1674
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
1675
|
+
throw new Error(`${label} must be a non-empty string.`);
|
|
1676
|
+
}
|
|
1677
|
+
return value.trim();
|
|
1678
|
+
}
|
|
1679
|
+
function asStringArray(value, label) {
|
|
1680
|
+
if (value === void 0) return void 0;
|
|
1681
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
1682
|
+
throw new Error(`${label} must be an array of strings.`);
|
|
1683
|
+
}
|
|
1684
|
+
return value;
|
|
1685
|
+
}
|
|
1686
|
+
function asPositiveNumber(value, label) {
|
|
1687
|
+
if (value === void 0) return void 0;
|
|
1688
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
1689
|
+
throw new Error(`${label} must be a non-negative number.`);
|
|
1690
|
+
}
|
|
1691
|
+
return value;
|
|
1692
|
+
}
|
|
1693
|
+
function validateCaseConfig(value, index) {
|
|
1694
|
+
const diagnostics = [];
|
|
1695
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1696
|
+
diagnostics.push(
|
|
1697
|
+
diagnostic("AI_SUITE_CONFIG_INVALID", `cases[${index}] must be an object.`)
|
|
1698
|
+
);
|
|
1699
|
+
return { diagnostics };
|
|
1700
|
+
}
|
|
1701
|
+
const raw = value;
|
|
1702
|
+
try {
|
|
1703
|
+
const id = asString(raw.id, `cases[${index}].id`);
|
|
1704
|
+
if (id === void 0) {
|
|
1705
|
+
diagnostics.push(
|
|
1706
|
+
diagnostic("AI_SUITE_CONFIG_INVALID", `cases[${index}].id is required.`)
|
|
1707
|
+
);
|
|
1708
|
+
return { diagnostics };
|
|
1709
|
+
}
|
|
1710
|
+
const trace = asString(raw.trace, `cases[${index}].trace`);
|
|
1711
|
+
const runId = asString(raw.runId, `cases[${index}].runId`);
|
|
1712
|
+
const input = asString(raw.input, `cases[${index}].input`);
|
|
1713
|
+
return {
|
|
1714
|
+
caseConfig: {
|
|
1715
|
+
id,
|
|
1716
|
+
...trace !== void 0 ? { trace } : {},
|
|
1717
|
+
...runId !== void 0 ? { runId } : {},
|
|
1718
|
+
...input !== void 0 ? { input } : {},
|
|
1719
|
+
...asStringArray(raw.requireTools, `cases[${index}].requireTools`) !== void 0 ? { requireTools: asStringArray(raw.requireTools, `cases[${index}].requireTools`) } : {},
|
|
1720
|
+
...asStringArray(raw.forbidTools, `cases[${index}].forbidTools`) !== void 0 ? { forbidTools: asStringArray(raw.forbidTools, `cases[${index}].forbidTools`) } : {},
|
|
1721
|
+
...asPositiveNumber(raw.maxDurationMs, `cases[${index}].maxDurationMs`) !== void 0 ? {
|
|
1722
|
+
maxDurationMs: asPositiveNumber(
|
|
1723
|
+
raw.maxDurationMs,
|
|
1724
|
+
`cases[${index}].maxDurationMs`
|
|
1725
|
+
)
|
|
1726
|
+
} : {},
|
|
1727
|
+
...asStringArray(
|
|
1728
|
+
raw.expectedObservations,
|
|
1729
|
+
`cases[${index}].expectedObservations`
|
|
1730
|
+
) !== void 0 ? {
|
|
1731
|
+
expectedObservations: asStringArray(
|
|
1732
|
+
raw.expectedObservations,
|
|
1733
|
+
`cases[${index}].expectedObservations`
|
|
1734
|
+
)
|
|
1735
|
+
} : {}
|
|
1736
|
+
},
|
|
1737
|
+
diagnostics
|
|
1738
|
+
};
|
|
1739
|
+
} catch (error) {
|
|
1740
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1741
|
+
diagnostics.push(diagnostic("AI_SUITE_CONFIG_INVALID", message));
|
|
1742
|
+
return { diagnostics };
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
function normalizeSuiteConfig(value) {
|
|
1746
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1747
|
+
throw new Error("Suite config must export an object.");
|
|
1748
|
+
}
|
|
1749
|
+
const raw = value;
|
|
1750
|
+
const name = asString(raw.name, "name");
|
|
1751
|
+
const traces = asString(raw.traces, "traces");
|
|
1752
|
+
if (name === void 0) throw new Error("name is required.");
|
|
1753
|
+
if (traces === void 0) throw new Error("traces is required.");
|
|
1754
|
+
if (!Array.isArray(raw.cases) || raw.cases.length === 0) {
|
|
1755
|
+
throw new Error("cases must be a non-empty array.");
|
|
1756
|
+
}
|
|
1757
|
+
const cases = [];
|
|
1758
|
+
for (let index = 0; index < raw.cases.length; index += 1) {
|
|
1759
|
+
const { caseConfig, diagnostics } = validateCaseConfig(raw.cases[index], index);
|
|
1760
|
+
if (diagnostics.length > 0) {
|
|
1761
|
+
throw new Error(diagnostics.map((item) => item.message).join("; "));
|
|
1762
|
+
}
|
|
1763
|
+
if (caseConfig !== void 0) cases.push(caseConfig);
|
|
1764
|
+
}
|
|
1765
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1766
|
+
for (const suiteCase of cases) {
|
|
1767
|
+
if (ids.has(suiteCase.id)) {
|
|
1768
|
+
throw new Error(`Duplicate case id "${suiteCase.id}".`);
|
|
1769
|
+
}
|
|
1770
|
+
ids.add(suiteCase.id);
|
|
1771
|
+
}
|
|
1772
|
+
const redactionProfile = raw.redactionProfile === "local" || raw.redactionProfile === "share" || raw.redactionProfile === "strict" ? raw.redactionProfile : void 0;
|
|
1773
|
+
if (raw.redactionProfile !== void 0 && redactionProfile === void 0) {
|
|
1774
|
+
throw new Error('redactionProfile must be "local", "share", or "strict".');
|
|
1775
|
+
}
|
|
1776
|
+
const config = { name, traces, cases };
|
|
1777
|
+
if (raw.checks !== void 0) {
|
|
1778
|
+
if (typeof raw.checks !== "object" || Array.isArray(raw.checks)) {
|
|
1779
|
+
throw new Error("checks must be an object.");
|
|
1780
|
+
}
|
|
1781
|
+
config.checks = raw.checks;
|
|
1782
|
+
}
|
|
1783
|
+
if (raw.eval !== void 0) {
|
|
1784
|
+
if (typeof raw.eval !== "object" || Array.isArray(raw.eval)) {
|
|
1785
|
+
throw new Error("eval must be an object.");
|
|
1786
|
+
}
|
|
1787
|
+
config.eval = raw.eval;
|
|
1788
|
+
}
|
|
1789
|
+
if (raw.artifacts !== void 0) {
|
|
1790
|
+
if (typeof raw.artifacts !== "object" || Array.isArray(raw.artifacts)) {
|
|
1791
|
+
throw new Error("artifacts must be an object.");
|
|
1792
|
+
}
|
|
1793
|
+
const outputDir = asString(
|
|
1794
|
+
raw.artifacts.outputDir,
|
|
1795
|
+
"artifacts.outputDir"
|
|
1796
|
+
);
|
|
1797
|
+
config.artifacts = outputDir !== void 0 ? { outputDir } : {};
|
|
1798
|
+
}
|
|
1799
|
+
if (raw.baseline !== void 0) {
|
|
1800
|
+
const baseline = asString(raw.baseline, "baseline");
|
|
1801
|
+
if (baseline !== void 0) config.baseline = baseline;
|
|
1802
|
+
}
|
|
1803
|
+
if (raw.candidate !== void 0) {
|
|
1804
|
+
const candidate = asString(raw.candidate, "candidate");
|
|
1805
|
+
if (candidate !== void 0) config.candidate = candidate;
|
|
1806
|
+
}
|
|
1807
|
+
if (redactionProfile !== void 0) config.redactionProfile = redactionProfile;
|
|
1808
|
+
return config;
|
|
1809
|
+
}
|
|
1810
|
+
async function validateSuiteConfig(config, options) {
|
|
1811
|
+
const diagnostics = [];
|
|
1812
|
+
const tracesDir = path3.resolve(options.configDir, config.traces);
|
|
1813
|
+
try {
|
|
1814
|
+
await access(tracesDir);
|
|
1815
|
+
} catch {
|
|
1816
|
+
diagnostics.push(
|
|
1817
|
+
diagnostic("AI_SUITE_CONFIG_INVALID", `traces directory not found: ${tracesDir}`)
|
|
1818
|
+
);
|
|
1819
|
+
}
|
|
1820
|
+
for (const suiteCase of config.cases) {
|
|
1821
|
+
if (suiteCase.input !== void 0) {
|
|
1822
|
+
const inputPath = path3.resolve(options.configDir, suiteCase.input);
|
|
1823
|
+
try {
|
|
1824
|
+
await access(inputPath);
|
|
1825
|
+
} catch {
|
|
1826
|
+
diagnostics.push(
|
|
1827
|
+
diagnostic(
|
|
1828
|
+
"AI_SUITE_CONFIG_INVALID",
|
|
1829
|
+
`input fixture not found: ${suiteCase.input}`,
|
|
1830
|
+
"warning",
|
|
1831
|
+
suiteCase.id
|
|
1832
|
+
)
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
return { ok: diagnostics.every((item) => item.severity !== "error"), diagnostics };
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
// packages/core/src/suite/load.ts
|
|
1841
|
+
var CONFIG_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
|
|
1842
|
+
var TS_CONFIG_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
|
|
1843
|
+
function diagnostic2(code, message) {
|
|
1844
|
+
return { code, message, severity: "error" };
|
|
1845
|
+
}
|
|
1846
|
+
async function fileExists(filePath) {
|
|
1847
|
+
try {
|
|
1848
|
+
await access(filePath);
|
|
1849
|
+
return true;
|
|
1850
|
+
} catch {
|
|
1851
|
+
return false;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
async function resolveSuiteConfigPath(options = {}) {
|
|
1855
|
+
const cwd = path3.resolve(options.cwd ?? process.cwd());
|
|
1856
|
+
if (options.configPath !== void 0 && options.configPath.trim() !== "") {
|
|
1857
|
+
return path3.resolve(cwd, options.configPath.trim());
|
|
1858
|
+
}
|
|
1859
|
+
for (const name of DEFAULT_SUITE_CONFIG_NAMES) {
|
|
1860
|
+
const candidate = path3.join(cwd, name);
|
|
1861
|
+
if (await fileExists(candidate)) return candidate;
|
|
1862
|
+
}
|
|
1863
|
+
throw new Error(
|
|
1864
|
+
`No suite config found. Create one with \`agent-inspect suite init\` or pass --config.`
|
|
1865
|
+
);
|
|
1866
|
+
}
|
|
1867
|
+
async function loadSuiteConfig(options = {}) {
|
|
1868
|
+
let configPath;
|
|
1869
|
+
try {
|
|
1870
|
+
configPath = await resolveSuiteConfigPath(options);
|
|
1871
|
+
} catch (error) {
|
|
1872
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1873
|
+
throw Object.assign(new Error(message), {
|
|
1874
|
+
diagnostics: [diagnostic2("AI_SUITE_CONFIG_LOAD_FAILED", message)]
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
const extension = path3.extname(configPath);
|
|
1878
|
+
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
1879
|
+
const message = "TypeScript suite configs require an explicit precompiled JavaScript config or future --config-loader support.";
|
|
1880
|
+
throw Object.assign(new Error(message), {
|
|
1881
|
+
diagnostics: [diagnostic2("AI_SUITE_CONFIG_LOAD_FAILED", message)]
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
if (!CONFIG_EXTENSIONS.has(extension)) {
|
|
1885
|
+
const message = "Unsupported suite config extension. Use .json, .js, .mjs, or .cjs.";
|
|
1886
|
+
throw Object.assign(new Error(message), {
|
|
1887
|
+
diagnostics: [diagnostic2("AI_SUITE_CONFIG_LOAD_FAILED", message)]
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
try {
|
|
1891
|
+
let raw;
|
|
1892
|
+
if (extension === ".json") {
|
|
1893
|
+
raw = JSON.parse(await readFile(configPath, "utf-8"));
|
|
1894
|
+
} else {
|
|
1895
|
+
const mod = await import(pathToFileURL(configPath).href);
|
|
1896
|
+
raw = "default" in mod ? mod.default : mod;
|
|
1897
|
+
}
|
|
1898
|
+
const config = normalizeSuiteConfig(raw);
|
|
1899
|
+
return {
|
|
1900
|
+
config,
|
|
1901
|
+
configPath,
|
|
1902
|
+
configDir: path3.dirname(configPath)
|
|
1903
|
+
};
|
|
1904
|
+
} catch (error) {
|
|
1905
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1906
|
+
throw Object.assign(new Error(message), {
|
|
1907
|
+
diagnostics: [diagnostic2("AI_SUITE_CONFIG_LOAD_FAILED", message)]
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
function defaultSuiteConfigTemplate() {
|
|
1912
|
+
return {
|
|
1913
|
+
name: "my-agent-suite",
|
|
1914
|
+
traces: "./.agent-inspect",
|
|
1915
|
+
cases: [
|
|
1916
|
+
{
|
|
1917
|
+
id: "example-case",
|
|
1918
|
+
runId: "example-run",
|
|
1919
|
+
requireTools: ["searchDocs"],
|
|
1920
|
+
maxDurationMs: 3e4,
|
|
1921
|
+
expectedObservations: ["answerReady"]
|
|
1922
|
+
}
|
|
1923
|
+
],
|
|
1924
|
+
checks: {
|
|
1925
|
+
select: ["run.status"]
|
|
1926
|
+
},
|
|
1927
|
+
redactionProfile: "local",
|
|
1928
|
+
artifacts: {
|
|
1929
|
+
outputDir: ".agent-inspect/suite-runs"
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
async function exists(filePath) {
|
|
1934
|
+
try {
|
|
1935
|
+
await access(filePath);
|
|
1936
|
+
return true;
|
|
1937
|
+
} catch {
|
|
1938
|
+
return false;
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
async function resolveSuiteCaseTrace(suiteCase, options) {
|
|
1942
|
+
if (suiteCase.trace !== void 0) {
|
|
1943
|
+
const tracePath = path3.resolve(options.configDir, suiteCase.trace);
|
|
1944
|
+
if (await exists(tracePath)) {
|
|
1945
|
+
return { caseId: suiteCase.id, tracePath, missing: false };
|
|
1946
|
+
}
|
|
1947
|
+
return {
|
|
1948
|
+
caseId: suiteCase.id,
|
|
1949
|
+
tracePath,
|
|
1950
|
+
missing: true,
|
|
1951
|
+
reason: `trace file not found: ${suiteCase.trace}`
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
const runKey = suiteCase.runId ?? suiteCase.id;
|
|
1955
|
+
const directPath = getTraceFilePath(runKey, options.tracesDir);
|
|
1956
|
+
if (await exists(directPath)) {
|
|
1957
|
+
return { caseId: suiteCase.id, tracePath: directPath, runId: runKey, missing: false };
|
|
1958
|
+
}
|
|
1959
|
+
const nestedPath = path3.join(options.tracesDir, `${path3.basename(runKey)}.jsonl`);
|
|
1960
|
+
if (await exists(nestedPath)) {
|
|
1961
|
+
return { caseId: suiteCase.id, tracePath: nestedPath, runId: runKey, missing: false };
|
|
1962
|
+
}
|
|
1963
|
+
return {
|
|
1964
|
+
caseId: suiteCase.id,
|
|
1965
|
+
runId: runKey,
|
|
1966
|
+
missing: true,
|
|
1967
|
+
reason: `no trace found for run id "${runKey}" under ${options.tracesDir}`
|
|
1968
|
+
};
|
|
1969
|
+
}
|
|
1970
|
+
function diagnostic3(code, message, severity = "error", caseId) {
|
|
1971
|
+
return { code, message, severity, ...caseId !== void 0 ? { caseId } : {} };
|
|
1972
|
+
}
|
|
1973
|
+
function buildCaseRules(suiteCase, config) {
|
|
1974
|
+
const rules = [];
|
|
1975
|
+
const select = new Set(config.checks?.select ?? []);
|
|
1976
|
+
if (select.has("run.status")) {
|
|
1977
|
+
rules.push(createRunStatusRule());
|
|
1978
|
+
}
|
|
1979
|
+
const requiredTools = [
|
|
1980
|
+
...config.checks?.tool?.required ?? [],
|
|
1981
|
+
...suiteCase.requireTools ?? []
|
|
1982
|
+
];
|
|
1983
|
+
const forbiddenTools = [
|
|
1984
|
+
...config.checks?.tool?.forbidden ?? [],
|
|
1985
|
+
...suiteCase.forbidTools ?? []
|
|
1986
|
+
];
|
|
1987
|
+
if (requiredTools.length > 0 || forbiddenTools.length > 0) {
|
|
1988
|
+
rules.push(
|
|
1989
|
+
createToolUsageRule({
|
|
1990
|
+
required: requiredTools.length > 0 ? requiredTools : void 0,
|
|
1991
|
+
forbidden: forbiddenTools.length > 0 ? forbiddenTools : void 0
|
|
1992
|
+
})
|
|
1993
|
+
);
|
|
1994
|
+
select.add("tool.usage");
|
|
1995
|
+
}
|
|
1996
|
+
const maxDurationMs = suiteCase.maxDurationMs ?? config.checks?.run?.maxDurationMs ?? config.eval?.maxDurationMs;
|
|
1997
|
+
if (maxDurationMs !== void 0) {
|
|
1998
|
+
rules.push(createRunDurationRule({ maxDurationMs }));
|
|
1999
|
+
select.add("run.duration");
|
|
2000
|
+
}
|
|
2001
|
+
const llm = config.checks?.llm;
|
|
2002
|
+
if (llm?.allowedModels !== void 0 || llm?.maxTotalTokens !== void 0) {
|
|
2003
|
+
rules.push(createLlmUsageRule(llm));
|
|
2004
|
+
select.add("llm.usage");
|
|
2005
|
+
}
|
|
2006
|
+
if (select.has("outcome.status")) {
|
|
2007
|
+
rules.push(createObservedOutcomeRule({ failOn: ["failed"] }));
|
|
2008
|
+
}
|
|
2009
|
+
return { rules, select: [...select] };
|
|
2010
|
+
}
|
|
2011
|
+
function outcomesFromRead(read) {
|
|
2012
|
+
const persistedOutcomes = extractOutcomesFromPersistedEvents(
|
|
2013
|
+
read.events.filter((event) => event.kind === "OUTCOME")
|
|
2014
|
+
);
|
|
2015
|
+
if (persistedOutcomes.length > 0) return persistedOutcomes;
|
|
2016
|
+
const traceEvents = [];
|
|
2017
|
+
for (const event of read.events) {
|
|
2018
|
+
const legacy = event;
|
|
2019
|
+
if (typeof legacy === "object" && legacy !== null && "event" in legacy && legacy.event === "outcome_observed") {
|
|
2020
|
+
traceEvents.push(legacy);
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
return traceEvents.length > 0 ? extractOutcomesFromTraceEvents(traceEvents) : [];
|
|
2024
|
+
}
|
|
2025
|
+
function validateExpectedObservations(suiteCase, read) {
|
|
2026
|
+
const expected = suiteCase.expectedObservations ?? [];
|
|
2027
|
+
if (expected.length === 0) return { ok: true, diagnostics: [] };
|
|
2028
|
+
const outcomes = outcomesFromRead(read);
|
|
2029
|
+
const diagnostics = [];
|
|
2030
|
+
for (const name of expected) {
|
|
2031
|
+
const match = outcomes.find((outcome) => outcome.name === name);
|
|
2032
|
+
if (!match) {
|
|
2033
|
+
diagnostics.push(
|
|
2034
|
+
diagnostic3(
|
|
2035
|
+
"AI_SUITE_CASE_OBSERVATION_FAILED",
|
|
2036
|
+
`Expected observation "${name}" was not recorded.`,
|
|
2037
|
+
"error",
|
|
2038
|
+
suiteCase.id
|
|
2039
|
+
)
|
|
2040
|
+
);
|
|
2041
|
+
continue;
|
|
2042
|
+
}
|
|
2043
|
+
if (match.status !== "passed") {
|
|
2044
|
+
diagnostics.push(
|
|
2045
|
+
diagnostic3(
|
|
2046
|
+
"AI_SUITE_CASE_OBSERVATION_FAILED",
|
|
2047
|
+
`Observation "${name}" has status "${match.status}", expected "passed".`,
|
|
2048
|
+
"error",
|
|
2049
|
+
suiteCase.id
|
|
2050
|
+
)
|
|
2051
|
+
);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
return { ok: diagnostics.length === 0, diagnostics };
|
|
2055
|
+
}
|
|
2056
|
+
async function runSuiteCase(suiteCase, config, options) {
|
|
2057
|
+
const resolved = await resolveSuiteCaseTrace(suiteCase, options);
|
|
2058
|
+
if (resolved.missing || resolved.tracePath === void 0) {
|
|
2059
|
+
return {
|
|
2060
|
+
id: suiteCase.id,
|
|
2061
|
+
status: "skipped",
|
|
2062
|
+
...resolved.runId !== void 0 ? { runId: resolved.runId } : {},
|
|
2063
|
+
message: resolved.reason,
|
|
2064
|
+
diagnostics: [
|
|
2065
|
+
diagnostic3(
|
|
2066
|
+
"AI_SUITE_CASE_TRACE_MISSING",
|
|
2067
|
+
resolved.reason ?? "Trace not found.",
|
|
2068
|
+
"warning",
|
|
2069
|
+
suiteCase.id
|
|
2070
|
+
)
|
|
2071
|
+
]
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
2074
|
+
let read;
|
|
2075
|
+
try {
|
|
2076
|
+
read = await openTrace({ type: "file", path: resolved.tracePath });
|
|
2077
|
+
} catch (error) {
|
|
2078
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2079
|
+
return {
|
|
2080
|
+
id: suiteCase.id,
|
|
2081
|
+
status: "error",
|
|
2082
|
+
tracePath: resolved.tracePath,
|
|
2083
|
+
...resolved.runId !== void 0 ? { runId: resolved.runId } : {},
|
|
2084
|
+
message,
|
|
2085
|
+
diagnostics: [
|
|
2086
|
+
diagnostic3("AI_SUITE_TRACE_UNREADABLE", message, "error", suiteCase.id)
|
|
2087
|
+
]
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
const { rules, select } = buildCaseRules(suiteCase, config);
|
|
2091
|
+
const checkResult = rules.length > 0 ? runTraceChecks({ read }, { rules, select }) : {
|
|
2092
|
+
ok: true,
|
|
2093
|
+
status: "pass",
|
|
2094
|
+
format: read.format,
|
|
2095
|
+
findings: [],
|
|
2096
|
+
diagnostics: []
|
|
2097
|
+
};
|
|
2098
|
+
const observationResult = validateExpectedObservations(suiteCase, read);
|
|
2099
|
+
const diagnostics = [
|
|
2100
|
+
...checkResult.diagnostics.map(
|
|
2101
|
+
(item) => diagnostic3(
|
|
2102
|
+
"AI_SUITE_CASE_CHECK_FAILED",
|
|
2103
|
+
item.message,
|
|
2104
|
+
item.severity,
|
|
2105
|
+
suiteCase.id
|
|
2106
|
+
)
|
|
2107
|
+
),
|
|
2108
|
+
...checkResult.findings.filter((finding) => finding.status === "fail").map(
|
|
2109
|
+
(finding) => diagnostic3(
|
|
2110
|
+
"AI_SUITE_CASE_CHECK_FAILED",
|
|
2111
|
+
finding.message,
|
|
2112
|
+
finding.severity,
|
|
2113
|
+
suiteCase.id
|
|
2114
|
+
)
|
|
2115
|
+
),
|
|
2116
|
+
...observationResult.diagnostics
|
|
2117
|
+
];
|
|
2118
|
+
const checkOk = checkResult.ok;
|
|
2119
|
+
const observationsOk = observationResult.ok;
|
|
2120
|
+
const ok = checkOk && observationsOk;
|
|
2121
|
+
const status = ok ? "pass" : checkResult.status === "error" ? "error" : "fail";
|
|
2122
|
+
return {
|
|
2123
|
+
id: suiteCase.id,
|
|
2124
|
+
status,
|
|
2125
|
+
tracePath: resolved.tracePath,
|
|
2126
|
+
...resolved.runId !== void 0 ? { runId: resolved.runId } : {},
|
|
2127
|
+
checkOk,
|
|
2128
|
+
observationsOk,
|
|
2129
|
+
diagnostics,
|
|
2130
|
+
...ok ? {} : {
|
|
2131
|
+
message: diagnostics.map((item) => item.message).join("; ") || checkResult.findings.map((item) => item.message).join("; ")
|
|
2132
|
+
}
|
|
2133
|
+
};
|
|
2134
|
+
}
|
|
2135
|
+
async function runSuite(options = {}) {
|
|
2136
|
+
const startedAt = new Date(options.nowMs ?? Date.now()).toISOString();
|
|
2137
|
+
const { config, configPath, configDir } = await loadSuiteConfig(options);
|
|
2138
|
+
const tracesDir = path3.resolve(configDir, config.traces);
|
|
2139
|
+
const cases = [];
|
|
2140
|
+
const diagnostics = [];
|
|
2141
|
+
for (const suiteCase of config.cases) {
|
|
2142
|
+
cases.push(
|
|
2143
|
+
await runSuiteCase(suiteCase, config, {
|
|
2144
|
+
configDir,
|
|
2145
|
+
tracesDir
|
|
2146
|
+
})
|
|
2147
|
+
);
|
|
2148
|
+
}
|
|
2149
|
+
const summary = {
|
|
2150
|
+
passed: cases.filter((item) => item.status === "pass").length,
|
|
2151
|
+
failed: cases.filter((item) => item.status === "fail").length,
|
|
2152
|
+
errors: cases.filter((item) => item.status === "error").length,
|
|
2153
|
+
skipped: cases.filter((item) => item.status === "skipped").length
|
|
2154
|
+
};
|
|
2155
|
+
const finishedAt = new Date(options.nowMs ?? Date.now()).toISOString();
|
|
2156
|
+
const ok = summary.failed === 0 && summary.errors === 0;
|
|
2157
|
+
const status = summary.errors > 0 ? "error" : summary.failed > 0 || !ok ? "fail" : "pass";
|
|
2158
|
+
return {
|
|
2159
|
+
ok,
|
|
2160
|
+
status,
|
|
2161
|
+
suiteName: config.name,
|
|
2162
|
+
configPath,
|
|
2163
|
+
tracesDir,
|
|
2164
|
+
startedAt,
|
|
2165
|
+
finishedAt,
|
|
2166
|
+
summary,
|
|
2167
|
+
cases,
|
|
2168
|
+
diagnostics
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
// packages/core/src/suite/report.ts
|
|
2173
|
+
function statusLabel(status) {
|
|
2174
|
+
return status.toUpperCase();
|
|
2175
|
+
}
|
|
2176
|
+
function renderSuiteReportMarkdown(result) {
|
|
2177
|
+
const lines = [];
|
|
2178
|
+
lines.push(`# Suite: ${result.suiteName}`);
|
|
2179
|
+
lines.push("");
|
|
2180
|
+
lines.push(`Status: **${statusLabel(result.status)}**`);
|
|
2181
|
+
lines.push(`Config: \`${result.configPath}\``);
|
|
2182
|
+
lines.push(`Traces: \`${result.tracesDir}\``);
|
|
2183
|
+
lines.push(`Started: ${result.startedAt}`);
|
|
2184
|
+
lines.push(`Finished: ${result.finishedAt}`);
|
|
2185
|
+
lines.push("");
|
|
2186
|
+
lines.push("## Summary");
|
|
2187
|
+
lines.push(`- Passed: ${result.summary.passed}`);
|
|
2188
|
+
lines.push(`- Failed: ${result.summary.failed}`);
|
|
2189
|
+
lines.push(`- Errors: ${result.summary.errors}`);
|
|
2190
|
+
lines.push(`- Skipped: ${result.summary.skipped}`);
|
|
2191
|
+
lines.push("");
|
|
2192
|
+
lines.push("## Cases");
|
|
2193
|
+
for (const suiteCase of result.cases) {
|
|
2194
|
+
lines.push(`### ${suiteCase.id} \u2014 ${statusLabel(suiteCase.status)}`);
|
|
2195
|
+
if (suiteCase.tracePath !== void 0) {
|
|
2196
|
+
lines.push(`- Trace: \`${suiteCase.tracePath}\``);
|
|
2197
|
+
}
|
|
2198
|
+
if (suiteCase.runId !== void 0) {
|
|
2199
|
+
lines.push(`- Run: \`${suiteCase.runId}\``);
|
|
2200
|
+
}
|
|
2201
|
+
if (suiteCase.message !== void 0 && suiteCase.message.trim() !== "") {
|
|
2202
|
+
lines.push(`- ${suiteCase.message}`);
|
|
2203
|
+
}
|
|
2204
|
+
if (suiteCase.diagnostics.length > 0) {
|
|
2205
|
+
for (const item of suiteCase.diagnostics) {
|
|
2206
|
+
lines.push(`- [${item.severity}] ${item.message}`);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
lines.push("");
|
|
2210
|
+
}
|
|
2211
|
+
return lines.join("\n").trimEnd();
|
|
2212
|
+
}
|
|
2213
|
+
function renderSuiteReport(result, options = {}) {
|
|
2214
|
+
const format = options.format ?? "markdown";
|
|
2215
|
+
if (format === "json") {
|
|
2216
|
+
return JSON.stringify(result, null, 2);
|
|
2217
|
+
}
|
|
2218
|
+
return renderSuiteReportMarkdown(result);
|
|
1636
2219
|
}
|
|
1637
2220
|
|
|
1638
|
-
export { SESSION_WORKFLOW_KEYS, aggregateBundleSafeStatus, aggregateSessionCheckResults, buildActivitySummary, buildBundleMetadata, buildBundleSummaryMarkdown, buildLocalExplanation, buildPlaceholderArtifact, buildSessionIndex, buildTraceStats, bundleFailsOnSafety, defaultBundleOutputPath, deriveSessionStatus, enrichSessionRunRecord, enrichSessionSummary, extractSessionWorkflowMetadata, filterMetasBySessionScope, filterTraces, groupSessionCohorts, isAgentInspectTrace, loadSessionRunRecords, loadTraceMetadataList, normalizeBundleOutputPath, parseDurationFilter, renderActivitySummaryHuman, renderTraceStats, resolveBundleRunIds, searchTraces, sessionKeyForRun, toMetadataSafeStatus, traceMetasToSessionRunRecords };
|
|
2221
|
+
export { DEFAULT_SUITE_ARTIFACTS_DIR, DEFAULT_SUITE_CONFIG_NAMES, SESSION_WORKFLOW_KEYS, aggregateBundleSafeStatus, aggregateSessionCheckResults, buildActivitySummary, buildBundleMetadata, buildBundleSummaryMarkdown, buildLocalExplanation, buildPlaceholderArtifact, buildSessionIndex, buildTraceStats, bundleFailsOnSafety, defaultBundleOutputPath, defaultSuiteConfigTemplate, deriveSessionStatus, enrichSessionRunRecord, enrichSessionSummary, extractSessionWorkflowMetadata, filterMetasBySessionScope, filterTraces, groupSessionCohorts, isAgentInspectTrace, loadSessionRunRecords, loadSuiteConfig, loadTraceMetadataList, normalizeBundleOutputPath, normalizeSuiteConfig, parseDurationFilter, renderActivitySummaryHuman, renderSuiteReport, renderSuiteReportMarkdown, renderTraceStats, resolveBundleRunIds, resolveSuiteCaseTrace, resolveSuiteConfigPath, runSuite, searchTraces, sessionKeyForRun, toMetadataSafeStatus, traceMetasToSessionRunRecords, validateSuiteConfig };
|
|
1639
2222
|
//# sourceMappingURL=advanced.mjs.map
|
|
1640
2223
|
//# sourceMappingURL=advanced.mjs.map
|