@agent-inspect/mcp-server 6.18.0 → 6.19.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/cli.cjs CHANGED
@@ -3003,6 +3003,325 @@ function pickString(record, keys) {
3003
3003
  return void 0;
3004
3004
  }
3005
3005
 
3006
+ // packages/core/src/checks/derived-failure.ts
3007
+ function isRecord7(value) {
3008
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3009
+ }
3010
+ function pickString2(record, keys) {
3011
+ if (!record) return void 0;
3012
+ for (const key of keys) {
3013
+ const value = record[key];
3014
+ if (typeof value === "string" && value.trim() !== "") return value;
3015
+ }
3016
+ return void 0;
3017
+ }
3018
+ function pickNumber(record, keys) {
3019
+ if (!record) return void 0;
3020
+ for (const key of keys) {
3021
+ const value = record[key];
3022
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
3023
+ return value;
3024
+ }
3025
+ }
3026
+ return void 0;
3027
+ }
3028
+ function eventMetadata(event) {
3029
+ const attrs = isRecord7(event.attributes) ? event.attributes : void 0;
3030
+ const nested = attrs !== void 0 && isRecord7(attrs.metadata) ? attrs.metadata : void 0;
3031
+ return {
3032
+ ...attrs ?? {},
3033
+ ...nested ?? {}
3034
+ };
3035
+ }
3036
+ function canonicalName(event) {
3037
+ if (event.kind === "TOOL") return resolveCanonicalToolName(event);
3038
+ return event.name;
3039
+ }
3040
+ function linkKeys(event) {
3041
+ const meta = eventMetadata(event);
3042
+ const keys = [];
3043
+ for (const key of ["linkedStepId", "toolCallId", "mcpToolCallId"]) {
3044
+ const value = pickString2(meta, [key]);
3045
+ if (value !== void 0) keys.push(`${key}:${value}`);
3046
+ }
3047
+ const stepId = pickString2(meta, ["stepId"]);
3048
+ if (stepId !== void 0) keys.push(`stepId:${stepId}`);
3049
+ return keys;
3050
+ }
3051
+ function buildRunContexts(logicalEvents) {
3052
+ const byRun = /* @__PURE__ */ new Map();
3053
+ for (const event of logicalEvents) {
3054
+ const existing = byRun.get(event.runId) ?? {
3055
+ runId: event.runId,
3056
+ name: event.name
3057
+ };
3058
+ const meta = eventMetadata(event);
3059
+ if (event.kind === "RUN" || existing.name === event.runId) {
3060
+ existing.name = event.name || existing.name;
3061
+ }
3062
+ if (event.kind === "RUN" && event.status !== void 0 && event.status !== "running") {
3063
+ existing.status = event.status;
3064
+ }
3065
+ existing.retryOf ??= pickString2(meta, ["retryOf"]);
3066
+ existing.attempt ??= pickNumber(meta, ["attempt", "retryAttempt", "retryCount"]);
3067
+ existing.sessionId ??= pickString2(meta, ["sessionId", "conversationId"]);
3068
+ existing.groupId ??= pickString2(meta, ["groupId"]);
3069
+ existing.parentGroupId ??= pickString2(meta, ["parentGroupId"]);
3070
+ existing.fallbackOf ??= pickString2(meta, ["fallbackOf", "fallbackFrom"]);
3071
+ byRun.set(event.runId, existing);
3072
+ }
3073
+ return byRun;
3074
+ }
3075
+ function sameCorrelationScope(a, b) {
3076
+ if (a.sessionId && b.sessionId && a.sessionId === b.sessionId) return true;
3077
+ if (a.groupId && b.groupId && a.groupId === b.groupId) return true;
3078
+ if (a.parentGroupId && b.parentGroupId && a.parentGroupId === b.parentGroupId) {
3079
+ return true;
3080
+ }
3081
+ return false;
3082
+ }
3083
+ function isSuccessful(event) {
3084
+ return event.status === "ok";
3085
+ }
3086
+ function isFailure(event) {
3087
+ return event.status === "error";
3088
+ }
3089
+ function compareEventOrder(a, b) {
3090
+ const byTime = a.timestamp.localeCompare(b.timestamp);
3091
+ if (byTime !== 0) return byTime;
3092
+ return a.eventId.localeCompare(b.eventId);
3093
+ }
3094
+ function collectCandidates(failure, logicalEvents, runs) {
3095
+ const failureRun = runs.get(failure.runId);
3096
+ const failureLinks = new Set(linkKeys(failure));
3097
+ const failureName = canonicalName(failure);
3098
+ const failureAttempt = pickNumber(eventMetadata(failure), ["attempt", "retryAttempt", "retryCount"]) ?? failureRun?.attempt;
3099
+ const candidates = [];
3100
+ for (const event of logicalEvents) {
3101
+ if (event.eventId === failure.eventId) continue;
3102
+ if (event.status === "running") continue;
3103
+ const eventRun = runs.get(event.runId);
3104
+ const eventMeta = eventMetadata(event);
3105
+ const sameRun = event.runId === failure.runId;
3106
+ if (eventRun?.retryOf === failure.runId) {
3107
+ candidates.push({
3108
+ event,
3109
+ basis: "retryOf",
3110
+ confidence: "explicit",
3111
+ viaRunId: event.runId
3112
+ });
3113
+ continue;
3114
+ }
3115
+ if (eventRun?.fallbackOf === failure.runId || pickString2(eventMeta, ["fallbackOf", "fallbackFrom"]) === failure.runId) {
3116
+ candidates.push({
3117
+ event,
3118
+ basis: "fallbackOf",
3119
+ confidence: "explicit",
3120
+ viaRunId: event.runId
3121
+ });
3122
+ continue;
3123
+ }
3124
+ if (sameRun && compareEventOrder(failure, event) >= 0) continue;
3125
+ const eventLinks = linkKeys(event);
3126
+ const sharedLink = eventLinks.find((key) => failureLinks.has(key));
3127
+ if (sharedLink !== void 0) {
3128
+ candidates.push({
3129
+ event,
3130
+ basis: sharedLink.split(":")[0] ?? "linkedId",
3131
+ confidence: "explicit"
3132
+ });
3133
+ continue;
3134
+ }
3135
+ const eventAttempt = pickNumber(eventMeta, ["attempt", "retryAttempt", "retryCount"]) ?? eventRun?.attempt;
3136
+ const sameParent = failure.parentId !== void 0 && event.parentId !== void 0 && failure.parentId === event.parentId;
3137
+ const differentParent = failure.parentId !== void 0 && event.parentId !== void 0 && failure.parentId !== event.parentId;
3138
+ const sessionScoped = failureRun !== void 0 && eventRun !== void 0 && sameCorrelationScope(failureRun, eventRun);
3139
+ if (canonicalName(event) === failureName && failureAttempt !== void 0 && eventAttempt !== void 0 && eventAttempt > failureAttempt && !differentParent && (sameParent || sessionScoped || sameRun)) {
3140
+ candidates.push({
3141
+ event,
3142
+ basis: "attempt-progression",
3143
+ confidence: "correlated",
3144
+ ...event.runId !== failure.runId ? { viaRunId: event.runId } : {}
3145
+ });
3146
+ }
3147
+ }
3148
+ const byId = /* @__PURE__ */ new Map();
3149
+ for (const candidate of candidates) {
3150
+ const prev = byId.get(candidate.event.eventId);
3151
+ if (!prev || prev.confidence !== "explicit" && candidate.confidence === "explicit") {
3152
+ byId.set(candidate.event.eventId, candidate);
3153
+ }
3154
+ }
3155
+ return [...byId.values()].sort((a, b) => compareEventOrder(a.event, b.event));
3156
+ }
3157
+ function classifyFailure(failure, candidates, runs, logicalEvents) {
3158
+ const successful = candidates.filter((c) => isSuccessful(c.event));
3159
+ const unsuccessful = candidates.filter((c) => !isSuccessful(c.event));
3160
+ const retryRunIds = Object.freeze(
3161
+ [...new Set(candidates.map((c) => c.viaRunId).filter((id) => id !== void 0))].sort(
3162
+ (a, b) => a.localeCompare(b)
3163
+ )
3164
+ );
3165
+ if (successful.length > 1) {
3166
+ const distinctRuns = new Set(successful.map((c) => c.event.runId));
3167
+ const distinctParents = new Set(
3168
+ successful.map((c) => c.event.parentId ?? "").filter((id) => id !== "")
3169
+ );
3170
+ if (distinctRuns.size > 1 || distinctParents.size > 1) {
3171
+ return {
3172
+ eventId: failure.eventId,
3173
+ runId: failure.runId,
3174
+ name: failure.name,
3175
+ kind: failure.kind,
3176
+ role: "unknown",
3177
+ confidence: "unknown",
3178
+ basis: Object.freeze(["ambiguous-recovery-candidates"]),
3179
+ recoveryEventIds: Object.freeze(
3180
+ successful.map((c) => c.event.eventId).sort((a, b) => a.localeCompare(b))
3181
+ ),
3182
+ retryRunIds
3183
+ };
3184
+ }
3185
+ }
3186
+ if (successful.length >= 1) {
3187
+ const best = successful[0];
3188
+ return {
3189
+ eventId: failure.eventId,
3190
+ runId: failure.runId,
3191
+ name: failure.name,
3192
+ kind: failure.kind,
3193
+ role: "recovered",
3194
+ confidence: best.confidence,
3195
+ basis: Object.freeze([best.basis]),
3196
+ recoveryEventIds: Object.freeze(
3197
+ successful.map((c) => c.event.eventId).sort((a, b) => a.localeCompare(b))
3198
+ ),
3199
+ retryRunIds
3200
+ };
3201
+ }
3202
+ if (candidates.length > 0) {
3203
+ const best = candidates[0];
3204
+ return {
3205
+ eventId: failure.eventId,
3206
+ runId: failure.runId,
3207
+ name: failure.name,
3208
+ kind: failure.kind,
3209
+ role: "transient",
3210
+ confidence: best.confidence,
3211
+ basis: Object.freeze([
3212
+ best.basis,
3213
+ unsuccessful.some((c) => c.event.status === void 0) ? "retry-incomplete" : "retry-without-success"
3214
+ ]),
3215
+ recoveryEventIds: Object.freeze([]),
3216
+ retryRunIds
3217
+ };
3218
+ }
3219
+ const failureMeta = eventMetadata(failure);
3220
+ const declaredSuccessor = pickString2(failureMeta, [
3221
+ "retriedBy",
3222
+ "nextRetryRunId",
3223
+ "retryRunId"
3224
+ ]);
3225
+ if (declaredSuccessor !== void 0 && !runs.has(declaredSuccessor)) {
3226
+ return {
3227
+ eventId: failure.eventId,
3228
+ runId: failure.runId,
3229
+ name: failure.name,
3230
+ kind: failure.kind,
3231
+ role: "transient",
3232
+ confidence: "explicit",
3233
+ basis: Object.freeze(["retry-declared", "retry-run-missing"]),
3234
+ recoveryEventIds: Object.freeze([]),
3235
+ retryRunIds: Object.freeze([declaredSuccessor])
3236
+ };
3237
+ }
3238
+ for (const run of runs.values()) {
3239
+ if (run.retryOf === failure.runId) {
3240
+ return {
3241
+ eventId: failure.eventId,
3242
+ runId: failure.runId,
3243
+ name: failure.name,
3244
+ kind: failure.kind,
3245
+ role: "transient",
3246
+ confidence: "explicit",
3247
+ basis: Object.freeze(["retryOf", "retry-run-missing-or-empty"]),
3248
+ recoveryEventIds: Object.freeze([]),
3249
+ retryRunIds: Object.freeze([run.runId])
3250
+ };
3251
+ }
3252
+ }
3253
+ const failureRun = runs.get(failure.runId);
3254
+ const hasSuccessorDeclared = [...runs.values()].some((run) => run.retryOf === failure.runId);
3255
+ const isFinalInChain = failureRun !== void 0 && !hasSuccessorDeclared && (failureRun.retryOf !== void 0 || failureRun.attempt !== void 0 && failureRun.attempt > 1 || pickNumber(eventMetadata(failure), ["attempt"]) !== void 0);
3256
+ if (isFinalInChain && failureRun?.status === "error" && !logicalEvents.some(
3257
+ (event) => event.runId === failure.runId && event.eventId !== failure.eventId && isSuccessful(event) && canonicalName(event) === canonicalName(failure)
3258
+ )) {
3259
+ return {
3260
+ eventId: failure.eventId,
3261
+ runId: failure.runId,
3262
+ name: failure.name,
3263
+ kind: failure.kind,
3264
+ role: "terminal",
3265
+ confidence: failureRun.retryOf !== void 0 ? "explicit" : "correlated",
3266
+ basis: Object.freeze(["final-retry-chain-member", "enclosing-run-error"]),
3267
+ recoveryEventIds: Object.freeze([]),
3268
+ retryRunIds: Object.freeze(
3269
+ failureRun.retryOf !== void 0 ? [failureRun.retryOf] : []
3270
+ )
3271
+ };
3272
+ }
3273
+ return {
3274
+ eventId: failure.eventId,
3275
+ runId: failure.runId,
3276
+ name: failure.name,
3277
+ kind: failure.kind,
3278
+ role: "unknown",
3279
+ confidence: "unknown",
3280
+ basis: Object.freeze(["no-explicit-or-correlated-recovery"]),
3281
+ recoveryEventIds: Object.freeze([]),
3282
+ retryRunIds: Object.freeze([])
3283
+ };
3284
+ }
3285
+ function deriveFailureFacts(logicalEvents) {
3286
+ const runs = buildRunContexts(logicalEvents);
3287
+ const failures = logicalEvents.filter((event) => isFailure(event)).sort(compareEventOrder);
3288
+ const failureFacts = failures.map(
3289
+ (failure) => classifyFailure(failure, collectCandidates(failure, logicalEvents, runs), runs, logicalEvents)
3290
+ );
3291
+ const byRole = /* @__PURE__ */ new Map([
3292
+ ["transient", []],
3293
+ ["recovered", []],
3294
+ ["terminal", []],
3295
+ ["unknown", []]
3296
+ ]);
3297
+ for (const fact of failureFacts) {
3298
+ byRole.get(fact.role).push(fact);
3299
+ }
3300
+ for (const [role, list] of byRole) {
3301
+ byRole.set(
3302
+ role,
3303
+ Object.freeze(
3304
+ [...list].sort((a, b) => {
3305
+ const byRun = a.runId.localeCompare(b.runId);
3306
+ if (byRun !== 0) return byRun;
3307
+ return a.eventId.localeCompare(b.eventId);
3308
+ })
3309
+ )
3310
+ );
3311
+ }
3312
+ const failureRoleCounts = {
3313
+ transient: byRole.get("transient").length,
3314
+ recovered: byRole.get("recovered").length,
3315
+ terminal: byRole.get("terminal").length,
3316
+ unknown: byRole.get("unknown").length
3317
+ };
3318
+ return {
3319
+ failureFacts: Object.freeze(failureFacts),
3320
+ failuresByRole: byRole,
3321
+ failureRoleCounts
3322
+ };
3323
+ }
3324
+
3006
3325
  // packages/core/src/checks/trace-facts.ts
3007
3326
  function summarizeSemanticParity(events) {
3008
3327
  const projection = projectLogicalEvents(events);
@@ -3013,6 +3332,7 @@ function summarizeSemanticParity(events) {
3013
3332
  const finishedToolNames = Object.freeze(
3014
3333
  finishedTools.map((event) => resolveCanonicalToolName(event)).sort((a, b) => a.localeCompare(b))
3015
3334
  );
3335
+ const derived = deriveFailureFacts(logical);
3016
3336
  return {
3017
3337
  rawEventCount: events.length,
3018
3338
  logicalEventCount: logical.length,
@@ -3023,7 +3343,8 @@ function summarizeSemanticParity(events) {
3023
3343
  parentRemapCount: projection.diagnostics.filter(
3024
3344
  (item) => item.code === "AI_LOGICAL_PARENT_REMAPPED"
3025
3345
  ).length,
3026
- diagnostics: projection.diagnostics
3346
+ diagnostics: projection.diagnostics,
3347
+ failureRoleCounts: derived.failureRoleCounts
3027
3348
  };
3028
3349
  }
3029
3350
  var TRACE_FACTS_INPUT_NOT_NORMALIZED = formatProgrammaticDiagnostic(
@@ -3086,6 +3407,8 @@ function buildTraceFacts(input) {
3086
3407
  for (const [name, list] of [...toolsByName.entries()]) {
3087
3408
  toolsByName.set(name, Object.freeze([...list]));
3088
3409
  }
3410
+ const derived = deriveFailureFacts(projection.logicalEvents);
3411
+ const summary = summarizeSemanticParity(events);
3089
3412
  return {
3090
3413
  rawEvents: Object.freeze([...events]),
3091
3414
  logicalEvents: projection.logicalEvents,
@@ -3093,7 +3416,12 @@ function buildTraceFacts(input) {
3093
3416
  toolsByName,
3094
3417
  llmEvents: Object.freeze(llmEvents),
3095
3418
  outcomeEvents: Object.freeze(outcomeEvents),
3096
- summary: summarizeSemanticParity(events)
3419
+ summary: {
3420
+ ...summary,
3421
+ failureRoleCounts: derived.failureRoleCounts
3422
+ },
3423
+ failureFacts: derived.failureFacts,
3424
+ failuresByRole: derived.failuresByRole
3097
3425
  };
3098
3426
  }
3099
3427
 
@@ -3419,7 +3747,7 @@ function failFinding(ruleId, message, evidence, expected, actual, meta) {
3419
3747
  function semanticEvents(context) {
3420
3748
  return context.logicalEvents ?? context.events;
3421
3749
  }
3422
- function isRecord7(value) {
3750
+ function isRecord8(value) {
3423
3751
  return typeof value === "object" && value !== null && !Array.isArray(value);
3424
3752
  }
3425
3753
  function normalizedKey(value) {
@@ -3450,7 +3778,7 @@ function pushValueEntries(entries, event, value, path17, key, depth = 0) {
3450
3778
  }
3451
3779
  return;
3452
3780
  }
3453
- if (!isRecord7(value)) return;
3781
+ if (!isRecord8(value)) return;
3454
3782
  for (const nestedKey of Object.keys(value).sort((a, b) => a.localeCompare(b))) {
3455
3783
  pushValueEntries(
3456
3784
  entries,
@@ -3698,7 +4026,7 @@ function createSafetyOversizedAttributeRule(options) {
3698
4026
  )
3699
4027
  );
3700
4028
  }
3701
- if (isRecord7(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
4029
+ if (isRecord8(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
3702
4030
  findings.push(
3703
4031
  failFinding(
3704
4032
  "safety.oversizedAttribute",
@@ -3816,14 +4144,14 @@ function runTraceChecks(input, options = {}) {
3816
4144
  }
3817
4145
 
3818
4146
  // packages/core/src/persisted/token-usage.ts
3819
- function isRecord8(value) {
4147
+ function isRecord9(value) {
3820
4148
  return typeof value === "object" && value !== null && !Array.isArray(value);
3821
4149
  }
3822
4150
  function nonNegativeFinite(value) {
3823
4151
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
3824
4152
  }
3825
4153
  function normalizeTokenUsage(value) {
3826
- if (!isRecord8(value)) return void 0;
4154
+ if (!isRecord9(value)) return void 0;
3827
4155
  const input = nonNegativeFinite(value.input);
3828
4156
  const output = nonNegativeFinite(value.output);
3829
4157
  const suppliedTotal = nonNegativeFinite(value.total);
@@ -4704,7 +5032,7 @@ function persistedEventsForParsedTrace(parsed) {
4704
5032
  sourceName: "agent-inspect-jsonl-reader"
4705
5033
  });
4706
5034
  }
4707
- function isRecord9(value) {
5035
+ function isRecord10(value) {
4708
5036
  return typeof value === "object" && value !== null && !Array.isArray(value);
4709
5037
  }
4710
5038
  function isNonEmptyString3(value) {
@@ -4719,13 +5047,13 @@ function readStringField(record, keys) {
4719
5047
  }
4720
5048
  function readRecordField(record, key) {
4721
5049
  const value = record[key];
4722
- return isRecord9(value) ? value : void 0;
5050
+ return isRecord10(value) ? value : void 0;
4723
5051
  }
4724
5052
  function parseJsonDocument(content) {
4725
5053
  return JSON.parse(content);
4726
5054
  }
4727
5055
  function looksLikeOpenInferenceSpan(value) {
4728
- if (!isRecord9(value)) return false;
5056
+ if (!isRecord10(value)) return false;
4729
5057
  const attributes = readRecordField(value, "attributes");
4730
5058
  return readStringField(value, ["trace_id", "traceId"]) !== void 0 && readStringField(value, ["span_id", "spanId"]) !== void 0 && (readStringField(value, ["name"]) !== void 0 || attributes?.["openinference.span.kind"] !== void 0);
4731
5059
  }
@@ -4750,7 +5078,7 @@ function extractOpenInferenceDocument(root) {
4750
5078
  unsupportedFields
4751
5079
  };
4752
5080
  }
4753
- if (!isRecord9(root)) return void 0;
5081
+ if (!isRecord10(root)) return void 0;
4754
5082
  const rootFormat = root.format;
4755
5083
  const rootCompatibility = root.compatibility;
4756
5084
  const version = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
@@ -4890,7 +5218,7 @@ function summarizeAttributeValue(value) {
4890
5218
  if (Array.isArray(value)) {
4891
5219
  return { type: "array", length: value.length };
4892
5220
  }
4893
- if (isRecord9(value)) {
5221
+ if (isRecord10(value)) {
4894
5222
  return { type: "object", keyCount: Object.keys(value).length };
4895
5223
  }
4896
5224
  if (value === null) {
@@ -4977,7 +5305,7 @@ function mapOpenInferenceKind(span, attributes, pathPrefix) {
4977
5305
  }
4978
5306
  }
4979
5307
  function mapOpenInferenceStatus(status) {
4980
- if (!isRecord9(status)) return void 0;
5308
+ if (!isRecord10(status)) return void 0;
4981
5309
  const rawCode = status.code;
4982
5310
  if (typeof rawCode !== "string") return void 0;
4983
5311
  switch (rawCode.toUpperCase()) {
@@ -5077,7 +5405,7 @@ function mapOpenInferenceSpan(span, index, version) {
5077
5405
  warnings.push(...kindWarnings);
5078
5406
  const status = mapOpenInferenceStatus(span.status);
5079
5407
  const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
5080
- const errorMessage = isRecord9(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
5408
+ const errorMessage = isRecord10(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
5081
5409
  const event = {
5082
5410
  schemaVersion: "0.2",
5083
5411
  eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
@@ -5223,7 +5551,7 @@ var openInferenceJsonReader = {
5223
5551
  }
5224
5552
  };
5225
5553
  function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
5226
- if (!isRecord9(value)) {
5554
+ if (!isRecord10(value)) {
5227
5555
  unsupportedFields.push(field);
5228
5556
  warnings.push({
5229
5557
  code: "otlp_attribute_value_invalid",
@@ -5245,15 +5573,15 @@ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
5245
5573
  if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
5246
5574
  return value.doubleValue;
5247
5575
  }
5248
- if (isRecord9(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
5576
+ if (isRecord10(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
5249
5577
  return value.arrayValue.values.map(
5250
5578
  (item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
5251
5579
  );
5252
5580
  }
5253
- if (isRecord9(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
5581
+ if (isRecord10(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
5254
5582
  const out = {};
5255
5583
  for (const [index, item] of value.kvlistValue.values.entries()) {
5256
- if (!isRecord9(item) || typeof item.key !== "string") {
5584
+ if (!isRecord10(item) || typeof item.key !== "string") {
5257
5585
  unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
5258
5586
  continue;
5259
5587
  }
@@ -5304,7 +5632,7 @@ function parseOtlpAttributes(value, pathPrefix) {
5304
5632
  }
5305
5633
  for (const [index, item] of value.entries()) {
5306
5634
  const field = `${pathPrefix}[${index}]`;
5307
- if (!isRecord9(item) || typeof item.key !== "string") {
5635
+ if (!isRecord10(item) || typeof item.key !== "string") {
5308
5636
  unsupportedFields.push(field);
5309
5637
  warnings.push({
5310
5638
  code: "otlp_attribute_invalid",
@@ -5327,16 +5655,16 @@ function parseOtlpAttributes(value, pathPrefix) {
5327
5655
  return { attributes, warnings, unsupportedFields };
5328
5656
  }
5329
5657
  function looksLikeOtlpSpan(value) {
5330
- return isRecord9(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
5658
+ return isRecord10(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
5331
5659
  }
5332
5660
  function extractOtlpDocument(root) {
5333
- if (!isRecord9(root) || !Array.isArray(root.resourceSpans)) return void 0;
5661
+ if (!isRecord10(root) || !Array.isArray(root.resourceSpans)) return void 0;
5334
5662
  const spans = [];
5335
5663
  const warnings = [];
5336
5664
  const unsupportedFields = [];
5337
5665
  for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
5338
5666
  const resourcePath = `resourceSpans[${resourceIndex}]`;
5339
- if (!isRecord9(resourceSpan)) {
5667
+ if (!isRecord10(resourceSpan)) {
5340
5668
  unsupportedFields.push(resourcePath);
5341
5669
  continue;
5342
5670
  }
@@ -5359,7 +5687,7 @@ function extractOtlpDocument(root) {
5359
5687
  }
5360
5688
  for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
5361
5689
  const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
5362
- if (!isRecord9(scopeSpan)) {
5690
+ if (!isRecord10(scopeSpan)) {
5363
5691
  unsupportedFields.push(scopePath);
5364
5692
  continue;
5365
5693
  }
@@ -5426,7 +5754,7 @@ function extractOtlpDocument(root) {
5426
5754
  };
5427
5755
  }
5428
5756
  function mapOtlpStatus(status) {
5429
- if (!isRecord9(status)) return void 0;
5757
+ if (!isRecord10(status)) return void 0;
5430
5758
  const rawCode = status.code;
5431
5759
  if (typeof rawCode !== "string") return void 0;
5432
5760
  switch (rawCode.toUpperCase()) {
@@ -5526,7 +5854,7 @@ function mapOtlpEvents(value, pathPrefix) {
5526
5854
  const events = [];
5527
5855
  for (const [index, event] of value.entries()) {
5528
5856
  const eventPath = `${pathPrefix}[${index}]`;
5529
- if (!isRecord9(event)) {
5857
+ if (!isRecord10(event)) {
5530
5858
  unsupportedFields.push(eventPath);
5531
5859
  continue;
5532
5860
  }
@@ -5664,7 +5992,7 @@ function mapOtlpSpan(context) {
5664
5992
  warnings.push(...kindWarnings);
5665
5993
  const status = mapOtlpStatus(span.status);
5666
5994
  const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
5667
- const errorMessage = isRecord9(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
5995
+ const errorMessage = isRecord10(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
5668
5996
  const event = {
5669
5997
  schemaVersion: "0.2",
5670
5998
  eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
@@ -6015,7 +6343,7 @@ function openTrace(input, options = {}) {
6015
6343
  var EXPORT_PAYLOAD_VERSION = "0.1.2";
6016
6344
 
6017
6345
  // packages/core/src/exporters/redact-export.ts
6018
- function isRecord10(value) {
6346
+ function isRecord11(value) {
6019
6347
  return typeof value === "object" && value !== null && !Array.isArray(value);
6020
6348
  }
6021
6349
  function deepClone(value) {
@@ -6089,7 +6417,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
6089
6417
  0
6090
6418
  );
6091
6419
  const err = bounded.error;
6092
- if (isRecord10(err) && typeof err.message === "string") {
6420
+ if (isRecord11(err) && typeof err.message === "string") {
6093
6421
  bounded.error = {
6094
6422
  ...err,
6095
6423
  message: truncateStringForProfile(
@@ -6814,7 +7142,7 @@ var STRICT_PROFILE_EXTRA_KEYS2 = [
6814
7142
  "retrieval",
6815
7143
  "query"
6816
7144
  ];
6817
- function isRecord11(value) {
7145
+ function isRecord12(value) {
6818
7146
  return typeof value === "object" && value !== null && !Array.isArray(value);
6819
7147
  }
6820
7148
  function toKey2(key) {
@@ -7194,7 +7522,7 @@ var Redactor2 = class {
7194
7522
  });
7195
7523
  return out;
7196
7524
  }
7197
- if (isRecord11(value)) {
7525
+ if (isRecord12(value)) {
7198
7526
  if (state.seen.has(value)) return state.seen.get(value);
7199
7527
  const out = {};
7200
7528
  state.seen.set(value, out);
@@ -7613,7 +7941,18 @@ async function callReadOnlyTool(context, name, args = {}) {
7613
7941
  toolNames: [...facts.toolsByName.keys()].sort((a, b) => a.localeCompare(b)),
7614
7942
  llmCount: facts.llmEvents.length,
7615
7943
  outcomeCount: facts.outcomeEvents.length,
7616
- note: "Bounded TraceFacts summary only; raw events and prompts are not included."
7944
+ failureRoleCounts: facts.summary.failureRoleCounts ?? {
7945
+ transient: 0,
7946
+ recovered: 0,
7947
+ terminal: 0,
7948
+ unknown: 0
7949
+ },
7950
+ failureFactIds: facts.failureFacts.map((fact) => ({
7951
+ eventId: fact.eventId,
7952
+ role: fact.role,
7953
+ confidence: fact.confidence
7954
+ })),
7955
+ note: "Bounded TraceFacts summary only; raw events, prompts, and error bodies are not included. Failure roles are derived classifications over recorded evidence."
7617
7956
  },
7618
7957
  context
7619
7958
  );