@agent-inspect/viewer 6.31.7 → 6.31.9
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 +198 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +198 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -771,7 +771,18 @@ async function readTraceEventsFromFile(filePath) {
|
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
// packages/core/src/context.ts
|
|
774
|
-
|
|
774
|
+
var GLOBAL_CONTEXT_ALS_KEY = "agent-inspect:execution-context-als:v1";
|
|
775
|
+
function getSharedContextStorage() {
|
|
776
|
+
const host = globalThis;
|
|
777
|
+
const existing = host[GLOBAL_CONTEXT_ALS_KEY];
|
|
778
|
+
if (existing instanceof async_hooks.AsyncLocalStorage) {
|
|
779
|
+
return existing;
|
|
780
|
+
}
|
|
781
|
+
const created = new async_hooks.AsyncLocalStorage();
|
|
782
|
+
host[GLOBAL_CONTEXT_ALS_KEY] = created;
|
|
783
|
+
return created;
|
|
784
|
+
}
|
|
785
|
+
getSharedContextStorage();
|
|
775
786
|
|
|
776
787
|
// packages/core/src/outcomes/types.ts
|
|
777
788
|
var OBSERVED_OUTCOME_METHODS = [
|
|
@@ -1374,7 +1385,7 @@ function enrichSessionSummary(summary, runs, options = {}) {
|
|
|
1374
1385
|
}
|
|
1375
1386
|
const lastMs = latestActivityMs(sessionRuns);
|
|
1376
1387
|
const lastActivity = lastMs > 0 ? new Date(lastMs).toISOString() : (/* @__PURE__ */ new Date(0)).toISOString();
|
|
1377
|
-
const
|
|
1388
|
+
const retryCount2 = summary.retries.filter(
|
|
1378
1389
|
(retry) => retry.retryOf !== void 0 || (retry.attempt ?? 0) > 1
|
|
1379
1390
|
).length;
|
|
1380
1391
|
return {
|
|
@@ -1388,7 +1399,7 @@ function enrichSessionSummary(summary, runs, options = {}) {
|
|
|
1388
1399
|
workflowId,
|
|
1389
1400
|
lastError: deriveLastError(sessionRuns),
|
|
1390
1401
|
lastActivity,
|
|
1391
|
-
retryCount,
|
|
1402
|
+
retryCount: retryCount2,
|
|
1392
1403
|
observationSummary: deriveObservationSummary(sessionRuns),
|
|
1393
1404
|
checkSummary: deriveCheckSummary(sessionRuns)
|
|
1394
1405
|
};
|
|
@@ -2261,6 +2272,13 @@ function metadataStringAttr(event, keys) {
|
|
|
2261
2272
|
}
|
|
2262
2273
|
return void 0;
|
|
2263
2274
|
}
|
|
2275
|
+
function numericAttr(event, keys) {
|
|
2276
|
+
for (const key of keys) {
|
|
2277
|
+
const value = event.attributes?.[key];
|
|
2278
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2279
|
+
}
|
|
2280
|
+
return void 0;
|
|
2281
|
+
}
|
|
2264
2282
|
function stripPrefix(name, prefixes) {
|
|
2265
2283
|
for (const prefix of prefixes) {
|
|
2266
2284
|
if (name.startsWith(prefix)) return name.slice(prefix.length);
|
|
@@ -2316,9 +2334,12 @@ function llmFinishReason(event) {
|
|
|
2316
2334
|
const keys = ["finishReason", "rawFinishReason", "finish_reason"];
|
|
2317
2335
|
return stringAttr(event, keys) ?? metadataStringAttr(event, keys);
|
|
2318
2336
|
}
|
|
2337
|
+
function retryCount(event) {
|
|
2338
|
+
return numericAttr(event, ["retryCount", "retryAttempt", "retry_attempt", "attempt"]);
|
|
2339
|
+
}
|
|
2319
2340
|
function finishedEvents(context, kind) {
|
|
2320
2341
|
return semanticEvents(context).filter(
|
|
2321
|
-
(event) => (event.kind === kind) && event.status !== "running"
|
|
2342
|
+
(event) => (kind === void 0 || event.kind === kind) && event.status !== "running"
|
|
2322
2343
|
);
|
|
2323
2344
|
}
|
|
2324
2345
|
function toolInvocationEvents(context) {
|
|
@@ -2383,6 +2404,35 @@ function createRunDurationRule(options) {
|
|
|
2383
2404
|
}
|
|
2384
2405
|
};
|
|
2385
2406
|
}
|
|
2407
|
+
function createRunDepthRule(options) {
|
|
2408
|
+
return {
|
|
2409
|
+
id: "run.depth",
|
|
2410
|
+
category: "run",
|
|
2411
|
+
defaultSeverity: "error",
|
|
2412
|
+
evaluate(context) {
|
|
2413
|
+
const nodes = [...context.nodesByEventId.values()];
|
|
2414
|
+
const maxDepth = nodes.reduce((max, node) => Math.max(max, node.depth), 0);
|
|
2415
|
+
if (maxDepth <= options.maxDepth) return [];
|
|
2416
|
+
const deepest = nodes.filter((node) => node.depth === maxDepth);
|
|
2417
|
+
return [
|
|
2418
|
+
failFinding(
|
|
2419
|
+
"run.depth",
|
|
2420
|
+
`Run depth ${maxDepth} exceeded ${options.maxDepth}.`,
|
|
2421
|
+
deepest.map((node) => ({
|
|
2422
|
+
runId: node.event.runId,
|
|
2423
|
+
eventId: node.event.eventId,
|
|
2424
|
+
parentId: node.event.parentId,
|
|
2425
|
+
kind: node.event.kind,
|
|
2426
|
+
name: node.event.name,
|
|
2427
|
+
status: node.event.status
|
|
2428
|
+
})),
|
|
2429
|
+
{ maxDepth: options.maxDepth },
|
|
2430
|
+
maxDepth
|
|
2431
|
+
)
|
|
2432
|
+
];
|
|
2433
|
+
}
|
|
2434
|
+
};
|
|
2435
|
+
}
|
|
2386
2436
|
function createToolUsageRule(options) {
|
|
2387
2437
|
return {
|
|
2388
2438
|
id: "tool.usage",
|
|
@@ -2447,6 +2497,45 @@ function createToolUsageRule(options) {
|
|
|
2447
2497
|
}
|
|
2448
2498
|
};
|
|
2449
2499
|
}
|
|
2500
|
+
function createToolFailureRule(options) {
|
|
2501
|
+
return {
|
|
2502
|
+
id: "tool.failures",
|
|
2503
|
+
category: "tool",
|
|
2504
|
+
defaultSeverity: "error",
|
|
2505
|
+
evaluate(context) {
|
|
2506
|
+
const tools = finishedEvents(context, "TOOL");
|
|
2507
|
+
const failures = tools.filter((event) => event.status === "error");
|
|
2508
|
+
const retries = tools.map((event) => ({ event, count: retryCount(event) })).filter((item) => item.count !== void 0);
|
|
2509
|
+
const findings = [];
|
|
2510
|
+
if (options.maxFailures !== void 0 && failures.length > options.maxFailures) {
|
|
2511
|
+
findings.push(
|
|
2512
|
+
failFinding(
|
|
2513
|
+
"tool.failures",
|
|
2514
|
+
`Tool failure count ${failures.length} exceeded ${options.maxFailures}.`,
|
|
2515
|
+
failures.map((event) => eventEvidence(event)),
|
|
2516
|
+
{ maxFailures: options.maxFailures },
|
|
2517
|
+
failures.length
|
|
2518
|
+
)
|
|
2519
|
+
);
|
|
2520
|
+
}
|
|
2521
|
+
if (options.maxRetries !== void 0) {
|
|
2522
|
+
const excessiveRetries = retries.filter((item) => item.count > options.maxRetries);
|
|
2523
|
+
if (excessiveRetries.length > 0) {
|
|
2524
|
+
findings.push(
|
|
2525
|
+
failFinding(
|
|
2526
|
+
"tool.failures",
|
|
2527
|
+
`Tool retry count exceeded ${options.maxRetries}.`,
|
|
2528
|
+
excessiveRetries.map((item) => eventEvidence(item.event, "attributes.retryCount")),
|
|
2529
|
+
{ maxRetries: options.maxRetries },
|
|
2530
|
+
excessiveRetries.map((item) => ({ tool: toolName(item.event), retries: item.count }))
|
|
2531
|
+
)
|
|
2532
|
+
);
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
return findings;
|
|
2536
|
+
}
|
|
2537
|
+
};
|
|
2538
|
+
}
|
|
2450
2539
|
function createLlmUsageRule(options) {
|
|
2451
2540
|
return {
|
|
2452
2541
|
id: "llm.usage",
|
|
@@ -3892,8 +3981,13 @@ function persistedInspectEventsToInspectEvents(events, options) {
|
|
|
3892
3981
|
}
|
|
3893
3982
|
|
|
3894
3983
|
// packages/core/src/persisted/tree-bridge.ts
|
|
3984
|
+
function logicalToPersisted(event) {
|
|
3985
|
+
const { sourceEventIds: _sourceEventIds, projection: _projection, ...rest } = event;
|
|
3986
|
+
return rest;
|
|
3987
|
+
}
|
|
3895
3988
|
function persistedInspectEventsToRunTrees(events, options) {
|
|
3896
|
-
const
|
|
3989
|
+
const sourceEvents = options?.coalesceLifecycle === true ? projectLogicalEvents(events).logicalEvents.map(logicalToPersisted) : events;
|
|
3990
|
+
const inspectEvents = persistedInspectEventsToInspectEvents(sourceEvents, {
|
|
3897
3991
|
skipInvalid: options?.skipInvalid
|
|
3898
3992
|
});
|
|
3899
3993
|
return new TreeBuilder().build(inspectEvents);
|
|
@@ -4587,7 +4681,7 @@ function mapOpenInferenceSpan(span, index, version) {
|
|
|
4587
4681
|
const errorMessage = isRecord7(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
|
|
4588
4682
|
const event = {
|
|
4589
4683
|
schemaVersion: "0.2",
|
|
4590
|
-
eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId
|
|
4684
|
+
eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : `${traceId}:${spanId}`,
|
|
4591
4685
|
runId: typeof rawAttributes["agent_inspect.run_id"] === "string" ? rawAttributes["agent_inspect.run_id"] : traceId,
|
|
4592
4686
|
kind,
|
|
4593
4687
|
name,
|
|
@@ -4638,12 +4732,16 @@ function mapOpenInferenceEvents(document) {
|
|
|
4638
4732
|
const mapped = document.spans.map(
|
|
4639
4733
|
(span, index) => mapOpenInferenceSpan(span, index, document.version)
|
|
4640
4734
|
);
|
|
4641
|
-
const
|
|
4642
|
-
mapped.map((span) =>
|
|
4735
|
+
const spanKeyToEventId = new Map(
|
|
4736
|
+
mapped.map((span) => {
|
|
4737
|
+
const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
|
|
4738
|
+
return [`${traceId}:${span.spanId}`, span.event.eventId];
|
|
4739
|
+
})
|
|
4643
4740
|
);
|
|
4644
4741
|
for (const span of mapped) {
|
|
4645
4742
|
if (span.parentSpanId === void 0) continue;
|
|
4646
|
-
span.event.
|
|
4743
|
+
const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
|
|
4744
|
+
span.event.parentId = spanKeyToEventId.get(`${traceId}:${span.parentSpanId}`) ?? span.parentSpanId;
|
|
4647
4745
|
}
|
|
4648
4746
|
return {
|
|
4649
4747
|
events: mapped.map((span) => span.event),
|
|
@@ -5192,7 +5290,7 @@ function mapOtlpSpan(context) {
|
|
|
5192
5290
|
const errorMessage = isRecord7(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
|
|
5193
5291
|
const event = {
|
|
5194
5292
|
schemaVersion: "0.2",
|
|
5195
|
-
eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId
|
|
5293
|
+
eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : `${traceId}:${spanId}`,
|
|
5196
5294
|
runId: typeof parsedSpanAttributes.attributes["agent_inspect.run_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.run_id"] : traceId,
|
|
5197
5295
|
kind,
|
|
5198
5296
|
name: readStringField(span, ["name"]) ?? spanId,
|
|
@@ -5241,12 +5339,16 @@ function mapOtlpSpan(context) {
|
|
|
5241
5339
|
}
|
|
5242
5340
|
function mapOtlpEventsToPersisted(document) {
|
|
5243
5341
|
const mapped = document.spans.map((span) => mapOtlpSpan(span));
|
|
5244
|
-
const
|
|
5245
|
-
mapped.map((span) =>
|
|
5342
|
+
const spanKeyToEventId = new Map(
|
|
5343
|
+
mapped.map((span) => {
|
|
5344
|
+
const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
|
|
5345
|
+
return [`${traceId}:${span.spanId}`, span.event.eventId];
|
|
5346
|
+
})
|
|
5246
5347
|
);
|
|
5247
5348
|
for (const span of mapped) {
|
|
5248
5349
|
if (span.parentSpanId === void 0) continue;
|
|
5249
|
-
span.event.
|
|
5350
|
+
const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
|
|
5351
|
+
span.event.parentId = spanKeyToEventId.get(`${traceId}:${span.parentSpanId}`) ?? span.parentSpanId;
|
|
5250
5352
|
}
|
|
5251
5353
|
return {
|
|
5252
5354
|
events: mapped.map((span) => span.event),
|
|
@@ -5537,21 +5639,48 @@ function openTrace(input, options = {}) {
|
|
|
5537
5639
|
}
|
|
5538
5640
|
|
|
5539
5641
|
// packages/core/src/suite/run.ts
|
|
5642
|
+
var KNOWN_SUITE_SELECT_IDS = /* @__PURE__ */ new Set([
|
|
5643
|
+
"run.status",
|
|
5644
|
+
"run.duration",
|
|
5645
|
+
"run.depth",
|
|
5646
|
+
"outcome.status",
|
|
5647
|
+
"tool.usage",
|
|
5648
|
+
"tool.failures",
|
|
5649
|
+
"llm.usage"
|
|
5650
|
+
]);
|
|
5540
5651
|
function diagnostic4(code, message, severity = "error", caseId) {
|
|
5541
5652
|
return { code, message, severity, ...caseId !== void 0 ? { caseId } : {} };
|
|
5542
5653
|
}
|
|
5543
|
-
function
|
|
5654
|
+
function buildCaseAssertions(suiteCase, config) {
|
|
5544
5655
|
const rules = [];
|
|
5545
5656
|
const select = new Set(config.checks?.select ?? []);
|
|
5546
|
-
|
|
5657
|
+
const configDiagnostics = [];
|
|
5658
|
+
const evalConfig = config.eval;
|
|
5659
|
+
const declaredSelect = [...select];
|
|
5660
|
+
for (const id of declaredSelect) {
|
|
5661
|
+
if (!KNOWN_SUITE_SELECT_IDS.has(id)) {
|
|
5662
|
+
configDiagnostics.push(
|
|
5663
|
+
diagnostic4(
|
|
5664
|
+
"AI_SUITE_UNKNOWN_SELECTOR",
|
|
5665
|
+
`Unknown or unsupported suite check selector "${id}".`,
|
|
5666
|
+
"error",
|
|
5667
|
+
suiteCase.id
|
|
5668
|
+
)
|
|
5669
|
+
);
|
|
5670
|
+
}
|
|
5671
|
+
}
|
|
5672
|
+
if (select.has("run.status") || evalConfig?.requireSuccess === true) {
|
|
5547
5673
|
rules.push(createRunStatusRule());
|
|
5674
|
+
select.add("run.status");
|
|
5548
5675
|
}
|
|
5549
5676
|
const requiredTools = [
|
|
5550
5677
|
...config.checks?.tool?.required ?? [],
|
|
5678
|
+
...evalConfig?.requiredTools ?? [],
|
|
5551
5679
|
...suiteCase.requireTools ?? []
|
|
5552
5680
|
];
|
|
5553
5681
|
const forbiddenTools = [
|
|
5554
5682
|
...config.checks?.tool?.forbidden ?? [],
|
|
5683
|
+
...evalConfig?.forbiddenTools ?? [],
|
|
5555
5684
|
...suiteCase.forbidTools ?? []
|
|
5556
5685
|
];
|
|
5557
5686
|
if (requiredTools.length > 0 || forbiddenTools.length > 0) {
|
|
@@ -5563,20 +5692,51 @@ function buildCaseRules(suiteCase, config) {
|
|
|
5563
5692
|
);
|
|
5564
5693
|
select.add("tool.usage");
|
|
5565
5694
|
}
|
|
5566
|
-
const maxDurationMs = suiteCase.maxDurationMs ?? config.checks?.run?.maxDurationMs ??
|
|
5695
|
+
const maxDurationMs = suiteCase.maxDurationMs ?? config.checks?.run?.maxDurationMs ?? evalConfig?.maxDurationMs;
|
|
5567
5696
|
if (maxDurationMs !== void 0) {
|
|
5568
5697
|
rules.push(createRunDurationRule({ maxDurationMs }));
|
|
5569
5698
|
select.add("run.duration");
|
|
5570
5699
|
}
|
|
5571
|
-
const
|
|
5572
|
-
if (
|
|
5573
|
-
rules.push(
|
|
5700
|
+
const maxDepth = config.checks?.run?.maxDepth ?? evalConfig?.maxDepth;
|
|
5701
|
+
if (maxDepth !== void 0) {
|
|
5702
|
+
rules.push(createRunDepthRule({ maxDepth }));
|
|
5703
|
+
select.add("run.depth");
|
|
5704
|
+
}
|
|
5705
|
+
if (evalConfig?.maxRetries !== void 0) {
|
|
5706
|
+
rules.push(createToolFailureRule({ maxRetries: evalConfig.maxRetries }));
|
|
5707
|
+
select.add("tool.failures");
|
|
5708
|
+
}
|
|
5709
|
+
const allowedModels = config.checks?.llm?.allowedModels;
|
|
5710
|
+
const maxTotalTokens = config.checks?.llm?.maxTotalTokens ?? evalConfig?.maxTotalTokens;
|
|
5711
|
+
if (allowedModels !== void 0 || maxTotalTokens !== void 0) {
|
|
5712
|
+
rules.push(
|
|
5713
|
+
createLlmUsageRule({
|
|
5714
|
+
...allowedModels !== void 0 ? { allowedModels } : {},
|
|
5715
|
+
...maxTotalTokens !== void 0 ? { maxTotalTokens } : {}
|
|
5716
|
+
})
|
|
5717
|
+
);
|
|
5574
5718
|
select.add("llm.usage");
|
|
5575
5719
|
}
|
|
5576
5720
|
if (select.has("outcome.status")) {
|
|
5577
5721
|
rules.push(createObservedOutcomeRule({ failOn: ["failed"] }));
|
|
5578
5722
|
}
|
|
5579
|
-
|
|
5723
|
+
const observationCount = suiteCase.expectedObservations?.length ?? 0;
|
|
5724
|
+
if (rules.length === 0 && observationCount === 0 && configDiagnostics.length === 0) {
|
|
5725
|
+
configDiagnostics.push(
|
|
5726
|
+
diagnostic4(
|
|
5727
|
+
"AI_SUITE_NO_ASSERTIONS",
|
|
5728
|
+
`Suite case "${suiteCase.id}" declares no effective checks, eval controls, or expected observations.`,
|
|
5729
|
+
"error",
|
|
5730
|
+
suiteCase.id
|
|
5731
|
+
)
|
|
5732
|
+
);
|
|
5733
|
+
}
|
|
5734
|
+
return {
|
|
5735
|
+
rules,
|
|
5736
|
+
select: [...select],
|
|
5737
|
+
observationCount,
|
|
5738
|
+
configDiagnostics
|
|
5739
|
+
};
|
|
5580
5740
|
}
|
|
5581
5741
|
function outcomesFromRead(read) {
|
|
5582
5742
|
const persistedOutcomes = extractOutcomesFromPersistedEvents(
|
|
@@ -5657,8 +5817,20 @@ async function runSuiteCase(suiteCase, config, options) {
|
|
|
5657
5817
|
]
|
|
5658
5818
|
};
|
|
5659
5819
|
}
|
|
5660
|
-
const
|
|
5661
|
-
|
|
5820
|
+
const compiled = buildCaseAssertions(suiteCase, config);
|
|
5821
|
+
if (compiled.configDiagnostics.length > 0) {
|
|
5822
|
+
return {
|
|
5823
|
+
id: suiteCase.id,
|
|
5824
|
+
status: "error",
|
|
5825
|
+
tracePath: resolved.tracePath,
|
|
5826
|
+
...resolved.runId !== void 0 ? { runId: resolved.runId } : {},
|
|
5827
|
+
checkOk: false,
|
|
5828
|
+
...config.eval?.requireSuccess === true ? { evalOk: false } : {},
|
|
5829
|
+
message: compiled.configDiagnostics.map((item) => item.message).join("; "),
|
|
5830
|
+
diagnostics: compiled.configDiagnostics
|
|
5831
|
+
};
|
|
5832
|
+
}
|
|
5833
|
+
const checkResult = compiled.rules.length > 0 ? runTraceChecks({ read }, { rules: compiled.rules, select: compiled.select }) : {
|
|
5662
5834
|
ok: true,
|
|
5663
5835
|
status: "pass",
|
|
5664
5836
|
format: read.format,
|
|
@@ -5686,6 +5858,9 @@ async function runSuiteCase(suiteCase, config, options) {
|
|
|
5686
5858
|
];
|
|
5687
5859
|
const checkOk = checkResult.ok;
|
|
5688
5860
|
const observationsOk = observationResult.ok;
|
|
5861
|
+
const evalOk = config.eval?.requireSuccess === true ? checkResult.findings.every(
|
|
5862
|
+
(finding) => finding.ruleId !== "run.status" || finding.status !== "fail"
|
|
5863
|
+
) && checkResult.diagnostics.every((item) => item.severity !== "error") : void 0;
|
|
5689
5864
|
const ok = checkOk && observationsOk;
|
|
5690
5865
|
const status = ok ? "pass" : checkResult.status === "error" ? "error" : "fail";
|
|
5691
5866
|
return {
|
|
@@ -5694,6 +5869,7 @@ async function runSuiteCase(suiteCase, config, options) {
|
|
|
5694
5869
|
tracePath: resolved.tracePath,
|
|
5695
5870
|
...resolved.runId !== void 0 ? { runId: resolved.runId } : {},
|
|
5696
5871
|
checkOk,
|
|
5872
|
+
...evalOk !== void 0 ? { evalOk } : {},
|
|
5697
5873
|
observationsOk,
|
|
5698
5874
|
diagnostics,
|
|
5699
5875
|
...ok ? {} : {
|