@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.cjs +186 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +185 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createServer } from 'http';
|
|
2
|
-
import
|
|
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 =
|
|
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
|
|
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 ?
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
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,
|
|
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) =>
|
|
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:
|
|
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:
|
|
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:
|
|
4008
|
+
traceDir: path7.resolve(traceDir),
|
|
3845
4009
|
url: `http://${host}:${resolvedPort}`
|
|
3846
4010
|
});
|
|
3847
4011
|
});
|