agent-inspect 6.31.21 → 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 +6 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/packages/cli/dist/{chunk-N5JN26MW.mjs → chunk-EMWA5EKU.mjs} +300 -31
  5. package/packages/cli/dist/chunk-EMWA5EKU.mjs.map +1 -0
  6. package/packages/cli/dist/index.cjs +379 -56
  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-VMGRSTG7.mjs → src-VZHGOLTO.mjs} +3 -3
  11. package/packages/cli/dist/{src-VMGRSTG7.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 +160 -27
  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-4CDX5GDS.mjs → chunk-ZOF6ON65.mjs} +104 -99
  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-N5JN26MW.mjs.map +0 -1
  45. package/packages/core/dist/chunk-4CDX5GDS.mjs.map +0 -1
  46. package/packages/core/dist/chunk-EIP5CNEL.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);
@@ -8248,19 +8363,48 @@ function classifyRetryAttempt(event, priorOrdered, allMembers) {
8248
8363
  }
8249
8364
  function redeliveryFingerprint(event) {
8250
8365
  const workflow = workflowFor(event);
8251
- const stableEventId = (event.eventId ?? "").replace(/:\d+$/, "");
8252
- return JSON.stringify({
8253
- stableEventId,
8366
+ return deliverySemanticFingerprint({
8367
+ eventId: event.eventId ?? "",
8254
8368
  runId: event.runId,
8255
8369
  kind: event.kind,
8256
8370
  name: event.name,
8257
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,
8258
8377
  operationId: workflow.operationId ?? null,
8259
8378
  attemptId: workflow.attemptId ?? null,
8260
8379
  attemptNumber: workflow.attemptNumber ?? null,
8261
8380
  retryOf: workflow.retryOf ?? null
8262
8381
  });
8263
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
+ }
8264
8408
  function hasConflictingAttemptIdReuse(members) {
8265
8409
  const byAttempt = /* @__PURE__ */ new Map();
8266
8410
  for (const event of members) {
@@ -8276,6 +8420,31 @@ function hasConflictingAttemptIdReuse(members) {
8276
8420
  }
8277
8421
  return false;
8278
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;
8445
+ }
8446
+ return false;
8447
+ }
8279
8448
  function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8280
8449
  const findings = [];
8281
8450
  const byOperation = /* @__PURE__ */ new Map();
@@ -8283,13 +8452,14 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8283
8452
  const workflow = workflowFor(event);
8284
8453
  const operationId = workflow.operationId;
8285
8454
  if (!operationId) continue;
8286
- const list2 = byOperation.get(operationId) ?? [];
8287
- list2.push(event);
8288
- 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);
8289
8459
  }
8290
8460
  if (rules.maxAttempts !== void 0) {
8291
- for (const [operationId, members] of byOperation) {
8292
- if (hasConflictingAttemptIdReuse(members)) {
8461
+ for (const { operationId, members } of byOperation.values()) {
8462
+ if (hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members)) {
8293
8463
  findings.push(
8294
8464
  fail2(
8295
8465
  "contract.retry.duplicate-attempt-id",
@@ -8300,6 +8470,31 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8300
8470
  )
8301
8471
  );
8302
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
+ }
8303
8498
  const count = countOperationAttempts(members);
8304
8499
  if (count > rules.maxAttempts) {
8305
8500
  findings.push(
@@ -8315,7 +8510,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8315
8510
  }
8316
8511
  }
8317
8512
  if (rules.requireTerminalResult) {
8318
- for (const [operationId, members] of byOperation) {
8513
+ for (const { operationId, members } of byOperation.values()) {
8319
8514
  const hasTerminal = members.some((event) => event.status === "ok" || event.status === "error");
8320
8515
  if (!hasTerminal) {
8321
8516
  findings.push(
@@ -8335,7 +8530,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8335
8530
  const workflow = workflowFor(event);
8336
8531
  const fallbackOf = workflow.fallbackOf;
8337
8532
  if (!fallbackOf) continue;
8338
- const prior = byOperation.get(fallbackOf) ?? [];
8533
+ const prior = byOperation.get(`${event.runId}\0${fallbackOf}`)?.members ?? [];
8339
8534
  const fallbackStart = eventTime(event);
8340
8535
  const earlierFailure = prior.some(
8341
8536
  (candidate) => candidate.status === "error" && eventTime(candidate) !== "" && fallbackStart !== "" && eventTime(candidate) < fallbackStart
@@ -8362,7 +8557,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8362
8557
  for (const event of toolEvents) {
8363
8558
  const name = resolveCanonicalToolName(event);
8364
8559
  const workflow = workflowFor(event);
8365
- const key = `${workflow.operationId ?? name}::${name}`;
8560
+ const key = `${event.runId}::${workflow.operationId ?? name}::${name}`;
8366
8561
  const list2 = byToolOp.get(key) ?? [];
8367
8562
  list2.push(event);
8368
8563
  byToolOp.set(key, list2);
@@ -8420,7 +8615,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8420
8615
  }
8421
8616
  }
8422
8617
  if (rules.requireRecoveredFailureVisible) {
8423
- for (const [operationId, members] of byOperation) {
8618
+ for (const { operationId, members } of byOperation.values()) {
8424
8619
  const ordered = sortByTime(members);
8425
8620
  const toolish = ordered.filter(
8426
8621
  (event) => (event.kind === "TOOL" || event.kind === "LLM") && (event.status === "ok" || event.status === "error")
@@ -8459,10 +8654,13 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8459
8654
  }
8460
8655
  return findings;
8461
8656
  }
8657
+ var IDENTITY_KEYS;
8462
8658
  var init_retry_safety = __esm({
8463
8659
  "packages/core/src/checks/retry-safety.ts"() {
8464
8660
  init_logical_events();
8661
+ init_delivery_identity();
8465
8662
  init_metadata();
8663
+ IDENTITY_KEYS = ["operationId", "attemptId", "retryOf", "attemptNumber"];
8466
8664
  }
8467
8665
  });
8468
8666
 
@@ -8679,14 +8877,7 @@ function attemptIdOf2(event) {
8679
8877
  return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
8680
8878
  }
8681
8879
  function hasDuplicateAttemptIds(members) {
8682
- const seen = /* @__PURE__ */ new Set();
8683
- for (const event of members) {
8684
- const id = attemptIdOf2(event);
8685
- if (!id) continue;
8686
- if (seen.has(id)) return true;
8687
- seen.add(id);
8688
- }
8689
- return false;
8880
+ return hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members);
8690
8881
  }
8691
8882
  function findRetryTarget(members, retryOf) {
8692
8883
  return members.find(
@@ -12898,6 +13089,7 @@ function resolveRunTiming(sorted, status) {
12898
13089
  var TreeBuilder;
12899
13090
  var init_tree_builder = __esm({
12900
13091
  "packages/core/src/logs/tree-builder.ts"() {
13092
+ init_delivery_identity();
12901
13093
  TreeBuilder = class {
12902
13094
  constructor(options) {
12903
13095
  void options?.config;
@@ -12913,7 +13105,47 @@ var init_tree_builder = __esm({
12913
13105
  const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
12914
13106
  const nodes = /* @__PURE__ */ new Map();
12915
13107
  for (const e of sorted) {
12916
- 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
+ });
12917
13149
  }
12918
13150
  const { roots, summary } = linkNodesVisibilityFirst(nodes);
12919
13151
  const confidenceBreakdown = {
@@ -14190,6 +14422,12 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
14190
14422
  ["agent_inspect.retry_of", "retryOf", "string"],
14191
14423
  ["agent_inspect.attempt_number", "attemptNumber", "int"]
14192
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
+ ];
14193
14431
  const metadata = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? { ...attributes.metadata } : {};
14194
14432
  for (const [dotted, camel, kind] of mapping) {
14195
14433
  const raw = attributes[dotted];
@@ -14241,6 +14479,46 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
14241
14479
  if (direct === void 0) attributes[camel] = promoted;
14242
14480
  if (nested === void 0) metadata[camel] = promoted;
14243
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
+ }
14244
14522
  if (Object.keys(metadata).length > 0) {
14245
14523
  attributes.metadata = metadata;
14246
14524
  }
@@ -16980,7 +17258,7 @@ var init_src = __esm({
16980
17258
  });
16981
17259
 
16982
17260
  // package.json
16983
- var version = "6.31.21";
17261
+ var version = "6.31.22";
16984
17262
 
16985
17263
  // packages/cli/src/list.ts
16986
17264
  init_advanced();
@@ -19588,6 +19866,7 @@ function exportOpenInference(tree, options) {
19588
19866
  }
19589
19867
 
19590
19868
  // packages/core/src/exporters/otlp-json-exporter.ts
19869
+ init_delivery_identity();
19591
19870
  init_helpers();
19592
19871
  var OTLP_STATUS_CODE_UNSET = 0;
19593
19872
  var OTLP_STATUS_CODE_OK = 1;
@@ -19638,43 +19917,81 @@ var STRUCTURAL_IDENTITY_KEYS = [
19638
19917
  "attemptNumber",
19639
19918
  "attempt"
19640
19919
  ];
19641
- function pickBoundedIdentityString(bag, key, maxLen) {
19920
+ function nestedBag(bag) {
19642
19921
  if (!bag || typeof bag !== "object") return void 0;
19643
- const direct = bag[key];
19644
- if (typeof direct === "string" && direct.trim() !== "") {
19645
- return direct.trim().slice(0, maxLen);
19646
- }
19647
- const nested = bag.metadata && typeof bag.metadata === "object" ? bag.metadata[key] : void 0;
19648
- if (typeof nested === "string" && nested.trim() !== "") {
19649
- return nested.trim().slice(0, maxLen);
19650
- }
19651
- 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 {};
19652
19938
  }
19653
19939
  function pickBoundedIdentityNumber(bag, key) {
19654
- if (!bag || typeof bag !== "object") return void 0;
19655
- const direct = bag[key];
19656
- if (typeof direct === "number" && Number.isFinite(direct)) return direct;
19657
- const nested = bag.metadata && typeof bag.metadata === "object" ? bag.metadata[key] : void 0;
19658
- if (typeof nested === "number" && Number.isFinite(nested)) return nested;
19659
- 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 {};
19660
19951
  }
19661
19952
  function appendStructuralIdentityAttrs(attrs, meta2, maxLen) {
19953
+ const conflicts = [];
19662
19954
  const operationId = pickBoundedIdentityString(meta2, "operationId", maxLen);
19663
- if (operationId !== void 0) {
19664
- 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");
19665
19963
  }
19666
19964
  const attemptId = pickBoundedIdentityString(meta2, "attemptId", maxLen);
19667
- if (attemptId !== void 0) {
19668
- 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");
19669
19971
  }
19670
19972
  const retryOf = pickBoundedIdentityString(meta2, "retryOf", maxLen);
19671
- if (retryOf !== void 0) {
19672
- attrs.push(stringAttr2("agent_inspect.retry_of", retryOf));
19973
+ if (retryOf.value !== void 0) {
19974
+ attrs.push(stringAttr2("agent_inspect.retry_of", retryOf.value));
19673
19975
  }
19674
- const attemptNumber2 = pickBoundedIdentityNumber(meta2, "attemptNumber") ?? pickBoundedIdentityNumber(meta2, "attempt");
19675
- if (attemptNumber2 !== void 0) {
19676
- 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");
19677
19990
  }
19991
+ if (meta2?.[DELIVERY_CONFLICT_ATTR] === true) {
19992
+ attrs.push(boolAttr(DELIVERY_CONFLICT_ATTR, true));
19993
+ }
19994
+ return conflicts;
19678
19995
  }
19679
19996
  function resolveSpanTimes(ev) {
19680
19997
  const startedAtMs = typeof ev.attributes?.startedAtMs === "number" && Number.isFinite(ev.attributes.startedAtMs) ? ev.attributes.startedAtMs : void 0;
@@ -19697,7 +20014,8 @@ function exportOtlpJson(tree, options) {
19697
20014
  "OTLP JSON export uses OTel GenAI-aligned attributes where applicable; experimental until verified against specific collectors.",
19698
20015
  "Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload.",
19699
20016
  "Status and span kind use OTLP numeric enums (StatusCode 0/1/2, SpanKind INTERNAL=1).",
19700
- "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."
19701
20019
  ];
19702
20020
  const traceId = hexFrom2(`trace:${tree.runId}`, 16);
19703
20021
  const includeAttributes = options?.includeAttributes ?? false;
@@ -19745,11 +20063,16 @@ function exportOtlpJson(tree, options) {
19745
20063
  if (typeof inp === "number") attrs.push(intAttr("gen_ai.usage.input_tokens", inp));
19746
20064
  if (typeof outp === "number") attrs.push(intAttr("gen_ai.usage.output_tokens", outp));
19747
20065
  }
19748
- appendStructuralIdentityAttrs(
20066
+ const identityConflicts = appendStructuralIdentityAttrs(
19749
20067
  attrs,
19750
20068
  meta2 && typeof meta2 === "object" ? meta2 : void 0,
19751
20069
  maxLen
19752
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
+ }
19753
20076
  if (includeAttributes && meta2 && typeof meta2 === "object") {
19754
20077
  const skipKeys = /* @__PURE__ */ new Set([
19755
20078
  "tokens",