agent-inspect 6.30.0 → 6.31.0

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.
@@ -5700,6 +5700,31 @@ function failFinding(ruleId, message, evidence, expected, actual, meta2) {
5700
5700
  function toolName(event) {
5701
5701
  return resolveCanonicalToolName(event);
5702
5702
  }
5703
+ function stepEndpointName(event, kind) {
5704
+ if (kind === "TOOL") return resolveCanonicalToolName(event);
5705
+ for (const prefix of ["llm:", "generation:", "transcription:", "speech:"]) {
5706
+ if (event.name.startsWith(prefix)) return event.name.slice(prefix.length);
5707
+ }
5708
+ return event.name;
5709
+ }
5710
+ function formatStepEndpoint(endpoint) {
5711
+ return `${endpoint.kind} ${endpoint.name}`;
5712
+ }
5713
+ function otherKindsForStepName(context, expectedKind, name) {
5714
+ return [
5715
+ ...new Set(
5716
+ semanticEvents(context).filter((event) => {
5717
+ const kind = typeof event.kind === "string" ? event.kind.toUpperCase() : "";
5718
+ if (kind === expectedKind) return false;
5719
+ if (kind === "TOOL") return resolveCanonicalToolName(event) === name;
5720
+ if (kind === "LLM") return stepEndpointName(event, "LLM") === name;
5721
+ return event.name === name || event.name === `tool:${name}` || event.name === `llm:${name}` || event.name.endsWith(`:${name}`);
5722
+ }).map(
5723
+ (event) => typeof event.kind === "string" ? event.kind.toUpperCase() : "UNKNOWN"
5724
+ )
5725
+ )
5726
+ ].sort();
5727
+ }
5703
5728
  function semanticEvents(context) {
5704
5729
  return context.logicalEvents ?? context.events;
5705
5730
  }
@@ -5726,14 +5751,6 @@ function finishedEvents(context, kind) {
5726
5751
  function toolInvocationEvents(context) {
5727
5752
  return semanticEvents(context).filter((event) => event.kind === "TOOL");
5728
5753
  }
5729
- function firstIndexByName(events) {
5730
- const index = /* @__PURE__ */ new Map();
5731
- for (const [position, event] of events.entries()) {
5732
- const name = toolName(event);
5733
- if (!index.has(name)) index.set(name, position);
5734
- }
5735
- return index;
5736
- }
5737
5754
  function isRecord9(value) {
5738
5755
  return typeof value === "object" && value !== null && !Array.isArray(value);
5739
5756
  }
@@ -6204,18 +6221,85 @@ function createToolUsageRule(options) {
6204
6221
  }
6205
6222
  };
6206
6223
  }
6207
- function createToolOrderingRule(options) {
6208
- const ruleId = options.id ?? "tool.order";
6224
+ function createStepOrderingRule(options) {
6225
+ const bothTools = options.before.kind === "TOOL" && options.after.kind === "TOOL";
6226
+ const ruleId = options.id ?? (bothTools ? "tool.order" : "step.order");
6209
6227
  const mode = options.mode ?? "first-occurrence";
6228
+ const requireEndpoints = options.requireEndpoints === true;
6229
+ const beforeLabel = bothTools ? options.before.name : formatStepEndpoint(options.before);
6230
+ const afterLabel = bothTools ? options.after.name : formatStepEndpoint(options.after);
6231
+ const subject = bothTools ? "Tool" : "Step";
6210
6232
  return {
6211
6233
  id: ruleId,
6212
- category: "tool",
6234
+ category: bothTools ? "tool" : "structure",
6213
6235
  defaultSeverity: "error",
6214
6236
  evaluate(context) {
6215
- const tools = finishedEvents(context, "TOOL");
6216
- const index = firstIndexByName(tools);
6217
- const beforeIndex = index.get(options.before);
6218
- const afterIndex = index.get(options.after);
6237
+ const beforeEvents = finishedEvents(context, options.before.kind).filter(
6238
+ (event) => stepEndpointName(event, options.before.kind) === options.before.name
6239
+ );
6240
+ const afterEvents = finishedEvents(context, options.after.kind).filter(
6241
+ (event) => stepEndpointName(event, options.after.kind) === options.after.name
6242
+ );
6243
+ if (beforeEvents.length === 0 || afterEvents.length === 0) {
6244
+ if (!requireEndpoints) return [];
6245
+ const findings = [];
6246
+ if (beforeEvents.length === 0) {
6247
+ const otherKinds = otherKindsForStepName(
6248
+ context,
6249
+ options.before.kind,
6250
+ options.before.name
6251
+ );
6252
+ const hint = otherKinds.length > 0 ? ` Required name appears under non-${options.before.kind} kind(s): ${otherKinds.join(", ")}.` : "";
6253
+ findings.push(
6254
+ failFinding(
6255
+ ruleId,
6256
+ `Required ${formatStepEndpoint(options.before)} did not appear.${hint}`,
6257
+ runEvidence(context.selectedRun),
6258
+ options.before,
6259
+ {
6260
+ code: bothTools ? "tool.order.missing-endpoint" : "step.order.missing-endpoint",
6261
+ endpoint: "before",
6262
+ otherKinds
6263
+ }
6264
+ )
6265
+ );
6266
+ }
6267
+ if (afterEvents.length === 0) {
6268
+ const otherKinds = otherKindsForStepName(
6269
+ context,
6270
+ options.after.kind,
6271
+ options.after.name
6272
+ );
6273
+ const hint = otherKinds.length > 0 ? ` Required name appears under non-${options.after.kind} kind(s): ${otherKinds.join(", ")}.` : "";
6274
+ findings.push(
6275
+ failFinding(
6276
+ ruleId,
6277
+ `Required ${formatStepEndpoint(options.after)} did not appear.${hint}`,
6278
+ runEvidence(context.selectedRun),
6279
+ options.after,
6280
+ {
6281
+ code: bothTools ? "tool.order.missing-endpoint" : "step.order.missing-endpoint",
6282
+ endpoint: "after",
6283
+ otherKinds
6284
+ }
6285
+ )
6286
+ );
6287
+ }
6288
+ return findings;
6289
+ }
6290
+ const encounter = finishedEvents(context).filter(
6291
+ (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
6292
+ );
6293
+ let beforeIndex;
6294
+ let afterIndex;
6295
+ for (const [position, event] of encounter.entries()) {
6296
+ if (beforeIndex === void 0 && event.kind === options.before.kind && stepEndpointName(event, options.before.kind) === options.before.name) {
6297
+ beforeIndex = position;
6298
+ }
6299
+ if (afterIndex === void 0 && event.kind === options.after.kind && stepEndpointName(event, options.after.kind) === options.after.name) {
6300
+ afterIndex = position;
6301
+ }
6302
+ }
6219
6303
  if (beforeIndex === void 0 || afterIndex === void 0) {
6220
6304
  return [];
6221
6305
  }
@@ -6223,32 +6307,37 @@ function createToolOrderingRule(options) {
6223
6307
  return [
6224
6308
  failFinding(
6225
6309
  ruleId,
6226
- `Tool ${options.before} must appear before ${options.after}.`,
6227
- [eventEvidence(tools[beforeIndex]), eventEvidence(tools[afterIndex])],
6228
- { before: options.before, after: options.after },
6229
- tools.map(toolName)
6310
+ `${subject} ${beforeLabel} must appear before ${afterLabel}.`,
6311
+ [
6312
+ eventEvidence(encounter[beforeIndex]),
6313
+ eventEvidence(encounter[afterIndex])
6314
+ ],
6315
+ bothTools ? { before: options.before.name, after: options.after.name } : { before: options.before, after: options.after },
6316
+ bothTools ? finishedEvents(context, "TOOL").map(toolName) : encounter.map(
6317
+ (event) => event.kind === "TOOL" || event.kind === "LLM" ? `${event.kind}:${stepEndpointName(event, event.kind)}` : event.name
6318
+ )
6230
6319
  )
6231
6320
  ];
6232
6321
  }
6233
- const beforeEvent = tools[beforeIndex];
6234
- const afterEvent = tools[afterIndex];
6322
+ const beforeEvent = beforeEvents[0];
6323
+ const afterEvent = afterEvents[0];
6235
6324
  const beforeEnd = eventEndMs(beforeEvent);
6236
6325
  const afterStart = eventStartMs(afterEvent);
6326
+ const endpointExpected = bothTools ? { before: options.before.name, after: options.after.name } : { before: options.before, after: options.after };
6237
6327
  if (mode === "happens-before") {
6238
6328
  const expected = {
6239
- before: options.before,
6240
- after: options.after,
6329
+ ...endpointExpected,
6241
6330
  mode,
6242
6331
  relation: "before.end <= after.start"
6243
6332
  };
6244
- if (options.before === options.after) {
6333
+ if (options.before.kind === options.after.kind && options.before.name === options.after.name) {
6245
6334
  return [
6246
6335
  failFinding(
6247
6336
  ruleId,
6248
- `Tool ${options.before} cannot causally happen before itself.`,
6337
+ `${subject} ${beforeLabel} cannot causally happen before itself.`,
6249
6338
  [eventEvidence(beforeEvent)],
6250
6339
  expected,
6251
- { code: "tool.order.same-tool" }
6340
+ { code: bothTools ? "tool.order.same-tool" : "step.order.same-step" }
6252
6341
  )
6253
6342
  ];
6254
6343
  }
@@ -6256,11 +6345,11 @@ function createToolOrderingRule(options) {
6256
6345
  return [
6257
6346
  failFinding(
6258
6347
  ruleId,
6259
- `Tool order ${options.before} before ${options.after} could not establish causal timing.`,
6348
+ `${subject} order ${beforeLabel} before ${afterLabel} could not establish causal timing.`,
6260
6349
  [eventEvidence(beforeEvent), eventEvidence(afterEvent)],
6261
6350
  expected,
6262
6351
  {
6263
- code: "tool.order.interval-unresolved",
6352
+ code: bothTools ? "tool.order.interval-unresolved" : "step.order.interval-unresolved",
6264
6353
  beforeEndResolved: beforeEnd !== void 0,
6265
6354
  afterStartResolved: afterStart !== void 0
6266
6355
  }
@@ -6271,7 +6360,7 @@ function createToolOrderingRule(options) {
6271
6360
  return [
6272
6361
  failFinding(
6273
6362
  ruleId,
6274
- `Tool ${options.before} must finish before ${options.after} starts.`,
6363
+ `${subject} ${beforeLabel} must finish before ${afterLabel} starts.`,
6275
6364
  [eventEvidence(beforeEvent), eventEvidence(afterEvent)],
6276
6365
  expected,
6277
6366
  {
@@ -6284,22 +6373,19 @@ function createToolOrderingRule(options) {
6284
6373
  return [];
6285
6374
  }
6286
6375
  if (mode === "all-occurrences") {
6287
- const beforeEvents = tools.filter((event) => toolName(event) === options.before);
6288
- const afterEvents = tools.filter((event) => toolName(event) === options.after);
6289
6376
  const expected = {
6290
- before: options.before,
6291
- after: options.after,
6377
+ ...endpointExpected,
6292
6378
  mode,
6293
6379
  relation: "max(before.end) <= min(after.start)"
6294
6380
  };
6295
- if (options.before === options.after) {
6381
+ if (options.before.kind === options.after.kind && options.before.name === options.after.name) {
6296
6382
  return [
6297
6383
  failFinding(
6298
6384
  ruleId,
6299
- `Tool ${options.before} cannot causally happen before itself.`,
6385
+ `${subject} ${beforeLabel} cannot causally happen before itself.`,
6300
6386
  [eventEvidence(beforeEvent)],
6301
6387
  expected,
6302
- { code: "tool.order.same-tool" }
6388
+ { code: bothTools ? "tool.order.same-tool" : "step.order.same-step" }
6303
6389
  )
6304
6390
  ];
6305
6391
  }
@@ -6331,11 +6417,11 @@ function createToolOrderingRule(options) {
6331
6417
  return [
6332
6418
  failFinding(
6333
6419
  ruleId,
6334
- `Tool order ${options.before} before ${options.after} could not establish all causal intervals.`,
6420
+ `${subject} order ${beforeLabel} before ${afterLabel} could not establish all causal intervals.`,
6335
6421
  [firstMissingBefore, firstMissingAfter].filter((event) => event !== void 0).map((event) => eventEvidence(event)),
6336
6422
  expected,
6337
6423
  {
6338
- code: "tool.order.interval-unresolved",
6424
+ code: bothTools ? "tool.order.interval-unresolved" : "step.order.interval-unresolved",
6339
6425
  missingBeforeEnds,
6340
6426
  missingAfterStarts
6341
6427
  }
@@ -6346,7 +6432,7 @@ function createToolOrderingRule(options) {
6346
6432
  return [
6347
6433
  failFinding(
6348
6434
  ruleId,
6349
- `Every ${options.before} tool call must finish before any ${options.after} tool call starts.`,
6435
+ bothTools ? `Every ${options.before.name} tool call must finish before any ${options.after.name} tool call starts.` : `Every ${beforeLabel} must finish before any ${afterLabel} starts.`,
6350
6436
  [eventEvidence(latestBefore.event), eventEvidence(earliestAfter.event)],
6351
6437
  expected,
6352
6438
  {
@@ -6364,10 +6450,13 @@ function createToolOrderingRule(options) {
6364
6450
  ruleId,
6365
6451
  severity: "warning",
6366
6452
  status: "warning",
6367
- message: `Tool order ${options.before} before ${options.after} satisfied start/encounter order, but intervals overlap so causal completion before the next tool was not established.`,
6368
- expected: { before: options.before, after: options.after, mode: "first-occurrence" },
6453
+ message: `${subject} order ${beforeLabel} before ${afterLabel} satisfied start/encounter order, but intervals overlap so causal completion before the next ${bothTools ? "tool" : "step"} was not established.`,
6454
+ expected: {
6455
+ ...endpointExpected,
6456
+ mode: "first-occurrence"
6457
+ },
6369
6458
  actual: {
6370
- code: "tool.order.overlap",
6459
+ code: bothTools ? "tool.order.overlap" : "step.order.overlap",
6371
6460
  beforeEndedAt: beforeEvent.endedAt,
6372
6461
  afterStartedAt: afterEvent.startedAt ?? afterEvent.timestamp
6373
6462
  },
@@ -6379,6 +6468,15 @@ function createToolOrderingRule(options) {
6379
6468
  }
6380
6469
  };
6381
6470
  }
6471
+ function createToolOrderingRule(options) {
6472
+ return createStepOrderingRule({
6473
+ before: { kind: "TOOL", name: options.before },
6474
+ after: { kind: "TOOL", name: options.after },
6475
+ ...options.id !== void 0 ? { id: options.id } : {},
6476
+ ...options.mode !== void 0 ? { mode: options.mode } : {},
6477
+ requireEndpoints: false
6478
+ });
6479
+ }
6382
6480
  function createLlmUsageRule(options) {
6383
6481
  return {
6384
6482
  id: "llm.usage",
@@ -8657,6 +8755,17 @@ function cloneBody(body) {
8657
8755
  }
8658
8756
  } : {},
8659
8757
  ...body.llm ? { llm: { ...body.llm } } : {},
8758
+ ...body.steps ? {
8759
+ steps: {
8760
+ ...body.steps.orderRelations ? {
8761
+ orderRelations: body.steps.orderRelations.map((item) => ({
8762
+ ...item,
8763
+ before: { ...item.before },
8764
+ after: { ...item.after }
8765
+ }))
8766
+ } : {}
8767
+ }
8768
+ } : {},
8660
8769
  ...body.observations ? {
8661
8770
  observations: {
8662
8771
  ...body.observations,
@@ -8696,7 +8805,7 @@ function cloneBody(body) {
8696
8805
  };
8697
8806
  }
8698
8807
  function bodyHasRules(body) {
8699
- return body.run !== void 0 || body.tools !== void 0 || body.llm !== void 0 || body.observations !== void 0 || body.controls !== void 0 || body.retry !== void 0;
8808
+ return body.run !== void 0 || body.tools !== void 0 || body.llm !== void 0 || body.steps !== void 0 || body.observations !== void 0 || body.controls !== void 0 || body.retry !== void 0;
8700
8809
  }
8701
8810
  function parseEvidenceEventIds(evidence) {
8702
8811
  if (evidence === void 0 || evidence === null) {
@@ -9037,6 +9146,18 @@ function contractToRules(contract) {
9037
9146
  })
9038
9147
  );
9039
9148
  }
9149
+ const orderRelations = contract.steps?.orderRelations ?? [];
9150
+ for (const [index, relation] of orderRelations.entries()) {
9151
+ rules.push(
9152
+ createStepOrderingRule({
9153
+ before: { kind: relation.before.kind, name: relation.before.name },
9154
+ after: { kind: relation.after.kind, name: relation.after.name },
9155
+ id: `contract.step.orderRelation.${index}`,
9156
+ mode: relation.mode ?? "first-occurrence",
9157
+ requireEndpoints: relation.requireEndpoints !== false
9158
+ })
9159
+ );
9160
+ }
9040
9161
  if (contract.observations) {
9041
9162
  const required = contract.observations.required ?? [];
9042
9163
  if (required.length > 0) {
@@ -16001,7 +16122,7 @@ var init_src = __esm({
16001
16122
  });
16002
16123
 
16003
16124
  // package.json
16004
- var version = "6.30.0";
16125
+ var version = "6.31.0";
16005
16126
 
16006
16127
  // packages/cli/src/list.ts
16007
16128
  init_advanced();
@@ -22925,6 +23046,7 @@ var CONTRACT_KEYS = /* @__PURE__ */ new Set([
22925
23046
  "run",
22926
23047
  "tools",
22927
23048
  "llm",
23049
+ "steps",
22928
23050
  "observations",
22929
23051
  "scope",
22930
23052
  "alternatives",
@@ -22935,6 +23057,7 @@ var CONTRACT_BODY_KEYS = /* @__PURE__ */ new Set([
22935
23057
  "run",
22936
23058
  "tools",
22937
23059
  "llm",
23060
+ "steps",
22938
23061
  "observations",
22939
23062
  "controls",
22940
23063
  "retry"
@@ -23012,6 +23135,15 @@ var CONTRACT_ORDER_RULE_KEYS = /* @__PURE__ */ new Set([
23012
23135
  "occurrenceMode",
23013
23136
  "requireEndpoints"
23014
23137
  ]);
23138
+ var CONTRACT_STEPS_KEYS = /* @__PURE__ */ new Set(["orderRelations"]);
23139
+ var CONTRACT_STEP_ORDER_RELATION_KEYS = /* @__PURE__ */ new Set([
23140
+ "before",
23141
+ "after",
23142
+ "mode",
23143
+ "requireEndpoints"
23144
+ ]);
23145
+ var CONTRACT_STEP_REF_KEYS = /* @__PURE__ */ new Set(["kind", "name"]);
23146
+ var CONTRACT_STEP_KINDS = /* @__PURE__ */ new Set(["TOOL", "LLM"]);
23015
23147
  var CONTRACT_ARGUMENT_KEYS = /* @__PURE__ */ new Set([
23016
23148
  "tool",
23017
23149
  "path",
@@ -23342,6 +23474,7 @@ function contractConfigHasEffect(contract) {
23342
23474
  if (sectionHasEffect(contract.run)) return true;
23343
23475
  if (sectionHasEffect(contract.tools)) return true;
23344
23476
  if (sectionHasEffect(contract.llm)) return true;
23477
+ if (sectionHasEffect(contract.steps)) return true;
23345
23478
  if (sectionHasEffect(contract.observations)) {
23346
23479
  return true;
23347
23480
  }
@@ -23526,6 +23659,66 @@ function parseContractLlmSection(value, pathPrefix = "contract.llm") {
23526
23659
  }
23527
23660
  return out;
23528
23661
  }
23662
+ function parseStepRef(value, pathPrefix) {
23663
+ const record = requireObject(value, pathPrefix);
23664
+ rejectUnknownKeys(record, CONTRACT_STEP_REF_KEYS, pathPrefix);
23665
+ if (typeof record.kind !== "string" || !CONTRACT_STEP_KINDS.has(record.kind)) {
23666
+ throw new CheckConfigError(
23667
+ "AI_CHECK_CONFIG_INVALID_VALUE",
23668
+ `${pathPrefix}.kind must be "TOOL" or "LLM".`
23669
+ );
23670
+ }
23671
+ return {
23672
+ kind: record.kind,
23673
+ name: requireNonEmptyString(record.name, `${pathPrefix}.name`)
23674
+ };
23675
+ }
23676
+ function parseStepOrderRelation(value, pathPrefix) {
23677
+ const record = requireObject(value, pathPrefix);
23678
+ rejectUnknownKeys(record, CONTRACT_STEP_ORDER_RELATION_KEYS, pathPrefix);
23679
+ if (record.before === void 0) {
23680
+ throw new CheckConfigError(
23681
+ "AI_CHECK_CONFIG_INVALID_VALUE",
23682
+ `${pathPrefix}.before is required.`
23683
+ );
23684
+ }
23685
+ if (record.after === void 0) {
23686
+ throw new CheckConfigError(
23687
+ "AI_CHECK_CONFIG_INVALID_VALUE",
23688
+ `${pathPrefix}.after is required.`
23689
+ );
23690
+ }
23691
+ const out = {
23692
+ before: parseStepRef(record.before, `${pathPrefix}.before`),
23693
+ after: parseStepRef(record.after, `${pathPrefix}.after`)
23694
+ };
23695
+ if (record.mode !== void 0) {
23696
+ out.mode = requireOrderMode(record.mode, `${pathPrefix}.mode`);
23697
+ }
23698
+ if (record.requireEndpoints !== void 0) {
23699
+ out.requireEndpoints = requireBoolean(
23700
+ record.requireEndpoints,
23701
+ `${pathPrefix}.requireEndpoints`
23702
+ );
23703
+ }
23704
+ return out;
23705
+ }
23706
+ function parseContractStepsSection(value, pathPrefix = "contract.steps") {
23707
+ const record = requireObject(value, pathPrefix);
23708
+ rejectUnknownKeys(record, CONTRACT_STEPS_KEYS, pathPrefix);
23709
+ const out = {};
23710
+ if (record.orderRelations !== void 0) {
23711
+ const items = requireBoundedArray(
23712
+ record.orderRelations,
23713
+ `${pathPrefix}.orderRelations`,
23714
+ CONTRACT_MAX_ORDER_RULES
23715
+ );
23716
+ out.orderRelations = items.map(
23717
+ (item, index) => parseStepOrderRelation(item, `${pathPrefix}.orderRelations[${index}]`)
23718
+ );
23719
+ }
23720
+ return out;
23721
+ }
23529
23722
  function parseRequireProvenance(value, pathPrefix) {
23530
23723
  const record = requireObject(value, pathPrefix);
23531
23724
  rejectUnknownKeys(record, CONTRACT_PROVENANCE_KEYS, pathPrefix);
@@ -23811,6 +24004,9 @@ function parseContractBodySection(value, pathPrefix) {
23811
24004
  out.tools = parseContractToolsSection(record.tools, `${pathPrefix}.tools`);
23812
24005
  }
23813
24006
  if (record.llm !== void 0) out.llm = parseContractLlmSection(record.llm, `${pathPrefix}.llm`);
24007
+ if (record.steps !== void 0) {
24008
+ out.steps = parseContractStepsSection(record.steps, `${pathPrefix}.steps`);
24009
+ }
23814
24010
  if (record.observations !== void 0) {
23815
24011
  out.observations = parseContractObservationsSection(
23816
24012
  record.observations,