agent-inspect 6.31.32 → 6.31.33

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.
@@ -5738,6 +5738,11 @@ function compareFindings(eventById) {
5738
5738
  if (STATUS_RANK[a.status] !== STATUS_RANK[b.status]) {
5739
5739
  return STATUS_RANK[a.status] - STATUS_RANK[b.status];
5740
5740
  }
5741
+ if (a.ruleId === "tool.usage") {
5742
+ const aHasEvent = a.evidence[0]?.eventId !== void 0;
5743
+ const bHasEvent = b.evidence[0]?.eventId !== void 0;
5744
+ if (aHasEvent !== bHasEvent) return aHasEvent ? -1 : 1;
5745
+ }
5741
5746
  const byRun = compareStrings(a.evidence[0]?.runId, b.evidence[0]?.runId);
5742
5747
  if (byRun !== 0) return byRun;
5743
5748
  const byTime = eventTimestamp(a, eventById).localeCompare(eventTimestamp(b, eventById));
@@ -5863,6 +5868,37 @@ function failFinding(ruleId, message, evidence, expected, actual, meta2) {
5863
5868
  function toolName(event) {
5864
5869
  return resolveCanonicalToolName(event);
5865
5870
  }
5871
+ function formatToolNameForMessage(name) {
5872
+ const details = [];
5873
+ for (let index = 0; index < name.length; ) {
5874
+ const codePoint = name.codePointAt(index);
5875
+ const width = codePoint > 65535 ? 2 : 1;
5876
+ if (codePoint > 127) {
5877
+ details.push(
5878
+ `U+${codePoint.toString(16).toUpperCase().padStart(4, "0")} at index ${index}`
5879
+ );
5880
+ }
5881
+ index += width;
5882
+ }
5883
+ if (details.length === 0) return name;
5884
+ return `"${name}" (contains ${details.join("; ")})`;
5885
+ }
5886
+ function describeRunningEvent(event) {
5887
+ if (event.kind === "TOOL") {
5888
+ return `tool ${formatToolNameForMessage(resolveCanonicalToolName(event))}`;
5889
+ }
5890
+ if (event.kind === "LLM") {
5891
+ return `llm ${stepEndpointName(event, "LLM")}`;
5892
+ }
5893
+ return `${event.kind} ${event.name}`;
5894
+ }
5895
+ function incompleteRunningMessage(prefix, running) {
5896
+ const labels = running.map(describeRunningEvent);
5897
+ if (labels.length === 1) {
5898
+ return `${prefix}: ${labels[0]} never completed.`;
5899
+ }
5900
+ return `${prefix}: ${labels.join("; ")}.`;
5901
+ }
5866
5902
  function stepEndpointName(event, kind) {
5867
5903
  if (kind === "TOOL") return resolveCanonicalToolName(event);
5868
5904
  for (const prefix of ["llm:", "generation:", "transcription:", "speech:"]) {
@@ -6204,10 +6240,13 @@ function createRunStatusRule(options = {}) {
6204
6240
  findings.push(
6205
6241
  failFinding(
6206
6242
  "run.status",
6207
- "Run contains incomplete running events.",
6243
+ incompleteRunningMessage("Run contains incomplete running events", running),
6208
6244
  running.map((event) => eventEvidence(event)),
6209
6245
  "no running events",
6210
- running.length
6246
+ {
6247
+ count: running.length,
6248
+ unfinished: running.map(describeRunningEvent)
6249
+ }
6211
6250
  )
6212
6251
  );
6213
6252
  }
@@ -6377,6 +6416,34 @@ function createToolUsageRule(options) {
6377
6416
  const names = tools.map(toolName);
6378
6417
  const nameSet = new Set(names);
6379
6418
  const findings = [];
6419
+ const forbidden = new Set(options.forbidden ?? []);
6420
+ const allowed = options.allowed?.length ? new Set(options.allowed) : void 0;
6421
+ for (const event of tools) {
6422
+ const name = toolName(event);
6423
+ const display = formatToolNameForMessage(name);
6424
+ if (forbidden.has(name)) {
6425
+ findings.push(
6426
+ failFinding(
6427
+ "tool.usage",
6428
+ `Forbidden tool ${display} appeared.`,
6429
+ [eventEvidence(event)],
6430
+ "tool absent",
6431
+ name
6432
+ )
6433
+ );
6434
+ }
6435
+ if (allowed && !allowed.has(name)) {
6436
+ findings.push(
6437
+ failFinding(
6438
+ "tool.usage",
6439
+ `Tool ${display} is not in the allowed tool set.`,
6440
+ [eventEvidence(event)],
6441
+ [...allowed].sort(),
6442
+ name
6443
+ )
6444
+ );
6445
+ }
6446
+ }
6380
6447
  for (const required of options.required ?? []) {
6381
6448
  if (!nameSet.has(required)) {
6382
6449
  const otherKinds = [
@@ -6394,7 +6461,7 @@ function createToolUsageRule(options) {
6394
6461
  findings.push(
6395
6462
  failFinding(
6396
6463
  "tool.usage",
6397
- `Required tool ${required} did not appear.${hint}`,
6464
+ `Required tool ${formatToolNameForMessage(required)} did not appear.${hint}`,
6398
6465
  runEvidence(context.selectedRun),
6399
6466
  required,
6400
6467
  names
@@ -6402,21 +6469,6 @@ function createToolUsageRule(options) {
6402
6469
  );
6403
6470
  }
6404
6471
  }
6405
- const forbidden = new Set(options.forbidden ?? []);
6406
- const allowed = options.allowed?.length ? new Set(options.allowed) : void 0;
6407
- for (const event of tools) {
6408
- const name = toolName(event);
6409
- if (forbidden.has(name)) {
6410
- findings.push(
6411
- failFinding("tool.usage", `Forbidden tool ${name} appeared.`, [eventEvidence(event)], "tool absent", name)
6412
- );
6413
- }
6414
- if (allowed && !allowed.has(name)) {
6415
- findings.push(
6416
- failFinding("tool.usage", `Tool ${name} is not in the allowed tool set.`, [eventEvidence(event)], [...allowed].sort(), name)
6417
- );
6418
- }
6419
- }
6420
6472
  if (options.minCount !== void 0 && tools.length < options.minCount) {
6421
6473
  findings.push(
6422
6474
  failFinding("tool.usage", `Tool count ${tools.length} was below minimum ${options.minCount}.`, runEvidence(context.selectedRun), { minCount: options.minCount }, tools.length)
@@ -6450,6 +6502,28 @@ function createStepOrderingRule(options) {
6450
6502
  const afterEvents = finishedEvents(context, options.after.kind).filter(
6451
6503
  (event) => stepEndpointName(event, options.after.kind) === options.after.name
6452
6504
  );
6505
+ const beforeRunning = semanticEvents(context).filter(
6506
+ (event) => event.kind === options.before.kind && event.status === "running" && stepEndpointName(event, options.before.kind) === options.before.name
6507
+ );
6508
+ if (beforeEvents.length === 0 && afterEvents.length > 0 && beforeRunning.length > 0) {
6509
+ const endpointExpected2 = bothTools ? { before: options.before.name, after: options.after.name } : { before: options.before, after: options.after };
6510
+ return [
6511
+ failFinding(
6512
+ ruleId,
6513
+ `${subject} ${beforeLabel} started but never finished before ${afterLabel} ran.`,
6514
+ [
6515
+ ...beforeRunning.map((event) => eventEvidence(event)),
6516
+ eventEvidence(afterEvents[0])
6517
+ ],
6518
+ { ...endpointExpected2, mode },
6519
+ {
6520
+ code: bothTools ? "tool.order.interval-unresolved" : "step.order.interval-unresolved",
6521
+ unfinishedBefore: true,
6522
+ beforeStatus: "running"
6523
+ }
6524
+ )
6525
+ ];
6526
+ }
6453
6527
  if (beforeEvents.length === 0 || afterEvents.length === 0) {
6454
6528
  if (!requireEndpoints) return [];
6455
6529
  const findings = [];
@@ -6826,10 +6900,13 @@ function createStructureIncompleteRule(options = {}) {
6826
6900
  findings.push(
6827
6901
  failFinding(
6828
6902
  "structure.incomplete",
6829
- "Trace contains incomplete running events.",
6903
+ incompleteRunningMessage("Trace contains incomplete running events", running),
6830
6904
  running.map((event) => eventEvidence(event, "status")),
6831
6905
  "no running events",
6832
- running.length
6906
+ {
6907
+ count: running.length,
6908
+ unfinished: running.map(describeRunningEvent)
6909
+ }
6833
6910
  )
6834
6911
  );
6835
6912
  }
@@ -9564,10 +9641,17 @@ function contractToRules(contract) {
9564
9641
  (event) => event.status === "running"
9565
9642
  );
9566
9643
  if (running.length > 0) {
9644
+ const labels = running.map((event) => {
9645
+ if (event.kind === "TOOL") {
9646
+ return `tool ${resolveCanonicalToolName(event)}`;
9647
+ }
9648
+ return `${event.kind} ${event.name}`;
9649
+ });
9650
+ const message = labels.length === 1 ? `Run contains incomplete running events: ${labels[0]} never completed.` : `Run contains incomplete running events: ${labels.join("; ")}.`;
9567
9651
  findings.push(
9568
9652
  contractFailFinding(
9569
9653
  "contract.run.allowedStatuses",
9570
- "Run contains incomplete running events.",
9654
+ message,
9571
9655
  running.map((event) => ({
9572
9656
  runId: event.runId,
9573
9657
  eventId: event.eventId,
@@ -9576,7 +9660,10 @@ function contractToRules(contract) {
9576
9660
  status: event.status
9577
9661
  })),
9578
9662
  "no running events",
9579
- running.length
9663
+ {
9664
+ count: running.length,
9665
+ unfinished: labels
9666
+ }
9580
9667
  )
9581
9668
  );
9582
9669
  }
@@ -17377,7 +17464,7 @@ var init_src = __esm({
17377
17464
  });
17378
17465
 
17379
17466
  // package.json
17380
- var version = "6.31.32";
17467
+ var version = "6.31.33";
17381
17468
 
17382
17469
  // packages/cli/src/list.ts
17383
17470
  init_advanced();