@agent-inspect/mcp-server 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.
@@ -669,12 +669,12 @@ function persistedInspectEventToTraceEvents(event) {
669
669
  if (!isPersistedInspectEvent(event)) {
670
670
  throw new Error("Invalid PersistedInspectEvent: failed isPersistedInspectEvent");
671
671
  }
672
- const legacyEvent = event.attributes?.legacyEvent;
673
- if (legacyEvent === "run_started") return [fromLegacyRunStarted(event)];
674
- if (legacyEvent === "run_completed") return [fromLegacyRunCompleted(event)];
675
- if (legacyEvent === "step_started") return [fromLegacyStepStarted(event)];
676
- if (legacyEvent === "step_completed") return [fromLegacyStepCompleted(event)];
677
- if (legacyEvent === "outcome_observed") return [fromLegacyOutcomeObserved(event)];
672
+ const legacyEvent2 = event.attributes?.legacyEvent;
673
+ if (legacyEvent2 === "run_started") return [fromLegacyRunStarted(event)];
674
+ if (legacyEvent2 === "run_completed") return [fromLegacyRunCompleted(event)];
675
+ if (legacyEvent2 === "step_started") return [fromLegacyStepStarted(event)];
676
+ if (legacyEvent2 === "step_completed") return [fromLegacyStepCompleted(event)];
677
+ if (legacyEvent2 === "outcome_observed") return [fromLegacyOutcomeObserved(event)];
678
678
  if (event.kind === "RUN") {
679
679
  return fromNativeRun(event);
680
680
  }
@@ -2567,6 +2567,289 @@ function diffRuns(left, right, options) {
2567
2567
  return table;
2568
2568
  })();
2569
2569
 
2570
+ // packages/core/src/checks/logical-events.ts
2571
+ function isRecord6(value) {
2572
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2573
+ }
2574
+ function legacyEvent(event) {
2575
+ const value = event.attributes?.legacyEvent;
2576
+ return typeof value === "string" ? value : void 0;
2577
+ }
2578
+ function stepIdOf(event) {
2579
+ const value = event.attributes?.stepId;
2580
+ if (typeof value === "string" && value.trim() !== "") return value;
2581
+ return void 0;
2582
+ }
2583
+ function cloneEvent(event) {
2584
+ return {
2585
+ ...event,
2586
+ ...event.attributes !== void 0 ? { attributes: { ...event.attributes } } : {},
2587
+ ...event.error !== void 0 ? { error: { ...event.error } } : {},
2588
+ ...event.tokenUsage !== void 0 ? { tokenUsage: { ...event.tokenUsage } } : {},
2589
+ ...event.source !== void 0 ? { source: { ...event.source } } : {}
2590
+ };
2591
+ }
2592
+ function mergeAttributes(start, complete) {
2593
+ const merged = {
2594
+ ...isRecord6(complete.attributes) ? complete.attributes : {},
2595
+ ...isRecord6(start.attributes) ? start.attributes : {}
2596
+ };
2597
+ merged.legacyEvent = start.attributes?.legacyEvent ?? complete.attributes?.legacyEvent;
2598
+ merged.legacyCompleteEvent = complete.attributes?.legacyEvent;
2599
+ if (complete.attributes?.errorStack !== void 0) {
2600
+ merged.errorStack = complete.attributes.errorStack;
2601
+ }
2602
+ return Object.keys(merged).length > 0 ? merged : void 0;
2603
+ }
2604
+ function pairStartComplete(start, complete) {
2605
+ const attributes = mergeAttributes(start, complete);
2606
+ const paired = {
2607
+ ...cloneEvent(start),
2608
+ status: complete.status,
2609
+ timestamp: complete.timestamp ?? start.timestamp,
2610
+ ...complete.endedAt !== void 0 ? { endedAt: complete.endedAt } : {},
2611
+ ...complete.durationMs !== void 0 ? { durationMs: complete.durationMs } : {},
2612
+ ...complete.error !== void 0 ? { error: { ...complete.error } } : {},
2613
+ ...complete.tokenUsage !== void 0 && start.tokenUsage === void 0 ? { tokenUsage: { ...complete.tokenUsage } } : {},
2614
+ ...attributes !== void 0 ? { attributes } : {}
2615
+ };
2616
+ return {
2617
+ ...paired,
2618
+ sourceEventIds: Object.freeze([start.eventId, complete.eventId]),
2619
+ projection: {
2620
+ paired: true,
2621
+ absorbedEventIds: Object.freeze([complete.eventId]),
2622
+ parentNormalized: false,
2623
+ ...start.parentId !== void 0 ? { originalParentId: start.parentId } : {}
2624
+ }
2625
+ };
2626
+ }
2627
+ function asLogical(event, extras) {
2628
+ return {
2629
+ ...cloneEvent(event),
2630
+ sourceEventIds: Object.freeze([event.eventId]),
2631
+ projection: {
2632
+ paired: false,
2633
+ absorbedEventIds: Object.freeze([]),
2634
+ parentNormalized: extras?.parentNormalized === true,
2635
+ ...{}
2636
+ }
2637
+ };
2638
+ }
2639
+ function projectLogicalEvents(events) {
2640
+ const diagnostics = [];
2641
+ const byRun = /* @__PURE__ */ new Map();
2642
+ for (const event of events) {
2643
+ const list = byRun.get(event.runId) ?? [];
2644
+ list.push(event);
2645
+ byRun.set(event.runId, list);
2646
+ }
2647
+ const absorbedIds = /* @__PURE__ */ new Set();
2648
+ const logicalByRawId = /* @__PURE__ */ new Map();
2649
+ const stepIdToLogicalId = /* @__PURE__ */ new Map();
2650
+ const logical = [];
2651
+ const orderedRuns = [...byRun.keys()].sort((a, b) => a.localeCompare(b));
2652
+ for (const runId of orderedRuns) {
2653
+ const runEvents = byRun.get(runId) ?? [];
2654
+ const starts = [];
2655
+ const completes = [];
2656
+ const others = [];
2657
+ for (const event of runEvents) {
2658
+ const legacy = legacyEvent(event);
2659
+ if (legacy === "step_started" || legacy === "run_started" && event.status === "running") {
2660
+ starts.push(event);
2661
+ } else if (legacy === "step_completed" || legacy === "run_completed") {
2662
+ completes.push(event);
2663
+ } else {
2664
+ others.push(event);
2665
+ }
2666
+ }
2667
+ const usedCompletes = /* @__PURE__ */ new Set();
2668
+ for (const start of starts) {
2669
+ const stepId = stepIdOf(start);
2670
+ let match;
2671
+ if (legacyEvent(start) === "run_started") {
2672
+ const candidates = completes.filter(
2673
+ (c) => !usedCompletes.has(c.eventId) && legacyEvent(c) === "run_completed"
2674
+ );
2675
+ if (candidates.length > 1) {
2676
+ diagnostics.push({
2677
+ code: "AI_LOGICAL_PAIR_AMBIGUOUS",
2678
+ message: `Multiple run_completed rows for run ${runId}; using first by eventId.`,
2679
+ eventIds: candidates.map((c) => c.eventId)
2680
+ });
2681
+ candidates.sort((a, b) => a.eventId.localeCompare(b.eventId));
2682
+ }
2683
+ match = candidates[0];
2684
+ } else if (stepId) {
2685
+ const candidates = completes.filter(
2686
+ (c) => !usedCompletes.has(c.eventId) && legacyEvent(c) === "step_completed" && stepIdOf(c) === stepId
2687
+ );
2688
+ if (candidates.length > 1) {
2689
+ diagnostics.push({
2690
+ code: "AI_LOGICAL_PAIR_AMBIGUOUS",
2691
+ message: `Multiple step_completed rows for stepId ${stepId}; using first by eventId.`,
2692
+ eventIds: candidates.map((c) => c.eventId)
2693
+ });
2694
+ candidates.sort((a, b) => a.eventId.localeCompare(b.eventId));
2695
+ }
2696
+ match = candidates[0];
2697
+ }
2698
+ if (match) {
2699
+ usedCompletes.add(match.eventId);
2700
+ absorbedIds.add(match.eventId);
2701
+ const paired = pairStartComplete(start, match);
2702
+ logical.push(paired);
2703
+ logicalByRawId.set(start.eventId, paired);
2704
+ logicalByRawId.set(match.eventId, paired);
2705
+ if (stepId) stepIdToLogicalId.set(`${runId}:${stepId}`, paired.eventId);
2706
+ } else {
2707
+ diagnostics.push({
2708
+ code: "AI_LOGICAL_PAIR_UNMATCHED_START",
2709
+ message: `No matching complete for start ${start.eventId}.`,
2710
+ eventIds: [start.eventId]
2711
+ });
2712
+ const alone = asLogical(start);
2713
+ logical.push(alone);
2714
+ logicalByRawId.set(start.eventId, alone);
2715
+ if (stepId) stepIdToLogicalId.set(`${runId}:${stepId}`, alone.eventId);
2716
+ }
2717
+ }
2718
+ for (const complete of completes) {
2719
+ if (usedCompletes.has(complete.eventId)) continue;
2720
+ diagnostics.push({
2721
+ code: "AI_LOGICAL_PAIR_UNMATCHED_COMPLETE",
2722
+ message: `No matching start for complete ${complete.eventId}.`,
2723
+ eventIds: [complete.eventId]
2724
+ });
2725
+ const alone = asLogical(complete);
2726
+ logical.push(alone);
2727
+ logicalByRawId.set(complete.eventId, alone);
2728
+ const stepId = stepIdOf(complete);
2729
+ if (stepId && !stepIdToLogicalId.has(`${runId}:${stepId}`)) {
2730
+ stepIdToLogicalId.set(`${runId}:${stepId}`, alone.eventId);
2731
+ }
2732
+ }
2733
+ for (const event of others) {
2734
+ const alone = asLogical(event);
2735
+ logical.push(alone);
2736
+ logicalByRawId.set(event.eventId, alone);
2737
+ const stepId = stepIdOf(event);
2738
+ if (stepId && !stepIdToLogicalId.has(`${runId}:${stepId}`)) {
2739
+ stepIdToLogicalId.set(`${runId}:${stepId}`, alone.eventId);
2740
+ }
2741
+ }
2742
+ }
2743
+ const logicalById = new Map(logical.map((e) => [e.eventId, e]));
2744
+ const normalized = [];
2745
+ for (const event of logical) {
2746
+ const originalParentId = event.parentId;
2747
+ if (!originalParentId) {
2748
+ normalized.push(event);
2749
+ continue;
2750
+ }
2751
+ let nextParent = originalParentId;
2752
+ let remapped = false;
2753
+ const viaAbsorbed = logicalByRawId.get(originalParentId);
2754
+ if (viaAbsorbed && viaAbsorbed.eventId !== originalParentId) {
2755
+ nextParent = viaAbsorbed.eventId;
2756
+ remapped = true;
2757
+ } else if (!logicalById.has(originalParentId)) {
2758
+ const viaStep = stepIdToLogicalId.get(`${event.runId}:${originalParentId}`);
2759
+ if (viaStep) {
2760
+ nextParent = viaStep;
2761
+ remapped = true;
2762
+ }
2763
+ }
2764
+ if (!remapped) {
2765
+ if (!logicalById.has(originalParentId) && !logicalByRawId.has(originalParentId)) {
2766
+ const mapping = event.attributes?.parentMapping;
2767
+ const unresolved = mapping === "unresolved" || event.attributes?.parentUnresolved === true || event.attributes?.unresolvedParent === true || // LangGraph/framework scaffolding sentinel labels are not event ids.
2768
+ /^LangGraph$/i.test(originalParentId) || originalParentId.startsWith("unresolved:");
2769
+ if (!unresolved) {
2770
+ diagnostics.push({
2771
+ code: "AI_LOGICAL_PARENT_UNRESOLVED",
2772
+ message: `Parent ${originalParentId} unresolved for ${event.eventId}.`,
2773
+ eventIds: [event.eventId]
2774
+ });
2775
+ }
2776
+ }
2777
+ normalized.push(event);
2778
+ continue;
2779
+ }
2780
+ diagnostics.push({
2781
+ code: "AI_LOGICAL_PARENT_REMAPPED",
2782
+ message: `Remapped parent ${originalParentId} \u2192 ${nextParent} for ${event.eventId}.`,
2783
+ eventIds: [event.eventId]
2784
+ });
2785
+ normalized.push({
2786
+ ...event,
2787
+ parentId: nextParent,
2788
+ projection: {
2789
+ ...event.projection,
2790
+ parentNormalized: true,
2791
+ originalParentId
2792
+ }
2793
+ });
2794
+ }
2795
+ const rawIndex = new Map(events.map((e, i) => [e.eventId, i]));
2796
+ normalized.sort((a, b) => {
2797
+ const ai = rawIndex.get(a.sourceEventIds[0]) ?? 0;
2798
+ const bi = rawIndex.get(b.sourceEventIds[0]) ?? 0;
2799
+ return ai - bi || a.eventId.localeCompare(b.eventId);
2800
+ });
2801
+ return {
2802
+ logicalEvents: Object.freeze(normalized),
2803
+ diagnostics: Object.freeze(diagnostics)
2804
+ };
2805
+ }
2806
+ function resolveCanonicalToolName(event) {
2807
+ const attrs = event.attributes;
2808
+ const direct = pickString(attrs, ["toolName", "tool"]);
2809
+ if (direct) return direct;
2810
+ const metadata = attrs?.metadata;
2811
+ if (isRecord6(metadata)) {
2812
+ const nested = pickString(metadata, ["toolName", "tool"]);
2813
+ if (nested) return nested;
2814
+ }
2815
+ for (const prefix of ["tool:", "function:", "mcp-tools:"]) {
2816
+ if (event.name.startsWith(prefix)) return event.name.slice(prefix.length);
2817
+ }
2818
+ return event.name;
2819
+ }
2820
+ function pickString(record, keys) {
2821
+ if (!record) return void 0;
2822
+ for (const key of keys) {
2823
+ const value = record[key];
2824
+ if (typeof value === "string" && value.trim() !== "") return value.trim();
2825
+ }
2826
+ return void 0;
2827
+ }
2828
+
2829
+ // packages/core/src/checks/trace-facts.ts
2830
+ function summarizeSemanticParity(events) {
2831
+ const projection = projectLogicalEvents(events);
2832
+ const logical = projection.logicalEvents;
2833
+ const finishedTools = logical.filter(
2834
+ (event) => event.kind === "TOOL" && event.status !== "running"
2835
+ );
2836
+ const finishedToolNames = Object.freeze(
2837
+ finishedTools.map((event) => resolveCanonicalToolName(event)).sort((a, b) => a.localeCompare(b))
2838
+ );
2839
+ return {
2840
+ rawEventCount: events.length,
2841
+ logicalEventCount: logical.length,
2842
+ runningLogicalCount: logical.filter((event) => event.status === "running").length,
2843
+ finishedToolNames,
2844
+ finishedToolCount: finishedTools.length,
2845
+ pairedCount: logical.filter((event) => event.projection.paired).length,
2846
+ parentRemapCount: projection.diagnostics.filter(
2847
+ (item) => item.code === "AI_LOGICAL_PARENT_REMAPPED"
2848
+ ).length,
2849
+ diagnostics: projection.diagnostics
2850
+ };
2851
+ }
2852
+
2570
2853
  // packages/core/src/checks/index.ts
2571
2854
  var SEVERITY_RANK = {
2572
2855
  error: 0,
@@ -2619,7 +2902,11 @@ var DEFAULT_RAW_CONTENT_KEYS = [
2619
2902
  "conversationtext",
2620
2903
  "conversation_text"
2621
2904
  ];
2622
- var DEFAULT_SAFE_RAW_CONTENT_PATH_PREFIXES = ["tokenUsage", "usage"];
2905
+ var DEFAULT_SAFE_RAW_CONTENT_PATH_PREFIXES = [
2906
+ "tokenUsage",
2907
+ "usage",
2908
+ "tokens"
2909
+ ];
2623
2910
  var SAFE_USAGE_LEAF_KEYS = /* @__PURE__ */ new Set([
2624
2911
  "input",
2625
2912
  "output",
@@ -2695,10 +2982,13 @@ function buildFacts(input, selectedRun) {
2695
2982
  childrenByParentId.set(parentId, children);
2696
2983
  }
2697
2984
  }
2985
+ const projection = projectLogicalEvents(scopedEvents);
2698
2986
  return {
2699
2987
  format: input.read.format,
2700
2988
  runs: Object.freeze([...input.read.runs]),
2701
2989
  events: Object.freeze([...scopedEvents]),
2990
+ logicalEvents: projection.logicalEvents,
2991
+ logicalProjectionDiagnostics: projection.diagnostics,
2702
2992
  readerWarnings: Object.freeze([...input.read.warnings]),
2703
2993
  unsupportedFields: Object.freeze([...input.read.unsupportedFields]),
2704
2994
  sourceFiles: Object.freeze([...input.read.sourceFiles]),
@@ -2863,7 +3153,10 @@ function failFinding(ruleId, message, evidence, expected, actual, meta) {
2863
3153
  ...meta?.action !== void 0 ? { action: meta.action } : {}
2864
3154
  };
2865
3155
  }
2866
- function isRecord6(value) {
3156
+ function semanticEvents(context) {
3157
+ return context.logicalEvents ?? context.events;
3158
+ }
3159
+ function isRecord7(value) {
2867
3160
  return typeof value === "object" && value !== null && !Array.isArray(value);
2868
3161
  }
2869
3162
  function normalizedKey(value) {
@@ -2894,7 +3187,7 @@ function pushValueEntries(entries, event, value, path16, key, depth = 0) {
2894
3187
  }
2895
3188
  return;
2896
3189
  }
2897
- if (!isRecord6(value)) return;
3190
+ if (!isRecord7(value)) return;
2898
3191
  for (const nestedKey of Object.keys(value).sort((a, b) => a.localeCompare(b))) {
2899
3192
  pushValueEntries(
2900
3193
  entries,
@@ -2976,7 +3269,7 @@ function createRunStatusRule(options = {}) {
2976
3269
  );
2977
3270
  }
2978
3271
  if (!allowIncomplete) {
2979
- const running = context.events.filter((event) => event.status === "running");
3272
+ const running = semanticEvents(context).filter((event) => event.status === "running");
2980
3273
  if (running.length > 0) {
2981
3274
  findings.push(
2982
3275
  failFinding(
@@ -3144,7 +3437,7 @@ function createSafetyOversizedAttributeRule(options) {
3144
3437
  )
3145
3438
  );
3146
3439
  }
3147
- if (isRecord6(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
3440
+ if (isRecord7(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
3148
3441
  findings.push(
3149
3442
  failFinding(
3150
3443
  "safety.oversizedAttribute",
@@ -3233,14 +3526,14 @@ function runTraceChecks(input, options = {}) {
3233
3526
  }
3234
3527
 
3235
3528
  // packages/core/src/persisted/token-usage.ts
3236
- function isRecord7(value) {
3529
+ function isRecord8(value) {
3237
3530
  return typeof value === "object" && value !== null && !Array.isArray(value);
3238
3531
  }
3239
3532
  function nonNegativeFinite(value) {
3240
3533
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
3241
3534
  }
3242
3535
  function normalizeTokenUsage(value) {
3243
- if (!isRecord7(value)) return void 0;
3536
+ if (!isRecord8(value)) return void 0;
3244
3537
  const input = nonNegativeFinite(value.input);
3245
3538
  const output = nonNegativeFinite(value.output);
3246
3539
  const suppliedTotal = nonNegativeFinite(value.total);
@@ -4009,7 +4302,7 @@ function persistedEventsForParsedTrace(parsed) {
4009
4302
  sourceName: "agent-inspect-jsonl-reader"
4010
4303
  });
4011
4304
  }
4012
- function isRecord8(value) {
4305
+ function isRecord9(value) {
4013
4306
  return typeof value === "object" && value !== null && !Array.isArray(value);
4014
4307
  }
4015
4308
  function isNonEmptyString3(value) {
@@ -4024,13 +4317,13 @@ function readStringField(record, keys) {
4024
4317
  }
4025
4318
  function readRecordField(record, key) {
4026
4319
  const value = record[key];
4027
- return isRecord8(value) ? value : void 0;
4320
+ return isRecord9(value) ? value : void 0;
4028
4321
  }
4029
4322
  function parseJsonDocument(content) {
4030
4323
  return JSON.parse(content);
4031
4324
  }
4032
4325
  function looksLikeOpenInferenceSpan(value) {
4033
- if (!isRecord8(value)) return false;
4326
+ if (!isRecord9(value)) return false;
4034
4327
  const attributes = readRecordField(value, "attributes");
4035
4328
  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);
4036
4329
  }
@@ -4055,7 +4348,7 @@ function extractOpenInferenceDocument(root) {
4055
4348
  unsupportedFields
4056
4349
  };
4057
4350
  }
4058
- if (!isRecord8(root)) return void 0;
4351
+ if (!isRecord9(root)) return void 0;
4059
4352
  const rootFormat = root.format;
4060
4353
  const rootCompatibility = root.compatibility;
4061
4354
  const version = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
@@ -4195,7 +4488,7 @@ function summarizeAttributeValue(value) {
4195
4488
  if (Array.isArray(value)) {
4196
4489
  return { type: "array", length: value.length };
4197
4490
  }
4198
- if (isRecord8(value)) {
4491
+ if (isRecord9(value)) {
4199
4492
  return { type: "object", keyCount: Object.keys(value).length };
4200
4493
  }
4201
4494
  if (value === null) {
@@ -4282,7 +4575,7 @@ function mapOpenInferenceKind(span, attributes, pathPrefix) {
4282
4575
  }
4283
4576
  }
4284
4577
  function mapOpenInferenceStatus(status) {
4285
- if (!isRecord8(status)) return void 0;
4578
+ if (!isRecord9(status)) return void 0;
4286
4579
  const rawCode = status.code;
4287
4580
  if (typeof rawCode !== "string") return void 0;
4288
4581
  switch (rawCode.toUpperCase()) {
@@ -4382,7 +4675,7 @@ function mapOpenInferenceSpan(span, index, version) {
4382
4675
  warnings.push(...kindWarnings);
4383
4676
  const status = mapOpenInferenceStatus(span.status);
4384
4677
  const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
4385
- const errorMessage = isRecord8(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
4678
+ const errorMessage = isRecord9(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
4386
4679
  const event = {
4387
4680
  schemaVersion: "0.2",
4388
4681
  eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
@@ -4528,7 +4821,7 @@ var openInferenceJsonReader = {
4528
4821
  }
4529
4822
  };
4530
4823
  function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
4531
- if (!isRecord8(value)) {
4824
+ if (!isRecord9(value)) {
4532
4825
  unsupportedFields.push(field);
4533
4826
  warnings.push({
4534
4827
  code: "otlp_attribute_value_invalid",
@@ -4550,15 +4843,15 @@ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
4550
4843
  if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
4551
4844
  return value.doubleValue;
4552
4845
  }
4553
- if (isRecord8(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
4846
+ if (isRecord9(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
4554
4847
  return value.arrayValue.values.map(
4555
4848
  (item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
4556
4849
  );
4557
4850
  }
4558
- if (isRecord8(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
4851
+ if (isRecord9(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
4559
4852
  const out = {};
4560
4853
  for (const [index, item] of value.kvlistValue.values.entries()) {
4561
- if (!isRecord8(item) || typeof item.key !== "string") {
4854
+ if (!isRecord9(item) || typeof item.key !== "string") {
4562
4855
  unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
4563
4856
  continue;
4564
4857
  }
@@ -4609,7 +4902,7 @@ function parseOtlpAttributes(value, pathPrefix) {
4609
4902
  }
4610
4903
  for (const [index, item] of value.entries()) {
4611
4904
  const field = `${pathPrefix}[${index}]`;
4612
- if (!isRecord8(item) || typeof item.key !== "string") {
4905
+ if (!isRecord9(item) || typeof item.key !== "string") {
4613
4906
  unsupportedFields.push(field);
4614
4907
  warnings.push({
4615
4908
  code: "otlp_attribute_invalid",
@@ -4632,16 +4925,16 @@ function parseOtlpAttributes(value, pathPrefix) {
4632
4925
  return { attributes, warnings, unsupportedFields };
4633
4926
  }
4634
4927
  function looksLikeOtlpSpan(value) {
4635
- return isRecord8(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
4928
+ return isRecord9(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
4636
4929
  }
4637
4930
  function extractOtlpDocument(root) {
4638
- if (!isRecord8(root) || !Array.isArray(root.resourceSpans)) return void 0;
4931
+ if (!isRecord9(root) || !Array.isArray(root.resourceSpans)) return void 0;
4639
4932
  const spans = [];
4640
4933
  const warnings = [];
4641
4934
  const unsupportedFields = [];
4642
4935
  for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
4643
4936
  const resourcePath = `resourceSpans[${resourceIndex}]`;
4644
- if (!isRecord8(resourceSpan)) {
4937
+ if (!isRecord9(resourceSpan)) {
4645
4938
  unsupportedFields.push(resourcePath);
4646
4939
  continue;
4647
4940
  }
@@ -4664,7 +4957,7 @@ function extractOtlpDocument(root) {
4664
4957
  }
4665
4958
  for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
4666
4959
  const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
4667
- if (!isRecord8(scopeSpan)) {
4960
+ if (!isRecord9(scopeSpan)) {
4668
4961
  unsupportedFields.push(scopePath);
4669
4962
  continue;
4670
4963
  }
@@ -4731,7 +5024,7 @@ function extractOtlpDocument(root) {
4731
5024
  };
4732
5025
  }
4733
5026
  function mapOtlpStatus(status) {
4734
- if (!isRecord8(status)) return void 0;
5027
+ if (!isRecord9(status)) return void 0;
4735
5028
  const rawCode = status.code;
4736
5029
  if (typeof rawCode !== "string") return void 0;
4737
5030
  switch (rawCode.toUpperCase()) {
@@ -4831,7 +5124,7 @@ function mapOtlpEvents(value, pathPrefix) {
4831
5124
  const events = [];
4832
5125
  for (const [index, event] of value.entries()) {
4833
5126
  const eventPath = `${pathPrefix}[${index}]`;
4834
- if (!isRecord8(event)) {
5127
+ if (!isRecord9(event)) {
4835
5128
  unsupportedFields.push(eventPath);
4836
5129
  continue;
4837
5130
  }
@@ -4969,7 +5262,7 @@ function mapOtlpSpan(context) {
4969
5262
  warnings.push(...kindWarnings);
4970
5263
  const status = mapOtlpStatus(span.status);
4971
5264
  const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
4972
- const errorMessage = isRecord8(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
5265
+ const errorMessage = isRecord9(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
4973
5266
  const event = {
4974
5267
  schemaVersion: "0.2",
4975
5268
  eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
@@ -5315,7 +5608,7 @@ function openTrace(input, options = {}) {
5315
5608
  var EXPORT_PAYLOAD_VERSION = "0.1.2";
5316
5609
 
5317
5610
  // packages/core/src/exporters/redact-export.ts
5318
- function isRecord9(value) {
5611
+ function isRecord10(value) {
5319
5612
  return typeof value === "object" && value !== null && !Array.isArray(value);
5320
5613
  }
5321
5614
  function deepClone(value) {
@@ -5389,7 +5682,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
5389
5682
  0
5390
5683
  );
5391
5684
  const err = bounded.error;
5392
- if (isRecord9(err) && typeof err.message === "string") {
5685
+ if (isRecord10(err) && typeof err.message === "string") {
5393
5686
  bounded.error = {
5394
5687
  ...err,
5395
5688
  message: truncateStringForProfile(
@@ -6051,7 +6344,7 @@ var STRICT_PROFILE_EXTRA_KEYS2 = [
6051
6344
  "retrieval",
6052
6345
  "query"
6053
6346
  ];
6054
- function isRecord10(value) {
6347
+ function isRecord11(value) {
6055
6348
  return typeof value === "object" && value !== null && !Array.isArray(value);
6056
6349
  }
6057
6350
  function toKey2(key) {
@@ -6416,7 +6709,7 @@ var Redactor2 = class {
6416
6709
  });
6417
6710
  return out;
6418
6711
  }
6419
- if (isRecord10(value)) {
6712
+ if (isRecord11(value)) {
6420
6713
  if (state.seen.has(value)) return state.seen.get(value);
6421
6714
  const out = {};
6422
6715
  state.seen.set(value, out);
@@ -6794,7 +7087,8 @@ async function callReadOnlyTool(context, name, args = {}) {
6794
7087
  sourceFile: path14.basename(meta.filePath),
6795
7088
  warnings: read.warnings.slice(0, 20),
6796
7089
  unsupportedFields: read.unsupportedFields.slice(0, 20),
6797
- note: "Bounded local diagnostics only; not a network health check."
7090
+ semanticParity: summarizeSemanticParity(read.events),
7091
+ note: "Bounded local diagnostics only; not a network health check. semanticParity uses logicalEvents projection."
6798
7092
  },
6799
7093
  context
6800
7094
  );
@@ -7237,5 +7531,5 @@ async function runReadOnlyMcpServer(options = {}) {
7237
7531
  }
7238
7532
 
7239
7533
  export { MCP_MAX_REQUEST_BYTES, MCP_PROTOCOL_VERSION, READ_ONLY_TOOLS, callReadOnlyTool, createMcpServerContext, handleMcpProtocolLine, runReadOnlyMcpServer };
7240
- //# sourceMappingURL=chunk-YSGVFUHF.mjs.map
7241
- //# sourceMappingURL=chunk-YSGVFUHF.mjs.map
7534
+ //# sourceMappingURL=chunk-TLE64A3T.mjs.map
7535
+ //# sourceMappingURL=chunk-TLE64A3T.mjs.map