agent-inspect 3.3.0 → 3.5.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/README.md +7 -8
- package/docs/COMPARE.md +13 -0
- package/package.json +1 -1
- package/packages/cli/dist/index.cjs +435 -70
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +436 -71
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/checks.cjs +105 -0
- package/packages/core/dist/checks.cjs.map +1 -1
- package/packages/core/dist/checks.d.cts +26 -1
- package/packages/core/dist/checks.d.ts +26 -1
- package/packages/core/dist/checks.mjs +103 -1
- package/packages/core/dist/checks.mjs.map +1 -1
|
@@ -5,7 +5,7 @@ import { fileURLToPath, pathToFileURL } from 'url';
|
|
|
5
5
|
import { Command, Option } from 'commander';
|
|
6
6
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
7
7
|
import crypto, { webcrypto, createHash } from 'crypto';
|
|
8
|
-
import { unlink, stat, mkdir, writeFile, appendFile, readdir, readFile, access, open, constants } from 'fs/promises';
|
|
8
|
+
import { unlink, stat, mkdir, writeFile, appendFile, rm, readdir, readFile, access, open, constants } from 'fs/promises';
|
|
9
9
|
import os from 'os';
|
|
10
10
|
import process3, { stdin, stdout } from 'process';
|
|
11
11
|
import tty from 'tty';
|
|
@@ -14,7 +14,7 @@ import { createServer } from 'http';
|
|
|
14
14
|
import { createRequire } from 'module';
|
|
15
15
|
|
|
16
16
|
// package.json
|
|
17
|
-
var version = "3.
|
|
17
|
+
var version = "3.5.0";
|
|
18
18
|
|
|
19
19
|
// packages/core/src/correlation-metadata.ts
|
|
20
20
|
var TRACE_CORRELATION_KEYS = [
|
|
@@ -3060,12 +3060,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3060
3060
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3061
3061
|
);
|
|
3062
3062
|
const ordered = [...runs].sort(compareRuns);
|
|
3063
|
-
const
|
|
3063
|
+
const path19 = [];
|
|
3064
3064
|
const visited = /* @__PURE__ */ new Set();
|
|
3065
3065
|
const pushRun = (run, confidence, source) => {
|
|
3066
3066
|
if (visited.has(run.runId)) return;
|
|
3067
3067
|
visited.add(run.runId);
|
|
3068
|
-
|
|
3068
|
+
path19.push({
|
|
3069
3069
|
runId: run.runId,
|
|
3070
3070
|
name: run.name,
|
|
3071
3071
|
startedAt: run.startedAt,
|
|
@@ -3090,7 +3090,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3090
3090
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3091
3091
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3092
3092
|
}
|
|
3093
|
-
return
|
|
3093
|
+
return path19;
|
|
3094
3094
|
}
|
|
3095
3095
|
function metaRunIdMatches(run, token, runById) {
|
|
3096
3096
|
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -3203,6 +3203,62 @@ async function isAgentInspectTrace(filePath) {
|
|
|
3203
3203
|
}
|
|
3204
3204
|
}
|
|
3205
3205
|
|
|
3206
|
+
// packages/cli/src/trace-dir-scale.ts
|
|
3207
|
+
var TRACE_COUNT_WARN = 1e3;
|
|
3208
|
+
var TRACE_COUNT_SEVERE = 1e4;
|
|
3209
|
+
var LARGE_TRACE_FILE_BYTES = 50 * 1024 * 1024;
|
|
3210
|
+
function buildScaleWarnings(traceCount, largeFileCount) {
|
|
3211
|
+
const warnings = [];
|
|
3212
|
+
if (traceCount >= TRACE_COUNT_SEVERE) {
|
|
3213
|
+
warnings.push(
|
|
3214
|
+
`trace directory has ${traceCount} runs (>= ${TRACE_COUNT_SEVERE}); archive or split traces \u2014 see docs/SCALE-LIMITS.md`
|
|
3215
|
+
);
|
|
3216
|
+
} else if (traceCount >= TRACE_COUNT_WARN) {
|
|
3217
|
+
warnings.push(
|
|
3218
|
+
`trace directory has ${traceCount} runs (>= ${TRACE_COUNT_WARN}); list/search/stats may be slow \u2014 consider agent-inspect index build`
|
|
3219
|
+
);
|
|
3220
|
+
}
|
|
3221
|
+
if (largeFileCount > 0) {
|
|
3222
|
+
warnings.push(
|
|
3223
|
+
`${largeFileCount} trace file(s) exceed ${Math.round(LARGE_TRACE_FILE_BYTES / (1024 * 1024))}MB; open/check/report may be slow`
|
|
3224
|
+
);
|
|
3225
|
+
}
|
|
3226
|
+
return warnings;
|
|
3227
|
+
}
|
|
3228
|
+
async function assessTraceDirectoryScale(td, options = {}) {
|
|
3229
|
+
const files = await td.list();
|
|
3230
|
+
const sample = options.sampleLargeFiles ?? 25;
|
|
3231
|
+
let largeFileCount = 0;
|
|
3232
|
+
if (files.length > 0 && files.length <= sample * 4) {
|
|
3233
|
+
for (const file of files) {
|
|
3234
|
+
try {
|
|
3235
|
+
const stats = await td.getFileStats(file);
|
|
3236
|
+
if (stats.size >= LARGE_TRACE_FILE_BYTES) largeFileCount += 1;
|
|
3237
|
+
} catch {
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
} else if (files.length > sample) {
|
|
3241
|
+
for (const file of files.slice(0, sample)) {
|
|
3242
|
+
try {
|
|
3243
|
+
const stats = await td.getFileStats(file);
|
|
3244
|
+
if (stats.size >= LARGE_TRACE_FILE_BYTES) largeFileCount += 1;
|
|
3245
|
+
} catch {
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
if (largeFileCount > 0) {
|
|
3249
|
+
largeFileCount = Math.max(largeFileCount, 1);
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
const warnings = buildScaleWarnings(files.length, largeFileCount);
|
|
3253
|
+
return { traceCount: files.length, largeFileCount, warnings };
|
|
3254
|
+
}
|
|
3255
|
+
function emitScaleWarnings(assessment, options = {}) {
|
|
3256
|
+
if (options.json || assessment.warnings.length === 0) return;
|
|
3257
|
+
for (const warning of assessment.warnings) {
|
|
3258
|
+
console.error(`[AgentInspect] warning: ${warning}`);
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3206
3262
|
// packages/cli/src/list.ts
|
|
3207
3263
|
function parseLimit(raw) {
|
|
3208
3264
|
const fallback = 20;
|
|
@@ -3237,6 +3293,8 @@ async function list(options = {}) {
|
|
|
3237
3293
|
parseDuration(options.since.trim());
|
|
3238
3294
|
}
|
|
3239
3295
|
const files = await td.list();
|
|
3296
|
+
const scale = await assessTraceDirectoryScale(td);
|
|
3297
|
+
emitScaleWarnings(scale, { json: options.json });
|
|
3240
3298
|
if (files.length === 0) {
|
|
3241
3299
|
if (options.json) {
|
|
3242
3300
|
console.log("[]");
|
|
@@ -8333,13 +8391,13 @@ function pairSteps(left, right) {
|
|
|
8333
8391
|
return pairs;
|
|
8334
8392
|
}
|
|
8335
8393
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
8336
|
-
const
|
|
8394
|
+
const path19 = buildPath(segments);
|
|
8337
8395
|
if (L.name !== R.name) {
|
|
8338
8396
|
out.push({
|
|
8339
8397
|
kind: "structure",
|
|
8340
8398
|
severity: "warning",
|
|
8341
8399
|
message: "Step name differs",
|
|
8342
|
-
path:
|
|
8400
|
+
path: path19,
|
|
8343
8401
|
left: L.name,
|
|
8344
8402
|
right: R.name
|
|
8345
8403
|
});
|
|
@@ -8349,7 +8407,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8349
8407
|
kind: "step-type",
|
|
8350
8408
|
severity: "warning",
|
|
8351
8409
|
message: "Step type differs",
|
|
8352
|
-
path:
|
|
8410
|
+
path: path19,
|
|
8353
8411
|
left: L.type,
|
|
8354
8412
|
right: R.type
|
|
8355
8413
|
});
|
|
@@ -8359,7 +8417,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8359
8417
|
kind: "step-status",
|
|
8360
8418
|
severity: "warning",
|
|
8361
8419
|
message: "Step status differs",
|
|
8362
|
-
path:
|
|
8420
|
+
path: path19,
|
|
8363
8421
|
left: L.status,
|
|
8364
8422
|
right: R.status
|
|
8365
8423
|
});
|
|
@@ -8371,7 +8429,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8371
8429
|
kind: "error",
|
|
8372
8430
|
severity: "error",
|
|
8373
8431
|
message: "Step error message differs",
|
|
8374
|
-
path:
|
|
8432
|
+
path: path19,
|
|
8375
8433
|
left: le || void 0,
|
|
8376
8434
|
right: re || void 0
|
|
8377
8435
|
});
|
|
@@ -8389,20 +8447,20 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8389
8447
|
kind: "duration",
|
|
8390
8448
|
severity: "info",
|
|
8391
8449
|
message: "Step duration differs",
|
|
8392
|
-
path:
|
|
8450
|
+
path: path19,
|
|
8393
8451
|
left: ld,
|
|
8394
8452
|
right: rd
|
|
8395
8453
|
});
|
|
8396
8454
|
}
|
|
8397
8455
|
}
|
|
8398
8456
|
const lm = stableJson(L.metadata ?? {});
|
|
8399
|
-
const
|
|
8400
|
-
if (lm !==
|
|
8457
|
+
const rm2 = stableJson(R.metadata ?? {});
|
|
8458
|
+
if (lm !== rm2) {
|
|
8401
8459
|
out.push({
|
|
8402
8460
|
kind: "metadata",
|
|
8403
8461
|
severity: "info",
|
|
8404
8462
|
message: "Step metadata differs",
|
|
8405
|
-
path:
|
|
8463
|
+
path: path19,
|
|
8406
8464
|
left: L.metadata,
|
|
8407
8465
|
right: R.metadata
|
|
8408
8466
|
});
|
|
@@ -8414,7 +8472,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8414
8472
|
kind: "output",
|
|
8415
8473
|
severity: "info",
|
|
8416
8474
|
message: "Output preview differs",
|
|
8417
|
-
path:
|
|
8475
|
+
path: path19,
|
|
8418
8476
|
left: L.outputPreview,
|
|
8419
8477
|
right: R.outputPreview
|
|
8420
8478
|
});
|
|
@@ -8574,11 +8632,11 @@ function diffRuns(left, right, options) {
|
|
|
8574
8632
|
}
|
|
8575
8633
|
|
|
8576
8634
|
// packages/core/src/diff/renderer.ts
|
|
8577
|
-
function formatPath(
|
|
8578
|
-
if (
|
|
8635
|
+
function formatPath(path19) {
|
|
8636
|
+
if (path19 === void 0 || path19.path.length === 0) {
|
|
8579
8637
|
return "(run)";
|
|
8580
8638
|
}
|
|
8581
|
-
return
|
|
8639
|
+
return path19.path.map((s) => s.name).join(" > ");
|
|
8582
8640
|
}
|
|
8583
8641
|
function formatValue(v, verbose) {
|
|
8584
8642
|
if (v === void 0) return "(undefined)";
|
|
@@ -8804,6 +8862,8 @@ async function statsCommand(options = {}) {
|
|
|
8804
8862
|
parseDuration(options.since.trim());
|
|
8805
8863
|
}
|
|
8806
8864
|
const files = await td.list();
|
|
8865
|
+
const scale = await assessTraceDirectoryScale(td);
|
|
8866
|
+
emitScaleWarnings(scale, { json: options.json });
|
|
8807
8867
|
if (files.length === 0) {
|
|
8808
8868
|
if (options.json) {
|
|
8809
8869
|
console.log(
|
|
@@ -8874,6 +8934,8 @@ async function searchCommand(options = {}) {
|
|
|
8874
8934
|
parseDurationFilter(options.duration);
|
|
8875
8935
|
}
|
|
8876
8936
|
const files = await td.list();
|
|
8937
|
+
const scale = await assessTraceDirectoryScale(td);
|
|
8938
|
+
emitScaleWarnings(scale, { json: options.json });
|
|
8877
8939
|
let metas = await loadTraceMetadataList(
|
|
8878
8940
|
traceDir,
|
|
8879
8941
|
files,
|
|
@@ -9456,17 +9518,17 @@ function applyRule(rule, value, replacement) {
|
|
|
9456
9518
|
}
|
|
9457
9519
|
return value;
|
|
9458
9520
|
}
|
|
9459
|
-
function childPath(
|
|
9521
|
+
function childPath(path19, key) {
|
|
9460
9522
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
9461
|
-
return
|
|
9523
|
+
return path19 ? `${path19}.${key}` : key;
|
|
9462
9524
|
}
|
|
9463
|
-
return `${
|
|
9525
|
+
return `${path19 || "$"}[${JSON.stringify(key)}]`;
|
|
9464
9526
|
}
|
|
9465
|
-
function indexPath(
|
|
9466
|
-
return `${
|
|
9527
|
+
function indexPath(path19, index) {
|
|
9528
|
+
return `${path19 || "$"}[${index}]`;
|
|
9467
9529
|
}
|
|
9468
|
-
function makeFinding(
|
|
9469
|
-
return preview === void 0 ? { path:
|
|
9530
|
+
function makeFinding(path19, detector, action, matchKind, severity = "warning", preview) {
|
|
9531
|
+
return preview === void 0 ? { path: path19, detector, action, severity, matchKind } : { path: path19, detector, action, severity, matchKind, preview };
|
|
9470
9532
|
}
|
|
9471
9533
|
function createRedactionProfile(profile = "local") {
|
|
9472
9534
|
switch (profile) {
|
|
@@ -9535,11 +9597,11 @@ var Redactor2 = class {
|
|
|
9535
9597
|
#recordFinding(state, finding) {
|
|
9536
9598
|
if (this.#collectFindings) state.findings.push(finding);
|
|
9537
9599
|
}
|
|
9538
|
-
#redactValue(value, key,
|
|
9600
|
+
#redactValue(value, key, path19, depth, state) {
|
|
9539
9601
|
if (depth > this.#maxDepth) {
|
|
9540
9602
|
this.#recordFinding(
|
|
9541
9603
|
state,
|
|
9542
|
-
makeFinding(
|
|
9604
|
+
makeFinding(path19, "structure.maxDepth", "truncate", "value", "warning")
|
|
9543
9605
|
);
|
|
9544
9606
|
return "[Truncated]";
|
|
9545
9607
|
}
|
|
@@ -9548,19 +9610,19 @@ var Redactor2 = class {
|
|
|
9548
9610
|
if (rule) {
|
|
9549
9611
|
this.#recordFinding(
|
|
9550
9612
|
state,
|
|
9551
|
-
makeFinding(
|
|
9613
|
+
makeFinding(path19, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
9552
9614
|
);
|
|
9553
9615
|
return applyRule(rule, value, this.#replacement);
|
|
9554
9616
|
}
|
|
9555
9617
|
}
|
|
9556
9618
|
for (const detector of this.#detectors) {
|
|
9557
|
-
const detections = detector.detect({ path:
|
|
9619
|
+
const detections = detector.detect({ path: path19, key, value });
|
|
9558
9620
|
for (const detection of detections) {
|
|
9559
9621
|
const action = detection.action ?? "replace";
|
|
9560
9622
|
this.#recordFinding(
|
|
9561
9623
|
state,
|
|
9562
9624
|
makeFinding(
|
|
9563
|
-
|
|
9625
|
+
path19,
|
|
9564
9626
|
detector.id,
|
|
9565
9627
|
action,
|
|
9566
9628
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -9578,7 +9640,7 @@ var Redactor2 = class {
|
|
|
9578
9640
|
const out = [];
|
|
9579
9641
|
state.seen.set(value, out);
|
|
9580
9642
|
value.forEach((item, index) => {
|
|
9581
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
9643
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path19, index), depth + 1, state);
|
|
9582
9644
|
});
|
|
9583
9645
|
return out;
|
|
9584
9646
|
}
|
|
@@ -9590,7 +9652,7 @@ var Redactor2 = class {
|
|
|
9590
9652
|
out[entryKey] = this.#redactValue(
|
|
9591
9653
|
entryValue,
|
|
9592
9654
|
entryKey,
|
|
9593
|
-
childPath(
|
|
9655
|
+
childPath(path19 === "$" ? "" : path19, entryKey),
|
|
9594
9656
|
depth + 1,
|
|
9595
9657
|
state
|
|
9596
9658
|
);
|
|
@@ -10462,7 +10524,7 @@ function stripPrefix(name, prefixes) {
|
|
|
10462
10524
|
}
|
|
10463
10525
|
return name;
|
|
10464
10526
|
}
|
|
10465
|
-
function eventEvidence(event,
|
|
10527
|
+
function eventEvidence(event, path19) {
|
|
10466
10528
|
return {
|
|
10467
10529
|
runId: event.runId,
|
|
10468
10530
|
eventId: event.eventId,
|
|
@@ -10472,7 +10534,7 @@ function eventEvidence(event, path18) {
|
|
|
10472
10534
|
kind: event.kind,
|
|
10473
10535
|
name: event.name,
|
|
10474
10536
|
status: event.status,
|
|
10475
|
-
...
|
|
10537
|
+
...path19 ? { path: path19 } : {}
|
|
10476
10538
|
};
|
|
10477
10539
|
}
|
|
10478
10540
|
function runEvidence(run) {
|
|
@@ -10535,9 +10597,9 @@ function eventEndMs(event) {
|
|
|
10535
10597
|
function normalizedKey(value) {
|
|
10536
10598
|
return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
10537
10599
|
}
|
|
10538
|
-
function lastPathSegment(
|
|
10539
|
-
const parts =
|
|
10540
|
-
return parts[parts.length - 1] ??
|
|
10600
|
+
function lastPathSegment(path19) {
|
|
10601
|
+
const parts = path19.split(".");
|
|
10602
|
+
return parts[parts.length - 1] ?? path19;
|
|
10541
10603
|
}
|
|
10542
10604
|
function valueType(value) {
|
|
10543
10605
|
if (Array.isArray(value)) return "array";
|
|
@@ -10551,12 +10613,12 @@ function serializedByteLength(value) {
|
|
|
10551
10613
|
return void 0;
|
|
10552
10614
|
}
|
|
10553
10615
|
}
|
|
10554
|
-
function pushValueEntries(entries, event, value,
|
|
10555
|
-
entries.push({ event, path:
|
|
10616
|
+
function pushValueEntries(entries, event, value, path19, key, depth = 0) {
|
|
10617
|
+
entries.push({ event, path: path19, key, value });
|
|
10556
10618
|
if (depth >= 8) return;
|
|
10557
10619
|
if (Array.isArray(value)) {
|
|
10558
10620
|
for (const [index, item] of value.entries()) {
|
|
10559
|
-
pushValueEntries(entries, event, item, `${
|
|
10621
|
+
pushValueEntries(entries, event, item, `${path19}.${index}`, String(index), depth + 1);
|
|
10560
10622
|
}
|
|
10561
10623
|
return;
|
|
10562
10624
|
}
|
|
@@ -10566,7 +10628,7 @@ function pushValueEntries(entries, event, value, path18, key, depth = 0) {
|
|
|
10566
10628
|
entries,
|
|
10567
10629
|
event,
|
|
10568
10630
|
value[nestedKey],
|
|
10569
|
-
`${
|
|
10631
|
+
`${path19}.${nestedKey}`,
|
|
10570
10632
|
nestedKey,
|
|
10571
10633
|
depth + 1
|
|
10572
10634
|
);
|
|
@@ -10647,9 +10709,9 @@ function eventDurationMs(event) {
|
|
|
10647
10709
|
}
|
|
10648
10710
|
function treeShape(nodes) {
|
|
10649
10711
|
const lines = [];
|
|
10650
|
-
const visit = (node,
|
|
10651
|
-
lines.push(`${
|
|
10652
|
-
node.children.forEach((child, index) => visit(child, `${
|
|
10712
|
+
const visit = (node, path19) => {
|
|
10713
|
+
lines.push(`${path19}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
|
|
10714
|
+
node.children.forEach((child, index) => visit(child, `${path19}.${index}`));
|
|
10653
10715
|
};
|
|
10654
10716
|
nodes.forEach((node, index) => visit(node, String(index)));
|
|
10655
10717
|
return lines;
|
|
@@ -10698,9 +10760,9 @@ function retrievalShape(context) {
|
|
|
10698
10760
|
function guardrailShape(context) {
|
|
10699
10761
|
return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
|
|
10700
10762
|
}
|
|
10701
|
-
function firstEvidenceForKind(context, kind,
|
|
10763
|
+
function firstEvidenceForKind(context, kind, path19) {
|
|
10702
10764
|
const event = context.events.find((candidate) => candidate.kind === kind);
|
|
10703
|
-
return event ? [eventEvidence(event,
|
|
10765
|
+
return event ? [eventEvidence(event, path19)] : runEvidence(context.selectedRun);
|
|
10704
10766
|
}
|
|
10705
10767
|
function baselineDiffFinding(message, evidence, expected, actual) {
|
|
10706
10768
|
return failFinding("baseline.regression", message, evidence, expected, actual);
|
|
@@ -10764,6 +10826,108 @@ function createRunDurationRule(options) {
|
|
|
10764
10826
|
}
|
|
10765
10827
|
};
|
|
10766
10828
|
}
|
|
10829
|
+
function createMaxStepDurationRule(options) {
|
|
10830
|
+
return {
|
|
10831
|
+
id: "run.maxStepDuration",
|
|
10832
|
+
category: "run",
|
|
10833
|
+
defaultSeverity: "error",
|
|
10834
|
+
evaluate(context) {
|
|
10835
|
+
const over = context.events.filter((event) => {
|
|
10836
|
+
const duration = eventDurationMs(event);
|
|
10837
|
+
return duration !== void 0 && duration > options.maxDurationMs;
|
|
10838
|
+
});
|
|
10839
|
+
if (over.length === 0) return [];
|
|
10840
|
+
return [
|
|
10841
|
+
failFinding(
|
|
10842
|
+
"run.maxStepDuration",
|
|
10843
|
+
`${over.length} step(s) exceeded max duration ${options.maxDurationMs}ms.`,
|
|
10844
|
+
over.map((event) => eventEvidence(event, "durationMs")),
|
|
10845
|
+
{ maxDurationMs: options.maxDurationMs },
|
|
10846
|
+
over.map((event) => ({
|
|
10847
|
+
eventId: event.eventId,
|
|
10848
|
+
name: event.name,
|
|
10849
|
+
durationMs: eventDurationMs(event)
|
|
10850
|
+
}))
|
|
10851
|
+
)
|
|
10852
|
+
];
|
|
10853
|
+
}
|
|
10854
|
+
};
|
|
10855
|
+
}
|
|
10856
|
+
function createStallDetectionRule(options = {}) {
|
|
10857
|
+
const requireEndedAt = options.requireEndedAt === true;
|
|
10858
|
+
return {
|
|
10859
|
+
id: "run.stall",
|
|
10860
|
+
category: "run",
|
|
10861
|
+
defaultSeverity: "warning",
|
|
10862
|
+
evaluate(context) {
|
|
10863
|
+
const findings = [];
|
|
10864
|
+
const running = context.events.filter((event) => event.status === "running");
|
|
10865
|
+
if (running.length > 0) {
|
|
10866
|
+
findings.push(
|
|
10867
|
+
failFinding(
|
|
10868
|
+
"run.stall",
|
|
10869
|
+
`Found ${running.length} event(s) still running (possible stall).`,
|
|
10870
|
+
running.map((event) => eventEvidence(event, "status")),
|
|
10871
|
+
"no running events",
|
|
10872
|
+
running.length
|
|
10873
|
+
)
|
|
10874
|
+
);
|
|
10875
|
+
}
|
|
10876
|
+
if (requireEndedAt) {
|
|
10877
|
+
const incomplete = context.events.filter(
|
|
10878
|
+
(event) => event.startedAt !== void 0 && event.endedAt === void 0 && event.status !== "running"
|
|
10879
|
+
);
|
|
10880
|
+
if (incomplete.length > 0) {
|
|
10881
|
+
findings.push(
|
|
10882
|
+
failFinding(
|
|
10883
|
+
"run.stall",
|
|
10884
|
+
`Found ${incomplete.length} started event(s) without endedAt.`,
|
|
10885
|
+
incomplete.map((event) => eventEvidence(event, "endedAt")),
|
|
10886
|
+
"endedAt for started events",
|
|
10887
|
+
incomplete.length
|
|
10888
|
+
)
|
|
10889
|
+
);
|
|
10890
|
+
}
|
|
10891
|
+
}
|
|
10892
|
+
return findings;
|
|
10893
|
+
}
|
|
10894
|
+
};
|
|
10895
|
+
}
|
|
10896
|
+
function createRequireCompletedRule() {
|
|
10897
|
+
return {
|
|
10898
|
+
id: "run.requireCompleted",
|
|
10899
|
+
category: "run",
|
|
10900
|
+
defaultSeverity: "error",
|
|
10901
|
+
evaluate(context) {
|
|
10902
|
+
const findings = [];
|
|
10903
|
+
const runStatus = context.selectedRun?.status;
|
|
10904
|
+
if (runStatus === "running") {
|
|
10905
|
+
findings.push(
|
|
10906
|
+
failFinding(
|
|
10907
|
+
"run.requireCompleted",
|
|
10908
|
+
"Run is still running.",
|
|
10909
|
+
runEvidence(context.selectedRun),
|
|
10910
|
+
"completed run",
|
|
10911
|
+
runStatus
|
|
10912
|
+
)
|
|
10913
|
+
);
|
|
10914
|
+
}
|
|
10915
|
+
const running = context.events.filter((event) => event.status === "running");
|
|
10916
|
+
if (running.length > 0) {
|
|
10917
|
+
findings.push(
|
|
10918
|
+
failFinding(
|
|
10919
|
+
"run.requireCompleted",
|
|
10920
|
+
`Run has ${running.length} incomplete running event(s).`,
|
|
10921
|
+
running.map((event) => eventEvidence(event, "status")),
|
|
10922
|
+
"no running events",
|
|
10923
|
+
running.length
|
|
10924
|
+
)
|
|
10925
|
+
);
|
|
10926
|
+
}
|
|
10927
|
+
return findings;
|
|
10928
|
+
}
|
|
10929
|
+
};
|
|
10930
|
+
}
|
|
10767
10931
|
function createRunDepthRule(options) {
|
|
10768
10932
|
return {
|
|
10769
10933
|
id: "run.depth",
|
|
@@ -10948,13 +11112,13 @@ function createStructureCycleRule() {
|
|
|
10948
11112
|
const seenCycles = /* @__PURE__ */ new Set();
|
|
10949
11113
|
const findings = [];
|
|
10950
11114
|
for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
|
|
10951
|
-
const
|
|
11115
|
+
const path19 = [];
|
|
10952
11116
|
const seenAt = /* @__PURE__ */ new Map();
|
|
10953
11117
|
let current = event;
|
|
10954
11118
|
while (current) {
|
|
10955
11119
|
const existing = seenAt.get(current.eventId);
|
|
10956
11120
|
if (existing !== void 0) {
|
|
10957
|
-
const cycle =
|
|
11121
|
+
const cycle = path19.slice(existing);
|
|
10958
11122
|
const key = cycle.map((item) => item.eventId).sort().join("\0");
|
|
10959
11123
|
if (!seenCycles.has(key)) {
|
|
10960
11124
|
seenCycles.add(key);
|
|
@@ -10970,8 +11134,8 @@ function createStructureCycleRule() {
|
|
|
10970
11134
|
}
|
|
10971
11135
|
break;
|
|
10972
11136
|
}
|
|
10973
|
-
seenAt.set(current.eventId,
|
|
10974
|
-
|
|
11137
|
+
seenAt.set(current.eventId, path19.length);
|
|
11138
|
+
path19.push(current);
|
|
10975
11139
|
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
10976
11140
|
}
|
|
10977
11141
|
}
|
|
@@ -11768,23 +11932,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
11768
11932
|
}
|
|
11769
11933
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
11770
11934
|
}
|
|
11771
|
-
function validateSchemaField(value, field,
|
|
11935
|
+
function validateSchemaField(value, field, path19, evidence) {
|
|
11772
11936
|
const ruleId = "guardrail.structured-output";
|
|
11773
11937
|
if (field.type) {
|
|
11774
11938
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
11775
11939
|
if (actual !== field.type) {
|
|
11776
|
-
evidence.push({ ruleId, path:
|
|
11940
|
+
evidence.push({ ruleId, path: path19, preview: `expected ${field.type}, got ${actual}` });
|
|
11777
11941
|
return;
|
|
11778
11942
|
}
|
|
11779
11943
|
}
|
|
11780
11944
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
11781
|
-
evidence.push({ ruleId, path:
|
|
11945
|
+
evidence.push({ ruleId, path: path19, preview: "value not in enum" });
|
|
11782
11946
|
}
|
|
11783
11947
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
11784
11948
|
const record = value;
|
|
11785
11949
|
for (const key of field.required) {
|
|
11786
11950
|
if (!(key in record)) {
|
|
11787
|
-
evidence.push({ ruleId, path: `${
|
|
11951
|
+
evidence.push({ ruleId, path: `${path19}.${key}`, preview: "missing required key" });
|
|
11788
11952
|
}
|
|
11789
11953
|
}
|
|
11790
11954
|
}
|
|
@@ -12145,6 +12309,17 @@ function buildRules(config, options) {
|
|
|
12145
12309
|
const safety = checks2.safety ?? {};
|
|
12146
12310
|
const maxDurationMs = parseNumber(options.maxDurationMs, "--max-duration-ms") ?? run.maxDurationMs;
|
|
12147
12311
|
const maxTotalTokens = parseNumber(options.maxTotalTokens, "--max-total-tokens") ?? llm.maxTotalTokens;
|
|
12312
|
+
let maxStepDurationMs;
|
|
12313
|
+
if (options.maxStepDuration !== void 0) {
|
|
12314
|
+
try {
|
|
12315
|
+
maxStepDurationMs = parseDuration(options.maxStepDuration.trim());
|
|
12316
|
+
} catch (error) {
|
|
12317
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12318
|
+
diagnostics.push(
|
|
12319
|
+
diagnostic2("AI_CHECK_INVALID_ARGUMENTS", `--max-step-duration: ${message}`)
|
|
12320
|
+
);
|
|
12321
|
+
}
|
|
12322
|
+
}
|
|
12148
12323
|
const rules = [
|
|
12149
12324
|
createRunStatusRule(run),
|
|
12150
12325
|
createStructureOrphanRule(),
|
|
@@ -12155,6 +12330,15 @@ function buildRules(config, options) {
|
|
|
12155
12330
|
if (maxDurationMs !== void 0) {
|
|
12156
12331
|
rules.push(createRunDurationRule({ maxDurationMs }));
|
|
12157
12332
|
}
|
|
12333
|
+
if (maxStepDurationMs !== void 0) {
|
|
12334
|
+
rules.push(createMaxStepDurationRule({ maxDurationMs: maxStepDurationMs }));
|
|
12335
|
+
}
|
|
12336
|
+
if (options.requireCompleted) {
|
|
12337
|
+
rules.push(createRequireCompletedRule());
|
|
12338
|
+
}
|
|
12339
|
+
if (options.detectStalls) {
|
|
12340
|
+
rules.push(createStallDetectionRule({ requireEndedAt: true }));
|
|
12341
|
+
}
|
|
12158
12342
|
if (run.maxDepth !== void 0) {
|
|
12159
12343
|
rules.push(createRunDepthRule({ maxDepth: run.maxDepth }));
|
|
12160
12344
|
}
|
|
@@ -12249,10 +12433,10 @@ function printHuman(result) {
|
|
|
12249
12433
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
12250
12434
|
}
|
|
12251
12435
|
for (const finding of result.findings) {
|
|
12252
|
-
const
|
|
12436
|
+
const path19 = finding.evidence[0]?.path;
|
|
12253
12437
|
const run = finding.evidence[0]?.runId;
|
|
12254
12438
|
const runPrefix = run ? `[${run}] ` : "";
|
|
12255
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
12439
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path19 ? ` (${path19})` : ""}`);
|
|
12256
12440
|
}
|
|
12257
12441
|
}
|
|
12258
12442
|
function readErrorResult(error) {
|
|
@@ -12790,10 +12974,10 @@ async function evalRun(input3, options = {}) {
|
|
|
12790
12974
|
diagnostics: []
|
|
12791
12975
|
};
|
|
12792
12976
|
}
|
|
12793
|
-
function evidenceForRun(run,
|
|
12794
|
-
return [{ runId: run.runId, ...
|
|
12977
|
+
function evidenceForRun(run, path19) {
|
|
12978
|
+
return [{ runId: run.runId, ...path19 !== void 0 ? { path: path19 } : {} }];
|
|
12795
12979
|
}
|
|
12796
|
-
function evidenceForEvent(event,
|
|
12980
|
+
function evidenceForEvent(event, path19) {
|
|
12797
12981
|
return [
|
|
12798
12982
|
{
|
|
12799
12983
|
runId: event.runId,
|
|
@@ -12801,7 +12985,7 @@ function evidenceForEvent(event, path18) {
|
|
|
12801
12985
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
12802
12986
|
kind: event.kind,
|
|
12803
12987
|
name: event.name,
|
|
12804
|
-
...
|
|
12988
|
+
...path19 !== void 0 ? { path: path19 } : {}
|
|
12805
12989
|
}
|
|
12806
12990
|
];
|
|
12807
12991
|
}
|
|
@@ -12959,9 +13143,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
12959
13143
|
function tokenize(text) {
|
|
12960
13144
|
return [...text.toLowerCase().matchAll(/[a-z0-9][a-z0-9'-]{2,}/g)].map((match) => match[0].replace(/^['-]+|['-]+$/g, "")).filter((token) => token.length > 2 && !STOP_WORDS.has(token));
|
|
12961
13145
|
}
|
|
12962
|
-
function firstEvidence(fields, run,
|
|
13146
|
+
function firstEvidence(fields, run, path19) {
|
|
12963
13147
|
const first = fields[0];
|
|
12964
|
-
return first === void 0 ? evidenceForRun(run,
|
|
13148
|
+
return first === void 0 ? evidenceForRun(run, path19) : evidenceForEvent(first.node.event, first.path);
|
|
12965
13149
|
}
|
|
12966
13150
|
function collectSourceIds(nodes, keys) {
|
|
12967
13151
|
const wanted = keySet(keys);
|
|
@@ -13338,8 +13522,8 @@ function renderEvalMarkdown(result) {
|
|
|
13338
13522
|
if (result.findings.length > 0) {
|
|
13339
13523
|
lines.push("", "## Findings");
|
|
13340
13524
|
for (const finding of result.findings) {
|
|
13341
|
-
const
|
|
13342
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
13525
|
+
const path19 = finding.evidence[0]?.path;
|
|
13526
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path19 ? ` (${path19})` : ""}`);
|
|
13343
13527
|
}
|
|
13344
13528
|
}
|
|
13345
13529
|
return `${lines.join("\n")}
|
|
@@ -13532,8 +13716,8 @@ function printHuman2(result) {
|
|
|
13532
13716
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
13533
13717
|
}
|
|
13534
13718
|
for (const finding of result.findings) {
|
|
13535
|
-
const
|
|
13536
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
13719
|
+
const path19 = finding.evidence[0]?.path;
|
|
13720
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path19 ? ` (${path19})` : ""}`);
|
|
13537
13721
|
}
|
|
13538
13722
|
}
|
|
13539
13723
|
function readErrorResult2(error) {
|
|
@@ -13771,8 +13955,8 @@ function printHuman3(result) {
|
|
|
13771
13955
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
13772
13956
|
}
|
|
13773
13957
|
for (const finding of result.findings) {
|
|
13774
|
-
const
|
|
13775
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
13958
|
+
const path19 = finding.evidence[0]?.path;
|
|
13959
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path19 ? ` (${path19})` : ""}`);
|
|
13776
13960
|
}
|
|
13777
13961
|
console.log(`Note: ${result.note}`);
|
|
13778
13962
|
}
|
|
@@ -13891,8 +14075,8 @@ function renderCheckSection(result) {
|
|
|
13891
14075
|
`Diagnostics: ${result.diagnostics.length}`
|
|
13892
14076
|
];
|
|
13893
14077
|
for (const finding of result.findings.slice(0, 10)) {
|
|
13894
|
-
const
|
|
13895
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
14078
|
+
const path19 = finding.evidence[0]?.path ?? "(run)";
|
|
14079
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path19})`);
|
|
13896
14080
|
}
|
|
13897
14081
|
for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
|
|
13898
14082
|
lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
@@ -14894,6 +15078,174 @@ Summary: ${failed} failed, ${warned} warnings`);
|
|
|
14894
15078
|
if (failed > 0) process3.exitCode = 1;
|
|
14895
15079
|
}
|
|
14896
15080
|
|
|
15081
|
+
// packages/adapter-sdk/src/indexer.ts
|
|
15082
|
+
function defineIndexer(indexer) {
|
|
15083
|
+
if (!indexer.id.trim()) throw new Error("indexer id is required");
|
|
15084
|
+
return indexer;
|
|
15085
|
+
}
|
|
15086
|
+
async function indexIsStale(snapshot, traceDir) {
|
|
15087
|
+
const builtMs = Date.parse(snapshot.builtAt);
|
|
15088
|
+
if (Number.isNaN(builtMs)) return true;
|
|
15089
|
+
const td = new TraceDirectory({ dir: traceDir });
|
|
15090
|
+
const files = await td.list();
|
|
15091
|
+
for (const file of files) {
|
|
15092
|
+
const stats = await td.getFileStats(file);
|
|
15093
|
+
if (stats.mtimeMs > builtMs) return true;
|
|
15094
|
+
}
|
|
15095
|
+
return false;
|
|
15096
|
+
}
|
|
15097
|
+
function createTraceDirectoryIndexer() {
|
|
15098
|
+
return defineIndexer({
|
|
15099
|
+
id: "trace-directory-metadata",
|
|
15100
|
+
async rebuild(traceDir, options = {}) {
|
|
15101
|
+
const warnings = [];
|
|
15102
|
+
const td = new TraceDirectory({ dir: traceDir });
|
|
15103
|
+
const files = await td.list();
|
|
15104
|
+
const maxEntries = options.maxEntries ?? 1e4;
|
|
15105
|
+
if (files.length > maxEntries) {
|
|
15106
|
+
warnings.push(
|
|
15107
|
+
`indexer.truncated: trace directory has ${files.length} files; indexing first ${maxEntries}`
|
|
15108
|
+
);
|
|
15109
|
+
}
|
|
15110
|
+
const slice = files.slice(0, maxEntries);
|
|
15111
|
+
const metas = await loadTraceMetadataList(
|
|
15112
|
+
traceDir,
|
|
15113
|
+
slice,
|
|
15114
|
+
(fileName) => td.getPath(fileName)
|
|
15115
|
+
);
|
|
15116
|
+
const entries = metas.map((meta) => ({
|
|
15117
|
+
runId: meta.runId,
|
|
15118
|
+
path: meta.filePath,
|
|
15119
|
+
name: meta.name,
|
|
15120
|
+
startedAt: meta.startedAt,
|
|
15121
|
+
status: meta.status
|
|
15122
|
+
})).sort((a, b) => a.runId.localeCompare(b.runId));
|
|
15123
|
+
if (entries.length < slice.length) {
|
|
15124
|
+
warnings.push(
|
|
15125
|
+
`indexer.partial: indexed ${entries.length} of ${slice.length} trace files`
|
|
15126
|
+
);
|
|
15127
|
+
}
|
|
15128
|
+
return {
|
|
15129
|
+
traceDir,
|
|
15130
|
+
builtAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15131
|
+
entries,
|
|
15132
|
+
warnings
|
|
15133
|
+
};
|
|
15134
|
+
}
|
|
15135
|
+
});
|
|
15136
|
+
}
|
|
15137
|
+
|
|
15138
|
+
// packages/cli/src/index-cmd.ts
|
|
15139
|
+
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
15140
|
+
function traceIndexPath(traceDir) {
|
|
15141
|
+
return path14.join(traceDir, INDEX_FILENAME);
|
|
15142
|
+
}
|
|
15143
|
+
function parseMaxEntries(raw) {
|
|
15144
|
+
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
15145
|
+
const parsed = Number.parseInt(raw, 10);
|
|
15146
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
15147
|
+
throw new Error("--max-entries must be a positive integer.");
|
|
15148
|
+
}
|
|
15149
|
+
return parsed;
|
|
15150
|
+
}
|
|
15151
|
+
async function readSnapshot(indexPath2) {
|
|
15152
|
+
try {
|
|
15153
|
+
const raw = await readFile(indexPath2, "utf8");
|
|
15154
|
+
return JSON.parse(raw);
|
|
15155
|
+
} catch {
|
|
15156
|
+
return void 0;
|
|
15157
|
+
}
|
|
15158
|
+
}
|
|
15159
|
+
async function indexBuildCommand(options = {}) {
|
|
15160
|
+
try {
|
|
15161
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
15162
|
+
await mkdir(traceDir, { recursive: true });
|
|
15163
|
+
const indexer = createTraceDirectoryIndexer();
|
|
15164
|
+
const snapshot = await indexer.rebuild(traceDir, {
|
|
15165
|
+
maxEntries: parseMaxEntries(options.maxEntries)
|
|
15166
|
+
});
|
|
15167
|
+
const indexPath2 = traceIndexPath(traceDir);
|
|
15168
|
+
await writeFile(indexPath2, `${JSON.stringify(snapshot, null, 2)}
|
|
15169
|
+
`, "utf8");
|
|
15170
|
+
if (options.json) {
|
|
15171
|
+
console.log(JSON.stringify({ ok: true, indexPath: indexPath2, ...snapshot }, null, 2));
|
|
15172
|
+
return;
|
|
15173
|
+
}
|
|
15174
|
+
console.log(`Built trace index: ${indexPath2}`);
|
|
15175
|
+
console.log(`Entries: ${snapshot.entries.length}`);
|
|
15176
|
+
if (snapshot.warnings.length > 0) {
|
|
15177
|
+
for (const warning of snapshot.warnings) {
|
|
15178
|
+
console.log(`warning: ${warning}`);
|
|
15179
|
+
}
|
|
15180
|
+
}
|
|
15181
|
+
} catch (e) {
|
|
15182
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
15183
|
+
console.error(`[AgentInspect] index build failed: ${msg}`);
|
|
15184
|
+
process.exitCode = 1;
|
|
15185
|
+
}
|
|
15186
|
+
}
|
|
15187
|
+
async function indexStatusCommand(options = {}) {
|
|
15188
|
+
try {
|
|
15189
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
15190
|
+
const indexPath2 = traceIndexPath(traceDir);
|
|
15191
|
+
const snapshot = await readSnapshot(indexPath2);
|
|
15192
|
+
if (!snapshot) {
|
|
15193
|
+
const payload2 = { ok: true, exists: false, indexPath: indexPath2, traceDir, stale: true };
|
|
15194
|
+
if (options.json) {
|
|
15195
|
+
console.log(JSON.stringify(payload2, null, 2));
|
|
15196
|
+
} else {
|
|
15197
|
+
console.log(`No index at ${indexPath2}`);
|
|
15198
|
+
console.log("Run: agent-inspect index build");
|
|
15199
|
+
}
|
|
15200
|
+
return;
|
|
15201
|
+
}
|
|
15202
|
+
const stale = await indexIsStale(snapshot, traceDir);
|
|
15203
|
+
const payload = {
|
|
15204
|
+
ok: true,
|
|
15205
|
+
exists: true,
|
|
15206
|
+
indexPath: indexPath2,
|
|
15207
|
+
traceDir,
|
|
15208
|
+
stale,
|
|
15209
|
+
builtAt: snapshot.builtAt,
|
|
15210
|
+
entries: snapshot.entries.length,
|
|
15211
|
+
warnings: snapshot.warnings
|
|
15212
|
+
};
|
|
15213
|
+
if (options.json) {
|
|
15214
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
15215
|
+
return;
|
|
15216
|
+
}
|
|
15217
|
+
console.log(`Index: ${indexPath2}`);
|
|
15218
|
+
console.log(`Built: ${snapshot.builtAt}`);
|
|
15219
|
+
console.log(`Entries: ${snapshot.entries.length}`);
|
|
15220
|
+
console.log(`Stale: ${stale ? "yes" : "no"}`);
|
|
15221
|
+
if (snapshot.warnings.length > 0) {
|
|
15222
|
+
for (const warning of snapshot.warnings) {
|
|
15223
|
+
console.log(`warning: ${warning}`);
|
|
15224
|
+
}
|
|
15225
|
+
}
|
|
15226
|
+
} catch (e) {
|
|
15227
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
15228
|
+
console.error(`[AgentInspect] index status failed: ${msg}`);
|
|
15229
|
+
process.exitCode = 1;
|
|
15230
|
+
}
|
|
15231
|
+
}
|
|
15232
|
+
async function indexCleanCommand(options = {}) {
|
|
15233
|
+
try {
|
|
15234
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
15235
|
+
const indexPath2 = traceIndexPath(traceDir);
|
|
15236
|
+
await rm(indexPath2, { force: true });
|
|
15237
|
+
if (options.json) {
|
|
15238
|
+
console.log(JSON.stringify({ ok: true, removed: indexPath2 }, null, 2));
|
|
15239
|
+
return;
|
|
15240
|
+
}
|
|
15241
|
+
console.log(`Removed index: ${indexPath2}`);
|
|
15242
|
+
} catch (e) {
|
|
15243
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
15244
|
+
console.error(`[AgentInspect] index clean failed: ${msg}`);
|
|
15245
|
+
process.exitCode = 1;
|
|
15246
|
+
}
|
|
15247
|
+
}
|
|
15248
|
+
|
|
14897
15249
|
// packages/cli/src/index.ts
|
|
14898
15250
|
function runCommand(action) {
|
|
14899
15251
|
void action().catch((error) => {
|
|
@@ -15018,7 +15370,10 @@ function createCliProgram() {
|
|
|
15018
15370
|
]).option("--allowed-model <model>", "allow an LLM model (repeatable)", (value, previous = []) => [
|
|
15019
15371
|
...previous,
|
|
15020
15372
|
value
|
|
15021
|
-
]).option("--max-total-tokens <number>", "add llm.usage with a max total-token budget").option(
|
|
15373
|
+
]).option("--max-total-tokens <number>", "add llm.usage with a max total-token budget").option(
|
|
15374
|
+
"--max-step-duration <duration>",
|
|
15375
|
+
"add run.maxStepDuration (e.g. 30s, 5m)"
|
|
15376
|
+
).option("--require-completed", "add run.requireCompleted").option("--detect-stalls", "add run.stall for running or incomplete events").option("--session <id>", "check all runs in a workflow session (requires --dir)").option("--group <id>", "check all runs sharing a groupId (requires --dir)").option(
|
|
15022
15377
|
"--correlate-group",
|
|
15023
15378
|
"when using --session, also match synthetic group: session keys"
|
|
15024
15379
|
).option(
|
|
@@ -15212,6 +15567,16 @@ function createCliProgram() {
|
|
|
15212
15567
|
).action((opts) => {
|
|
15213
15568
|
runCommand(() => doctorCommand(opts));
|
|
15214
15569
|
});
|
|
15570
|
+
const indexCmd = program.command("index").description("Optional local trace directory index (rebuildable metadata cache)");
|
|
15571
|
+
indexCmd.command("build").description("Build or refresh .agent-inspect-index.json").option("--dir <path>", "trace directory").option("--json", "print JSON result").option("--max-entries <n>", "cap indexed entries (default 10000)").action((opts) => {
|
|
15572
|
+
runCommand(() => indexBuildCommand(opts));
|
|
15573
|
+
});
|
|
15574
|
+
indexCmd.command("status").description("Show index freshness and entry count").option("--dir <path>", "trace directory").option("--json", "print JSON result").action((opts) => {
|
|
15575
|
+
runCommand(() => indexStatusCommand(opts));
|
|
15576
|
+
});
|
|
15577
|
+
indexCmd.command("clean").description("Remove the local index file").option("--dir <path>", "trace directory").option("--json", "print JSON result").action((opts) => {
|
|
15578
|
+
runCommand(() => indexCleanCommand(opts));
|
|
15579
|
+
});
|
|
15215
15580
|
return program;
|
|
15216
15581
|
}
|
|
15217
15582
|
function isPrimaryModule() {
|