@agent-inspect/viewer 4.3.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var http = require('http');
4
- var path7 = require('path');
4
+ var path11 = require('path');
5
5
  var async_hooks = require('async_hooks');
6
6
  require('crypto');
7
7
  var promises = require('fs/promises');
@@ -10,10 +10,11 @@ require('nanoid');
10
10
  require('chalk');
11
11
  require('fs');
12
12
  require('readline');
13
+ require('url');
13
14
 
14
15
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
16
 
16
- var path7__default = /*#__PURE__*/_interopDefault(path7);
17
+ var path11__default = /*#__PURE__*/_interopDefault(path11);
17
18
  var os__default = /*#__PURE__*/_interopDefault(os);
18
19
 
19
20
  // packages/viewer/src/server.ts
@@ -78,6 +79,9 @@ function isTraceEvent(value) {
78
79
  case "step_completed": {
79
80
  return typeof value.runId === "string" && typeof value.stepId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
80
81
  }
82
+ case "outcome_observed": {
83
+ return typeof value.runId === "string" && typeof value.outcomeId === "string" && typeof value.name === "string" && typeof value.expectation === "string" && (value.status === "passed" || value.status === "failed" || value.status === "unknown" || value.status === "skipped") && typeof value.observedAt === "number";
84
+ }
81
85
  default:
82
86
  return false;
83
87
  }
@@ -95,7 +99,8 @@ var INSPECT_KINDS = [
95
99
  "RESULT",
96
100
  "ERROR",
97
101
  "LOGIC",
98
- "LOG"
102
+ "LOG",
103
+ "OUTCOME"
99
104
  ];
100
105
  var ATTRIBUTION_CONFIDENCES = [
101
106
  "explicit",
@@ -387,6 +392,32 @@ function fromLegacyStepCompleted(event) {
387
392
  if (error) out.error = error;
388
393
  return out;
389
394
  }
395
+ function fromLegacyOutcomeObserved(event) {
396
+ const attrs = event.attributes ?? {};
397
+ const observedAtRaw = attrs.observedAt;
398
+ const observedAt = typeof observedAtRaw === "string" ? Date.parse(observedAtRaw) : typeof observedAtRaw === "number" && Number.isFinite(observedAtRaw) ? observedAtRaw : resolveTimes(event).timestamp;
399
+ const status = attrs.outcomeStatus;
400
+ const out = {
401
+ schemaVersion: "0.1",
402
+ event: "outcome_observed",
403
+ timestamp: observedAt,
404
+ runId: event.runId,
405
+ outcomeId: typeof attrs.outcomeId === "string" ? attrs.outcomeId : event.eventId,
406
+ name: event.name,
407
+ expectation: typeof attrs.expectation === "string" ? attrs.expectation : event.name,
408
+ status: status === "passed" || status === "failed" || status === "unknown" || status === "skipped" ? status : "unknown",
409
+ observedAt
410
+ };
411
+ if (event.parentId !== void 0) out.parentId = event.parentId;
412
+ if (typeof attrs.method === "string") out.method = attrs.method;
413
+ if (attrs.actual !== void 0) out.actual = attrs.actual;
414
+ if (event.outputSummary !== void 0) out.actual = event.outputSummary;
415
+ if (attrs.evidence !== void 0) out.evidence = attrs.evidence;
416
+ return out;
417
+ }
418
+ function fromNativeOutcome(event) {
419
+ return [fromLegacyOutcomeObserved(event)];
420
+ }
390
421
  function fromNativeRun(event) {
391
422
  const { timestamp, startTime, endTime } = resolveTimes(event);
392
423
  const runStatus = mapPersistedStatusToRunStatus(event.status);
@@ -474,9 +505,13 @@ function persistedInspectEventToTraceEvents(event) {
474
505
  if (legacyEvent === "run_completed") return [fromLegacyRunCompleted(event)];
475
506
  if (legacyEvent === "step_started") return [fromLegacyStepStarted(event)];
476
507
  if (legacyEvent === "step_completed") return [fromLegacyStepCompleted(event)];
508
+ if (legacyEvent === "outcome_observed") return [fromLegacyOutcomeObserved(event)];
477
509
  if (event.kind === "RUN") {
478
510
  return fromNativeRun(event);
479
511
  }
512
+ if (event.kind === "OUTCOME") {
513
+ return fromNativeOutcome(event);
514
+ }
480
515
  return fromNativeStep(event);
481
516
  }
482
517
  function persistedInspectEventsToTraceEvents(events, options) {
@@ -490,7 +525,7 @@ function persistedInspectEventsToTraceEvents(events, options) {
490
525
  }
491
526
  var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
492
527
  var RUNS_DIR_NAME = "runs";
493
- var FALLBACK_TRACE_DIR = path7__default.default.join(
528
+ var FALLBACK_TRACE_DIR = path11__default.default.join(
494
529
  os__default.default.tmpdir(),
495
530
  "agent-inspect",
496
531
  RUNS_DIR_NAME
@@ -505,7 +540,7 @@ function getDefaultTraceDir() {
505
540
  if (typeof home !== "string" || home.trim() === "") {
506
541
  return FALLBACK_TRACE_DIR;
507
542
  }
508
- return path7__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
543
+ return path11__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
509
544
  } catch {
510
545
  return FALLBACK_TRACE_DIR;
511
546
  }
@@ -676,6 +711,9 @@ function validateEvent(event) {
676
711
  case "step_completed": {
677
712
  return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
678
713
  }
714
+ case "outcome_observed": {
715
+ 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);
716
+ }
679
717
  default:
680
718
  return false;
681
719
  }
@@ -711,7 +749,7 @@ var TraceDirectory = class {
711
749
  this.#dir = resolveTraceDir(options);
712
750
  }
713
751
  getPath(filename) {
714
- return filename ? path7__default.default.join(this.#dir, filename) : this.#dir;
752
+ return filename ? path11__default.default.join(this.#dir, filename) : this.#dir;
715
753
  }
716
754
  async list() {
717
755
  try {
@@ -738,7 +776,7 @@ function parseIsoToMs2(value) {
738
776
  }
739
777
  async function extractMetadata(filePath, _quickScan) {
740
778
  const stats = await promises.stat(filePath);
741
- let runIdFromFile = path7__default.default.basename(filePath);
779
+ let runIdFromFile = path11__default.default.basename(filePath);
742
780
  if (runIdFromFile.endsWith(".jsonl")) {
743
781
  runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
744
782
  }
@@ -1348,12 +1386,12 @@ function buildCriticalPath(runs, handoffs) {
1348
1386
  handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
1349
1387
  );
1350
1388
  const ordered = [...runs].sort(compareRuns);
1351
- const path8 = [];
1389
+ const path12 = [];
1352
1390
  const visited = /* @__PURE__ */ new Set();
1353
1391
  const pushRun = (run, confidence, source) => {
1354
1392
  if (visited.has(run.runId)) return;
1355
1393
  visited.add(run.runId);
1356
- path8.push({
1394
+ path12.push({
1357
1395
  runId: run.runId,
1358
1396
  name: run.name,
1359
1397
  startedAt: run.startedAt,
@@ -1378,7 +1416,7 @@ function buildCriticalPath(runs, handoffs) {
1378
1416
  const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
1379
1417
  pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
1380
1418
  }
1381
- return path8;
1419
+ return path12;
1382
1420
  }
1383
1421
  function metaRunIdMatches(run, token, runById) {
1384
1422
  const meta = extractSessionWorkflowMetadata(run.metadata);
@@ -1651,7 +1689,7 @@ function summarize(findings, diagnostics) {
1651
1689
  errors: diagnostics.filter((item) => item.severity === "error").length
1652
1690
  };
1653
1691
  }
1654
- function eventEvidence(event, path8) {
1692
+ function eventEvidence(event, path12) {
1655
1693
  return {
1656
1694
  runId: event.runId,
1657
1695
  eventId: event.eventId,
@@ -1800,6 +1838,8 @@ function nodeIdForEvent(event) {
1800
1838
  case "step_started":
1801
1839
  case "step_completed":
1802
1840
  return event.stepId;
1841
+ case "outcome_observed":
1842
+ return event.outcomeId;
1803
1843
  default:
1804
1844
  return "unknown";
1805
1845
  }
@@ -1983,6 +2023,39 @@ function traceEventToPersistedInspectEvent(event, options) {
1983
2023
  error
1984
2024
  };
1985
2025
  }
2026
+ case "outcome_observed": {
2027
+ const tsObserved = toIsoTimestamp(event.observedAt);
2028
+ const attributes = compactAttributes({
2029
+ legacyEvent: "outcome_observed",
2030
+ outcomeId: event.outcomeId,
2031
+ outcomeStatus: event.status,
2032
+ expectation: event.expectation,
2033
+ method: event.method,
2034
+ actual: event.actual,
2035
+ evidence: event.evidence,
2036
+ observedAt: tsObserved.iso,
2037
+ invalidTimestamp: tsMain.invalidTimestamp || tsObserved.invalidTimestamp ? true : void 0
2038
+ });
2039
+ const out = {
2040
+ schemaVersion: "0.2",
2041
+ eventId,
2042
+ runId: event.runId,
2043
+ kind: "OUTCOME",
2044
+ name: event.name,
2045
+ status: event.status === "failed" ? "error" : "ok",
2046
+ timestamp: tsMain.iso,
2047
+ confidence: "explicit",
2048
+ source,
2049
+ attributes
2050
+ };
2051
+ if (event.parentId !== void 0) {
2052
+ out.parentId = event.parentId;
2053
+ }
2054
+ if (event.actual !== void 0) {
2055
+ out.outputSummary = event.actual;
2056
+ }
2057
+ return out;
2058
+ }
1986
2059
  default: {
1987
2060
  const _exhaustive = event;
1988
2061
  throw new Error(`Unsupported trace event: ${_exhaustive.event}`);
@@ -1995,6 +2068,86 @@ function traceEventsToPersistedInspectEvents(events, options) {
1995
2068
  );
1996
2069
  }
1997
2070
 
2071
+ // packages/core/src/logs/tree-builder.ts
2072
+ function inc(map, key) {
2073
+ map[key] = (map[key] ?? 0) + 1;
2074
+ }
2075
+ function computeRunStatus(events) {
2076
+ let hasRunning = false;
2077
+ for (const e of events) {
2078
+ if (e.status === "error") return "error";
2079
+ if (e.status === "running") hasRunning = true;
2080
+ }
2081
+ if (hasRunning) return "running";
2082
+ return "ok";
2083
+ }
2084
+ var TreeBuilder = class {
2085
+ constructor(options) {
2086
+ void options?.config;
2087
+ }
2088
+ build(events) {
2089
+ const byRun = /* @__PURE__ */ new Map();
2090
+ for (const e of events) {
2091
+ if (!byRun.has(e.runId)) byRun.set(e.runId, []);
2092
+ byRun.get(e.runId).push(e);
2093
+ }
2094
+ const out = [];
2095
+ for (const [runId, runEvents] of byRun.entries()) {
2096
+ const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
2097
+ const nodes = /* @__PURE__ */ new Map();
2098
+ for (const e of sorted) {
2099
+ nodes.set(e.eventId, { event: e, children: [], depth: 0 });
2100
+ }
2101
+ const roots = [];
2102
+ for (const node of nodes.values()) {
2103
+ const parentId = node.event.parentId;
2104
+ if (parentId && nodes.has(parentId)) {
2105
+ nodes.get(parentId).children.push(node);
2106
+ } else {
2107
+ roots.push(node);
2108
+ }
2109
+ }
2110
+ const assignDepth = (n, depth) => {
2111
+ n.depth = depth;
2112
+ for (const c of n.children) assignDepth(c, depth + 1);
2113
+ };
2114
+ for (const r of roots) assignDepth(r, 0);
2115
+ const confidenceBreakdown = {
2116
+ explicit: 0,
2117
+ correlated: 0,
2118
+ heuristic: 0,
2119
+ unknown: 0
2120
+ };
2121
+ const kinds = {};
2122
+ for (const e of sorted) {
2123
+ inc(confidenceBreakdown, e.confidence);
2124
+ kinds[e.kind] = (kinds[e.kind] ?? 0) + 1;
2125
+ }
2126
+ const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
2127
+ const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
2128
+ const status = computeRunStatus(sorted);
2129
+ const durationMs = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
2130
+ const name = sorted.find((e) => e.kind === "RUN")?.name;
2131
+ out.push({
2132
+ runId,
2133
+ name,
2134
+ status,
2135
+ startedAt,
2136
+ endedAt: status === "running" ? void 0 : endedAt,
2137
+ durationMs,
2138
+ children: roots,
2139
+ metadata: {
2140
+ totalEvents: sorted.length,
2141
+ confidenceBreakdown,
2142
+ kinds
2143
+ }
2144
+ });
2145
+ }
2146
+ out.sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0));
2147
+ return out;
2148
+ }
2149
+ };
2150
+
1998
2151
  // packages/core/src/persisted/to-inspect-event.ts
1999
2152
  function compactAttributes2(entries) {
2000
2153
  const out = {};
@@ -2133,86 +2286,6 @@ function persistedInspectEventsToInspectEvents(events, options) {
2133
2286
  return out;
2134
2287
  }
2135
2288
 
2136
- // packages/core/src/logs/tree-builder.ts
2137
- function inc(map, key) {
2138
- map[key] = (map[key] ?? 0) + 1;
2139
- }
2140
- function computeRunStatus(events) {
2141
- let hasRunning = false;
2142
- for (const e of events) {
2143
- if (e.status === "error") return "error";
2144
- if (e.status === "running") hasRunning = true;
2145
- }
2146
- if (hasRunning) return "running";
2147
- return "ok";
2148
- }
2149
- var TreeBuilder = class {
2150
- constructor(options) {
2151
- void options?.config;
2152
- }
2153
- build(events) {
2154
- const byRun = /* @__PURE__ */ new Map();
2155
- for (const e of events) {
2156
- if (!byRun.has(e.runId)) byRun.set(e.runId, []);
2157
- byRun.get(e.runId).push(e);
2158
- }
2159
- const out = [];
2160
- for (const [runId, runEvents] of byRun.entries()) {
2161
- const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
2162
- const nodes = /* @__PURE__ */ new Map();
2163
- for (const e of sorted) {
2164
- nodes.set(e.eventId, { event: e, children: [], depth: 0 });
2165
- }
2166
- const roots = [];
2167
- for (const node of nodes.values()) {
2168
- const parentId = node.event.parentId;
2169
- if (parentId && nodes.has(parentId)) {
2170
- nodes.get(parentId).children.push(node);
2171
- } else {
2172
- roots.push(node);
2173
- }
2174
- }
2175
- const assignDepth = (n, depth) => {
2176
- n.depth = depth;
2177
- for (const c of n.children) assignDepth(c, depth + 1);
2178
- };
2179
- for (const r of roots) assignDepth(r, 0);
2180
- const confidenceBreakdown = {
2181
- explicit: 0,
2182
- correlated: 0,
2183
- heuristic: 0,
2184
- unknown: 0
2185
- };
2186
- const kinds = {};
2187
- for (const e of sorted) {
2188
- inc(confidenceBreakdown, e.confidence);
2189
- kinds[e.kind] = (kinds[e.kind] ?? 0) + 1;
2190
- }
2191
- const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
2192
- const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
2193
- const status = computeRunStatus(sorted);
2194
- const durationMs = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
2195
- const name = sorted.find((e) => e.kind === "RUN")?.name;
2196
- out.push({
2197
- runId,
2198
- name,
2199
- status,
2200
- startedAt,
2201
- endedAt: status === "running" ? void 0 : endedAt,
2202
- durationMs,
2203
- children: roots,
2204
- metadata: {
2205
- totalEvents: sorted.length,
2206
- confidenceBreakdown,
2207
- kinds
2208
- }
2209
- });
2210
- }
2211
- out.sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0));
2212
- return out;
2213
- }
2214
- };
2215
-
2216
2289
  // packages/core/src/persisted/tree-bridge.ts
2217
2290
  function persistedInspectEventsToRunTrees(events, options) {
2218
2291
  const inspectEvents = persistedInspectEventsToInspectEvents(events, {
@@ -2220,6 +2293,8 @@ function persistedInspectEventsToRunTrees(events, options) {
2220
2293
  });
2221
2294
  return new TreeBuilder().build(inspectEvents);
2222
2295
  }
2296
+
2297
+ // packages/core/src/readers/index.ts
2223
2298
  var DEFAULT_MAX_TRACE_INPUT_BYTES = 10 * 1024 * 1024;
2224
2299
  var MIN_DETECTION_CONFIDENCE = 0.5;
2225
2300
  var AMBIGUOUS_CONFIDENCE_DELTA = 0.05;
@@ -2342,7 +2417,7 @@ function findReaderByFormat(format, readers) {
2342
2417
  }
2343
2418
  async function jsonlFilesInDirectory(dirPath) {
2344
2419
  const entries = await promises.readdir(dirPath, { withFileTypes: true });
2345
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path7__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
2420
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path11__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
2346
2421
  }
2347
2422
  async function resolveInput(input) {
2348
2423
  const cached = resolvedInputCache.get(input);
@@ -2712,7 +2787,7 @@ function sanitizeOpenInferenceAttributes(attributes, pathPrefix) {
2712
2787
  function mapOpenInferenceKind(span, attributes, pathPrefix) {
2713
2788
  const warnings = [];
2714
2789
  const agentInspectKind = attributes["agent_inspect.kind"];
2715
- if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
2790
+ 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") {
2716
2791
  return { kind: agentInspectKind, warnings };
2717
2792
  }
2718
2793
  const rawKind = readStringField(span, ["kind", "span_kind", "spanKind"]) ?? (typeof attributes["openinference.span.kind"] === "string" ? attributes["openinference.span.kind"] : void 0);
@@ -3233,7 +3308,7 @@ function mapOtlpStatus(status) {
3233
3308
  function readOtlpKind(attributes, pathPrefix) {
3234
3309
  const warnings = [];
3235
3310
  const agentInspectKind = attributes["agent_inspect.kind"];
3236
- if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
3311
+ 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") {
3237
3312
  return { kind: agentInspectKind, warnings };
3238
3313
  }
3239
3314
  const operation = attributes["gen_ai.operation.name"];
@@ -3879,7 +3954,7 @@ function createViewerServer(options = {}) {
3879
3954
  return sendJson(res, 200, {
3880
3955
  ok: true,
3881
3956
  readOnly: true,
3882
- traceDir: path7__default.default.resolve(traceDir)
3957
+ traceDir: path11__default.default.resolve(traceDir)
3883
3958
  });
3884
3959
  }
3885
3960
  const td = new TraceDirectory({ dir: traceDir });
@@ -3897,7 +3972,7 @@ function createViewerServer(options = {}) {
3897
3972
  runId: meta.runId,
3898
3973
  name: meta.name,
3899
3974
  status: meta.status,
3900
- file: path7__default.default.basename(meta.filePath),
3975
+ file: path11__default.default.basename(meta.filePath),
3901
3976
  startedAt: meta.startedAt,
3902
3977
  durationMs: meta.durationMs
3903
3978
  }))
@@ -4012,7 +4087,7 @@ function startViewerServer(options = {}) {
4012
4087
  resolve({
4013
4088
  host,
4014
4089
  port: resolvedPort,
4015
- traceDir: path7__default.default.resolve(traceDir),
4090
+ traceDir: path11__default.default.resolve(traceDir),
4016
4091
  url: `http://${host}:${resolvedPort}`
4017
4092
  });
4018
4093
  });