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,15 +1,15 @@
1
- import { extractSessionWorkflowMetadata, sessionKeyForRun, defineTraceContract, runTraceChecks, createRunStatusRule, createToolUsageRule, createRunDurationRule, createRunDepthRule, createToolFailureRule, createLlmUsageRule, createObservedOutcomeRule } from './chunk-6G67ZN72.mjs';
2
- export { extractSessionWorkflowMetadata, sessionKeyForRun } from './chunk-6G67ZN72.mjs';
3
- export { MAX_TERMINAL_DEPTH, MAX_TERMINAL_NAME_LENGTH, TERMINAL_INDENT, TraceDirectory, createInspector, createInspectorRuntime, formatTerminalName, getCurrentContext, getCurrentCorrelationMetadata, getCurrentDepth, getCurrentRunId, getCurrentRunName, getCurrentStepId, getIndent, getParentStepId, getTraceDirFromContext, getTraceSafetyFromContext, hasActiveContext, isAgentInspectEnabled, isSilentContext, maybeInspectRun, printError, printFailedAt, printRunComplete, printRunStart, printStepComplete, printStepStart, renderErrorLine, renderRunSummary, renderStepLine, resolveTraceDir, runWithContext, runWithStepContext } from './chunk-VIEJJ5JB.mjs';
4
- import { buildRunTimeline, filterTraces, extractMetadata, buildRunSummary } from './chunk-6S666BF4.mjs';
5
- export { buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildTraceStats, extractMetadata, filterTraces, formatStepLabel, renderRunWhat, renderTimeline, renderTraceStats } from './chunk-6S666BF4.mjs';
6
- import { extractOutcomesFromTraceEvents, parseObservationFilter, summarizeObservedOutcomes, extractOutcomesFromPersistedEvents, renderObservedOutcomesHtml } from './chunk-FBPDF7HO.mjs';
7
- export { extractOutcomesFromPersistedEvents, extractOutcomesFromTraceEvents } from './chunk-FBPDF7HO.mjs';
1
+ import { extractSessionWorkflowMetadata, sessionKeyForRun, defineTraceContract, runTraceChecks, createRunStatusRule, createToolUsageRule, createRunDurationRule, createRunDepthRule, createToolFailureRule, createLlmUsageRule, createObservedOutcomeRule } from './chunk-CXC7L4PY.mjs';
2
+ export { extractSessionWorkflowMetadata, sessionKeyForRun } from './chunk-CXC7L4PY.mjs';
3
+ export { MAX_TERMINAL_DEPTH, MAX_TERMINAL_NAME_LENGTH, TERMINAL_INDENT, TraceDirectory, createInspector, createInspectorRuntime, formatTerminalName, getCurrentContext, getCurrentCorrelationMetadata, getCurrentDepth, getCurrentRunId, getCurrentRunName, getCurrentStepId, getIndent, getParentStepId, getTraceDirFromContext, getTraceSafetyFromContext, hasActiveContext, isAgentInspectEnabled, isSilentContext, maybeInspectRun, printError, printFailedAt, printRunComplete, printRunStart, printStepComplete, printStepStart, renderErrorLine, renderRunSummary, renderStepLine, resolveTraceDir, runWithContext, runWithStepContext } from './chunk-X5RP2E2H.mjs';
4
+ import { buildRunTimeline, filterTraces, extractMetadata, buildRunSummary } from './chunk-2SKAI5ZN.mjs';
5
+ export { buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildTraceStats, extractMetadata, filterTraces, formatStepLabel, renderRunWhat, renderTimeline, renderTraceStats } from './chunk-2SKAI5ZN.mjs';
6
+ import { extractOutcomesFromTraceEvents, parseObservationFilter, summarizeObservedOutcomes, extractOutcomesFromPersistedEvents, renderObservedOutcomesHtml } from './chunk-6F6KLGCR.mjs';
7
+ export { extractOutcomesFromPersistedEvents, extractOutcomesFromTraceEvents } from './chunk-6F6KLGCR.mjs';
8
8
  import { diffTraceEvents, renderRunDiff } from './chunk-F7STQ5JF.mjs';
9
9
  import './chunk-BT7CATSD.mjs';
10
10
  import { escapeHtml, flattenTree } from './chunk-CAWPF22J.mjs';
11
- import { resolveRedactionProfile, readTraceEventsFromFile, stringContainsHighConfidenceCredential } from './chunk-RB6WANSW.mjs';
12
- export { DEFAULT_MAX_EVENT_BYTES, DEFAULT_MAX_METADATA_VALUE_LENGTH, DEFAULT_MAX_PREVIEW_LENGTH, getRunIdFromTraceFileName, initializeTraceFile, listTraceFiles, prepareMetadataForDisk, prepareTraceEventForDisk, readTraceEvents, readTraceFile, resolveRedactionProfile, resolveTraceSafetyOptions, serializeEvent, validateEvent, writeTraceEvent } from './chunk-RB6WANSW.mjs';
11
+ import { resolveRedactionProfile, readTraceEventsFromFile, stringContainsHighConfidenceCredential } from './chunk-PU3FF5AP.mjs';
12
+ export { DEFAULT_MAX_EVENT_BYTES, DEFAULT_MAX_METADATA_VALUE_LENGTH, DEFAULT_MAX_PREVIEW_LENGTH, getRunIdFromTraceFileName, initializeTraceFile, listTraceFiles, prepareMetadataForDisk, prepareTraceEventForDisk, readTraceEvents, readTraceFile, resolveRedactionProfile, resolveTraceSafetyOptions, serializeEvent, validateEvent, writeTraceEvent } from './chunk-PU3FF5AP.mjs';
13
13
  import { Redactor } from './chunk-VLVCLAPB.mjs';
14
14
  import { openTrace } from './chunk-JJSL346L.mjs';
15
15
  import './chunk-77PUPLPG.mjs';
@@ -3010,10 +3010,17 @@ function contractToRules(contract) {
3010
3010
  (event) => event.status === "running"
3011
3011
  );
3012
3012
  if (running.length > 0) {
3013
+ const labels = running.map((event) => {
3014
+ if (event.kind === "TOOL") {
3015
+ return `tool ${resolveCanonicalToolName(event)}`;
3016
+ }
3017
+ return `${event.kind} ${event.name}`;
3018
+ });
3019
+ const message = labels.length === 1 ? `Run contains incomplete running events: ${labels[0]} never completed.` : `Run contains incomplete running events: ${labels.join("; ")}.`;
3013
3020
  findings.push(
3014
3021
  contractFailFinding(
3015
3022
  "contract.run.allowedStatuses",
3016
- "Run contains incomplete running events.",
3023
+ message,
3017
3024
  running.map((event) => ({
3018
3025
  runId: event.runId,
3019
3026
  eventId: event.eventId,
@@ -3022,7 +3029,10 @@ function contractToRules(contract) {
3022
3029
  status: event.status
3023
3030
  })),
3024
3031
  "no running events",
3025
- running.length
3032
+ {
3033
+ count: running.length,
3034
+ unfinished: labels
3035
+ }
3026
3036
  )
3027
3037
  );
3028
3038
  }
@@ -3972,10 +3982,11 @@ var SAFE_USAGE_LEAF_KEYS = /* @__PURE__ */ new Set([
3972
3982
  var DEFAULT_SECRET_PATTERNS = [
3973
3983
  { id: "bearer-token", pattern: /Bearer\s+[A-Za-z0-9._~+/-]{12,}=*/ },
3974
3984
  { id: "openai-key", pattern: /sk-[A-Za-z0-9_-]{16,}/ },
3975
- // Stripe + Slack: keep in sync with packages/redact + credential-value-patterns (#520).
3985
+ // Stripe + Slack: keep in sync with packages/redact + credential-value-patterns (#520/#528).
3986
+ // Non-alnum lookarounds so underscore-adjacent forms (acct_sk_live_…, …_eu) match.
3976
3987
  {
3977
3988
  id: "stripe-key",
3978
- pattern: /\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/
3989
+ pattern: /(?<![A-Za-z0-9])(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}(?![A-Za-z0-9])/
3979
3990
  },
3980
3991
  { id: "slack-token", pattern: /\bxox[abposr]-[A-Za-z0-9-]{10,}\b/ },
3981
3992
  { id: "aws-access-key", pattern: /AKIA[0-9A-Z]{16}/ },
@@ -4159,6 +4170,11 @@ function compareFindings(eventById) {
4159
4170
  if (STATUS_RANK[a.status] !== STATUS_RANK[b.status]) {
4160
4171
  return STATUS_RANK[a.status] - STATUS_RANK[b.status];
4161
4172
  }
4173
+ if (a.ruleId === "tool.usage") {
4174
+ const aHasEvent = a.evidence[0]?.eventId !== void 0;
4175
+ const bHasEvent = b.evidence[0]?.eventId !== void 0;
4176
+ if (aHasEvent !== bHasEvent) return aHasEvent ? -1 : 1;
4177
+ }
4162
4178
  const byRun = compareStrings(a.evidence[0]?.runId, b.evidence[0]?.runId);
4163
4179
  if (byRun !== 0) return byRun;
4164
4180
  const byTime = eventTimestamp(a, eventById).localeCompare(eventTimestamp(b, eventById));
@@ -4284,6 +4300,37 @@ function failFinding(ruleId, message, evidence, expected, actual, meta) {
4284
4300
  function toolName(event) {
4285
4301
  return resolveCanonicalToolName(event);
4286
4302
  }
4303
+ function formatToolNameForMessage(name) {
4304
+ const details = [];
4305
+ for (let index = 0; index < name.length; ) {
4306
+ const codePoint = name.codePointAt(index);
4307
+ const width = codePoint > 65535 ? 2 : 1;
4308
+ if (codePoint > 127) {
4309
+ details.push(
4310
+ `U+${codePoint.toString(16).toUpperCase().padStart(4, "0")} at index ${index}`
4311
+ );
4312
+ }
4313
+ index += width;
4314
+ }
4315
+ if (details.length === 0) return name;
4316
+ return `"${name}" (contains ${details.join("; ")})`;
4317
+ }
4318
+ function describeRunningEvent(event) {
4319
+ if (event.kind === "TOOL") {
4320
+ return `tool ${formatToolNameForMessage(resolveCanonicalToolName(event))}`;
4321
+ }
4322
+ if (event.kind === "LLM") {
4323
+ return `llm ${stepEndpointName(event, "LLM")}`;
4324
+ }
4325
+ return `${event.kind} ${event.name}`;
4326
+ }
4327
+ function incompleteRunningMessage(prefix, running) {
4328
+ const labels = running.map(describeRunningEvent);
4329
+ if (labels.length === 1) {
4330
+ return `${prefix}: ${labels[0]} never completed.`;
4331
+ }
4332
+ return `${prefix}: ${labels.join("; ")}.`;
4333
+ }
4287
4334
  function stepEndpointName(event, kind) {
4288
4335
  if (kind === "TOOL") return resolveCanonicalToolName(event);
4289
4336
  for (const prefix of ["llm:", "generation:", "transcription:", "speech:"]) {
@@ -4628,10 +4675,13 @@ function createRunStatusRule(options = {}) {
4628
4675
  findings.push(
4629
4676
  failFinding(
4630
4677
  "run.status",
4631
- "Run contains incomplete running events.",
4678
+ incompleteRunningMessage("Run contains incomplete running events", running),
4632
4679
  running.map((event) => eventEvidence3(event)),
4633
4680
  "no running events",
4634
- running.length
4681
+ {
4682
+ count: running.length,
4683
+ unfinished: running.map(describeRunningEvent)
4684
+ }
4635
4685
  )
4636
4686
  );
4637
4687
  }
@@ -4837,6 +4887,34 @@ function createToolUsageRule(options) {
4837
4887
  const names = tools.map(toolName);
4838
4888
  const nameSet = new Set(names);
4839
4889
  const findings = [];
4890
+ const forbidden = new Set(options.forbidden ?? []);
4891
+ const allowed = options.allowed?.length ? new Set(options.allowed) : void 0;
4892
+ for (const event of tools) {
4893
+ const name = toolName(event);
4894
+ const display = formatToolNameForMessage(name);
4895
+ if (forbidden.has(name)) {
4896
+ findings.push(
4897
+ failFinding(
4898
+ "tool.usage",
4899
+ `Forbidden tool ${display} appeared.`,
4900
+ [eventEvidence3(event)],
4901
+ "tool absent",
4902
+ name
4903
+ )
4904
+ );
4905
+ }
4906
+ if (allowed && !allowed.has(name)) {
4907
+ findings.push(
4908
+ failFinding(
4909
+ "tool.usage",
4910
+ `Tool ${display} is not in the allowed tool set.`,
4911
+ [eventEvidence3(event)],
4912
+ [...allowed].sort(),
4913
+ name
4914
+ )
4915
+ );
4916
+ }
4917
+ }
4840
4918
  for (const required of options.required ?? []) {
4841
4919
  if (!nameSet.has(required)) {
4842
4920
  const otherKinds = [
@@ -4854,7 +4932,7 @@ function createToolUsageRule(options) {
4854
4932
  findings.push(
4855
4933
  failFinding(
4856
4934
  "tool.usage",
4857
- `Required tool ${required} did not appear.${hint}`,
4935
+ `Required tool ${formatToolNameForMessage(required)} did not appear.${hint}`,
4858
4936
  runEvidence(context.selectedRun),
4859
4937
  required,
4860
4938
  names
@@ -4862,21 +4940,6 @@ function createToolUsageRule(options) {
4862
4940
  );
4863
4941
  }
4864
4942
  }
4865
- const forbidden = new Set(options.forbidden ?? []);
4866
- const allowed = options.allowed?.length ? new Set(options.allowed) : void 0;
4867
- for (const event of tools) {
4868
- const name = toolName(event);
4869
- if (forbidden.has(name)) {
4870
- findings.push(
4871
- failFinding("tool.usage", `Forbidden tool ${name} appeared.`, [eventEvidence3(event)], "tool absent", name)
4872
- );
4873
- }
4874
- if (allowed && !allowed.has(name)) {
4875
- findings.push(
4876
- failFinding("tool.usage", `Tool ${name} is not in the allowed tool set.`, [eventEvidence3(event)], [...allowed].sort(), name)
4877
- );
4878
- }
4879
- }
4880
4943
  if (options.minCount !== void 0 && tools.length < options.minCount) {
4881
4944
  findings.push(
4882
4945
  failFinding("tool.usage", `Tool count ${tools.length} was below minimum ${options.minCount}.`, runEvidence(context.selectedRun), { minCount: options.minCount }, tools.length)
@@ -4910,7 +4973,36 @@ function createStepOrderingRule(options) {
4910
4973
  const afterEvents = finishedEvents(context, options.after.kind).filter(
4911
4974
  (event) => stepEndpointName(event, options.after.kind) === options.after.name
4912
4975
  );
4913
- if (beforeEvents.length === 0 || afterEvents.length === 0) {
4976
+ const beforeRunning = semanticEvents(context).filter(
4977
+ (event) => event.kind === options.before.kind && event.status === "running" && stepEndpointName(event, options.before.kind) === options.before.name
4978
+ );
4979
+ const afterRunning = semanticEvents(context).filter(
4980
+ (event) => event.kind === options.after.kind && event.status === "running" && stepEndpointName(event, options.after.kind) === options.after.name
4981
+ );
4982
+ const afterStarted = afterEvents.length > 0 || afterRunning.length > 0;
4983
+ const afterEvidenceEvent = afterEvents[0] ?? afterRunning[0];
4984
+ if (beforeRunning.length > 0 && afterStarted && afterEvidenceEvent !== void 0) {
4985
+ const endpointExpected2 = bothTools ? { before: options.before.name, after: options.after.name } : { before: options.before, after: options.after };
4986
+ return [
4987
+ failFinding(
4988
+ ruleId,
4989
+ `${subject} ${beforeLabel} started but never finished before ${afterLabel} ran.`,
4990
+ [
4991
+ ...beforeRunning.map((event) => eventEvidence3(event)),
4992
+ eventEvidence3(afterEvidenceEvent)
4993
+ ],
4994
+ { ...endpointExpected2, mode },
4995
+ {
4996
+ code: bothTools ? "tool.order.interval-unresolved" : "step.order.interval-unresolved",
4997
+ unfinishedBefore: true,
4998
+ beforeStatus: "running",
4999
+ ...beforeEvents.length > 0 ? { finishedBeforeMasked: true } : {},
5000
+ ...afterEvents.length === 0 ? { afterStatus: "running" } : {}
5001
+ }
5002
+ )
5003
+ ];
5004
+ }
5005
+ if (beforeEvents.length === 0 || !afterStarted) {
4914
5006
  if (!requireEndpoints) return [];
4915
5007
  const findings = [];
4916
5008
  if (beforeEvents.length === 0) {
@@ -4934,7 +5026,7 @@ function createStepOrderingRule(options) {
4934
5026
  )
4935
5027
  );
4936
5028
  }
4937
- if (afterEvents.length === 0) {
5029
+ if (!afterStarted) {
4938
5030
  const otherKinds = otherKindsForStepName(
4939
5031
  context,
4940
5032
  options.after.kind,
@@ -4957,9 +5049,15 @@ function createStepOrderingRule(options) {
4957
5049
  }
4958
5050
  return findings;
4959
5051
  }
4960
- const encounter = finishedEvents(context).filter(
4961
- (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
4962
- );
5052
+ const afterForOrder = afterEvents.length > 0 ? afterEvents : afterRunning;
5053
+ const encounter = [
5054
+ ...finishedEvents(context).filter(
5055
+ (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
5056
+ ),
5057
+ ...afterEvents.length === 0 ? afterRunning.filter(
5058
+ (event) => !finishedEvents(context).some((finished) => finished.eventId === event.eventId)
5059
+ ) : []
5060
+ ];
4963
5061
  let beforeIndex;
4964
5062
  let afterIndex;
4965
5063
  for (const [position, event] of encounter.entries()) {
@@ -4990,7 +5088,7 @@ function createStepOrderingRule(options) {
4990
5088
  ];
4991
5089
  }
4992
5090
  const beforeEvent = beforeEvents[0];
4993
- const afterEvent = afterEvents[0];
5091
+ const afterEvent = afterForOrder[0];
4994
5092
  const beforeEnd = eventEndMs(beforeEvent);
4995
5093
  const afterStart = eventStartMs(afterEvent);
4996
5094
  const endpointExpected = bothTools ? { before: options.before.name, after: options.after.name } : { before: options.before, after: options.after };
@@ -5076,7 +5174,7 @@ function createStepOrderingRule(options) {
5076
5174
  latestBefore = { event, end };
5077
5175
  }
5078
5176
  }
5079
- for (const event of afterEvents) {
5177
+ for (const event of afterForOrder) {
5080
5178
  const start = eventStartMs(event);
5081
5179
  if (start === void 0) {
5082
5180
  missingAfterStarts += 1;
@@ -5105,7 +5203,7 @@ function createStepOrderingRule(options) {
5105
5203
  const tie = tiedEnd === tiedStart ? recordedTieOrder(
5106
5204
  context,
5107
5205
  beforeEvents.filter((event) => eventEndMs(event) === tiedEnd),
5108
- afterEvents.filter((event) => eventStartMs(event) === tiedStart)
5206
+ afterForOrder.filter((event) => eventStartMs(event) === tiedStart)
5109
5207
  ) : void 0;
5110
5208
  if (latestBefore.end > earliestAfter.start || tie !== void 0 && tie.inOrder !== true) {
5111
5209
  return [
@@ -5286,10 +5384,13 @@ function createStructureIncompleteRule(options = {}) {
5286
5384
  findings.push(
5287
5385
  failFinding(
5288
5386
  "structure.incomplete",
5289
- "Trace contains incomplete running events.",
5387
+ incompleteRunningMessage("Trace contains incomplete running events", running),
5290
5388
  running.map((event) => eventEvidence3(event, "status")),
5291
5389
  "no running events",
5292
- running.length
5390
+ {
5391
+ count: running.length,
5392
+ unfinished: running.map(describeRunningEvent)
5393
+ }
5293
5394
  )
5294
5395
  );
5295
5396
  }