agent-inspect 4.3.0 → 4.4.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 (97) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/docs/API.md +3 -0
  3. package/docs/CLI.md +3 -0
  4. package/docs/SCHEMA.md +27 -1
  5. package/package.json +1 -1
  6. package/packages/cli/dist/{chunk-BS5LSKZ3.mjs → chunk-ORHDQUT6.mjs} +198 -7
  7. package/packages/cli/dist/chunk-ORHDQUT6.mjs.map +1 -0
  8. package/packages/cli/dist/index.cjs +409 -17
  9. package/packages/cli/dist/index.cjs.map +1 -1
  10. package/packages/cli/dist/index.mjs +176 -10
  11. package/packages/cli/dist/index.mjs.map +1 -1
  12. package/packages/cli/dist/{src-YFMPWEIS.mjs → src-FJOHPC4X.mjs} +3 -3
  13. package/packages/cli/dist/{src-YFMPWEIS.mjs.map → src-FJOHPC4X.mjs.map} +1 -1
  14. package/packages/core/dist/advanced.cjs +201 -9
  15. package/packages/core/dist/advanced.cjs.map +1 -1
  16. package/packages/core/dist/advanced.d.cts +12 -8
  17. package/packages/core/dist/advanced.d.ts +12 -8
  18. package/packages/core/dist/advanced.mjs +30 -13
  19. package/packages/core/dist/advanced.mjs.map +1 -1
  20. package/packages/core/dist/checks.cjs +117 -18
  21. package/packages/core/dist/checks.cjs.map +1 -1
  22. package/packages/core/dist/checks.d.cts +11 -3
  23. package/packages/core/dist/checks.d.ts +11 -3
  24. package/packages/core/dist/checks.mjs +42 -1
  25. package/packages/core/dist/checks.mjs.map +1 -1
  26. package/packages/core/dist/{chunk-2ZXEMWGK.mjs → chunk-3USJVBLA.mjs} +3 -3
  27. package/packages/core/dist/{chunk-2ZXEMWGK.mjs.map → chunk-3USJVBLA.mjs.map} +1 -1
  28. package/packages/core/dist/{chunk-HY7H3CQM.mjs → chunk-CAWPF22J.mjs} +4 -3
  29. package/packages/core/dist/chunk-CAWPF22J.mjs.map +1 -0
  30. package/packages/core/dist/{chunk-XUNJMAPD.mjs → chunk-KNYL56KZ.mjs} +38 -3
  31. package/packages/core/dist/chunk-KNYL56KZ.mjs.map +1 -0
  32. package/packages/core/dist/{chunk-IZBJAZGF.mjs → chunk-P366CCL2.mjs} +34 -3
  33. package/packages/core/dist/chunk-P366CCL2.mjs.map +1 -0
  34. package/packages/core/dist/{chunk-4JVGFNQH.mjs → chunk-ULCGIRTC.mjs} +95 -8
  35. package/packages/core/dist/chunk-ULCGIRTC.mjs.map +1 -0
  36. package/packages/core/dist/chunk-VFO76UH3.mjs +228 -0
  37. package/packages/core/dist/chunk-VFO76UH3.mjs.map +1 -0
  38. package/packages/core/dist/{chunk-NQZPZ2FN.mjs → chunk-WRE4CNPF.mjs} +6 -3
  39. package/packages/core/dist/chunk-WRE4CNPF.mjs.map +1 -0
  40. package/packages/core/dist/{chunk-A4V2H3YU.mjs → chunk-ZWA5RWMV.mjs} +40 -4
  41. package/packages/core/dist/chunk-ZWA5RWMV.mjs.map +1 -0
  42. package/packages/core/dist/{context-DjY-jvQk.d.cts → context-BbfkMYjz.d.cts} +5 -3
  43. package/packages/core/dist/{context-BDZmi53V.d.ts → context-Cp8NRbBX.d.ts} +5 -3
  44. package/packages/core/dist/diff.cjs.map +1 -1
  45. package/packages/core/dist/diff.d.cts +3 -3
  46. package/packages/core/dist/diff.d.ts +3 -3
  47. package/packages/core/dist/diff.mjs +1 -1
  48. package/packages/core/dist/exporters.cjs +137 -1
  49. package/packages/core/dist/exporters.cjs.map +1 -1
  50. package/packages/core/dist/exporters.d.cts +6 -3
  51. package/packages/core/dist/exporters.d.ts +6 -3
  52. package/packages/core/dist/exporters.mjs +71 -6
  53. package/packages/core/dist/exporters.mjs.map +1 -1
  54. package/packages/core/dist/index.cjs +181 -6
  55. package/packages/core/dist/index.cjs.map +1 -1
  56. package/packages/core/dist/index.d.cts +14 -7
  57. package/packages/core/dist/index.d.ts +14 -7
  58. package/packages/core/dist/index.mjs +51 -7
  59. package/packages/core/dist/index.mjs.map +1 -1
  60. package/packages/core/dist/{inspect-event-CYAV7Hxm.d.cts → inspect-event-IqwOHbGo.d.cts} +1 -1
  61. package/packages/core/dist/{inspect-event-CYAV7Hxm.d.ts → inspect-event-IqwOHbGo.d.ts} +1 -1
  62. package/packages/core/dist/{log-config-BNQ9UTmP.d.cts → log-config-CW8w5YQ9.d.cts} +1 -1
  63. package/packages/core/dist/{log-config-D3Yp1SZN.d.ts → log-config-SRA4xTp8.d.ts} +1 -1
  64. package/packages/core/dist/logs.d.cts +3 -3
  65. package/packages/core/dist/logs.d.ts +3 -3
  66. package/packages/core/dist/{persisted-inspect-event-BLvb0jSX.d.ts → persisted-inspect-event-DruwqARZ.d.ts} +1 -1
  67. package/packages/core/dist/{persisted-inspect-event-D5SjBz9b.d.cts → persisted-inspect-event-Gd-W8vB7.d.cts} +1 -1
  68. package/packages/core/dist/persisted.cjs +67 -1
  69. package/packages/core/dist/persisted.cjs.map +1 -1
  70. package/packages/core/dist/persisted.d.cts +5 -5
  71. package/packages/core/dist/persisted.d.ts +5 -5
  72. package/packages/core/dist/persisted.mjs +3 -3
  73. package/packages/core/dist/readers.cjs +72 -3
  74. package/packages/core/dist/readers.cjs.map +1 -1
  75. package/packages/core/dist/readers.d.cts +2 -2
  76. package/packages/core/dist/readers.d.ts +2 -2
  77. package/packages/core/dist/readers.mjs +5 -5
  78. package/packages/core/dist/readers.mjs.map +1 -1
  79. package/packages/core/dist/{types-CQun9LW6.d.ts → types-B1X87dUW.d.cts} +16 -2
  80. package/packages/core/dist/{types-C-llnPH0.d.cts → types-BVkjSd0q.d.ts} +16 -2
  81. package/packages/core/dist/types-CvsKGweN.d.cts +12 -0
  82. package/packages/core/dist/types-CvsKGweN.d.ts +12 -0
  83. package/packages/core/dist/writers.cjs +2 -1
  84. package/packages/core/dist/writers.cjs.map +1 -1
  85. package/packages/core/dist/writers.d.cts +2 -2
  86. package/packages/core/dist/writers.d.ts +2 -2
  87. package/packages/core/dist/writers.mjs +3 -4
  88. package/packages/core/dist/writers.mjs.map +1 -1
  89. package/packages/cli/dist/chunk-BS5LSKZ3.mjs.map +0 -1
  90. package/packages/core/dist/chunk-4JVGFNQH.mjs.map +0 -1
  91. package/packages/core/dist/chunk-A4V2H3YU.mjs.map +0 -1
  92. package/packages/core/dist/chunk-EDTQHZPM.mjs +0 -88
  93. package/packages/core/dist/chunk-EDTQHZPM.mjs.map +0 -1
  94. package/packages/core/dist/chunk-HY7H3CQM.mjs.map +0 -1
  95. package/packages/core/dist/chunk-IZBJAZGF.mjs.map +0 -1
  96. package/packages/core/dist/chunk-NQZPZ2FN.mjs.map +0 -1
  97. package/packages/core/dist/chunk-XUNJMAPD.mjs.map +0 -1
@@ -306,6 +306,9 @@ function isTraceEvent(value) {
306
306
  case "step_completed": {
307
307
  return typeof value.runId === "string" && typeof value.stepId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
308
308
  }
309
+ case "outcome_observed": {
310
+ return typeof value.runId === "string" && typeof value.outcomeId === "string" && typeof value.name === "string" && typeof value.expectation === "string" && (value.status === "passed" || value.status === "failed" || value.status === "unknown" || value.status === "skipped") && typeof value.observedAt === "number";
311
+ }
309
312
  default:
310
313
  return false;
311
314
  }
@@ -436,7 +439,8 @@ var init_persisted_inspect_event = __esm({
436
439
  "RESULT",
437
440
  "ERROR",
438
441
  "LOGIC",
439
- "LOG"
442
+ "LOG",
443
+ "OUTCOME"
440
444
  ];
441
445
  ATTRIBUTION_CONFIDENCES = [
442
446
  "explicit",
@@ -634,6 +638,32 @@ function fromLegacyStepCompleted(event) {
634
638
  if (error) out.error = error;
635
639
  return out;
636
640
  }
641
+ function fromLegacyOutcomeObserved(event) {
642
+ const attrs = event.attributes ?? {};
643
+ const observedAtRaw = attrs.observedAt;
644
+ const observedAt = typeof observedAtRaw === "string" ? Date.parse(observedAtRaw) : typeof observedAtRaw === "number" && Number.isFinite(observedAtRaw) ? observedAtRaw : resolveTimes(event).timestamp;
645
+ const status = attrs.outcomeStatus;
646
+ const out = {
647
+ schemaVersion: "0.1",
648
+ event: "outcome_observed",
649
+ timestamp: observedAt,
650
+ runId: event.runId,
651
+ outcomeId: typeof attrs.outcomeId === "string" ? attrs.outcomeId : event.eventId,
652
+ name: event.name,
653
+ expectation: typeof attrs.expectation === "string" ? attrs.expectation : event.name,
654
+ status: status === "passed" || status === "failed" || status === "unknown" || status === "skipped" ? status : "unknown",
655
+ observedAt
656
+ };
657
+ if (event.parentId !== void 0) out.parentId = event.parentId;
658
+ if (typeof attrs.method === "string") out.method = attrs.method;
659
+ if (attrs.actual !== void 0) out.actual = attrs.actual;
660
+ if (event.outputSummary !== void 0) out.actual = event.outputSummary;
661
+ if (attrs.evidence !== void 0) out.evidence = attrs.evidence;
662
+ return out;
663
+ }
664
+ function fromNativeOutcome(event) {
665
+ return [fromLegacyOutcomeObserved(event)];
666
+ }
637
667
  function fromNativeRun(event) {
638
668
  const { timestamp, startTime, endTime } = resolveTimes(event);
639
669
  const runStatus = mapPersistedStatusToRunStatus(event.status);
@@ -721,9 +751,13 @@ function persistedInspectEventToTraceEvents(event) {
721
751
  if (legacyEvent === "run_completed") return [fromLegacyRunCompleted(event)];
722
752
  if (legacyEvent === "step_started") return [fromLegacyStepStarted(event)];
723
753
  if (legacyEvent === "step_completed") return [fromLegacyStepCompleted(event)];
754
+ if (legacyEvent === "outcome_observed") return [fromLegacyOutcomeObserved(event)];
724
755
  if (event.kind === "RUN") {
725
756
  return fromNativeRun(event);
726
757
  }
758
+ if (event.kind === "OUTCOME") {
759
+ return fromNativeOutcome(event);
760
+ }
727
761
  return fromNativeStep(event);
728
762
  }
729
763
  function persistedInspectEventsToTraceEvents(events, options) {
@@ -1071,6 +1105,9 @@ function validateEvent(event) {
1071
1105
  case "step_completed": {
1072
1106
  return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
1073
1107
  }
1108
+ case "outcome_observed": {
1109
+ return nonEmptyString(event.runId) && nonEmptyString(event.outcomeId) && nonEmptyString(event.name) && nonEmptyString(event.expectation) && (event.status === "passed" || event.status === "failed" || event.status === "unknown" || event.status === "skipped") && finiteNumber(event.observedAt);
1110
+ }
1074
1111
  default:
1075
1112
  return false;
1076
1113
  }
@@ -1119,10 +1156,178 @@ var init_inspector_runtime = __esm({
1119
1156
  }
1120
1157
  });
1121
1158
 
1159
+ // packages/core/src/outcomes/types.ts
1160
+ var OBSERVED_OUTCOME_STATUSES, OUTCOME_ATTRIBUTE_STATUS_KEY, OUTCOME_ATTRIBUTE_EXPECTATION_KEY, OUTCOME_ATTRIBUTE_METHOD_KEY, OUTCOME_ATTRIBUTE_OBSERVED_AT_KEY, OUTCOME_LEGACY_EVENT;
1161
+ var init_types2 = __esm({
1162
+ "packages/core/src/outcomes/types.ts"() {
1163
+ OBSERVED_OUTCOME_STATUSES = [
1164
+ "passed",
1165
+ "failed",
1166
+ "unknown",
1167
+ "skipped"
1168
+ ];
1169
+ OUTCOME_ATTRIBUTE_STATUS_KEY = "outcomeStatus";
1170
+ OUTCOME_ATTRIBUTE_EXPECTATION_KEY = "expectation";
1171
+ OUTCOME_ATTRIBUTE_METHOD_KEY = "method";
1172
+ OUTCOME_ATTRIBUTE_OBSERVED_AT_KEY = "observedAt";
1173
+ OUTCOME_LEGACY_EVENT = "outcome_observed";
1174
+ }
1175
+ });
1176
+
1177
+ // packages/core/src/outcomes/validate.ts
1178
+ function parseObservedOutcomeStatus(value) {
1179
+ const trimmed = value.trim().toLowerCase();
1180
+ if (OBSERVED_OUTCOME_STATUSES.includes(trimmed)) {
1181
+ return trimmed;
1182
+ }
1183
+ throw new Error(
1184
+ `Unsupported observation status "${value}". Use passed, failed, unknown, or skipped.`
1185
+ );
1186
+ }
1187
+ var init_validate = __esm({
1188
+ "packages/core/src/outcomes/validate.ts"() {
1189
+ init_trace_event_safety();
1190
+ init_types2();
1191
+ }
1192
+ });
1193
+
1194
+ // packages/core/src/outcomes/extract.ts
1195
+ function isOutcomeStatus(value) {
1196
+ return value === "passed" || value === "failed" || value === "unknown" || value === "skipped";
1197
+ }
1198
+ function parseMethod(value) {
1199
+ if (typeof value !== "string" || value.trim() === "") return void 0;
1200
+ return value;
1201
+ }
1202
+ function fromOutcomeObservedEvent(event) {
1203
+ return {
1204
+ outcomeId: event.outcomeId,
1205
+ runId: event.runId,
1206
+ ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
1207
+ name: event.name,
1208
+ expectation: event.expectation,
1209
+ status: event.status,
1210
+ ...event.method !== void 0 ? { method: event.method } : {},
1211
+ ...event.actual !== void 0 ? { actual: event.actual } : {},
1212
+ ...event.evidence !== void 0 ? { evidence: event.evidence } : {},
1213
+ observedAt: event.observedAt
1214
+ };
1215
+ }
1216
+ function fromPersistedOutcome(event) {
1217
+ if (event.kind !== "OUTCOME") return void 0;
1218
+ const attrs = event.attributes ?? {};
1219
+ const statusRaw = attrs[OUTCOME_ATTRIBUTE_STATUS_KEY];
1220
+ if (!isOutcomeStatus(statusRaw)) return void 0;
1221
+ const expectation = typeof attrs[OUTCOME_ATTRIBUTE_EXPECTATION_KEY] === "string" ? attrs[OUTCOME_ATTRIBUTE_EXPECTATION_KEY] : event.name;
1222
+ const observedAtRaw = attrs[OUTCOME_ATTRIBUTE_OBSERVED_AT_KEY];
1223
+ const observedAt = typeof observedAtRaw === "string" ? Date.parse(observedAtRaw) : typeof observedAtRaw === "number" && Number.isFinite(observedAtRaw) ? observedAtRaw : Date.parse(event.timestamp);
1224
+ return {
1225
+ outcomeId: event.eventId,
1226
+ runId: event.runId,
1227
+ ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
1228
+ name: event.name,
1229
+ expectation,
1230
+ status: statusRaw,
1231
+ ...parseMethod(attrs[OUTCOME_ATTRIBUTE_METHOD_KEY]) !== void 0 ? { method: parseMethod(attrs[OUTCOME_ATTRIBUTE_METHOD_KEY]) } : {},
1232
+ ...event.outputSummary !== void 0 ? { actual: event.outputSummary } : {},
1233
+ ...attrs.evidence !== void 0 ? { evidence: attrs.evidence } : {},
1234
+ observedAt: Number.isFinite(observedAt) ? observedAt : Date.parse(event.timestamp)
1235
+ };
1236
+ }
1237
+ function extractOutcomesFromTraceEvents(events) {
1238
+ const out = [];
1239
+ for (const event of events) {
1240
+ if (event.event === OUTCOME_LEGACY_EVENT) {
1241
+ out.push(fromOutcomeObservedEvent(event));
1242
+ }
1243
+ }
1244
+ return out.sort((a, b) => a.observedAt - b.observedAt || a.name.localeCompare(b.name));
1245
+ }
1246
+ function extractOutcomesFromPersistedEvents(events) {
1247
+ const out = [];
1248
+ for (const event of events) {
1249
+ const outcome = fromPersistedOutcome(event);
1250
+ if (outcome) out.push(outcome);
1251
+ }
1252
+ return out.sort((a, b) => a.observedAt - b.observedAt || a.name.localeCompare(b.name));
1253
+ }
1254
+ function summarizeObservedOutcomes(outcomes) {
1255
+ const summary = {
1256
+ total: outcomes.length,
1257
+ passed: 0,
1258
+ failed: 0,
1259
+ unknown: 0,
1260
+ skipped: 0,
1261
+ outcomes: [...outcomes]
1262
+ };
1263
+ for (const outcome of outcomes) {
1264
+ summary[outcome.status] += 1;
1265
+ }
1266
+ return summary;
1267
+ }
1268
+ function outcomesMatchingStatus(outcomes, statuses) {
1269
+ const set = new Set(statuses);
1270
+ return outcomes.filter((outcome) => set.has(outcome.status));
1271
+ }
1272
+ function parseObservationFilter(value) {
1273
+ if (value === void 0 || value.trim() === "") return void 0;
1274
+ return parseObservedOutcomeStatus(value);
1275
+ }
1276
+ var init_extract = __esm({
1277
+ "packages/core/src/outcomes/extract.ts"() {
1278
+ init_types2();
1279
+ init_validate();
1280
+ }
1281
+ });
1282
+
1283
+ // packages/core/src/outcomes/render.ts
1284
+ function renderObservedOutcomesMarkdown(summary) {
1285
+ if (summary.total === 0) {
1286
+ return "No observed outcomes recorded for this run.";
1287
+ }
1288
+ const lines = [
1289
+ `Total: ${summary.total} (passed ${summary.passed}, failed ${summary.failed}, unknown ${summary.unknown}, skipped ${summary.skipped})`,
1290
+ "",
1291
+ "| Name | Status | Expectation | Method |",
1292
+ "| --- | --- | --- | --- |"
1293
+ ];
1294
+ for (const outcome of summary.outcomes) {
1295
+ lines.push(
1296
+ `| ${outcome.name} | ${outcome.status} | ${outcome.expectation.replace(/\|/g, "\\|")} | ${outcome.method ?? "-"} |`
1297
+ );
1298
+ }
1299
+ return lines.join("\n");
1300
+ }
1301
+ function renderObservedOutcomesHtml(summary) {
1302
+ if (summary.total === 0) {
1303
+ return "<p>No observed outcomes recorded for this run.</p>";
1304
+ }
1305
+ const rows = summary.outcomes.map((outcome) => {
1306
+ const esc = (v) => v.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
1307
+ return `<tr><td>${esc(outcome.name)}</td><td>${esc(outcome.status)}</td><td>${esc(outcome.expectation)}</td><td>${esc(outcome.method ?? "-")}</td></tr>`;
1308
+ }).join("");
1309
+ return `<p>Total: ${summary.total} (passed ${summary.passed}, failed ${summary.failed}, unknown ${summary.unknown}, skipped ${summary.skipped})</p><table><thead><tr><th>Name</th><th>Status</th><th>Expectation</th><th>Method</th></tr></thead><tbody>${rows}</tbody></table>`;
1310
+ }
1311
+ var init_render = __esm({
1312
+ "packages/core/src/outcomes/render.ts"() {
1313
+ }
1314
+ });
1315
+
1316
+ // packages/core/src/outcomes/index.ts
1317
+ var init_outcomes = __esm({
1318
+ "packages/core/src/outcomes/index.ts"() {
1319
+ init_types2();
1320
+ init_extract();
1321
+ init_validate();
1322
+ init_render();
1323
+ }
1324
+ });
1325
+
1122
1326
  // packages/core/src/inspector.ts
1123
1327
  var init_inspector = __esm({
1124
1328
  "packages/core/src/inspector.ts"() {
1125
1329
  init_inspector_runtime();
1330
+ init_outcomes();
1126
1331
  init_trace_event_safety();
1127
1332
  init_utils();
1128
1333
  }
@@ -2737,8 +2942,9 @@ async function searchTraces(metas, options) {
2737
2942
  }
2738
2943
  const limit = options.limit ?? 50;
2739
2944
  const sessionId = options.session?.trim();
2945
+ const observationStatus = parseObservationFilter(options.observation);
2740
2946
  const hasContentFilter = Boolean(
2741
- options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
2947
+ options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter || observationStatus
2742
2948
  );
2743
2949
  const results = [];
2744
2950
  const sessionLabel = sessionId && sessionId !== "" ? sessionId : void 0;
@@ -2783,6 +2989,22 @@ async function searchTraces(metas, options) {
2783
2989
  statusFilter: options.status
2784
2990
  });
2785
2991
  results.push(...stepMatches);
2992
+ if (observationStatus) {
2993
+ const outcomes = extractOutcomesFromTraceEvents(events);
2994
+ const matched = outcomes.filter((outcome) => outcome.status === observationStatus);
2995
+ for (const outcome of matched) {
2996
+ results.push({
2997
+ runId: m.runId,
2998
+ runName: m.name,
2999
+ runStatus: m.status,
3000
+ stepName: outcome.name,
3001
+ timestamp: outcome.observedAt,
3002
+ matchReason: `observation status=${outcome.status}`,
3003
+ matchedFields: ["outcome.status", "outcome.name"],
3004
+ filePath: m.filePath
3005
+ });
3006
+ }
3007
+ }
2786
3008
  }
2787
3009
  results.sort((a, b) => {
2788
3010
  const ta = a.timestamp ?? 0;
@@ -2898,6 +3120,7 @@ var init_search = __esm({
2898
3120
  init_trace_filter();
2899
3121
  init_storage();
2900
3122
  init_duration();
3123
+ init_outcomes();
2901
3124
  }
2902
3125
  });
2903
3126
 
@@ -3189,9 +3412,10 @@ function buildActivitySummary(index, options = {}) {
3189
3412
  entries
3190
3413
  };
3191
3414
  }
3192
- function renderActivitySummaryHuman(summary) {
3415
+ function renderActivitySummaryHuman(summary, options) {
3193
3416
  const lines = [];
3194
- const todayStart = /* @__PURE__ */ new Date();
3417
+ const nowMs = Date.now();
3418
+ const todayStart = new Date(nowMs);
3195
3419
  todayStart.setHours(0, 0, 0, 0);
3196
3420
  const todayMs = todayStart.getTime();
3197
3421
  const today = summary.entries.filter(
@@ -3217,7 +3441,7 @@ var init_activity = __esm({
3217
3441
  });
3218
3442
 
3219
3443
  // packages/core/src/sessions/types.ts
3220
- var init_types2 = __esm({
3444
+ var init_types3 = __esm({
3221
3445
  "packages/core/src/sessions/types.ts"() {
3222
3446
  }
3223
3447
  });
@@ -3675,7 +3899,7 @@ var init_sessions = __esm({
3675
3899
  init_metadata();
3676
3900
  init_status();
3677
3901
  init_activity();
3678
- init_types2();
3902
+ init_types3();
3679
3903
  init_load();
3680
3904
  init_scope();
3681
3905
  init_cohort();
@@ -4000,7 +4224,7 @@ var init_advanced = __esm({
4000
4224
 
4001
4225
  // packages/index-sqlite/src/types.ts
4002
4226
  var INDEX_SCHEMA_VERSION, INDEX_DB_FILENAME;
4003
- var init_types3 = __esm({
4227
+ var init_types4 = __esm({
4004
4228
  "packages/index-sqlite/src/types.ts"() {
4005
4229
  INDEX_SCHEMA_VERSION = "1";
4006
4230
  INDEX_DB_FILENAME = "trace-index.sqlite";
@@ -4778,7 +5002,7 @@ function metaDefaults(sourceDir, fileCount) {
4778
5002
  var INDEX_SCHEMA_SQL, DERIVE_SESSIONS_SQL, META_KEYS;
4779
5003
  var init_schema = __esm({
4780
5004
  "packages/index-sqlite/src/schema.ts"() {
4781
- init_types3();
5005
+ init_types4();
4782
5006
  INDEX_SCHEMA_SQL = `
4783
5007
  DROP TABLE IF EXISTS meta;
4784
5008
  DROP TABLE IF EXISTS errors;
@@ -5031,7 +5255,7 @@ var init_builder = __esm({
5031
5255
  import_better_sqlite3 = __toESM(require_lib());
5032
5256
  init_advanced();
5033
5257
  init_schema();
5034
- init_types3();
5258
+ init_types4();
5035
5259
  DEFAULT_MAX_RUNS = 1e4;
5036
5260
  rebuildIndex = buildIndex;
5037
5261
  }
@@ -5181,14 +5405,14 @@ __export(src_exports, {
5181
5405
  });
5182
5406
  var init_src = __esm({
5183
5407
  "packages/index-sqlite/src/index.ts"() {
5184
- init_types3();
5408
+ init_types4();
5185
5409
  init_builder();
5186
5410
  init_query();
5187
5411
  }
5188
5412
  });
5189
5413
 
5190
5414
  // package.json
5191
- var version = "4.3.0";
5415
+ var version = "4.4.0";
5192
5416
 
5193
5417
  // packages/cli/src/list.ts
5194
5418
  init_advanced();
@@ -5548,6 +5772,8 @@ function nodeIdForEvent(event) {
5548
5772
  case "step_started":
5549
5773
  case "step_completed":
5550
5774
  return event.stepId;
5775
+ case "outcome_observed":
5776
+ return event.outcomeId;
5551
5777
  default:
5552
5778
  return "unknown";
5553
5779
  }
@@ -5731,6 +5957,39 @@ function traceEventToPersistedInspectEvent(event, options) {
5731
5957
  error
5732
5958
  };
5733
5959
  }
5960
+ case "outcome_observed": {
5961
+ const tsObserved = toIsoTimestamp(event.observedAt);
5962
+ const attributes = compactAttributes({
5963
+ legacyEvent: "outcome_observed",
5964
+ outcomeId: event.outcomeId,
5965
+ outcomeStatus: event.status,
5966
+ expectation: event.expectation,
5967
+ method: event.method,
5968
+ actual: event.actual,
5969
+ evidence: event.evidence,
5970
+ observedAt: tsObserved.iso,
5971
+ invalidTimestamp: tsMain.invalidTimestamp || tsObserved.invalidTimestamp ? true : void 0
5972
+ });
5973
+ const out = {
5974
+ schemaVersion: "0.2",
5975
+ eventId,
5976
+ runId: event.runId,
5977
+ kind: "OUTCOME",
5978
+ name: event.name,
5979
+ status: event.status === "failed" ? "error" : "ok",
5980
+ timestamp: tsMain.iso,
5981
+ confidence: "explicit",
5982
+ source,
5983
+ attributes
5984
+ };
5985
+ if (event.parentId !== void 0) {
5986
+ out.parentId = event.parentId;
5987
+ }
5988
+ if (event.actual !== void 0) {
5989
+ out.outputSummary = event.actual;
5990
+ }
5991
+ return out;
5992
+ }
5734
5993
  default: {
5735
5994
  const _exhaustive = event;
5736
5995
  throw new Error(`Unsupported trace event: ${_exhaustive.event}`);
@@ -6467,7 +6726,7 @@ function sanitizeOpenInferenceAttributes(attributes, pathPrefix) {
6467
6726
  function mapOpenInferenceKind(span, attributes, pathPrefix) {
6468
6727
  const warnings = [];
6469
6728
  const agentInspectKind = attributes["agent_inspect.kind"];
6470
- if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
6729
+ if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG" || agentInspectKind === "OUTCOME") {
6471
6730
  return { kind: agentInspectKind, warnings };
6472
6731
  }
6473
6732
  const rawKind = readStringField(span, ["kind", "span_kind", "spanKind"]) ?? (typeof attributes["openinference.span.kind"] === "string" ? attributes["openinference.span.kind"] : void 0);
@@ -6988,7 +7247,7 @@ function mapOtlpStatus(status) {
6988
7247
  function readOtlpKind(attributes, pathPrefix) {
6989
7248
  const warnings = [];
6990
7249
  const agentInspectKind = attributes["agent_inspect.kind"];
6991
- if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
7250
+ if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG" || agentInspectKind === "OUTCOME") {
6992
7251
  return { kind: agentInspectKind, warnings };
6993
7252
  }
6994
7253
  const operation = attributes["gen_ai.operation.name"];
@@ -9127,6 +9386,40 @@ function redactTraceEventsForReport(events, options) {
9127
9386
  )
9128
9387
  } : {}
9129
9388
  };
9389
+ case "outcome_observed": {
9390
+ const actualAttrs = event.actual !== void 0 ? redactEventAttributes(
9391
+ { value: event.actual },
9392
+ redactor,
9393
+ maxMetadataValueLength,
9394
+ maxPreviewLength
9395
+ ) : void 0;
9396
+ const redactedActual = actualAttrs !== void 0 && "value" in actualAttrs ? actualAttrs.value : void 0;
9397
+ const redactedEvidence = event.evidence !== void 0 ? redactEventAttributes(
9398
+ isRecord12(event.evidence) ? event.evidence : { value: event.evidence },
9399
+ redactor,
9400
+ maxMetadataValueLength,
9401
+ maxPreviewLength
9402
+ ) : void 0;
9403
+ return {
9404
+ ...event,
9405
+ name: truncateStringForProfile(
9406
+ event.name,
9407
+ "name",
9408
+ maxMetadataValueLength,
9409
+ maxPreviewLength
9410
+ ),
9411
+ expectation: truncateStringForProfile(
9412
+ event.expectation,
9413
+ "expectation",
9414
+ maxMetadataValueLength,
9415
+ maxPreviewLength
9416
+ ),
9417
+ ...redactedActual !== void 0 ? { actual: redactedActual } : {},
9418
+ ...redactedEvidence !== void 0 ? { evidence: redactedEvidence } : {}
9419
+ };
9420
+ }
9421
+ default:
9422
+ return event;
9130
9423
  }
9131
9424
  });
9132
9425
  }
@@ -9265,7 +9558,8 @@ function zeroKinds() {
9265
9558
  RESULT: 0,
9266
9559
  ERROR: 0,
9267
9560
  LOGIC: 0,
9268
- LOG: 0
9561
+ LOG: 0,
9562
+ OUTCOME: 0
9269
9563
  };
9270
9564
  }
9271
9565
 
@@ -10040,6 +10334,7 @@ function validateExport(result) {
10040
10334
  // packages/core/src/report.ts
10041
10335
  init_timeline();
10042
10336
  init_what();
10337
+ init_outcomes();
10043
10338
  function resolveTree(events, profile) {
10044
10339
  const tree = manualTraceEventsToRunTree(events);
10045
10340
  return profile === "local" ? tree : redactRunTreeForExport(tree, { redactionProfile: profile });
@@ -10070,9 +10365,34 @@ footer{margin-top:2rem;font-size:0.85rem;color:#555}
10070
10365
  `.trim();
10071
10366
  function buildRunReport(events, options) {
10072
10367
  const profile = options.redactionProfile ?? "local";
10368
+ const section = options.section ?? "all";
10073
10369
  const safeEvents = redactTraceEventsForReport(events, {
10074
10370
  redactionProfile: profile
10075
10371
  });
10372
+ const outcomes = summarizeObservedOutcomes(
10373
+ extractOutcomesFromTraceEvents(safeEvents)
10374
+ );
10375
+ const observationsMarkdown = renderObservedOutcomesMarkdown(outcomes);
10376
+ const observationsHtml = renderObservedOutcomesHtml(outcomes);
10377
+ if (section === "observations") {
10378
+ if (options.format === "markdown") {
10379
+ return {
10380
+ format: "markdown",
10381
+ content: `## Observed outcomes
10382
+
10383
+ ${observationsMarkdown}
10384
+ `,
10385
+ contentType: "text/markdown",
10386
+ fileExtension: ".md"
10387
+ };
10388
+ }
10389
+ return {
10390
+ format: "html",
10391
+ content: `<!doctype html><html lang="en"><head><meta charset="utf-8"/><title>Observed outcomes</title><style>${REPORT_HTML_CSS}</style></head><body><h1>Observed outcomes</h1>${observationsHtml}</body></html>`,
10392
+ contentType: "text/html",
10393
+ fileExtension: ".html"
10394
+ };
10395
+ }
10076
10396
  const whatSummary = buildRunWhatSummary(safeEvents);
10077
10397
  const whatText = renderRunWhat(whatSummary, {
10078
10398
  correlation: options.correlation !== false
@@ -10106,6 +10426,10 @@ function buildRunReport(events, options) {
10106
10426
  "```text",
10107
10427
  timelineText,
10108
10428
  "```",
10429
+ "",
10430
+ "## Observed outcomes",
10431
+ "",
10432
+ observationsMarkdown,
10109
10433
  ""
10110
10434
  ];
10111
10435
  if (tail2) {
@@ -10149,6 +10473,7 @@ function buildRunReport(events, options) {
10149
10473
  <p class="note">Generated locally by AgentInspect. Review for sensitive data before sharing.</p>
10150
10474
  <section class="what"><h2>What happened</h2><pre>${escapeHtml(whatText)}</pre></section>
10151
10475
  <section class="timeline"><h2>Timeline</h2><pre>${escapeHtml(timelineText)}</pre></section>
10476
+ <section class="observations"><h2>Observed outcomes</h2>${observationsHtml}</section>
10152
10477
  ${treeSection || '<section class="tree"><h2>Execution tree</h2><p>No steps recorded.</p></section>'}
10153
10478
  ${errorsSection}
10154
10479
  ${attrsSection}
@@ -11007,7 +11332,8 @@ async function searchCommand(options = {}) {
11007
11332
  duration: options.duration,
11008
11333
  limit: parseLimit2(options.limit),
11009
11334
  ...sessionId ? { session: sessionId } : {},
11010
- ...options.correlateGroup ? { correlateGroup: true } : {}
11335
+ ...options.correlateGroup ? { correlateGroup: true } : {},
11336
+ ...options.observation ? { observation: options.observation } : {}
11011
11337
  });
11012
11338
  if (options.json) {
11013
11339
  console.log(JSON.stringify(results, null, 2));
@@ -11534,7 +11860,8 @@ async function reportCommand(runId, options = {}) {
11534
11860
  includeAttributes: options.includeAttributes === true,
11535
11861
  includeErrors: options.noErrors !== true,
11536
11862
  redactionProfile,
11537
- correlation: !options.noCorrelation
11863
+ correlation: !options.noCorrelation,
11864
+ ...options.section ? { section: options.section } : {}
11538
11865
  });
11539
11866
  const outPath = options.output !== void 0 && options.output.trim() !== "" ? path19__default.default.resolve(options.output.trim()) : void 0;
11540
11867
  if (outPath !== void 0) {
@@ -12542,6 +12869,7 @@ async function migrateCommand(input3, options = {}) {
12542
12869
  init_advanced();
12543
12870
 
12544
12871
  // packages/core/src/checks/index.ts
12872
+ init_outcomes();
12545
12873
  var SEVERITY_RANK = {
12546
12874
  error: 0,
12547
12875
  warning: 1,
@@ -13852,6 +14180,40 @@ function createBaselineRegressionRule(options) {
13852
14180
  }
13853
14181
  };
13854
14182
  }
14183
+ function createObservedOutcomeRule(options = {}) {
14184
+ const failOn = options.failOn ?? ["failed"];
14185
+ return {
14186
+ id: "outcome.status",
14187
+ category: "run",
14188
+ defaultSeverity: "error",
14189
+ evaluate(context) {
14190
+ const outcomes = extractOutcomesFromPersistedEvents(context.events);
14191
+ const matching = outcomesMatchingStatus(outcomes, failOn);
14192
+ if (matching.length === 0) return [];
14193
+ return [
14194
+ failFinding(
14195
+ "outcome.status",
14196
+ `Observed outcome count ${matching.length} matched [${failOn.join(", ")}].`,
14197
+ matching.map((outcome) => ({
14198
+ runId: outcome.runId,
14199
+ eventId: outcome.outcomeId,
14200
+ ...outcome.parentId !== void 0 ? { parentId: outcome.parentId } : {},
14201
+ kind: "OUTCOME",
14202
+ name: outcome.name,
14203
+ status: outcome.status,
14204
+ path: `outcome.${outcome.name}`
14205
+ })),
14206
+ { failOn },
14207
+ matching.map((outcome) => ({
14208
+ name: outcome.name,
14209
+ status: outcome.status,
14210
+ expectation: outcome.expectation
14211
+ }))
14212
+ )
14213
+ ];
14214
+ }
14215
+ };
14216
+ }
13855
14217
  function runTraceChecks(input3, options = {}) {
13856
14218
  const selected = resolveSelectedRun(input3, options.runId);
13857
14219
  if (selected.diagnostics.length > 0) {
@@ -14623,6 +14985,22 @@ function buildRules(config, options) {
14623
14985
  if (options.detectStalls) {
14624
14986
  rules.push(createStallDetectionRule({ requireEndedAt: true }));
14625
14987
  }
14988
+ if (options.failOnObservation !== void 0 && options.failOnObservation.trim() !== "") {
14989
+ try {
14990
+ const statuses = options.failOnObservation.split(",").map((value) => value.trim()).filter((value) => value !== "").map((value) => {
14991
+ if (value === "passed" || value === "failed" || value === "unknown" || value === "skipped") {
14992
+ return value;
14993
+ }
14994
+ throw new Error(`unsupported status "${value}"`);
14995
+ });
14996
+ rules.push(createObservedOutcomeRule({ failOn: statuses }));
14997
+ } catch (error) {
14998
+ const message = error instanceof Error ? error.message : String(error);
14999
+ diagnostics.push(
15000
+ diagnostic2("AI_CHECK_INVALID_ARGUMENTS", `--fail-on-observation: ${message}`)
15001
+ );
15002
+ }
15003
+ }
14626
15004
  if (run.maxDepth !== void 0) {
14627
15005
  rules.push(createRunDepthRule({ maxDepth: run.maxDepth }));
14628
15006
  }
@@ -18762,7 +19140,10 @@ function createCliProgram() {
18762
19140
  ]).option("--max-total-tokens <number>", "add llm.usage with a max total-token budget").option(
18763
19141
  "--max-step-duration <duration>",
18764
19142
  "add run.maxStepDuration (e.g. 30s, 5m)"
18765
- ).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(
19143
+ ).option("--require-completed", "add run.requireCompleted").option("--detect-stalls", "add run.stall for running or incomplete events").option(
19144
+ "--fail-on-observation <status>",
19145
+ "fail when observed outcomes match status (passed, failed, unknown, skipped; comma-separated)"
19146
+ ).option("--session <id>", "check all runs in a workflow session (requires --dir)").option("--group <id>", "check all runs sharing a groupId (requires --dir)").option(
18766
19147
  "--correlate-group",
18767
19148
  "when using --session, also match synthetic group: session keys"
18768
19149
  ).option(
@@ -18883,6 +19264,9 @@ function createCliProgram() {
18883
19264
  "unknown"
18884
19265
  ])
18885
19266
  ).option("--kind <kind>", "filter by step kind/type (llm, tool, logic, \u2026)").option("--type <type>", "alias for --kind on manual trace step type").option("--name <query>", "substring match on run or step name").option("--tool <query>", "substring match on tool step name or metadata.toolName").option(
19267
+ "--observation <status>",
19268
+ "filter by observed outcome status (passed, failed, unknown, skipped)"
19269
+ ).option(
18886
19270
  "--duration <expr>",
18887
19271
  "duration filter on run or step (e.g. >5s, >=500ms)"
18888
19272
  ).option("--limit <number>", "max results (default 50)").option("--session <id>", "limit search to one workflow session").option(
@@ -18929,6 +19313,14 @@ function createCliProgram() {
18929
19313
  "html"
18930
19314
  ])
18931
19315
  ).option("-o, --output <path>", "write report to file (creates parent dirs)").option("--json", "emit JSON wrapper (includes content when writing to stdout)").option("--include-attributes", "include bounded step attributes in tree section").option("--no-errors", "omit error details from tree section").option("--no-correlation", "omit correlation metadata from what section").addOption(
19316
+ new commander.Option("--section <section>", "report section (default: all)").choices([
19317
+ "all",
19318
+ "observations",
19319
+ "what",
19320
+ "timeline",
19321
+ "tree"
19322
+ ])
19323
+ ).addOption(
18932
19324
  new commander.Option(
18933
19325
  "--redaction-profile <profile>",
18934
19326
  "redaction profile for entire report: local, share, strict (default: local)"