agent-inspect 2.3.0 → 2.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.
- package/CHANGELOG.md +16 -0
- package/README.md +33 -4
- package/docs/ADAPTERS.md +47 -0
- package/docs/CLI.md +54 -1
- package/docs/SCHEMA.md +1 -0
- package/package.json +2 -2
- package/packages/cli/dist/index.cjs +757 -14
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +757 -14
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/advanced.cjs +581 -3
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +172 -8
- package/packages/core/dist/advanced.d.ts +172 -8
- package/packages/core/dist/advanced.mjs +572 -4
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/checks.d.cts +2 -2
- package/packages/core/dist/checks.d.ts +2 -2
- package/packages/core/dist/{context-yv2VSDQF.d.ts → context-BDZmi53V.d.ts} +3 -3
- package/packages/core/dist/{context-CSKnzpXR.d.cts → context-DjY-jvQk.d.cts} +3 -3
- package/packages/core/dist/diff.d.cts +3 -3
- package/packages/core/dist/diff.d.ts +3 -3
- package/packages/core/dist/exporters.d.cts +3 -3
- package/packages/core/dist/exporters.d.ts +3 -3
- package/packages/core/dist/index.d.cts +6 -6
- package/packages/core/dist/index.d.ts +6 -6
- package/packages/core/dist/{inspect-event-CevRYp58.d.cts → inspect-event-CYAV7Hxm.d.cts} +1 -1
- package/packages/core/dist/{inspect-event-CevRYp58.d.ts → inspect-event-CYAV7Hxm.d.ts} +1 -1
- package/packages/core/dist/{log-config-8aE5Kxtr.d.cts → log-config-BNQ9UTmP.d.cts} +1 -1
- package/packages/core/dist/{log-config-DVimQJho.d.ts → log-config-D3Yp1SZN.d.ts} +1 -1
- package/packages/core/dist/logs.d.cts +3 -3
- package/packages/core/dist/logs.d.ts +3 -3
- package/packages/core/dist/{persisted-inspect-event-D-WpXeZX.d.ts → persisted-inspect-event-BLvb0jSX.d.ts} +1 -1
- package/packages/core/dist/{persisted-inspect-event-DHcHPUKv.d.cts → persisted-inspect-event-D5SjBz9b.d.cts} +1 -1
- package/packages/core/dist/persisted.d.cts +5 -5
- package/packages/core/dist/persisted.d.ts +5 -5
- package/packages/core/dist/readers.d.cts +2 -2
- package/packages/core/dist/readers.d.ts +2 -2
- package/packages/core/dist/{types-DgMN3qow.d.cts → types-C-llnPH0.d.cts} +1 -1
- package/packages/core/dist/{types-D-Y1kOU-.d.ts → types-CQun9LW6.d.ts} +1 -1
- package/packages/core/dist/writers.d.cts +2 -2
- package/packages/core/dist/writers.d.ts +2 -2
|
@@ -3866,10 +3866,12 @@ async function searchTraces(metas, options) {
|
|
|
3866
3866
|
durationFilter = parseDurationFilter(options.duration);
|
|
3867
3867
|
}
|
|
3868
3868
|
const limit = options.limit ?? 50;
|
|
3869
|
+
const sessionId = options.session?.trim();
|
|
3869
3870
|
const hasContentFilter = Boolean(
|
|
3870
3871
|
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
|
|
3871
3872
|
);
|
|
3872
3873
|
const results = [];
|
|
3874
|
+
const sessionLabel = sessionId && sessionId !== "" ? sessionId : void 0;
|
|
3873
3875
|
if (!hasContentFilter) {
|
|
3874
3876
|
for (const m of filtered) {
|
|
3875
3877
|
results.push({
|
|
@@ -3878,9 +3880,10 @@ async function searchTraces(metas, options) {
|
|
|
3878
3880
|
runStatus: m.status,
|
|
3879
3881
|
timestamp: m.startedAt,
|
|
3880
3882
|
durationMs: m.durationMs,
|
|
3881
|
-
matchReason: "trace in directory",
|
|
3882
|
-
matchedFields: ["run"],
|
|
3883
|
-
filePath: m.filePath
|
|
3883
|
+
matchReason: sessionLabel ? `trace in session ${sessionLabel}` : "trace in directory",
|
|
3884
|
+
matchedFields: sessionLabel ? ["run", "session"] : ["run"],
|
|
3885
|
+
filePath: m.filePath,
|
|
3886
|
+
...sessionLabel ? { sessionId: sessionLabel } : {}
|
|
3884
3887
|
});
|
|
3885
3888
|
}
|
|
3886
3889
|
return results.slice(0, limit);
|
|
@@ -4019,6 +4022,571 @@ async function loadTraceMetadataList(_traceDir, fileNames, getPath) {
|
|
|
4019
4022
|
}
|
|
4020
4023
|
return metas;
|
|
4021
4024
|
}
|
|
4025
|
+
|
|
4026
|
+
// packages/core/src/sessions/metadata.ts
|
|
4027
|
+
function isNonEmptyString3(value) {
|
|
4028
|
+
return typeof value === "string" && value.trim() !== "";
|
|
4029
|
+
}
|
|
4030
|
+
function finitePositiveInt(value) {
|
|
4031
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 1) {
|
|
4032
|
+
return void 0;
|
|
4033
|
+
}
|
|
4034
|
+
return Math.trunc(value);
|
|
4035
|
+
}
|
|
4036
|
+
function extractSessionWorkflowMetadata(record) {
|
|
4037
|
+
if (!record) return void 0;
|
|
4038
|
+
const out = {};
|
|
4039
|
+
let found = false;
|
|
4040
|
+
const assignString = (key, value) => {
|
|
4041
|
+
if (isNonEmptyString3(value)) {
|
|
4042
|
+
out[key] = value.trim();
|
|
4043
|
+
found = true;
|
|
4044
|
+
}
|
|
4045
|
+
};
|
|
4046
|
+
assignString("sessionId", record.sessionId);
|
|
4047
|
+
assignString("conversationId", record.conversationId);
|
|
4048
|
+
assignString("groupId", record.groupId);
|
|
4049
|
+
assignString("parentGroupId", record.parentGroupId);
|
|
4050
|
+
assignString("retryOf", record.retryOf);
|
|
4051
|
+
assignString("retryReason", record.retryReason);
|
|
4052
|
+
assignString("handoffFrom", record.handoffFrom);
|
|
4053
|
+
assignString("handoffTo", record.handoffTo);
|
|
4054
|
+
assignString("subAgentId", record.subAgentId);
|
|
4055
|
+
assignString("subAgentName", record.subAgentName);
|
|
4056
|
+
assignString("jobId", record.jobId);
|
|
4057
|
+
assignString("queueName", record.queueName);
|
|
4058
|
+
assignString("workflowName", record.workflowName);
|
|
4059
|
+
assignString("workflowStep", record.workflowStep);
|
|
4060
|
+
assignString("toolCallId", record.toolCallId);
|
|
4061
|
+
assignString("mcpToolCallId", record.mcpToolCallId);
|
|
4062
|
+
assignString("linkedStepId", record.linkedStepId);
|
|
4063
|
+
assignString("correlationId", record.correlationId);
|
|
4064
|
+
assignString("requestId", record.requestId);
|
|
4065
|
+
assignString("decisionId", record.decisionId);
|
|
4066
|
+
const attempt = finitePositiveInt(record.attempt);
|
|
4067
|
+
if (attempt !== void 0) {
|
|
4068
|
+
out.attempt = attempt;
|
|
4069
|
+
found = true;
|
|
4070
|
+
}
|
|
4071
|
+
return found ? out : void 0;
|
|
4072
|
+
}
|
|
4073
|
+
function sessionKeyForRun(meta, options) {
|
|
4074
|
+
if (meta?.sessionId) return meta.sessionId;
|
|
4075
|
+
if (options?.correlateByGroupId && meta?.groupId) {
|
|
4076
|
+
return `group:${meta.groupId}`;
|
|
4077
|
+
}
|
|
4078
|
+
return void 0;
|
|
4079
|
+
}
|
|
4080
|
+
|
|
4081
|
+
// packages/core/src/sessions/types.ts
|
|
4082
|
+
var SESSION_WORKFLOW_KEYS = [
|
|
4083
|
+
"sessionId",
|
|
4084
|
+
"conversationId",
|
|
4085
|
+
"groupId",
|
|
4086
|
+
"parentGroupId",
|
|
4087
|
+
"attempt",
|
|
4088
|
+
"retryOf",
|
|
4089
|
+
"retryReason",
|
|
4090
|
+
"handoffFrom",
|
|
4091
|
+
"handoffTo",
|
|
4092
|
+
"subAgentId",
|
|
4093
|
+
"subAgentName",
|
|
4094
|
+
"jobId",
|
|
4095
|
+
"queueName",
|
|
4096
|
+
"workflowName",
|
|
4097
|
+
"workflowStep",
|
|
4098
|
+
"toolCallId",
|
|
4099
|
+
"mcpToolCallId",
|
|
4100
|
+
"linkedStepId",
|
|
4101
|
+
"correlationId",
|
|
4102
|
+
"requestId",
|
|
4103
|
+
"decisionId"
|
|
4104
|
+
];
|
|
4105
|
+
|
|
4106
|
+
// packages/core/src/sessions/load.ts
|
|
4107
|
+
async function enrichSessionRunRecord(meta) {
|
|
4108
|
+
let metadata;
|
|
4109
|
+
try {
|
|
4110
|
+
const events = await readTraceEventsFromFile(meta.filePath);
|
|
4111
|
+
for (const event of events) {
|
|
4112
|
+
if (event.event !== "run_started") continue;
|
|
4113
|
+
if (event.metadata && typeof event.metadata === "object") {
|
|
4114
|
+
metadata = event.metadata;
|
|
4115
|
+
}
|
|
4116
|
+
break;
|
|
4117
|
+
}
|
|
4118
|
+
} catch {
|
|
4119
|
+
}
|
|
4120
|
+
return {
|
|
4121
|
+
runId: meta.runId,
|
|
4122
|
+
name: meta.name,
|
|
4123
|
+
status: meta.status,
|
|
4124
|
+
startedAt: meta.startedAt,
|
|
4125
|
+
endedAt: meta.endedAt,
|
|
4126
|
+
durationMs: meta.durationMs,
|
|
4127
|
+
filePath: meta.filePath,
|
|
4128
|
+
metadata
|
|
4129
|
+
};
|
|
4130
|
+
}
|
|
4131
|
+
async function loadSessionRunRecords(metas) {
|
|
4132
|
+
const out = [];
|
|
4133
|
+
for (const meta of metas) {
|
|
4134
|
+
out.push(await enrichSessionRunRecord(meta));
|
|
4135
|
+
}
|
|
4136
|
+
return out;
|
|
4137
|
+
}
|
|
4138
|
+
|
|
4139
|
+
// packages/core/src/sessions/scope.ts
|
|
4140
|
+
function metaToSessionRunRecord(meta) {
|
|
4141
|
+
return {
|
|
4142
|
+
runId: meta.runId,
|
|
4143
|
+
name: meta.name,
|
|
4144
|
+
status: meta.status,
|
|
4145
|
+
startedAt: meta.startedAt,
|
|
4146
|
+
endedAt: meta.endedAt,
|
|
4147
|
+
durationMs: meta.durationMs,
|
|
4148
|
+
filePath: meta.filePath,
|
|
4149
|
+
metadata: void 0
|
|
4150
|
+
};
|
|
4151
|
+
}
|
|
4152
|
+
function filterMetasBySessionScope(metas, records, options) {
|
|
4153
|
+
const sessionId = options.sessionId?.trim();
|
|
4154
|
+
const groupId = options.groupId?.trim();
|
|
4155
|
+
const warnings = [];
|
|
4156
|
+
if (sessionId) {
|
|
4157
|
+
const index = buildSessionIndex(records, {
|
|
4158
|
+
correlateByGroupId: options.correlateByGroupId === true
|
|
4159
|
+
});
|
|
4160
|
+
warnings.push(...index.warnings);
|
|
4161
|
+
const session = index.sessions.find((item) => item.sessionId === sessionId);
|
|
4162
|
+
if (!session) {
|
|
4163
|
+
return {
|
|
4164
|
+
metas: [],
|
|
4165
|
+
scopeLabel: sessionId,
|
|
4166
|
+
scopeKind: "session",
|
|
4167
|
+
runIds: [],
|
|
4168
|
+
warnings,
|
|
4169
|
+
notFound: true
|
|
4170
|
+
};
|
|
4171
|
+
}
|
|
4172
|
+
const runIdSet = new Set(session.runIds);
|
|
4173
|
+
const filtered = metas.filter((meta) => runIdSet.has(meta.runId));
|
|
4174
|
+
return {
|
|
4175
|
+
metas: filtered,
|
|
4176
|
+
scopeLabel: sessionId,
|
|
4177
|
+
scopeKind: "session",
|
|
4178
|
+
runIds: session.runIds,
|
|
4179
|
+
warnings,
|
|
4180
|
+
notFound: false
|
|
4181
|
+
};
|
|
4182
|
+
}
|
|
4183
|
+
if (groupId) {
|
|
4184
|
+
const runIds = records.filter((run) => extractSessionWorkflowMetadata(run.metadata)?.groupId === groupId).map((run) => run.runId).sort();
|
|
4185
|
+
if (runIds.length === 0) {
|
|
4186
|
+
return {
|
|
4187
|
+
metas: [],
|
|
4188
|
+
scopeLabel: groupId,
|
|
4189
|
+
scopeKind: "group",
|
|
4190
|
+
runIds: [],
|
|
4191
|
+
warnings,
|
|
4192
|
+
notFound: true
|
|
4193
|
+
};
|
|
4194
|
+
}
|
|
4195
|
+
const runIdSet = new Set(runIds);
|
|
4196
|
+
return {
|
|
4197
|
+
metas: metas.filter((meta) => runIdSet.has(meta.runId)),
|
|
4198
|
+
scopeLabel: groupId,
|
|
4199
|
+
scopeKind: "group",
|
|
4200
|
+
runIds,
|
|
4201
|
+
warnings,
|
|
4202
|
+
notFound: false
|
|
4203
|
+
};
|
|
4204
|
+
}
|
|
4205
|
+
return {
|
|
4206
|
+
metas: [...metas],
|
|
4207
|
+
scopeLabel: "",
|
|
4208
|
+
scopeKind: "session",
|
|
4209
|
+
runIds: [],
|
|
4210
|
+
warnings,
|
|
4211
|
+
notFound: false
|
|
4212
|
+
};
|
|
4213
|
+
}
|
|
4214
|
+
function traceMetasToSessionRunRecords(metas) {
|
|
4215
|
+
return metas.map(metaToSessionRunRecord);
|
|
4216
|
+
}
|
|
4217
|
+
|
|
4218
|
+
// packages/core/src/sessions/cohort.ts
|
|
4219
|
+
function groupSessionCohorts(runs, options = {}) {
|
|
4220
|
+
const groupBy = options.groupBy ?? "session";
|
|
4221
|
+
const cohorts = [];
|
|
4222
|
+
if (groupBy === "session") {
|
|
4223
|
+
const index = buildSessionIndex(runs, options);
|
|
4224
|
+
for (const session of index.sessions) {
|
|
4225
|
+
cohorts.push({
|
|
4226
|
+
key: session.sessionId,
|
|
4227
|
+
kind: "session",
|
|
4228
|
+
runIds: [...session.runIds]
|
|
4229
|
+
});
|
|
4230
|
+
}
|
|
4231
|
+
if (index.unscopedRunIds.length > 0) {
|
|
4232
|
+
cohorts.push({
|
|
4233
|
+
key: "__unscoped__",
|
|
4234
|
+
kind: "session",
|
|
4235
|
+
runIds: [...index.unscopedRunIds]
|
|
4236
|
+
});
|
|
4237
|
+
}
|
|
4238
|
+
return cohorts.sort((a, b) => a.key.localeCompare(b.key));
|
|
4239
|
+
}
|
|
4240
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
4241
|
+
const unscoped = [];
|
|
4242
|
+
for (const run of runs) {
|
|
4243
|
+
const groupId = extractSessionWorkflowMetadata(run.metadata)?.groupId;
|
|
4244
|
+
if (!groupId) {
|
|
4245
|
+
unscoped.push(run.runId);
|
|
4246
|
+
continue;
|
|
4247
|
+
}
|
|
4248
|
+
const bucket = byGroup.get(groupId) ?? [];
|
|
4249
|
+
bucket.push(run.runId);
|
|
4250
|
+
byGroup.set(groupId, bucket);
|
|
4251
|
+
}
|
|
4252
|
+
for (const [key, runIds] of [...byGroup.entries()].sort(
|
|
4253
|
+
([a], [b]) => a.localeCompare(b)
|
|
4254
|
+
)) {
|
|
4255
|
+
cohorts.push({
|
|
4256
|
+
key,
|
|
4257
|
+
kind: "group",
|
|
4258
|
+
runIds: runIds.sort()
|
|
4259
|
+
});
|
|
4260
|
+
}
|
|
4261
|
+
if (unscoped.length > 0) {
|
|
4262
|
+
cohorts.push({
|
|
4263
|
+
key: "__unscoped__",
|
|
4264
|
+
kind: "group",
|
|
4265
|
+
runIds: unscoped.sort()
|
|
4266
|
+
});
|
|
4267
|
+
}
|
|
4268
|
+
return cohorts;
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4271
|
+
// packages/core/src/sessions/checks.ts
|
|
4272
|
+
function emptySummary() {
|
|
4273
|
+
return { passed: 0, failed: 0, warnings: 0, errors: 0 };
|
|
4274
|
+
}
|
|
4275
|
+
function mergeSummary(target, source) {
|
|
4276
|
+
return {
|
|
4277
|
+
passed: target.passed + source.passed,
|
|
4278
|
+
failed: target.failed + source.failed,
|
|
4279
|
+
warnings: target.warnings + source.warnings,
|
|
4280
|
+
errors: target.errors + source.errors
|
|
4281
|
+
};
|
|
4282
|
+
}
|
|
4283
|
+
function sessionDiagnostic(code, message) {
|
|
4284
|
+
return { code, message, severity: "error" };
|
|
4285
|
+
}
|
|
4286
|
+
function aggregateSessionCheckResults(perRun, scope) {
|
|
4287
|
+
if (scope.notFound) {
|
|
4288
|
+
return {
|
|
4289
|
+
ok: false,
|
|
4290
|
+
status: "error",
|
|
4291
|
+
format: perRun[0]?.format ?? "agent-inspect-jsonl",
|
|
4292
|
+
scopeKind: scope.scopeKind,
|
|
4293
|
+
scopeLabel: scope.scopeLabel,
|
|
4294
|
+
runIds: [],
|
|
4295
|
+
runResults: [],
|
|
4296
|
+
summary: { ...emptySummary(), errors: 1 },
|
|
4297
|
+
findings: [],
|
|
4298
|
+
diagnostics: [
|
|
4299
|
+
sessionDiagnostic(
|
|
4300
|
+
"AI_CHECK_INVALID_ARGUMENTS",
|
|
4301
|
+
`${scope.scopeKind} not found: ${scope.scopeLabel}`
|
|
4302
|
+
)
|
|
4303
|
+
],
|
|
4304
|
+
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
4305
|
+
};
|
|
4306
|
+
}
|
|
4307
|
+
if (scope.empty || perRun.length === 0) {
|
|
4308
|
+
return {
|
|
4309
|
+
ok: false,
|
|
4310
|
+
status: "error",
|
|
4311
|
+
format: perRun[0]?.format ?? "agent-inspect-jsonl",
|
|
4312
|
+
scopeKind: scope.scopeKind,
|
|
4313
|
+
scopeLabel: scope.scopeLabel,
|
|
4314
|
+
runIds: scope.runIds,
|
|
4315
|
+
runResults: [],
|
|
4316
|
+
summary: { ...emptySummary(), errors: 1 },
|
|
4317
|
+
findings: [],
|
|
4318
|
+
diagnostics: [
|
|
4319
|
+
sessionDiagnostic(
|
|
4320
|
+
"AI_CHECK_TRACE_UNREADABLE",
|
|
4321
|
+
`No readable traces in ${scope.scopeKind}: ${scope.scopeLabel}`
|
|
4322
|
+
)
|
|
4323
|
+
],
|
|
4324
|
+
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
4325
|
+
};
|
|
4326
|
+
}
|
|
4327
|
+
let summary = emptySummary();
|
|
4328
|
+
const findings = [];
|
|
4329
|
+
const diagnostics = [];
|
|
4330
|
+
const runResults = [];
|
|
4331
|
+
for (const result of perRun) {
|
|
4332
|
+
summary = mergeSummary(summary, result.summary);
|
|
4333
|
+
findings.push(...result.findings);
|
|
4334
|
+
diagnostics.push(...result.diagnostics);
|
|
4335
|
+
if (result.runId) {
|
|
4336
|
+
runResults.push({ runId: result.runId, status: result.status });
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
runResults.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
4340
|
+
findings.sort((a, b) => {
|
|
4341
|
+
const runCmp = (a.evidence[0]?.runId ?? "").localeCompare(
|
|
4342
|
+
b.evidence[0]?.runId ?? ""
|
|
4343
|
+
);
|
|
4344
|
+
if (runCmp !== 0) return runCmp;
|
|
4345
|
+
return a.ruleId.localeCompare(b.ruleId);
|
|
4346
|
+
});
|
|
4347
|
+
const hasErrors = diagnostics.some((item) => item.severity === "error");
|
|
4348
|
+
const status = hasErrors ? "error" : summary.failed > 0 ? "fail" : "pass";
|
|
4349
|
+
return {
|
|
4350
|
+
ok: status === "pass",
|
|
4351
|
+
status,
|
|
4352
|
+
format: perRun[0]?.format ?? "agent-inspect-jsonl",
|
|
4353
|
+
scopeKind: scope.scopeKind,
|
|
4354
|
+
scopeLabel: scope.scopeLabel,
|
|
4355
|
+
runIds: scope.runIds,
|
|
4356
|
+
runResults,
|
|
4357
|
+
summary,
|
|
4358
|
+
findings,
|
|
4359
|
+
diagnostics,
|
|
4360
|
+
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
4361
|
+
};
|
|
4362
|
+
}
|
|
4363
|
+
|
|
4364
|
+
// packages/core/src/sessions/index.ts
|
|
4365
|
+
function compareRuns(a, b) {
|
|
4366
|
+
const aStart = a.startedAt ?? 0;
|
|
4367
|
+
const bStart = b.startedAt ?? 0;
|
|
4368
|
+
if (aStart !== bStart) return aStart - bStart;
|
|
4369
|
+
return a.runId.localeCompare(b.runId);
|
|
4370
|
+
}
|
|
4371
|
+
function buildGroups(runIds, metaByRunId) {
|
|
4372
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
4373
|
+
for (const runId of runIds) {
|
|
4374
|
+
const groupId = metaByRunId.get(runId)?.groupId;
|
|
4375
|
+
if (!groupId) continue;
|
|
4376
|
+
const existing = byGroup.get(groupId);
|
|
4377
|
+
if (existing) {
|
|
4378
|
+
existing.runIds.push(runId);
|
|
4379
|
+
} else {
|
|
4380
|
+
byGroup.set(groupId, {
|
|
4381
|
+
groupId,
|
|
4382
|
+
parentGroupId: metaByRunId.get(runId)?.parentGroupId,
|
|
4383
|
+
runIds: [runId]
|
|
4384
|
+
});
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4387
|
+
return [...byGroup.values()].map((group) => ({
|
|
4388
|
+
...group,
|
|
4389
|
+
runIds: [...group.runIds].sort((a, b) => a.localeCompare(b))
|
|
4390
|
+
}));
|
|
4391
|
+
}
|
|
4392
|
+
function buildHandoffs(runIds, metaByRunId, warnings, sessionId) {
|
|
4393
|
+
const edges = [];
|
|
4394
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4395
|
+
const pushEdge = (edge) => {
|
|
4396
|
+
const key = `${edge.from}->${edge.to}:${edge.confidence}`;
|
|
4397
|
+
if (seen.has(key)) return;
|
|
4398
|
+
seen.add(key);
|
|
4399
|
+
edges.push(edge);
|
|
4400
|
+
};
|
|
4401
|
+
for (const runId of runIds) {
|
|
4402
|
+
const meta = metaByRunId.get(runId);
|
|
4403
|
+
if (!meta) continue;
|
|
4404
|
+
if (meta.handoffFrom && meta.handoffTo) {
|
|
4405
|
+
pushEdge({
|
|
4406
|
+
from: meta.handoffFrom,
|
|
4407
|
+
to: meta.handoffTo,
|
|
4408
|
+
source: "manual",
|
|
4409
|
+
confidence: "explicit"
|
|
4410
|
+
});
|
|
4411
|
+
continue;
|
|
4412
|
+
}
|
|
4413
|
+
if (meta.handoffFrom) {
|
|
4414
|
+
pushEdge({
|
|
4415
|
+
from: meta.handoffFrom,
|
|
4416
|
+
to: runId,
|
|
4417
|
+
source: "manual",
|
|
4418
|
+
confidence: "explicit"
|
|
4419
|
+
});
|
|
4420
|
+
}
|
|
4421
|
+
if (meta.handoffTo) {
|
|
4422
|
+
pushEdge({
|
|
4423
|
+
from: runId,
|
|
4424
|
+
to: meta.handoffTo,
|
|
4425
|
+
source: "manual",
|
|
4426
|
+
confidence: "explicit"
|
|
4427
|
+
});
|
|
4428
|
+
}
|
|
4429
|
+
if (meta.subAgentId && meta.parentGroupId && !meta.handoffFrom && !meta.handoffTo) {
|
|
4430
|
+
pushEdge({
|
|
4431
|
+
from: meta.parentGroupId,
|
|
4432
|
+
to: meta.subAgentId,
|
|
4433
|
+
source: "inferred",
|
|
4434
|
+
confidence: "correlated"
|
|
4435
|
+
});
|
|
4436
|
+
warnings.push({
|
|
4437
|
+
code: "ambiguous-handoff-endpoints",
|
|
4438
|
+
message: "Handoff inferred from parentGroupId and subAgentId without explicit handoffFrom/handoffTo.",
|
|
4439
|
+
runId,
|
|
4440
|
+
sessionId
|
|
4441
|
+
});
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
return edges.sort((a, b) => {
|
|
4445
|
+
const from = a.from.localeCompare(b.from);
|
|
4446
|
+
if (from !== 0) return from;
|
|
4447
|
+
return a.to.localeCompare(b.to);
|
|
4448
|
+
});
|
|
4449
|
+
}
|
|
4450
|
+
function buildRetries(runIds, metaByRunId, warnings, sessionId) {
|
|
4451
|
+
const retries = [];
|
|
4452
|
+
for (const runId of runIds) {
|
|
4453
|
+
const meta = metaByRunId.get(runId);
|
|
4454
|
+
if (!meta) continue;
|
|
4455
|
+
if (meta.retryOf) {
|
|
4456
|
+
retries.push({
|
|
4457
|
+
runId,
|
|
4458
|
+
retryOf: meta.retryOf,
|
|
4459
|
+
attempt: meta.attempt,
|
|
4460
|
+
source: "manual",
|
|
4461
|
+
confidence: "explicit"
|
|
4462
|
+
});
|
|
4463
|
+
continue;
|
|
4464
|
+
}
|
|
4465
|
+
if (meta.attempt !== void 0 && meta.attempt > 1) {
|
|
4466
|
+
retries.push({
|
|
4467
|
+
runId,
|
|
4468
|
+
attempt: meta.attempt,
|
|
4469
|
+
source: "inferred",
|
|
4470
|
+
confidence: "correlated"
|
|
4471
|
+
});
|
|
4472
|
+
warnings.push({
|
|
4473
|
+
code: "ambiguous-retry-link",
|
|
4474
|
+
message: "attempt > 1 without retryOf; retry link is correlated only.",
|
|
4475
|
+
runId,
|
|
4476
|
+
sessionId
|
|
4477
|
+
});
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
return retries.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
4481
|
+
}
|
|
4482
|
+
function buildCriticalPath(runs, handoffs) {
|
|
4483
|
+
const runById = new Map(runs.map((run) => [run.runId, run]));
|
|
4484
|
+
const explicitTargets = new Set(
|
|
4485
|
+
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.to)
|
|
4486
|
+
);
|
|
4487
|
+
const explicitSources = new Set(
|
|
4488
|
+
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
4489
|
+
);
|
|
4490
|
+
const ordered = [...runs].sort(compareRuns);
|
|
4491
|
+
const path5 = [];
|
|
4492
|
+
const visited = /* @__PURE__ */ new Set();
|
|
4493
|
+
const pushRun = (run, confidence, source) => {
|
|
4494
|
+
if (visited.has(run.runId)) return;
|
|
4495
|
+
visited.add(run.runId);
|
|
4496
|
+
path5.push({
|
|
4497
|
+
runId: run.runId,
|
|
4498
|
+
name: run.name,
|
|
4499
|
+
startedAt: run.startedAt,
|
|
4500
|
+
durationMs: run.durationMs,
|
|
4501
|
+
confidence,
|
|
4502
|
+
source
|
|
4503
|
+
});
|
|
4504
|
+
};
|
|
4505
|
+
for (const edge of handoffs) {
|
|
4506
|
+
if (edge.confidence !== "explicit") continue;
|
|
4507
|
+
const fromRun = [...runById.values()].find(
|
|
4508
|
+
(run) => run.runId === edge.from || metaRunIdMatches(run, edge.from, runById)
|
|
4509
|
+
);
|
|
4510
|
+
const toRun = [...runById.values()].find(
|
|
4511
|
+
(run) => run.runId === edge.to || metaRunIdMatches(run, edge.to, runById)
|
|
4512
|
+
);
|
|
4513
|
+
if (fromRun) pushRun(fromRun, "explicit", "manual");
|
|
4514
|
+
if (toRun) pushRun(toRun, "explicit", "manual");
|
|
4515
|
+
}
|
|
4516
|
+
for (const run of ordered) {
|
|
4517
|
+
if (visited.has(run.runId)) continue;
|
|
4518
|
+
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
4519
|
+
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
4520
|
+
}
|
|
4521
|
+
return path5;
|
|
4522
|
+
}
|
|
4523
|
+
function metaRunIdMatches(run, token, runById) {
|
|
4524
|
+
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
4525
|
+
return meta?.subAgentId === token || meta?.groupId === token || runById.has(token);
|
|
4526
|
+
}
|
|
4527
|
+
function buildSessionIndex(inputRuns, options = {}) {
|
|
4528
|
+
const warnings = [];
|
|
4529
|
+
const runs = [...inputRuns].sort(compareRuns);
|
|
4530
|
+
const metaByRunId = /* @__PURE__ */ new Map();
|
|
4531
|
+
for (const run of runs) {
|
|
4532
|
+
metaByRunId.set(run.runId, extractSessionWorkflowMetadata(run.metadata));
|
|
4533
|
+
}
|
|
4534
|
+
const sessionsByKey = /* @__PURE__ */ new Map();
|
|
4535
|
+
const unscopedRunIds = [];
|
|
4536
|
+
for (const run of runs) {
|
|
4537
|
+
const meta = metaByRunId.get(run.runId);
|
|
4538
|
+
const key = sessionKeyForRun(meta, {
|
|
4539
|
+
correlateByGroupId: options.correlateByGroupId === true
|
|
4540
|
+
});
|
|
4541
|
+
if (!key) {
|
|
4542
|
+
unscopedRunIds.push(run.runId);
|
|
4543
|
+
continue;
|
|
4544
|
+
}
|
|
4545
|
+
const bucket = sessionsByKey.get(key) ?? [];
|
|
4546
|
+
bucket.push(run);
|
|
4547
|
+
sessionsByKey.set(key, bucket);
|
|
4548
|
+
}
|
|
4549
|
+
const sessions = [...sessionsByKey.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([sessionId, sessionRuns]) => {
|
|
4550
|
+
const runIds = sessionRuns.map((run) => run.runId).sort();
|
|
4551
|
+
const handoffs = buildHandoffs(runIds, metaByRunId, warnings, sessionId);
|
|
4552
|
+
const retries = buildRetries(runIds, metaByRunId, warnings, sessionId);
|
|
4553
|
+
const groups = buildGroups(runIds, metaByRunId);
|
|
4554
|
+
const criticalPath = buildCriticalPath(sessionRuns, handoffs);
|
|
4555
|
+
const confidences = new Set(handoffs.map((edge) => edge.confidence));
|
|
4556
|
+
if (confidences.has("explicit") && confidences.has("correlated")) {
|
|
4557
|
+
warnings.push({
|
|
4558
|
+
code: "mixed-confidence-group",
|
|
4559
|
+
message: "Session aggregates explicit and correlated handoff edges.",
|
|
4560
|
+
sessionId
|
|
4561
|
+
});
|
|
4562
|
+
}
|
|
4563
|
+
return {
|
|
4564
|
+
sessionId,
|
|
4565
|
+
runIds,
|
|
4566
|
+
groups,
|
|
4567
|
+
handoffs,
|
|
4568
|
+
retries,
|
|
4569
|
+
criticalPath
|
|
4570
|
+
};
|
|
4571
|
+
});
|
|
4572
|
+
if (sessions.length === 0 && runs.length > 0) {
|
|
4573
|
+
warnings.push({
|
|
4574
|
+
code: "missing-session-id",
|
|
4575
|
+
message: "No sessionId (or correlated groupId) found on input runs."
|
|
4576
|
+
});
|
|
4577
|
+
}
|
|
4578
|
+
warnings.sort((a, b) => {
|
|
4579
|
+
const code = a.code.localeCompare(b.code);
|
|
4580
|
+
if (code !== 0) return code;
|
|
4581
|
+
return (a.runId ?? "").localeCompare(b.runId ?? "");
|
|
4582
|
+
});
|
|
4583
|
+
return {
|
|
4584
|
+
runs,
|
|
4585
|
+
sessions,
|
|
4586
|
+
unscopedRunIds: unscopedRunIds.sort(),
|
|
4587
|
+
warnings
|
|
4588
|
+
};
|
|
4589
|
+
}
|
|
4022
4590
|
var KNOWN_EVENTS = /* @__PURE__ */ new Set([
|
|
4023
4591
|
"run_started",
|
|
4024
4592
|
"run_completed",
|
|
@@ -4202,19 +4770,25 @@ exports.MAX_NAME_LENGTH = MAX_NAME_LENGTH;
|
|
|
4202
4770
|
exports.MAX_TERMINAL_DEPTH = MAX_TERMINAL_DEPTH;
|
|
4203
4771
|
exports.MAX_TERMINAL_NAME_LENGTH = MAX_TERMINAL_NAME_LENGTH;
|
|
4204
4772
|
exports.RUNS_DIR_NAME = RUNS_DIR_NAME;
|
|
4773
|
+
exports.SESSION_WORKFLOW_KEYS = SESSION_WORKFLOW_KEYS;
|
|
4205
4774
|
exports.TERMINAL_INDENT = TERMINAL_INDENT;
|
|
4206
4775
|
exports.TraceDirectory = TraceDirectory;
|
|
4776
|
+
exports.aggregateSessionCheckResults = aggregateSessionCheckResults;
|
|
4207
4777
|
exports.buildLocalExplanation = buildLocalExplanation;
|
|
4208
4778
|
exports.buildRunSummary = buildRunSummary;
|
|
4209
4779
|
exports.buildRunTimeline = buildRunTimeline;
|
|
4210
4780
|
exports.buildRunWhatSummary = buildRunWhatSummary;
|
|
4781
|
+
exports.buildSessionIndex = buildSessionIndex;
|
|
4211
4782
|
exports.buildTraceStats = buildTraceStats;
|
|
4212
4783
|
exports.createInspector = createInspector;
|
|
4213
4784
|
exports.createInspectorRuntime = createInspectorRuntime;
|
|
4214
4785
|
exports.createRunId = createRunId;
|
|
4215
4786
|
exports.createStepId = createStepId;
|
|
4787
|
+
exports.enrichSessionRunRecord = enrichSessionRunRecord;
|
|
4216
4788
|
exports.ensureTraceDir = ensureTraceDir;
|
|
4217
4789
|
exports.extractMetadata = extractMetadata;
|
|
4790
|
+
exports.extractSessionWorkflowMetadata = extractSessionWorkflowMetadata;
|
|
4791
|
+
exports.filterMetasBySessionScope = filterMetasBySessionScope;
|
|
4218
4792
|
exports.filterTraces = filterTraces;
|
|
4219
4793
|
exports.formatDuration = formatDuration2;
|
|
4220
4794
|
exports.formatError = formatError;
|
|
@@ -4233,6 +4807,7 @@ exports.getRunIdFromTraceFileName = getRunIdFromTraceFileName;
|
|
|
4233
4807
|
exports.getTraceDirFromContext = getTraceDirFromContext;
|
|
4234
4808
|
exports.getTraceFilePath = getTraceFilePath;
|
|
4235
4809
|
exports.getTraceSafetyFromContext = getTraceSafetyFromContext;
|
|
4810
|
+
exports.groupSessionCohorts = groupSessionCohorts;
|
|
4236
4811
|
exports.hasActiveContext = hasActiveContext;
|
|
4237
4812
|
exports.initializeTraceFile = initializeTraceFile;
|
|
4238
4813
|
exports.isAgentInspectEnabled = isAgentInspectEnabled;
|
|
@@ -4242,6 +4817,7 @@ exports.isStepStatus = isStepStatus;
|
|
|
4242
4817
|
exports.isStepType = isStepType;
|
|
4243
4818
|
exports.isTraceEvent = isTraceEvent;
|
|
4244
4819
|
exports.listTraceFiles = listTraceFiles;
|
|
4820
|
+
exports.loadSessionRunRecords = loadSessionRunRecords;
|
|
4245
4821
|
exports.loadTraceMetadataList = loadTraceMetadataList;
|
|
4246
4822
|
exports.maybeInspectRun = maybeInspectRun;
|
|
4247
4823
|
exports.parseDuration = parseDuration;
|
|
@@ -4270,6 +4846,8 @@ exports.runWithContext = runWithContext;
|
|
|
4270
4846
|
exports.runWithStepContext = runWithStepContext;
|
|
4271
4847
|
exports.searchTraces = searchTraces;
|
|
4272
4848
|
exports.serializeEvent = serializeEvent;
|
|
4849
|
+
exports.sessionKeyForRun = sessionKeyForRun;
|
|
4850
|
+
exports.traceMetasToSessionRunRecords = traceMetasToSessionRunRecords;
|
|
4273
4851
|
exports.truncateName = truncateName;
|
|
4274
4852
|
exports.unknownTraceFormatMessage = unknownTraceFormatMessage;
|
|
4275
4853
|
exports.validateEvent = validateEvent;
|