agent-inspect 6.12.1 → 6.13.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.
@@ -717,12 +717,12 @@ function persistedInspectEventToTraceEvents(event) {
717
717
  if (!isPersistedInspectEvent(event)) {
718
718
  throw new Error("Invalid PersistedInspectEvent: failed isPersistedInspectEvent");
719
719
  }
720
- const legacyEvent = event.attributes?.legacyEvent;
721
- if (legacyEvent === "run_started") return [fromLegacyRunStarted(event)];
722
- if (legacyEvent === "run_completed") return [fromLegacyRunCompleted(event)];
723
- if (legacyEvent === "step_started") return [fromLegacyStepStarted(event)];
724
- if (legacyEvent === "step_completed") return [fromLegacyStepCompleted(event)];
725
- if (legacyEvent === "outcome_observed") return [fromLegacyOutcomeObserved(event)];
720
+ const legacyEvent2 = event.attributes?.legacyEvent;
721
+ if (legacyEvent2 === "run_started") return [fromLegacyRunStarted(event)];
722
+ if (legacyEvent2 === "run_completed") return [fromLegacyRunCompleted(event)];
723
+ if (legacyEvent2 === "step_started") return [fromLegacyStepStarted(event)];
724
+ if (legacyEvent2 === "step_completed") return [fromLegacyStepCompleted(event)];
725
+ if (legacyEvent2 === "outcome_observed") return [fromLegacyOutcomeObserved(event)];
726
726
  if (event.kind === "RUN") {
727
727
  return fromNativeRun(event);
728
728
  }
@@ -6352,6 +6352,276 @@ var init_resolve2 = __esm({
6352
6352
  }
6353
6353
  });
6354
6354
 
6355
+ // packages/core/src/checks/logical-events.ts
6356
+ function isRecord7(value) {
6357
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6358
+ }
6359
+ function legacyEvent(event) {
6360
+ const value = event.attributes?.legacyEvent;
6361
+ return typeof value === "string" ? value : void 0;
6362
+ }
6363
+ function stepIdOf(event) {
6364
+ const value = event.attributes?.stepId;
6365
+ if (typeof value === "string" && value.trim() !== "") return value;
6366
+ return void 0;
6367
+ }
6368
+ function cloneEvent(event) {
6369
+ return {
6370
+ ...event,
6371
+ ...event.attributes !== void 0 ? { attributes: { ...event.attributes } } : {},
6372
+ ...event.error !== void 0 ? { error: { ...event.error } } : {},
6373
+ ...event.tokenUsage !== void 0 ? { tokenUsage: { ...event.tokenUsage } } : {},
6374
+ ...event.source !== void 0 ? { source: { ...event.source } } : {}
6375
+ };
6376
+ }
6377
+ function mergeAttributes(start, complete) {
6378
+ const merged = {
6379
+ ...isRecord7(complete.attributes) ? complete.attributes : {},
6380
+ ...isRecord7(start.attributes) ? start.attributes : {}
6381
+ };
6382
+ merged.legacyEvent = start.attributes?.legacyEvent ?? complete.attributes?.legacyEvent;
6383
+ merged.legacyCompleteEvent = complete.attributes?.legacyEvent;
6384
+ if (complete.attributes?.errorStack !== void 0) {
6385
+ merged.errorStack = complete.attributes.errorStack;
6386
+ }
6387
+ return Object.keys(merged).length > 0 ? merged : void 0;
6388
+ }
6389
+ function pairStartComplete(start, complete) {
6390
+ const attributes = mergeAttributes(start, complete);
6391
+ const paired = {
6392
+ ...cloneEvent(start),
6393
+ status: complete.status,
6394
+ timestamp: complete.timestamp ?? start.timestamp,
6395
+ ...complete.endedAt !== void 0 ? { endedAt: complete.endedAt } : {},
6396
+ ...complete.durationMs !== void 0 ? { durationMs: complete.durationMs } : {},
6397
+ ...complete.error !== void 0 ? { error: { ...complete.error } } : {},
6398
+ ...complete.tokenUsage !== void 0 && start.tokenUsage === void 0 ? { tokenUsage: { ...complete.tokenUsage } } : {},
6399
+ ...attributes !== void 0 ? { attributes } : {}
6400
+ };
6401
+ return {
6402
+ ...paired,
6403
+ sourceEventIds: Object.freeze([start.eventId, complete.eventId]),
6404
+ projection: {
6405
+ paired: true,
6406
+ absorbedEventIds: Object.freeze([complete.eventId]),
6407
+ parentNormalized: false,
6408
+ ...start.parentId !== void 0 ? { originalParentId: start.parentId } : {}
6409
+ }
6410
+ };
6411
+ }
6412
+ function asLogical(event, extras) {
6413
+ return {
6414
+ ...cloneEvent(event),
6415
+ sourceEventIds: Object.freeze([event.eventId]),
6416
+ projection: {
6417
+ paired: false,
6418
+ absorbedEventIds: Object.freeze([]),
6419
+ parentNormalized: extras?.parentNormalized === true,
6420
+ ...{}
6421
+ }
6422
+ };
6423
+ }
6424
+ function projectLogicalEvents(events) {
6425
+ const diagnostics = [];
6426
+ const byRun = /* @__PURE__ */ new Map();
6427
+ for (const event of events) {
6428
+ const list2 = byRun.get(event.runId) ?? [];
6429
+ list2.push(event);
6430
+ byRun.set(event.runId, list2);
6431
+ }
6432
+ const absorbedIds = /* @__PURE__ */ new Set();
6433
+ const logicalByRawId = /* @__PURE__ */ new Map();
6434
+ const stepIdToLogicalId = /* @__PURE__ */ new Map();
6435
+ const logical = [];
6436
+ const orderedRuns = [...byRun.keys()].sort((a, b) => a.localeCompare(b));
6437
+ for (const runId of orderedRuns) {
6438
+ const runEvents = byRun.get(runId) ?? [];
6439
+ const starts = [];
6440
+ const completes = [];
6441
+ const others = [];
6442
+ for (const event of runEvents) {
6443
+ const legacy = legacyEvent(event);
6444
+ if (legacy === "step_started" || legacy === "run_started" && event.status === "running") {
6445
+ starts.push(event);
6446
+ } else if (legacy === "step_completed" || legacy === "run_completed") {
6447
+ completes.push(event);
6448
+ } else {
6449
+ others.push(event);
6450
+ }
6451
+ }
6452
+ const usedCompletes = /* @__PURE__ */ new Set();
6453
+ for (const start of starts) {
6454
+ const stepId = stepIdOf(start);
6455
+ let match;
6456
+ if (legacyEvent(start) === "run_started") {
6457
+ const candidates = completes.filter(
6458
+ (c) => !usedCompletes.has(c.eventId) && legacyEvent(c) === "run_completed"
6459
+ );
6460
+ if (candidates.length > 1) {
6461
+ diagnostics.push({
6462
+ code: "AI_LOGICAL_PAIR_AMBIGUOUS",
6463
+ message: `Multiple run_completed rows for run ${runId}; using first by eventId.`,
6464
+ eventIds: candidates.map((c) => c.eventId)
6465
+ });
6466
+ candidates.sort((a, b) => a.eventId.localeCompare(b.eventId));
6467
+ }
6468
+ match = candidates[0];
6469
+ } else if (stepId) {
6470
+ const candidates = completes.filter(
6471
+ (c) => !usedCompletes.has(c.eventId) && legacyEvent(c) === "step_completed" && stepIdOf(c) === stepId
6472
+ );
6473
+ if (candidates.length > 1) {
6474
+ diagnostics.push({
6475
+ code: "AI_LOGICAL_PAIR_AMBIGUOUS",
6476
+ message: `Multiple step_completed rows for stepId ${stepId}; using first by eventId.`,
6477
+ eventIds: candidates.map((c) => c.eventId)
6478
+ });
6479
+ candidates.sort((a, b) => a.eventId.localeCompare(b.eventId));
6480
+ }
6481
+ match = candidates[0];
6482
+ }
6483
+ if (match) {
6484
+ usedCompletes.add(match.eventId);
6485
+ absorbedIds.add(match.eventId);
6486
+ const paired = pairStartComplete(start, match);
6487
+ logical.push(paired);
6488
+ logicalByRawId.set(start.eventId, paired);
6489
+ logicalByRawId.set(match.eventId, paired);
6490
+ if (stepId) stepIdToLogicalId.set(`${runId}:${stepId}`, paired.eventId);
6491
+ } else {
6492
+ diagnostics.push({
6493
+ code: "AI_LOGICAL_PAIR_UNMATCHED_START",
6494
+ message: `No matching complete for start ${start.eventId}.`,
6495
+ eventIds: [start.eventId]
6496
+ });
6497
+ const alone = asLogical(start);
6498
+ logical.push(alone);
6499
+ logicalByRawId.set(start.eventId, alone);
6500
+ if (stepId) stepIdToLogicalId.set(`${runId}:${stepId}`, alone.eventId);
6501
+ }
6502
+ }
6503
+ for (const complete of completes) {
6504
+ if (usedCompletes.has(complete.eventId)) continue;
6505
+ diagnostics.push({
6506
+ code: "AI_LOGICAL_PAIR_UNMATCHED_COMPLETE",
6507
+ message: `No matching start for complete ${complete.eventId}.`,
6508
+ eventIds: [complete.eventId]
6509
+ });
6510
+ const alone = asLogical(complete);
6511
+ logical.push(alone);
6512
+ logicalByRawId.set(complete.eventId, alone);
6513
+ const stepId = stepIdOf(complete);
6514
+ if (stepId && !stepIdToLogicalId.has(`${runId}:${stepId}`)) {
6515
+ stepIdToLogicalId.set(`${runId}:${stepId}`, alone.eventId);
6516
+ }
6517
+ }
6518
+ for (const event of others) {
6519
+ const alone = asLogical(event);
6520
+ logical.push(alone);
6521
+ logicalByRawId.set(event.eventId, alone);
6522
+ const stepId = stepIdOf(event);
6523
+ if (stepId && !stepIdToLogicalId.has(`${runId}:${stepId}`)) {
6524
+ stepIdToLogicalId.set(`${runId}:${stepId}`, alone.eventId);
6525
+ }
6526
+ }
6527
+ }
6528
+ const logicalById = new Map(logical.map((e) => [e.eventId, e]));
6529
+ const normalized = [];
6530
+ for (const event of logical) {
6531
+ const originalParentId = event.parentId;
6532
+ if (!originalParentId) {
6533
+ normalized.push(event);
6534
+ continue;
6535
+ }
6536
+ let nextParent = originalParentId;
6537
+ let remapped = false;
6538
+ const viaAbsorbed = logicalByRawId.get(originalParentId);
6539
+ if (viaAbsorbed && viaAbsorbed.eventId !== originalParentId) {
6540
+ nextParent = viaAbsorbed.eventId;
6541
+ remapped = true;
6542
+ } else if (!logicalById.has(originalParentId)) {
6543
+ const viaStep = stepIdToLogicalId.get(`${event.runId}:${originalParentId}`);
6544
+ if (viaStep) {
6545
+ nextParent = viaStep;
6546
+ remapped = true;
6547
+ }
6548
+ }
6549
+ if (!remapped) {
6550
+ if (!logicalById.has(originalParentId) && !logicalByRawId.has(originalParentId)) {
6551
+ const mapping = event.attributes?.parentMapping;
6552
+ const unresolved = mapping === "unresolved" || event.attributes?.parentUnresolved === true || event.attributes?.unresolvedParent === true || // LangGraph/framework scaffolding sentinel labels are not event ids.
6553
+ /^LangGraph$/i.test(originalParentId) || originalParentId.startsWith("unresolved:");
6554
+ if (!unresolved) {
6555
+ diagnostics.push({
6556
+ code: "AI_LOGICAL_PARENT_UNRESOLVED",
6557
+ message: `Parent ${originalParentId} unresolved for ${event.eventId}.`,
6558
+ eventIds: [event.eventId]
6559
+ });
6560
+ }
6561
+ }
6562
+ normalized.push(event);
6563
+ continue;
6564
+ }
6565
+ diagnostics.push({
6566
+ code: "AI_LOGICAL_PARENT_REMAPPED",
6567
+ message: `Remapped parent ${originalParentId} \u2192 ${nextParent} for ${event.eventId}.`,
6568
+ eventIds: [event.eventId]
6569
+ });
6570
+ normalized.push({
6571
+ ...event,
6572
+ parentId: nextParent,
6573
+ projection: {
6574
+ ...event.projection,
6575
+ parentNormalized: true,
6576
+ originalParentId
6577
+ }
6578
+ });
6579
+ }
6580
+ const rawIndex = new Map(events.map((e, i) => [e.eventId, i]));
6581
+ normalized.sort((a, b) => {
6582
+ const ai = rawIndex.get(a.sourceEventIds[0]) ?? 0;
6583
+ const bi = rawIndex.get(b.sourceEventIds[0]) ?? 0;
6584
+ return ai - bi || a.eventId.localeCompare(b.eventId);
6585
+ });
6586
+ return {
6587
+ logicalEvents: Object.freeze(normalized),
6588
+ diagnostics: Object.freeze(diagnostics)
6589
+ };
6590
+ }
6591
+ function resolveCanonicalToolName(event) {
6592
+ const attrs = event.attributes;
6593
+ const direct = pickString(attrs, ["toolName", "tool"]);
6594
+ if (direct) return direct;
6595
+ const metadata = attrs?.metadata;
6596
+ if (isRecord7(metadata)) {
6597
+ const nested = pickString(metadata, ["toolName", "tool"]);
6598
+ if (nested) return nested;
6599
+ }
6600
+ for (const prefix of ["tool:", "function:", "mcp-tools:"]) {
6601
+ if (event.name.startsWith(prefix)) return event.name.slice(prefix.length);
6602
+ }
6603
+ return event.name;
6604
+ }
6605
+ function pickString(record, keys) {
6606
+ if (!record) return void 0;
6607
+ for (const key of keys) {
6608
+ const value = record[key];
6609
+ if (typeof value === "string" && value.trim() !== "") return value.trim();
6610
+ }
6611
+ return void 0;
6612
+ }
6613
+ var init_logical_events = __esm({
6614
+ "packages/core/src/checks/logical-events.ts"() {
6615
+ }
6616
+ });
6617
+
6618
+ // packages/core/src/checks/trace-facts.ts
6619
+ var init_trace_facts = __esm({
6620
+ "packages/core/src/checks/trace-facts.ts"() {
6621
+ init_logical_events();
6622
+ }
6623
+ });
6624
+
6355
6625
  // packages/core/src/checks/contract.ts
6356
6626
  var init_contract = __esm({
6357
6627
  "packages/core/src/checks/contract.ts"() {
@@ -6413,10 +6683,13 @@ function buildFacts2(input3, selectedRun) {
6413
6683
  childrenByParentId.set(parentId, children);
6414
6684
  }
6415
6685
  }
6686
+ const projection = projectLogicalEvents(scopedEvents);
6416
6687
  return {
6417
6688
  format: input3.read.format,
6418
6689
  runs: Object.freeze([...input3.read.runs]),
6419
6690
  events: Object.freeze([...scopedEvents]),
6691
+ logicalEvents: projection.logicalEvents,
6692
+ logicalProjectionDiagnostics: projection.diagnostics,
6420
6693
  readerWarnings: Object.freeze([...input3.read.warnings]),
6421
6694
  unsupportedFields: Object.freeze([...input3.read.unsupportedFields]),
6422
6695
  sourceFiles: Object.freeze([...input3.read.sourceFiles]),
@@ -6609,7 +6882,10 @@ function failFinding(ruleId, message, evidence, expected, actual, meta2) {
6609
6882
  };
6610
6883
  }
6611
6884
  function toolName(event) {
6612
- return stringAttr(event, ["toolName", "tool"]) ?? stripPrefix(event.name, ["tool:", "function:", "mcp-tools:"]);
6885
+ return resolveCanonicalToolName(event);
6886
+ }
6887
+ function semanticEvents(context) {
6888
+ return context.logicalEvents ?? context.events;
6613
6889
  }
6614
6890
  function llmModel(event) {
6615
6891
  return stringAttr(event, ["model", "modelId", "responseModelId", "modelName", "model_name"]) ?? stripPrefix(event.name, ["llm:", "generation:", "transcription:", "speech:"]);
@@ -6624,11 +6900,11 @@ function retryCount(event) {
6624
6900
  return numericAttr(event, ["retryCount", "retryAttempt", "retry_attempt", "attempt"]);
6625
6901
  }
6626
6902
  function finishedEvents(context, kind) {
6627
- return context.events.filter(
6903
+ return semanticEvents(context).filter(
6628
6904
  (event) => (kind === void 0 || event.kind === kind) && event.status !== "running"
6629
6905
  );
6630
6906
  }
6631
- function isRecord7(value) {
6907
+ function isRecord8(value) {
6632
6908
  return typeof value === "object" && value !== null && !Array.isArray(value);
6633
6909
  }
6634
6910
  function eventMap(events) {
@@ -6679,7 +6955,7 @@ function pushValueEntries(entries, event, value, path41, key, depth = 0) {
6679
6955
  }
6680
6956
  return;
6681
6957
  }
6682
- if (!isRecord7(value)) return;
6958
+ if (!isRecord8(value)) return;
6683
6959
  for (const nestedKey of Object.keys(value).sort((a, b) => a.localeCompare(b))) {
6684
6960
  pushValueEntries(
6685
6961
  entries,
@@ -6759,14 +7035,11 @@ function signalName(event, attributeKeys, prefixes) {
6759
7035
  return stringAttr(event, attributeKeys) ?? stripPrefix(event.name, prefixes);
6760
7036
  }
6761
7037
  function guardrailEvents(context) {
6762
- return finishedEvents2().filter((event) => {
7038
+ return finishedEvents(context).filter((event) => {
6763
7039
  const name = event.name.toLowerCase();
6764
7040
  if (name.startsWith("guardrail:") || name.includes(".guardrail.")) return true;
6765
7041
  return stringAttr(event, ["guardrailName", "guardrail", "guardrailId"]) !== void 0;
6766
7042
  });
6767
- function finishedEvents2() {
6768
- return context.events.filter((event) => event.status !== "running");
6769
- }
6770
7043
  }
6771
7044
  function retryValue(event) {
6772
7045
  return retryCount(event) ?? 0;
@@ -6787,7 +7060,7 @@ function treeShape(nodes) {
6787
7060
  return lines;
6788
7061
  }
6789
7062
  function statusShape(context) {
6790
- return context.events.map((event) => `${event.kind}:${event.name}:${event.status ?? "unknown"}`).sort((a, b) => a.localeCompare(b));
7063
+ return semanticEvents(context).map((event) => `${event.kind}:${event.name}:${event.status ?? "unknown"}`).sort((a, b) => a.localeCompare(b));
6791
7064
  }
6792
7065
  function toolShape(context) {
6793
7066
  return finishedEvents(context, "TOOL").map(
@@ -6813,7 +7086,7 @@ function llmShape(context) {
6813
7086
  );
6814
7087
  }
6815
7088
  function errorShape(context) {
6816
- return context.events.filter((event) => event.status === "error" || event.error !== void 0).map(
7089
+ return semanticEvents(context).filter((event) => event.status === "error" || event.error !== void 0).map(
6817
7090
  (event) => [
6818
7091
  event.kind,
6819
7092
  event.name,
@@ -6831,7 +7104,7 @@ function guardrailShape(context) {
6831
7104
  return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
6832
7105
  }
6833
7106
  function firstEvidenceForKind(context, kind, path41) {
6834
- const event = context.events.find((candidate) => candidate.kind === kind);
7107
+ const event = semanticEvents(context).find((candidate) => candidate.kind === kind);
6835
7108
  return event ? [eventEvidence(event, path41)] : runEvidence(context.selectedRun);
6836
7109
  }
6837
7110
  function baselineDiffFinding(message, evidence, expected, actual) {
@@ -6859,7 +7132,7 @@ function createRunStatusRule(options = {}) {
6859
7132
  );
6860
7133
  }
6861
7134
  if (!allowIncomplete) {
6862
- const running = context.events.filter((event) => event.status === "running");
7135
+ const running = semanticEvents(context).filter((event) => event.status === "running");
6863
7136
  if (running.length > 0) {
6864
7137
  findings.push(
6865
7138
  failFinding(
@@ -6902,7 +7175,7 @@ function createMaxStepDurationRule(options) {
6902
7175
  category: "run",
6903
7176
  defaultSeverity: "error",
6904
7177
  evaluate(context) {
6905
- const over = context.events.filter((event) => {
7178
+ const over = semanticEvents(context).filter((event) => {
6906
7179
  const duration = eventDurationMs(event);
6907
7180
  return duration !== void 0 && duration > options.maxDurationMs;
6908
7181
  });
@@ -6931,7 +7204,7 @@ function createStallDetectionRule(options = {}) {
6931
7204
  defaultSeverity: "warning",
6932
7205
  evaluate(context) {
6933
7206
  const findings = [];
6934
- const running = context.events.filter((event) => event.status === "running");
7207
+ const running = semanticEvents(context).filter((event) => event.status === "running");
6935
7208
  if (running.length > 0) {
6936
7209
  findings.push(
6937
7210
  failFinding(
@@ -6944,7 +7217,7 @@ function createStallDetectionRule(options = {}) {
6944
7217
  );
6945
7218
  }
6946
7219
  if (requireEndedAt) {
6947
- const incomplete = context.events.filter(
7220
+ const incomplete = semanticEvents(context).filter(
6948
7221
  (event) => event.startedAt !== void 0 && event.endedAt === void 0 && event.status !== "running"
6949
7222
  );
6950
7223
  if (incomplete.length > 0) {
@@ -6982,7 +7255,7 @@ function createRequireCompletedRule() {
6982
7255
  )
6983
7256
  );
6984
7257
  }
6985
- const running = context.events.filter((event) => event.status === "running");
7258
+ const running = semanticEvents(context).filter((event) => event.status === "running");
6986
7259
  if (running.length > 0) {
6987
7260
  findings.push(
6988
7261
  failFinding(
@@ -7154,8 +7427,8 @@ function createStructureOrphanRule(options = {}) {
7154
7427
  category: "structure",
7155
7428
  defaultSeverity: "error",
7156
7429
  evaluate(context) {
7157
- const byId = eventMap(context.events);
7158
- const orphans = context.events.filter((event) => {
7430
+ const byId = eventMap(semanticEvents(context));
7431
+ const orphans = semanticEvents(context).filter((event) => {
7159
7432
  if (!event.parentId || byId.has(event.parentId)) return false;
7160
7433
  return !(allowMarkedUnresolved && parentMarkedUnresolved(event));
7161
7434
  });
@@ -7178,10 +7451,10 @@ function createStructureCycleRule() {
7178
7451
  category: "structure",
7179
7452
  defaultSeverity: "error",
7180
7453
  evaluate(context) {
7181
- const byId = eventMap(context.events);
7454
+ const byId = eventMap(semanticEvents(context));
7182
7455
  const seenCycles = /* @__PURE__ */ new Set();
7183
7456
  const findings = [];
7184
- for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
7457
+ for (const event of [...semanticEvents(context)].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
7185
7458
  const path41 = [];
7186
7459
  const seenAt = /* @__PURE__ */ new Map();
7187
7460
  let current = event;
@@ -7219,10 +7492,10 @@ function createStructureRelationshipRule(options = {}) {
7219
7492
  category: "structure",
7220
7493
  defaultSeverity: "error",
7221
7494
  evaluate(context) {
7222
- const byId = eventMap(context.events);
7495
+ const byId = eventMap(semanticEvents(context));
7223
7496
  const findings = [];
7224
7497
  const minConfidence = options.minConfidence;
7225
- for (const event of context.events) {
7498
+ for (const event of semanticEvents(context)) {
7226
7499
  if (minConfidence && CONFIDENCE_RANK[event.confidence] < CONFIDENCE_RANK[minConfidence]) {
7227
7500
  findings.push(
7228
7501
  failFinding(
@@ -7290,7 +7563,7 @@ function createStructureParallelWidthRule(options) {
7290
7563
  defaultSeverity: "error",
7291
7564
  evaluate(context) {
7292
7565
  const findings = [];
7293
- const byId = eventMap(context.events);
7566
+ const byId = eventMap(semanticEvents(context));
7294
7567
  if (options.maxChildren !== void 0) {
7295
7568
  for (const [parentId, children] of context.childrenByParentId.entries()) {
7296
7569
  if (children.length <= options.maxChildren) continue;
@@ -7317,7 +7590,7 @@ function createStructureParallelWidthRule(options) {
7317
7590
  }
7318
7591
  }
7319
7592
  if (options.maxConcurrent !== void 0) {
7320
- const intervals = context.events.map((event) => ({ event, start: eventStartMs(event), end: eventEndMs(event) })).filter(
7593
+ const intervals = semanticEvents(context).map((event) => ({ event, start: eventStartMs(event), end: eventEndMs(event) })).filter(
7321
7594
  (item) => item.start !== void 0 && item.end !== void 0 && item.end > item.start
7322
7595
  );
7323
7596
  const points = intervals.flatMap((item) => [
@@ -7510,7 +7783,7 @@ function createSafetyOversizedAttributeRule(options) {
7510
7783
  )
7511
7784
  );
7512
7785
  }
7513
- if (isRecord7(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
7786
+ if (isRecord8(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
7514
7787
  findings.push(
7515
7788
  failFinding(
7516
7789
  "safety.oversizedAttribute",
@@ -7763,6 +8036,9 @@ var SEVERITY_RANK, STATUS_RANK, CONFIDENCE_RANK, DEFAULT_SENSITIVE_KEYS, DEFAULT
7763
8036
  var init_checks2 = __esm({
7764
8037
  "packages/core/src/checks/index.ts"() {
7765
8038
  init_outcomes();
8039
+ init_logical_events();
8040
+ init_logical_events();
8041
+ init_trace_facts();
7766
8042
  init_contract();
7767
8043
  SEVERITY_RANK = {
7768
8044
  error: 0,
@@ -7821,7 +8097,11 @@ var init_checks2 = __esm({
7821
8097
  "conversationtext",
7822
8098
  "conversation_text"
7823
8099
  ];
7824
- DEFAULT_SAFE_RAW_CONTENT_PATH_PREFIXES = ["tokenUsage", "usage"];
8100
+ DEFAULT_SAFE_RAW_CONTENT_PATH_PREFIXES = [
8101
+ "tokenUsage",
8102
+ "usage",
8103
+ "tokens"
8104
+ ];
7825
8105
  SAFE_USAGE_LEAF_KEYS = /* @__PURE__ */ new Set([
7826
8106
  "input",
7827
8107
  "output",
@@ -7849,14 +8129,14 @@ var init_checks2 = __esm({
7849
8129
  });
7850
8130
 
7851
8131
  // packages/core/src/persisted/token-usage.ts
7852
- function isRecord8(value) {
8132
+ function isRecord9(value) {
7853
8133
  return typeof value === "object" && value !== null && !Array.isArray(value);
7854
8134
  }
7855
8135
  function nonNegativeFinite(value) {
7856
8136
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
7857
8137
  }
7858
8138
  function normalizeTokenUsage(value) {
7859
- if (!isRecord8(value)) return void 0;
8139
+ if (!isRecord9(value)) return void 0;
7860
8140
  const input3 = nonNegativeFinite(value.input);
7861
8141
  const output2 = nonNegativeFinite(value.output);
7862
8142
  const suppliedTotal = nonNegativeFinite(value.total);
@@ -8577,7 +8857,7 @@ function persistedEventsForParsedTrace(parsed) {
8577
8857
  sourceName: "agent-inspect-jsonl-reader"
8578
8858
  });
8579
8859
  }
8580
- function isRecord9(value) {
8860
+ function isRecord10(value) {
8581
8861
  return typeof value === "object" && value !== null && !Array.isArray(value);
8582
8862
  }
8583
8863
  function isNonEmptyString4(value) {
@@ -8592,13 +8872,13 @@ function readStringField(record, keys) {
8592
8872
  }
8593
8873
  function readRecordField(record, key) {
8594
8874
  const value = record[key];
8595
- return isRecord9(value) ? value : void 0;
8875
+ return isRecord10(value) ? value : void 0;
8596
8876
  }
8597
8877
  function parseJsonDocument(content) {
8598
8878
  return JSON.parse(content);
8599
8879
  }
8600
8880
  function looksLikeOpenInferenceSpan(value) {
8601
- if (!isRecord9(value)) return false;
8881
+ if (!isRecord10(value)) return false;
8602
8882
  const attributes = readRecordField(value, "attributes");
8603
8883
  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);
8604
8884
  }
@@ -8623,7 +8903,7 @@ function extractOpenInferenceDocument(root) {
8623
8903
  unsupportedFields
8624
8904
  };
8625
8905
  }
8626
- if (!isRecord9(root)) return void 0;
8906
+ if (!isRecord10(root)) return void 0;
8627
8907
  const rootFormat = root.format;
8628
8908
  const rootCompatibility = root.compatibility;
8629
8909
  const version2 = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
@@ -8763,7 +9043,7 @@ function summarizeAttributeValue(value) {
8763
9043
  if (Array.isArray(value)) {
8764
9044
  return { type: "array", length: value.length };
8765
9045
  }
8766
- if (isRecord9(value)) {
9046
+ if (isRecord10(value)) {
8767
9047
  return { type: "object", keyCount: Object.keys(value).length };
8768
9048
  }
8769
9049
  if (value === null) {
@@ -8850,7 +9130,7 @@ function mapOpenInferenceKind(span, attributes, pathPrefix) {
8850
9130
  }
8851
9131
  }
8852
9132
  function mapOpenInferenceStatus(status) {
8853
- if (!isRecord9(status)) return void 0;
9133
+ if (!isRecord10(status)) return void 0;
8854
9134
  const rawCode = status.code;
8855
9135
  if (typeof rawCode !== "string") return void 0;
8856
9136
  switch (rawCode.toUpperCase()) {
@@ -8950,7 +9230,7 @@ function mapOpenInferenceSpan(span, index, version2) {
8950
9230
  warnings.push(...kindWarnings);
8951
9231
  const status = mapOpenInferenceStatus(span.status);
8952
9232
  const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
8953
- const errorMessage = isRecord9(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
9233
+ const errorMessage = isRecord10(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
8954
9234
  const event = {
8955
9235
  schemaVersion: "0.2",
8956
9236
  eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
@@ -9018,7 +9298,7 @@ function mapOpenInferenceEvents(document) {
9018
9298
  };
9019
9299
  }
9020
9300
  function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
9021
- if (!isRecord9(value)) {
9301
+ if (!isRecord10(value)) {
9022
9302
  unsupportedFields.push(field);
9023
9303
  warnings.push({
9024
9304
  code: "otlp_attribute_value_invalid",
@@ -9040,15 +9320,15 @@ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
9040
9320
  if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
9041
9321
  return value.doubleValue;
9042
9322
  }
9043
- if (isRecord9(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
9323
+ if (isRecord10(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
9044
9324
  return value.arrayValue.values.map(
9045
9325
  (item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
9046
9326
  );
9047
9327
  }
9048
- if (isRecord9(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
9328
+ if (isRecord10(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
9049
9329
  const out = {};
9050
9330
  for (const [index, item] of value.kvlistValue.values.entries()) {
9051
- if (!isRecord9(item) || typeof item.key !== "string") {
9331
+ if (!isRecord10(item) || typeof item.key !== "string") {
9052
9332
  unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
9053
9333
  continue;
9054
9334
  }
@@ -9099,7 +9379,7 @@ function parseOtlpAttributes(value, pathPrefix) {
9099
9379
  }
9100
9380
  for (const [index, item] of value.entries()) {
9101
9381
  const field = `${pathPrefix}[${index}]`;
9102
- if (!isRecord9(item) || typeof item.key !== "string") {
9382
+ if (!isRecord10(item) || typeof item.key !== "string") {
9103
9383
  unsupportedFields.push(field);
9104
9384
  warnings.push({
9105
9385
  code: "otlp_attribute_invalid",
@@ -9122,16 +9402,16 @@ function parseOtlpAttributes(value, pathPrefix) {
9122
9402
  return { attributes, warnings, unsupportedFields };
9123
9403
  }
9124
9404
  function looksLikeOtlpSpan(value) {
9125
- return isRecord9(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
9405
+ return isRecord10(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
9126
9406
  }
9127
9407
  function extractOtlpDocument(root) {
9128
- if (!isRecord9(root) || !Array.isArray(root.resourceSpans)) return void 0;
9408
+ if (!isRecord10(root) || !Array.isArray(root.resourceSpans)) return void 0;
9129
9409
  const spans = [];
9130
9410
  const warnings = [];
9131
9411
  const unsupportedFields = [];
9132
9412
  for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
9133
9413
  const resourcePath = `resourceSpans[${resourceIndex}]`;
9134
- if (!isRecord9(resourceSpan)) {
9414
+ if (!isRecord10(resourceSpan)) {
9135
9415
  unsupportedFields.push(resourcePath);
9136
9416
  continue;
9137
9417
  }
@@ -9154,7 +9434,7 @@ function extractOtlpDocument(root) {
9154
9434
  }
9155
9435
  for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
9156
9436
  const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
9157
- if (!isRecord9(scopeSpan)) {
9437
+ if (!isRecord10(scopeSpan)) {
9158
9438
  unsupportedFields.push(scopePath);
9159
9439
  continue;
9160
9440
  }
@@ -9221,7 +9501,7 @@ function extractOtlpDocument(root) {
9221
9501
  };
9222
9502
  }
9223
9503
  function mapOtlpStatus(status) {
9224
- if (!isRecord9(status)) return void 0;
9504
+ if (!isRecord10(status)) return void 0;
9225
9505
  const rawCode = status.code;
9226
9506
  if (typeof rawCode !== "string") return void 0;
9227
9507
  switch (rawCode.toUpperCase()) {
@@ -9321,7 +9601,7 @@ function mapOtlpEvents(value, pathPrefix) {
9321
9601
  const events = [];
9322
9602
  for (const [index, event] of value.entries()) {
9323
9603
  const eventPath = `${pathPrefix}[${index}]`;
9324
- if (!isRecord9(event)) {
9604
+ if (!isRecord10(event)) {
9325
9605
  unsupportedFields.push(eventPath);
9326
9606
  continue;
9327
9607
  }
@@ -9459,7 +9739,7 @@ function mapOtlpSpan(context) {
9459
9739
  warnings.push(...kindWarnings);
9460
9740
  const status = mapOtlpStatus(span.status);
9461
9741
  const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
9462
- const errorMessage = isRecord9(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
9742
+ const errorMessage = isRecord10(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
9463
9743
  const event = {
9464
9744
  schemaVersion: "0.2",
9465
9745
  eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
@@ -11889,7 +12169,7 @@ var init_src = __esm({
11889
12169
  });
11890
12170
 
11891
12171
  // package.json
11892
- var version = "6.12.1";
12172
+ var version = "6.13.0";
11893
12173
 
11894
12174
  // packages/cli/src/list.ts
11895
12175
  init_advanced();
@@ -12506,7 +12786,7 @@ async function view(runId, options = {}) {
12506
12786
  process.exitCode = 1;
12507
12787
  }
12508
12788
  }
12509
- function isRecord10(v) {
12789
+ function isRecord11(v) {
12510
12790
  return typeof v === "object" && v !== null && !Array.isArray(v);
12511
12791
  }
12512
12792
  function isNonEmptyStringArray(v) {
@@ -12518,7 +12798,7 @@ function validateRedact(redact2) {
12518
12798
  }
12519
12799
  for (const r of redact2) {
12520
12800
  if (typeof r === "string") continue;
12521
- if (!isRecord10(r)) {
12801
+ if (!isRecord11(r)) {
12522
12802
  throw new Error("Invalid config: redact entries must be strings or objects");
12523
12803
  }
12524
12804
  if (typeof r.key !== "string" || r.key.trim() === "") {
@@ -12537,7 +12817,7 @@ function validateRedact(redact2) {
12537
12817
  }
12538
12818
  }
12539
12819
  function validateMappings(mappings) {
12540
- if (!isRecord10(mappings)) {
12820
+ if (!isRecord11(mappings)) {
12541
12821
  throw new Error("Invalid config: mappings must be an object");
12542
12822
  }
12543
12823
  }
@@ -12587,7 +12867,7 @@ async function loadLogIngestConfig(configPath) {
12587
12867
  const msg = e instanceof Error ? e.message : String(e);
12588
12868
  throw new Error(`Invalid JSON in config file: ${configPath} (${msg})`);
12589
12869
  }
12590
- if (!isRecord10(parsed)) {
12870
+ if (!isRecord11(parsed)) {
12591
12871
  throw new Error("Invalid config: expected a JSON object at top-level");
12592
12872
  }
12593
12873
  const user = parsed;
@@ -12624,7 +12904,7 @@ async function loadLogIngestConfig(configPath) {
12624
12904
  }
12625
12905
  return mergeLogIngestConfig(DEFAULT_LOG_INGEST_CONFIG, user);
12626
12906
  }
12627
- function isRecord11(v) {
12907
+ function isRecord12(v) {
12628
12908
  return typeof v === "object" && v !== null && !Array.isArray(v);
12629
12909
  }
12630
12910
  var JsonLogParser = class {
@@ -12649,7 +12929,7 @@ var JsonLogParser = class {
12649
12929
  });
12650
12930
  continue;
12651
12931
  }
12652
- if (!isRecord11(parsed)) {
12932
+ if (!isRecord12(parsed)) {
12653
12933
  warnings.push({
12654
12934
  code: "MALFORMED_JSON",
12655
12935
  message: "JSON log line must be an object",
@@ -12680,7 +12960,7 @@ var JsonLogParser = class {
12680
12960
  return this.parseLines(lines, filePath);
12681
12961
  }
12682
12962
  };
12683
- function isRecord12(v) {
12963
+ function isRecord13(v) {
12684
12964
  return typeof v === "object" && v !== null && !Array.isArray(v);
12685
12965
  }
12686
12966
  function findLastJsonObjectSubstring(line) {
@@ -12756,7 +13036,7 @@ var Log4jsParser = class {
12756
13036
  });
12757
13037
  continue;
12758
13038
  }
12759
- if (!isRecord12(parsed)) {
13039
+ if (!isRecord13(parsed)) {
12760
13040
  warnings.push({
12761
13041
  code: "UNSUPPORTED_LOG4JS_PAYLOAD",
12762
13042
  message: "Embedded JSON payload must be an object",
@@ -13630,7 +13910,7 @@ var EXPORT_PAYLOAD_VERSION = "0.1.2";
13630
13910
  // packages/core/src/exporters/redact-export.ts
13631
13911
  init_redactor();
13632
13912
  init_redaction_profiles();
13633
- function isRecord13(value) {
13913
+ function isRecord14(value) {
13634
13914
  return typeof value === "object" && value !== null && !Array.isArray(value);
13635
13915
  }
13636
13916
  function deepClone(value) {
@@ -13704,7 +13984,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
13704
13984
  0
13705
13985
  );
13706
13986
  const err = bounded.error;
13707
- if (isRecord13(err) && typeof err.message === "string") {
13987
+ if (isRecord14(err) && typeof err.message === "string") {
13708
13988
  bounded.error = {
13709
13989
  ...err,
13710
13990
  message: truncateStringForProfile(
@@ -13734,7 +14014,7 @@ function redactErrorInfo(error, redactor, maxMetadataValueLength, maxPreviewLeng
13734
14014
  maxPreviewLength
13735
14015
  );
13736
14016
  const redacted = record?.error;
13737
- if (!isRecord13(redacted) || typeof redacted.message !== "string") {
14017
+ if (!isRecord14(redacted) || typeof redacted.message !== "string") {
13738
14018
  return void 0;
13739
14019
  }
13740
14020
  return {
@@ -13814,7 +14094,7 @@ function redactTraceEventsForReport(events, options) {
13814
14094
  ) : void 0;
13815
14095
  const redactedActual = actualAttrs !== void 0 && "value" in actualAttrs ? actualAttrs.value : void 0;
13816
14096
  const redactedEvidence = event.evidence !== void 0 ? redactEventAttributes(
13817
- isRecord13(event.evidence) ? event.evidence : { value: event.evidence },
14097
+ isRecord14(event.evidence) ? event.evidence : { value: event.evidence },
13818
14098
  redactor,
13819
14099
  maxMetadataValueLength,
13820
14100
  maxPreviewLength
@@ -15834,7 +16114,7 @@ var STRICT_PROFILE_EXTRA_KEYS2 = [
15834
16114
  "retrieval",
15835
16115
  "query"
15836
16116
  ];
15837
- function isRecord14(value) {
16117
+ function isRecord15(value) {
15838
16118
  return typeof value === "object" && value !== null && !Array.isArray(value);
15839
16119
  }
15840
16120
  function toKey2(key) {
@@ -16199,7 +16479,7 @@ var Redactor2 = class {
16199
16479
  });
16200
16480
  return out;
16201
16481
  }
16202
- if (isRecord14(value)) {
16482
+ if (isRecord15(value)) {
16203
16483
  if (state.seen.has(value)) return state.seen.get(value);
16204
16484
  const out = {};
16205
16485
  state.seen.set(value, out);
@@ -16656,7 +16936,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
16656
16936
 
16657
16937
  // packages/cli/src/migrate.ts
16658
16938
  init_advanced();
16659
- function isRecord15(value) {
16939
+ function isRecord16(value) {
16660
16940
  return typeof value === "object" && value !== null && !Array.isArray(value);
16661
16941
  }
16662
16942
  function parseTarget(value) {
@@ -16665,7 +16945,7 @@ function parseTarget(value) {
16665
16945
  throw new Error('Unsupported migration target. Use "--to 1.0".');
16666
16946
  }
16667
16947
  function formatOf(value) {
16668
- if (!isRecord15(value)) return "unknown";
16948
+ if (!isRecord16(value)) return "unknown";
16669
16949
  if (value.schemaVersion === "0.1") return "0.1";
16670
16950
  if (value.schemaVersion === "0.2") return "0.2";
16671
16951
  if (value.schemaVersion === "1.0") return "1.0";