agent-inspect 6.31.32 → 6.31.34

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 (41) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/docs/TRACE-CONTRACTS.md +2 -0
  4. package/package.json +1 -1
  5. package/packages/cli/dist/{chunk-PEGM6T2X.mjs → chunk-6TXW53UR.mjs} +138 -36
  6. package/packages/cli/dist/chunk-6TXW53UR.mjs.map +1 -0
  7. package/packages/cli/dist/index.cjs +197 -50
  8. package/packages/cli/dist/index.cjs.map +1 -1
  9. package/packages/cli/dist/index.mjs +64 -19
  10. package/packages/cli/dist/index.mjs.map +1 -1
  11. package/packages/cli/dist/{src-CWUJTMRD.mjs → src-GCLC4DIC.mjs} +3 -3
  12. package/packages/cli/dist/{src-CWUJTMRD.mjs.map → src-GCLC4DIC.mjs.map} +1 -1
  13. package/packages/core/dist/advanced.cjs +79 -20
  14. package/packages/core/dist/advanced.cjs.map +1 -1
  15. package/packages/core/dist/advanced.mjs +9 -9
  16. package/packages/core/dist/checks.cjs +133 -32
  17. package/packages/core/dist/checks.cjs.map +1 -1
  18. package/packages/core/dist/checks.mjs +3 -3
  19. package/packages/core/dist/{chunk-6S666BF4.mjs → chunk-2SKAI5ZN.mjs} +3 -3
  20. package/packages/core/dist/{chunk-6S666BF4.mjs.map → chunk-2SKAI5ZN.mjs.map} +1 -1
  21. package/packages/core/dist/{chunk-FBPDF7HO.mjs → chunk-6F6KLGCR.mjs} +3 -3
  22. package/packages/core/dist/{chunk-FBPDF7HO.mjs.map → chunk-6F6KLGCR.mjs.map} +1 -1
  23. package/packages/core/dist/{chunk-6G67ZN72.mjs → chunk-CXC7L4PY.mjs} +136 -35
  24. package/packages/core/dist/chunk-CXC7L4PY.mjs.map +1 -0
  25. package/packages/core/dist/{chunk-RB6WANSW.mjs → chunk-PU3FF5AP.mjs} +5 -4
  26. package/packages/core/dist/chunk-PU3FF5AP.mjs.map +1 -0
  27. package/packages/core/dist/{chunk-VIEJJ5JB.mjs → chunk-X5RP2E2H.mjs} +4 -4
  28. package/packages/core/dist/{chunk-VIEJJ5JB.mjs.map → chunk-X5RP2E2H.mjs.map} +1 -1
  29. package/packages/core/dist/exporters.cjs +33 -9
  30. package/packages/core/dist/exporters.cjs.map +1 -1
  31. package/packages/core/dist/exporters.mjs +33 -10
  32. package/packages/core/dist/exporters.mjs.map +1 -1
  33. package/packages/core/dist/index.cjs +3 -2
  34. package/packages/core/dist/index.cjs.map +1 -1
  35. package/packages/core/dist/index.mjs +4 -4
  36. package/packages/core/dist/writers.cjs +3 -2
  37. package/packages/core/dist/writers.cjs.map +1 -1
  38. package/packages/core/dist/writers.mjs +1 -1
  39. package/packages/cli/dist/chunk-PEGM6T2X.mjs.map +0 -1
  40. package/packages/core/dist/chunk-6G67ZN72.mjs.map +0 -1
  41. package/packages/core/dist/chunk-RB6WANSW.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { OBSERVED_OUTCOME_METHODS, extractOutcomesFromPersistedEvents, outcomesMatchingStatus } from './chunk-FBPDF7HO.mjs';
1
+ import { OBSERVED_OUTCOME_METHODS, extractOutcomesFromPersistedEvents, outcomesMatchingStatus } from './chunk-6F6KLGCR.mjs';
2
2
  import { DEFAULT_CREDENTIAL_SENSITIVE_KEYS, isCredentialSensitiveKey } from './chunk-VLVCLAPB.mjs';
3
3
  import { projectLogicalEvents, resolveCanonicalToolName } from './chunk-AHUZNHFI.mjs';
4
4
  import { formatProgrammaticDiagnostic } from './chunk-S6LQBLX5.mjs';
@@ -2345,10 +2345,17 @@ function contractToRules(contract) {
2345
2345
  (event) => event.status === "running"
2346
2346
  );
2347
2347
  if (running.length > 0) {
2348
+ const labels = running.map((event) => {
2349
+ if (event.kind === "TOOL") {
2350
+ return `tool ${resolveCanonicalToolName(event)}`;
2351
+ }
2352
+ return `${event.kind} ${event.name}`;
2353
+ });
2354
+ const message = labels.length === 1 ? `Run contains incomplete running events: ${labels[0]} never completed.` : `Run contains incomplete running events: ${labels.join("; ")}.`;
2348
2355
  findings.push(
2349
2356
  contractFailFinding(
2350
2357
  "contract.run.allowedStatuses",
2351
- "Run contains incomplete running events.",
2358
+ message,
2352
2359
  running.map((event) => ({
2353
2360
  runId: event.runId,
2354
2361
  eventId: event.eventId,
@@ -2357,7 +2364,10 @@ function contractToRules(contract) {
2357
2364
  status: event.status
2358
2365
  })),
2359
2366
  "no running events",
2360
- running.length
2367
+ {
2368
+ count: running.length,
2369
+ unfinished: labels
2370
+ }
2361
2371
  )
2362
2372
  );
2363
2373
  }
@@ -3307,10 +3317,11 @@ var SAFE_USAGE_LEAF_KEYS = /* @__PURE__ */ new Set([
3307
3317
  var DEFAULT_SECRET_PATTERNS = [
3308
3318
  { id: "bearer-token", pattern: /Bearer\s+[A-Za-z0-9._~+/-]{12,}=*/ },
3309
3319
  { id: "openai-key", pattern: /sk-[A-Za-z0-9_-]{16,}/ },
3310
- // Stripe + Slack: keep in sync with packages/redact + credential-value-patterns (#520).
3320
+ // Stripe + Slack: keep in sync with packages/redact + credential-value-patterns (#520/#528).
3321
+ // Non-alnum lookarounds so underscore-adjacent forms (acct_sk_live_…, …_eu) match.
3311
3322
  {
3312
3323
  id: "stripe-key",
3313
- pattern: /\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/
3324
+ pattern: /(?<![A-Za-z0-9])(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}(?![A-Za-z0-9])/
3314
3325
  },
3315
3326
  { id: "slack-token", pattern: /\bxox[abposr]-[A-Za-z0-9-]{10,}\b/ },
3316
3327
  { id: "aws-access-key", pattern: /AKIA[0-9A-Z]{16}/ },
@@ -3494,6 +3505,11 @@ function compareFindings(eventById) {
3494
3505
  if (STATUS_RANK[a.status] !== STATUS_RANK[b.status]) {
3495
3506
  return STATUS_RANK[a.status] - STATUS_RANK[b.status];
3496
3507
  }
3508
+ if (a.ruleId === "tool.usage") {
3509
+ const aHasEvent = a.evidence[0]?.eventId !== void 0;
3510
+ const bHasEvent = b.evidence[0]?.eventId !== void 0;
3511
+ if (aHasEvent !== bHasEvent) return aHasEvent ? -1 : 1;
3512
+ }
3497
3513
  const byRun = compareStrings(a.evidence[0]?.runId, b.evidence[0]?.runId);
3498
3514
  if (byRun !== 0) return byRun;
3499
3515
  const byTime = eventTimestamp(a, eventById).localeCompare(eventTimestamp(b, eventById));
@@ -3619,6 +3635,37 @@ function failFinding(ruleId, message, evidence, expected, actual, meta) {
3619
3635
  function toolName(event) {
3620
3636
  return resolveCanonicalToolName(event);
3621
3637
  }
3638
+ function formatToolNameForMessage(name) {
3639
+ const details = [];
3640
+ for (let index = 0; index < name.length; ) {
3641
+ const codePoint = name.codePointAt(index);
3642
+ const width = codePoint > 65535 ? 2 : 1;
3643
+ if (codePoint > 127) {
3644
+ details.push(
3645
+ `U+${codePoint.toString(16).toUpperCase().padStart(4, "0")} at index ${index}`
3646
+ );
3647
+ }
3648
+ index += width;
3649
+ }
3650
+ if (details.length === 0) return name;
3651
+ return `"${name}" (contains ${details.join("; ")})`;
3652
+ }
3653
+ function describeRunningEvent(event) {
3654
+ if (event.kind === "TOOL") {
3655
+ return `tool ${formatToolNameForMessage(resolveCanonicalToolName(event))}`;
3656
+ }
3657
+ if (event.kind === "LLM") {
3658
+ return `llm ${stepEndpointName(event, "LLM")}`;
3659
+ }
3660
+ return `${event.kind} ${event.name}`;
3661
+ }
3662
+ function incompleteRunningMessage(prefix, running) {
3663
+ const labels = running.map(describeRunningEvent);
3664
+ if (labels.length === 1) {
3665
+ return `${prefix}: ${labels[0]} never completed.`;
3666
+ }
3667
+ return `${prefix}: ${labels.join("; ")}.`;
3668
+ }
3622
3669
  function stepEndpointName(event, kind) {
3623
3670
  if (kind === "TOOL") return resolveCanonicalToolName(event);
3624
3671
  for (const prefix of ["llm:", "generation:", "transcription:", "speech:"]) {
@@ -3963,10 +4010,13 @@ function createRunStatusRule(options = {}) {
3963
4010
  findings.push(
3964
4011
  failFinding(
3965
4012
  "run.status",
3966
- "Run contains incomplete running events.",
4013
+ incompleteRunningMessage("Run contains incomplete running events", running),
3967
4014
  running.map((event) => eventEvidence3(event)),
3968
4015
  "no running events",
3969
- running.length
4016
+ {
4017
+ count: running.length,
4018
+ unfinished: running.map(describeRunningEvent)
4019
+ }
3970
4020
  )
3971
4021
  );
3972
4022
  }
@@ -4172,6 +4222,34 @@ function createToolUsageRule(options) {
4172
4222
  const names = tools.map(toolName);
4173
4223
  const nameSet = new Set(names);
4174
4224
  const findings = [];
4225
+ const forbidden = new Set(options.forbidden ?? []);
4226
+ const allowed = options.allowed?.length ? new Set(options.allowed) : void 0;
4227
+ for (const event of tools) {
4228
+ const name = toolName(event);
4229
+ const display = formatToolNameForMessage(name);
4230
+ if (forbidden.has(name)) {
4231
+ findings.push(
4232
+ failFinding(
4233
+ "tool.usage",
4234
+ `Forbidden tool ${display} appeared.`,
4235
+ [eventEvidence3(event)],
4236
+ "tool absent",
4237
+ name
4238
+ )
4239
+ );
4240
+ }
4241
+ if (allowed && !allowed.has(name)) {
4242
+ findings.push(
4243
+ failFinding(
4244
+ "tool.usage",
4245
+ `Tool ${display} is not in the allowed tool set.`,
4246
+ [eventEvidence3(event)],
4247
+ [...allowed].sort(),
4248
+ name
4249
+ )
4250
+ );
4251
+ }
4252
+ }
4175
4253
  for (const required of options.required ?? []) {
4176
4254
  if (!nameSet.has(required)) {
4177
4255
  const otherKinds = [
@@ -4189,7 +4267,7 @@ function createToolUsageRule(options) {
4189
4267
  findings.push(
4190
4268
  failFinding(
4191
4269
  "tool.usage",
4192
- `Required tool ${required} did not appear.${hint}`,
4270
+ `Required tool ${formatToolNameForMessage(required)} did not appear.${hint}`,
4193
4271
  runEvidence(context.selectedRun),
4194
4272
  required,
4195
4273
  names
@@ -4197,21 +4275,6 @@ function createToolUsageRule(options) {
4197
4275
  );
4198
4276
  }
4199
4277
  }
4200
- const forbidden = new Set(options.forbidden ?? []);
4201
- const allowed = options.allowed?.length ? new Set(options.allowed) : void 0;
4202
- for (const event of tools) {
4203
- const name = toolName(event);
4204
- if (forbidden.has(name)) {
4205
- findings.push(
4206
- failFinding("tool.usage", `Forbidden tool ${name} appeared.`, [eventEvidence3(event)], "tool absent", name)
4207
- );
4208
- }
4209
- if (allowed && !allowed.has(name)) {
4210
- findings.push(
4211
- failFinding("tool.usage", `Tool ${name} is not in the allowed tool set.`, [eventEvidence3(event)], [...allowed].sort(), name)
4212
- );
4213
- }
4214
- }
4215
4278
  if (options.minCount !== void 0 && tools.length < options.minCount) {
4216
4279
  findings.push(
4217
4280
  failFinding("tool.usage", `Tool count ${tools.length} was below minimum ${options.minCount}.`, runEvidence(context.selectedRun), { minCount: options.minCount }, tools.length)
@@ -4245,7 +4308,36 @@ function createStepOrderingRule(options) {
4245
4308
  const afterEvents = finishedEvents(context, options.after.kind).filter(
4246
4309
  (event) => stepEndpointName(event, options.after.kind) === options.after.name
4247
4310
  );
4248
- if (beforeEvents.length === 0 || afterEvents.length === 0) {
4311
+ const beforeRunning = semanticEvents(context).filter(
4312
+ (event) => event.kind === options.before.kind && event.status === "running" && stepEndpointName(event, options.before.kind) === options.before.name
4313
+ );
4314
+ const afterRunning = semanticEvents(context).filter(
4315
+ (event) => event.kind === options.after.kind && event.status === "running" && stepEndpointName(event, options.after.kind) === options.after.name
4316
+ );
4317
+ const afterStarted = afterEvents.length > 0 || afterRunning.length > 0;
4318
+ const afterEvidenceEvent = afterEvents[0] ?? afterRunning[0];
4319
+ if (beforeRunning.length > 0 && afterStarted && afterEvidenceEvent !== void 0) {
4320
+ const endpointExpected2 = bothTools ? { before: options.before.name, after: options.after.name } : { before: options.before, after: options.after };
4321
+ return [
4322
+ failFinding(
4323
+ ruleId,
4324
+ `${subject} ${beforeLabel} started but never finished before ${afterLabel} ran.`,
4325
+ [
4326
+ ...beforeRunning.map((event) => eventEvidence3(event)),
4327
+ eventEvidence3(afterEvidenceEvent)
4328
+ ],
4329
+ { ...endpointExpected2, mode },
4330
+ {
4331
+ code: bothTools ? "tool.order.interval-unresolved" : "step.order.interval-unresolved",
4332
+ unfinishedBefore: true,
4333
+ beforeStatus: "running",
4334
+ ...beforeEvents.length > 0 ? { finishedBeforeMasked: true } : {},
4335
+ ...afterEvents.length === 0 ? { afterStatus: "running" } : {}
4336
+ }
4337
+ )
4338
+ ];
4339
+ }
4340
+ if (beforeEvents.length === 0 || !afterStarted) {
4249
4341
  if (!requireEndpoints) return [];
4250
4342
  const findings = [];
4251
4343
  if (beforeEvents.length === 0) {
@@ -4269,7 +4361,7 @@ function createStepOrderingRule(options) {
4269
4361
  )
4270
4362
  );
4271
4363
  }
4272
- if (afterEvents.length === 0) {
4364
+ if (!afterStarted) {
4273
4365
  const otherKinds = otherKindsForStepName(
4274
4366
  context,
4275
4367
  options.after.kind,
@@ -4292,9 +4384,15 @@ function createStepOrderingRule(options) {
4292
4384
  }
4293
4385
  return findings;
4294
4386
  }
4295
- const encounter = finishedEvents(context).filter(
4296
- (event) => event.kind === options.before.kind && stepEndpointName(event, options.before.kind) === options.before.name || event.kind === options.after.kind && stepEndpointName(event, options.after.kind) === options.after.name
4297
- );
4387
+ const afterForOrder = afterEvents.length > 0 ? afterEvents : afterRunning;
4388
+ const encounter = [
4389
+ ...finishedEvents(context).filter(
4390
+ (event) => event.kind === options.before.kind && stepEndpointName(event, options.before.kind) === options.before.name || event.kind === options.after.kind && stepEndpointName(event, options.after.kind) === options.after.name
4391
+ ),
4392
+ ...afterEvents.length === 0 ? afterRunning.filter(
4393
+ (event) => !finishedEvents(context).some((finished) => finished.eventId === event.eventId)
4394
+ ) : []
4395
+ ];
4298
4396
  let beforeIndex;
4299
4397
  let afterIndex;
4300
4398
  for (const [position, event] of encounter.entries()) {
@@ -4325,7 +4423,7 @@ function createStepOrderingRule(options) {
4325
4423
  ];
4326
4424
  }
4327
4425
  const beforeEvent = beforeEvents[0];
4328
- const afterEvent = afterEvents[0];
4426
+ const afterEvent = afterForOrder[0];
4329
4427
  const beforeEnd = eventEndMs(beforeEvent);
4330
4428
  const afterStart = eventStartMs(afterEvent);
4331
4429
  const endpointExpected = bothTools ? { before: options.before.name, after: options.after.name } : { before: options.before, after: options.after };
@@ -4411,7 +4509,7 @@ function createStepOrderingRule(options) {
4411
4509
  latestBefore = { event, end };
4412
4510
  }
4413
4511
  }
4414
- for (const event of afterEvents) {
4512
+ for (const event of afterForOrder) {
4415
4513
  const start = eventStartMs(event);
4416
4514
  if (start === void 0) {
4417
4515
  missingAfterStarts += 1;
@@ -4440,7 +4538,7 @@ function createStepOrderingRule(options) {
4440
4538
  const tie = tiedEnd === tiedStart ? recordedTieOrder(
4441
4539
  context,
4442
4540
  beforeEvents.filter((event) => eventEndMs(event) === tiedEnd),
4443
- afterEvents.filter((event) => eventStartMs(event) === tiedStart)
4541
+ afterForOrder.filter((event) => eventStartMs(event) === tiedStart)
4444
4542
  ) : void 0;
4445
4543
  if (latestBefore.end > earliestAfter.start || tie !== void 0 && tie.inOrder !== true) {
4446
4544
  return [
@@ -4621,10 +4719,13 @@ function createStructureIncompleteRule(options = {}) {
4621
4719
  findings.push(
4622
4720
  failFinding(
4623
4721
  "structure.incomplete",
4624
- "Trace contains incomplete running events.",
4722
+ incompleteRunningMessage("Trace contains incomplete running events", running),
4625
4723
  running.map((event) => eventEvidence3(event, "status")),
4626
4724
  "no running events",
4627
- running.length
4725
+ {
4726
+ count: running.length,
4727
+ unfinished: running.map(describeRunningEvent)
4728
+ }
4628
4729
  )
4629
4730
  );
4630
4731
  }
@@ -5418,5 +5519,5 @@ function runTraceChecks(input, options = {}) {
5418
5519
  }
5419
5520
 
5420
5521
  export { buildTraceFacts, createBaselineRegressionRule, createDecisionRule, createGuardrailRule, createLlmUsageRule, createMaxStepDurationRule, createObservedOutcomeRule, createRequireCompletedRule, createRetrievalRule, createRunDepthRule, createRunDurationRule, createRunEventCountRule, createRunStatusRule, createSafetyOversizedAttributeRule, createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createStallDetectionRule, createStepOrderingRule, createStructureCycleRule, createStructureIncompleteRule, createStructureOrphanRule, createStructureParallelWidthRule, createStructureRelationshipRule, createToolFailureRule, createToolOrderingRule, createToolUsageRule, defineTraceContract, deriveFailureFacts, deriveRelationshipFacts, evaluateToolArgumentValue, evaluateTraceContract, evaluateTraceContractRead, explainTraceContract, extractSessionWorkflowMetadata, extractToolArgumentPayload, lintTraceContract, resolveJsonPointer, resolveTraceContractScope, runTraceChecks, sessionKeyForRun, summarizeSemanticParity, workflowMetadataForRun };
5421
- //# sourceMappingURL=chunk-6G67ZN72.mjs.map
5422
- //# sourceMappingURL=chunk-6G67ZN72.mjs.map
5522
+ //# sourceMappingURL=chunk-CXC7L4PY.mjs.map
5523
+ //# sourceMappingURL=chunk-CXC7L4PY.mjs.map