agent-inspect 6.31.20 → 6.31.22

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/packages/cli/dist/{chunk-EVSIYDB2.mjs → chunk-EMWA5EKU.mjs} +324 -35
  5. package/packages/cli/dist/chunk-EMWA5EKU.mjs.map +1 -0
  6. package/packages/cli/dist/index.cjs +403 -60
  7. package/packages/cli/dist/index.cjs.map +1 -1
  8. package/packages/cli/dist/index.mjs +75 -31
  9. package/packages/cli/dist/index.mjs.map +1 -1
  10. package/packages/cli/dist/{src-NWDDK72G.mjs → src-VZHGOLTO.mjs} +3 -3
  11. package/packages/cli/dist/{src-NWDDK72G.mjs.map → src-VZHGOLTO.mjs.map} +1 -1
  12. package/packages/core/dist/advanced.cjs +247 -5
  13. package/packages/core/dist/advanced.cjs.map +1 -1
  14. package/packages/core/dist/advanced.mjs +6 -5
  15. package/packages/core/dist/advanced.mjs.map +1 -1
  16. package/packages/core/dist/checks.cjs +184 -31
  17. package/packages/core/dist/checks.cjs.map +1 -1
  18. package/packages/core/dist/checks.mjs +2 -1
  19. package/packages/core/dist/chunk-GCZUWY47.mjs +182 -0
  20. package/packages/core/dist/chunk-GCZUWY47.mjs.map +1 -0
  21. package/packages/core/dist/{chunk-JE3TUFAQ.mjs → chunk-RBXD7BNX.mjs} +3 -3
  22. package/packages/core/dist/{chunk-JE3TUFAQ.mjs.map → chunk-RBXD7BNX.mjs.map} +1 -1
  23. package/packages/core/dist/{chunk-YU6XT5A2.mjs → chunk-S4NU55LU.mjs} +45 -3
  24. package/packages/core/dist/chunk-S4NU55LU.mjs.map +1 -0
  25. package/packages/core/dist/{chunk-EIP5CNEL.mjs → chunk-UPGBMRL4.mjs} +49 -3
  26. package/packages/core/dist/chunk-UPGBMRL4.mjs.map +1 -0
  27. package/packages/core/dist/{chunk-GFQPPNSF.mjs → chunk-ZOF6ON65.mjs} +128 -103
  28. package/packages/core/dist/chunk-ZOF6ON65.mjs.map +1 -0
  29. package/packages/core/dist/exporters.cjs +82 -27
  30. package/packages/core/dist/exporters.cjs.map +1 -1
  31. package/packages/core/dist/exporters.mjs +72 -27
  32. package/packages/core/dist/exporters.mjs.map +1 -1
  33. package/packages/core/dist/logs.cjs +197 -1
  34. package/packages/core/dist/logs.cjs.map +1 -1
  35. package/packages/core/dist/logs.mjs +3 -2
  36. package/packages/core/dist/logs.mjs.map +1 -1
  37. package/packages/core/dist/persisted.cjs +197 -1
  38. package/packages/core/dist/persisted.cjs.map +1 -1
  39. package/packages/core/dist/persisted.mjs +4 -3
  40. package/packages/core/dist/persisted.mjs.map +1 -1
  41. package/packages/core/dist/readers.cjs +243 -1
  42. package/packages/core/dist/readers.cjs.map +1 -1
  43. package/packages/core/dist/readers.mjs +4 -3
  44. package/packages/cli/dist/chunk-EVSIYDB2.mjs.map +0 -1
  45. package/packages/core/dist/chunk-EIP5CNEL.mjs.map +0 -1
  46. package/packages/core/dist/chunk-GFQPPNSF.mjs.map +0 -1
  47. package/packages/core/dist/chunk-YU6XT5A2.mjs.map +0 -1
@@ -8114,6 +8114,121 @@ var init_tool_arguments = __esm({
8114
8114
  }
8115
8115
  });
8116
8116
 
8117
+ // packages/core/src/persisted/delivery-identity.ts
8118
+ function stripReaderDeliveryDiscriminator(eventId) {
8119
+ if (!SYNTHETIC_DELIVERY_ID.test(eventId)) return eventId;
8120
+ return eventId.replace(/:\d+$/, "");
8121
+ }
8122
+ function canonicalDigest(value) {
8123
+ if (value === void 0) return null;
8124
+ const encoded = encodeCanonicalStructured(value);
8125
+ return encoded.ok ? encoded.value : `unencodable:${encoded.code}`;
8126
+ }
8127
+ function capturedContentDigest(attributes) {
8128
+ if (!attributes || typeof attributes !== "object") {
8129
+ return { args: null, result: null };
8130
+ }
8131
+ const nested = attributes.metadata && typeof attributes.metadata === "object" ? attributes.metadata : void 0;
8132
+ const args = attributes.arguments ?? attributes.args ?? attributes.input ?? nested?.arguments ?? nested?.args ?? nested?.input;
8133
+ const result = attributes.result ?? attributes.output ?? attributes.response ?? nested?.result ?? nested?.output ?? nested?.response;
8134
+ return {
8135
+ args: args === void 0 ? null : canonicalDigest(args),
8136
+ result: result === void 0 ? null : canonicalDigest(result)
8137
+ };
8138
+ }
8139
+ function timeKey(fields) {
8140
+ if (typeof fields.startedAt === "string" && fields.startedAt.trim() !== "") {
8141
+ return fields.startedAt;
8142
+ }
8143
+ if (typeof fields.timestamp === "string" && fields.timestamp.trim() !== "") {
8144
+ return fields.timestamp;
8145
+ }
8146
+ if (typeof fields.timestamp === "number" && Number.isFinite(fields.timestamp)) {
8147
+ return String(fields.timestamp);
8148
+ }
8149
+ return null;
8150
+ }
8151
+ function deliverySemanticFingerprint(fields) {
8152
+ const content = capturedContentDigest(fields.attributes);
8153
+ return JSON.stringify({
8154
+ stableEventId: stripReaderDeliveryDiscriminator(fields.eventId),
8155
+ runId: fields.runId,
8156
+ kind: fields.kind,
8157
+ name: fields.name,
8158
+ status: fields.status ?? null,
8159
+ parentId: fields.parentId ?? null,
8160
+ sourceType: fields.sourceType ?? null,
8161
+ time: timeKey(fields),
8162
+ operationId: fields.operationId ?? null,
8163
+ attemptId: fields.attemptId ?? null,
8164
+ attemptNumber: fields.attemptNumber ?? null,
8165
+ retryOf: fields.retryOf ?? null,
8166
+ argsDigest: content.args,
8167
+ resultDigest: content.result
8168
+ });
8169
+ }
8170
+ function identityFieldsFromAttributes(attributes) {
8171
+ if (!attributes || typeof attributes !== "object") {
8172
+ return {
8173
+ operationId: null,
8174
+ attemptId: null,
8175
+ attemptNumber: null,
8176
+ retryOf: null
8177
+ };
8178
+ }
8179
+ const nested = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? attributes.metadata : void 0;
8180
+ const pickString3 = (key) => {
8181
+ const direct = attributes[key];
8182
+ if (typeof direct === "string" && direct.trim() !== "") return direct.trim();
8183
+ const nestedValue = nested?.[key];
8184
+ if (typeof nestedValue === "string" && nestedValue.trim() !== "") {
8185
+ return nestedValue.trim();
8186
+ }
8187
+ return null;
8188
+ };
8189
+ const pickNumber2 = () => {
8190
+ const direct = attributes.attemptNumber ?? attributes.attempt;
8191
+ if (typeof direct === "number" && Number.isFinite(direct)) return direct;
8192
+ const nestedValue = nested?.attemptNumber ?? nested?.attempt;
8193
+ if (typeof nestedValue === "number" && Number.isFinite(nestedValue)) {
8194
+ return nestedValue;
8195
+ }
8196
+ return null;
8197
+ };
8198
+ return {
8199
+ operationId: pickString3("operationId"),
8200
+ attemptId: pickString3("attemptId"),
8201
+ retryOf: pickString3("retryOf"),
8202
+ attemptNumber: pickNumber2()
8203
+ };
8204
+ }
8205
+ function hasDeliveryConflictMarker(attributes) {
8206
+ return attributes?.[DELIVERY_CONFLICT_ATTR] === true;
8207
+ }
8208
+ function stampDeliveryConflict(event) {
8209
+ return {
8210
+ ...event,
8211
+ attributes: {
8212
+ ...event.attributes ?? {},
8213
+ [DELIVERY_CONFLICT_ATTR]: true
8214
+ }
8215
+ };
8216
+ }
8217
+ var DELIVERY_CONFLICT_ATTR, IDENTITY_CONFLICT_ATTR, SYNTHETIC_DELIVERY_ID;
8218
+ var init_delivery_identity = __esm({
8219
+ "packages/core/src/persisted/delivery-identity.ts"() {
8220
+ init_canonical_equality();
8221
+ DELIVERY_CONFLICT_ATTR = "agent_inspect.delivery_conflict";
8222
+ IDENTITY_CONFLICT_ATTR = {
8223
+ operationId: "agent_inspect.identity_conflict.operation_id",
8224
+ attemptId: "agent_inspect.identity_conflict.attempt_id",
8225
+ retryOf: "agent_inspect.identity_conflict.retry_of",
8226
+ attemptNumber: "agent_inspect.identity_conflict.attempt_number"
8227
+ };
8228
+ SYNTHETIC_DELIVERY_ID = /^(?:manual|inspect):[A-Za-z0-9_-]+:[A-Za-z0-9_-]+:[A-Za-z0-9_-]+:\d+$/;
8229
+ }
8230
+ });
8231
+
8117
8232
  // packages/core/src/checks/retry-safety.ts
8118
8233
  function fail2(ruleId, message, evidence, expected, actual) {
8119
8234
  return {
@@ -8169,7 +8284,7 @@ function attemptIdOf(event) {
8169
8284
  }
8170
8285
  function countOperationAttempts(members) {
8171
8286
  const identified = /* @__PURE__ */ new Set();
8172
- let unidentified = 0;
8287
+ const unidentifiedFingerprints = /* @__PURE__ */ new Set();
8173
8288
  for (const event of members) {
8174
8289
  if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
8175
8290
  const id = attemptIdOf(event);
@@ -8177,13 +8292,13 @@ function countOperationAttempts(members) {
8177
8292
  identified.add(id);
8178
8293
  continue;
8179
8294
  }
8180
- unidentified += 1;
8295
+ unidentifiedFingerprints.add(redeliveryFingerprint(event));
8181
8296
  }
8182
8297
  if (identified.size > 0) {
8183
- return identified.size + unidentified;
8298
+ return identified.size + unidentifiedFingerprints.size;
8184
8299
  }
8185
8300
  const numbered = /* @__PURE__ */ new Set();
8186
- let unnumbered = 0;
8301
+ const unnumberedFingerprints = /* @__PURE__ */ new Set();
8187
8302
  for (const event of members) {
8188
8303
  if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
8189
8304
  const num2 = attemptNumberOf(event);
@@ -8191,12 +8306,12 @@ function countOperationAttempts(members) {
8191
8306
  numbered.add(num2);
8192
8307
  continue;
8193
8308
  }
8194
- unnumbered += 1;
8309
+ unnumberedFingerprints.add(redeliveryFingerprint(event));
8195
8310
  }
8196
8311
  if (numbered.size > 0) {
8197
- return numbered.size + unnumbered;
8312
+ return numbered.size + unnumberedFingerprints.size;
8198
8313
  }
8199
- return unnumbered;
8314
+ return unnumberedFingerprints.size;
8200
8315
  }
8201
8316
  function classifyRetryAttempt(event, priorOrdered, allMembers) {
8202
8317
  const workflow = workflowFor(event);
@@ -8246,13 +8361,87 @@ function classifyRetryAttempt(event, priorOrdered, allMembers) {
8246
8361
  }
8247
8362
  return { kind: "unknown", reason: "ambiguous attempt identity" };
8248
8363
  }
8249
- function hasDuplicateAttemptIds(members) {
8250
- const seen = /* @__PURE__ */ new Set();
8364
+ function redeliveryFingerprint(event) {
8365
+ const workflow = workflowFor(event);
8366
+ return deliverySemanticFingerprint({
8367
+ eventId: event.eventId ?? "",
8368
+ runId: event.runId,
8369
+ kind: event.kind,
8370
+ name: event.name,
8371
+ status: event.status,
8372
+ parentId: event.parentId,
8373
+ timestamp: event.timestamp,
8374
+ startedAt: event.startedAt,
8375
+ sourceType: event.source?.type,
8376
+ attributes: event.attributes && typeof event.attributes === "object" ? event.attributes : void 0,
8377
+ operationId: workflow.operationId ?? null,
8378
+ attemptId: workflow.attemptId ?? null,
8379
+ attemptNumber: workflow.attemptNumber ?? null,
8380
+ retryOf: workflow.retryOf ?? null
8381
+ });
8382
+ }
8383
+ function identityValuesEqual(a, b) {
8384
+ if (typeof a === "number" && typeof b === "number") {
8385
+ return Number.isFinite(a) && Number.isFinite(b) && a === b;
8386
+ }
8387
+ if (typeof a === "string" && typeof b === "string") {
8388
+ return a.trim() === b.trim();
8389
+ }
8390
+ return a === b;
8391
+ }
8392
+ function directNestedIdentityConflicts(event) {
8393
+ const attrs = event.attributes;
8394
+ if (!attrs || typeof attrs !== "object") return [];
8395
+ const nested = attrs.metadata && typeof attrs.metadata === "object" && !Array.isArray(attrs.metadata) ? attrs.metadata : void 0;
8396
+ if (!nested) return [];
8397
+ const conflicts = [];
8398
+ for (const key of IDENTITY_KEYS) {
8399
+ const direct = attrs[key];
8400
+ const nestedValue = nested[key];
8401
+ if (direct === void 0 || nestedValue === void 0) continue;
8402
+ if (!identityValuesEqual(direct, nestedValue)) {
8403
+ conflicts.push(key);
8404
+ }
8405
+ }
8406
+ return conflicts;
8407
+ }
8408
+ function hasConflictingAttemptIdReuse(members) {
8409
+ const byAttempt = /* @__PURE__ */ new Map();
8251
8410
  for (const event of members) {
8411
+ if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
8252
8412
  const id = attemptIdOf(event);
8253
8413
  if (!id) continue;
8254
- if (seen.has(id)) return true;
8255
- seen.add(id);
8414
+ const fingerprints = byAttempt.get(id) ?? /* @__PURE__ */ new Set();
8415
+ fingerprints.add(redeliveryFingerprint(event));
8416
+ byAttempt.set(id, fingerprints);
8417
+ }
8418
+ for (const fingerprints of byAttempt.values()) {
8419
+ if (fingerprints.size > 1) return true;
8420
+ }
8421
+ return false;
8422
+ }
8423
+ function hasConflictingEventIdReuse(members) {
8424
+ const byEventId = /* @__PURE__ */ new Map();
8425
+ for (const event of members) {
8426
+ if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
8427
+ const eventId = event.eventId;
8428
+ if (!eventId) continue;
8429
+ if (hasDeliveryConflictMarker(event.attributes)) {
8430
+ return true;
8431
+ }
8432
+ const fingerprints = byEventId.get(eventId) ?? /* @__PURE__ */ new Set();
8433
+ fingerprints.add(redeliveryFingerprint(event));
8434
+ byEventId.set(eventId, fingerprints);
8435
+ }
8436
+ for (const fingerprints of byEventId.values()) {
8437
+ if (fingerprints.size > 1) return true;
8438
+ }
8439
+ return false;
8440
+ }
8441
+ function hasIdentityRepresentationConflict(members) {
8442
+ for (const event of members) {
8443
+ if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
8444
+ if (directNestedIdentityConflicts(event).length > 0) return true;
8256
8445
  }
8257
8446
  return false;
8258
8447
  }
@@ -8263,23 +8452,49 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8263
8452
  const workflow = workflowFor(event);
8264
8453
  const operationId = workflow.operationId;
8265
8454
  if (!operationId) continue;
8266
- const list2 = byOperation.get(operationId) ?? [];
8267
- list2.push(event);
8268
- byOperation.set(operationId, list2);
8455
+ const key = `${event.runId}\0${operationId}`;
8456
+ const group = byOperation.get(key) ?? { operationId, members: [] };
8457
+ group.members.push(event);
8458
+ byOperation.set(key, group);
8269
8459
  }
8270
8460
  if (rules.maxAttempts !== void 0) {
8271
- for (const [operationId, members] of byOperation) {
8272
- if (hasDuplicateAttemptIds(members)) {
8461
+ for (const { operationId, members } of byOperation.values()) {
8462
+ if (hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members)) {
8273
8463
  findings.push(
8274
8464
  fail2(
8275
8465
  "contract.retry.duplicate-attempt-id",
8276
- `Operation ${operationId} has duplicate attemptId values.`,
8466
+ `Operation ${operationId} has conflicting attemptId reuse (distinct executions).`,
8277
8467
  members.slice(0, 4).map(eventEvidence2),
8278
8468
  "unique attemptId",
8279
8469
  "duplicate"
8280
8470
  )
8281
8471
  );
8282
8472
  }
8473
+ if (hasIdentityRepresentationConflict(members)) {
8474
+ findings.push(
8475
+ fail2(
8476
+ "contract.retry.ambiguous-identity",
8477
+ `Operation ${operationId} has conflicting direct vs nested identity fields; strict identity cannot pass.`,
8478
+ members.slice(0, 4).map(eventEvidence2),
8479
+ "agreeing identity representation",
8480
+ "direct/nested conflict"
8481
+ )
8482
+ );
8483
+ }
8484
+ const toolish = members.filter((event) => event.kind === "TOOL" || event.kind === "LLM");
8485
+ const hasAttemptId = toolish.some((event) => attemptIdOf(event) !== void 0);
8486
+ const missingAttemptId = toolish.some((event) => attemptIdOf(event) === void 0);
8487
+ if (hasAttemptId && missingAttemptId) {
8488
+ findings.push(
8489
+ fail2(
8490
+ "contract.retry.ambiguous-identity",
8491
+ `Operation ${operationId} has partial attempt identity; strict identity conformance cannot pass.`,
8492
+ members.slice(0, 4).map(eventEvidence2),
8493
+ "complete attempt identity",
8494
+ "partial attemptId coverage"
8495
+ )
8496
+ );
8497
+ }
8283
8498
  const count = countOperationAttempts(members);
8284
8499
  if (count > rules.maxAttempts) {
8285
8500
  findings.push(
@@ -8295,7 +8510,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8295
8510
  }
8296
8511
  }
8297
8512
  if (rules.requireTerminalResult) {
8298
- for (const [operationId, members] of byOperation) {
8513
+ for (const { operationId, members } of byOperation.values()) {
8299
8514
  const hasTerminal = members.some((event) => event.status === "ok" || event.status === "error");
8300
8515
  if (!hasTerminal) {
8301
8516
  findings.push(
@@ -8315,7 +8530,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8315
8530
  const workflow = workflowFor(event);
8316
8531
  const fallbackOf = workflow.fallbackOf;
8317
8532
  if (!fallbackOf) continue;
8318
- const prior = byOperation.get(fallbackOf) ?? [];
8533
+ const prior = byOperation.get(`${event.runId}\0${fallbackOf}`)?.members ?? [];
8319
8534
  const fallbackStart = eventTime(event);
8320
8535
  const earlierFailure = prior.some(
8321
8536
  (candidate) => candidate.status === "error" && eventTime(candidate) !== "" && fallbackStart !== "" && eventTime(candidate) < fallbackStart
@@ -8342,7 +8557,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8342
8557
  for (const event of toolEvents) {
8343
8558
  const name = resolveCanonicalToolName(event);
8344
8559
  const workflow = workflowFor(event);
8345
- const key = `${workflow.operationId ?? name}::${name}`;
8560
+ const key = `${event.runId}::${workflow.operationId ?? name}::${name}`;
8346
8561
  const list2 = byToolOp.get(key) ?? [];
8347
8562
  list2.push(event);
8348
8563
  byToolOp.set(key, list2);
@@ -8400,7 +8615,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8400
8615
  }
8401
8616
  }
8402
8617
  if (rules.requireRecoveredFailureVisible) {
8403
- for (const [operationId, members] of byOperation) {
8618
+ for (const { operationId, members } of byOperation.values()) {
8404
8619
  const ordered = sortByTime(members);
8405
8620
  const toolish = ordered.filter(
8406
8621
  (event) => (event.kind === "TOOL" || event.kind === "LLM") && (event.status === "ok" || event.status === "error")
@@ -8439,10 +8654,13 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8439
8654
  }
8440
8655
  return findings;
8441
8656
  }
8657
+ var IDENTITY_KEYS;
8442
8658
  var init_retry_safety = __esm({
8443
8659
  "packages/core/src/checks/retry-safety.ts"() {
8444
8660
  init_logical_events();
8661
+ init_delivery_identity();
8445
8662
  init_metadata();
8663
+ IDENTITY_KEYS = ["operationId", "attemptId", "retryOf", "attemptNumber"];
8446
8664
  }
8447
8665
  });
8448
8666
 
@@ -8658,15 +8876,8 @@ function attemptIdOf2(event) {
8658
8876
  const value = workflowFor2(event).attemptId;
8659
8877
  return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
8660
8878
  }
8661
- function hasDuplicateAttemptIds2(members) {
8662
- const seen = /* @__PURE__ */ new Set();
8663
- for (const event of members) {
8664
- const id = attemptIdOf2(event);
8665
- if (!id) continue;
8666
- if (seen.has(id)) return true;
8667
- seen.add(id);
8668
- }
8669
- return false;
8879
+ function hasDuplicateAttemptIds(members) {
8880
+ return hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members);
8670
8881
  }
8671
8882
  function findRetryTarget(members, retryOf) {
8672
8883
  return members.find(
@@ -8754,7 +8965,7 @@ function evaluateRecoveryOperations(events, operations) {
8754
8965
  }
8755
8966
  for (const [operationKey, members] of groups) {
8756
8967
  const ordered = sortByTime2(members);
8757
- if (hasDuplicateAttemptIds2(members)) {
8968
+ if (hasDuplicateAttemptIds(members)) {
8758
8969
  findings.push(
8759
8970
  fail3(
8760
8971
  "contract.retry.operations.duplicate-attempt-id",
@@ -12878,6 +13089,7 @@ function resolveRunTiming(sorted, status) {
12878
13089
  var TreeBuilder;
12879
13090
  var init_tree_builder = __esm({
12880
13091
  "packages/core/src/logs/tree-builder.ts"() {
13092
+ init_delivery_identity();
12881
13093
  TreeBuilder = class {
12882
13094
  constructor(options) {
12883
13095
  void options?.config;
@@ -12893,7 +13105,47 @@ var init_tree_builder = __esm({
12893
13105
  const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
12894
13106
  const nodes = /* @__PURE__ */ new Map();
12895
13107
  for (const e of sorted) {
12896
- nodes.set(e.eventId, { event: e, children: [], depth: 0 });
13108
+ const existing = nodes.get(e.eventId);
13109
+ if (!existing) {
13110
+ nodes.set(e.eventId, { event: e, children: [], depth: 0 });
13111
+ continue;
13112
+ }
13113
+ const existingAttrs = existing.event.attributes && typeof existing.event.attributes === "object" ? existing.event.attributes : void 0;
13114
+ const nextAttrs = e.attributes && typeof e.attributes === "object" ? e.attributes : void 0;
13115
+ const existingIdentity = identityFieldsFromAttributes(existingAttrs);
13116
+ const nextIdentity = identityFieldsFromAttributes(nextAttrs);
13117
+ const existingFp = deliverySemanticFingerprint({
13118
+ eventId: existing.event.eventId,
13119
+ runId: existing.event.runId,
13120
+ kind: existing.event.kind,
13121
+ name: existing.event.name,
13122
+ status: existing.event.status,
13123
+ parentId: existing.event.parentId,
13124
+ timestamp: existing.event.timestamp,
13125
+ sourceType: existing.event.source?.type,
13126
+ attributes: existingAttrs,
13127
+ ...existingIdentity
13128
+ });
13129
+ const nextFp = deliverySemanticFingerprint({
13130
+ eventId: e.eventId,
13131
+ runId: e.runId,
13132
+ kind: e.kind,
13133
+ name: e.name,
13134
+ status: e.status,
13135
+ parentId: e.parentId,
13136
+ timestamp: e.timestamp,
13137
+ sourceType: e.source?.type,
13138
+ attributes: nextAttrs,
13139
+ ...nextIdentity
13140
+ });
13141
+ if (existingFp === nextFp) {
13142
+ continue;
13143
+ }
13144
+ nodes.set(e.eventId, {
13145
+ event: stampDeliveryConflict(e),
13146
+ children: [],
13147
+ depth: 0
13148
+ });
12897
13149
  }
12898
13150
  const { roots, summary } = linkNodesVisibilityFirst(nodes);
12899
13151
  const confidenceBreakdown = {
@@ -14170,6 +14422,12 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
14170
14422
  ["agent_inspect.retry_of", "retryOf", "string"],
14171
14423
  ["agent_inspect.attempt_number", "attemptNumber", "int"]
14172
14424
  ];
14425
+ const conflictMapping = [
14426
+ ["agent_inspect.identity_conflict.operation_id", "operationId", "string"],
14427
+ ["agent_inspect.identity_conflict.attempt_id", "attemptId", "string"],
14428
+ ["agent_inspect.identity_conflict.retry_of", "retryOf", "string"],
14429
+ ["agent_inspect.identity_conflict.attempt_number", "attemptNumber", "int"]
14430
+ ];
14173
14431
  const metadata = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? { ...attributes.metadata } : {};
14174
14432
  for (const [dotted, camel, kind] of mapping) {
14175
14433
  const raw = attributes[dotted];
@@ -14221,6 +14479,46 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
14221
14479
  if (direct === void 0) attributes[camel] = promoted;
14222
14480
  if (nested === void 0) metadata[camel] = promoted;
14223
14481
  }
14482
+ for (const [dotted, camel, kind] of conflictMapping) {
14483
+ const raw = attributes[dotted];
14484
+ if (raw === void 0 || raw === null) continue;
14485
+ let alternate;
14486
+ if (kind === "int") {
14487
+ const n = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
14488
+ if (!Number.isFinite(n) || n < 1) {
14489
+ warnings.push({
14490
+ code: "otlp_identity_invalid",
14491
+ message: `Ignoring invalid ${dotted} identity conflict value.`,
14492
+ severity: "warning",
14493
+ field: `${pathPrefix}.${dotted}`
14494
+ });
14495
+ continue;
14496
+ }
14497
+ alternate = Math.trunc(n);
14498
+ } else if (typeof raw === "string" && raw.trim() !== "") {
14499
+ alternate = raw.trim();
14500
+ } else {
14501
+ warnings.push({
14502
+ code: "otlp_identity_invalid",
14503
+ message: `Ignoring non-string ${dotted} identity conflict value.`,
14504
+ severity: "warning",
14505
+ field: `${pathPrefix}.${dotted}`
14506
+ });
14507
+ continue;
14508
+ }
14509
+ const preferred = attributes[camel];
14510
+ if (preferred !== void 0 && preferred !== alternate) {
14511
+ metadata[camel] = alternate;
14512
+ warnings.push({
14513
+ code: "otlp_identity_conflict",
14514
+ message: `Conflicting ${camel}: attributes.${camel} vs nested alternate from ${dotted}; retaining both.`,
14515
+ severity: "warning",
14516
+ field: `${pathPrefix}.${dotted}`
14517
+ });
14518
+ } else if (preferred === void 0) {
14519
+ metadata[camel] = alternate;
14520
+ }
14521
+ }
14224
14522
  if (Object.keys(metadata).length > 0) {
14225
14523
  attributes.metadata = metadata;
14226
14524
  }
@@ -16960,7 +17258,7 @@ var init_src = __esm({
16960
17258
  });
16961
17259
 
16962
17260
  // package.json
16963
- var version = "6.31.20";
17261
+ var version = "6.31.22";
16964
17262
 
16965
17263
  // packages/cli/src/list.ts
16966
17264
  init_advanced();
@@ -19568,6 +19866,7 @@ function exportOpenInference(tree, options) {
19568
19866
  }
19569
19867
 
19570
19868
  // packages/core/src/exporters/otlp-json-exporter.ts
19869
+ init_delivery_identity();
19571
19870
  init_helpers();
19572
19871
  var OTLP_STATUS_CODE_UNSET = 0;
19573
19872
  var OTLP_STATUS_CODE_OK = 1;
@@ -19618,43 +19917,81 @@ var STRUCTURAL_IDENTITY_KEYS = [
19618
19917
  "attemptNumber",
19619
19918
  "attempt"
19620
19919
  ];
19621
- function pickBoundedIdentityString(bag, key, maxLen) {
19920
+ function nestedBag(bag) {
19622
19921
  if (!bag || typeof bag !== "object") return void 0;
19623
- const direct = bag[key];
19624
- if (typeof direct === "string" && direct.trim() !== "") {
19625
- return direct.trim().slice(0, maxLen);
19626
- }
19627
- const nested = bag.metadata && typeof bag.metadata === "object" ? bag.metadata[key] : void 0;
19628
- if (typeof nested === "string" && nested.trim() !== "") {
19629
- return nested.trim().slice(0, maxLen);
19630
- }
19631
- return void 0;
19922
+ const nested = bag.metadata;
19923
+ if (!nested || typeof nested !== "object" || Array.isArray(nested)) return void 0;
19924
+ return nested;
19925
+ }
19926
+ function pickBoundedIdentityString(bag, key, maxLen) {
19927
+ if (!bag || typeof bag !== "object") return {};
19928
+ const directRaw = bag[key];
19929
+ const nestedRaw = nestedBag(bag)?.[key];
19930
+ const direct = typeof directRaw === "string" && directRaw.trim() !== "" ? directRaw.trim().slice(0, maxLen) : void 0;
19931
+ const nested = typeof nestedRaw === "string" && nestedRaw.trim() !== "" ? nestedRaw.trim().slice(0, maxLen) : void 0;
19932
+ if (direct !== void 0 && nested !== void 0 && direct !== nested) {
19933
+ return { value: direct, conflictAlternate: nested };
19934
+ }
19935
+ if (direct !== void 0) return { value: direct };
19936
+ if (nested !== void 0) return { value: nested };
19937
+ return {};
19632
19938
  }
19633
19939
  function pickBoundedIdentityNumber(bag, key) {
19634
- if (!bag || typeof bag !== "object") return void 0;
19635
- const direct = bag[key];
19636
- if (typeof direct === "number" && Number.isFinite(direct)) return direct;
19637
- const nested = bag.metadata && typeof bag.metadata === "object" ? bag.metadata[key] : void 0;
19638
- if (typeof nested === "number" && Number.isFinite(nested)) return nested;
19639
- return void 0;
19940
+ if (!bag || typeof bag !== "object") return {};
19941
+ const directRaw = bag[key];
19942
+ const nestedRaw = nestedBag(bag)?.[key];
19943
+ const direct = typeof directRaw === "number" && Number.isFinite(directRaw) ? directRaw : void 0;
19944
+ const nested = typeof nestedRaw === "number" && Number.isFinite(nestedRaw) ? nestedRaw : void 0;
19945
+ if (direct !== void 0 && nested !== void 0 && direct !== nested) {
19946
+ return { value: direct, conflictAlternate: nested };
19947
+ }
19948
+ if (direct !== void 0) return { value: direct };
19949
+ if (nested !== void 0) return { value: nested };
19950
+ return {};
19640
19951
  }
19641
19952
  function appendStructuralIdentityAttrs(attrs, meta2, maxLen) {
19953
+ const conflicts = [];
19642
19954
  const operationId = pickBoundedIdentityString(meta2, "operationId", maxLen);
19643
- if (operationId !== void 0) {
19644
- attrs.push(stringAttr2("agent_inspect.operation_id", operationId));
19955
+ if (operationId.value !== void 0) {
19956
+ attrs.push(stringAttr2("agent_inspect.operation_id", operationId.value));
19957
+ }
19958
+ if (operationId.conflictAlternate !== void 0) {
19959
+ attrs.push(
19960
+ stringAttr2(IDENTITY_CONFLICT_ATTR.operationId, operationId.conflictAlternate)
19961
+ );
19962
+ conflicts.push("operationId");
19645
19963
  }
19646
19964
  const attemptId = pickBoundedIdentityString(meta2, "attemptId", maxLen);
19647
- if (attemptId !== void 0) {
19648
- attrs.push(stringAttr2("agent_inspect.attempt_id", attemptId));
19965
+ if (attemptId.value !== void 0) {
19966
+ attrs.push(stringAttr2("agent_inspect.attempt_id", attemptId.value));
19967
+ }
19968
+ if (attemptId.conflictAlternate !== void 0) {
19969
+ attrs.push(stringAttr2(IDENTITY_CONFLICT_ATTR.attemptId, attemptId.conflictAlternate));
19970
+ conflicts.push("attemptId");
19649
19971
  }
19650
19972
  const retryOf = pickBoundedIdentityString(meta2, "retryOf", maxLen);
19651
- if (retryOf !== void 0) {
19652
- attrs.push(stringAttr2("agent_inspect.retry_of", retryOf));
19973
+ if (retryOf.value !== void 0) {
19974
+ attrs.push(stringAttr2("agent_inspect.retry_of", retryOf.value));
19653
19975
  }
19654
- const attemptNumber2 = pickBoundedIdentityNumber(meta2, "attemptNumber") ?? pickBoundedIdentityNumber(meta2, "attempt");
19655
- if (attemptNumber2 !== void 0) {
19656
- attrs.push(intAttr("agent_inspect.attempt_number", attemptNumber2));
19976
+ if (retryOf.conflictAlternate !== void 0) {
19977
+ attrs.push(stringAttr2(IDENTITY_CONFLICT_ATTR.retryOf, retryOf.conflictAlternate));
19978
+ conflicts.push("retryOf");
19979
+ }
19980
+ const attemptNumberPrimary = pickBoundedIdentityNumber(meta2, "attemptNumber");
19981
+ const attemptNumber2 = attemptNumberPrimary.value !== void 0 || attemptNumberPrimary.conflictAlternate !== void 0 ? attemptNumberPrimary : pickBoundedIdentityNumber(meta2, "attempt");
19982
+ if (attemptNumber2.value !== void 0) {
19983
+ attrs.push(intAttr("agent_inspect.attempt_number", attemptNumber2.value));
19984
+ }
19985
+ if (attemptNumber2.conflictAlternate !== void 0) {
19986
+ attrs.push(
19987
+ intAttr(IDENTITY_CONFLICT_ATTR.attemptNumber, attemptNumber2.conflictAlternate)
19988
+ );
19989
+ conflicts.push("attemptNumber");
19657
19990
  }
19991
+ if (meta2?.[DELIVERY_CONFLICT_ATTR] === true) {
19992
+ attrs.push(boolAttr(DELIVERY_CONFLICT_ATTR, true));
19993
+ }
19994
+ return conflicts;
19658
19995
  }
19659
19996
  function resolveSpanTimes(ev) {
19660
19997
  const startedAtMs = typeof ev.attributes?.startedAtMs === "number" && Number.isFinite(ev.attributes.startedAtMs) ? ev.attributes.startedAtMs : void 0;
@@ -19677,7 +20014,8 @@ function exportOtlpJson(tree, options) {
19677
20014
  "OTLP JSON export uses OTel GenAI-aligned attributes where applicable; experimental until verified against specific collectors.",
19678
20015
  "Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload.",
19679
20016
  "Status and span kind use OTLP numeric enums (StatusCode 0/1/2, SpanKind INTERNAL=1).",
19680
- "When present on source events, operationId/attemptId/retryOf/attemptNumber are emitted as bounded agent_inspect.* identity attributes (not a broad attribute dump)."
20017
+ "When present on source events, operationId/attemptId/retryOf/attemptNumber are emitted as bounded agent_inspect.* identity attributes (not a broad attribute dump).",
20018
+ "When direct and nested identity disagree, export prefers direct for non-strict consumers and emits agent_inspect.identity_conflict.* for the nested alternate; this does not certify conflicting identity."
19681
20019
  ];
19682
20020
  const traceId = hexFrom2(`trace:${tree.runId}`, 16);
19683
20021
  const includeAttributes = options?.includeAttributes ?? false;
@@ -19725,11 +20063,16 @@ function exportOtlpJson(tree, options) {
19725
20063
  if (typeof inp === "number") attrs.push(intAttr("gen_ai.usage.input_tokens", inp));
19726
20064
  if (typeof outp === "number") attrs.push(intAttr("gen_ai.usage.output_tokens", outp));
19727
20065
  }
19728
- appendStructuralIdentityAttrs(
20066
+ const identityConflicts = appendStructuralIdentityAttrs(
19729
20067
  attrs,
19730
20068
  meta2 && typeof meta2 === "object" ? meta2 : void 0,
19731
20069
  maxLen
19732
20070
  );
20071
+ if (identityConflicts.length > 0) {
20072
+ warnings.push(
20073
+ `Identity representation conflict on event ${ev.eventId}: ${identityConflicts.join(", ")} (direct preferred; nested retained on agent_inspect.identity_conflict.*).`
20074
+ );
20075
+ }
19733
20076
  if (includeAttributes && meta2 && typeof meta2 === "object") {
19734
20077
  const skipKeys = /* @__PURE__ */ new Set([
19735
20078
  "tokens",