@adcp/sdk 14.0.0-beta.11 → 14.0.0-beta.13

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 (235) hide show
  1. package/bin/adcp-storyboard-sandbox.js +16 -0
  2. package/bin/adcp.js +28 -30
  3. package/dist/lib/index.d.mts +3 -3
  4. package/dist/lib/index.d.ts +3 -3
  5. package/dist/lib/index.d.ts.map +1 -1
  6. package/dist/lib/index.js +2 -0
  7. package/dist/lib/index.js.map +1 -1
  8. package/dist/lib/index.mjs +3 -1
  9. package/dist/lib/index.mjs.map +1 -1
  10. package/dist/lib/schemas/index.d.mts +385 -1
  11. package/dist/lib/schemas/index.d.ts +385 -1
  12. package/dist/lib/schemas/index.d.ts.map +1 -1
  13. package/dist/lib/schemas/index.js +13 -0
  14. package/dist/lib/schemas/index.js.map +1 -1
  15. package/dist/lib/schemas/index.mjs +11 -0
  16. package/dist/lib/schemas/index.mjs.map +1 -1
  17. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  18. package/dist/lib/server/create-adcp-server.d.mts +2 -2
  19. package/dist/lib/server/create-adcp-server.d.ts +2 -2
  20. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  21. package/dist/lib/server/create-adcp-server.js +6 -1
  22. package/dist/lib/server/create-adcp-server.js.map +1 -1
  23. package/dist/lib/server/create-adcp-server.mjs +6 -1
  24. package/dist/lib/server/create-adcp-server.mjs.map +1 -1
  25. package/dist/lib/server/decisioning/index.d.mts +3 -3
  26. package/dist/lib/server/decisioning/index.d.ts +3 -3
  27. package/dist/lib/server/decisioning/index.d.ts.map +1 -1
  28. package/dist/lib/server/decisioning/index.js.map +1 -1
  29. package/dist/lib/server/decisioning/index.mjs.map +1 -1
  30. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +24 -17
  31. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +24 -17
  32. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  33. package/dist/lib/server/decisioning/runtime/from-platform.js +71 -42
  34. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  35. package/dist/lib/server/decisioning/runtime/from-platform.mjs +75 -43
  36. package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
  37. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.mts +15 -21
  38. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +15 -21
  39. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts.map +1 -1
  40. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +100 -30
  41. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js.map +1 -1
  42. package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +100 -30
  43. package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs.map +1 -1
  44. package/dist/lib/server/decisioning/runtime/task-registry.d.mts +30 -16
  45. package/dist/lib/server/decisioning/runtime/task-registry.d.ts +30 -16
  46. package/dist/lib/server/decisioning/runtime/task-registry.d.ts.map +1 -1
  47. package/dist/lib/server/decisioning/runtime/task-registry.js +40 -20
  48. package/dist/lib/server/decisioning/runtime/task-registry.js.map +1 -1
  49. package/dist/lib/server/decisioning/runtime/task-registry.mjs +38 -19
  50. package/dist/lib/server/decisioning/runtime/task-registry.mjs.map +1 -1
  51. package/dist/lib/server/decisioning/runtime/to-context.d.mts +2 -2
  52. package/dist/lib/server/decisioning/runtime/to-context.d.ts +2 -2
  53. package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -1
  54. package/dist/lib/server/decisioning/runtime/to-context.js +2 -2
  55. package/dist/lib/server/decisioning/runtime/to-context.js.map +1 -1
  56. package/dist/lib/server/decisioning/runtime/to-context.mjs +2 -2
  57. package/dist/lib/server/decisioning/runtime/to-context.mjs.map +1 -1
  58. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.mts +3 -2
  59. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +3 -2
  60. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -1
  61. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -1
  62. package/dist/lib/server/decisioning/specialisms/creative.d.mts +10 -10
  63. package/dist/lib/server/decisioning/specialisms/creative.d.ts +10 -10
  64. package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -1
  65. package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -1
  66. package/dist/lib/server/index.d.mts +1 -1
  67. package/dist/lib/server/index.d.ts +1 -1
  68. package/dist/lib/server/index.d.ts.map +1 -1
  69. package/dist/lib/server/index.js.map +1 -1
  70. package/dist/lib/server/index.mjs.map +1 -1
  71. package/dist/lib/signing/agent-context.d.mts +1 -0
  72. package/dist/lib/signing/agent-context.d.ts +1 -0
  73. package/dist/lib/signing/agent-context.d.ts.map +1 -1
  74. package/dist/lib/signing/agent-context.js +37 -2
  75. package/dist/lib/signing/agent-context.js.map +1 -1
  76. package/dist/lib/signing/agent-context.mjs +38 -3
  77. package/dist/lib/signing/agent-context.mjs.map +1 -1
  78. package/dist/lib/signing/agent-fetch.d.mts +1 -2
  79. package/dist/lib/signing/agent-fetch.d.ts +1 -2
  80. package/dist/lib/signing/agent-fetch.d.ts.map +1 -1
  81. package/dist/lib/signing/agent-fetch.js +2 -0
  82. package/dist/lib/signing/agent-fetch.js.map +1 -1
  83. package/dist/lib/signing/agent-fetch.mjs +2 -0
  84. package/dist/lib/signing/agent-fetch.mjs.map +1 -1
  85. package/dist/lib/signing/agent-resolver/etld.js.map +1 -1
  86. package/dist/lib/signing/agent-resolver/etld.mjs.map +1 -1
  87. package/dist/lib/testing/client.d.mts +6 -0
  88. package/dist/lib/testing/client.d.ts +6 -0
  89. package/dist/lib/testing/client.d.ts.map +1 -1
  90. package/dist/lib/testing/client.js +76 -4
  91. package/dist/lib/testing/client.js.map +1 -1
  92. package/dist/lib/testing/client.mjs +75 -4
  93. package/dist/lib/testing/client.mjs.map +1 -1
  94. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  95. package/dist/lib/testing/compliance/comply.js +6 -0
  96. package/dist/lib/testing/compliance/comply.js.map +1 -1
  97. package/dist/lib/testing/compliance/comply.mjs +7 -1
  98. package/dist/lib/testing/compliance/comply.mjs.map +1 -1
  99. package/dist/lib/testing/storyboard/default-invariants.d.ts.map +1 -1
  100. package/dist/lib/testing/storyboard/default-invariants.js +11 -2
  101. package/dist/lib/testing/storyboard/default-invariants.js.map +1 -1
  102. package/dist/lib/testing/storyboard/default-invariants.mjs +11 -2
  103. package/dist/lib/testing/storyboard/default-invariants.mjs.map +1 -1
  104. package/dist/lib/testing/storyboard/index.d.mts +1 -1
  105. package/dist/lib/testing/storyboard/index.d.ts +1 -1
  106. package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
  107. package/dist/lib/testing/storyboard/index.js.map +1 -1
  108. package/dist/lib/testing/storyboard/index.mjs.map +1 -1
  109. package/dist/lib/testing/storyboard/loader.d.ts.map +1 -1
  110. package/dist/lib/testing/storyboard/loader.js +14 -0
  111. package/dist/lib/testing/storyboard/loader.js.map +1 -1
  112. package/dist/lib/testing/storyboard/loader.mjs +14 -0
  113. package/dist/lib/testing/storyboard/loader.mjs.map +1 -1
  114. package/dist/lib/testing/storyboard/phase-condition.d.mts +41 -0
  115. package/dist/lib/testing/storyboard/phase-condition.d.ts +42 -0
  116. package/dist/lib/testing/storyboard/phase-condition.d.ts.map +1 -0
  117. package/dist/lib/testing/storyboard/phase-condition.js +215 -0
  118. package/dist/lib/testing/storyboard/phase-condition.js.map +1 -0
  119. package/dist/lib/testing/storyboard/phase-condition.mjs +189 -0
  120. package/dist/lib/testing/storyboard/phase-condition.mjs.map +1 -0
  121. package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -1
  122. package/dist/lib/testing/storyboard/request-builder.js +15 -2
  123. package/dist/lib/testing/storyboard/request-builder.js.map +1 -1
  124. package/dist/lib/testing/storyboard/request-builder.mjs +15 -2
  125. package/dist/lib/testing/storyboard/request-builder.mjs.map +1 -1
  126. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.d.mts +15 -0
  127. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.d.ts +16 -0
  128. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.d.ts.map +1 -0
  129. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.js +106 -0
  130. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.js.map +1 -0
  131. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.mjs +82 -0
  132. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.mjs.map +1 -0
  133. package/dist/lib/testing/storyboard/request-signing/test-kit.d.mts +15 -0
  134. package/dist/lib/testing/storyboard/request-signing/test-kit.d.ts +15 -0
  135. package/dist/lib/testing/storyboard/request-signing/test-kit.d.ts.map +1 -1
  136. package/dist/lib/testing/storyboard/request-signing/test-kit.js +58 -0
  137. package/dist/lib/testing/storyboard/request-signing/test-kit.js.map +1 -1
  138. package/dist/lib/testing/storyboard/request-signing/test-kit.mjs +58 -0
  139. package/dist/lib/testing/storyboard/request-signing/test-kit.mjs.map +1 -1
  140. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +2 -0
  141. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +2 -0
  142. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts.map +1 -1
  143. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +7 -1
  144. package/dist/lib/testing/storyboard/request-signing/vector-loader.js.map +1 -1
  145. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +6 -1
  146. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs.map +1 -1
  147. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  148. package/dist/lib/testing/storyboard/runner.js +67 -24
  149. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  150. package/dist/lib/testing/storyboard/runner.mjs +67 -24
  151. package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
  152. package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
  153. package/dist/lib/testing/storyboard/task-map.js +6 -2
  154. package/dist/lib/testing/storyboard/task-map.js.map +1 -1
  155. package/dist/lib/testing/storyboard/task-map.mjs +6 -2
  156. package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
  157. package/dist/lib/testing/storyboard/types.d.mts +5 -4
  158. package/dist/lib/testing/storyboard/types.d.ts +5 -4
  159. package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
  160. package/dist/lib/testing/storyboard/types.js.map +1 -1
  161. package/dist/lib/testing/storyboard/types.mjs.map +1 -1
  162. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  163. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  164. package/dist/lib/testing/storyboard/webhook-assertions.d.ts.map +1 -1
  165. package/dist/lib/testing/storyboard/webhook-assertions.js +60 -4
  166. package/dist/lib/testing/storyboard/webhook-assertions.js.map +1 -1
  167. package/dist/lib/testing/storyboard/webhook-assertions.mjs +60 -4
  168. package/dist/lib/testing/storyboard/webhook-assertions.mjs.map +1 -1
  169. package/dist/lib/testing/storyboard/webhook-receiver.d.mts +15 -0
  170. package/dist/lib/testing/storyboard/webhook-receiver.d.ts +15 -0
  171. package/dist/lib/testing/storyboard/webhook-receiver.d.ts.map +1 -1
  172. package/dist/lib/testing/storyboard/webhook-receiver.js +57 -6
  173. package/dist/lib/testing/storyboard/webhook-receiver.js.map +1 -1
  174. package/dist/lib/testing/storyboard/webhook-receiver.mjs +57 -6
  175. package/dist/lib/testing/storyboard/webhook-receiver.mjs.map +1 -1
  176. package/dist/lib/testing/types.d.mts +12 -0
  177. package/dist/lib/testing/types.d.ts +12 -0
  178. package/dist/lib/testing/types.d.ts.map +1 -1
  179. package/dist/lib/testing/types.js.map +1 -1
  180. package/dist/lib/types/comply-test-controller.d.ts +1 -14
  181. package/dist/lib/types/core.generated.d.mts +6 -3
  182. package/dist/lib/types/core.generated.d.ts +6 -3
  183. package/dist/lib/types/core.generated.d.ts.map +1 -1
  184. package/dist/lib/types/core.generated.js.map +1 -1
  185. package/dist/lib/types/get-products.d.ts +1 -14
  186. package/dist/lib/types/index.d.mts +1 -1
  187. package/dist/lib/types/index.d.ts +1 -1
  188. package/dist/lib/types/index.d.ts.map +1 -1
  189. package/dist/lib/types/index.js.map +1 -1
  190. package/dist/lib/types/index.mjs.map +1 -1
  191. package/dist/lib/types/list-transformers.d.ts +9 -5
  192. package/dist/lib/types/schemas.generated.d.ts +23 -352
  193. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  194. package/dist/lib/types/schemas.generated.js +7 -4
  195. package/dist/lib/types/schemas.generated.js.map +1 -1
  196. package/dist/lib/types/schemas.generated.mjs +6 -4
  197. package/dist/lib/types/schemas.generated.mjs.map +1 -1
  198. package/dist/lib/types/server-payload-aliases.d.mts +2 -1
  199. package/dist/lib/types/server-payload-aliases.d.ts +2 -1
  200. package/dist/lib/types/server-payload-aliases.d.ts.map +1 -1
  201. package/dist/lib/types/server-payload-aliases.js.map +1 -1
  202. package/dist/lib/types/tools.generated.d.mts +6 -3
  203. package/dist/lib/types/tools.generated.d.ts +6 -3
  204. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  205. package/dist/lib/types/tools.generated.js.map +1 -1
  206. package/dist/lib/utils/build-creative-return-builders.d.mts +5 -1
  207. package/dist/lib/utils/build-creative-return-builders.d.ts +5 -1
  208. package/dist/lib/utils/build-creative-return-builders.d.ts.map +1 -1
  209. package/dist/lib/utils/build-creative-return-builders.js +9 -3
  210. package/dist/lib/utils/build-creative-return-builders.js.map +1 -1
  211. package/dist/lib/utils/build-creative-return-builders.mjs +7 -2
  212. package/dist/lib/utils/build-creative-return-builders.mjs.map +1 -1
  213. package/dist/lib/utils/response-unwrapper.js +1 -1
  214. package/dist/lib/utils/response-unwrapper.js.map +1 -1
  215. package/dist/lib/utils/response-unwrapper.mjs +1 -1
  216. package/dist/lib/utils/response-unwrapper.mjs.map +1 -1
  217. package/dist/lib/validation/schema-loader.d.ts.map +1 -1
  218. package/dist/lib/validation/schema-loader.js +16 -7
  219. package/dist/lib/validation/schema-loader.js.map +1 -1
  220. package/dist/lib/validation/schema-loader.mjs +16 -7
  221. package/dist/lib/validation/schema-loader.mjs.map +1 -1
  222. package/dist/lib/version.d.mts +3 -3
  223. package/dist/lib/version.d.ts +3 -3
  224. package/dist/lib/version.js +3 -3
  225. package/dist/lib/version.js.map +1 -1
  226. package/dist/lib/version.mjs +3 -3
  227. package/dist/lib/version.mjs.map +1 -1
  228. package/docs/llms.txt +2 -2
  229. package/docs/migration-5.x-to-6.x.md +3 -2
  230. package/docs/migration-task-registry-scoping.md +61 -0
  231. package/examples/hello_seller_adapter_guaranteed.ts +1 -1
  232. package/package.json +5 -5
  233. package/skills/build-decisioning-creative-template/SKILL.md +2 -2
  234. package/skills/build-decisioning-platform/SKILL.md +4 -2
  235. package/skills/build-decisioning-platform/advanced/REFERENCE.md +7 -6
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/testing/client.ts"],"sourcesContent":["/**\n * Test client utilities for AdCP Agent E2E Testing\n */\n\nimport { ADCPMultiAgentClient } from '../core/ADCPMultiAgentClient';\nimport { getBestUnionErrors, type SchemaViolation } from '../utils/union-errors';\nimport { getFormatAssets, usesDeprecatedAssetsField } from '../utils/format-assets';\nimport { brandManifestToBrandReference } from '../types/compat';\nimport type { Product } from '../types/core.generated';\nimport type {\n GetProductsResponse,\n ListCreativeFormatsResponse,\n Format,\n GetSignalsResponse,\n AccountReference,\n BrandReference,\n} from '../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult, Logger } from './types';\nimport { prepareResponseForSchemaValidation, TOOL_RESPONSE_SCHEMAS } from '../utils/response-schemas';\nimport { injectLegacyEnvelopeStatus } from '../utils/envelope-status-compat';\nimport { parseCapabilitiesResponse } from '../utils/capabilities';\nimport { classifyProbeUrl } from '../utils/probe-policy';\nimport { SsrfRefusedError } from '../net/ssrf-fetch';\nimport { ADCP_VERSION } from '../version';\nimport type { VersionEnvelopeMode } from '../protocols';\nimport { validateIncomingResponse } from '../validation/client-hooks';\nimport { extractVersionUnsupportedDetails } from '../utils/error-extraction';\n\nconst TEST_CLIENT_VERSION_OPTIONS = Symbol('adcp.testClientVersionOptions');\n\ninterface TestClientVersionOptions {\n adcpVersion: string;\n wireAdcpVersion?: string;\n versionEnvelope: VersionEnvelopeMode;\n strictResponseSchemaValidation: boolean;\n authMode?: string;\n fetchFn?: typeof fetch;\n maxResponseBytes?: number;\n requestTimeoutMs?: number;\n}\n\n/**\n * Extract a principal identifier from TestOptions auth.\n * For bearer auth this is the token; for basic auth this is the username;\n * for oauth this is the access_token.\n */\nexport function resolveAuthPrincipal(options: TestOptions): string | undefined {\n if (!options.auth) return undefined;\n switch (options.auth.type) {\n case 'basic':\n return options.auth.username;\n case 'oauth':\n return options.auth.tokens.access_token;\n case 'bearer':\n return options.auth.token;\n }\n}\n\nconst DEFAULT_BRAND_REF: BrandReference = { domain: 'test.example' };\n\n/**\n * Resolve the brand reference to use for a test call.\n * Prefers the new brand field, falls back to converting a legacy brand_manifest.\n *\n * The runner enforces a storyboard-run-scoped brand invariant on every\n * outgoing request, so a missing brand yields a stable default that stays\n * consistent across create/get/update/delete within a single run.\n */\nexport function resolveBrand(options: TestOptions): BrandReference {\n return (\n options.brand ||\n (options.brand_manifest && brandManifestToBrandReference(options.brand_manifest)) ||\n DEFAULT_BRAND_REF\n );\n}\n\n/**\n * Resolve the account reference to use for a test call.\n * Uses the brand+operator form of AccountReference.\n */\nexport function resolveAccount(options: TestOptions): AccountReference {\n const brand = resolveBrand(options);\n return {\n brand,\n operator: brand.domain,\n sandbox: options.sandbox,\n };\n}\n\n// Default console-based logger\nconst defaultLogger: Logger = {\n info: (ctx, msg) => console.log(`[INFO] ${msg}`, JSON.stringify(ctx, null, 2)),\n error: (ctx, msg) => console.error(`[ERROR] ${msg}`, JSON.stringify(ctx, null, 2)),\n warn: (ctx, msg) => console.warn(`[WARN] ${msg}`, JSON.stringify(ctx, null, 2)),\n debug: () => {}, // Silent by default\n};\n\n// Allow custom logger injection\nlet logger: Logger = defaultLogger;\n\n/**\n * Set a custom logger for the agent tester\n */\nexport function setAgentTesterLogger(customLogger: Logger): void {\n logger = customLogger;\n}\n\n/**\n * Get current logger instance\n */\nexport function getLogger(): Logger {\n return logger;\n}\n\n/**\n * Create a test client for an agent\n */\nexport function createTestClient(agentUrl: string, protocol: 'mcp' | 'a2a' = 'mcp', options: TestOptions = {}) {\n options = withTestKitAuthDefaults(options);\n\n // adcp-client#1618: SSRF policy gate at client construction. Once the\n // TestClient exists, every transport call inherits its agent URI; guarding\n // once here covers the entire client lifecycle, including downstream\n // `discoverAgentProfile` fetches (`getAgentInfo`, `getAdcpCapabilities`).\n // Throws synchronously — `SsrfRefusedError` is the documented refusal\n // type and operators see a clear hostname-only message (no resolved IP\n // in the user-visible text; see `probe-policy.ts` rationale).\n const policy = classifyProbeUrl(agentUrl);\n if (!policy.allowed) {\n // `classifyProbeUrl` already returned `{ allowed: true }` for any URL\n // that fails `new URL(...)`, so reaching the !allowed branch implies the\n // URL parses cleanly. Reparse only to extract the bare hostname for the\n // SsrfRefusedError meta.\n const hostname = new URL(agentUrl).hostname.replace(/^\\[|\\]$/g, '');\n throw new SsrfRefusedError(\n policy.code === 'always_blocked' ? 'always_blocked_address' : 'private_address',\n policy.reason,\n { url: agentUrl, hostname }\n );\n }\n\n const headers: Record<string, string> = {};\n\n if (options.test_session_id) {\n headers['X-Test-Session-ID'] = options.test_session_id;\n }\n\n // Build agent config with auth_token if provided\n const agentConfig: {\n id: string;\n name: string;\n agent_uri: string;\n protocol: 'mcp' | 'a2a';\n auth_token?: string;\n oauth_tokens?: import('../types/adcp').AgentOAuthTokens;\n oauth_client?: import('../types/adcp').AgentOAuthClient;\n oauth_client_credentials?: import('../types/adcp').AgentOAuthClientCredentials;\n headers?: Record<string, string>;\n } = {\n id: 'test',\n name: 'E2E Test Client',\n agent_uri: agentUrl,\n protocol,\n };\n\n // Caller-supplied tenant/routing headers carry through to every transport\n // request. Merged before auth so auth still wins on Authorization conflicts\n // (the basic-auth branch below intentionally overwrites this).\n if (options.headers && Object.keys(options.headers).length > 0) {\n agentConfig.headers = { ...options.headers };\n }\n\n // Add auth to agent config - the library will use it automatically\n if (options.auth) {\n if (options.auth.type === 'basic') {\n // basic: encode credentials here; library sends the Authorization header as-is\n const encoded = Buffer.from(`${options.auth.username}:${options.auth.password}`).toString('base64');\n agentConfig.headers = { ...agentConfig.headers, Authorization: `Basic ${encoded}` };\n } else if (options.auth.type === 'oauth') {\n // oauth: attach tokens + client registration; ProtocolClient detects\n // oauth_tokens and routes through the refresh-capable MCP OAuth path.\n agentConfig.oauth_tokens = options.auth.tokens;\n if (options.auth.client) agentConfig.oauth_client = options.auth.client;\n } else if (options.auth.type === 'oauth_client_credentials') {\n // oauth_client_credentials: attach credentials + optional cached tokens.\n // ProtocolClient pre-refreshes via secret re-exchange before each call\n // and sends the resulting access_token as a plain bearer.\n agentConfig.oauth_client_credentials = options.auth.credentials;\n if (options.auth.tokens) agentConfig.oauth_tokens = options.auth.tokens;\n } else {\n // bearer: raw token stored; library prepends 'Bearer ' internally via createMCPAuthHeaders\n agentConfig.auth_token = options.auth.token;\n }\n }\n\n const multiClient = new ADCPMultiAgentClient([agentConfig], {\n headers,\n validation: {\n responses: options.strictResponseSchemaValidation === false ? 'warn' : 'strict',\n logSchemaViolations: false,\n },\n ...(options.adcpVersion !== undefined && { adcpVersion: options.adcpVersion }),\n ...(options.wireAdcpVersion !== undefined && { wireAdcpVersion: options.wireAdcpVersion }),\n ...(options.versionEnvelope !== undefined && { versionEnvelope: options.versionEnvelope }),\n ...(options.userAgent && { userAgent: options.userAgent }),\n ...(options.transport && { transport: options.transport }),\n });\n\n const client = multiClient.agent('test');\n const authMode = authReuseMode(options);\n Object.defineProperty(client, TEST_CLIENT_VERSION_OPTIONS, {\n value: {\n adcpVersion: multiClient.getAdcpVersion(),\n ...(options.wireAdcpVersion !== undefined && { wireAdcpVersion: options.wireAdcpVersion }),\n versionEnvelope: options.versionEnvelope ?? 'auto',\n strictResponseSchemaValidation: options.strictResponseSchemaValidation !== false,\n ...(authMode !== undefined && { authMode }),\n ...(options.transport?.trustedFetchFn && { fetchFn: options.transport.trustedFetchFn }),\n ...(options.transport?.maxResponseBytes !== undefined && {\n maxResponseBytes: options.transport.maxResponseBytes,\n }),\n ...(options.transport?.requestTimeoutMs !== undefined && {\n requestTimeoutMs: options.transport.requestTimeoutMs,\n }),\n } satisfies TestClientVersionOptions,\n enumerable: false,\n });\n return client;\n}\n\nexport type TestClient = ReturnType<typeof createTestClient>;\nexport interface TestClientResolution {\n client: TestClient;\n reusedShared: boolean;\n}\n\n/**\n * Return a shared client from options (set by comply()) or create a fresh one.\n * When comply() runs, it creates a single client and passes it via options._client\n * so scenarios reuse the same MCP connection instead of opening 36+ connections.\n */\nexport function getOrCreateClient(agentUrl: string, options: TestOptions): TestClient {\n return getOrCreateClientResolution(agentUrl, options).client;\n}\n\nexport function getOrCreateClientResolution(agentUrl: string, options: TestOptions): TestClientResolution {\n const shared = options._client as TestClient | undefined;\n if (shared && isExecutableTestClient(shared) && testClientMatchesVersionOptions(shared, options)) {\n return { client: shared, reusedShared: true };\n }\n return { client: createTestClient(agentUrl, options.protocol || 'mcp', options), reusedShared: false };\n}\n\nfunction isExecutableTestClient(client: unknown): client is TestClient {\n if (client == null || typeof client !== 'object') return false;\n const candidate = client as Record<string, unknown>;\n if (typeof candidate['executeTask'] === 'function' || typeof candidate['resetContext'] === 'function') return true;\n return Object.entries(candidate).some(([key, value]) => key !== 'getAgentInfo' && typeof value === 'function');\n}\n\nfunction testClientMatchesVersionOptions(client: TestClient, options: TestOptions): boolean {\n const effectiveOptions = withTestKitAuthDefaults(options);\n const meta = (client as unknown as { [TEST_CLIENT_VERSION_OPTIONS]?: TestClientVersionOptions })[\n TEST_CLIENT_VERSION_OPTIONS\n ];\n const expectedAuthMode = authReuseMode(effectiveOptions);\n if (!meta) {\n return (\n effectiveOptions.adcpVersion === undefined &&\n effectiveOptions.versionEnvelope === undefined &&\n effectiveOptions.transport === undefined\n );\n }\n const expectedAdcpVersion = effectiveOptions.adcpVersion ?? ADCP_VERSION;\n const expectedWireAdcpVersion = effectiveOptions.wireAdcpVersion;\n const expectedVersionEnvelope = effectiveOptions.versionEnvelope ?? 'auto';\n return (\n meta.adcpVersion === expectedAdcpVersion &&\n meta.wireAdcpVersion === expectedWireAdcpVersion &&\n meta.versionEnvelope === expectedVersionEnvelope &&\n meta.strictResponseSchemaValidation === (effectiveOptions.strictResponseSchemaValidation !== false) &&\n meta.authMode === expectedAuthMode &&\n meta.fetchFn === effectiveOptions.transport?.trustedFetchFn &&\n meta.maxResponseBytes === effectiveOptions.transport?.maxResponseBytes &&\n meta.requestTimeoutMs === effectiveOptions.transport?.requestTimeoutMs\n );\n}\n\nfunction withTestKitAuthDefaults(options: TestOptions): TestOptions {\n if (options.auth) return options;\n const apiKey = options.test_kit?.auth?.api_key;\n if (typeof apiKey === 'string' && apiKey.length > 0) {\n return { ...options, auth: { type: 'bearer', token: apiKey } };\n }\n\n const basic = options.test_kit?.auth?.basic;\n if (!basic) return options;\n if (\n typeof basic.username === 'string' &&\n basic.username.length > 0 &&\n typeof basic.password === 'string' &&\n basic.password.length > 0\n ) {\n return { ...options, auth: { type: 'basic', username: basic.username, password: basic.password } };\n }\n if (typeof basic.credentials === 'string') {\n const splitAt = basic.credentials.indexOf(':');\n if (splitAt > 0) {\n return {\n ...options,\n auth: {\n type: 'basic',\n username: basic.credentials.slice(0, splitAt),\n password: basic.credentials.slice(splitAt + 1),\n },\n };\n }\n }\n return options;\n}\n\nfunction authReuseMode(options: TestOptions): string | undefined {\n return options.auth?.type;\n}\n\n/**\n * Return a pre-discovered profile from options (set by comply()) or discover fresh.\n */\nexport async function getOrDiscoverProfile(\n client: TestClient,\n options: TestOptions\n): Promise<{ profile: AgentProfile; step: TestStepResult }> {\n if (options._profile) {\n return {\n profile: options._profile,\n step: { step: 'Discover agent capabilities', passed: true, duration_ms: 0 },\n };\n }\n return discoverAgentProfile(client, options.signal, options.adcpVersion);\n}\n\n/**\n * Run a single test step with timing\n */\n/**\n * Race a promise against an AbortSignal. Adopted by `discoverAgentProfile`\n * so the comply pipeline's timeout actually bounds discovery wall-clock —\n * the underlying transport's `getAgentInfo()` doesn't accept a signal\n * (public API), so we resolve the wrapper promise on abort and let the\n * orphaned in-flight request finish on its own. (adcp-client#1612)\n *\n * Throws the signal's reason on abort.\n *\n * **SECURITY (security-reviewer follow-up on #1612):** the orphaned\n * promise's `.then` handlers below stay attached until the underlying\n * transport call settles. The resolved value `v` carries an authenticated\n * agent response — `getAgentInfo()` and `getAdcpCapabilities()` round-trip\n * through the bearer-token transport, so the promise body holds the wire\n * response in memory until GC'd. **Do not log `v` from inside this\n * resolver** (or any future `console.error` / telemetry hook on the\n * orphaned path) — the buyer has already moved on past the abort, and\n * logging here would leak agent-side data after the caller stopped\n * trusting it. The early `resolve(v)` is intentionally a no-op on the\n * already-rejected race-promise; `v` becomes unreferenced and GC-eligible\n * the moment this `.then` returns.\n */\nfunction raceWithSignal<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) {\n return Promise.reject(signal.reason ?? new Error('aborted'));\n }\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(signal.reason ?? new Error('aborted'));\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n v => {\n signal.removeEventListener('abort', onAbort);\n // INTENTIONAL: no-op on an already-rejected race-promise. Do NOT\n // log `v` here — see security note in the JSDoc above.\n resolve(v);\n },\n e => {\n signal.removeEventListener('abort', onAbort);\n // INTENTIONAL: no-op on an already-rejected race-promise. Do NOT\n // log `e` here either — `Error.message` from a transport rejection\n // can carry an echoed response body, see security note above.\n reject(e);\n }\n );\n });\n}\n\n/**\n * Result of {@link runStep}. The optional `caughtError` carries the raw\n * thrown value (typed `unknown`, narrow via `instanceof` at the call site)\n * so callers can pattern-match on typed exceptions like\n * `ResponseSchemaValidationError` without losing the freeform string\n * representation on `step.error`. Pre-existing callers that only consume\n * `result` and `step` are unaffected.\n *\n * Spec: adcp-client#1709 (storyboard runner attributes Zod rejects to\n * the canonical `response_schema` validation entry by detecting the typed\n * error here).\n */\nexport interface RunStepOutcome<T> {\n result?: T;\n step: TestStepResult;\n caughtError?: unknown;\n}\n\nexport async function runStep<T>(\n stepName: string,\n taskName: string | undefined,\n fn: () => Promise<T>\n): Promise<RunStepOutcome<T>> {\n const start = Date.now();\n try {\n const result = await fn();\n const duration = Date.now() - start;\n return {\n result,\n step: {\n step: stepName,\n task: taskName,\n passed: true,\n duration_ms: duration,\n },\n };\n } catch (error) {\n const duration = Date.now() - start;\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n step: {\n step: stepName,\n task: taskName,\n passed: false,\n duration_ms: duration,\n error: errorMessage,\n },\n caughtError: error,\n };\n }\n}\n\nfunction describeVersionUnsupported(result: unknown, requestedVersion: string | undefined): string | undefined {\n if (!result || typeof result !== 'object') return undefined;\n const record = result as Record<string, unknown>;\n const dataRecord =\n record.data && typeof record.data === 'object' && !Array.isArray(record.data)\n ? (record.data as Record<string, unknown>)\n : undefined;\n const dataError =\n dataRecord?.adcp_error && typeof dataRecord.adcp_error === 'object' ? dataRecord.adcp_error : undefined;\n const adcpError = record.adcpError ?? record.adcp_error ?? dataError;\n if (!adcpError || typeof adcpError !== 'object') return undefined;\n const adcpErrorRecord = adcpError as Record<string, unknown>;\n if (adcpErrorRecord.code !== 'VERSION_UNSUPPORTED') return undefined;\n\n const details = extractVersionUnsupportedDetails(adcpErrorRecord) ?? extractVersionUnsupportedDetails(record.data);\n const requested = details?.requested_version ?? requestedVersion;\n const supported = details?.supported_versions;\n const requestedText = requested ? `requested ${JSON.stringify(requested)}` : 'requested version is unsupported';\n const supportedText = supported?.length\n ? `; seller supports ${supported.map(version => JSON.stringify(version)).join(', ')}`\n : '; seller did not report supported_versions';\n return `VERSION_UNSUPPORTED: ${requestedText}${supportedText}`;\n}\n\n/**\n * Discover agent profile - what capabilities does this agent have?\n *\n * When the agent exposes `get_adcp_capabilities`, its response populates\n * `supported_protocols` + `specialisms` on the profile so the compliance\n * runner can select domain and specialism bundles.\n *\n * Pass `signal` for hard external cancellation. `comply()` deliberately does\n * not pass its soft `timeout_ms` storyboard-start budget here; that budget\n * stops new storyboards after discovery instead of aborting an active run.\n */\nexport async function discoverAgentProfile(\n client: TestClient,\n signal?: AbortSignal,\n /** Compliance/schema line selected by the caller. Defaults to the client pin. */\n schemaAdcpVersion?: string\n): Promise<{ profile: AgentProfile; step: TestStepResult }> {\n const { result: agentInfo, step } = await runStep('Discover agent capabilities', 'getAgentInfo', () =>\n raceWithSignal(client.getAgentInfo({ signal }), signal)\n );\n\n const profile: AgentProfile = {\n name: agentInfo?.name || 'Unknown',\n tools: agentInfo?.tools?.map((t: { name: string }) => t.name) || [],\n };\n\n if (agentInfo) {\n step.details = `Agent: ${profile.name}, Tools: ${profile.tools.length}`;\n step.response_preview = JSON.stringify(\n {\n name: profile.name,\n tools: profile.tools,\n },\n null,\n 2\n );\n }\n\n if (profile.tools.includes('get_adcp_capabilities')) {\n try {\n const caps = (await raceWithSignal(client.getAdcpCapabilities({}, undefined, { signal }), signal)) as TaskResult;\n const versionUnsupported = describeVersionUnsupported(caps, schemaAdcpVersion ?? client.getAdcpVersion?.());\n if (versionUnsupported) {\n // Some transports return AdCP error envelopes as successful tool data.\n // Detect the protocol error before validating/parsing it as a\n // capabilities success response, or best-effort parsing will produce\n // a synthetic v2 profile from the error object.\n profile.capabilities_probe_error = versionUnsupported;\n step.passed = false;\n step.error = versionUnsupported;\n } else if (caps?.data) {\n profile.raw_capabilities = caps.data;\n const validation = validateIncomingResponse(\n 'get_adcp_capabilities',\n caps.data,\n 'strict',\n undefined,\n schemaAdcpVersion ?? client.getAdcpVersion()\n );\n if (!validation.valid) {\n profile.capabilities_schema_issues = validation.issues.map(issue => ({\n pointer: issue.pointer,\n message: issue.message,\n }));\n }\n\n // Even a schema-invalid response can contain enough trustworthy\n // discriminators to select the storyboards the seller claimed. Keep\n // parsing best-effort so the preflight notice augments downstream\n // failures instead of suppressing them.\n const parsed = parseCapabilitiesResponse(caps.data);\n profile.adcp_version = parsed.version;\n profile.adcp_major_versions = parsed.majorVersions;\n if (parsed.supportedVersions !== undefined) profile.adcp_supported_versions = parsed.supportedVersions;\n if (parsed.buildVersion !== undefined) profile.adcp_build_version = parsed.buildVersion;\n profile.supported_protocols = parsed.protocols;\n profile.supports_governance = parsed.protocols.includes('governance');\n profile.supports_si = parsed.protocols.includes('sponsored_intelligence');\n const specialisms = (caps.data as { specialisms?: unknown }).specialisms;\n if (Array.isArray(specialisms)) {\n profile.specialisms = specialisms.filter((s): s is string => typeof s === 'string');\n }\n const libVersion = (caps.data as Record<string, unknown>).library_version;\n if (typeof libVersion === 'string') profile.library_version = libVersion;\n }\n if (!versionUnsupported && (!caps?.success || !caps?.data) && !profile.capabilities_schema_issues?.length) {\n profile.capabilities_probe_error = caps?.error || 'get_adcp_capabilities returned no data';\n }\n } catch (err) {\n // Agent advertises the tool but the call failed. Don't silently downgrade —\n // record the failure so the compliance report shows why only universal ran.\n profile.capabilities_probe_error = (err as Error)?.message || String(err);\n }\n }\n\n return { profile, step };\n}\n\n/**\n * Discover what channels, pricing models, formats the agent supports\n * by calling get_products and analyzing the response\n */\nexport async function discoverAgentCapabilities(\n client: TestClient,\n profile: AgentProfile,\n options: TestOptions\n): Promise<{ capabilities: Partial<AgentProfile>; steps: TestStepResult[] }> {\n const steps: TestStepResult[] = [];\n const capabilities: Partial<AgentProfile> = {};\n\n if (!profile.tools.includes('get_products')) {\n return { capabilities, steps };\n }\n\n const brief = options.brief || 'Show me all available advertising products across all channels';\n const getProductsParams: Record<string, unknown> = {\n buying_mode: 'brief',\n brief,\n brand: resolveBrand(options),\n };\n const { result, step } = await runStep<TaskResult>(\n 'Discover products for capability analysis',\n 'get_products',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- bypasses strict request typing\n async () => client.getProducts(getProductsParams as any) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const responseData = result.data as GetProductsResponse;\n const products: Product[] = responseData.products ?? [];\n\n // Extract unique channels\n const channels = new Set<string>();\n const pricingModels = new Set<string>();\n const formatIds = new Set<string>();\n const deliveryTypes = new Set<string>();\n\n for (const product of products) {\n // Channels from product\n if (product.channels) {\n for (const ch of product.channels) {\n channels.add(ch);\n }\n }\n // Delivery type\n if (product.delivery_type) {\n deliveryTypes.add(product.delivery_type);\n }\n // Pricing models\n if (product.pricing_options) {\n for (const po of product.pricing_options) {\n if (po.pricing_model) pricingModels.add(po.pricing_model);\n }\n }\n // Format IDs\n if (product.format_ids) {\n for (const fid of product.format_ids) {\n const id = typeof fid === 'string' ? fid : fid.id;\n if (id) formatIds.add(id);\n }\n }\n }\n\n capabilities.channels = Array.from(channels);\n capabilities.pricing_models = Array.from(pricingModels);\n capabilities.format_ids = Array.from(formatIds);\n capabilities.delivery_types = Array.from(deliveryTypes);\n\n step.details = `Found ${products.length} products across ${channels.size} channel(s), ${pricingModels.size} pricing model(s)`;\n step.response_preview = JSON.stringify(\n {\n products_count: products.length,\n channels: capabilities.channels,\n pricing_models: capabilities.pricing_models,\n delivery_types: capabilities.delivery_types,\n format_count: capabilities.format_ids?.length,\n },\n null,\n 2\n );\n step.observation_data = { products_count: products.length, channels: capabilities.channels };\n } else if (result && !result.success) {\n step.passed = false;\n step.error = result.error || 'get_products failed';\n }\n\n steps.push(step);\n return { capabilities, steps };\n}\n\n/**\n * Discover creative formats from a creative agent\n */\nexport async function discoverCreativeFormats(\n client: TestClient,\n profile: AgentProfile\n): Promise<{ formats: AgentProfile['supported_formats']; step: TestStepResult }> {\n const formats: AgentProfile['supported_formats'] = [];\n\n if (!profile.tools.includes('list_creative_formats')) {\n return {\n formats,\n step: {\n step: 'Discover creative formats',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support list_creative_formats',\n },\n };\n }\n\n const { result, step } = await runStep<TaskResult>(\n 'Discover creative formats',\n 'list_creative_formats',\n async () => client.listCreativeFormatsLegacy({}) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const responseData = result.data as ListCreativeFormatsResponse;\n const rawFormats: Format[] = responseData.formats ?? [];\n const deprecatedFormats: string[] = [];\n\n for (const format of rawFormats) {\n const formatInfo: NonNullable<AgentProfile['supported_formats']>[0] = {\n format_id: format.format_id,\n name: format.name,\n required_assets: [],\n optional_assets: [],\n };\n\n // Check for deprecated assets_required usage\n if (usesDeprecatedAssetsField(format as unknown as Parameters<typeof usesDeprecatedAssetsField>[0])) {\n const displayId = typeof formatInfo.format_id === 'object' ? formatInfo.format_id.id : formatInfo.format_id;\n deprecatedFormats.push(displayId);\n }\n\n // Extract asset requirements from format spec using format-assets utilities\n // This handles both v2.6 `assets` and deprecated `assets_required` fields\n const formatAssets = getFormatAssets(format as unknown as Parameters<typeof getFormatAssets>[0]);\n for (const asset of formatAssets) {\n const assetId = asset.item_type === 'individual' ? asset.asset_id : asset.asset_group_id;\n\n if (asset.required) {\n formatInfo.required_assets?.push(assetId);\n } else {\n formatInfo.optional_assets?.push(assetId);\n }\n }\n\n formats.push(formatInfo);\n }\n\n step.details = `Found ${formats.length} format(s)`;\n step.response_preview = JSON.stringify(\n {\n format_count: formats.length,\n sample_formats: formats.slice(0, 3).map(f => ({\n id: f.format_id,\n name: f.name,\n required_assets: f.required_assets?.length || 0,\n })),\n },\n null,\n 2\n );\n\n // Add deprecation warnings if any formats use assets_required\n if (deprecatedFormats.length > 0) {\n step.warnings = [\n `⚠️ DEPRECATION: ${deprecatedFormats.length} format(s) use 'assets_required' field which is deprecated and will be removed in a future version. Please migrate to the 'assets' field instead. (adcp-client 3.6.0+)`,\n ];\n logger.warn(\n { deprecated_formats: deprecatedFormats },\n `Agent uses deprecated 'assets_required' field in ${deprecatedFormats.length} format(s). Migrate to 'assets' field.`\n );\n }\n } else if (result && !result.success) {\n step.passed = false;\n step.error = result.error || 'list_creative_formats failed';\n }\n\n return { formats, step };\n}\n\n/**\n * Discover signals from a signals agent\n */\nexport async function discoverSignals(\n client: TestClient,\n profile: AgentProfile,\n options: TestOptions\n): Promise<{\n signals: AgentProfile['supported_signals'];\n rawSignals: GetSignalsResponse['signals'];\n step: TestStepResult;\n schemaStep?: TestStepResult;\n}> {\n const signals: AgentProfile['supported_signals'] = [];\n let rawSignals: GetSignalsResponse['signals'] = [];\n\n if (!profile.tools.includes('get_signals')) {\n return {\n signals,\n rawSignals,\n step: {\n step: 'Discover signals',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support get_signals',\n },\n };\n }\n\n const { result, step } = await runStep<TaskResult>(\n 'Discover available signals',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Show me all available audience signals and segments',\n }) as Promise<TaskResult>\n );\n\n let schemaStep: TestStepResult | undefined;\n\n if (result?.success && result?.data) {\n schemaStep = validateResponseSchema('get_signals', result.data);\n const responseData = result.data as GetSignalsResponse;\n rawSignals = responseData.signals ?? [];\n\n for (const signal of rawSignals) {\n const signalData = signal as {\n signal_agent_segment_id?: unknown;\n signal_ref?: unknown;\n name?: unknown;\n signal_type?: unknown;\n type?: unknown;\n };\n let signalId: string | undefined;\n if (typeof signalData.signal_agent_segment_id === 'string') {\n signalId = signalData.signal_agent_segment_id;\n } else if (typeof signalData.signal_ref === 'string') {\n signalId = signalData.signal_ref;\n } else if (signalData.signal_ref != null) {\n // Summary-only convenience for the test report; rawSignals above\n // preserves the seller's canonical signal_ref object.\n signalId = JSON.stringify(signalData.signal_ref);\n }\n if (!signalId) continue;\n signals.push({\n signal_id: signalId,\n name: typeof signalData.name === 'string' ? signalData.name : undefined,\n type:\n typeof signalData.signal_type === 'string'\n ? signalData.signal_type\n : typeof signalData.type === 'string'\n ? signalData.type\n : undefined,\n });\n }\n\n step.details = `Found ${signals.length} signal(s)`;\n step.response_preview = JSON.stringify(\n {\n signal_count: signals.length,\n signal_types: [...new Set(signals.map(s => s.type).filter(Boolean))],\n sample_signals: signals.slice(0, 5).map(s => ({\n id: s.signal_id,\n name: s.name,\n type: s.type,\n })),\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n step.passed = false;\n step.error = result.error || 'get_signals failed';\n }\n\n return { signals, rawSignals, step, schemaStep };\n}\n\n/**\n * Validate response data against the AdCP Zod schema for a tool.\n * Returns a TestStepResult indicating pass/fail with details on schema violations.\n *\n * For union schemas (success | error responses), Zod's top-level error is the\n * unhelpful \"(root): Invalid input\". This function detects that case and\n * reports per-variant errors instead, picking the variant with the fewest\n * issues (the closest match) so the developer sees actionable field names.\n *\n * Violations are split into two categories so remediation guidance differs\n * appropriately (set the field vs. fix the value):\n * - `required` — a required field is absent from the response. Zod emits\n * `invalid_type` with `received: 'undefined'` for this case; we re-tag\n * it as `required` and report it as a missing field.\n * - constraint keyword (`minimum`, `maximum`, `enum`, `format`, …) — the\n * field is present but violates a JSON Schema keyword constraint.\n */\nexport function validateResponseSchema(toolName: string, data: unknown, responseAdcpVersion?: string): TestStepResult {\n const schema = TOOL_RESPONSE_SCHEMAS[toolName];\n if (!schema) {\n return {\n step: `Schema validation: ${toolName}`,\n passed: true,\n duration_ms: 0,\n details: `No response schema available for ${toolName}`,\n warnings: [`No Zod schema registered for \"${toolName}\" — validation skipped`],\n };\n }\n\n // 3.0.x back-compat: synthesize envelope `status` for legacy peers so\n // strict 3.1 validators don't reject otherwise-conformant 3.0 wire\n // responses. See `utils/envelope-status-compat.ts`.\n const compatData =\n data && typeof data === 'object' && !Array.isArray(data)\n ? injectLegacyEnvelopeStatus(data as Record<string, unknown>, { toolName })\n : data;\n const result = schema.safeParse(prepareResponseForSchemaValidation(toolName, compatData, responseAdcpVersion));\n if (result.success) {\n return {\n step: `Schema validation: ${toolName}`,\n passed: true,\n duration_ms: 0,\n details: `Response matches ${toolName} schema`,\n };\n }\n\n let violations: SchemaViolation[] = result.error.issues.map(i => {\n const path = i.path.length > 0 ? i.path.join('.') : '(root)';\n return { path, message: i.message, code: i.code };\n });\n\n // Union schemas produce \"(root): Invalid input\" when no variant matches.\n // Try each variant individually and report the closest match's errors.\n const first = violations[0];\n const isUnionError = violations.length === 1 && first && first.path === '(root)' && first.code === 'invalid_union';\n\n if (isUnionError) {\n const betterErrors = getBestUnionErrors(schema, data);\n if (betterErrors && betterErrors.length > 0) {\n violations = betterErrors;\n }\n }\n\n const classified = violations.map(classifyViolation);\n const missing = classified.filter(v => v.kind === 'missing');\n const constraint = classified.filter(v => v.kind === 'constraint');\n\n const parts: string[] = [];\n if (missing.length > 0) {\n parts.push(`Response missing required fields: ${missing.map(v => v.json_pointer).join(', ')}`);\n }\n if (constraint.length > 0) {\n parts.push(\n `Response constraint violations: ${constraint\n .map(v => `${v.json_pointer} (${v.keyword}): ${v.message}`)\n .join('; ')}`\n );\n }\n\n return {\n step: `Schema validation: ${toolName}`,\n passed: false,\n duration_ms: 0,\n error: parts.join(' | '),\n response_preview: JSON.stringify({ violations: classified }, null, 2),\n };\n}\n\n/**\n * Classify a Zod-flavored schema violation as either a missing required field\n * or a constraint violation (with the failed JSON Schema keyword). Adds a\n * JSON Pointer (`/foo/0/bar`) so downstream tooling can locate the field\n * without re-parsing dot paths.\n */\nfunction classifyViolation(v: SchemaViolation): {\n kind: 'missing' | 'constraint';\n json_pointer: string;\n keyword: string;\n message: string;\n code: SchemaViolation['code'];\n} {\n const segments = v.path === '(root)' ? [] : v.path.split('.');\n const json_pointer = '/' + segments.map(s => s.replace(/~/g, '~0').replace(/\\//g, '~1')).join('/');\n\n // Zod emits `invalid_type` with `received: 'undefined'` for missing required\n // fields. The `code` alone is ambiguous (`invalid_type` also covers wrong-\n // type-but-present), so we sniff the message for the canonical Zod wording.\n const isMissing = v.code === 'invalid_type' && /received `?undefined`?/i.test(v.message);\n if (isMissing) {\n return { kind: 'missing', json_pointer, keyword: 'required', message: v.message, code: v.code };\n }\n\n return {\n kind: 'constraint',\n json_pointer,\n keyword: zodCodeToKeyword(v.code),\n message: v.message,\n code: v.code,\n };\n}\n\n/**\n * Map a Zod error code to the equivalent JSON Schema keyword so downstream\n * tooling (and humans reading the report) see the standard vocabulary\n * (`minimum`, `enum`, `format`, …) instead of Zod-specific names.\n */\nfunction zodCodeToKeyword(code: SchemaViolation['code']): string {\n switch (code) {\n case 'invalid_type':\n return 'type';\n case 'invalid_value':\n return 'enum';\n case 'too_small':\n return 'minimum';\n case 'too_big':\n return 'maximum';\n case 'invalid_format':\n return 'format';\n case 'unrecognized_keys':\n return 'additionalProperties';\n case 'invalid_union':\n return 'oneOf';\n case 'not_multiple_of':\n return 'multipleOf';\n default:\n return code;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/testing/client.ts"],"sourcesContent":["/**\n * Test client utilities for AdCP Agent E2E Testing\n */\n\nimport { ADCPMultiAgentClient } from '../core/ADCPMultiAgentClient';\nimport { getBestUnionErrors, type SchemaViolation } from '../utils/union-errors';\nimport { getFormatAssets, usesDeprecatedAssetsField } from '../utils/format-assets';\nimport { brandManifestToBrandReference } from '../types/compat';\nimport type { Product } from '../types/core.generated';\nimport type {\n GetProductsResponse,\n ListCreativeFormatsResponse,\n Format,\n GetSignalsResponse,\n AccountReference,\n BrandReference,\n} from '../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult, Logger } from './types';\nimport { prepareResponseForSchemaValidation, TOOL_RESPONSE_SCHEMAS } from '../utils/response-schemas';\nimport { injectLegacyEnvelopeStatus } from '../utils/envelope-status-compat';\nimport { parseCapabilitiesResponse } from '../utils/capabilities';\nimport { classifyProbeUrl } from '../utils/probe-policy';\nimport { SsrfRefusedError } from '../net/ssrf-fetch';\nimport { ADCP_VERSION } from '../version';\nimport type { VersionEnvelopeMode } from '../protocols';\nimport type { AgentRequestSigningConfig } from '../types/adcp';\nimport { createHmac, hkdfSync, randomBytes } from 'node:crypto';\nimport { validateIncomingResponse } from '../validation/client-hooks';\nimport { extractVersionUnsupportedDetails } from '../utils/error-extraction';\nimport { buildAgentSigningContext } from '../signing/client';\nimport type { VerifierCapability } from '../signing/types';\n\nconst TEST_CLIENT_VERSION_OPTIONS = Symbol('adcp.testClientVersionOptions');\nconst TEST_CLIENT_SCOPE_SALT = randomBytes(32);\n\ninterface TestClientVersionOptions {\n agentUrl: string;\n protocol: 'mcp' | 'a2a';\n adcpVersion: string;\n wireAdcpVersion?: string;\n versionEnvelope: VersionEnvelopeMode;\n strictResponseSchemaValidation: boolean;\n authMode?: string;\n requestScopeMode?: string;\n requestSigningMode?: string;\n fetchFn?: typeof fetch;\n allowPrivateIp?: boolean;\n maxResponseBytes?: number;\n requestTimeoutMs?: number;\n}\n\n/**\n * Extract a principal identifier from TestOptions auth.\n * For bearer auth this is the token; for basic auth this is the username;\n * for oauth this is the access_token.\n */\nexport function resolveAuthPrincipal(options: TestOptions): string | undefined {\n if (!options.auth) return undefined;\n switch (options.auth.type) {\n case 'basic':\n return options.auth.username;\n case 'oauth':\n return options.auth.tokens.access_token;\n case 'bearer':\n return options.auth.token;\n }\n}\n\nconst DEFAULT_BRAND_REF: BrandReference = { domain: 'test.example' };\n\n/**\n * Resolve the brand reference to use for a test call.\n * Prefers the new brand field, falls back to converting a legacy brand_manifest.\n *\n * The runner enforces a storyboard-run-scoped brand invariant on every\n * outgoing request, so a missing brand yields a stable default that stays\n * consistent across create/get/update/delete within a single run.\n */\nexport function resolveBrand(options: TestOptions): BrandReference {\n return (\n options.brand ||\n (options.brand_manifest && brandManifestToBrandReference(options.brand_manifest)) ||\n DEFAULT_BRAND_REF\n );\n}\n\n/**\n * Resolve the account reference to use for a test call.\n * Uses the brand+operator form of AccountReference.\n */\nexport function resolveAccount(options: TestOptions): AccountReference {\n const brand = resolveBrand(options);\n return {\n brand,\n operator: brand.domain,\n sandbox: options.sandbox,\n };\n}\n\n// Default console-based logger\nconst defaultLogger: Logger = {\n info: (ctx, msg) => console.log(`[INFO] ${msg}`, JSON.stringify(ctx, null, 2)),\n error: (ctx, msg) => console.error(`[ERROR] ${msg}`, JSON.stringify(ctx, null, 2)),\n warn: (ctx, msg) => console.warn(`[WARN] ${msg}`, JSON.stringify(ctx, null, 2)),\n debug: () => {}, // Silent by default\n};\n\n// Allow custom logger injection\nlet logger: Logger = defaultLogger;\n\n/**\n * Set a custom logger for the agent tester\n */\nexport function setAgentTesterLogger(customLogger: Logger): void {\n logger = customLogger;\n}\n\n/**\n * Get current logger instance\n */\nexport function getLogger(): Logger {\n return logger;\n}\n\n/**\n * Create a test client for an agent\n */\nexport function createTestClient(agentUrl: string, protocol: 'mcp' | 'a2a' = 'mcp', options: TestOptions = {}) {\n options = withTestKitAuthDefaults(options);\n\n // adcp-client#1618: SSRF policy gate at client construction. Once the\n // TestClient exists, every transport call inherits its agent URI; guarding\n // once here covers the entire client lifecycle, including downstream\n // `discoverAgentProfile` fetches (`getAgentInfo`, `getAdcpCapabilities`).\n // Throws synchronously — `SsrfRefusedError` is the documented refusal\n // type and operators see a clear hostname-only message (no resolved IP\n // in the user-visible text; see `probe-policy.ts` rationale).\n const policy = classifyProbeUrl(agentUrl);\n if (!policy.allowed) {\n // `classifyProbeUrl` already returned `{ allowed: true }` for any URL\n // that fails `new URL(...)`, so reaching the !allowed branch implies the\n // URL parses cleanly. Reparse only to extract the bare hostname for the\n // SsrfRefusedError meta.\n const hostname = new URL(agentUrl).hostname.replace(/^\\[|\\]$/g, '');\n throw new SsrfRefusedError(\n policy.code === 'always_blocked' ? 'always_blocked_address' : 'private_address',\n policy.reason,\n { url: agentUrl, hostname }\n );\n }\n\n const headers: Record<string, string> = {};\n\n if (options.test_session_id) {\n headers['X-Test-Session-ID'] = options.test_session_id;\n }\n\n // Build agent config with auth_token if provided\n const agentConfig: {\n id: string;\n name: string;\n agent_uri: string;\n protocol: 'mcp' | 'a2a';\n auth_token?: string;\n oauth_tokens?: import('../types/adcp').AgentOAuthTokens;\n oauth_client?: import('../types/adcp').AgentOAuthClient;\n oauth_client_credentials?: import('../types/adcp').AgentOAuthClientCredentials;\n request_signing?: AgentRequestSigningConfig;\n headers?: Record<string, string>;\n } = {\n id: 'test',\n name: 'E2E Test Client',\n agent_uri: agentUrl,\n protocol,\n };\n\n // Caller-supplied tenant/routing headers carry through to every transport\n // request. Merged before auth so auth still wins on Authorization conflicts\n // (the basic-auth branch below intentionally overwrites this).\n if (options.headers && Object.keys(options.headers).length > 0) {\n agentConfig.headers = { ...options.headers };\n }\n\n // Add auth to agent config - the library will use it automatically\n if (options.auth) {\n if (options.auth.type === 'basic') {\n // basic: encode credentials here; library sends the Authorization header as-is\n const encoded = Buffer.from(`${options.auth.username}:${options.auth.password}`).toString('base64');\n agentConfig.headers = { ...agentConfig.headers, Authorization: `Basic ${encoded}` };\n } else if (options.auth.type === 'oauth') {\n // oauth: attach tokens + client registration; ProtocolClient detects\n // oauth_tokens and routes through the refresh-capable MCP OAuth path.\n agentConfig.oauth_tokens = options.auth.tokens;\n if (options.auth.client) agentConfig.oauth_client = options.auth.client;\n } else if (options.auth.type === 'oauth_client_credentials') {\n // oauth_client_credentials: attach credentials + optional cached tokens.\n // ProtocolClient pre-refreshes via secret re-exchange before each call\n // and sends the resulting access_token as a plain bearer.\n agentConfig.oauth_client_credentials = options.auth.credentials;\n if (options.auth.tokens) agentConfig.oauth_tokens = options.auth.tokens;\n } else {\n // bearer: raw token stored; library prepends 'Bearer ' internally via createMCPAuthHeaders\n agentConfig.auth_token = options.auth.token;\n }\n }\n\n if (options.functional_request_signing) {\n agentConfig.request_signing = options.functional_request_signing;\n }\n\n const multiClient = new ADCPMultiAgentClient([agentConfig], {\n headers,\n validation: {\n responses: options.strictResponseSchemaValidation === false ? 'warn' : 'strict',\n logSchemaViolations: false,\n },\n ...(options.adcpVersion !== undefined && { adcpVersion: options.adcpVersion }),\n ...(options.wireAdcpVersion !== undefined && { wireAdcpVersion: options.wireAdcpVersion }),\n ...(options.versionEnvelope !== undefined && { versionEnvelope: options.versionEnvelope }),\n ...(options.userAgent && { userAgent: options.userAgent }),\n ...(options.transport && { transport: options.transport }),\n });\n\n const client = multiClient.agent('test');\n const authMode = authReuseMode(options);\n const requestScopeMode = requestScopeReuseMode(options);\n const requestSigningMode = requestSigningReuseMode(options.functional_request_signing);\n Object.defineProperty(client, TEST_CLIENT_VERSION_OPTIONS, {\n value: {\n agentUrl,\n protocol,\n adcpVersion: multiClient.getAdcpVersion(),\n ...(options.wireAdcpVersion !== undefined && { wireAdcpVersion: options.wireAdcpVersion }),\n versionEnvelope: options.versionEnvelope ?? 'auto',\n strictResponseSchemaValidation: options.strictResponseSchemaValidation !== false,\n ...(authMode !== undefined && { authMode }),\n ...(requestScopeMode !== undefined && { requestScopeMode }),\n ...(requestSigningMode !== undefined && { requestSigningMode }),\n ...(options.transport?.trustedFetchFn && { fetchFn: options.transport.trustedFetchFn }),\n ...(options.transport?.allowPrivateIp !== undefined && { allowPrivateIp: options.transport.allowPrivateIp }),\n ...(options.transport?.maxResponseBytes !== undefined && {\n maxResponseBytes: options.transport.maxResponseBytes,\n }),\n ...(options.transport?.requestTimeoutMs !== undefined && {\n requestTimeoutMs: options.transport.requestTimeoutMs,\n }),\n } satisfies TestClientVersionOptions,\n enumerable: false,\n });\n return client;\n}\n\nexport type TestClient = ReturnType<typeof createTestClient>;\nexport interface TestClientResolution {\n client: TestClient;\n reusedShared: boolean;\n}\n\n/**\n * Return a shared client from options (set by comply()) or create a fresh one.\n * When comply() runs, it creates a single client and passes it via options._client\n * so scenarios reuse the same MCP connection instead of opening 36+ connections.\n */\nexport function getOrCreateClient(agentUrl: string, options: TestOptions): TestClient {\n return getOrCreateClientResolution(agentUrl, options).client;\n}\n\nexport function getOrCreateClientResolution(agentUrl: string, options: TestOptions): TestClientResolution {\n const shared = options._client as TestClient | undefined;\n if (shared && isExecutableTestClient(shared) && testClientMatchesVersionOptions(shared, agentUrl, options)) {\n return { client: shared, reusedShared: true };\n }\n return { client: createTestClient(agentUrl, options.protocol || 'mcp', options), reusedShared: false };\n}\n\nfunction isExecutableTestClient(client: unknown): client is TestClient {\n if (client == null || typeof client !== 'object') return false;\n const candidate = client as Record<string, unknown>;\n if (typeof candidate['executeTask'] === 'function' || typeof candidate['resetContext'] === 'function') return true;\n return Object.entries(candidate).some(([key, value]) => key !== 'getAgentInfo' && typeof value === 'function');\n}\n\nfunction testClientMatchesVersionOptions(client: TestClient, agentUrl: string, options: TestOptions): boolean {\n const effectiveOptions = withTestKitAuthDefaults(options);\n const meta = (client as unknown as { [TEST_CLIENT_VERSION_OPTIONS]?: TestClientVersionOptions })[\n TEST_CLIENT_VERSION_OPTIONS\n ];\n const expectedAuthMode = authReuseMode(effectiveOptions);\n const expectedRequestScopeMode = requestScopeReuseMode(effectiveOptions);\n const expectedRequestSigningMode = requestSigningReuseMode(effectiveOptions.functional_request_signing);\n if (!meta) {\n return (\n expectedRequestSigningMode === undefined &&\n effectiveOptions.adcpVersion === undefined &&\n effectiveOptions.versionEnvelope === undefined &&\n effectiveOptions.transport === undefined\n );\n }\n const expectedAdcpVersion = effectiveOptions.adcpVersion ?? ADCP_VERSION;\n const expectedWireAdcpVersion = effectiveOptions.wireAdcpVersion;\n const expectedVersionEnvelope = effectiveOptions.versionEnvelope ?? 'auto';\n return (\n meta.agentUrl === agentUrl &&\n meta.protocol === (effectiveOptions.protocol ?? 'mcp') &&\n meta.adcpVersion === expectedAdcpVersion &&\n meta.wireAdcpVersion === expectedWireAdcpVersion &&\n meta.versionEnvelope === expectedVersionEnvelope &&\n meta.strictResponseSchemaValidation === (effectiveOptions.strictResponseSchemaValidation !== false) &&\n meta.authMode === expectedAuthMode &&\n meta.requestScopeMode === expectedRequestScopeMode &&\n meta.requestSigningMode === expectedRequestSigningMode &&\n meta.fetchFn === effectiveOptions.transport?.trustedFetchFn &&\n meta.allowPrivateIp === effectiveOptions.transport?.allowPrivateIp &&\n meta.maxResponseBytes === effectiveOptions.transport?.maxResponseBytes &&\n meta.requestTimeoutMs === effectiveOptions.transport?.requestTimeoutMs\n );\n}\n\nfunction withTestKitAuthDefaults(options: TestOptions): TestOptions {\n if (options.auth) return options;\n const apiKey = options.test_kit?.auth?.api_key;\n if (typeof apiKey === 'string' && apiKey.length > 0) {\n return { ...options, auth: { type: 'bearer', token: apiKey } };\n }\n\n const basic = options.test_kit?.auth?.basic;\n if (!basic) return options;\n if (\n typeof basic.username === 'string' &&\n basic.username.length > 0 &&\n typeof basic.password === 'string' &&\n basic.password.length > 0\n ) {\n return { ...options, auth: { type: 'basic', username: basic.username, password: basic.password } };\n }\n if (typeof basic.credentials === 'string') {\n const splitAt = basic.credentials.indexOf(':');\n if (splitAt > 0) {\n return {\n ...options,\n auth: {\n type: 'basic',\n username: basic.credentials.slice(0, splitAt),\n password: basic.credentials.slice(splitAt + 1),\n },\n };\n }\n }\n return options;\n}\n\nfunction authReuseMode(options: TestOptions): string | undefined {\n return options.auth?.type;\n}\n\nfunction requestScopeReuseMode(options: TestOptions): string | undefined {\n const headers = options.headers\n ? Object.fromEntries(\n Object.entries(options.headers)\n .map(([name, value]) => [name.toLowerCase(), value] as const)\n .sort(([a], [b]) => a.localeCompare(b))\n )\n : undefined;\n if (!options.auth && !headers && !options.test_session_id && !options.userAgent) return undefined;\n return testClientScopeDisambiguator(\n JSON.stringify({\n auth: options.auth,\n headers,\n testSessionId: options.test_session_id,\n userAgent: options.userAgent,\n })\n );\n}\n\nfunction testClientScopeDisambiguator(value: string): string {\n return Buffer.from(hkdfSync('sha256', value, TEST_CLIENT_SCOPE_SALT, 'adcp-test-client-cache', 8)).toString('hex');\n}\n\nfunction requestSigningReuseMode(config: AgentRequestSigningConfig | undefined): string | undefined {\n if (!config) return undefined;\n const kind = config.kind === 'provider' ? 'provider' : 'inline';\n const identity =\n config.kind === 'provider'\n ? {\n algorithm: config.provider.algorithm,\n keyid: config.provider.keyid,\n adcpUse: config.provider.adcpUse,\n fingerprint: config.provider.fingerprint,\n }\n : { algorithm: config.alg, keyid: config.kid, privateKey: config.private_key };\n const fingerprint = createHmac('sha256', '')\n .update(\n JSON.stringify({\n identity,\n agentUrl: config.agent_url,\n jwksUri: config.jwks_uri,\n signSupported: config.sign_supported === true,\n alwaysSign: config.always_sign ?? [],\n })\n )\n .digest('hex')\n .slice(0, 16);\n return `${kind}:${fingerprint}`;\n}\n\n/**\n * Return a pre-discovered profile from options (set by comply()) or discover fresh.\n */\nexport async function getOrDiscoverProfile(\n client: TestClient,\n options: TestOptions\n): Promise<{ profile: AgentProfile; step: TestStepResult }> {\n if (options._profile) {\n seedTestClientSigningCapability(client, options._profile, options.adcpVersion);\n return {\n profile: options._profile,\n step: { step: 'Discover agent capabilities', passed: true, duration_ms: 0 },\n };\n }\n return discoverAgentProfile(client, options.signal, options.adcpVersion);\n}\n\n/**\n * Reuse the already-observed capability advertisement for signing decisions.\n * This avoids a second discovery call whose failure could otherwise downgrade\n * a functional compliance dispatch to unsigned.\n */\nexport function seedTestClientSigningCapability(client: TestClient, profile: AgentProfile, adcpVersion?: string): void {\n const raw = profile.raw_capabilities;\n if (!raw || typeof raw !== 'object') return;\n const clientAccess = client as unknown as {\n getAgent?: TestClient['getAgent'];\n getAdcpVersion?: TestClient['getAdcpVersion'];\n };\n if (typeof clientAccess.getAgent !== 'function') return;\n const agent = clientAccess.getAgent.call(client);\n const meta = (client as unknown as { [TEST_CLIENT_VERSION_OPTIONS]?: TestClientVersionOptions })[\n TEST_CLIENT_VERSION_OPTIONS\n ];\n const effectiveVersion =\n meta?.wireAdcpVersion ??\n meta?.adcpVersion ??\n (typeof clientAccess.getAdcpVersion === 'function' ? clientAccess.getAdcpVersion.call(client) : undefined) ??\n adcpVersion;\n const signingContext = buildAgentSigningContext(agent, { adcpVersion: effectiveVersion });\n if (!signingContext) return;\n signingContext.cache.set(signingContext.capabilityCacheKey, {\n requestSigning: (raw as { request_signing?: VerifierCapability }).request_signing,\n adcpVersion: profile.adcp_major_versions?.[0],\n fetchedAt: Math.floor(Date.now() / 1000),\n });\n}\n\n/**\n * Run a single test step with timing\n */\n/**\n * Race a promise against an AbortSignal. Adopted by `discoverAgentProfile`\n * so the comply pipeline's timeout actually bounds discovery wall-clock —\n * the underlying transport's `getAgentInfo()` doesn't accept a signal\n * (public API), so we resolve the wrapper promise on abort and let the\n * orphaned in-flight request finish on its own. (adcp-client#1612)\n *\n * Throws the signal's reason on abort.\n *\n * **SECURITY (security-reviewer follow-up on #1612):** the orphaned\n * promise's `.then` handlers below stay attached until the underlying\n * transport call settles. The resolved value `v` carries an authenticated\n * agent response — `getAgentInfo()` and `getAdcpCapabilities()` round-trip\n * through the bearer-token transport, so the promise body holds the wire\n * response in memory until GC'd. **Do not log `v` from inside this\n * resolver** (or any future `console.error` / telemetry hook on the\n * orphaned path) — the buyer has already moved on past the abort, and\n * logging here would leak agent-side data after the caller stopped\n * trusting it. The early `resolve(v)` is intentionally a no-op on the\n * already-rejected race-promise; `v` becomes unreferenced and GC-eligible\n * the moment this `.then` returns.\n */\nfunction raceWithSignal<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) {\n return Promise.reject(signal.reason ?? new Error('aborted'));\n }\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(signal.reason ?? new Error('aborted'));\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n v => {\n signal.removeEventListener('abort', onAbort);\n // INTENTIONAL: no-op on an already-rejected race-promise. Do NOT\n // log `v` here — see security note in the JSDoc above.\n resolve(v);\n },\n e => {\n signal.removeEventListener('abort', onAbort);\n // INTENTIONAL: no-op on an already-rejected race-promise. Do NOT\n // log `e` here either — `Error.message` from a transport rejection\n // can carry an echoed response body, see security note above.\n reject(e);\n }\n );\n });\n}\n\n/**\n * Result of {@link runStep}. The optional `caughtError` carries the raw\n * thrown value (typed `unknown`, narrow via `instanceof` at the call site)\n * so callers can pattern-match on typed exceptions like\n * `ResponseSchemaValidationError` without losing the freeform string\n * representation on `step.error`. Pre-existing callers that only consume\n * `result` and `step` are unaffected.\n *\n * Spec: adcp-client#1709 (storyboard runner attributes Zod rejects to\n * the canonical `response_schema` validation entry by detecting the typed\n * error here).\n */\nexport interface RunStepOutcome<T> {\n result?: T;\n step: TestStepResult;\n caughtError?: unknown;\n}\n\nexport async function runStep<T>(\n stepName: string,\n taskName: string | undefined,\n fn: () => Promise<T>\n): Promise<RunStepOutcome<T>> {\n const start = Date.now();\n try {\n const result = await fn();\n const duration = Date.now() - start;\n return {\n result,\n step: {\n step: stepName,\n task: taskName,\n passed: true,\n duration_ms: duration,\n },\n };\n } catch (error) {\n const duration = Date.now() - start;\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n step: {\n step: stepName,\n task: taskName,\n passed: false,\n duration_ms: duration,\n error: errorMessage,\n },\n caughtError: error,\n };\n }\n}\n\nfunction describeVersionUnsupported(result: unknown, requestedVersion: string | undefined): string | undefined {\n if (!result || typeof result !== 'object') return undefined;\n const record = result as Record<string, unknown>;\n const dataRecord =\n record.data && typeof record.data === 'object' && !Array.isArray(record.data)\n ? (record.data as Record<string, unknown>)\n : undefined;\n const dataError =\n dataRecord?.adcp_error && typeof dataRecord.adcp_error === 'object' ? dataRecord.adcp_error : undefined;\n const adcpError = record.adcpError ?? record.adcp_error ?? dataError;\n if (!adcpError || typeof adcpError !== 'object') return undefined;\n const adcpErrorRecord = adcpError as Record<string, unknown>;\n if (adcpErrorRecord.code !== 'VERSION_UNSUPPORTED') return undefined;\n\n const details = extractVersionUnsupportedDetails(adcpErrorRecord) ?? extractVersionUnsupportedDetails(record.data);\n const requested = details?.requested_version ?? requestedVersion;\n const supported = details?.supported_versions;\n const requestedText = requested ? `requested ${JSON.stringify(requested)}` : 'requested version is unsupported';\n const supportedText = supported?.length\n ? `; seller supports ${supported.map(version => JSON.stringify(version)).join(', ')}`\n : '; seller did not report supported_versions';\n return `VERSION_UNSUPPORTED: ${requestedText}${supportedText}`;\n}\n\n/**\n * Discover agent profile - what capabilities does this agent have?\n *\n * When the agent exposes `get_adcp_capabilities`, its response populates\n * `supported_protocols` + `specialisms` on the profile so the compliance\n * runner can select domain and specialism bundles.\n *\n * Pass `signal` for hard external cancellation. `comply()` deliberately does\n * not pass its soft `timeout_ms` storyboard-start budget here; that budget\n * stops new storyboards after discovery instead of aborting an active run.\n */\nexport async function discoverAgentProfile(\n client: TestClient,\n signal?: AbortSignal,\n /** Compliance/schema line selected by the caller. Defaults to the client pin. */\n schemaAdcpVersion?: string\n): Promise<{ profile: AgentProfile; step: TestStepResult }> {\n const { result: agentInfo, step } = await runStep('Discover agent capabilities', 'getAgentInfo', () =>\n raceWithSignal(client.getAgentInfo({ signal }), signal)\n );\n\n const profile: AgentProfile = {\n name: agentInfo?.name || 'Unknown',\n tools: agentInfo?.tools?.map((t: { name: string }) => t.name) || [],\n };\n\n if (agentInfo) {\n step.details = `Agent: ${profile.name}, Tools: ${profile.tools.length}`;\n step.response_preview = JSON.stringify(\n {\n name: profile.name,\n tools: profile.tools,\n },\n null,\n 2\n );\n }\n\n if (profile.tools.includes('get_adcp_capabilities')) {\n try {\n const caps = (await raceWithSignal(client.getAdcpCapabilities({}, undefined, { signal }), signal)) as TaskResult;\n const versionUnsupported = describeVersionUnsupported(caps, schemaAdcpVersion ?? client.getAdcpVersion?.());\n if (versionUnsupported) {\n // Some transports return AdCP error envelopes as successful tool data.\n // Detect the protocol error before validating/parsing it as a\n // capabilities success response, or best-effort parsing will produce\n // a synthetic v2 profile from the error object.\n profile.capabilities_probe_error = versionUnsupported;\n step.passed = false;\n step.error = versionUnsupported;\n } else if (caps?.data) {\n profile.raw_capabilities = caps.data;\n const validation = validateIncomingResponse(\n 'get_adcp_capabilities',\n caps.data,\n 'strict',\n undefined,\n schemaAdcpVersion ?? client.getAdcpVersion()\n );\n if (!validation.valid) {\n profile.capabilities_schema_issues = validation.issues.map(issue => ({\n pointer: issue.pointer,\n message: issue.message,\n }));\n }\n\n // Even a schema-invalid response can contain enough trustworthy\n // discriminators to select the storyboards the seller claimed. Keep\n // parsing best-effort so the preflight notice augments downstream\n // failures instead of suppressing them.\n const parsed = parseCapabilitiesResponse(caps.data);\n profile.adcp_version = parsed.version;\n profile.adcp_major_versions = parsed.majorVersions;\n if (parsed.supportedVersions !== undefined) profile.adcp_supported_versions = parsed.supportedVersions;\n if (parsed.buildVersion !== undefined) profile.adcp_build_version = parsed.buildVersion;\n profile.supported_protocols = parsed.protocols;\n profile.supports_governance = parsed.protocols.includes('governance');\n profile.supports_si = parsed.protocols.includes('sponsored_intelligence');\n const specialisms = (caps.data as { specialisms?: unknown }).specialisms;\n if (Array.isArray(specialisms)) {\n profile.specialisms = specialisms.filter((s): s is string => typeof s === 'string');\n }\n const libVersion = (caps.data as Record<string, unknown>).library_version;\n if (typeof libVersion === 'string') profile.library_version = libVersion;\n }\n if (!versionUnsupported && (!caps?.success || !caps?.data) && !profile.capabilities_schema_issues?.length) {\n profile.capabilities_probe_error = caps?.error || 'get_adcp_capabilities returned no data';\n }\n } catch (err) {\n // Agent advertises the tool but the call failed. Don't silently downgrade —\n // record the failure so the compliance report shows why only universal ran.\n profile.capabilities_probe_error = (err as Error)?.message || String(err);\n }\n }\n\n seedTestClientSigningCapability(client, profile, schemaAdcpVersion);\n return { profile, step };\n}\n\n/**\n * Discover what channels, pricing models, formats the agent supports\n * by calling get_products and analyzing the response\n */\nexport async function discoverAgentCapabilities(\n client: TestClient,\n profile: AgentProfile,\n options: TestOptions\n): Promise<{ capabilities: Partial<AgentProfile>; steps: TestStepResult[] }> {\n const steps: TestStepResult[] = [];\n const capabilities: Partial<AgentProfile> = {};\n\n if (!profile.tools.includes('get_products')) {\n return { capabilities, steps };\n }\n\n const brief = options.brief || 'Show me all available advertising products across all channels';\n const getProductsParams: Record<string, unknown> = {\n buying_mode: 'brief',\n brief,\n brand: resolveBrand(options),\n };\n const { result, step } = await runStep<TaskResult>(\n 'Discover products for capability analysis',\n 'get_products',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- bypasses strict request typing\n async () => client.getProducts(getProductsParams as any) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const responseData = result.data as GetProductsResponse;\n const products: Product[] = responseData.products ?? [];\n\n // Extract unique channels\n const channels = new Set<string>();\n const pricingModels = new Set<string>();\n const formatIds = new Set<string>();\n const deliveryTypes = new Set<string>();\n\n for (const product of products) {\n // Channels from product\n if (product.channels) {\n for (const ch of product.channels) {\n channels.add(ch);\n }\n }\n // Delivery type\n if (product.delivery_type) {\n deliveryTypes.add(product.delivery_type);\n }\n // Pricing models\n if (product.pricing_options) {\n for (const po of product.pricing_options) {\n if (po.pricing_model) pricingModels.add(po.pricing_model);\n }\n }\n // Format IDs\n if (product.format_ids) {\n for (const fid of product.format_ids) {\n const id = typeof fid === 'string' ? fid : fid.id;\n if (id) formatIds.add(id);\n }\n }\n }\n\n capabilities.channels = Array.from(channels);\n capabilities.pricing_models = Array.from(pricingModels);\n capabilities.format_ids = Array.from(formatIds);\n capabilities.delivery_types = Array.from(deliveryTypes);\n\n step.details = `Found ${products.length} products across ${channels.size} channel(s), ${pricingModels.size} pricing model(s)`;\n step.response_preview = JSON.stringify(\n {\n products_count: products.length,\n channels: capabilities.channels,\n pricing_models: capabilities.pricing_models,\n delivery_types: capabilities.delivery_types,\n format_count: capabilities.format_ids?.length,\n },\n null,\n 2\n );\n step.observation_data = { products_count: products.length, channels: capabilities.channels };\n } else if (result && !result.success) {\n step.passed = false;\n step.error = result.error || 'get_products failed';\n }\n\n steps.push(step);\n return { capabilities, steps };\n}\n\n/**\n * Discover creative formats from a creative agent\n */\nexport async function discoverCreativeFormats(\n client: TestClient,\n profile: AgentProfile\n): Promise<{ formats: AgentProfile['supported_formats']; step: TestStepResult }> {\n const formats: AgentProfile['supported_formats'] = [];\n\n if (!profile.tools.includes('list_creative_formats')) {\n return {\n formats,\n step: {\n step: 'Discover creative formats',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support list_creative_formats',\n },\n };\n }\n\n const { result, step } = await runStep<TaskResult>(\n 'Discover creative formats',\n 'list_creative_formats',\n async () => client.listCreativeFormatsLegacy({}) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const responseData = result.data as ListCreativeFormatsResponse;\n const rawFormats: Format[] = responseData.formats ?? [];\n const deprecatedFormats: string[] = [];\n\n for (const format of rawFormats) {\n const formatInfo: NonNullable<AgentProfile['supported_formats']>[0] = {\n format_id: format.format_id,\n name: format.name,\n required_assets: [],\n optional_assets: [],\n };\n\n // Check for deprecated assets_required usage\n if (usesDeprecatedAssetsField(format as unknown as Parameters<typeof usesDeprecatedAssetsField>[0])) {\n const displayId = typeof formatInfo.format_id === 'object' ? formatInfo.format_id.id : formatInfo.format_id;\n deprecatedFormats.push(displayId);\n }\n\n // Extract asset requirements from format spec using format-assets utilities\n // This handles both v2.6 `assets` and deprecated `assets_required` fields\n const formatAssets = getFormatAssets(format as unknown as Parameters<typeof getFormatAssets>[0]);\n for (const asset of formatAssets) {\n const assetId = asset.item_type === 'individual' ? asset.asset_id : asset.asset_group_id;\n\n if (asset.required) {\n formatInfo.required_assets?.push(assetId);\n } else {\n formatInfo.optional_assets?.push(assetId);\n }\n }\n\n formats.push(formatInfo);\n }\n\n step.details = `Found ${formats.length} format(s)`;\n step.response_preview = JSON.stringify(\n {\n format_count: formats.length,\n sample_formats: formats.slice(0, 3).map(f => ({\n id: f.format_id,\n name: f.name,\n required_assets: f.required_assets?.length || 0,\n })),\n },\n null,\n 2\n );\n\n // Add deprecation warnings if any formats use assets_required\n if (deprecatedFormats.length > 0) {\n step.warnings = [\n `⚠️ DEPRECATION: ${deprecatedFormats.length} format(s) use 'assets_required' field which is deprecated and will be removed in a future version. Please migrate to the 'assets' field instead. (adcp-client 3.6.0+)`,\n ];\n logger.warn(\n { deprecated_formats: deprecatedFormats },\n `Agent uses deprecated 'assets_required' field in ${deprecatedFormats.length} format(s). Migrate to 'assets' field.`\n );\n }\n } else if (result && !result.success) {\n step.passed = false;\n step.error = result.error || 'list_creative_formats failed';\n }\n\n return { formats, step };\n}\n\n/**\n * Discover signals from a signals agent\n */\nexport async function discoverSignals(\n client: TestClient,\n profile: AgentProfile,\n options: TestOptions\n): Promise<{\n signals: AgentProfile['supported_signals'];\n rawSignals: GetSignalsResponse['signals'];\n step: TestStepResult;\n schemaStep?: TestStepResult;\n}> {\n const signals: AgentProfile['supported_signals'] = [];\n let rawSignals: GetSignalsResponse['signals'] = [];\n\n if (!profile.tools.includes('get_signals')) {\n return {\n signals,\n rawSignals,\n step: {\n step: 'Discover signals',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support get_signals',\n },\n };\n }\n\n const { result, step } = await runStep<TaskResult>(\n 'Discover available signals',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Show me all available audience signals and segments',\n }) as Promise<TaskResult>\n );\n\n let schemaStep: TestStepResult | undefined;\n\n if (result?.success && result?.data) {\n schemaStep = validateResponseSchema('get_signals', result.data);\n const responseData = result.data as GetSignalsResponse;\n rawSignals = responseData.signals ?? [];\n\n for (const signal of rawSignals) {\n const signalData = signal as {\n signal_agent_segment_id?: unknown;\n signal_ref?: unknown;\n name?: unknown;\n signal_type?: unknown;\n type?: unknown;\n };\n let signalId: string | undefined;\n if (typeof signalData.signal_agent_segment_id === 'string') {\n signalId = signalData.signal_agent_segment_id;\n } else if (typeof signalData.signal_ref === 'string') {\n signalId = signalData.signal_ref;\n } else if (signalData.signal_ref != null) {\n // Summary-only convenience for the test report; rawSignals above\n // preserves the seller's canonical signal_ref object.\n signalId = JSON.stringify(signalData.signal_ref);\n }\n if (!signalId) continue;\n signals.push({\n signal_id: signalId,\n name: typeof signalData.name === 'string' ? signalData.name : undefined,\n type:\n typeof signalData.signal_type === 'string'\n ? signalData.signal_type\n : typeof signalData.type === 'string'\n ? signalData.type\n : undefined,\n });\n }\n\n step.details = `Found ${signals.length} signal(s)`;\n step.response_preview = JSON.stringify(\n {\n signal_count: signals.length,\n signal_types: [...new Set(signals.map(s => s.type).filter(Boolean))],\n sample_signals: signals.slice(0, 5).map(s => ({\n id: s.signal_id,\n name: s.name,\n type: s.type,\n })),\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n step.passed = false;\n step.error = result.error || 'get_signals failed';\n }\n\n return { signals, rawSignals, step, schemaStep };\n}\n\n/**\n * Validate response data against the AdCP Zod schema for a tool.\n * Returns a TestStepResult indicating pass/fail with details on schema violations.\n *\n * For union schemas (success | error responses), Zod's top-level error is the\n * unhelpful \"(root): Invalid input\". This function detects that case and\n * reports per-variant errors instead, picking the variant with the fewest\n * issues (the closest match) so the developer sees actionable field names.\n *\n * Violations are split into two categories so remediation guidance differs\n * appropriately (set the field vs. fix the value):\n * - `required` — a required field is absent from the response. Zod emits\n * `invalid_type` with `received: 'undefined'` for this case; we re-tag\n * it as `required` and report it as a missing field.\n * - constraint keyword (`minimum`, `maximum`, `enum`, `format`, …) — the\n * field is present but violates a JSON Schema keyword constraint.\n */\nexport function validateResponseSchema(toolName: string, data: unknown, responseAdcpVersion?: string): TestStepResult {\n const schema = TOOL_RESPONSE_SCHEMAS[toolName];\n if (!schema) {\n return {\n step: `Schema validation: ${toolName}`,\n passed: true,\n duration_ms: 0,\n details: `No response schema available for ${toolName}`,\n warnings: [`No Zod schema registered for \"${toolName}\" — validation skipped`],\n };\n }\n\n // 3.0.x back-compat: synthesize envelope `status` for legacy peers so\n // strict 3.1 validators don't reject otherwise-conformant 3.0 wire\n // responses. See `utils/envelope-status-compat.ts`.\n const compatData =\n data && typeof data === 'object' && !Array.isArray(data)\n ? injectLegacyEnvelopeStatus(data as Record<string, unknown>, { toolName })\n : data;\n const result = schema.safeParse(prepareResponseForSchemaValidation(toolName, compatData, responseAdcpVersion));\n if (result.success) {\n return {\n step: `Schema validation: ${toolName}`,\n passed: true,\n duration_ms: 0,\n details: `Response matches ${toolName} schema`,\n };\n }\n\n let violations: SchemaViolation[] = result.error.issues.map(i => {\n const path = i.path.length > 0 ? i.path.join('.') : '(root)';\n return { path, message: i.message, code: i.code };\n });\n\n // Union schemas produce \"(root): Invalid input\" when no variant matches.\n // Try each variant individually and report the closest match's errors.\n const first = violations[0];\n const isUnionError = violations.length === 1 && first && first.path === '(root)' && first.code === 'invalid_union';\n\n if (isUnionError) {\n const betterErrors = getBestUnionErrors(schema, data);\n if (betterErrors && betterErrors.length > 0) {\n violations = betterErrors;\n }\n }\n\n const classified = violations.map(classifyViolation);\n const missing = classified.filter(v => v.kind === 'missing');\n const constraint = classified.filter(v => v.kind === 'constraint');\n\n const parts: string[] = [];\n if (missing.length > 0) {\n parts.push(`Response missing required fields: ${missing.map(v => v.json_pointer).join(', ')}`);\n }\n if (constraint.length > 0) {\n parts.push(\n `Response constraint violations: ${constraint\n .map(v => `${v.json_pointer} (${v.keyword}): ${v.message}`)\n .join('; ')}`\n );\n }\n\n return {\n step: `Schema validation: ${toolName}`,\n passed: false,\n duration_ms: 0,\n error: parts.join(' | '),\n response_preview: JSON.stringify({ violations: classified }, null, 2),\n };\n}\n\n/**\n * Classify a Zod-flavored schema violation as either a missing required field\n * or a constraint violation (with the failed JSON Schema keyword). Adds a\n * JSON Pointer (`/foo/0/bar`) so downstream tooling can locate the field\n * without re-parsing dot paths.\n */\nfunction classifyViolation(v: SchemaViolation): {\n kind: 'missing' | 'constraint';\n json_pointer: string;\n keyword: string;\n message: string;\n code: SchemaViolation['code'];\n} {\n const segments = v.path === '(root)' ? [] : v.path.split('.');\n const json_pointer = '/' + segments.map(s => s.replace(/~/g, '~0').replace(/\\//g, '~1')).join('/');\n\n // Zod emits `invalid_type` with `received: 'undefined'` for missing required\n // fields. The `code` alone is ambiguous (`invalid_type` also covers wrong-\n // type-but-present), so we sniff the message for the canonical Zod wording.\n const isMissing = v.code === 'invalid_type' && /received `?undefined`?/i.test(v.message);\n if (isMissing) {\n return { kind: 'missing', json_pointer, keyword: 'required', message: v.message, code: v.code };\n }\n\n return {\n kind: 'constraint',\n json_pointer,\n keyword: zodCodeToKeyword(v.code),\n message: v.message,\n code: v.code,\n };\n}\n\n/**\n * Map a Zod error code to the equivalent JSON Schema keyword so downstream\n * tooling (and humans reading the report) see the standard vocabulary\n * (`minimum`, `enum`, `format`, …) instead of Zod-specific names.\n */\nfunction zodCodeToKeyword(code: SchemaViolation['code']): string {\n switch (code) {\n case 'invalid_type':\n return 'type';\n case 'invalid_value':\n return 'enum';\n case 'too_small':\n return 'minimum';\n case 'too_big':\n return 'maximum';\n case 'invalid_format':\n return 'format';\n case 'unrecognized_keys':\n return 'additionalProperties';\n case 'invalid_union':\n return 'oneOf';\n case 'not_multiple_of':\n return 'multipleOf';\n default:\n return code;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"comply.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/compliance/comply.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"comply.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/compliance/comply.ts"],"names":[],"mappings":"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"}
@@ -56,6 +56,7 @@ var import_oauth_metadata_graph = require('../storyboard/oauth-metadata-graph/in
56
56
  var import_version = require('../../version.js');
57
57
  var import_validations = require('../storyboard/validations.js');
58
58
  var import_address_guards = require('../../net/address-guards.js');
59
+ var import_functional_dispatch = require('../storyboard/request-signing/functional-dispatch.js');
59
60
  (0, import_default_invariants.registerDefaultInvariants)();
60
61
  const TRACK_ORDER = [
61
62
  "core",
@@ -807,6 +808,10 @@ async function complyImpl(agentUrl, options) {
807
808
  sandbox: testOptions.sandbox !== false,
808
809
  test_session_id: testOptions.test_session_id || `comply-${Date.now()}`
809
810
  });
811
+ effectiveOptions = (0, import_functional_dispatch.applyFunctionalRequestSigning)(effectiveOptions, {
812
+ ...complianceDir !== void 0 && { complianceDir },
813
+ version: complianceIndex.adcp_version
814
+ });
810
815
  signal?.throwIfAborted();
811
816
  const allObservations = [];
812
817
  let discoveryOptions = effectiveOptions;
@@ -838,6 +843,7 @@ async function complyImpl(agentUrl, options) {
838
843
  ...testOptions.versionEnvelope !== void 0 && { callerVersionEnvelope: testOptions.versionEnvelope }
839
844
  });
840
845
  const client = discoveryOptions === effectiveOptions ? discoveryClient : (0, import_client.createTestClient)(agentUrl, effectiveOptions.protocol ?? "mcp", effectiveOptions);
846
+ (0, import_client.seedTestClientSigningCapability)(client, profile, complianceIndex.adcp_version);
841
847
  effectiveOptions._client = client;
842
848
  effectiveOptions._profile = profile;
843
849
  if (profileStep.passed) {