agent-inspect 6.31.21 → 6.31.23

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 (48) 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-N5JN26MW.mjs → chunk-P27XTK5U.mjs} +347 -36
  5. package/packages/cli/dist/chunk-P27XTK5U.mjs.map +1 -0
  6. package/packages/cli/dist/index.cjs +434 -63
  7. package/packages/cli/dist/index.cjs.map +1 -1
  8. package/packages/cli/dist/index.mjs +81 -33
  9. package/packages/cli/dist/index.mjs.map +1 -1
  10. package/packages/cli/dist/{src-VMGRSTG7.mjs → src-EWZYLDST.mjs} +3 -3
  11. package/packages/cli/dist/{src-VMGRSTG7.mjs.map → src-EWZYLDST.mjs.map} +1 -1
  12. package/packages/core/dist/advanced.cjs +280 -10
  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 +185 -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-JE3TUFAQ.mjs → chunk-77PUPLPG.mjs} +14 -8
  20. package/packages/core/dist/chunk-77PUPLPG.mjs.map +1 -0
  21. package/packages/core/dist/chunk-AN5MOADW.mjs +204 -0
  22. package/packages/core/dist/chunk-AN5MOADW.mjs.map +1 -0
  23. package/packages/core/dist/{chunk-4CDX5GDS.mjs → chunk-IMCM42W6.mjs} +110 -99
  24. package/packages/core/dist/chunk-IMCM42W6.mjs.map +1 -0
  25. package/packages/core/dist/{chunk-YU6XT5A2.mjs → chunk-J2ST4VCX.mjs} +45 -3
  26. package/packages/core/dist/chunk-J2ST4VCX.mjs.map +1 -0
  27. package/packages/core/dist/{chunk-EIP5CNEL.mjs → chunk-JJSL346L.mjs} +58 -3
  28. package/packages/core/dist/chunk-JJSL346L.mjs.map +1 -0
  29. package/packages/core/dist/exporters.cjs +91 -29
  30. package/packages/core/dist/exporters.cjs.map +1 -1
  31. package/packages/core/dist/exporters.mjs +78 -29
  32. package/packages/core/dist/exporters.mjs.map +1 -1
  33. package/packages/core/dist/logs.cjs +206 -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 +226 -8
  38. package/packages/core/dist/persisted.cjs.map +1 -1
  39. package/packages/core/dist/persisted.mjs +9 -5
  40. package/packages/core/dist/persisted.mjs.map +1 -1
  41. package/packages/core/dist/readers.cjs +276 -6
  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-JE3TUFAQ.mjs.map +0 -1
  48. package/packages/core/dist/chunk-YU6XT5A2.mjs.map +0 -1
@@ -8114,6 +8114,143 @@ var init_tool_arguments = __esm({
8114
8114
  }
8115
8115
  });
8116
8116
 
8117
+ // packages/core/src/persisted/delivery-identity.ts
8118
+ function stripReaderDeliveryDiscriminator(eventId, attributes) {
8119
+ if (!eventId) return eventId;
8120
+ const rawBase = attributes?.[DELIVERY_EVENT_BASE_ATTR];
8121
+ if (typeof rawBase !== "string" || rawBase.trim() === "") return eventId;
8122
+ const base = rawBase.trim().slice(0, MAX_DELIVERY_BASE_LEN);
8123
+ if (eventId === base) return base;
8124
+ const prefix = `${base}:`;
8125
+ if (!eventId.startsWith(prefix)) return eventId;
8126
+ const suffix = eventId.slice(prefix.length);
8127
+ if (/^\d+$/.test(suffix)) return base;
8128
+ return eventId;
8129
+ }
8130
+ function deliveryEventBaseFromIndexedId(eventId) {
8131
+ if (!/:\d+$/.test(eventId)) return void 0;
8132
+ const base = eventId.replace(/:\d+$/, "");
8133
+ return base.length > 0 ? base.slice(0, MAX_DELIVERY_BASE_LEN) : void 0;
8134
+ }
8135
+ function canonicalDigest(value) {
8136
+ if (value === void 0) return null;
8137
+ const encoded = encodeCanonicalStructured(value);
8138
+ return encoded.ok ? encoded.value : `unencodable:${encoded.code}`;
8139
+ }
8140
+ function capturedContentDigest(attributes) {
8141
+ if (!attributes || typeof attributes !== "object") {
8142
+ return { args: null, result: null };
8143
+ }
8144
+ const nested = attributes.metadata && typeof attributes.metadata === "object" ? attributes.metadata : void 0;
8145
+ const args = attributes.arguments ?? attributes.args ?? attributes.input ?? nested?.arguments ?? nested?.args ?? nested?.input;
8146
+ const result = attributes.result ?? attributes.output ?? attributes.response ?? nested?.result ?? nested?.output ?? nested?.response;
8147
+ return {
8148
+ args: args === void 0 ? null : canonicalDigest(args),
8149
+ result: result === void 0 ? null : canonicalDigest(result)
8150
+ };
8151
+ }
8152
+ function timeKey(fields) {
8153
+ if (typeof fields.startedAt === "string" && fields.startedAt.trim() !== "") {
8154
+ return fields.startedAt;
8155
+ }
8156
+ if (typeof fields.timestamp === "string" && fields.timestamp.trim() !== "") {
8157
+ return fields.timestamp;
8158
+ }
8159
+ if (typeof fields.timestamp === "number" && Number.isFinite(fields.timestamp)) {
8160
+ return String(fields.timestamp);
8161
+ }
8162
+ return null;
8163
+ }
8164
+ function deliverySemanticFingerprint(fields) {
8165
+ const content = capturedContentDigest(fields.attributes);
8166
+ return JSON.stringify({
8167
+ stableEventId: stripReaderDeliveryDiscriminator(fields.eventId, fields.attributes),
8168
+ runId: fields.runId,
8169
+ kind: fields.kind,
8170
+ name: fields.name,
8171
+ status: fields.status ?? null,
8172
+ parentId: fields.parentId ?? null,
8173
+ sourceType: fields.sourceType ?? null,
8174
+ time: timeKey(fields),
8175
+ operationId: fields.operationId ?? null,
8176
+ attemptId: fields.attemptId ?? null,
8177
+ attemptNumber: fields.attemptNumber ?? null,
8178
+ retryOf: fields.retryOf ?? null,
8179
+ argsDigest: content.args,
8180
+ resultDigest: content.result
8181
+ });
8182
+ }
8183
+ function identityFieldsFromAttributes(attributes) {
8184
+ if (!attributes || typeof attributes !== "object") {
8185
+ return {
8186
+ operationId: null,
8187
+ attemptId: null,
8188
+ attemptNumber: null,
8189
+ retryOf: null
8190
+ };
8191
+ }
8192
+ const nested = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? attributes.metadata : void 0;
8193
+ const pickString3 = (key) => {
8194
+ const direct = attributes[key];
8195
+ if (typeof direct === "string" && direct.trim() !== "") return direct.trim();
8196
+ const nestedValue = nested?.[key];
8197
+ if (typeof nestedValue === "string" && nestedValue.trim() !== "") {
8198
+ return nestedValue.trim();
8199
+ }
8200
+ return null;
8201
+ };
8202
+ const pickNumber2 = () => {
8203
+ const direct = attributes.attemptNumber ?? attributes.attempt;
8204
+ if (typeof direct === "number" && Number.isFinite(direct)) return direct;
8205
+ const nestedValue = nested?.attemptNumber ?? nested?.attempt;
8206
+ if (typeof nestedValue === "number" && Number.isFinite(nestedValue)) {
8207
+ return nestedValue;
8208
+ }
8209
+ return null;
8210
+ };
8211
+ return {
8212
+ operationId: pickString3("operationId"),
8213
+ attemptId: pickString3("attemptId"),
8214
+ retryOf: pickString3("retryOf"),
8215
+ attemptNumber: pickNumber2()
8216
+ };
8217
+ }
8218
+ function identityConflictFieldsFromAttributes(attributes) {
8219
+ const raw = attributes?.[IDENTITY_CONFLICT_ATTR.fields];
8220
+ if (typeof raw !== "string" || raw.trim() === "") return [];
8221
+ return raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0).slice(0, MAX_CONFLICT_FIELDS);
8222
+ }
8223
+ function hasDeliveryConflictMarker(attributes) {
8224
+ return attributes?.[DELIVERY_CONFLICT_ATTR] === true;
8225
+ }
8226
+ function stampDeliveryConflict(event) {
8227
+ return {
8228
+ ...event,
8229
+ attributes: {
8230
+ ...event.attributes ?? {},
8231
+ [DELIVERY_CONFLICT_ATTR]: true
8232
+ }
8233
+ };
8234
+ }
8235
+ var DELIVERY_CONFLICT_ATTR, DELIVERY_EVENT_BASE_ATTR, IDENTITY_CONFLICT_ATTR, MAX_CONFLICT_FIELDS, MAX_DELIVERY_BASE_LEN;
8236
+ var init_delivery_identity = __esm({
8237
+ "packages/core/src/persisted/delivery-identity.ts"() {
8238
+ init_canonical_equality();
8239
+ DELIVERY_CONFLICT_ATTR = "agent_inspect.delivery_conflict";
8240
+ DELIVERY_EVENT_BASE_ATTR = "agent_inspect.delivery_event_base";
8241
+ IDENTITY_CONFLICT_ATTR = {
8242
+ operationId: "agent_inspect.identity_conflict.operation_id",
8243
+ attemptId: "agent_inspect.identity_conflict.attempt_id",
8244
+ retryOf: "agent_inspect.identity_conflict.retry_of",
8245
+ attemptNumber: "agent_inspect.identity_conflict.attempt_number",
8246
+ /** Comma-separated field names when a conflict survives lossy bounding. */
8247
+ fields: "agent_inspect.identity_conflict.fields"
8248
+ };
8249
+ MAX_CONFLICT_FIELDS = 8;
8250
+ MAX_DELIVERY_BASE_LEN = 500;
8251
+ }
8252
+ });
8253
+
8117
8254
  // packages/core/src/checks/retry-safety.ts
8118
8255
  function fail2(ruleId, message, evidence, expected, actual) {
8119
8256
  return {
@@ -8169,7 +8306,7 @@ function attemptIdOf(event) {
8169
8306
  }
8170
8307
  function countOperationAttempts(members) {
8171
8308
  const identified = /* @__PURE__ */ new Set();
8172
- let unidentified = 0;
8309
+ const unidentifiedFingerprints = /* @__PURE__ */ new Set();
8173
8310
  for (const event of members) {
8174
8311
  if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
8175
8312
  const id = attemptIdOf(event);
@@ -8177,13 +8314,13 @@ function countOperationAttempts(members) {
8177
8314
  identified.add(id);
8178
8315
  continue;
8179
8316
  }
8180
- unidentified += 1;
8317
+ unidentifiedFingerprints.add(redeliveryFingerprint(event));
8181
8318
  }
8182
8319
  if (identified.size > 0) {
8183
- return identified.size + unidentified;
8320
+ return identified.size + unidentifiedFingerprints.size;
8184
8321
  }
8185
8322
  const numbered = /* @__PURE__ */ new Set();
8186
- let unnumbered = 0;
8323
+ const unnumberedFingerprints = /* @__PURE__ */ new Set();
8187
8324
  for (const event of members) {
8188
8325
  if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
8189
8326
  const num2 = attemptNumberOf(event);
@@ -8191,12 +8328,12 @@ function countOperationAttempts(members) {
8191
8328
  numbered.add(num2);
8192
8329
  continue;
8193
8330
  }
8194
- unnumbered += 1;
8331
+ unnumberedFingerprints.add(redeliveryFingerprint(event));
8195
8332
  }
8196
8333
  if (numbered.size > 0) {
8197
- return numbered.size + unnumbered;
8334
+ return numbered.size + unnumberedFingerprints.size;
8198
8335
  }
8199
- return unnumbered;
8336
+ return unnumberedFingerprints.size;
8200
8337
  }
8201
8338
  function classifyRetryAttempt(event, priorOrdered, allMembers) {
8202
8339
  const workflow = workflowFor(event);
@@ -8248,19 +8385,54 @@ function classifyRetryAttempt(event, priorOrdered, allMembers) {
8248
8385
  }
8249
8386
  function redeliveryFingerprint(event) {
8250
8387
  const workflow = workflowFor(event);
8251
- const stableEventId = (event.eventId ?? "").replace(/:\d+$/, "");
8252
- return JSON.stringify({
8253
- stableEventId,
8388
+ return deliverySemanticFingerprint({
8389
+ eventId: event.eventId ?? "",
8254
8390
  runId: event.runId,
8255
8391
  kind: event.kind,
8256
8392
  name: event.name,
8257
8393
  status: event.status,
8394
+ parentId: event.parentId,
8395
+ timestamp: event.timestamp,
8396
+ startedAt: event.startedAt,
8397
+ sourceType: event.source?.type,
8398
+ attributes: event.attributes && typeof event.attributes === "object" ? event.attributes : void 0,
8258
8399
  operationId: workflow.operationId ?? null,
8259
8400
  attemptId: workflow.attemptId ?? null,
8260
8401
  attemptNumber: workflow.attemptNumber ?? null,
8261
8402
  retryOf: workflow.retryOf ?? null
8262
8403
  });
8263
8404
  }
8405
+ function identityValuesEqual(a, b) {
8406
+ if (typeof a === "number" && typeof b === "number") {
8407
+ return Number.isFinite(a) && Number.isFinite(b) && a === b;
8408
+ }
8409
+ if (typeof a === "string" && typeof b === "string") {
8410
+ return a.trim() === b.trim();
8411
+ }
8412
+ return a === b;
8413
+ }
8414
+ function directNestedIdentityConflicts(event) {
8415
+ const attrs = event.attributes;
8416
+ if (!attrs || typeof attrs !== "object") return [];
8417
+ const nested = attrs.metadata && typeof attrs.metadata === "object" && !Array.isArray(attrs.metadata) ? attrs.metadata : void 0;
8418
+ const conflicts = [];
8419
+ if (nested) {
8420
+ for (const key of IDENTITY_KEYS) {
8421
+ const direct = attrs[key];
8422
+ const nestedValue = nested[key];
8423
+ if (direct === void 0 || nestedValue === void 0) continue;
8424
+ if (!identityValuesEqual(direct, nestedValue)) {
8425
+ conflicts.push(key);
8426
+ }
8427
+ }
8428
+ }
8429
+ for (const key of identityConflictFieldsFromAttributes(attrs)) {
8430
+ if (IDENTITY_KEYS.includes(key) && !conflicts.includes(key)) {
8431
+ conflicts.push(key);
8432
+ }
8433
+ }
8434
+ return conflicts;
8435
+ }
8264
8436
  function hasConflictingAttemptIdReuse(members) {
8265
8437
  const byAttempt = /* @__PURE__ */ new Map();
8266
8438
  for (const event of members) {
@@ -8276,6 +8448,31 @@ function hasConflictingAttemptIdReuse(members) {
8276
8448
  }
8277
8449
  return false;
8278
8450
  }
8451
+ function hasConflictingEventIdReuse(members) {
8452
+ const byEventId = /* @__PURE__ */ new Map();
8453
+ for (const event of members) {
8454
+ if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
8455
+ const eventId = event.eventId;
8456
+ if (!eventId) continue;
8457
+ if (hasDeliveryConflictMarker(event.attributes)) {
8458
+ return true;
8459
+ }
8460
+ const fingerprints = byEventId.get(eventId) ?? /* @__PURE__ */ new Set();
8461
+ fingerprints.add(redeliveryFingerprint(event));
8462
+ byEventId.set(eventId, fingerprints);
8463
+ }
8464
+ for (const fingerprints of byEventId.values()) {
8465
+ if (fingerprints.size > 1) return true;
8466
+ }
8467
+ return false;
8468
+ }
8469
+ function hasIdentityRepresentationConflict(members) {
8470
+ for (const event of members) {
8471
+ if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
8472
+ if (directNestedIdentityConflicts(event).length > 0) return true;
8473
+ }
8474
+ return false;
8475
+ }
8279
8476
  function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8280
8477
  const findings = [];
8281
8478
  const byOperation = /* @__PURE__ */ new Map();
@@ -8283,13 +8480,14 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8283
8480
  const workflow = workflowFor(event);
8284
8481
  const operationId = workflow.operationId;
8285
8482
  if (!operationId) continue;
8286
- const list2 = byOperation.get(operationId) ?? [];
8287
- list2.push(event);
8288
- byOperation.set(operationId, list2);
8483
+ const key = `${event.runId}\0${operationId}`;
8484
+ const group = byOperation.get(key) ?? { operationId, members: [] };
8485
+ group.members.push(event);
8486
+ byOperation.set(key, group);
8289
8487
  }
8290
8488
  if (rules.maxAttempts !== void 0) {
8291
- for (const [operationId, members] of byOperation) {
8292
- if (hasConflictingAttemptIdReuse(members)) {
8489
+ for (const { operationId, members } of byOperation.values()) {
8490
+ if (hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members)) {
8293
8491
  findings.push(
8294
8492
  fail2(
8295
8493
  "contract.retry.duplicate-attempt-id",
@@ -8300,6 +8498,31 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8300
8498
  )
8301
8499
  );
8302
8500
  }
8501
+ if (hasIdentityRepresentationConflict(members)) {
8502
+ findings.push(
8503
+ fail2(
8504
+ "contract.retry.ambiguous-identity",
8505
+ `Operation ${operationId} has conflicting direct vs nested identity fields; strict identity cannot pass.`,
8506
+ members.slice(0, 4).map(eventEvidence2),
8507
+ "agreeing identity representation",
8508
+ "direct/nested conflict"
8509
+ )
8510
+ );
8511
+ }
8512
+ const toolish = members.filter((event) => event.kind === "TOOL" || event.kind === "LLM");
8513
+ const hasAttemptId = toolish.some((event) => attemptIdOf(event) !== void 0);
8514
+ const missingAttemptId = toolish.some((event) => attemptIdOf(event) === void 0);
8515
+ if (hasAttemptId && missingAttemptId) {
8516
+ findings.push(
8517
+ fail2(
8518
+ "contract.retry.ambiguous-identity",
8519
+ `Operation ${operationId} has partial attempt identity; strict identity conformance cannot pass.`,
8520
+ members.slice(0, 4).map(eventEvidence2),
8521
+ "complete attempt identity",
8522
+ "partial attemptId coverage"
8523
+ )
8524
+ );
8525
+ }
8303
8526
  const count = countOperationAttempts(members);
8304
8527
  if (count > rules.maxAttempts) {
8305
8528
  findings.push(
@@ -8315,7 +8538,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8315
8538
  }
8316
8539
  }
8317
8540
  if (rules.requireTerminalResult) {
8318
- for (const [operationId, members] of byOperation) {
8541
+ for (const { operationId, members } of byOperation.values()) {
8319
8542
  const hasTerminal = members.some((event) => event.status === "ok" || event.status === "error");
8320
8543
  if (!hasTerminal) {
8321
8544
  findings.push(
@@ -8335,7 +8558,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8335
8558
  const workflow = workflowFor(event);
8336
8559
  const fallbackOf = workflow.fallbackOf;
8337
8560
  if (!fallbackOf) continue;
8338
- const prior = byOperation.get(fallbackOf) ?? [];
8561
+ const prior = byOperation.get(`${event.runId}\0${fallbackOf}`)?.members ?? [];
8339
8562
  const fallbackStart = eventTime(event);
8340
8563
  const earlierFailure = prior.some(
8341
8564
  (candidate) => candidate.status === "error" && eventTime(candidate) !== "" && fallbackStart !== "" && eventTime(candidate) < fallbackStart
@@ -8362,7 +8585,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8362
8585
  for (const event of toolEvents) {
8363
8586
  const name = resolveCanonicalToolName(event);
8364
8587
  const workflow = workflowFor(event);
8365
- const key = `${workflow.operationId ?? name}::${name}`;
8588
+ const key = `${event.runId}::${workflow.operationId ?? name}::${name}`;
8366
8589
  const list2 = byToolOp.get(key) ?? [];
8367
8590
  list2.push(event);
8368
8591
  byToolOp.set(key, list2);
@@ -8420,7 +8643,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8420
8643
  }
8421
8644
  }
8422
8645
  if (rules.requireRecoveredFailureVisible) {
8423
- for (const [operationId, members] of byOperation) {
8646
+ for (const { operationId, members } of byOperation.values()) {
8424
8647
  const ordered = sortByTime(members);
8425
8648
  const toolish = ordered.filter(
8426
8649
  (event) => (event.kind === "TOOL" || event.kind === "LLM") && (event.status === "ok" || event.status === "error")
@@ -8459,10 +8682,13 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
8459
8682
  }
8460
8683
  return findings;
8461
8684
  }
8685
+ var IDENTITY_KEYS;
8462
8686
  var init_retry_safety = __esm({
8463
8687
  "packages/core/src/checks/retry-safety.ts"() {
8464
8688
  init_logical_events();
8689
+ init_delivery_identity();
8465
8690
  init_metadata();
8691
+ IDENTITY_KEYS = ["operationId", "attemptId", "retryOf", "attemptNumber"];
8466
8692
  }
8467
8693
  });
8468
8694
 
@@ -8679,14 +8905,7 @@ function attemptIdOf2(event) {
8679
8905
  return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
8680
8906
  }
8681
8907
  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;
8908
+ return hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members);
8690
8909
  }
8691
8910
  function findRetryTarget(members, retryOf) {
8692
8911
  return members.find(
@@ -12565,6 +12784,11 @@ function compactAttributes2(entries) {
12565
12784
  }
12566
12785
  return Object.keys(out).length > 0 ? out : void 0;
12567
12786
  }
12787
+ function stampDeliveryEventBase(eventId, attributes) {
12788
+ const base = deliveryEventBaseFromIndexedId(eventId);
12789
+ if (!base) return attributes;
12790
+ return { ...attributes ?? {}, [DELIVERY_EVENT_BASE_ATTR]: base };
12791
+ }
12568
12792
  function traceEventToPersistedInspectEvent(event, options) {
12569
12793
  const eventIndex = options?.eventIndex ?? 0;
12570
12794
  const eventId = createPersistedEventId(event, eventIndex);
@@ -12594,7 +12818,7 @@ function traceEventToPersistedInspectEvent(event, options) {
12594
12818
  startedAt: tsStart.iso,
12595
12819
  confidence: "explicit",
12596
12820
  source,
12597
- attributes
12821
+ attributes: stampDeliveryEventBase(eventId, attributes)
12598
12822
  };
12599
12823
  }
12600
12824
  case "run_completed": {
@@ -12617,7 +12841,7 @@ function traceEventToPersistedInspectEvent(event, options) {
12617
12841
  durationMs: event.durationMs,
12618
12842
  confidence: "explicit",
12619
12843
  source,
12620
- attributes,
12844
+ attributes: stampDeliveryEventBase(eventId, attributes),
12621
12845
  error
12622
12846
  };
12623
12847
  }
@@ -12642,7 +12866,7 @@ function traceEventToPersistedInspectEvent(event, options) {
12642
12866
  startedAt: tsStart.iso,
12643
12867
  confidence: "explicit",
12644
12868
  source,
12645
- attributes
12869
+ attributes: stampDeliveryEventBase(eventId, attributes)
12646
12870
  };
12647
12871
  if (event.parentId !== void 0) {
12648
12872
  out.parentId = event.parentId;
@@ -12673,7 +12897,7 @@ function traceEventToPersistedInspectEvent(event, options) {
12673
12897
  durationMs: event.durationMs,
12674
12898
  confidence: "explicit",
12675
12899
  source,
12676
- attributes,
12900
+ attributes: stampDeliveryEventBase(eventId, attributes),
12677
12901
  error
12678
12902
  };
12679
12903
  }
@@ -12700,7 +12924,7 @@ function traceEventToPersistedInspectEvent(event, options) {
12700
12924
  timestamp: tsMain.iso,
12701
12925
  confidence: "explicit",
12702
12926
  source,
12703
- attributes
12927
+ attributes: stampDeliveryEventBase(eventId, attributes)
12704
12928
  };
12705
12929
  if (event.parentId !== void 0) {
12706
12930
  out.parentId = event.parentId;
@@ -12724,6 +12948,7 @@ function traceEventsToPersistedInspectEvents(events, options) {
12724
12948
  var init_from_trace_event = __esm({
12725
12949
  "packages/core/src/persisted/from-trace-event.ts"() {
12726
12950
  init_correlation_metadata();
12951
+ init_delivery_identity();
12727
12952
  init_token_usage();
12728
12953
  }
12729
12954
  });
@@ -12898,6 +13123,7 @@ function resolveRunTiming(sorted, status) {
12898
13123
  var TreeBuilder;
12899
13124
  var init_tree_builder = __esm({
12900
13125
  "packages/core/src/logs/tree-builder.ts"() {
13126
+ init_delivery_identity();
12901
13127
  TreeBuilder = class {
12902
13128
  constructor(options) {
12903
13129
  void options?.config;
@@ -12913,7 +13139,47 @@ var init_tree_builder = __esm({
12913
13139
  const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
12914
13140
  const nodes = /* @__PURE__ */ new Map();
12915
13141
  for (const e of sorted) {
12916
- nodes.set(e.eventId, { event: e, children: [], depth: 0 });
13142
+ const existing = nodes.get(e.eventId);
13143
+ if (!existing) {
13144
+ nodes.set(e.eventId, { event: e, children: [], depth: 0 });
13145
+ continue;
13146
+ }
13147
+ const existingAttrs = existing.event.attributes && typeof existing.event.attributes === "object" ? existing.event.attributes : void 0;
13148
+ const nextAttrs = e.attributes && typeof e.attributes === "object" ? e.attributes : void 0;
13149
+ const existingIdentity = identityFieldsFromAttributes(existingAttrs);
13150
+ const nextIdentity = identityFieldsFromAttributes(nextAttrs);
13151
+ const existingFp = deliverySemanticFingerprint({
13152
+ eventId: existing.event.eventId,
13153
+ runId: existing.event.runId,
13154
+ kind: existing.event.kind,
13155
+ name: existing.event.name,
13156
+ status: existing.event.status,
13157
+ parentId: existing.event.parentId,
13158
+ timestamp: existing.event.timestamp,
13159
+ sourceType: existing.event.source?.type,
13160
+ attributes: existingAttrs,
13161
+ ...existingIdentity
13162
+ });
13163
+ const nextFp = deliverySemanticFingerprint({
13164
+ eventId: e.eventId,
13165
+ runId: e.runId,
13166
+ kind: e.kind,
13167
+ name: e.name,
13168
+ status: e.status,
13169
+ parentId: e.parentId,
13170
+ timestamp: e.timestamp,
13171
+ sourceType: e.source?.type,
13172
+ attributes: nextAttrs,
13173
+ ...nextIdentity
13174
+ });
13175
+ if (existingFp === nextFp) {
13176
+ continue;
13177
+ }
13178
+ nodes.set(e.eventId, {
13179
+ event: stampDeliveryConflict(e),
13180
+ children: [],
13181
+ depth: 0
13182
+ });
12917
13183
  }
12918
13184
  const { roots, summary } = linkNodesVisibilityFirst(nodes);
12919
13185
  const confidenceBreakdown = {
@@ -14190,6 +14456,12 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
14190
14456
  ["agent_inspect.retry_of", "retryOf", "string"],
14191
14457
  ["agent_inspect.attempt_number", "attemptNumber", "int"]
14192
14458
  ];
14459
+ const conflictMapping = [
14460
+ ["agent_inspect.identity_conflict.operation_id", "operationId", "string"],
14461
+ ["agent_inspect.identity_conflict.attempt_id", "attemptId", "string"],
14462
+ ["agent_inspect.identity_conflict.retry_of", "retryOf", "string"],
14463
+ ["agent_inspect.identity_conflict.attempt_number", "attemptNumber", "int"]
14464
+ ];
14193
14465
  const metadata = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? { ...attributes.metadata } : {};
14194
14466
  for (const [dotted, camel, kind] of mapping) {
14195
14467
  const raw = attributes[dotted];
@@ -14241,6 +14513,55 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
14241
14513
  if (direct === void 0) attributes[camel] = promoted;
14242
14514
  if (nested === void 0) metadata[camel] = promoted;
14243
14515
  }
14516
+ for (const [dotted, camel, kind] of conflictMapping) {
14517
+ const raw = attributes[dotted];
14518
+ if (raw === void 0 || raw === null) continue;
14519
+ let alternate;
14520
+ if (kind === "int") {
14521
+ const n = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
14522
+ if (!Number.isFinite(n) || n < 1) {
14523
+ warnings.push({
14524
+ code: "otlp_identity_invalid",
14525
+ message: `Ignoring invalid ${dotted} identity conflict value.`,
14526
+ severity: "warning",
14527
+ field: `${pathPrefix}.${dotted}`
14528
+ });
14529
+ continue;
14530
+ }
14531
+ alternate = Math.trunc(n);
14532
+ } else if (typeof raw === "string" && raw.trim() !== "") {
14533
+ alternate = raw.trim();
14534
+ } else {
14535
+ warnings.push({
14536
+ code: "otlp_identity_invalid",
14537
+ message: `Ignoring non-string ${dotted} identity conflict value.`,
14538
+ severity: "warning",
14539
+ field: `${pathPrefix}.${dotted}`
14540
+ });
14541
+ continue;
14542
+ }
14543
+ const preferred = attributes[camel];
14544
+ if (preferred !== void 0 && preferred !== alternate) {
14545
+ metadata[camel] = alternate;
14546
+ warnings.push({
14547
+ code: "otlp_identity_conflict",
14548
+ message: `Conflicting ${camel}: attributes.${camel} vs nested alternate from ${dotted}; retaining both.`,
14549
+ severity: "warning",
14550
+ field: `${pathPrefix}.${dotted}`
14551
+ });
14552
+ } else if (preferred === void 0) {
14553
+ metadata[camel] = alternate;
14554
+ }
14555
+ }
14556
+ const conflictFields = attributes["agent_inspect.identity_conflict.fields"];
14557
+ if (typeof conflictFields === "string" && conflictFields.trim() !== "") {
14558
+ warnings.push({
14559
+ code: "otlp_identity_conflict",
14560
+ message: `Identity representation conflict fields retained after OTLP bounding: ${conflictFields.trim().slice(0, 200)}.`,
14561
+ severity: "warning",
14562
+ field: `${pathPrefix}.agent_inspect.identity_conflict.fields`
14563
+ });
14564
+ }
14244
14565
  if (Object.keys(metadata).length > 0) {
14245
14566
  attributes.metadata = metadata;
14246
14567
  }
@@ -16980,7 +17301,7 @@ var init_src = __esm({
16980
17301
  });
16981
17302
 
16982
17303
  // package.json
16983
- var version = "6.31.21";
17304
+ var version = "6.31.23";
16984
17305
 
16985
17306
  // packages/cli/src/list.ts
16986
17307
  init_advanced();
@@ -17302,6 +17623,7 @@ init_persisted_inspect_event();
17302
17623
  init_from_trace_event();
17303
17624
 
17304
17625
  // packages/core/src/persisted/from-inspect-event.ts
17626
+ init_delivery_identity();
17305
17627
  init_token_usage();
17306
17628
 
17307
17629
  // packages/core/src/entries/persisted.ts
@@ -19588,6 +19910,7 @@ function exportOpenInference(tree, options) {
19588
19910
  }
19589
19911
 
19590
19912
  // packages/core/src/exporters/otlp-json-exporter.ts
19913
+ init_delivery_identity();
19591
19914
  init_helpers();
19592
19915
  var OTLP_STATUS_CODE_UNSET = 0;
19593
19916
  var OTLP_STATUS_CODE_OK = 1;
@@ -19638,43 +19961,85 @@ var STRUCTURAL_IDENTITY_KEYS = [
19638
19961
  "attemptNumber",
19639
19962
  "attempt"
19640
19963
  ];
19641
- function pickBoundedIdentityString(bag, key, maxLen) {
19964
+ function nestedBag(bag) {
19642
19965
  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);
19966
+ const nested = bag.metadata;
19967
+ if (!nested || typeof nested !== "object" || Array.isArray(nested)) return void 0;
19968
+ return nested;
19969
+ }
19970
+ function pickBoundedIdentityString(bag, key, maxLen) {
19971
+ if (!bag || typeof bag !== "object") return {};
19972
+ const directRaw = bag[key];
19973
+ const nestedRaw = nestedBag(bag)?.[key];
19974
+ const directFull = typeof directRaw === "string" && directRaw.trim() !== "" ? directRaw.trim() : void 0;
19975
+ const nestedFull = typeof nestedRaw === "string" && nestedRaw.trim() !== "" ? nestedRaw.trim() : void 0;
19976
+ const direct = directFull !== void 0 ? directFull.slice(0, maxLen) : void 0;
19977
+ const nested = nestedFull !== void 0 ? nestedFull.slice(0, maxLen) : void 0;
19978
+ if (directFull !== void 0 && nestedFull !== void 0 && directFull !== nestedFull) {
19979
+ return {
19980
+ value: direct,
19981
+ conflictAlternate: nested,
19982
+ truncatedCollision: direct === nested
19983
+ };
19650
19984
  }
19651
- return void 0;
19985
+ if (direct !== void 0) return { value: direct };
19986
+ if (nested !== void 0) return { value: nested };
19987
+ return {};
19652
19988
  }
19653
19989
  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;
19990
+ if (!bag || typeof bag !== "object") return {};
19991
+ const directRaw = bag[key];
19992
+ const nestedRaw = nestedBag(bag)?.[key];
19993
+ const direct = typeof directRaw === "number" && Number.isFinite(directRaw) ? directRaw : void 0;
19994
+ const nested = typeof nestedRaw === "number" && Number.isFinite(nestedRaw) ? nestedRaw : void 0;
19995
+ if (direct !== void 0 && nested !== void 0 && direct !== nested) {
19996
+ return { value: direct, conflictAlternate: nested };
19997
+ }
19998
+ if (direct !== void 0) return { value: direct };
19999
+ if (nested !== void 0) return { value: nested };
20000
+ return {};
19660
20001
  }
19661
20002
  function appendStructuralIdentityAttrs(attrs, meta2, maxLen) {
19662
- const operationId = pickBoundedIdentityString(meta2, "operationId", maxLen);
19663
- if (operationId !== void 0) {
19664
- attrs.push(stringAttr2("agent_inspect.operation_id", operationId));
20003
+ const conflicts = [];
20004
+ const emitString = (key, otlpKey, conflictKey) => {
20005
+ const picked = pickBoundedIdentityString(meta2, key, maxLen);
20006
+ if (picked.value !== void 0) {
20007
+ attrs.push(stringAttr2(otlpKey, picked.value));
20008
+ }
20009
+ if (picked.conflictAlternate !== void 0 || picked.truncatedCollision) {
20010
+ if (picked.conflictAlternate !== void 0) {
20011
+ attrs.push(stringAttr2(conflictKey, picked.conflictAlternate));
20012
+ }
20013
+ conflicts.push(key);
20014
+ }
20015
+ };
20016
+ emitString("operationId", "agent_inspect.operation_id", IDENTITY_CONFLICT_ATTR.operationId);
20017
+ emitString("attemptId", "agent_inspect.attempt_id", IDENTITY_CONFLICT_ATTR.attemptId);
20018
+ emitString("retryOf", "agent_inspect.retry_of", IDENTITY_CONFLICT_ATTR.retryOf);
20019
+ const attemptNumberPrimary = pickBoundedIdentityNumber(meta2, "attemptNumber");
20020
+ const attemptNumber2 = attemptNumberPrimary.value !== void 0 || attemptNumberPrimary.conflictAlternate !== void 0 ? attemptNumberPrimary : pickBoundedIdentityNumber(meta2, "attempt");
20021
+ if (attemptNumber2.value !== void 0) {
20022
+ attrs.push(intAttr("agent_inspect.attempt_number", attemptNumber2.value));
20023
+ }
20024
+ if (attemptNumber2.conflictAlternate !== void 0) {
20025
+ attrs.push(
20026
+ intAttr(IDENTITY_CONFLICT_ATTR.attemptNumber, attemptNumber2.conflictAlternate)
20027
+ );
20028
+ conflicts.push("attemptNumber");
19665
20029
  }
19666
- const attemptId = pickBoundedIdentityString(meta2, "attemptId", maxLen);
19667
- if (attemptId !== void 0) {
19668
- attrs.push(stringAttr2("agent_inspect.attempt_id", attemptId));
20030
+ if (conflicts.length > 0) {
20031
+ attrs.push(
20032
+ stringAttr2(IDENTITY_CONFLICT_ATTR.fields, conflicts.join(",").slice(0, maxLen))
20033
+ );
19669
20034
  }
19670
- const retryOf = pickBoundedIdentityString(meta2, "retryOf", maxLen);
19671
- if (retryOf !== void 0) {
19672
- attrs.push(stringAttr2("agent_inspect.retry_of", retryOf));
20035
+ if (meta2?.[DELIVERY_CONFLICT_ATTR] === true) {
20036
+ attrs.push(boolAttr(DELIVERY_CONFLICT_ATTR, true));
19673
20037
  }
19674
- const attemptNumber2 = pickBoundedIdentityNumber(meta2, "attemptNumber") ?? pickBoundedIdentityNumber(meta2, "attempt");
19675
- if (attemptNumber2 !== void 0) {
19676
- attrs.push(intAttr("agent_inspect.attempt_number", attemptNumber2));
20038
+ const deliveryBase = meta2?.[DELIVERY_EVENT_BASE_ATTR];
20039
+ if (typeof deliveryBase === "string" && deliveryBase.trim() !== "") {
20040
+ attrs.push(stringAttr2(DELIVERY_EVENT_BASE_ATTR, deliveryBase.trim().slice(0, maxLen)));
19677
20041
  }
20042
+ return conflicts;
19678
20043
  }
19679
20044
  function resolveSpanTimes(ev) {
19680
20045
  const startedAtMs = typeof ev.attributes?.startedAtMs === "number" && Number.isFinite(ev.attributes.startedAtMs) ? ev.attributes.startedAtMs : void 0;
@@ -19697,7 +20062,8 @@ function exportOtlpJson(tree, options) {
19697
20062
  "OTLP JSON export uses OTel GenAI-aligned attributes where applicable; experimental until verified against specific collectors.",
19698
20063
  "Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload.",
19699
20064
  "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)."
20065
+ "When present on source events, operationId/attemptId/retryOf/attemptNumber are emitted as bounded agent_inspect.* identity attributes (not a broad attribute dump).",
20066
+ "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
20067
  ];
19702
20068
  const traceId = hexFrom2(`trace:${tree.runId}`, 16);
19703
20069
  const includeAttributes = options?.includeAttributes ?? false;
@@ -19745,11 +20111,16 @@ function exportOtlpJson(tree, options) {
19745
20111
  if (typeof inp === "number") attrs.push(intAttr("gen_ai.usage.input_tokens", inp));
19746
20112
  if (typeof outp === "number") attrs.push(intAttr("gen_ai.usage.output_tokens", outp));
19747
20113
  }
19748
- appendStructuralIdentityAttrs(
20114
+ const identityConflicts = appendStructuralIdentityAttrs(
19749
20115
  attrs,
19750
20116
  meta2 && typeof meta2 === "object" ? meta2 : void 0,
19751
20117
  maxLen
19752
20118
  );
20119
+ if (identityConflicts.length > 0) {
20120
+ warnings.push(
20121
+ `Identity representation conflict on event ${ev.eventId}: ${identityConflicts.join(", ")} (direct preferred; nested retained on agent_inspect.identity_conflict.*).`
20122
+ );
20123
+ }
19753
20124
  if (includeAttributes && meta2 && typeof meta2 === "object") {
19754
20125
  const skipKeys = /* @__PURE__ */ new Set([
19755
20126
  "tokens",