@adcp/sdk 9.1.2 → 9.2.2

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 (53) hide show
  1. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  2. package/dist/lib/core/SingleAgentClient.js +8 -8
  3. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  4. package/dist/lib/index.d.ts +1 -1
  5. package/dist/lib/index.d.ts.map +1 -1
  6. package/dist/lib/index.js +9 -5
  7. package/dist/lib/index.js.map +1 -1
  8. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  9. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  10. package/dist/lib/server/decisioning/runtime/from-platform.js +2 -0
  11. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  12. package/dist/lib/server/test-controller.d.ts +4 -1
  13. package/dist/lib/server/test-controller.d.ts.map +1 -1
  14. package/dist/lib/server/test-controller.js +18 -0
  15. package/dist/lib/server/test-controller.js.map +1 -1
  16. package/dist/lib/testing/comply-controller.d.ts +8 -0
  17. package/dist/lib/testing/comply-controller.d.ts.map +1 -1
  18. package/dist/lib/testing/comply-controller.js +7 -0
  19. package/dist/lib/testing/comply-controller.js.map +1 -1
  20. package/dist/lib/testing/index.d.ts +1 -1
  21. package/dist/lib/testing/index.d.ts.map +1 -1
  22. package/dist/lib/testing/index.js.map +1 -1
  23. package/dist/lib/testing/storyboard/runner.d.ts +8 -5
  24. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  25. package/dist/lib/testing/storyboard/runner.js +106 -17
  26. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  27. package/dist/lib/testing/storyboard/seeding.d.ts +1 -1
  28. package/dist/lib/testing/storyboard/seeding.d.ts.map +1 -1
  29. package/dist/lib/testing/storyboard/seeding.js +20 -0
  30. package/dist/lib/testing/storyboard/seeding.js.map +1 -1
  31. package/dist/lib/testing/storyboard/types.d.ts +24 -10
  32. package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
  33. package/dist/lib/testing/storyboard/types.js +1 -0
  34. package/dist/lib/testing/storyboard/types.js.map +1 -1
  35. package/dist/lib/v2/projection/augment-response.d.ts +67 -1
  36. package/dist/lib/v2/projection/augment-response.d.ts.map +1 -1
  37. package/dist/lib/v2/projection/augment-response.js +151 -1
  38. package/dist/lib/v2/projection/augment-response.js.map +1 -1
  39. package/dist/lib/v2/projection/index.d.ts +14 -4
  40. package/dist/lib/v2/projection/index.d.ts.map +1 -1
  41. package/dist/lib/v2/projection/index.js +16 -2
  42. package/dist/lib/v2/projection/index.js.map +1 -1
  43. package/dist/lib/v2/projection/types.d.ts +36 -0
  44. package/dist/lib/v2/projection/types.d.ts.map +1 -1
  45. package/dist/lib/v2/projection/v1-to-v2.d.ts +104 -1
  46. package/dist/lib/v2/projection/v1-to-v2.d.ts.map +1 -1
  47. package/dist/lib/v2/projection/v1-to-v2.js +107 -0
  48. package/dist/lib/v2/projection/v1-to-v2.js.map +1 -1
  49. package/dist/lib/validation/schema-loader.js +57 -0
  50. package/dist/lib/validation/schema-loader.js.map +1 -1
  51. package/dist/lib/version.d.ts +3 -3
  52. package/dist/lib/version.js +3 -3
  53. package/package.json +1 -1
@@ -169,10 +169,44 @@ function resolveCapabilityPath(raw, dottedPath) {
169
169
  for (const key of keys) {
170
170
  if (current === null || typeof current !== 'object')
171
171
  return undefined;
172
+ if (!Object.prototype.hasOwnProperty.call(current, key))
173
+ return undefined;
172
174
  current = current[key];
173
175
  }
174
176
  return current;
175
177
  }
178
+ const GET_ADCP_CAPABILITIES_RESPONSE_SCHEMA_REF = 'protocol/get-adcp-capabilities-response.json';
179
+ function resolveCapabilityPathForGate(raw, predicate, adcpVersion) {
180
+ const actual = resolveCapabilityPath(raw, predicate.path);
181
+ if (actual !== undefined)
182
+ return actual;
183
+ // `present:` is an absence-detection matcher — an absent field IS the
184
+ // load-bearing signal. Materializing a schema default would make a defaulted
185
+ // field never read as absent, silently flipping the gate (e.g. a signals
186
+ // seller that omits `signals.discovery_modes`, default `["brief"]`, would run
187
+ // a `present: true`-gated scenario that should skip). Defaults are resolved
188
+ // only for the value matchers (`equals` / `contains`), where the default's
189
+ // VALUE is what the gate tests.
190
+ if ('present' in predicate)
191
+ return undefined;
192
+ if (!schemaDefaultShouldApply(raw, predicate.path))
193
+ return undefined;
194
+ return (0, schema_loader_1.getSchemaDefaultByPath)(GET_ADCP_CAPABILITIES_RESPONSE_SCHEMA_REF, predicate.path, adcpVersion);
195
+ }
196
+ function schemaDefaultShouldApply(raw, dottedPath) {
197
+ const keys = dottedPath.split('.');
198
+ if (keys.length <= 1)
199
+ return raw !== null && typeof raw === 'object';
200
+ let current = raw;
201
+ for (const key of keys.slice(0, -1)) {
202
+ if (current === null || typeof current !== 'object')
203
+ return false;
204
+ if (!Object.prototype.hasOwnProperty.call(current, key))
205
+ return false;
206
+ current = current[key];
207
+ }
208
+ return current !== null && typeof current === 'object';
209
+ }
176
210
  /**
177
211
  * Evaluate a `requires_capability` predicate against the value already
178
212
  * resolved from the agent's raw capabilities. Returns `null` when the
@@ -182,8 +216,8 @@ function resolveCapabilityPath(raw, dottedPath) {
182
216
  * Three matcher forms — see `Storyboard.requires_capability` for full semantics:
183
217
  *
184
218
  * - `equals: V` — scalar equality. `actual` must be declared and must equal
185
- * `V`. Absent fields (`undefined`) skip because the agent has not opted
186
- * into the capability or capability variant this storyboard tests.
219
+ * `V`. Absent fields (`undefined`) skip unless the capabilities schema
220
+ * declares a default that the gate materialized before predicate evaluation.
187
221
  *
188
222
  * - `present: B` — presence is the load-bearing signal. `present: true`
189
223
  * skips when the field is absent (treats `undefined` and `null` as absent).
@@ -193,12 +227,15 @@ function resolveCapabilityPath(raw, dottedPath) {
193
227
  * non-conformant for object-typed capabilities (`"type": "object"` rejects
194
228
  * null in JSON Schema), but is coalesced with absent here in the spirit of
195
229
  * Postel — agents that misdeclare a not-supported capability as `null`
196
- * get the same not_applicable skip as agents that omit the field.
230
+ * get the same not_applicable skip as agents that omit the field. Schema
231
+ * defaults are deliberately NOT materialized for this matcher: presence is
232
+ * the signal, so a default would defeat the gate (see
233
+ * `resolveCapabilityPathForGate`).
197
234
  *
198
235
  * - `contains: V` — array-membership. `actual` must be an array that
199
236
  * includes `V` (strict equality, no coercion). Empty arrays, non-arrays,
200
- * and absent fields all skip absence means the agent hasn't opted into
201
- * the array variant this storyboard tests.
237
+ * and absent fields all skip unless the capabilities schema declares a
238
+ * default that the gate materialized before predicate evaluation.
202
239
  *
203
240
  * Exported for direct testing so the predicate semantics are pinned without
204
241
  * needing a full runStoryboard() roundtrip.
@@ -237,10 +274,10 @@ function evaluateCapabilityPredicate(predicate, actual) {
237
274
  }
238
275
  return null;
239
276
  }
240
- function evaluateRequiresCapabilityGate(predicate, profile, agentTools) {
277
+ function evaluateRequiresCapabilityGate(predicate, profile, agentTools, adcpVersion) {
241
278
  const rawCaps = profile?.raw_capabilities;
242
279
  if (rawCaps !== undefined) {
243
- const actual = resolveCapabilityPath(rawCaps, predicate.path);
280
+ const actual = resolveCapabilityPathForGate(rawCaps, predicate, adcpVersion);
244
281
  return evaluateCapabilityPredicate(predicate, actual);
245
282
  }
246
283
  const tools = agentTools ?? profile?.tools;
@@ -249,12 +286,12 @@ function evaluateRequiresCapabilityGate(predicate, profile, agentTools) {
249
286
  }
250
287
  return null;
251
288
  }
252
- function collectPhaseCapabilitySkipDetails(storyboard, profile, agentTools) {
289
+ function collectPhaseCapabilitySkipDetails(storyboard, profile, agentTools, adcpVersion) {
253
290
  const skipDetails = new Map();
254
291
  for (const phase of storyboard.phases) {
255
292
  if (!phase.requires_capability)
256
293
  continue;
257
- const unmetDetail = evaluateRequiresCapabilityGate(phase.requires_capability, profile, agentTools);
294
+ const unmetDetail = evaluateRequiresCapabilityGate(phase.requires_capability, profile, agentTools, adcpVersion);
258
295
  if (unmetDetail !== null) {
259
296
  skipDetails.set(phase.id, unmetDetail);
260
297
  }
@@ -825,6 +862,17 @@ async function runStoryboardBody(agentUrlOrUrls, storyboard, options) {
825
862
  }
826
863
  return runMultiPass(agentUrls, storyboard, options);
827
864
  }
865
+ const allRequires = resolveStoryboardRequires(storyboard, options);
866
+ if (allRequires.length) {
867
+ const unmet = checkRequires(allRequires, storyboard, options, options._profile);
868
+ if (unmet) {
869
+ const resultAgentUrls = options.agents ? Object.values(options.agents).map(e => e.url) : agentUrls;
870
+ return {
871
+ ...buildRequirementUnmetResult(resultAgentUrls, storyboard, unmet.requirement, unmet.detail),
872
+ notices: collectCapabilityNotices(storyboard, options._profile?.raw_capabilities),
873
+ };
874
+ }
875
+ }
828
876
  if (options.agents) {
829
877
  // Project the agents map's URLs into the legacy `agentUrls` array so
830
878
  // downstream signatures (per-step `agent_url:` records, etc.) keep
@@ -1008,6 +1056,7 @@ const REQUIREMENT_TO_SKIP_REASON = {
1008
1056
  real_wire: 'requirement_unmet',
1009
1057
  webhook_receiver: 'requirement_unmet',
1010
1058
  request_signer: 'not_applicable',
1059
+ multi_agent: 'requirement_unmet',
1011
1060
  };
1012
1061
  function isKnownRequirement(requirement) {
1013
1062
  return types_1.KNOWN_REQUIREMENTS.has(requirement);
@@ -1167,8 +1216,14 @@ function normalizeAgentToolNames(tools) {
1167
1216
  * threaded through), the gate is a no-op — the caller accepted
1168
1217
  * responsibility for capability compatibility by reusing an external
1169
1218
  * client. Spec: adcp-client#1702.
1219
+ * - `multi_agent` — `options.agents` is set and the storyboard's
1220
+ * declared route keys (`default_agent` and step-level `agent:` overrides)
1221
+ * resolve to at least two distinct entries in that map. Raw
1222
+ * `options.agents` cardinality is not enough; the requirement describes
1223
+ * the topology this storyboard actually routes through.
1224
+ * Spec: adcp-client#2281.
1170
1225
  */
1171
- function checkRequires(requires, options, profile) {
1226
+ function checkRequires(requires, storyboard, options, profile) {
1172
1227
  for (const requirement of requires) {
1173
1228
  if (!isKnownRequirement(requirement)) {
1174
1229
  return {
@@ -1243,10 +1298,46 @@ function checkRequires(requires, options, profile) {
1243
1298
  'register the test keypair before the 4.0 cut to avoid a hard compliance failure then.',
1244
1299
  };
1245
1300
  }
1301
+ case 'multi_agent': {
1302
+ const routeKeys = collectMultiAgentRequirementRouteKeys(storyboard, options);
1303
+ if (routeKeys.length >= 2)
1304
+ break;
1305
+ const availableKeys = options.agents ? Object.keys(options.agents) : [];
1306
+ const routed = routeKeys.length ? routeKeys.join(', ') : '(none)';
1307
+ const available = availableKeys.length ? availableKeys.join(', ') : '(none)';
1308
+ return {
1309
+ requirement,
1310
+ detail: "Storyboard requires 'multi_agent'; configure `agents` and route this storyboard " +
1311
+ 'to at least two distinct agent keys via `default_agent` and/or step-level `agent:` overrides. ' +
1312
+ `Resolved route keys: [${routed}]. Available agents: [${available}].`,
1313
+ };
1314
+ }
1246
1315
  }
1247
1316
  }
1248
1317
  return null;
1249
1318
  }
1319
+ function collectMultiAgentRequirementRouteKeys(storyboard, options) {
1320
+ const agents = options.agents;
1321
+ if (!agents)
1322
+ return [];
1323
+ const routeKeys = new Set();
1324
+ if (options.default_agent !== undefined && options.default_agent in agents) {
1325
+ routeKeys.add(options.default_agent);
1326
+ }
1327
+ for (const phase of storyboard.phases ?? []) {
1328
+ for (const step of phase.steps ?? []) {
1329
+ if (step.agent !== undefined && step.agent in agents) {
1330
+ routeKeys.add(step.agent);
1331
+ }
1332
+ }
1333
+ }
1334
+ return [...routeKeys];
1335
+ }
1336
+ function resolveStoryboardRequires(storyboard, options) {
1337
+ const declared = storyboard.requires ?? [];
1338
+ const implicit = detectImplicitRequires(storyboard, options);
1339
+ return [...declared, ...implicit.filter(r => !declared.includes(r))];
1340
+ }
1250
1341
  /**
1251
1342
  * Webhook-token regex used to autodetect the implicit `webhook_receiver`
1252
1343
  * requirement. Matches `{{runner.webhook_url:<step_id>}}` and the bare
@@ -1739,11 +1830,9 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1739
1830
  // standalone runner path options._profile may be undefined; notices will be
1740
1831
  // collected again from the fully-fetched profile at result-build time.
1741
1832
  const preflightNotices = collectCapabilityNotices(storyboard, options._profile?.raw_capabilities);
1742
- const declared = storyboard.requires ?? [];
1743
- const implicit = detectImplicitRequires(storyboard, options);
1744
- const allRequires = [...declared, ...implicit.filter(r => !declared.includes(r))];
1833
+ const allRequires = resolveStoryboardRequires(storyboard, options);
1745
1834
  if (allRequires.length) {
1746
- const unmet = checkRequires(allRequires, options, profile);
1835
+ const unmet = checkRequires(allRequires, storyboard, options, profile);
1747
1836
  if (unmet) {
1748
1837
  if (!callerOwnsClients)
1749
1838
  await (0, protocols_1.closeConnections)(options.protocol);
@@ -1772,7 +1861,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1772
1861
  // tests (e.g. `adcp.idempotency.supported: false`), skip the whole storyboard
1773
1862
  // rather than producing a cascade of misleading per-phase failures.
1774
1863
  if (storyboard.requires_capability) {
1775
- const unmetDetail = evaluateRequiresCapabilityGate(storyboard.requires_capability, profile, options.agentTools);
1864
+ const unmetDetail = evaluateRequiresCapabilityGate(storyboard.requires_capability, profile, options.agentTools, options.adcpVersion);
1776
1865
  if (unmetDetail !== null) {
1777
1866
  if (!callerOwnsClients)
1778
1867
  await (0, protocols_1.closeConnections)(options.protocol);
@@ -1913,7 +2002,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1913
2002
  // an implementor reading the report can't tell "nothing tested" from
1914
2003
  // "everything passed".
1915
2004
  const hasExecutableSteps = storyboard.phases.some(p => p.steps.length > 0);
1916
- const phaseCapabilitySkipDetails = collectPhaseCapabilitySkipDetails(storyboard, profile, options.agentTools);
2005
+ const phaseCapabilitySkipDetails = collectPhaseCapabilitySkipDetails(storyboard, profile, options.agentTools, options.adcpVersion);
1917
2006
  const skipControllerSeedingForPhaseGates = allExecutablePhasesCapabilitySkipped(storyboard, phaseCapabilitySkipDetails);
1918
2007
  if (!hasExecutableSteps) {
1919
2008
  const isScenarioComposed = (storyboard.requires_scenarios?.length ?? 0) > 0;
@@ -2854,7 +2943,7 @@ async function runMultiPass(agentUrls, storyboard, options) {
2854
2943
  ...(options.agentTools ? {} : { agentTools: normalizeAgentToolNames(preSeedProfile.tools) }),
2855
2944
  };
2856
2945
  }
2857
- const phaseCapabilitySkipDetails = collectPhaseCapabilitySkipDetails(storyboard, preSeedProfile, options.agentTools);
2946
+ const phaseCapabilitySkipDetails = collectPhaseCapabilitySkipDetails(storyboard, preSeedProfile, options.agentTools, options.adcpVersion);
2858
2947
  const preSeededResult = allExecutablePhasesCapabilitySkipped(storyboard, phaseCapabilitySkipDetails)
2859
2948
  ? null
2860
2949
  : await (0, seeding_1.runControllerSeeding)(preSeedClients[0], storyboard, options, preSeedContext);