agent-inspect 6.14.1 → 6.15.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.
Files changed (79) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/README.md +1 -1
  3. package/docs/API.md +19 -3
  4. package/docs/KNOWN-ISSUES.md +2 -1
  5. package/package.json +2 -2
  6. package/packages/cli/dist/{chunk-MEO2Z3KE.mjs → chunk-LFSBMUCD.mjs} +316 -41
  7. package/packages/cli/dist/chunk-LFSBMUCD.mjs.map +1 -0
  8. package/packages/cli/dist/index.cjs +388 -42
  9. package/packages/cli/dist/index.cjs.map +1 -1
  10. package/packages/cli/dist/index.mjs +59 -6
  11. package/packages/cli/dist/index.mjs.map +1 -1
  12. package/packages/cli/dist/{src-6VZNGIF6.mjs → src-5J2HPOJ3.mjs} +3 -3
  13. package/packages/cli/dist/{src-6VZNGIF6.mjs.map → src-5J2HPOJ3.mjs.map} +1 -1
  14. package/packages/core/dist/advanced.cjs +268 -24
  15. package/packages/core/dist/advanced.cjs.map +1 -1
  16. package/packages/core/dist/advanced.d.cts +18 -10
  17. package/packages/core/dist/advanced.d.ts +18 -10
  18. package/packages/core/dist/advanced.mjs +7 -6
  19. package/packages/core/dist/advanced.mjs.map +1 -1
  20. package/packages/core/dist/checks.cjs +221 -22
  21. package/packages/core/dist/checks.cjs.map +1 -1
  22. package/packages/core/dist/checks.d.cts +18 -8
  23. package/packages/core/dist/checks.d.ts +18 -8
  24. package/packages/core/dist/checks.mjs +2 -1
  25. package/packages/core/dist/chunk-AK5EN4U2.mjs +174 -0
  26. package/packages/core/dist/chunk-AK5EN4U2.mjs.map +1 -0
  27. package/packages/core/dist/chunk-FWK3Q3OJ.mjs +56 -0
  28. package/packages/core/dist/chunk-FWK3Q3OJ.mjs.map +1 -0
  29. package/packages/core/dist/{chunk-CTA6XNDP.mjs → chunk-HT54OLPE.mjs} +54 -7
  30. package/packages/core/dist/chunk-HT54OLPE.mjs.map +1 -0
  31. package/packages/core/dist/{chunk-BS2QCAJX.mjs → chunk-NF4ZHNTC.mjs} +169 -25
  32. package/packages/core/dist/chunk-NF4ZHNTC.mjs.map +1 -0
  33. package/packages/core/dist/{chunk-UOPVGCOB.mjs → chunk-NXQF73EC.mjs} +3 -3
  34. package/packages/core/dist/{chunk-UOPVGCOB.mjs.map → chunk-NXQF73EC.mjs.map} +1 -1
  35. package/packages/core/dist/{chunk-LFWZEO2L.mjs → chunk-SGL4JGCD.mjs} +3 -3
  36. package/packages/core/dist/{chunk-LFWZEO2L.mjs.map → chunk-SGL4JGCD.mjs.map} +1 -1
  37. package/packages/core/dist/{context-BHAgRjOe.d.cts → context-Ca5yK8Cs.d.cts} +3 -3
  38. package/packages/core/dist/{context-Blyjb5my.d.ts → context-D6cS4XIL.d.ts} +3 -3
  39. package/packages/core/dist/diff.d.cts +3 -3
  40. package/packages/core/dist/diff.d.ts +3 -3
  41. package/packages/core/dist/exporters.d.cts +3 -3
  42. package/packages/core/dist/exporters.d.ts +3 -3
  43. package/packages/core/dist/exporters.mjs +1 -1
  44. package/packages/core/dist/index-B259NKkH.d.cts +102 -0
  45. package/packages/core/dist/index-B9ZGvUVL.d.ts +102 -0
  46. package/packages/core/dist/{index-Bu_vOjql.d.ts → index-BsCcOKxy.d.ts} +4 -4
  47. package/packages/core/dist/{index-CmXMS-MF.d.cts → index-Xk9X-yjY.d.cts} +4 -4
  48. package/packages/core/dist/index.d.cts +6 -6
  49. package/packages/core/dist/index.d.ts +6 -6
  50. package/packages/core/dist/{inspect-event-DVg84S4v.d.cts → inspect-event-DRthdZlf.d.cts} +9 -0
  51. package/packages/core/dist/{inspect-event-DVg84S4v.d.ts → inspect-event-DRthdZlf.d.ts} +9 -0
  52. package/packages/core/dist/{log-config-BG1WmWf2.d.cts → log-config-CFlIJHTf.d.cts} +1 -1
  53. package/packages/core/dist/{log-config-Ck0aT_Ou.d.ts → log-config-OZRfpHED.d.ts} +1 -1
  54. package/packages/core/dist/logs.cjs +95 -15
  55. package/packages/core/dist/logs.cjs.map +1 -1
  56. package/packages/core/dist/logs.d.cts +3 -3
  57. package/packages/core/dist/logs.d.ts +3 -3
  58. package/packages/core/dist/logs.mjs +2 -2
  59. package/packages/core/dist/{persisted-inspect-event-ChE7pGb7.d.ts → persisted-inspect-event-BVucFVrP.d.ts} +1 -1
  60. package/packages/core/dist/{persisted-inspect-event-d-mSP8kd.d.cts → persisted-inspect-event-CVZWZldL.d.cts} +1 -1
  61. package/packages/core/dist/persisted.cjs +95 -15
  62. package/packages/core/dist/persisted.cjs.map +1 -1
  63. package/packages/core/dist/persisted.d.cts +5 -5
  64. package/packages/core/dist/persisted.d.ts +5 -5
  65. package/packages/core/dist/persisted.mjs +3 -3
  66. package/packages/core/dist/readers.cjs +203 -18
  67. package/packages/core/dist/readers.cjs.map +1 -1
  68. package/packages/core/dist/readers.d.cts +27 -78
  69. package/packages/core/dist/readers.d.ts +27 -78
  70. package/packages/core/dist/readers.mjs +4 -3
  71. package/packages/core/dist/{types-MuwXSJ4b.d.ts → types--ainI31J.d.ts} +1 -1
  72. package/packages/core/dist/{types-BLX3tiOW.d.cts → types-UnrNaTo2.d.cts} +1 -1
  73. package/packages/core/dist/writers.d.cts +2 -2
  74. package/packages/core/dist/writers.d.ts +2 -2
  75. package/packages/cli/dist/chunk-MEO2Z3KE.mjs.map +0 -1
  76. package/packages/core/dist/chunk-BS2QCAJX.mjs.map +0 -1
  77. package/packages/core/dist/chunk-CTA6XNDP.mjs.map +0 -1
  78. package/packages/core/dist/chunk-T5MASTIW.mjs +0 -94
  79. package/packages/core/dist/chunk-T5MASTIW.mjs.map +0 -1
@@ -6354,6 +6354,136 @@ var init_resolve2 = __esm({
6354
6354
  }
6355
6355
  });
6356
6356
 
6357
+ // packages/core/src/diagnostics/programmatic.ts
6358
+ function formatProgrammaticDiagnostic(code, detail) {
6359
+ const spec = PROGRAMMATIC_DIAGNOSTIC_SPECS[code];
6360
+ const summary = detail?.trim() ? detail.trim() : spec.summary;
6361
+ return `${code}: ${summary} Remediation: ${spec.remediation}`;
6362
+ }
6363
+ var PROGRAMMATIC_DIAGNOSTIC_SPECS;
6364
+ var init_programmatic = __esm({
6365
+ "packages/core/src/diagnostics/programmatic.ts"() {
6366
+ PROGRAMMATIC_DIAGNOSTIC_SPECS = Object.freeze({
6367
+ AI_TRACE_INPUT_INVALID: {
6368
+ code: "AI_TRACE_INPUT_INVALID",
6369
+ summary: 'Expected { type: "file", path }, { type: "directory", path }, { type: "string", content }, { type: "buffer", content }, or { type: "stdin" }.',
6370
+ remediation: "For a file path, use openTraceFile(path).",
6371
+ relatedCodes: ["invalid_input"]
6372
+ },
6373
+ AI_TRACE_FORMAT_UNSUPPORTED: {
6374
+ code: "AI_TRACE_FORMAT_UNSUPPORTED",
6375
+ summary: "No trace reader could detect the input format.",
6376
+ remediation: "Pass an AgentInspect JSONL file via openTraceFile, or set options.format to a registered reader.",
6377
+ relatedCodes: ["unsupported_format"]
6378
+ },
6379
+ AI_TRACE_FORMAT_AMBIGUOUS: {
6380
+ code: "AI_TRACE_FORMAT_AMBIGUOUS",
6381
+ summary: "Multiple trace readers matched the input with equal confidence.",
6382
+ remediation: "Set options.format explicitly to disambiguate the reader.",
6383
+ relatedCodes: ["ambiguous_format"]
6384
+ },
6385
+ AI_TRACE_FACTS_INPUT_NOT_NORMALIZED: {
6386
+ code: "AI_TRACE_FACTS_INPUT_NOT_NORMALIZED",
6387
+ summary: "TraceFacts requires TraceReadResult or PersistedInspectEvent[].",
6388
+ remediation: "Use openTraceFile() to normalize a JSONL trace first."
6389
+ },
6390
+ AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED: {
6391
+ code: "AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED",
6392
+ summary: "Multiple runs are available; select a run before executing checks.",
6393
+ remediation: "Pass options.runId or TraceCheckInput.selectedRun.",
6394
+ relatedCodes: ["AI_CHECK_RUN_SELECTION_REQUIRED"]
6395
+ },
6396
+ AI_TRACE_RELATIONSHIP_SELF_PARENT: {
6397
+ code: "AI_TRACE_RELATIONSHIP_SELF_PARENT",
6398
+ summary: "A parentId equals its own event/step id.",
6399
+ remediation: "Reject at capture (AI_LANGGRAPH_SELF_PARENT_REJECTED) or drop via logical projection; do not invent replacement parents.",
6400
+ relatedCodes: [
6401
+ "AI_LANGGRAPH_SELF_PARENT_REJECTED",
6402
+ "AI_LOGICAL_SELF_PARENT_REMOVED"
6403
+ ]
6404
+ },
6405
+ AI_TRACE_RELATIONSHIP_CYCLE: {
6406
+ code: "AI_TRACE_RELATIONSHIP_CYCLE",
6407
+ summary: "Trace contains a parentId cycle.",
6408
+ remediation: "Use visibility-first tree linking for legacy fixtures; prefer acyclic capture for new adapter output.",
6409
+ relatedCodes: ["structure.cycle"]
6410
+ }
6411
+ });
6412
+ }
6413
+ });
6414
+
6415
+ // packages/core/src/safety/sensitive-key.ts
6416
+ function normalizeSensitiveKey(value) {
6417
+ return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
6418
+ }
6419
+ function isTokenCredentialKey(normalized) {
6420
+ if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
6421
+ if (normalized === "token") return true;
6422
+ if (normalized.endsWith("tokens")) return false;
6423
+ return normalized.endsWith("token");
6424
+ }
6425
+ function isCredentialSensitiveKey(key, sensitiveKeys = DEFAULT_CREDENTIAL_SENSITIVE_KEYS) {
6426
+ if (!key) return false;
6427
+ const normalized = normalizeSensitiveKey(key);
6428
+ if (!normalized) return false;
6429
+ if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS.has(normalized)) return false;
6430
+ for (const sensitive of sensitiveKeys) {
6431
+ const s = normalizeSensitiveKey(sensitive);
6432
+ if (!s) continue;
6433
+ if (s === "token") {
6434
+ if (isTokenCredentialKey(normalized)) return true;
6435
+ continue;
6436
+ }
6437
+ if (normalized === s) return true;
6438
+ if (normalized.endsWith(`_${s}`) || normalized.startsWith(`${s}_`)) return true;
6439
+ }
6440
+ return false;
6441
+ }
6442
+ var NON_CREDENTIAL_TOKEN_CONFIG_KEYS, DEFAULT_CREDENTIAL_SENSITIVE_KEYS;
6443
+ var init_sensitive_key = __esm({
6444
+ "packages/core/src/safety/sensitive-key.ts"() {
6445
+ NON_CREDENTIAL_TOKEN_CONFIG_KEYS = new Set(
6446
+ [
6447
+ "tokens",
6448
+ "max_tokens",
6449
+ "min_tokens",
6450
+ "ls_max_tokens",
6451
+ "token_count",
6452
+ "token_limit",
6453
+ "token_budget",
6454
+ "input_tokens",
6455
+ "output_tokens",
6456
+ "total_tokens",
6457
+ "cached_tokens",
6458
+ "prompt_tokens",
6459
+ "completion_tokens"
6460
+ ].map(normalizeSensitiveKey)
6461
+ );
6462
+ DEFAULT_CREDENTIAL_SENSITIVE_KEYS = [
6463
+ "authorization",
6464
+ "cookie",
6465
+ "token",
6466
+ "access_token",
6467
+ "accesstoken",
6468
+ "auth_token",
6469
+ "authtoken",
6470
+ "refresh_token",
6471
+ "refreshtoken",
6472
+ "id_token",
6473
+ "idtoken",
6474
+ "bearer_token",
6475
+ "bearertoken",
6476
+ "api_token",
6477
+ "apitoken",
6478
+ "apikey",
6479
+ "api_key",
6480
+ "password",
6481
+ "secret",
6482
+ "email"
6483
+ ];
6484
+ }
6485
+ });
6486
+
6357
6487
  // packages/core/src/checks/logical-events.ts
6358
6488
  function isRecord7(value) {
6359
6489
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -6549,6 +6679,26 @@ function projectLogicalEvents(events) {
6549
6679
  }
6550
6680
  }
6551
6681
  if (!remapped) {
6682
+ if (originalParentId === event.eventId) {
6683
+ diagnostics.push({
6684
+ code: "AI_LOGICAL_SELF_PARENT_REMOVED",
6685
+ message: formatProgrammaticDiagnostic(
6686
+ "AI_TRACE_RELATIONSHIP_SELF_PARENT",
6687
+ `Removed self-parent edge on ${event.eventId}.`
6688
+ ),
6689
+ eventIds: [event.eventId]
6690
+ });
6691
+ const { parentId: _drop, ...rest } = event;
6692
+ normalized.push({
6693
+ ...rest,
6694
+ projection: {
6695
+ ...event.projection,
6696
+ parentNormalized: true,
6697
+ originalParentId
6698
+ }
6699
+ });
6700
+ continue;
6701
+ }
6552
6702
  if (!logicalById.has(originalParentId) && !logicalByRawId.has(originalParentId)) {
6553
6703
  const mapping = event.attributes?.parentMapping;
6554
6704
  const unresolved = mapping === "unresolved" || event.attributes?.parentUnresolved === true || event.attributes?.unresolvedParent === true || // LangGraph/framework scaffolding sentinel labels are not event ids.
@@ -6564,6 +6714,26 @@ function projectLogicalEvents(events) {
6564
6714
  normalized.push(event);
6565
6715
  continue;
6566
6716
  }
6717
+ if (nextParent === event.eventId) {
6718
+ diagnostics.push({
6719
+ code: "AI_LOGICAL_SELF_PARENT_REMOVED",
6720
+ message: formatProgrammaticDiagnostic(
6721
+ "AI_TRACE_RELATIONSHIP_SELF_PARENT",
6722
+ `Removed self-parent edge on ${event.eventId} (was ${originalParentId}).`
6723
+ ),
6724
+ eventIds: [event.eventId]
6725
+ });
6726
+ const { parentId: _drop, ...rest } = event;
6727
+ normalized.push({
6728
+ ...rest,
6729
+ projection: {
6730
+ ...event.projection,
6731
+ parentNormalized: true,
6732
+ originalParentId
6733
+ }
6734
+ });
6735
+ continue;
6736
+ }
6567
6737
  diagnostics.push({
6568
6738
  code: "AI_LOGICAL_PARENT_REMAPPED",
6569
6739
  message: `Remapped parent ${originalParentId} \u2192 ${nextParent} for ${event.eventId}.`,
@@ -6614,6 +6784,7 @@ function pickString(record, keys) {
6614
6784
  }
6615
6785
  var init_logical_events = __esm({
6616
6786
  "packages/core/src/checks/logical-events.ts"() {
6787
+ init_programmatic();
6617
6788
  }
6618
6789
  });
6619
6790
 
@@ -6642,7 +6813,11 @@ function summarizeSemanticParity(events) {
6642
6813
  }
6643
6814
  var init_trace_facts = __esm({
6644
6815
  "packages/core/src/checks/trace-facts.ts"() {
6816
+ init_programmatic();
6645
6817
  init_logical_events();
6818
+ formatProgrammaticDiagnostic(
6819
+ "AI_TRACE_FACTS_INPUT_NOT_NORMALIZED"
6820
+ );
6646
6821
  }
6647
6822
  });
6648
6823
 
@@ -6753,7 +6928,13 @@ function resolveSelectedRun(input3, runId) {
6753
6928
  if (input3.read.runs.length === 0) {
6754
6929
  return {
6755
6930
  diagnostics: [
6756
- diagnostic3("AI_CHECK_RUN_SELECTION_REQUIRED", "No runs are available for checks.")
6931
+ diagnostic3(
6932
+ "AI_CHECK_RUN_SELECTION_REQUIRED",
6933
+ formatProgrammaticDiagnostic(
6934
+ "AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED",
6935
+ "No runs are available for checks."
6936
+ )
6937
+ )
6757
6938
  ]
6758
6939
  };
6759
6940
  }
@@ -6761,7 +6942,7 @@ function resolveSelectedRun(input3, runId) {
6761
6942
  diagnostics: [
6762
6943
  diagnostic3(
6763
6944
  "AI_CHECK_RUN_SELECTION_REQUIRED",
6764
- "Multiple runs are available; select a run before executing checks."
6945
+ formatProgrammaticDiagnostic("AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED")
6765
6946
  )
6766
6947
  ]
6767
6948
  };
@@ -7017,9 +7198,7 @@ function hasRedactionMarker(value, markers) {
7017
7198
  return markers.some((marker) => value.includes(marker)) || /^\[HASH:[A-Za-z0-9_-]+\]$/.test(value);
7018
7199
  }
7019
7200
  function isSensitiveKey(key, sensitiveKeys) {
7020
- if (!key) return false;
7021
- const normalized = normalizedKey(key);
7022
- return sensitiveKeys.some((sensitive) => normalized.includes(normalizedKey(sensitive)));
7201
+ return isCredentialSensitiveKey(key, sensitiveKeys);
7023
7202
  }
7024
7203
  function isRawContentKey(key, forbiddenKeys) {
7025
7204
  if (!key) return false;
@@ -7342,7 +7521,7 @@ function createToolUsageRule(options) {
7342
7521
  }
7343
7522
  }
7344
7523
  const forbidden = new Set(options.forbidden ?? []);
7345
- const allowed = options.allowed ? new Set(options.allowed) : void 0;
7524
+ const allowed = options.allowed?.length ? new Set(options.allowed) : void 0;
7346
7525
  for (const event of tools) {
7347
7526
  const name = toolName(event);
7348
7527
  if (forbidden.has(name)) {
@@ -7378,9 +7557,9 @@ function createLlmUsageRule(options) {
7378
7557
  evaluate(context) {
7379
7558
  const llms = finishedEvents(context, "LLM");
7380
7559
  const findings = [];
7381
- const allowedModels = options.allowedModels ? new Set(options.allowedModels) : void 0;
7382
- const allowedProviders = options.allowedProviders ? new Set(options.allowedProviders) : void 0;
7383
- const finishReasons = options.finishReasons ? new Set(options.finishReasons) : void 0;
7560
+ const allowedModels = options.allowedModels?.length ? new Set(options.allowedModels) : void 0;
7561
+ const allowedProviders = options.allowedProviders?.length ? new Set(options.allowedProviders) : void 0;
7562
+ const finishReasons = options.finishReasons?.length ? new Set(options.finishReasons) : void 0;
7384
7563
  if (options.maxCalls !== void 0 && llms.length > options.maxCalls) {
7385
7564
  findings.push(
7386
7565
  failFinding(
@@ -7492,7 +7671,7 @@ function createStructureCycleRule() {
7492
7671
  findings.push(
7493
7672
  failFinding(
7494
7673
  "structure.cycle",
7495
- "Trace contains a parentId cycle.",
7674
+ formatProgrammaticDiagnostic("AI_TRACE_RELATIONSHIP_CYCLE"),
7496
7675
  cycle.map((item) => eventEvidence(item, "parentId")),
7497
7676
  "acyclic parentId graph",
7498
7677
  cycle.map((item) => item.eventId).sort()
@@ -8059,10 +8238,14 @@ function runTraceChecks(input3, options = {}) {
8059
8238
  var SEVERITY_RANK, STATUS_RANK, CONFIDENCE_RANK, DEFAULT_SENSITIVE_KEYS, DEFAULT_RAW_CONTENT_KEYS, DEFAULT_SAFE_RAW_CONTENT_PATH_PREFIXES, SAFE_USAGE_LEAF_KEYS, DEFAULT_SECRET_PATTERNS;
8060
8239
  var init_checks2 = __esm({
8061
8240
  "packages/core/src/checks/index.ts"() {
8241
+ init_programmatic();
8062
8242
  init_outcomes();
8243
+ init_sensitive_key();
8063
8244
  init_logical_events();
8064
8245
  init_logical_events();
8065
8246
  init_trace_facts();
8247
+ init_programmatic();
8248
+ init_sensitive_key();
8066
8249
  init_contract();
8067
8250
  SEVERITY_RANK = {
8068
8251
  error: 0,
@@ -8080,16 +8263,7 @@ var init_checks2 = __esm({
8080
8263
  correlated: 2,
8081
8264
  explicit: 3
8082
8265
  };
8083
- DEFAULT_SENSITIVE_KEYS = [
8084
- "authorization",
8085
- "cookie",
8086
- "token",
8087
- "apikey",
8088
- "api_key",
8089
- "password",
8090
- "secret",
8091
- "email"
8092
- ];
8266
+ DEFAULT_SENSITIVE_KEYS = DEFAULT_CREDENTIAL_SENSITIVE_KEYS;
8093
8267
  DEFAULT_RAW_CONTENT_KEYS = [
8094
8268
  "body",
8095
8269
  "headers",
@@ -8434,6 +8608,20 @@ var init_from_trace_event = __esm({
8434
8608
  function inc(map, key) {
8435
8609
  map[key] = (map[key] ?? 0) + 1;
8436
8610
  }
8611
+ function confidenceRank(confidence) {
8612
+ switch (confidence) {
8613
+ case "unknown":
8614
+ return 0;
8615
+ case "heuristic":
8616
+ return 1;
8617
+ case "correlated":
8618
+ return 2;
8619
+ case "explicit":
8620
+ return 3;
8621
+ default:
8622
+ return 0;
8623
+ }
8624
+ }
8437
8625
  function computeRunStatus(events) {
8438
8626
  let runTerminal;
8439
8627
  let sawRunEvent = false;
@@ -8454,6 +8642,84 @@ function computeRunStatus(events) {
8454
8642
  }
8455
8643
  return hasRunning ? "running" : "ok";
8456
8644
  }
8645
+ function linkNodesVisibilityFirst(nodes) {
8646
+ let selfParentCount = 0;
8647
+ let unresolvedParentCount = 0;
8648
+ let normalizedEdgeCount = 0;
8649
+ let cycleCount = 0;
8650
+ const pending = [];
8651
+ for (const node of nodes.values()) {
8652
+ const parentId = node.event.parentId;
8653
+ if (!parentId) continue;
8654
+ if (parentId === node.event.eventId) {
8655
+ selfParentCount += 1;
8656
+ normalizedEdgeCount += 1;
8657
+ continue;
8658
+ }
8659
+ if (!nodes.has(parentId)) {
8660
+ unresolvedParentCount += 1;
8661
+ continue;
8662
+ }
8663
+ pending.push({
8664
+ childId: node.event.eventId,
8665
+ parentId,
8666
+ childTimestamp: node.event.timestamp,
8667
+ childConfidence: node.event.confidence
8668
+ });
8669
+ }
8670
+ pending.sort((a, b) => {
8671
+ const conf = confidenceRank(b.childConfidence) - confidenceRank(a.childConfidence);
8672
+ if (conf !== 0) return conf;
8673
+ return a.childTimestamp - b.childTimestamp;
8674
+ });
8675
+ const parentOf = /* @__PURE__ */ new Map();
8676
+ for (const edge of pending) {
8677
+ parentOf.set(edge.childId, edge.parentId);
8678
+ let cursor = edge.parentId;
8679
+ const seen = /* @__PURE__ */ new Set([edge.childId]);
8680
+ let cyclic = false;
8681
+ while (cursor) {
8682
+ if (seen.has(cursor)) {
8683
+ cyclic = true;
8684
+ break;
8685
+ }
8686
+ seen.add(cursor);
8687
+ cursor = parentOf.get(cursor);
8688
+ }
8689
+ if (cyclic) {
8690
+ parentOf.delete(edge.childId);
8691
+ cycleCount += 1;
8692
+ normalizedEdgeCount += 1;
8693
+ }
8694
+ }
8695
+ for (const [childId, parentId] of parentOf) {
8696
+ nodes.get(parentId).children.push(nodes.get(childId));
8697
+ }
8698
+ const roots = [];
8699
+ for (const node of nodes.values()) {
8700
+ if (!parentOf.has(node.event.eventId)) {
8701
+ roots.push(node);
8702
+ }
8703
+ }
8704
+ const assignDepth = (n, depth, stack) => {
8705
+ if (stack.has(n.event.eventId)) return;
8706
+ n.depth = depth;
8707
+ stack.add(n.event.eventId);
8708
+ for (const c of n.children) assignDepth(c, depth + 1, stack);
8709
+ stack.delete(n.event.eventId);
8710
+ };
8711
+ for (const r of roots) assignDepth(r, 0, /* @__PURE__ */ new Set());
8712
+ return {
8713
+ roots,
8714
+ summary: {
8715
+ rootCount: roots.length,
8716
+ selfParentCount,
8717
+ cycleCount,
8718
+ unresolvedParentCount,
8719
+ normalizedEdgeCount
8720
+ }
8721
+ };
8722
+ }
8457
8723
  var TreeBuilder;
8458
8724
  var init_tree_builder = __esm({
8459
8725
  "packages/core/src/logs/tree-builder.ts"() {
@@ -8474,20 +8740,7 @@ var init_tree_builder = __esm({
8474
8740
  for (const e of sorted) {
8475
8741
  nodes.set(e.eventId, { event: e, children: [], depth: 0 });
8476
8742
  }
8477
- const roots = [];
8478
- for (const node of nodes.values()) {
8479
- const parentId = node.event.parentId;
8480
- if (parentId && nodes.has(parentId)) {
8481
- nodes.get(parentId).children.push(node);
8482
- } else {
8483
- roots.push(node);
8484
- }
8485
- }
8486
- const assignDepth = (n, depth) => {
8487
- n.depth = depth;
8488
- for (const c of n.children) assignDepth(c, depth + 1);
8489
- };
8490
- for (const r of roots) assignDepth(r, 0);
8743
+ const { roots, summary } = linkNodesVisibilityFirst(nodes);
8491
8744
  const confidenceBreakdown = {
8492
8745
  explicit: 0,
8493
8746
  correlated: 0,
@@ -8515,7 +8768,8 @@ var init_tree_builder = __esm({
8515
8768
  metadata: {
8516
8769
  totalEvents: sorted.length,
8517
8770
  confidenceBreakdown,
8518
- kinds
8771
+ kinds,
8772
+ relationshipSummary: summary
8519
8773
  }
8520
8774
  });
8521
8775
  }
@@ -8683,6 +8937,35 @@ var init_tree_bridge = __esm({
8683
8937
  init_to_inspect_event();
8684
8938
  }
8685
8939
  });
8940
+ function isTraceInput(input3) {
8941
+ if (typeof input3 !== "object" || input3 === null || Array.isArray(input3)) {
8942
+ return false;
8943
+ }
8944
+ const record = input3;
8945
+ switch (record.type) {
8946
+ case "file":
8947
+ case "directory":
8948
+ return typeof record.path === "string";
8949
+ case "string":
8950
+ return typeof record.content === "string";
8951
+ case "buffer":
8952
+ return Buffer.isBuffer(record.content);
8953
+ case "stdin":
8954
+ return true;
8955
+ default:
8956
+ return false;
8957
+ }
8958
+ }
8959
+ function assertTraceInput(input3) {
8960
+ if (isTraceInput(input3)) return;
8961
+ throw new TraceReadError("invalid_input", TRACE_INPUT_INVALID_MESSAGE, [
8962
+ {
8963
+ code: "AI_TRACE_INPUT_INVALID",
8964
+ message: TRACE_INPUT_INVALID_MESSAGE,
8965
+ severity: "error"
8966
+ }
8967
+ ]);
8968
+ }
8686
8969
  function normalizeCandidate(reader, candidate) {
8687
8970
  const confidence = Number.isFinite(candidate.confidence) ? Math.max(0, Math.min(1, candidate.confidence)) : 0;
8688
8971
  return {
@@ -9829,6 +10112,7 @@ function mapOtlpEventsToPersisted(document) {
9829
10112
  };
9830
10113
  }
9831
10114
  async function detectTraceFormat(input3, options = {}) {
10115
+ assertTraceInput(input3);
9832
10116
  const readers = options.readers ?? DEFAULT_TRACE_READERS;
9833
10117
  if (options.format !== void 0) {
9834
10118
  const reader = findReaderByFormat(options.format, readers);
@@ -9925,19 +10209,20 @@ async function detectTraceFormat(input3, options = {}) {
9925
10209
  };
9926
10210
  }
9927
10211
  async function readTrace(input3, options = {}) {
10212
+ assertTraceInput(input3);
9928
10213
  const readers = options.readers ?? DEFAULT_TRACE_READERS;
9929
10214
  const detection = await detectTraceFormat(input3, options);
9930
10215
  if (detection.status === "unsupported" || detection.format === void 0) {
9931
10216
  throw new TraceReadError(
9932
10217
  "unsupported_format",
9933
- "No trace reader could detect the input format.",
10218
+ formatProgrammaticDiagnostic("AI_TRACE_FORMAT_UNSUPPORTED"),
9934
10219
  detection.warnings
9935
10220
  );
9936
10221
  }
9937
10222
  if (detection.status === "ambiguous") {
9938
10223
  throw new TraceReadError(
9939
10224
  "ambiguous_format",
9940
- "Multiple trace readers matched the input with equal confidence.",
10225
+ formatProgrammaticDiagnostic("AI_TRACE_FORMAT_AMBIGUOUS"),
9941
10226
  detection.warnings
9942
10227
  );
9943
10228
  }
@@ -9945,7 +10230,10 @@ async function readTrace(input3, options = {}) {
9945
10230
  if (!reader) {
9946
10231
  throw new TraceReadError(
9947
10232
  "unsupported_format",
9948
- `No trace reader is registered for format "${detection.format}".`,
10233
+ formatProgrammaticDiagnostic(
10234
+ "AI_TRACE_FORMAT_UNSUPPORTED",
10235
+ `No trace reader is registered for format "${detection.format}".`
10236
+ ),
9949
10237
  detection.warnings
9950
10238
  );
9951
10239
  }
@@ -9974,12 +10262,13 @@ async function readTrace(input3, options = {}) {
9974
10262
  function openTrace(input3, options = {}) {
9975
10263
  return readTrace(input3, options);
9976
10264
  }
9977
- var DEFAULT_MAX_TRACE_INPUT_BYTES, MIN_DETECTION_CONFIDENCE, AMBIGUOUS_CONFIDENCE_DELTA, resolvedInputCache, OPENINFERENCE_READER_FORMAT, OTLP_READER_FORMAT, OPENINFERENCE_SPAN_KEYS, OPENINFERENCE_SENSITIVE_ATTRIBUTE_KEYS, OTLP_SPAN_KEYS, TraceReadError, openInferenceJsonReader, otlpJsonReader, agentInspectJsonlReader, DEFAULT_TRACE_READERS;
10265
+ var DEFAULT_MAX_TRACE_INPUT_BYTES, MIN_DETECTION_CONFIDENCE, AMBIGUOUS_CONFIDENCE_DELTA, resolvedInputCache, OPENINFERENCE_READER_FORMAT, OTLP_READER_FORMAT, OPENINFERENCE_SPAN_KEYS, OPENINFERENCE_SENSITIVE_ATTRIBUTE_KEYS, OTLP_SPAN_KEYS, TraceReadError, TRACE_INPUT_INVALID_MESSAGE, openInferenceJsonReader, otlpJsonReader, agentInspectJsonlReader, DEFAULT_TRACE_READERS;
9978
10266
  var init_readers = __esm({
9979
10267
  "packages/core/src/readers/index.ts"() {
9980
10268
  init_read_trace();
9981
10269
  init_from_trace_event();
9982
10270
  init_tree_bridge();
10271
+ init_programmatic();
9983
10272
  DEFAULT_MAX_TRACE_INPUT_BYTES = 10 * 1024 * 1024;
9984
10273
  MIN_DETECTION_CONFIDENCE = 0.5;
9985
10274
  AMBIGUOUS_CONFIDENCE_DELTA = 0.05;
@@ -10053,6 +10342,9 @@ var init_readers = __esm({
10053
10342
  this.warnings = warnings;
10054
10343
  }
10055
10344
  };
10345
+ TRACE_INPUT_INVALID_MESSAGE = formatProgrammaticDiagnostic(
10346
+ "AI_TRACE_INPUT_INVALID"
10347
+ );
10056
10348
  openInferenceJsonReader = {
10057
10349
  format: OPENINFERENCE_READER_FORMAT,
10058
10350
  name: "OpenInference JSON",
@@ -12193,7 +12485,7 @@ var init_src = __esm({
12193
12485
  });
12194
12486
 
12195
12487
  // package.json
12196
- var version = "6.14.1";
12488
+ var version = "6.15.0";
12197
12489
 
12198
12490
  // packages/cli/src/list.ts
12199
12491
  init_advanced();
@@ -12523,6 +12815,7 @@ init_tree_bridge();
12523
12815
 
12524
12816
  // packages/core/src/entries/readers.ts
12525
12817
  init_readers();
12818
+ init_programmatic();
12526
12819
 
12527
12820
  // packages/cli/src/read-run.ts
12528
12821
  function mapReaderFormat(format) {
@@ -15540,7 +15833,7 @@ async function searchCommand(options = {}) {
15540
15833
  }
15541
15834
  console.log(`Search results (${results.length})`);
15542
15835
  for (const r of results) {
15543
- const step = r.stepName !== void 0 ? ` | ${r.stepType ?? "step"}:${r.stepName}` : "";
15836
+ const step = r.stepName !== void 0 ? ` | ${formatStepLabel(r.stepType ?? "step", r.stepName)}` : "";
15544
15837
  const dur = r.durationMs !== void 0 ? ` | ${r.durationMs}ms` : "";
15545
15838
  console.log(
15546
15839
  `${r.runId}${step} | ${r.runStatus}${dur} | ${r.matchReason}`
@@ -16083,6 +16376,53 @@ async function reportCommand(runId, options = {}) {
16083
16376
 
16084
16377
  // packages/cli/src/redact.ts
16085
16378
  init_advanced();
16379
+
16380
+ // packages/redact/src/sensitive-key.ts
16381
+ function normalizeSensitiveKey2(value) {
16382
+ return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
16383
+ }
16384
+ var NON_CREDENTIAL_TOKEN_CONFIG_KEYS2 = new Set(
16385
+ [
16386
+ "tokens",
16387
+ "max_tokens",
16388
+ "min_tokens",
16389
+ "ls_max_tokens",
16390
+ "token_count",
16391
+ "token_limit",
16392
+ "token_budget",
16393
+ "input_tokens",
16394
+ "output_tokens",
16395
+ "total_tokens",
16396
+ "cached_tokens",
16397
+ "prompt_tokens",
16398
+ "completion_tokens"
16399
+ ].map(normalizeSensitiveKey2)
16400
+ );
16401
+ function isTokenCredentialKey2(normalized) {
16402
+ if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS2.has(normalized)) return false;
16403
+ if (normalized === "token") return true;
16404
+ if (normalized.endsWith("tokens")) return false;
16405
+ return normalized.endsWith("token");
16406
+ }
16407
+ function isCredentialSensitiveKey2(key, sensitiveKeys) {
16408
+ if (!key) return false;
16409
+ const normalized = normalizeSensitiveKey2(key);
16410
+ if (!normalized) return false;
16411
+ if (NON_CREDENTIAL_TOKEN_CONFIG_KEYS2.has(normalized)) return false;
16412
+ for (const sensitive of sensitiveKeys) {
16413
+ const s = normalizeSensitiveKey2(sensitive);
16414
+ if (!s) continue;
16415
+ if (s === "token") {
16416
+ if (isTokenCredentialKey2(normalized)) return true;
16417
+ continue;
16418
+ }
16419
+ if (normalized === s) return true;
16420
+ if (normalized.endsWith(`_${s}`) || normalized.startsWith(`${s}_`)) return true;
16421
+ }
16422
+ return false;
16423
+ }
16424
+
16425
+ // packages/redact/src/index.ts
16086
16426
  var DEFAULT_REDACT_KEYS2 = [
16087
16427
  "authorization",
16088
16428
  "cookie",
@@ -16144,6 +16484,12 @@ function isRecord15(value) {
16144
16484
  function toKey2(key) {
16145
16485
  return key.toLowerCase();
16146
16486
  }
16487
+ function findCompiledKeyRule(key, rules) {
16488
+ const exact = toKey2(key);
16489
+ const direct = rules.find((candidate) => candidate.key === exact);
16490
+ if (direct) return direct;
16491
+ return rules.find((candidate) => isCredentialSensitiveKey2(key, [candidate.key]));
16492
+ }
16147
16493
  function stableHash2(value) {
16148
16494
  const hash = crypto__default.default.createHash("sha256").update(value, "utf8").digest("hex");
16149
16495
  return hash.slice(0, 8);
@@ -16465,7 +16811,7 @@ var Redactor2 = class {
16465
16811
  return "[Truncated]";
16466
16812
  }
16467
16813
  if (key !== void 0) {
16468
- const rule = this.#rules.find((candidate) => candidate.key === toKey2(key));
16814
+ const rule = findCompiledKeyRule(key, this.#rules);
16469
16815
  if (rule) {
16470
16816
  this.#recordFinding(
16471
16817
  state,