@agent-inspect/viewer 4.1.0 → 4.3.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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createServer } from 'http';
2
- import path6 from 'path';
2
+ import path7 from 'path';
3
3
  import { AsyncLocalStorage } from 'async_hooks';
4
4
  import 'crypto';
5
5
  import { readdir, stat, readFile } from 'fs/promises';
@@ -483,7 +483,7 @@ function persistedInspectEventsToTraceEvents(events, options) {
483
483
  }
484
484
  var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
485
485
  var RUNS_DIR_NAME = "runs";
486
- var FALLBACK_TRACE_DIR = path6.join(
486
+ var FALLBACK_TRACE_DIR = path7.join(
487
487
  os.tmpdir(),
488
488
  "agent-inspect",
489
489
  RUNS_DIR_NAME
@@ -498,7 +498,7 @@ function getDefaultTraceDir() {
498
498
  if (typeof home !== "string" || home.trim() === "") {
499
499
  return FALLBACK_TRACE_DIR;
500
500
  }
501
- return path6.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
501
+ return path7.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
502
502
  } catch {
503
503
  return FALLBACK_TRACE_DIR;
504
504
  }
@@ -704,7 +704,7 @@ var TraceDirectory = class {
704
704
  this.#dir = resolveTraceDir(options);
705
705
  }
706
706
  getPath(filename) {
707
- return filename ? path6.join(this.#dir, filename) : this.#dir;
707
+ return filename ? path7.join(this.#dir, filename) : this.#dir;
708
708
  }
709
709
  async list() {
710
710
  try {
@@ -731,7 +731,7 @@ function parseIsoToMs2(value) {
731
731
  }
732
732
  async function extractMetadata(filePath, _quickScan) {
733
733
  const stats = await stat(filePath);
734
- let runIdFromFile = path6.basename(filePath);
734
+ let runIdFromFile = path7.basename(filePath);
735
735
  if (runIdFromFile.endsWith(".jsonl")) {
736
736
  runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
737
737
  }
@@ -1024,6 +1024,163 @@ function sessionKeyForRun(meta, options) {
1024
1024
  return void 0;
1025
1025
  }
1026
1026
 
1027
+ // packages/core/src/sessions/status.ts
1028
+ var DEFAULT_STALE_THRESHOLD_MS = 864e5;
1029
+ var EXPLICIT_STATUS_PRIORITY = {
1030
+ error: 5,
1031
+ waiting_input: 4,
1032
+ idle: 3,
1033
+ stale: 2,
1034
+ completed: 1
1035
+ };
1036
+ var EXPLICIT_SESSION_STATUSES = /* @__PURE__ */ new Set([
1037
+ "running",
1038
+ "waiting_input",
1039
+ "idle",
1040
+ "completed",
1041
+ "error",
1042
+ "stale",
1043
+ "unknown"
1044
+ ]);
1045
+ function isExplicitSessionStatus(value) {
1046
+ return typeof value === "string" && EXPLICIT_SESSION_STATUSES.has(value);
1047
+ }
1048
+ function activityMs(run) {
1049
+ return run.endedAt ?? run.startedAt ?? 0;
1050
+ }
1051
+ function latestActivityMs(runs) {
1052
+ let latest = 0;
1053
+ for (const run of runs) {
1054
+ const ms = activityMs(run);
1055
+ if (ms > latest) latest = ms;
1056
+ }
1057
+ return latest;
1058
+ }
1059
+ function earliestStart(runs) {
1060
+ let earliest;
1061
+ for (const run of runs) {
1062
+ if (run.startedAt === void 0) continue;
1063
+ if (earliest === void 0 || run.startedAt < earliest) {
1064
+ earliest = run.startedAt;
1065
+ }
1066
+ }
1067
+ return earliest;
1068
+ }
1069
+ function latestEndWhenAllEnded(runs) {
1070
+ if (runs.length === 0) return void 0;
1071
+ let latest;
1072
+ for (const run of runs) {
1073
+ if (run.endedAt === void 0) return void 0;
1074
+ if (latest === void 0 || run.endedAt > latest) latest = run.endedAt;
1075
+ }
1076
+ return latest;
1077
+ }
1078
+ function pickExplicitStatus(runs) {
1079
+ let best;
1080
+ let bestPriority = 0;
1081
+ for (const run of runs) {
1082
+ const raw = run.metadata?.sessionStatus;
1083
+ if (!isExplicitSessionStatus(raw)) continue;
1084
+ const priority = EXPLICIT_STATUS_PRIORITY[raw] ?? 0;
1085
+ if (priority > bestPriority) {
1086
+ bestPriority = priority;
1087
+ best = raw;
1088
+ }
1089
+ }
1090
+ return best;
1091
+ }
1092
+ function deriveLastError(runs) {
1093
+ const errorRuns = runs.filter((run) => run.status === "error").sort((a, b) => activityMs(b) - activityMs(a));
1094
+ const latest = errorRuns[0];
1095
+ if (!latest) return void 0;
1096
+ const meta = latest.metadata ?? {};
1097
+ const message = typeof meta.errorMessage === "string" && meta.errorMessage.trim() !== "" ? meta.errorMessage.trim() : latest.name ?? latest.runId;
1098
+ const code = typeof meta.errorCode === "string" && meta.errorCode.trim() !== "" ? meta.errorCode.trim() : void 0;
1099
+ return { runId: latest.runId, message, code };
1100
+ }
1101
+ function deriveCheckSummary(runs) {
1102
+ let pass = 0;
1103
+ let fail = 0;
1104
+ let warn2 = 0;
1105
+ let found = false;
1106
+ for (const run of runs) {
1107
+ const summary = run.metadata?.checkSummary;
1108
+ if (!summary || typeof summary !== "object") continue;
1109
+ const record = summary;
1110
+ if (typeof record.pass === "number") {
1111
+ pass += record.pass;
1112
+ found = true;
1113
+ }
1114
+ if (typeof record.fail === "number") {
1115
+ fail += record.fail;
1116
+ found = true;
1117
+ }
1118
+ if (typeof record.warn === "number") {
1119
+ warn2 += record.warn;
1120
+ found = true;
1121
+ }
1122
+ }
1123
+ return found ? { pass, fail, warn: warn2 } : void 0;
1124
+ }
1125
+ function deriveObservationSummary(runs) {
1126
+ for (const run of [...runs].sort((a, b) => activityMs(b) - activityMs(a))) {
1127
+ const value = run.metadata?.observationSummary;
1128
+ if (typeof value === "string" && value.trim() !== "") {
1129
+ return value.trim();
1130
+ }
1131
+ }
1132
+ return void 0;
1133
+ }
1134
+ function deriveSessionStatus(runs, options = {}) {
1135
+ if (runs.length === 0) return "unknown";
1136
+ if (runs.some((run) => run.status === "running")) return "running";
1137
+ const explicit = pickExplicitStatus(runs);
1138
+ if (explicit && explicit !== "running") return explicit;
1139
+ if (runs.some((run) => run.status === "error")) return "error";
1140
+ if (runs.every((run) => run.status === "success")) return "completed";
1141
+ const nowMs = options.nowMs ?? Date.now();
1142
+ const staleThresholdMs = options.staleThresholdMs ?? DEFAULT_STALE_THRESHOLD_MS;
1143
+ const lastMs = latestActivityMs(runs);
1144
+ if (lastMs > 0 && nowMs - lastMs > staleThresholdMs) return "stale";
1145
+ return "unknown";
1146
+ }
1147
+ function enrichSessionSummary(summary, runs, options = {}) {
1148
+ const sessionRuns = runs.filter((run) => summary.runIds.includes(run.runId)).sort((a, b) => a.runId.localeCompare(b.runId));
1149
+ const startedAt = earliestStart(sessionRuns);
1150
+ const endedAt = latestEndWhenAllEnded(sessionRuns);
1151
+ const durationMs = startedAt !== void 0 && endedAt !== void 0 ? endedAt - startedAt : void 0;
1152
+ let correlationId;
1153
+ let jobId;
1154
+ let workflowId;
1155
+ for (const run of sessionRuns) {
1156
+ const meta = extractSessionWorkflowMetadata(run.metadata);
1157
+ if (!correlationId && meta?.correlationId) correlationId = meta.correlationId;
1158
+ if (!jobId && meta?.jobId) jobId = meta.jobId;
1159
+ if (!workflowId && meta?.workflowName) workflowId = meta.workflowName;
1160
+ else if (!workflowId && meta?.workflowStep) workflowId = meta.workflowStep;
1161
+ }
1162
+ const lastMs = latestActivityMs(sessionRuns);
1163
+ const lastActivity = lastMs > 0 ? new Date(lastMs).toISOString() : (/* @__PURE__ */ new Date(0)).toISOString();
1164
+ const retryCount = summary.retries.filter(
1165
+ (retry) => retry.retryOf !== void 0 || (retry.attempt ?? 0) > 1
1166
+ ).length;
1167
+ return {
1168
+ ...summary,
1169
+ status: deriveSessionStatus(sessionRuns, options),
1170
+ startedAt,
1171
+ endedAt,
1172
+ durationMs,
1173
+ correlationId,
1174
+ jobId,
1175
+ workflowId,
1176
+ lastError: deriveLastError(sessionRuns),
1177
+ lastActivity,
1178
+ retryCount,
1179
+ observationSummary: deriveObservationSummary(sessionRuns),
1180
+ checkSummary: deriveCheckSummary(sessionRuns)
1181
+ };
1182
+ }
1183
+
1027
1184
  // packages/core/src/sessions/load.ts
1028
1185
  async function enrichSessionRunRecord(meta) {
1029
1186
  let metadata;
@@ -1184,12 +1341,12 @@ function buildCriticalPath(runs, handoffs) {
1184
1341
  handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
1185
1342
  );
1186
1343
  const ordered = [...runs].sort(compareRuns);
1187
- const path7 = [];
1344
+ const path8 = [];
1188
1345
  const visited = /* @__PURE__ */ new Set();
1189
1346
  const pushRun = (run, confidence, source) => {
1190
1347
  if (visited.has(run.runId)) return;
1191
1348
  visited.add(run.runId);
1192
- path7.push({
1349
+ path8.push({
1193
1350
  runId: run.runId,
1194
1351
  name: run.name,
1195
1352
  startedAt: run.startedAt,
@@ -1214,7 +1371,7 @@ function buildCriticalPath(runs, handoffs) {
1214
1371
  const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
1215
1372
  pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
1216
1373
  }
1217
- return path7;
1374
+ return path8;
1218
1375
  }
1219
1376
  function metaRunIdMatches(run, token, runById) {
1220
1377
  const meta = extractSessionWorkflowMetadata(run.metadata);
@@ -1256,14 +1413,21 @@ function buildSessionIndex(inputRuns, options = {}) {
1256
1413
  sessionId
1257
1414
  });
1258
1415
  }
1259
- return {
1260
- sessionId,
1261
- runIds,
1262
- groups,
1263
- handoffs,
1264
- retries,
1265
- criticalPath
1266
- };
1416
+ return enrichSessionSummary(
1417
+ {
1418
+ sessionId,
1419
+ runIds,
1420
+ groups,
1421
+ handoffs,
1422
+ retries,
1423
+ criticalPath
1424
+ },
1425
+ runs,
1426
+ {
1427
+ nowMs: options.nowMs,
1428
+ staleThresholdMs: options.staleThresholdMs
1429
+ }
1430
+ );
1267
1431
  });
1268
1432
  if (sessions.length === 0 && runs.length > 0) {
1269
1433
  warnings.push({
@@ -1480,7 +1644,7 @@ function summarize(findings, diagnostics) {
1480
1644
  errors: diagnostics.filter((item) => item.severity === "error").length
1481
1645
  };
1482
1646
  }
1483
- function eventEvidence(event, path7) {
1647
+ function eventEvidence(event, path8) {
1484
1648
  return {
1485
1649
  runId: event.runId,
1486
1650
  eventId: event.eventId,
@@ -2171,7 +2335,7 @@ function findReaderByFormat(format, readers) {
2171
2335
  }
2172
2336
  async function jsonlFilesInDirectory(dirPath) {
2173
2337
  const entries = await readdir(dirPath, { withFileTypes: true });
2174
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path6.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
2338
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path7.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
2175
2339
  }
2176
2340
  async function resolveInput(input) {
2177
2341
  const cached = resolvedInputCache.get(input);
@@ -3708,7 +3872,7 @@ function createViewerServer(options = {}) {
3708
3872
  return sendJson(res, 200, {
3709
3873
  ok: true,
3710
3874
  readOnly: true,
3711
- traceDir: path6.resolve(traceDir)
3875
+ traceDir: path7.resolve(traceDir)
3712
3876
  });
3713
3877
  }
3714
3878
  const td = new TraceDirectory({ dir: traceDir });
@@ -3726,7 +3890,7 @@ function createViewerServer(options = {}) {
3726
3890
  runId: meta.runId,
3727
3891
  name: meta.name,
3728
3892
  status: meta.status,
3729
- file: path6.basename(meta.filePath),
3893
+ file: path7.basename(meta.filePath),
3730
3894
  startedAt: meta.startedAt,
3731
3895
  durationMs: meta.durationMs
3732
3896
  }))
@@ -3841,7 +4005,7 @@ function startViewerServer(options = {}) {
3841
4005
  resolve({
3842
4006
  host,
3843
4007
  port: resolvedPort,
3844
- traceDir: path6.resolve(traceDir),
4008
+ traceDir: path7.resolve(traceDir),
3845
4009
  url: `http://${host}:${resolvedPort}`
3846
4010
  });
3847
4011
  });