@adcp/sdk 12.1.1 → 13.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/README.md +19 -3
  2. package/bin/adcp-fuzz.js +3 -1
  3. package/dist/lib/adapters/content-standards-adapter.d.mts +9 -9
  4. package/dist/lib/adapters/content-standards-adapter.d.ts +9 -9
  5. package/dist/lib/adapters/content-standards-adapter.d.ts.map +1 -1
  6. package/dist/lib/adapters/content-standards-adapter.js +22 -22
  7. package/dist/lib/adapters/content-standards-adapter.js.map +1 -1
  8. package/dist/lib/adapters/content-standards-adapter.mjs +18 -18
  9. package/dist/lib/adapters/content-standards-adapter.mjs.map +1 -1
  10. package/dist/lib/adapters/index.d.mts +2 -2
  11. package/dist/lib/adapters/index.d.ts +2 -2
  12. package/dist/lib/adapters/index.d.ts.map +1 -1
  13. package/dist/lib/adapters/index.js +10 -10
  14. package/dist/lib/adapters/index.js.map +1 -1
  15. package/dist/lib/adapters/index.mjs +9 -9
  16. package/dist/lib/adapters/index.mjs.map +1 -1
  17. package/dist/lib/auth/oauth/provider-cache.d.mts +7 -0
  18. package/dist/lib/auth/oauth/provider-cache.d.ts +8 -0
  19. package/dist/lib/auth/oauth/provider-cache.d.ts.map +1 -0
  20. package/dist/lib/auth/oauth/provider-cache.js +44 -0
  21. package/dist/lib/auth/oauth/provider-cache.js.map +1 -0
  22. package/dist/lib/auth/oauth/provider-cache.mjs +19 -0
  23. package/dist/lib/auth/oauth/provider-cache.mjs.map +1 -0
  24. package/dist/lib/conformance/invariants/uniformError.js +1 -1
  25. package/dist/lib/conformance/invariants/uniformError.js.map +1 -1
  26. package/dist/lib/conformance/invariants/uniformError.mjs +1 -1
  27. package/dist/lib/conformance/invariants/uniformError.mjs.map +1 -1
  28. package/dist/lib/conformance/runners.js +1 -1
  29. package/dist/lib/conformance/runners.js.map +1 -1
  30. package/dist/lib/conformance/runners.mjs +1 -1
  31. package/dist/lib/conformance/runners.mjs.map +1 -1
  32. package/dist/lib/conformance/seeder.js +5 -5
  33. package/dist/lib/conformance/seeder.js.map +1 -1
  34. package/dist/lib/conformance/seeder.mjs +5 -5
  35. package/dist/lib/conformance/seeder.mjs.map +1 -1
  36. package/dist/lib/core/ADCPMultiAgentClient.d.mts +26 -29
  37. package/dist/lib/core/ADCPMultiAgentClient.d.ts +26 -29
  38. package/dist/lib/core/ADCPMultiAgentClient.d.ts.map +1 -1
  39. package/dist/lib/core/ADCPMultiAgentClient.js +27 -19
  40. package/dist/lib/core/ADCPMultiAgentClient.js.map +1 -1
  41. package/dist/lib/core/ADCPMultiAgentClient.mjs +27 -19
  42. package/dist/lib/core/ADCPMultiAgentClient.mjs.map +1 -1
  43. package/dist/lib/core/AgentClient.d.mts +148 -138
  44. package/dist/lib/core/AgentClient.d.ts +148 -138
  45. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  46. package/dist/lib/core/AgentClient.js +174 -85
  47. package/dist/lib/core/AgentClient.js.map +1 -1
  48. package/dist/lib/core/AgentClient.mjs +174 -85
  49. package/dist/lib/core/AgentClient.mjs.map +1 -1
  50. package/dist/lib/core/AsyncHandler.d.mts +18 -16
  51. package/dist/lib/core/AsyncHandler.d.ts +18 -16
  52. package/dist/lib/core/AsyncHandler.d.ts.map +1 -1
  53. package/dist/lib/core/AsyncHandler.js +22 -1
  54. package/dist/lib/core/AsyncHandler.js.map +1 -1
  55. package/dist/lib/core/AsyncHandler.mjs +22 -1
  56. package/dist/lib/core/AsyncHandler.mjs.map +1 -1
  57. package/dist/lib/core/ConversationTypes.d.mts +6 -2
  58. package/dist/lib/core/ConversationTypes.d.ts +6 -2
  59. package/dist/lib/core/ConversationTypes.d.ts.map +1 -1
  60. package/dist/lib/core/ConversationTypes.js.map +1 -1
  61. package/dist/lib/core/CreativeAgentClient.d.mts +41 -17
  62. package/dist/lib/core/CreativeAgentClient.d.ts +41 -17
  63. package/dist/lib/core/CreativeAgentClient.d.ts.map +1 -1
  64. package/dist/lib/core/CreativeAgentClient.js +39 -12
  65. package/dist/lib/core/CreativeAgentClient.js.map +1 -1
  66. package/dist/lib/core/CreativeAgentClient.mjs +39 -12
  67. package/dist/lib/core/CreativeAgentClient.mjs.map +1 -1
  68. package/dist/lib/core/SingleAgentClient.d.mts +127 -50
  69. package/dist/lib/core/SingleAgentClient.d.ts +127 -50
  70. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  71. package/dist/lib/core/SingleAgentClient.js +1617 -177
  72. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  73. package/dist/lib/core/SingleAgentClient.mjs +1627 -177
  74. package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
  75. package/dist/lib/core/TaskExecutor.d.mts +9 -0
  76. package/dist/lib/core/TaskExecutor.d.ts +9 -0
  77. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  78. package/dist/lib/core/TaskExecutor.js +136 -43
  79. package/dist/lib/core/TaskExecutor.js.map +1 -1
  80. package/dist/lib/core/TaskExecutor.mjs +136 -43
  81. package/dist/lib/core/TaskExecutor.mjs.map +1 -1
  82. package/dist/lib/index.d.mts +111 -17
  83. package/dist/lib/index.d.ts +111 -17
  84. package/dist/lib/index.d.ts.map +1 -1
  85. package/dist/lib/index.js +94 -94
  86. package/dist/lib/index.js.map +1 -1
  87. package/dist/lib/index.mjs +93 -94
  88. package/dist/lib/index.mjs.map +1 -1
  89. package/dist/lib/protocols/index.d.ts.map +1 -1
  90. package/dist/lib/protocols/index.js +6 -15
  91. package/dist/lib/protocols/index.js.map +1 -1
  92. package/dist/lib/protocols/index.mjs +6 -16
  93. package/dist/lib/protocols/index.mjs.map +1 -1
  94. package/dist/lib/protocols/mcp-modern.d.ts.map +1 -1
  95. package/dist/lib/protocols/mcp-modern.js +87 -12
  96. package/dist/lib/protocols/mcp-modern.js.map +1 -1
  97. package/dist/lib/protocols/mcp-modern.mjs +89 -12
  98. package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
  99. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  100. package/dist/lib/server/create-adcp-server.d.mts +6 -0
  101. package/dist/lib/server/create-adcp-server.d.ts +6 -0
  102. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  103. package/dist/lib/server/create-adcp-server.js +295 -48
  104. package/dist/lib/server/create-adcp-server.js.map +1 -1
  105. package/dist/lib/server/create-adcp-server.mjs +301 -50
  106. package/dist/lib/server/create-adcp-server.mjs.map +1 -1
  107. package/dist/lib/server/decisioning/assembly-helpers.d.mts +27 -13
  108. package/dist/lib/server/decisioning/assembly-helpers.d.ts +27 -13
  109. package/dist/lib/server/decisioning/assembly-helpers.d.ts.map +1 -1
  110. package/dist/lib/server/decisioning/assembly-helpers.js +136 -14
  111. package/dist/lib/server/decisioning/assembly-helpers.js.map +1 -1
  112. package/dist/lib/server/decisioning/assembly-helpers.mjs +134 -13
  113. package/dist/lib/server/decisioning/assembly-helpers.mjs.map +1 -1
  114. package/dist/lib/server/decisioning/index.d.mts +13 -12
  115. package/dist/lib/server/decisioning/index.d.ts +13 -12
  116. package/dist/lib/server/decisioning/index.d.ts.map +1 -1
  117. package/dist/lib/server/decisioning/index.js +6 -0
  118. package/dist/lib/server/decisioning/index.js.map +1 -1
  119. package/dist/lib/server/decisioning/index.mjs +9 -3
  120. package/dist/lib/server/decisioning/index.mjs.map +1 -1
  121. package/dist/lib/server/decisioning/list-helpers.d.mts +13 -3
  122. package/dist/lib/server/decisioning/list-helpers.d.ts +13 -3
  123. package/dist/lib/server/decisioning/list-helpers.d.ts.map +1 -1
  124. package/dist/lib/server/decisioning/list-helpers.js +13 -3
  125. package/dist/lib/server/decisioning/list-helpers.js.map +1 -1
  126. package/dist/lib/server/decisioning/list-helpers.mjs +11 -2
  127. package/dist/lib/server/decisioning/list-helpers.mjs.map +1 -1
  128. package/dist/lib/server/decisioning/manifest-helpers.d.mts +5 -3
  129. package/dist/lib/server/decisioning/manifest-helpers.d.ts +5 -3
  130. package/dist/lib/server/decisioning/manifest-helpers.d.ts.map +1 -1
  131. package/dist/lib/server/decisioning/manifest-helpers.js.map +1 -1
  132. package/dist/lib/server/decisioning/manifest-helpers.mjs.map +1 -1
  133. package/dist/lib/server/decisioning/proposal/dispatch.d.mts +2 -2
  134. package/dist/lib/server/decisioning/proposal/dispatch.d.ts +2 -2
  135. package/dist/lib/server/decisioning/proposal/dispatch.d.ts.map +1 -1
  136. package/dist/lib/server/decisioning/proposal/dispatch.js.map +1 -1
  137. package/dist/lib/server/decisioning/proposal/dispatch.mjs.map +1 -1
  138. package/dist/lib/server/decisioning/proposal/index.d.mts +1 -1
  139. package/dist/lib/server/decisioning/proposal/index.d.ts +1 -1
  140. package/dist/lib/server/decisioning/proposal/index.d.ts.map +1 -1
  141. package/dist/lib/server/decisioning/proposal/index.js.map +1 -1
  142. package/dist/lib/server/decisioning/proposal/index.mjs.map +1 -1
  143. package/dist/lib/server/decisioning/proposal/lifecycle.d.mts +3 -2
  144. package/dist/lib/server/decisioning/proposal/lifecycle.d.ts +3 -2
  145. package/dist/lib/server/decisioning/proposal/lifecycle.d.ts.map +1 -1
  146. package/dist/lib/server/decisioning/proposal/lifecycle.js.map +1 -1
  147. package/dist/lib/server/decisioning/proposal/lifecycle.mjs.map +1 -1
  148. package/dist/lib/server/decisioning/proposal/mock-manager.d.mts +3 -3
  149. package/dist/lib/server/decisioning/proposal/mock-manager.d.ts +3 -3
  150. package/dist/lib/server/decisioning/proposal/mock-manager.d.ts.map +1 -1
  151. package/dist/lib/server/decisioning/proposal/mock-manager.js.map +1 -1
  152. package/dist/lib/server/decisioning/proposal/mock-manager.mjs.map +1 -1
  153. package/dist/lib/server/decisioning/proposal/types.d.mts +10 -6
  154. package/dist/lib/server/decisioning/proposal/types.d.ts +10 -6
  155. package/dist/lib/server/decisioning/proposal/types.d.ts.map +1 -1
  156. package/dist/lib/server/decisioning/proposal/types.js.map +1 -1
  157. package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
  158. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +21 -2
  159. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +21 -2
  160. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  161. package/dist/lib/server/decisioning/runtime/from-platform.js +754 -81
  162. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  163. package/dist/lib/server/decisioning/runtime/from-platform.mjs +763 -81
  164. package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
  165. package/dist/lib/server/decisioning/specialisms/brand-rights.d.mts +9 -9
  166. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts +9 -9
  167. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts.map +1 -1
  168. package/dist/lib/server/decisioning/specialisms/brand-rights.js.map +1 -1
  169. package/dist/lib/server/decisioning/specialisms/content-standards.d.mts +16 -16
  170. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts +16 -16
  171. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts.map +1 -1
  172. package/dist/lib/server/decisioning/specialisms/content-standards.js.map +1 -1
  173. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.mts +15 -13
  174. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +15 -13
  175. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -1
  176. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -1
  177. package/dist/lib/server/decisioning/specialisms/creative.d.mts +12 -11
  178. package/dist/lib/server/decisioning/specialisms/creative.d.ts +12 -11
  179. package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -1
  180. package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -1
  181. package/dist/lib/server/decisioning/specialisms/sales.d.mts +25 -15
  182. package/dist/lib/server/decisioning/specialisms/sales.d.ts +25 -15
  183. package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
  184. package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
  185. package/dist/lib/server/index.d.mts +3 -3
  186. package/dist/lib/server/index.d.ts +3 -3
  187. package/dist/lib/server/index.d.ts.map +1 -1
  188. package/dist/lib/server/index.js +72 -72
  189. package/dist/lib/server/index.js.map +1 -1
  190. package/dist/lib/server/index.mjs +36 -36
  191. package/dist/lib/server/index.mjs.map +1 -1
  192. package/dist/lib/server/legacy/v5/index.d.mts +1 -0
  193. package/dist/lib/server/legacy/v5/index.d.ts +1 -0
  194. package/dist/lib/server/legacy/v5/index.d.ts.map +1 -1
  195. package/dist/lib/server/legacy/v5/index.js +74 -1
  196. package/dist/lib/server/legacy/v5/index.js.map +1 -1
  197. package/dist/lib/server/legacy/v5/index.mjs +75 -1
  198. package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
  199. package/dist/lib/server/responses.d.mts +2 -2
  200. package/dist/lib/server/responses.d.ts +2 -2
  201. package/dist/lib/server/responses.js.map +1 -1
  202. package/dist/lib/server/responses.mjs.map +1 -1
  203. package/dist/lib/testing/client.js +1 -1
  204. package/dist/lib/testing/client.js.map +1 -1
  205. package/dist/lib/testing/client.mjs +1 -1
  206. package/dist/lib/testing/client.mjs.map +1 -1
  207. package/dist/lib/testing/scenarios/brand-rights.js +6 -6
  208. package/dist/lib/testing/scenarios/brand-rights.js.map +1 -1
  209. package/dist/lib/testing/scenarios/brand-rights.mjs +6 -6
  210. package/dist/lib/testing/scenarios/brand-rights.mjs.map +1 -1
  211. package/dist/lib/testing/scenarios/creative.js +7 -7
  212. package/dist/lib/testing/scenarios/creative.js.map +1 -1
  213. package/dist/lib/testing/scenarios/creative.mjs +7 -7
  214. package/dist/lib/testing/scenarios/creative.mjs.map +1 -1
  215. package/dist/lib/testing/scenarios/discovery.js +2 -2
  216. package/dist/lib/testing/scenarios/discovery.js.map +1 -1
  217. package/dist/lib/testing/scenarios/discovery.mjs +2 -2
  218. package/dist/lib/testing/scenarios/discovery.mjs.map +1 -1
  219. package/dist/lib/testing/scenarios/edge-cases.js +11 -11
  220. package/dist/lib/testing/scenarios/edge-cases.js.map +1 -1
  221. package/dist/lib/testing/scenarios/edge-cases.mjs +11 -11
  222. package/dist/lib/testing/scenarios/edge-cases.mjs.map +1 -1
  223. package/dist/lib/testing/scenarios/governance.d.ts.map +1 -1
  224. package/dist/lib/testing/scenarios/governance.js +16 -22
  225. package/dist/lib/testing/scenarios/governance.js.map +1 -1
  226. package/dist/lib/testing/scenarios/governance.mjs +16 -22
  227. package/dist/lib/testing/scenarios/governance.mjs.map +1 -1
  228. package/dist/lib/testing/scenarios/media-buy.js +5 -5
  229. package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
  230. package/dist/lib/testing/scenarios/media-buy.mjs +5 -5
  231. package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
  232. package/dist/lib/testing/scenarios/schema-compliance.js +1 -1
  233. package/dist/lib/testing/scenarios/schema-compliance.js.map +1 -1
  234. package/dist/lib/testing/scenarios/schema-compliance.mjs +1 -1
  235. package/dist/lib/testing/scenarios/schema-compliance.mjs.map +1 -1
  236. package/dist/lib/testing/scenarios/trusted-match.d.ts.map +1 -1
  237. package/dist/lib/testing/scenarios/trusted-match.js +4 -3
  238. package/dist/lib/testing/scenarios/trusted-match.js.map +1 -1
  239. package/dist/lib/testing/scenarios/trusted-match.mjs +4 -3
  240. package/dist/lib/testing/scenarios/trusted-match.mjs.map +1 -1
  241. package/dist/lib/testing/storyboard/shape-drift-hints.d.mts +3 -4
  242. package/dist/lib/testing/storyboard/shape-drift-hints.d.ts +3 -4
  243. package/dist/lib/testing/storyboard/shape-drift-hints.d.ts.map +1 -1
  244. package/dist/lib/testing/storyboard/shape-drift-hints.js +27 -27
  245. package/dist/lib/testing/storyboard/shape-drift-hints.js.map +1 -1
  246. package/dist/lib/testing/storyboard/shape-drift-hints.mjs +27 -27
  247. package/dist/lib/testing/storyboard/shape-drift-hints.mjs.map +1 -1
  248. package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
  249. package/dist/lib/testing/storyboard/task-map.js +43 -5
  250. package/dist/lib/testing/storyboard/task-map.js.map +1 -1
  251. package/dist/lib/testing/storyboard/task-map.mjs +43 -5
  252. package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
  253. package/dist/lib/testing/test-helpers.d.mts +2 -2
  254. package/dist/lib/testing/test-helpers.d.ts +2 -2
  255. package/dist/lib/testing/test-helpers.js.map +1 -1
  256. package/dist/lib/testing/test-helpers.mjs.map +1 -1
  257. package/dist/lib/types/adcp.d.mts +14 -14
  258. package/dist/lib/types/adcp.d.ts +14 -14
  259. package/dist/lib/types/adcp.d.ts.map +1 -1
  260. package/dist/lib/types/adcp.js.map +1 -1
  261. package/dist/lib/types/adcp.mjs.map +1 -1
  262. package/dist/lib/types/index.d.mts +2 -2
  263. package/dist/lib/types/index.d.ts +2 -2
  264. package/dist/lib/types/index.d.ts.map +1 -1
  265. package/dist/lib/types/index.js.map +1 -1
  266. package/dist/lib/types/index.mjs.map +1 -1
  267. package/dist/lib/utils/capabilities.d.mts +6 -0
  268. package/dist/lib/utils/capabilities.d.ts +6 -0
  269. package/dist/lib/utils/capabilities.d.ts.map +1 -1
  270. package/dist/lib/utils/capabilities.js +4 -0
  271. package/dist/lib/utils/capabilities.js.map +1 -1
  272. package/dist/lib/utils/capabilities.mjs +4 -0
  273. package/dist/lib/utils/capabilities.mjs.map +1 -1
  274. package/dist/lib/utils/creative-delivery.d.mts +52 -10
  275. package/dist/lib/utils/creative-delivery.d.ts +52 -10
  276. package/dist/lib/utils/creative-delivery.d.ts.map +1 -1
  277. package/dist/lib/utils/creative-delivery.js +104 -9
  278. package/dist/lib/utils/creative-delivery.js.map +1 -1
  279. package/dist/lib/utils/creative-delivery.mjs +104 -8
  280. package/dist/lib/utils/creative-delivery.mjs.map +1 -1
  281. package/dist/lib/utils/format-assets.d.mts +41 -38
  282. package/dist/lib/utils/format-assets.d.ts +41 -38
  283. package/dist/lib/utils/format-assets.d.ts.map +1 -1
  284. package/dist/lib/utils/format-assets.js +3 -1
  285. package/dist/lib/utils/format-assets.js.map +1 -1
  286. package/dist/lib/utils/format-assets.mjs +3 -1
  287. package/dist/lib/utils/format-assets.mjs.map +1 -1
  288. package/dist/lib/utils/index.d.mts +8 -8
  289. package/dist/lib/utils/index.d.ts +8 -8
  290. package/dist/lib/utils/index.d.ts.map +1 -1
  291. package/dist/lib/utils/index.js +11 -9
  292. package/dist/lib/utils/index.js.map +1 -1
  293. package/dist/lib/utils/index.mjs +9 -8
  294. package/dist/lib/utils/index.mjs.map +1 -1
  295. package/dist/lib/utils/preview-utils.d.mts +11 -8
  296. package/dist/lib/utils/preview-utils.d.ts +11 -8
  297. package/dist/lib/utils/preview-utils.d.ts.map +1 -1
  298. package/dist/lib/utils/preview-utils.js +4 -4
  299. package/dist/lib/utils/preview-utils.js.map +1 -1
  300. package/dist/lib/utils/preview-utils.mjs +3 -3
  301. package/dist/lib/utils/preview-utils.mjs.map +1 -1
  302. package/dist/lib/utils/tool-request-schemas.d.mts +2 -2
  303. package/dist/lib/utils/tool-request-schemas.d.ts +2 -2
  304. package/dist/lib/v2/projection/aao-reference-formats.json +492 -0
  305. package/dist/lib/v2/projection/augment-response.d.mts +31 -11
  306. package/dist/lib/v2/projection/augment-response.d.ts +31 -11
  307. package/dist/lib/v2/projection/augment-response.d.ts.map +1 -1
  308. package/dist/lib/v2/projection/augment-response.js +233 -27
  309. package/dist/lib/v2/projection/augment-response.js.map +1 -1
  310. package/dist/lib/v2/projection/augment-response.mjs +232 -27
  311. package/dist/lib/v2/projection/augment-response.mjs.map +1 -1
  312. package/dist/lib/v2/projection/builders.d.mts +7 -6
  313. package/dist/lib/v2/projection/builders.d.ts +7 -6
  314. package/dist/lib/v2/projection/builders.d.ts.map +1 -1
  315. package/dist/lib/v2/projection/builders.js +11 -8
  316. package/dist/lib/v2/projection/builders.js.map +1 -1
  317. package/dist/lib/v2/projection/builders.mjs +9 -6
  318. package/dist/lib/v2/projection/builders.mjs.map +1 -1
  319. package/dist/lib/v2/projection/catalog-snapshot.d.mts +47 -0
  320. package/dist/lib/v2/projection/catalog-snapshot.d.ts +48 -0
  321. package/dist/lib/v2/projection/catalog-snapshot.d.ts.map +1 -0
  322. package/dist/lib/v2/projection/catalog-snapshot.js +291 -0
  323. package/dist/lib/v2/projection/catalog-snapshot.js.map +1 -0
  324. package/dist/lib/v2/projection/catalog-snapshot.mjs +265 -0
  325. package/dist/lib/v2/projection/catalog-snapshot.mjs.map +1 -0
  326. package/dist/lib/v2/projection/catalog.d.mts +23 -2
  327. package/dist/lib/v2/projection/catalog.d.ts +23 -2
  328. package/dist/lib/v2/projection/catalog.d.ts.map +1 -1
  329. package/dist/lib/v2/projection/catalog.js +34 -10
  330. package/dist/lib/v2/projection/catalog.js.map +1 -1
  331. package/dist/lib/v2/projection/catalog.mjs +33 -10
  332. package/dist/lib/v2/projection/catalog.mjs.map +1 -1
  333. package/dist/lib/v2/projection/creative-delivery.d.mts +157 -0
  334. package/dist/lib/v2/projection/creative-delivery.d.ts +158 -0
  335. package/dist/lib/v2/projection/creative-delivery.d.ts.map +1 -0
  336. package/dist/lib/v2/projection/creative-delivery.js +967 -0
  337. package/dist/lib/v2/projection/creative-delivery.js.map +1 -0
  338. package/dist/lib/v2/projection/creative-delivery.mjs +941 -0
  339. package/dist/lib/v2/projection/creative-delivery.mjs.map +1 -0
  340. package/dist/lib/v2/projection/index.d.mts +8 -6
  341. package/dist/lib/v2/projection/index.d.ts +8 -6
  342. package/dist/lib/v2/projection/index.d.ts.map +1 -1
  343. package/dist/lib/v2/projection/index.js +26 -4
  344. package/dist/lib/v2/projection/index.js.map +1 -1
  345. package/dist/lib/v2/projection/index.mjs +28 -4
  346. package/dist/lib/v2/projection/index.mjs.map +1 -1
  347. package/dist/lib/v2/projection/legacy-metadata.d.mts +21 -0
  348. package/dist/lib/v2/projection/legacy-metadata.d.ts +22 -0
  349. package/dist/lib/v2/projection/legacy-metadata.d.ts.map +1 -0
  350. package/dist/lib/v2/projection/legacy-metadata.js +73 -0
  351. package/dist/lib/v2/projection/legacy-metadata.js.map +1 -0
  352. package/dist/lib/v2/projection/legacy-metadata.mjs +45 -0
  353. package/dist/lib/v2/projection/legacy-metadata.mjs.map +1 -0
  354. package/dist/lib/v2/projection/types.d.mts +29 -23
  355. package/dist/lib/v2/projection/types.d.ts +29 -23
  356. package/dist/lib/v2/projection/types.d.ts.map +1 -1
  357. package/dist/lib/v2/projection/types.js.map +1 -1
  358. package/dist/lib/v2/projection/v1-to-v2.d.mts +29 -6
  359. package/dist/lib/v2/projection/v1-to-v2.d.ts +29 -6
  360. package/dist/lib/v2/projection/v1-to-v2.d.ts.map +1 -1
  361. package/dist/lib/v2/projection/v1-to-v2.js +218 -9
  362. package/dist/lib/v2/projection/v1-to-v2.js.map +1 -1
  363. package/dist/lib/v2/projection/v1-to-v2.mjs +219 -10
  364. package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
  365. package/dist/lib/v2/projection/v2-to-v1.d.mts +31 -2
  366. package/dist/lib/v2/projection/v2-to-v1.d.ts +31 -2
  367. package/dist/lib/v2/projection/v2-to-v1.d.ts.map +1 -1
  368. package/dist/lib/v2/projection/v2-to-v1.js +138 -7
  369. package/dist/lib/v2/projection/v2-to-v1.js.map +1 -1
  370. package/dist/lib/v2/projection/v2-to-v1.mjs +135 -6
  371. package/dist/lib/v2/projection/v2-to-v1.mjs.map +1 -1
  372. package/dist/lib/v2/projection/write-side.d.mts +12 -13
  373. package/dist/lib/v2/projection/write-side.d.ts +12 -13
  374. package/dist/lib/v2/projection/write-side.d.ts.map +1 -1
  375. package/dist/lib/v2/projection/write-side.js +16 -12
  376. package/dist/lib/v2/projection/write-side.js.map +1 -1
  377. package/dist/lib/v2/projection/write-side.mjs +16 -12
  378. package/dist/lib/v2/projection/write-side.mjs.map +1 -1
  379. package/dist/lib/version.d.mts +3 -3
  380. package/dist/lib/version.d.ts +3 -3
  381. package/dist/lib/version.d.ts.map +1 -1
  382. package/dist/lib/version.js +3 -3
  383. package/dist/lib/version.js.map +1 -1
  384. package/dist/lib/version.mjs +3 -3
  385. package/dist/lib/version.mjs.map +1 -1
  386. package/docs/guides/BUILD-AN-AGENT.md +7 -2
  387. package/docs/guides/PREVIEW-ASSET-DURABILITY.md +6 -2
  388. package/docs/llms.txt +1 -0
  389. package/examples/README.md +1 -1
  390. package/examples/batch-preview-test.ts +3 -3
  391. package/examples/conversation-client.ts +2 -2
  392. package/examples/debug-preview-response.ts +1 -1
  393. package/examples/decisioning-platform-broadcast-tv.ts +10 -4
  394. package/examples/decisioning-platform-mock-seller.ts +16 -9
  395. package/examples/decisioning-platform-programmatic.ts +18 -7
  396. package/examples/error-compliant-server.ts +26 -16
  397. package/examples/generative-creative-demo.ts +7 -19
  398. package/examples/hello_creative_adapter_ad_server.ts +37 -16
  399. package/examples/hello_creative_adapter_template.ts +12 -10
  400. package/examples/hello_seller_adapter_guaranteed.ts +52 -23
  401. package/examples/hello_seller_adapter_multi_tenant.ts +6 -3
  402. package/examples/hello_seller_adapter_non_guaranteed.ts +54 -26
  403. package/examples/hello_seller_adapter_proposal_mode.ts +40 -14
  404. package/examples/hello_seller_adapter_social.ts +2 -7
  405. package/examples/inspect-card-formats.ts +1 -1
  406. package/examples/simple-getting-started.ts +1 -1
  407. package/examples/test-helpers-demo.ts +1 -1
  408. package/package.json +2 -2
  409. package/skills/build-decisioning-creative-template/SKILL.md +11 -11
  410. package/skills/build-decisioning-platform/advanced/REFERENCE.md +8 -2
@@ -189,7 +189,7 @@ async function testSchemaCompliance(agentUrl, options) {
189
189
  const { result: formatsResult, step: formatsStep } = await (0, import_client.runStep)(
190
190
  "Get creative formats (check assets structure)",
191
191
  "list_creative_formats",
192
- async () => client.listCreativeFormats({})
192
+ async () => client.listCreativeFormatsLegacy({})
193
193
  );
194
194
  if (formatsResult?.success && formatsResult?.data) {
195
195
  steps.push((0, import_client.validateResponseSchema)("list_creative_formats", formatsResult.data));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/testing/scenarios/schema-compliance.ts"],"sourcesContent":["/**\n * Schema Compliance Testing\n *\n * Validates that an agent's responses use correct v3 field names and enum values.\n * Uses GET-only operations — no writes required.\n *\n * Checks:\n * - Channel enum values (hard fail on invalid values)\n * - Pricing field names: fixed_price (not fixed_rate), floor_price top-level\n * - Format assets: assets array with required boolean (not assets_required)\n */\n\nimport type { Product } from '../../types/core.generated';\nimport type {\n GetProductsResponse,\n GetSignalsResponse,\n ListCreativeFormatsResponse,\n Format,\n} from '../../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile, validateResponseSchema } from '../client';\n\n// v3 channel taxonomy — 19 channels\nconst V3_CHANNELS = new Set([\n 'display',\n 'olv',\n 'social',\n 'search',\n 'ctv',\n 'linear_tv',\n 'radio',\n 'streaming_audio',\n 'podcast',\n 'dooh',\n 'ooh',\n 'print',\n 'cinema',\n 'email',\n 'gaming',\n 'retail_media',\n 'influencer',\n 'affiliate',\n 'product_placement',\n]);\n\nexport async function testSchemaCompliance(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n if (!profile.tools.includes('get_products') && !profile.tools.includes('get_signals')) {\n // Path A: no supported discovery tool — skip field-shape checks gracefully\n steps.push({\n step: 'Schema compliance check support',\n passed: true,\n duration_ms: 0,\n details: 'Agent does not advertise get_products or get_signals — discovery field-shape checks skipped',\n warnings: ['Schema compliance: no supported discovery tool (get_products, get_signals) found; checks skipped'],\n });\n // Fall through to list_creative_formats check below\n } else if (profile.tools.includes('get_signals') && !profile.tools.includes('get_products')) {\n // Path B: signals agent — validate GetSignalsResponse schema and field semantics\n const { result: signalsResult, step: signalsStep } = await runStep<TaskResult>(\n 'Get signals (schema compliance)',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Schema compliance test — retrieve all available signals',\n }) as Promise<TaskResult>\n );\n\n if (!signalsResult?.success || !signalsResult?.data) {\n signalsStep.passed = false;\n signalsStep.error = signalsResult?.error || 'get_signals returned no data';\n steps.push(signalsStep);\n return { steps, profile };\n }\n steps.push(signalsStep);\n\n const signalsData = signalsResult.data as GetSignalsResponse;\n // Zod schema validation covers required-field presence (signal_agent_segment_id, name, signal_type).\n steps.push(validateResponseSchema('get_signals', signalsData));\n\n const signals = signalsData.signals ?? [];\n steps.push({\n step: 'Validate signal required fields',\n passed: true,\n duration_ms: 0,\n details:\n signals.length === 0\n ? 'Agent returned no signals — field-shape checks skipped'\n : `${signals.length} signal(s) validated via schema check (signal_agent_segment_id, name, signal_type)`,\n warnings:\n signals.length === 0\n ? ['No signals returned; cannot validate signal_agent_segment_id, name, signal_type fields']\n : undefined,\n });\n // Fall through to list_creative_formats check below\n } else {\n // Path C: get_products present — existing product catalog checks\n const { result: productsResult, step: productsStep } = await runStep<TaskResult>(\n 'Get products (schema compliance)',\n 'get_products',\n async () =>\n client.getProducts({\n buying_mode: 'brief',\n brief: options.brief || 'Schema compliance test — retrieve all available products',\n brand: options.brand,\n }) as Promise<TaskResult>\n );\n\n if (!productsResult?.success || !productsResult?.data) {\n productsStep.passed = false;\n productsStep.error = productsResult?.error || 'get_products returned no data';\n steps.push(productsStep);\n return { steps, profile };\n }\n steps.push(productsStep);\n\n const data = productsResult.data as GetProductsResponse;\n const products: Product[] = data.products || [];\n\n // --- Zod schema validation (catches missing required fields + invalid enum values) ---\n steps.push(validateResponseSchema('get_products', data));\n\n if (products.length === 0) {\n steps.push({\n step: 'Schema compliance: no products to validate',\n passed: true,\n duration_ms: 0,\n details: 'Agent returned no products — schema compliance checks skipped',\n warnings: ['No products returned; cannot validate channel, pricing, or format field schemas'],\n });\n return { steps, profile };\n }\n\n // --- Channel enum validation (hard fail) ---\n const invalidChannels: string[] = [];\n const allChannels = new Set<string>();\n\n for (const product of products) {\n for (const channel of product.channels || []) {\n allChannels.add(channel);\n if (!V3_CHANNELS.has(channel)) {\n invalidChannels.push(`\"${channel}\" in product ${product.product_id}`);\n }\n }\n }\n\n steps.push({\n step: 'Validate channel enum values',\n passed: invalidChannels.length === 0,\n duration_ms: 0,\n details:\n invalidChannels.length === 0\n ? `All ${allChannels.size} channel value(s) are valid v3 channels: ${Array.from(allChannels).join(', ')}`\n : `Invalid channel values detected (not in v3 taxonomy): ${invalidChannels.join('; ')}`,\n error:\n invalidChannels.length > 0\n ? `Channel enum violations: ${invalidChannels.join('; ')}. Valid channels: ${Array.from(V3_CHANNELS).join(', ')}`\n : undefined,\n response_preview: JSON.stringify(\n {\n channels_found: Array.from(allChannels),\n invalid_channels: invalidChannels,\n },\n null,\n 2\n ),\n });\n\n // --- Pricing field name validation (warn, not fail) ---\n const pricingIssues: string[] = [];\n const pricingChecked: string[] = [];\n let fixedPriceFound = false;\n\n for (const product of products) {\n for (const option of product.pricing_options || []) {\n const optionId = option.pricing_option_id || '(unknown)';\n // Cast to Record for deprecated-field checks — compliance testing intentionally\n // probes fields that may not exist on the generated PricingOption union\n const raw = option as unknown as Record<string, unknown>;\n\n // Check for deprecated fixed_rate field\n if ('fixed_rate' in raw) {\n pricingIssues.push(`pricing_option ${optionId} uses deprecated \"fixed_rate\" — should be \"fixed_price\"`);\n }\n if ('fixed_price' in raw) {\n fixedPriceFound = true;\n pricingChecked.push(optionId);\n }\n\n // Check for floor_price inside price_guidance (deprecated location)\n const pg = raw.price_guidance as Record<string, unknown> | undefined;\n if (pg && 'floor' in pg) {\n pricingIssues.push(\n `pricing_option ${optionId} has \"floor\" inside price_guidance — should be top-level \"floor_price\"`\n );\n }\n if ('floor_price' in raw) {\n pricingChecked.push(`${optionId} (floor_price)`);\n }\n }\n }\n\n const pricingPassed = pricingIssues.length === 0;\n const pricingDetails =\n pricingIssues.length > 0\n ? `Pricing field issues: ${pricingIssues.join('; ')}`\n : fixedPriceFound\n ? `Pricing fields valid (checked ${pricingChecked.length} option(s))`\n : 'No fixed-price products found to validate (agent may be auction-only — cannot confirm field names)';\n\n steps.push({\n step: 'Validate pricing field names',\n passed: pricingPassed,\n duration_ms: 0,\n details: pricingDetails,\n error: pricingIssues.length > 0 ? pricingIssues.join('; ') : undefined,\n warnings:\n !fixedPriceFound && pricingIssues.length === 0\n ? [\n 'No fixed-price products found. If agent supports fixed pricing, verify it uses \"fixed_price\" (not \"fixed_rate\") and \"floor_price\" at the pricing option level (not inside price_guidance).',\n ]\n : undefined,\n response_preview: JSON.stringify(\n {\n issues: pricingIssues,\n options_checked: pricingChecked,\n },\n null,\n 2\n ),\n });\n }\n\n // --- Format assets structure (optional: list_creative_formats) ---\n // Runs for all agent types that advertise list_creative_formats, regardless of discovery path\n if (profile.tools.includes('list_creative_formats')) {\n const { result: formatsResult, step: formatsStep } = await runStep<TaskResult>(\n 'Get creative formats (check assets structure)',\n 'list_creative_formats',\n async () => client.listCreativeFormats({}) as Promise<TaskResult>\n );\n\n if (formatsResult?.success && formatsResult?.data) {\n steps.push(validateResponseSchema('list_creative_formats', formatsResult.data));\n const formatsData = formatsResult.data as ListCreativeFormatsResponse;\n const formats: Format[] = formatsData.formats || [];\n const assetsIssues: string[] = [];\n let formatsChecked = 0;\n\n for (const format of formats) {\n formatsChecked++;\n const formatIdStr = typeof format.format_id === 'object' ? format.format_id.id : String(format.format_id);\n // Check for deprecated assets_required field\n if ('assets_required' in format) {\n assetsIssues.push(\n `format ${formatIdStr} uses deprecated \"assets_required\" — should be \"assets\" array with \"required\" boolean`\n );\n }\n // Validate assets array structure\n if (Array.isArray(format.assets)) {\n for (const asset of format.assets) {\n if (!('required' in asset)) {\n assetsIssues.push(`format ${formatIdStr} asset missing \"required\" boolean field`);\n }\n }\n }\n }\n\n formatsStep.details =\n assetsIssues.length === 0\n ? `Format assets valid across ${formatsChecked} format(s)`\n : `Format asset issues: ${assetsIssues.join('; ')}`;\n formatsStep.passed = assetsIssues.length === 0;\n formatsStep.error = assetsIssues.length > 0 ? assetsIssues.join('; ') : undefined;\n }\n steps.push(formatsStep);\n }\n\n return { steps, profile };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBA,oBAAyF;AAGzF,MAAM,cAAc,oBAAI,IAAI;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,eAAsB,qBACpB,UACA,SAC8D;AAC9D,QAAM,QAA0B,CAAC;AACjC,QAAM,aAAS,iCAAkB,UAAU,OAAO;AAElD,QAAM,EAAE,SAAS,MAAM,YAAY,IAAI,UAAM,oCAAqB,QAAQ,OAAO;AACjF,QAAM,KAAK,WAAW;AAEtB,MAAI,CAAC,YAAY,QAAQ;AACvB,WAAO,EAAE,OAAO,QAAQ;AAAA,EAC1B;AAEA,MAAI,CAAC,QAAQ,MAAM,SAAS,cAAc,KAAK,CAAC,QAAQ,MAAM,SAAS,aAAa,GAAG;AAErF,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,SAAS;AAAA,MACT,UAAU,CAAC,kGAAkG;AAAA,IAC/G,CAAC;AAAA,EAEH,WAAW,QAAQ,MAAM,SAAS,aAAa,KAAK,CAAC,QAAQ,MAAM,SAAS,cAAc,GAAG;AAE3F,UAAM,EAAE,QAAQ,eAAe,MAAM,YAAY,IAAI,UAAM;AAAA,MACzD;AAAA,MACA;AAAA,MACA,YACE,OAAO,WAAW;AAAA,QAChB,aAAa,QAAQ,SAAS;AAAA,MAChC,CAAC;AAAA,IACL;AAEA,QAAI,CAAC,eAAe,WAAW,CAAC,eAAe,MAAM;AACnD,kBAAY,SAAS;AACrB,kBAAY,QAAQ,eAAe,SAAS;AAC5C,YAAM,KAAK,WAAW;AACtB,aAAO,EAAE,OAAO,QAAQ;AAAA,IAC1B;AACA,UAAM,KAAK,WAAW;AAEtB,UAAM,cAAc,cAAc;AAElC,UAAM,SAAK,sCAAuB,eAAe,WAAW,CAAC;AAE7D,UAAM,UAAU,YAAY,WAAW,CAAC;AACxC,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,SACE,QAAQ,WAAW,IACf,gEACA,GAAG,QAAQ,MAAM;AAAA,MACvB,UACE,QAAQ,WAAW,IACf,CAAC,wFAAwF,IACzF;AAAA,IACR,CAAC;AAAA,EAEH,OAAO;AAEL,UAAM,EAAE,QAAQ,gBAAgB,MAAM,aAAa,IAAI,UAAM;AAAA,MAC3D;AAAA,MACA;AAAA,MACA,YACE,OAAO,YAAY;AAAA,QACjB,aAAa;AAAA,QACb,OAAO,QAAQ,SAAS;AAAA,QACxB,OAAO,QAAQ;AAAA,MACjB,CAAC;AAAA,IACL;AAEA,QAAI,CAAC,gBAAgB,WAAW,CAAC,gBAAgB,MAAM;AACrD,mBAAa,SAAS;AACtB,mBAAa,QAAQ,gBAAgB,SAAS;AAC9C,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,OAAO,QAAQ;AAAA,IAC1B;AACA,UAAM,KAAK,YAAY;AAEvB,UAAM,OAAO,eAAe;AAC5B,UAAM,WAAsB,KAAK,YAAY,CAAC;AAG9C,UAAM,SAAK,sCAAuB,gBAAgB,IAAI,CAAC;AAEvD,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,SAAS;AAAA,QACT,UAAU,CAAC,iFAAiF;AAAA,MAC9F,CAAC;AACD,aAAO,EAAE,OAAO,QAAQ;AAAA,IAC1B;AAGA,UAAM,kBAA4B,CAAC;AACnC,UAAM,cAAc,oBAAI,IAAY;AAEpC,eAAW,WAAW,UAAU;AAC9B,iBAAW,WAAW,QAAQ,YAAY,CAAC,GAAG;AAC5C,oBAAY,IAAI,OAAO;AACvB,YAAI,CAAC,YAAY,IAAI,OAAO,GAAG;AAC7B,0BAAgB,KAAK,IAAI,OAAO,gBAAgB,QAAQ,UAAU,EAAE;AAAA,QACtE;AAAA,MACF;AAAA,IACF;AAEA,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ,gBAAgB,WAAW;AAAA,MACnC,aAAa;AAAA,MACb,SACE,gBAAgB,WAAW,IACvB,OAAO,YAAY,IAAI,4CAA4C,MAAM,KAAK,WAAW,EAAE,KAAK,IAAI,CAAC,KACrG,yDAAyD,gBAAgB,KAAK,IAAI,CAAC;AAAA,MACzF,OACE,gBAAgB,SAAS,IACrB,4BAA4B,gBAAgB,KAAK,IAAI,CAAC,qBAAqB,MAAM,KAAK,WAAW,EAAE,KAAK,IAAI,CAAC,KAC7G;AAAA,MACN,kBAAkB,KAAK;AAAA,QACrB;AAAA,UACE,gBAAgB,MAAM,KAAK,WAAW;AAAA,UACtC,kBAAkB;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAGD,UAAM,gBAA0B,CAAC;AACjC,UAAM,iBAA2B,CAAC;AAClC,QAAI,kBAAkB;AAEtB,eAAW,WAAW,UAAU;AAC9B,iBAAW,UAAU,QAAQ,mBAAmB,CAAC,GAAG;AAClD,cAAM,WAAW,OAAO,qBAAqB;AAG7C,cAAM,MAAM;AAGZ,YAAI,gBAAgB,KAAK;AACvB,wBAAc,KAAK,kBAAkB,QAAQ,8DAAyD;AAAA,QACxG;AACA,YAAI,iBAAiB,KAAK;AACxB,4BAAkB;AAClB,yBAAe,KAAK,QAAQ;AAAA,QAC9B;AAGA,cAAM,KAAK,IAAI;AACf,YAAI,MAAM,WAAW,IAAI;AACvB,wBAAc;AAAA,YACZ,kBAAkB,QAAQ;AAAA,UAC5B;AAAA,QACF;AACA,YAAI,iBAAiB,KAAK;AACxB,yBAAe,KAAK,GAAG,QAAQ,gBAAgB;AAAA,QACjD;AAAA,MACF;AAAA,IACF;AAEA,UAAM,gBAAgB,cAAc,WAAW;AAC/C,UAAM,iBACJ,cAAc,SAAS,IACnB,yBAAyB,cAAc,KAAK,IAAI,CAAC,KACjD,kBACE,iCAAiC,eAAe,MAAM,gBACtD;AAER,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OAAO,cAAc,SAAS,IAAI,cAAc,KAAK,IAAI,IAAI;AAAA,MAC7D,UACE,CAAC,mBAAmB,cAAc,WAAW,IACzC;AAAA,QACE;AAAA,MACF,IACA;AAAA,MACN,kBAAkB,KAAK;AAAA,QACrB;AAAA,UACE,QAAQ;AAAA,UACR,iBAAiB;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAIA,MAAI,QAAQ,MAAM,SAAS,uBAAuB,GAAG;AACnD,UAAM,EAAE,QAAQ,eAAe,MAAM,YAAY,IAAI,UAAM;AAAA,MACzD;AAAA,MACA;AAAA,MACA,YAAY,OAAO,oBAAoB,CAAC,CAAC;AAAA,IAC3C;AAEA,QAAI,eAAe,WAAW,eAAe,MAAM;AACjD,YAAM,SAAK,sCAAuB,yBAAyB,cAAc,IAAI,CAAC;AAC9E,YAAM,cAAc,cAAc;AAClC,YAAM,UAAoB,YAAY,WAAW,CAAC;AAClD,YAAM,eAAyB,CAAC;AAChC,UAAI,iBAAiB;AAErB,iBAAW,UAAU,SAAS;AAC5B;AACA,cAAM,cAAc,OAAO,OAAO,cAAc,WAAW,OAAO,UAAU,KAAK,OAAO,OAAO,SAAS;AAExG,YAAI,qBAAqB,QAAQ;AAC/B,uBAAa;AAAA,YACX,UAAU,WAAW;AAAA,UACvB;AAAA,QACF;AAEA,YAAI,MAAM,QAAQ,OAAO,MAAM,GAAG;AAChC,qBAAW,SAAS,OAAO,QAAQ;AACjC,gBAAI,EAAE,cAAc,QAAQ;AAC1B,2BAAa,KAAK,UAAU,WAAW,yCAAyC;AAAA,YAClF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,kBAAY,UACV,aAAa,WAAW,IACpB,8BAA8B,cAAc,eAC5C,wBAAwB,aAAa,KAAK,IAAI,CAAC;AACrD,kBAAY,SAAS,aAAa,WAAW;AAC7C,kBAAY,QAAQ,aAAa,SAAS,IAAI,aAAa,KAAK,IAAI,IAAI;AAAA,IAC1E;AACA,UAAM,KAAK,WAAW;AAAA,EACxB;AAEA,SAAO,EAAE,OAAO,QAAQ;AAC1B;","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/testing/scenarios/schema-compliance.ts"],"sourcesContent":["/**\n * Schema Compliance Testing\n *\n * Validates that an agent's responses use correct v3 field names and enum values.\n * Uses GET-only operations — no writes required.\n *\n * Checks:\n * - Channel enum values (hard fail on invalid values)\n * - Pricing field names: fixed_price (not fixed_rate), floor_price top-level\n * - Format assets: assets array with required boolean (not assets_required)\n */\n\nimport type { Product } from '../../types/core.generated';\nimport type {\n GetProductsResponse,\n GetSignalsResponse,\n ListCreativeFormatsResponse,\n Format,\n} from '../../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile, validateResponseSchema } from '../client';\n\n// v3 channel taxonomy — 19 channels\nconst V3_CHANNELS = new Set([\n 'display',\n 'olv',\n 'social',\n 'search',\n 'ctv',\n 'linear_tv',\n 'radio',\n 'streaming_audio',\n 'podcast',\n 'dooh',\n 'ooh',\n 'print',\n 'cinema',\n 'email',\n 'gaming',\n 'retail_media',\n 'influencer',\n 'affiliate',\n 'product_placement',\n]);\n\nexport async function testSchemaCompliance(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n if (!profile.tools.includes('get_products') && !profile.tools.includes('get_signals')) {\n // Path A: no supported discovery tool — skip field-shape checks gracefully\n steps.push({\n step: 'Schema compliance check support',\n passed: true,\n duration_ms: 0,\n details: 'Agent does not advertise get_products or get_signals — discovery field-shape checks skipped',\n warnings: ['Schema compliance: no supported discovery tool (get_products, get_signals) found; checks skipped'],\n });\n // Fall through to list_creative_formats check below\n } else if (profile.tools.includes('get_signals') && !profile.tools.includes('get_products')) {\n // Path B: signals agent — validate GetSignalsResponse schema and field semantics\n const { result: signalsResult, step: signalsStep } = await runStep<TaskResult>(\n 'Get signals (schema compliance)',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Schema compliance test — retrieve all available signals',\n }) as Promise<TaskResult>\n );\n\n if (!signalsResult?.success || !signalsResult?.data) {\n signalsStep.passed = false;\n signalsStep.error = signalsResult?.error || 'get_signals returned no data';\n steps.push(signalsStep);\n return { steps, profile };\n }\n steps.push(signalsStep);\n\n const signalsData = signalsResult.data as GetSignalsResponse;\n // Zod schema validation covers required-field presence (signal_agent_segment_id, name, signal_type).\n steps.push(validateResponseSchema('get_signals', signalsData));\n\n const signals = signalsData.signals ?? [];\n steps.push({\n step: 'Validate signal required fields',\n passed: true,\n duration_ms: 0,\n details:\n signals.length === 0\n ? 'Agent returned no signals — field-shape checks skipped'\n : `${signals.length} signal(s) validated via schema check (signal_agent_segment_id, name, signal_type)`,\n warnings:\n signals.length === 0\n ? ['No signals returned; cannot validate signal_agent_segment_id, name, signal_type fields']\n : undefined,\n });\n // Fall through to list_creative_formats check below\n } else {\n // Path C: get_products present — existing product catalog checks\n const { result: productsResult, step: productsStep } = await runStep<TaskResult>(\n 'Get products (schema compliance)',\n 'get_products',\n async () =>\n client.getProducts({\n buying_mode: 'brief',\n brief: options.brief || 'Schema compliance test — retrieve all available products',\n brand: options.brand,\n }) as Promise<TaskResult>\n );\n\n if (!productsResult?.success || !productsResult?.data) {\n productsStep.passed = false;\n productsStep.error = productsResult?.error || 'get_products returned no data';\n steps.push(productsStep);\n return { steps, profile };\n }\n steps.push(productsStep);\n\n const data = productsResult.data as GetProductsResponse;\n const products: Product[] = data.products || [];\n\n // --- Zod schema validation (catches missing required fields + invalid enum values) ---\n steps.push(validateResponseSchema('get_products', data));\n\n if (products.length === 0) {\n steps.push({\n step: 'Schema compliance: no products to validate',\n passed: true,\n duration_ms: 0,\n details: 'Agent returned no products — schema compliance checks skipped',\n warnings: ['No products returned; cannot validate channel, pricing, or format field schemas'],\n });\n return { steps, profile };\n }\n\n // --- Channel enum validation (hard fail) ---\n const invalidChannels: string[] = [];\n const allChannels = new Set<string>();\n\n for (const product of products) {\n for (const channel of product.channels || []) {\n allChannels.add(channel);\n if (!V3_CHANNELS.has(channel)) {\n invalidChannels.push(`\"${channel}\" in product ${product.product_id}`);\n }\n }\n }\n\n steps.push({\n step: 'Validate channel enum values',\n passed: invalidChannels.length === 0,\n duration_ms: 0,\n details:\n invalidChannels.length === 0\n ? `All ${allChannels.size} channel value(s) are valid v3 channels: ${Array.from(allChannels).join(', ')}`\n : `Invalid channel values detected (not in v3 taxonomy): ${invalidChannels.join('; ')}`,\n error:\n invalidChannels.length > 0\n ? `Channel enum violations: ${invalidChannels.join('; ')}. Valid channels: ${Array.from(V3_CHANNELS).join(', ')}`\n : undefined,\n response_preview: JSON.stringify(\n {\n channels_found: Array.from(allChannels),\n invalid_channels: invalidChannels,\n },\n null,\n 2\n ),\n });\n\n // --- Pricing field name validation (warn, not fail) ---\n const pricingIssues: string[] = [];\n const pricingChecked: string[] = [];\n let fixedPriceFound = false;\n\n for (const product of products) {\n for (const option of product.pricing_options || []) {\n const optionId = option.pricing_option_id || '(unknown)';\n // Cast to Record for deprecated-field checks — compliance testing intentionally\n // probes fields that may not exist on the generated PricingOption union\n const raw = option as unknown as Record<string, unknown>;\n\n // Check for deprecated fixed_rate field\n if ('fixed_rate' in raw) {\n pricingIssues.push(`pricing_option ${optionId} uses deprecated \"fixed_rate\" — should be \"fixed_price\"`);\n }\n if ('fixed_price' in raw) {\n fixedPriceFound = true;\n pricingChecked.push(optionId);\n }\n\n // Check for floor_price inside price_guidance (deprecated location)\n const pg = raw.price_guidance as Record<string, unknown> | undefined;\n if (pg && 'floor' in pg) {\n pricingIssues.push(\n `pricing_option ${optionId} has \"floor\" inside price_guidance — should be top-level \"floor_price\"`\n );\n }\n if ('floor_price' in raw) {\n pricingChecked.push(`${optionId} (floor_price)`);\n }\n }\n }\n\n const pricingPassed = pricingIssues.length === 0;\n const pricingDetails =\n pricingIssues.length > 0\n ? `Pricing field issues: ${pricingIssues.join('; ')}`\n : fixedPriceFound\n ? `Pricing fields valid (checked ${pricingChecked.length} option(s))`\n : 'No fixed-price products found to validate (agent may be auction-only — cannot confirm field names)';\n\n steps.push({\n step: 'Validate pricing field names',\n passed: pricingPassed,\n duration_ms: 0,\n details: pricingDetails,\n error: pricingIssues.length > 0 ? pricingIssues.join('; ') : undefined,\n warnings:\n !fixedPriceFound && pricingIssues.length === 0\n ? [\n 'No fixed-price products found. If agent supports fixed pricing, verify it uses \"fixed_price\" (not \"fixed_rate\") and \"floor_price\" at the pricing option level (not inside price_guidance).',\n ]\n : undefined,\n response_preview: JSON.stringify(\n {\n issues: pricingIssues,\n options_checked: pricingChecked,\n },\n null,\n 2\n ),\n });\n }\n\n // --- Format assets structure (optional: list_creative_formats) ---\n // Runs for all agent types that advertise list_creative_formats, regardless of discovery path\n if (profile.tools.includes('list_creative_formats')) {\n const { result: formatsResult, step: formatsStep } = await runStep<TaskResult>(\n 'Get creative formats (check assets structure)',\n 'list_creative_formats',\n async () => client.listCreativeFormatsLegacy({}) as Promise<TaskResult>\n );\n\n if (formatsResult?.success && formatsResult?.data) {\n steps.push(validateResponseSchema('list_creative_formats', formatsResult.data));\n const formatsData = formatsResult.data as ListCreativeFormatsResponse;\n const formats: Format[] = formatsData.formats || [];\n const assetsIssues: string[] = [];\n let formatsChecked = 0;\n\n for (const format of formats) {\n formatsChecked++;\n const formatIdStr = typeof format.format_id === 'object' ? format.format_id.id : String(format.format_id);\n // Check for deprecated assets_required field\n if ('assets_required' in format) {\n assetsIssues.push(\n `format ${formatIdStr} uses deprecated \"assets_required\" — should be \"assets\" array with \"required\" boolean`\n );\n }\n // Validate assets array structure\n if (Array.isArray(format.assets)) {\n for (const asset of format.assets) {\n if (!('required' in asset)) {\n assetsIssues.push(`format ${formatIdStr} asset missing \"required\" boolean field`);\n }\n }\n }\n }\n\n formatsStep.details =\n assetsIssues.length === 0\n ? `Format assets valid across ${formatsChecked} format(s)`\n : `Format asset issues: ${assetsIssues.join('; ')}`;\n formatsStep.passed = assetsIssues.length === 0;\n formatsStep.error = assetsIssues.length > 0 ? assetsIssues.join('; ') : undefined;\n }\n steps.push(formatsStep);\n }\n\n return { steps, profile };\n}\n"],"mappings":"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","names":[]}
@@ -166,7 +166,7 @@ async function testSchemaCompliance(agentUrl, options) {
166
166
  const { result: formatsResult, step: formatsStep } = await runStep(
167
167
  "Get creative formats (check assets structure)",
168
168
  "list_creative_formats",
169
- async () => client.listCreativeFormats({})
169
+ async () => client.listCreativeFormatsLegacy({})
170
170
  );
171
171
  if (formatsResult?.success && formatsResult?.data) {
172
172
  steps.push(validateResponseSchema("list_creative_formats", formatsResult.data));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/testing/scenarios/schema-compliance.ts"],"sourcesContent":["/**\n * Schema Compliance Testing\n *\n * Validates that an agent's responses use correct v3 field names and enum values.\n * Uses GET-only operations — no writes required.\n *\n * Checks:\n * - Channel enum values (hard fail on invalid values)\n * - Pricing field names: fixed_price (not fixed_rate), floor_price top-level\n * - Format assets: assets array with required boolean (not assets_required)\n */\n\nimport type { Product } from '../../types/core.generated';\nimport type {\n GetProductsResponse,\n GetSignalsResponse,\n ListCreativeFormatsResponse,\n Format,\n} from '../../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile, validateResponseSchema } from '../client';\n\n// v3 channel taxonomy — 19 channels\nconst V3_CHANNELS = new Set([\n 'display',\n 'olv',\n 'social',\n 'search',\n 'ctv',\n 'linear_tv',\n 'radio',\n 'streaming_audio',\n 'podcast',\n 'dooh',\n 'ooh',\n 'print',\n 'cinema',\n 'email',\n 'gaming',\n 'retail_media',\n 'influencer',\n 'affiliate',\n 'product_placement',\n]);\n\nexport async function testSchemaCompliance(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n if (!profile.tools.includes('get_products') && !profile.tools.includes('get_signals')) {\n // Path A: no supported discovery tool — skip field-shape checks gracefully\n steps.push({\n step: 'Schema compliance check support',\n passed: true,\n duration_ms: 0,\n details: 'Agent does not advertise get_products or get_signals — discovery field-shape checks skipped',\n warnings: ['Schema compliance: no supported discovery tool (get_products, get_signals) found; checks skipped'],\n });\n // Fall through to list_creative_formats check below\n } else if (profile.tools.includes('get_signals') && !profile.tools.includes('get_products')) {\n // Path B: signals agent — validate GetSignalsResponse schema and field semantics\n const { result: signalsResult, step: signalsStep } = await runStep<TaskResult>(\n 'Get signals (schema compliance)',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Schema compliance test — retrieve all available signals',\n }) as Promise<TaskResult>\n );\n\n if (!signalsResult?.success || !signalsResult?.data) {\n signalsStep.passed = false;\n signalsStep.error = signalsResult?.error || 'get_signals returned no data';\n steps.push(signalsStep);\n return { steps, profile };\n }\n steps.push(signalsStep);\n\n const signalsData = signalsResult.data as GetSignalsResponse;\n // Zod schema validation covers required-field presence (signal_agent_segment_id, name, signal_type).\n steps.push(validateResponseSchema('get_signals', signalsData));\n\n const signals = signalsData.signals ?? [];\n steps.push({\n step: 'Validate signal required fields',\n passed: true,\n duration_ms: 0,\n details:\n signals.length === 0\n ? 'Agent returned no signals — field-shape checks skipped'\n : `${signals.length} signal(s) validated via schema check (signal_agent_segment_id, name, signal_type)`,\n warnings:\n signals.length === 0\n ? ['No signals returned; cannot validate signal_agent_segment_id, name, signal_type fields']\n : undefined,\n });\n // Fall through to list_creative_formats check below\n } else {\n // Path C: get_products present — existing product catalog checks\n const { result: productsResult, step: productsStep } = await runStep<TaskResult>(\n 'Get products (schema compliance)',\n 'get_products',\n async () =>\n client.getProducts({\n buying_mode: 'brief',\n brief: options.brief || 'Schema compliance test — retrieve all available products',\n brand: options.brand,\n }) as Promise<TaskResult>\n );\n\n if (!productsResult?.success || !productsResult?.data) {\n productsStep.passed = false;\n productsStep.error = productsResult?.error || 'get_products returned no data';\n steps.push(productsStep);\n return { steps, profile };\n }\n steps.push(productsStep);\n\n const data = productsResult.data as GetProductsResponse;\n const products: Product[] = data.products || [];\n\n // --- Zod schema validation (catches missing required fields + invalid enum values) ---\n steps.push(validateResponseSchema('get_products', data));\n\n if (products.length === 0) {\n steps.push({\n step: 'Schema compliance: no products to validate',\n passed: true,\n duration_ms: 0,\n details: 'Agent returned no products — schema compliance checks skipped',\n warnings: ['No products returned; cannot validate channel, pricing, or format field schemas'],\n });\n return { steps, profile };\n }\n\n // --- Channel enum validation (hard fail) ---\n const invalidChannels: string[] = [];\n const allChannels = new Set<string>();\n\n for (const product of products) {\n for (const channel of product.channels || []) {\n allChannels.add(channel);\n if (!V3_CHANNELS.has(channel)) {\n invalidChannels.push(`\"${channel}\" in product ${product.product_id}`);\n }\n }\n }\n\n steps.push({\n step: 'Validate channel enum values',\n passed: invalidChannels.length === 0,\n duration_ms: 0,\n details:\n invalidChannels.length === 0\n ? `All ${allChannels.size} channel value(s) are valid v3 channels: ${Array.from(allChannels).join(', ')}`\n : `Invalid channel values detected (not in v3 taxonomy): ${invalidChannels.join('; ')}`,\n error:\n invalidChannels.length > 0\n ? `Channel enum violations: ${invalidChannels.join('; ')}. Valid channels: ${Array.from(V3_CHANNELS).join(', ')}`\n : undefined,\n response_preview: JSON.stringify(\n {\n channels_found: Array.from(allChannels),\n invalid_channels: invalidChannels,\n },\n null,\n 2\n ),\n });\n\n // --- Pricing field name validation (warn, not fail) ---\n const pricingIssues: string[] = [];\n const pricingChecked: string[] = [];\n let fixedPriceFound = false;\n\n for (const product of products) {\n for (const option of product.pricing_options || []) {\n const optionId = option.pricing_option_id || '(unknown)';\n // Cast to Record for deprecated-field checks — compliance testing intentionally\n // probes fields that may not exist on the generated PricingOption union\n const raw = option as unknown as Record<string, unknown>;\n\n // Check for deprecated fixed_rate field\n if ('fixed_rate' in raw) {\n pricingIssues.push(`pricing_option ${optionId} uses deprecated \"fixed_rate\" — should be \"fixed_price\"`);\n }\n if ('fixed_price' in raw) {\n fixedPriceFound = true;\n pricingChecked.push(optionId);\n }\n\n // Check for floor_price inside price_guidance (deprecated location)\n const pg = raw.price_guidance as Record<string, unknown> | undefined;\n if (pg && 'floor' in pg) {\n pricingIssues.push(\n `pricing_option ${optionId} has \"floor\" inside price_guidance — should be top-level \"floor_price\"`\n );\n }\n if ('floor_price' in raw) {\n pricingChecked.push(`${optionId} (floor_price)`);\n }\n }\n }\n\n const pricingPassed = pricingIssues.length === 0;\n const pricingDetails =\n pricingIssues.length > 0\n ? `Pricing field issues: ${pricingIssues.join('; ')}`\n : fixedPriceFound\n ? `Pricing fields valid (checked ${pricingChecked.length} option(s))`\n : 'No fixed-price products found to validate (agent may be auction-only — cannot confirm field names)';\n\n steps.push({\n step: 'Validate pricing field names',\n passed: pricingPassed,\n duration_ms: 0,\n details: pricingDetails,\n error: pricingIssues.length > 0 ? pricingIssues.join('; ') : undefined,\n warnings:\n !fixedPriceFound && pricingIssues.length === 0\n ? [\n 'No fixed-price products found. If agent supports fixed pricing, verify it uses \"fixed_price\" (not \"fixed_rate\") and \"floor_price\" at the pricing option level (not inside price_guidance).',\n ]\n : undefined,\n response_preview: JSON.stringify(\n {\n issues: pricingIssues,\n options_checked: pricingChecked,\n },\n null,\n 2\n ),\n });\n }\n\n // --- Format assets structure (optional: list_creative_formats) ---\n // Runs for all agent types that advertise list_creative_formats, regardless of discovery path\n if (profile.tools.includes('list_creative_formats')) {\n const { result: formatsResult, step: formatsStep } = await runStep<TaskResult>(\n 'Get creative formats (check assets structure)',\n 'list_creative_formats',\n async () => client.listCreativeFormats({}) as Promise<TaskResult>\n );\n\n if (formatsResult?.success && formatsResult?.data) {\n steps.push(validateResponseSchema('list_creative_formats', formatsResult.data));\n const formatsData = formatsResult.data as ListCreativeFormatsResponse;\n const formats: Format[] = formatsData.formats || [];\n const assetsIssues: string[] = [];\n let formatsChecked = 0;\n\n for (const format of formats) {\n formatsChecked++;\n const formatIdStr = typeof format.format_id === 'object' ? format.format_id.id : String(format.format_id);\n // Check for deprecated assets_required field\n if ('assets_required' in format) {\n assetsIssues.push(\n `format ${formatIdStr} uses deprecated \"assets_required\" — should be \"assets\" array with \"required\" boolean`\n );\n }\n // Validate assets array structure\n if (Array.isArray(format.assets)) {\n for (const asset of format.assets) {\n if (!('required' in asset)) {\n assetsIssues.push(`format ${formatIdStr} asset missing \"required\" boolean field`);\n }\n }\n }\n }\n\n formatsStep.details =\n assetsIssues.length === 0\n ? `Format assets valid across ${formatsChecked} format(s)`\n : `Format asset issues: ${assetsIssues.join('; ')}`;\n formatsStep.passed = assetsIssues.length === 0;\n formatsStep.error = assetsIssues.length > 0 ? assetsIssues.join('; ') : undefined;\n }\n steps.push(formatsStep);\n }\n\n return { steps, profile };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/testing/scenarios/schema-compliance.ts"],"sourcesContent":["/**\n * Schema Compliance Testing\n *\n * Validates that an agent's responses use correct v3 field names and enum values.\n * Uses GET-only operations — no writes required.\n *\n * Checks:\n * - Channel enum values (hard fail on invalid values)\n * - Pricing field names: fixed_price (not fixed_rate), floor_price top-level\n * - Format assets: assets array with required boolean (not assets_required)\n */\n\nimport type { Product } from '../../types/core.generated';\nimport type {\n GetProductsResponse,\n GetSignalsResponse,\n ListCreativeFormatsResponse,\n Format,\n} from '../../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile, validateResponseSchema } from '../client';\n\n// v3 channel taxonomy — 19 channels\nconst V3_CHANNELS = new Set([\n 'display',\n 'olv',\n 'social',\n 'search',\n 'ctv',\n 'linear_tv',\n 'radio',\n 'streaming_audio',\n 'podcast',\n 'dooh',\n 'ooh',\n 'print',\n 'cinema',\n 'email',\n 'gaming',\n 'retail_media',\n 'influencer',\n 'affiliate',\n 'product_placement',\n]);\n\nexport async function testSchemaCompliance(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n if (!profile.tools.includes('get_products') && !profile.tools.includes('get_signals')) {\n // Path A: no supported discovery tool — skip field-shape checks gracefully\n steps.push({\n step: 'Schema compliance check support',\n passed: true,\n duration_ms: 0,\n details: 'Agent does not advertise get_products or get_signals — discovery field-shape checks skipped',\n warnings: ['Schema compliance: no supported discovery tool (get_products, get_signals) found; checks skipped'],\n });\n // Fall through to list_creative_formats check below\n } else if (profile.tools.includes('get_signals') && !profile.tools.includes('get_products')) {\n // Path B: signals agent — validate GetSignalsResponse schema and field semantics\n const { result: signalsResult, step: signalsStep } = await runStep<TaskResult>(\n 'Get signals (schema compliance)',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Schema compliance test — retrieve all available signals',\n }) as Promise<TaskResult>\n );\n\n if (!signalsResult?.success || !signalsResult?.data) {\n signalsStep.passed = false;\n signalsStep.error = signalsResult?.error || 'get_signals returned no data';\n steps.push(signalsStep);\n return { steps, profile };\n }\n steps.push(signalsStep);\n\n const signalsData = signalsResult.data as GetSignalsResponse;\n // Zod schema validation covers required-field presence (signal_agent_segment_id, name, signal_type).\n steps.push(validateResponseSchema('get_signals', signalsData));\n\n const signals = signalsData.signals ?? [];\n steps.push({\n step: 'Validate signal required fields',\n passed: true,\n duration_ms: 0,\n details:\n signals.length === 0\n ? 'Agent returned no signals — field-shape checks skipped'\n : `${signals.length} signal(s) validated via schema check (signal_agent_segment_id, name, signal_type)`,\n warnings:\n signals.length === 0\n ? ['No signals returned; cannot validate signal_agent_segment_id, name, signal_type fields']\n : undefined,\n });\n // Fall through to list_creative_formats check below\n } else {\n // Path C: get_products present — existing product catalog checks\n const { result: productsResult, step: productsStep } = await runStep<TaskResult>(\n 'Get products (schema compliance)',\n 'get_products',\n async () =>\n client.getProducts({\n buying_mode: 'brief',\n brief: options.brief || 'Schema compliance test — retrieve all available products',\n brand: options.brand,\n }) as Promise<TaskResult>\n );\n\n if (!productsResult?.success || !productsResult?.data) {\n productsStep.passed = false;\n productsStep.error = productsResult?.error || 'get_products returned no data';\n steps.push(productsStep);\n return { steps, profile };\n }\n steps.push(productsStep);\n\n const data = productsResult.data as GetProductsResponse;\n const products: Product[] = data.products || [];\n\n // --- Zod schema validation (catches missing required fields + invalid enum values) ---\n steps.push(validateResponseSchema('get_products', data));\n\n if (products.length === 0) {\n steps.push({\n step: 'Schema compliance: no products to validate',\n passed: true,\n duration_ms: 0,\n details: 'Agent returned no products — schema compliance checks skipped',\n warnings: ['No products returned; cannot validate channel, pricing, or format field schemas'],\n });\n return { steps, profile };\n }\n\n // --- Channel enum validation (hard fail) ---\n const invalidChannels: string[] = [];\n const allChannels = new Set<string>();\n\n for (const product of products) {\n for (const channel of product.channels || []) {\n allChannels.add(channel);\n if (!V3_CHANNELS.has(channel)) {\n invalidChannels.push(`\"${channel}\" in product ${product.product_id}`);\n }\n }\n }\n\n steps.push({\n step: 'Validate channel enum values',\n passed: invalidChannels.length === 0,\n duration_ms: 0,\n details:\n invalidChannels.length === 0\n ? `All ${allChannels.size} channel value(s) are valid v3 channels: ${Array.from(allChannels).join(', ')}`\n : `Invalid channel values detected (not in v3 taxonomy): ${invalidChannels.join('; ')}`,\n error:\n invalidChannels.length > 0\n ? `Channel enum violations: ${invalidChannels.join('; ')}. Valid channels: ${Array.from(V3_CHANNELS).join(', ')}`\n : undefined,\n response_preview: JSON.stringify(\n {\n channels_found: Array.from(allChannels),\n invalid_channels: invalidChannels,\n },\n null,\n 2\n ),\n });\n\n // --- Pricing field name validation (warn, not fail) ---\n const pricingIssues: string[] = [];\n const pricingChecked: string[] = [];\n let fixedPriceFound = false;\n\n for (const product of products) {\n for (const option of product.pricing_options || []) {\n const optionId = option.pricing_option_id || '(unknown)';\n // Cast to Record for deprecated-field checks — compliance testing intentionally\n // probes fields that may not exist on the generated PricingOption union\n const raw = option as unknown as Record<string, unknown>;\n\n // Check for deprecated fixed_rate field\n if ('fixed_rate' in raw) {\n pricingIssues.push(`pricing_option ${optionId} uses deprecated \"fixed_rate\" — should be \"fixed_price\"`);\n }\n if ('fixed_price' in raw) {\n fixedPriceFound = true;\n pricingChecked.push(optionId);\n }\n\n // Check for floor_price inside price_guidance (deprecated location)\n const pg = raw.price_guidance as Record<string, unknown> | undefined;\n if (pg && 'floor' in pg) {\n pricingIssues.push(\n `pricing_option ${optionId} has \"floor\" inside price_guidance — should be top-level \"floor_price\"`\n );\n }\n if ('floor_price' in raw) {\n pricingChecked.push(`${optionId} (floor_price)`);\n }\n }\n }\n\n const pricingPassed = pricingIssues.length === 0;\n const pricingDetails =\n pricingIssues.length > 0\n ? `Pricing field issues: ${pricingIssues.join('; ')}`\n : fixedPriceFound\n ? `Pricing fields valid (checked ${pricingChecked.length} option(s))`\n : 'No fixed-price products found to validate (agent may be auction-only — cannot confirm field names)';\n\n steps.push({\n step: 'Validate pricing field names',\n passed: pricingPassed,\n duration_ms: 0,\n details: pricingDetails,\n error: pricingIssues.length > 0 ? pricingIssues.join('; ') : undefined,\n warnings:\n !fixedPriceFound && pricingIssues.length === 0\n ? [\n 'No fixed-price products found. If agent supports fixed pricing, verify it uses \"fixed_price\" (not \"fixed_rate\") and \"floor_price\" at the pricing option level (not inside price_guidance).',\n ]\n : undefined,\n response_preview: JSON.stringify(\n {\n issues: pricingIssues,\n options_checked: pricingChecked,\n },\n null,\n 2\n ),\n });\n }\n\n // --- Format assets structure (optional: list_creative_formats) ---\n // Runs for all agent types that advertise list_creative_formats, regardless of discovery path\n if (profile.tools.includes('list_creative_formats')) {\n const { result: formatsResult, step: formatsStep } = await runStep<TaskResult>(\n 'Get creative formats (check assets structure)',\n 'list_creative_formats',\n async () => client.listCreativeFormatsLegacy({}) as Promise<TaskResult>\n );\n\n if (formatsResult?.success && formatsResult?.data) {\n steps.push(validateResponseSchema('list_creative_formats', formatsResult.data));\n const formatsData = formatsResult.data as ListCreativeFormatsResponse;\n const formats: Format[] = formatsData.formats || [];\n const assetsIssues: string[] = [];\n let formatsChecked = 0;\n\n for (const format of formats) {\n formatsChecked++;\n const formatIdStr = typeof format.format_id === 'object' ? format.format_id.id : String(format.format_id);\n // Check for deprecated assets_required field\n if ('assets_required' in format) {\n assetsIssues.push(\n `format ${formatIdStr} uses deprecated \"assets_required\" — should be \"assets\" array with \"required\" boolean`\n );\n }\n // Validate assets array structure\n if (Array.isArray(format.assets)) {\n for (const asset of format.assets) {\n if (!('required' in asset)) {\n assetsIssues.push(`format ${formatIdStr} asset missing \"required\" boolean field`);\n }\n }\n }\n }\n\n formatsStep.details =\n assetsIssues.length === 0\n ? `Format assets valid across ${formatsChecked} format(s)`\n : `Format asset issues: ${assetsIssues.join('; ')}`;\n formatsStep.passed = assetsIssues.length === 0;\n formatsStep.error = assetsIssues.length > 0 ? assetsIssues.join('; ') : undefined;\n }\n steps.push(formatsStep);\n }\n\n return { steps, profile };\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"trusted-match.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAc,MAAM,UAAU,CAAC;AAItF;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,CAAC,CA4H9D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAE7D"}
1
+ {"version":3,"file":"trusted-match.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAc,MAAM,UAAU,CAAC;AAItF;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,CAAC,CA6H9D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAE7D"}
@@ -51,8 +51,9 @@ async function testTrustedMatchFlow(agentUrl, options) {
51
51
  type: "context_match_request",
52
52
  request_id: `e2e-ctx-${Date.now()}`,
53
53
  property_rid: "00000000-0000-7000-0000-000000000001",
54
- property_type: "web",
54
+ property_type: "website",
55
55
  placement_id: "e2e-test-placement",
56
+ seller_agent_url: agentUrl,
56
57
  context_signals: {
57
58
  topics: ["632"],
58
59
  taxonomy_source: "iab",
@@ -100,8 +101,8 @@ async function testTrustedMatchFlow(agentUrl, options) {
100
101
  async () => client.executeTask("identity_match", {
101
102
  type: "identity_match_request",
102
103
  request_id: `e2e-id-${Date.now()}`,
103
- user_token: "e2e-test-opaque-token",
104
- uid_type: "publisher_first_party",
104
+ seller_agent_url: agentUrl,
105
+ identities: [{ user_token: "e2e-test-opaque-token", uid_type: "publisher_first_party" }],
105
106
  package_ids: ["e2e-test-package-001", "e2e-test-package-002"],
106
107
  consent: {
107
108
  gdpr: false
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"sourcesContent":["/**\n * Trusted Match Protocol (TMP) Testing Scenarios (v3)\n *\n * Tests TMP agent capabilities including:\n * - context_match — evaluates packages against content context (no user identity)\n * - identity_match — evaluates user eligibility for packages using an opaque identity token (no page context)\n */\n\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile } from '../client';\nimport { TRUSTED_MATCH_TOOLS } from '../../utils/capabilities';\n\n/**\n * Test: Trusted Match Flow\n *\n * Flow: discover profile -> check TMP tools -> context_match -> identity_match\n */\nexport async function testTrustedMatchFlow(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n // Discover agent profile\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n // Check if agent supports any TMP tools\n const hasTMP = TRUSTED_MATCH_TOOLS.some(t => profile.tools.includes(t));\n if (!hasTMP) {\n steps.push({\n step: 'TMP support check',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support Trusted Match Protocol tools',\n details: `Required tools: ${TRUSTED_MATCH_TOOLS.join(', ')}. Available: ${profile.tools.join(', ')}`,\n });\n return { steps, profile };\n }\n\n // Test: context_match\n if (profile.tools.includes('context_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Context match: evaluate packages against page context',\n 'context_match',\n async () =>\n client.executeTask('context_match', {\n type: 'context_match_request',\n request_id: `e2e-ctx-${Date.now()}`,\n property_rid: '00000000-0000-7000-0000-000000000001',\n property_type: 'web',\n placement_id: 'e2e-test-placement',\n context_signals: {\n topics: ['632'],\n taxonomy_source: 'iab',\n taxonomy_id: 7,\n sentiment: 'positive',\n keywords: ['technology', 'innovation'],\n language: 'en',\n },\n geo: {\n country: 'US',\n region: 'US-CA',\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const offers = Array.isArray(data['offers']) ? data['offers'] : [];\n step.details = `Context match returned ${offers.length} offer(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n offers_count: offers.length,\n cache_ttl: data['cache_ttl'],\n has_signals: !!data['signals'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Context match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'context_match failed';\n }\n }\n steps.push(step);\n }\n\n // Test: identity_match\n if (profile.tools.includes('identity_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Identity match: evaluate user eligibility for packages',\n 'identity_match',\n async () =>\n client.executeTask('identity_match', {\n type: 'identity_match_request',\n request_id: `e2e-id-${Date.now()}`,\n user_token: 'e2e-test-opaque-token',\n uid_type: 'publisher_first_party',\n package_ids: ['e2e-test-package-001', 'e2e-test-package-002'],\n consent: {\n gdpr: false,\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const eligibleIds = Array.isArray(data['eligible_package_ids']) ? data['eligible_package_ids'] : [];\n step.details = `Identity match returned ${eligibleIds.length} eligible package(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n eligible_package_ids: eligibleIds,\n ttl_sec: data['ttl_sec'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Identity match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'identity_match failed';\n }\n }\n steps.push(step);\n }\n\n return { steps, profile };\n}\n\n/**\n * Check if agent has any TMP tools\n */\nexport function hasTrustedMatchTools(tools: string[]): boolean {\n return TRUSTED_MATCH_TOOLS.some(t => tools.includes(t));\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"sourcesContent":["/**\n * Trusted Match Protocol (TMP) Testing Scenarios (v3)\n *\n * Tests TMP agent capabilities including:\n * - context_match — evaluates packages against content context (no user identity)\n * - identity_match — evaluates user eligibility for packages using an opaque identity token (no page context)\n */\n\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile } from '../client';\nimport { TRUSTED_MATCH_TOOLS } from '../../utils/capabilities';\n\n/**\n * Test: Trusted Match Flow\n *\n * Flow: discover profile -> check TMP tools -> context_match -> identity_match\n */\nexport async function testTrustedMatchFlow(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n // Discover agent profile\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n // Check if agent supports any TMP tools\n const hasTMP = TRUSTED_MATCH_TOOLS.some(t => profile.tools.includes(t));\n if (!hasTMP) {\n steps.push({\n step: 'TMP support check',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support Trusted Match Protocol tools',\n details: `Required tools: ${TRUSTED_MATCH_TOOLS.join(', ')}. Available: ${profile.tools.join(', ')}`,\n });\n return { steps, profile };\n }\n\n // Test: context_match\n if (profile.tools.includes('context_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Context match: evaluate packages against page context',\n 'context_match',\n async () =>\n client.executeTask('context_match', {\n type: 'context_match_request',\n request_id: `e2e-ctx-${Date.now()}`,\n property_rid: '00000000-0000-7000-0000-000000000001',\n property_type: 'website',\n placement_id: 'e2e-test-placement',\n seller_agent_url: agentUrl,\n context_signals: {\n topics: ['632'],\n taxonomy_source: 'iab',\n taxonomy_id: 7,\n sentiment: 'positive',\n keywords: ['technology', 'innovation'],\n language: 'en',\n },\n geo: {\n country: 'US',\n region: 'US-CA',\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const offers = Array.isArray(data['offers']) ? data['offers'] : [];\n step.details = `Context match returned ${offers.length} offer(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n offers_count: offers.length,\n cache_ttl: data['cache_ttl'],\n has_signals: !!data['signals'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Context match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'context_match failed';\n }\n }\n steps.push(step);\n }\n\n // Test: identity_match\n if (profile.tools.includes('identity_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Identity match: evaluate user eligibility for packages',\n 'identity_match',\n async () =>\n client.executeTask('identity_match', {\n type: 'identity_match_request',\n request_id: `e2e-id-${Date.now()}`,\n seller_agent_url: agentUrl,\n identities: [{ user_token: 'e2e-test-opaque-token', uid_type: 'publisher_first_party' }],\n package_ids: ['e2e-test-package-001', 'e2e-test-package-002'],\n consent: {\n gdpr: false,\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const eligibleIds = Array.isArray(data['eligible_package_ids']) ? data['eligible_package_ids'] : [];\n step.details = `Identity match returned ${eligibleIds.length} eligible package(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n eligible_package_ids: eligibleIds,\n ttl_sec: data['ttl_sec'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Identity match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'identity_match failed';\n }\n }\n steps.push(step);\n }\n\n return { steps, profile };\n}\n\n/**\n * Check if agent has any TMP tools\n */\nexport function hasTrustedMatchTools(tools: string[]): boolean {\n return TRUSTED_MATCH_TOOLS.some(t => tools.includes(t));\n}\n"],"mappings":"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","names":[]}
@@ -27,8 +27,9 @@ async function testTrustedMatchFlow(agentUrl, options) {
27
27
  type: "context_match_request",
28
28
  request_id: `e2e-ctx-${Date.now()}`,
29
29
  property_rid: "00000000-0000-7000-0000-000000000001",
30
- property_type: "web",
30
+ property_type: "website",
31
31
  placement_id: "e2e-test-placement",
32
+ seller_agent_url: agentUrl,
32
33
  context_signals: {
33
34
  topics: ["632"],
34
35
  taxonomy_source: "iab",
@@ -76,8 +77,8 @@ async function testTrustedMatchFlow(agentUrl, options) {
76
77
  async () => client.executeTask("identity_match", {
77
78
  type: "identity_match_request",
78
79
  request_id: `e2e-id-${Date.now()}`,
79
- user_token: "e2e-test-opaque-token",
80
- uid_type: "publisher_first_party",
80
+ seller_agent_url: agentUrl,
81
+ identities: [{ user_token: "e2e-test-opaque-token", uid_type: "publisher_first_party" }],
81
82
  package_ids: ["e2e-test-package-001", "e2e-test-package-002"],
82
83
  consent: {
83
84
  gdpr: false
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"sourcesContent":["/**\n * Trusted Match Protocol (TMP) Testing Scenarios (v3)\n *\n * Tests TMP agent capabilities including:\n * - context_match — evaluates packages against content context (no user identity)\n * - identity_match — evaluates user eligibility for packages using an opaque identity token (no page context)\n */\n\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile } from '../client';\nimport { TRUSTED_MATCH_TOOLS } from '../../utils/capabilities';\n\n/**\n * Test: Trusted Match Flow\n *\n * Flow: discover profile -> check TMP tools -> context_match -> identity_match\n */\nexport async function testTrustedMatchFlow(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n // Discover agent profile\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n // Check if agent supports any TMP tools\n const hasTMP = TRUSTED_MATCH_TOOLS.some(t => profile.tools.includes(t));\n if (!hasTMP) {\n steps.push({\n step: 'TMP support check',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support Trusted Match Protocol tools',\n details: `Required tools: ${TRUSTED_MATCH_TOOLS.join(', ')}. Available: ${profile.tools.join(', ')}`,\n });\n return { steps, profile };\n }\n\n // Test: context_match\n if (profile.tools.includes('context_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Context match: evaluate packages against page context',\n 'context_match',\n async () =>\n client.executeTask('context_match', {\n type: 'context_match_request',\n request_id: `e2e-ctx-${Date.now()}`,\n property_rid: '00000000-0000-7000-0000-000000000001',\n property_type: 'web',\n placement_id: 'e2e-test-placement',\n context_signals: {\n topics: ['632'],\n taxonomy_source: 'iab',\n taxonomy_id: 7,\n sentiment: 'positive',\n keywords: ['technology', 'innovation'],\n language: 'en',\n },\n geo: {\n country: 'US',\n region: 'US-CA',\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const offers = Array.isArray(data['offers']) ? data['offers'] : [];\n step.details = `Context match returned ${offers.length} offer(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n offers_count: offers.length,\n cache_ttl: data['cache_ttl'],\n has_signals: !!data['signals'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Context match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'context_match failed';\n }\n }\n steps.push(step);\n }\n\n // Test: identity_match\n if (profile.tools.includes('identity_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Identity match: evaluate user eligibility for packages',\n 'identity_match',\n async () =>\n client.executeTask('identity_match', {\n type: 'identity_match_request',\n request_id: `e2e-id-${Date.now()}`,\n user_token: 'e2e-test-opaque-token',\n uid_type: 'publisher_first_party',\n package_ids: ['e2e-test-package-001', 'e2e-test-package-002'],\n consent: {\n gdpr: false,\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const eligibleIds = Array.isArray(data['eligible_package_ids']) ? data['eligible_package_ids'] : [];\n step.details = `Identity match returned ${eligibleIds.length} eligible package(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n eligible_package_ids: eligibleIds,\n ttl_sec: data['ttl_sec'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Identity match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'identity_match failed';\n }\n }\n steps.push(step);\n }\n\n return { steps, profile };\n}\n\n/**\n * Check if agent has any TMP tools\n */\nexport function hasTrustedMatchTools(tools: string[]): boolean {\n return TRUSTED_MATCH_TOOLS.some(t => tools.includes(t));\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"sourcesContent":["/**\n * Trusted Match Protocol (TMP) Testing Scenarios (v3)\n *\n * Tests TMP agent capabilities including:\n * - context_match — evaluates packages against content context (no user identity)\n * - identity_match — evaluates user eligibility for packages using an opaque identity token (no page context)\n */\n\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile } from '../client';\nimport { TRUSTED_MATCH_TOOLS } from '../../utils/capabilities';\n\n/**\n * Test: Trusted Match Flow\n *\n * Flow: discover profile -> check TMP tools -> context_match -> identity_match\n */\nexport async function testTrustedMatchFlow(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n // Discover agent profile\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n // Check if agent supports any TMP tools\n const hasTMP = TRUSTED_MATCH_TOOLS.some(t => profile.tools.includes(t));\n if (!hasTMP) {\n steps.push({\n step: 'TMP support check',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support Trusted Match Protocol tools',\n details: `Required tools: ${TRUSTED_MATCH_TOOLS.join(', ')}. Available: ${profile.tools.join(', ')}`,\n });\n return { steps, profile };\n }\n\n // Test: context_match\n if (profile.tools.includes('context_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Context match: evaluate packages against page context',\n 'context_match',\n async () =>\n client.executeTask('context_match', {\n type: 'context_match_request',\n request_id: `e2e-ctx-${Date.now()}`,\n property_rid: '00000000-0000-7000-0000-000000000001',\n property_type: 'website',\n placement_id: 'e2e-test-placement',\n seller_agent_url: agentUrl,\n context_signals: {\n topics: ['632'],\n taxonomy_source: 'iab',\n taxonomy_id: 7,\n sentiment: 'positive',\n keywords: ['technology', 'innovation'],\n language: 'en',\n },\n geo: {\n country: 'US',\n region: 'US-CA',\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const offers = Array.isArray(data['offers']) ? data['offers'] : [];\n step.details = `Context match returned ${offers.length} offer(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n offers_count: offers.length,\n cache_ttl: data['cache_ttl'],\n has_signals: !!data['signals'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Context match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'context_match failed';\n }\n }\n steps.push(step);\n }\n\n // Test: identity_match\n if (profile.tools.includes('identity_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Identity match: evaluate user eligibility for packages',\n 'identity_match',\n async () =>\n client.executeTask('identity_match', {\n type: 'identity_match_request',\n request_id: `e2e-id-${Date.now()}`,\n seller_agent_url: agentUrl,\n identities: [{ user_token: 'e2e-test-opaque-token', uid_type: 'publisher_first_party' }],\n package_ids: ['e2e-test-package-001', 'e2e-test-package-002'],\n consent: {\n gdpr: false,\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const eligibleIds = Array.isArray(data['eligible_package_ids']) ? data['eligible_package_ids'] : [];\n step.details = `Identity match returned ${eligibleIds.length} eligible package(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n eligible_package_ids: eligibleIds,\n ttl_sec: data['ttl_sec'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Identity match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'identity_match failed';\n }\n }\n steps.push(step);\n }\n\n return { steps, profile };\n}\n\n/**\n * Check if agent has any TMP tools\n */\nexport function hasTrustedMatchTools(tools: string[]): boolean {\n return TRUSTED_MATCH_TOOLS.some(t => tools.includes(t));\n}\n"],"mappings":"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","names":[]}
@@ -26,10 +26,9 @@ import type { ShapeDriftHint } from './types.mjs';
26
26
  * helper that builds the correct shape.
27
27
  *
28
28
  * Helper names aren't uniformly prefixed — `get_products` uses
29
- * `productsResponse` (no `get` prefix) while `get_media_buys` uses
30
- * `getMediaBuysResponse`. Names match the exports in
31
- * `src/lib/server/responses.ts` verbatim so a developer can grep
32
- * straight from the hint.
29
+ * `legacyProductsResponse` (no `get` prefix) while `get_media_buys` uses
30
+ * `legacyGetMediaBuysResponse`. Names match the explicit compatibility
31
+ * aliases on `@adcp/sdk/server`.
33
32
  */
34
33
  export declare const LIST_WRAPPER_TOOLS: Record<string, {
35
34
  wrapperKey: string;
@@ -26,10 +26,9 @@ import type { ShapeDriftHint } from './types';
26
26
  * helper that builds the correct shape.
27
27
  *
28
28
  * Helper names aren't uniformly prefixed — `get_products` uses
29
- * `productsResponse` (no `get` prefix) while `get_media_buys` uses
30
- * `getMediaBuysResponse`. Names match the exports in
31
- * `src/lib/server/responses.ts` verbatim so a developer can grep
32
- * straight from the hint.
29
+ * `legacyProductsResponse` (no `get` prefix) while `get_media_buys` uses
30
+ * `legacyGetMediaBuysResponse`. Names match the explicit compatibility
31
+ * aliases on `@adcp/sdk/server`.
33
32
  */
34
33
  export declare const LIST_WRAPPER_TOOLS: Record<string, {
35
34
  wrapperKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"shape-drift-hints.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/storyboard/shape-drift-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA0C9C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAWrF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CAKnH"}
1
+ {"version":3,"file":"shape-drift-hints.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/storyboard/shape-drift-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA0C9C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAWrF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CAKnH"}
@@ -23,19 +23,19 @@ __export(shape_drift_hints_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(shape_drift_hints_exports);
25
25
  const HELPER_MIN_VERSION = {
26
- buildCreativeResponse: "5.14.0",
27
- listCreativesResponse: "5.10.0",
28
- listCreativeFormatsResponse: "5.10.0",
29
- listAccountsResponse: "5.10.0",
30
- productsResponse: "5.10.0",
31
- getMediaBuysResponse: "5.10.0",
32
- getSignalsResponse: "5.10.0",
33
- listPropertyListsResponse: "5.10.0",
34
- listCollectionListsResponse: "5.10.0",
35
- listContentStandardsResponse: "5.10.0",
36
- getPlanAuditLogsResponse: "5.10.0",
37
- syncCreativesResponse: "5.10.0",
38
- previewCreativeResponse: "5.10.0"
26
+ legacyBuildCreativeResponse: "13.0.0",
27
+ legacyListCreativesResponse: "13.0.0",
28
+ legacyListCreativeFormatsResponse: "13.0.0",
29
+ legacyListAccountsResponse: "13.0.0",
30
+ legacyProductsResponse: "13.0.0",
31
+ legacyGetMediaBuysResponse: "13.0.0",
32
+ legacyGetSignalsResponse: "13.0.0",
33
+ legacyListPropertyListsResponse: "13.0.0",
34
+ legacyListCollectionListsResponse: "13.0.0",
35
+ legacyListContentStandardsResponse: "13.0.0",
36
+ legacyGetPlanAuditLogsResponse: "13.0.0",
37
+ legacySyncCreativesResponse: "13.0.0",
38
+ legacyPreviewCreativeResponse: "13.0.0"
39
39
  };
40
40
  function semverLessThan(a, b) {
41
41
  const normalize = (v) => v.replace(/^.*@/, "").replace(/-.*$/, "");
@@ -47,16 +47,16 @@ function semverLessThan(a, b) {
47
47
  return aPatch < bPatch;
48
48
  }
49
49
  const LIST_WRAPPER_TOOLS = {
50
- list_creatives: { wrapperKey: "creatives", helper: "listCreativesResponse" },
51
- list_creative_formats: { wrapperKey: "formats", helper: "listCreativeFormatsResponse" },
52
- list_accounts: { wrapperKey: "accounts", helper: "listAccountsResponse" },
53
- get_products: { wrapperKey: "products", helper: "productsResponse" },
54
- get_media_buys: { wrapperKey: "media_buys", helper: "getMediaBuysResponse" },
55
- get_signals: { wrapperKey: "signals", helper: "getSignalsResponse" },
56
- list_property_lists: { wrapperKey: "lists", helper: "listPropertyListsResponse" },
57
- list_collection_lists: { wrapperKey: "lists", helper: "listCollectionListsResponse" },
58
- list_content_standards: { wrapperKey: "standards", helper: "listContentStandardsResponse" },
59
- get_plan_audit_logs: { wrapperKey: "plans", helper: "getPlanAuditLogsResponse" }
50
+ list_creatives: { wrapperKey: "creatives", helper: "legacyListCreativesResponse" },
51
+ list_creative_formats: { wrapperKey: "formats", helper: "legacyListCreativeFormatsResponse" },
52
+ list_accounts: { wrapperKey: "accounts", helper: "legacyListAccountsResponse" },
53
+ get_products: { wrapperKey: "products", helper: "legacyProductsResponse" },
54
+ get_media_buys: { wrapperKey: "media_buys", helper: "legacyGetMediaBuysResponse" },
55
+ get_signals: { wrapperKey: "signals", helper: "legacyGetSignalsResponse" },
56
+ list_property_lists: { wrapperKey: "lists", helper: "legacyListPropertyListsResponse" },
57
+ list_collection_lists: { wrapperKey: "lists", helper: "legacyListCollectionListsResponse" },
58
+ list_content_standards: { wrapperKey: "standards", helper: "legacyListContentStandardsResponse" },
59
+ get_plan_audit_logs: { wrapperKey: "plans", helper: "legacyGetPlanAuditLogsResponse" }
60
60
  };
61
61
  function detectShapeDriftHints(taskName, payload, libraryVersion) {
62
62
  const hint = detect(taskName, payload);
@@ -100,7 +100,7 @@ function detect(taskName, payload) {
100
100
  observed_variant: "platform_native_fields",
101
101
  expected_variant: "{ creative_manifest: { format_id, assets } }",
102
102
  instance_path: "",
103
- message: `build_creative returned platform-native fields at the top level (${platformNativePresent.join(", ")}). Required: { creative_manifest: { format_id, assets } }. Use buildCreativeResponse() from @adcp/sdk/server.`
103
+ message: `build_creative returned platform-native fields at the top level (${platformNativePresent.join(", ")}). Required: { creative_manifest: { format_id, assets } }. Use legacyBuildCreativeResponse() from @adcp/sdk/server.`
104
104
  };
105
105
  }
106
106
  }
@@ -115,7 +115,7 @@ function detect(taskName, payload) {
115
115
  observed_variant: "per_item_shape",
116
116
  expected_variant: "{ creatives: [{ creative_id, action, ... }] }",
117
117
  instance_path: "",
118
- message: `sync_creatives returned a single creative's inner shape at the top level (${perItemPresent.join(", ")}). Required: { creatives: [{ creative_id, action, ... }] } (or { errors: [...] } / { status: 'submitted', task_id }). Use syncCreativesResponse() from @adcp/sdk/server.`
118
+ message: `sync_creatives returned a single creative's inner shape at the top level (${perItemPresent.join(", ")}). Required: { creatives: [{ creative_id, action, ... }] } (or { errors: [...] } / { status: 'submitted', task_id }). Use legacySyncCreativesResponse() from @adcp/sdk/server.`
119
119
  };
120
120
  }
121
121
  const results = p.results;
@@ -129,7 +129,7 @@ function detect(taskName, payload) {
129
129
  observed_variant: "wrong_wrapper_key",
130
130
  expected_variant: "{ creatives: [{ creative_id, action, ... }] }",
131
131
  instance_path: "/results",
132
- message: `sync_creatives returned { results: [...] } instead of { creatives: [...] } \u2014 wrong wrapper key. Required: { creatives: [{ creative_id, action, ... }] }. Use syncCreativesResponse() from @adcp/sdk/server.`
132
+ message: `sync_creatives returned { results: [...] } instead of { creatives: [...] } \u2014 wrong wrapper key. Required: { creatives: [{ creative_id, action, ... }] }. Use legacySyncCreativesResponse() from @adcp/sdk/server.`
133
133
  };
134
134
  }
135
135
  }
@@ -146,7 +146,7 @@ function detect(taskName, payload) {
146
146
  observed_variant: "raw_render_fields",
147
147
  expected_variant: "{ response_type: 'single', previews: [{ renders: [...] }], expires_at }",
148
148
  instance_path: "",
149
- message: `preview_creative returned raw render fields at the top level (${driftSignal.join(", ")}). Required: { response_type: 'single', previews: [{ renders: [{ preview_url | preview_html }] }], expires_at }. Use previewCreativeResponse() from @adcp/sdk/server.`
149
+ message: `preview_creative returned raw render fields at the top level (${driftSignal.join(", ")}). Required: { response_type: 'single', previews: [{ renders: [{ preview_url | preview_html }] }], expires_at }. Use legacyPreviewCreativeResponse() from @adcp/sdk/server.`
150
150
  };
151
151
  }
152
152
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/testing/storyboard/shape-drift-hints.ts"],"sourcesContent":["/**\n * Structured shape-drift hint detection (issue #935).\n *\n * The runner emits one `ShapeDriftHint` per response when it recognizes a\n * common payload-shape mistake — bare arrays from list tools, platform-\n * native fields from `build_creative`, missing wrappers on `sync_creatives`\n * / `preview_creative`. Each hint carries the same prose the legacy\n * `detectShapeDriftHint` returned, plus structured fields (`tool`,\n * `observed_variant`, `expected_variant`, `instance_path`) so renderers\n * (CLI, Addie, JUnit, SARIF) can build per-case fix plans without re-\n * parsing the message.\n *\n * The string-only `detectShapeDriftHint` in `validations.ts` is a thin\n * shim over this detector — kept so existing unit tests and external\n * callers keep working, but the canonical path is structured.\n *\n * Fires unconditionally (regardless of step pass/fail) — same gate as\n * `ValidationResult.warning` carried previously. The caller (`runner.ts`)\n * merges the result into `StoryboardStepResult.hints[]`.\n */\nimport type { ShapeDriftHint } from './types';\n\n/**\n * Minimum @adcp/client version in which each server-side helper first shipped.\n * Used to suffix shape-drift hints when the agent reports an older SDK version.\n * Keys match the helper name referenced in the hint `message`.\n */\nconst HELPER_MIN_VERSION: Record<string, string> = {\n buildCreativeResponse: '5.14.0',\n listCreativesResponse: '5.10.0',\n listCreativeFormatsResponse: '5.10.0',\n listAccountsResponse: '5.10.0',\n productsResponse: '5.10.0',\n getMediaBuysResponse: '5.10.0',\n getSignalsResponse: '5.10.0',\n listPropertyListsResponse: '5.10.0',\n listCollectionListsResponse: '5.10.0',\n listContentStandardsResponse: '5.10.0',\n getPlanAuditLogsResponse: '5.10.0',\n syncCreativesResponse: '5.10.0',\n previewCreativeResponse: '5.10.0',\n};\n\n/**\n * Compare two semver strings using numeric segment ordering.\n * Returns true when `a` is strictly less than `b`.\n * Handles `@adcp/client@X.Y.Z` format by stripping the package prefix.\n */\nfunction semverLessThan(a: string, b: string): boolean {\n // Strip package prefix (e.g. \"@adcp/client@\") and pre-release suffix (e.g. \"-beta.1\")\n const normalize = (v: string) => v.replace(/^.*@/, '').replace(/-.*$/, '');\n const segs = (v: string) =>\n normalize(v)\n .split('.')\n .map(s => parseInt(s, 10) || 0);\n const [aMaj = 0, aMin = 0, aPatch = 0] = segs(a);\n const [bMaj = 0, bMin = 0, bPatch = 0] = segs(b);\n if (aMaj !== bMaj) return aMaj < bMaj;\n if (aMin !== bMin) return aMin < bMin;\n return aPatch < bPatch;\n}\n\n/**\n * List-shaped tools where handlers commonly return the bare inner array\n * (`[{...}]`) at the top level instead of wrapping it in the required\n * object envelope. Each entry names the wrapper key and the response\n * helper that builds the correct shape.\n *\n * Helper names aren't uniformly prefixed — `get_products` uses\n * `productsResponse` (no `get` prefix) while `get_media_buys` uses\n * `getMediaBuysResponse`. Names match the exports in\n * `src/lib/server/responses.ts` verbatim so a developer can grep\n * straight from the hint.\n */\nexport const LIST_WRAPPER_TOOLS: Record<string, { wrapperKey: string; helper: string }> = {\n list_creatives: { wrapperKey: 'creatives', helper: 'listCreativesResponse' },\n list_creative_formats: { wrapperKey: 'formats', helper: 'listCreativeFormatsResponse' },\n list_accounts: { wrapperKey: 'accounts', helper: 'listAccountsResponse' },\n get_products: { wrapperKey: 'products', helper: 'productsResponse' },\n get_media_buys: { wrapperKey: 'media_buys', helper: 'getMediaBuysResponse' },\n get_signals: { wrapperKey: 'signals', helper: 'getSignalsResponse' },\n list_property_lists: { wrapperKey: 'lists', helper: 'listPropertyListsResponse' },\n list_collection_lists: { wrapperKey: 'lists', helper: 'listCollectionListsResponse' },\n list_content_standards: { wrapperKey: 'standards', helper: 'listContentStandardsResponse' },\n get_plan_audit_logs: { wrapperKey: 'plans', helper: 'getPlanAuditLogsResponse' },\n};\n\n/**\n * Detect shape-drift and return the structured hints that apply (zero or\n * one — the detector emits at most one hint per response, but returns an\n * array so callers can spread it into `step.hints[]` without a guard).\n *\n * @param taskName — tool name (snake_case) the storyboard dispatched under\n * @param payload — raw response payload, after the runner's `_message`\n * pre-strip. `unknown` rather than `Record<string, unknown>` so bare-\n * array payloads are recognizable at the top level; object branches\n * guard internally.\n * @param libraryVersion — optional SDK version string the agent self-reported\n * in `get_adcp_capabilities` (e.g. `\"@adcp/client@4.16.2\"`). When present\n * and below the helper's minimum version, the hint message is suffixed with\n * an upgrade note so developers know to update their SDK dep.\n */\nexport function detectShapeDriftHints(taskName: string, payload: unknown, libraryVersion?: string): ShapeDriftHint[] {\n const hint = detect(taskName, payload);\n if (!hint) return [];\n if (libraryVersion) hint.message = appendVersionSuffix(hint.message, libraryVersion);\n return [hint];\n}\n\n/**\n * If the hint message references a helper that requires a minimum SDK\n * version and the agent's reported version is below it, append an upgrade\n * note to the message. Returns the message unchanged if no version data or\n * no match.\n */\nfunction appendVersionSuffix(message: string, libraryVersion: string): string {\n // Skip non-numeric version strings (e.g. \"local-dev\") to avoid spurious suffixes\n const stripped = libraryVersion.replace(/^.*@/, '').replace(/-.*$/, '');\n if (!/^\\d+\\.\\d+/.test(stripped)) return message;\n for (const [helper, minVersion] of Object.entries(HELPER_MIN_VERSION)) {\n if (message.includes(helper) && semverLessThan(libraryVersion, minVersion)) {\n return (\n message +\n ` (Note: your agent reports ${libraryVersion} — ${helper}() ships in @adcp/client ≥${minVersion}. Upgrade your SDK dep.)`\n );\n }\n }\n return message;\n}\n\nfunction detect(taskName: string, payload: unknown): ShapeDriftHint | undefined {\n if (Array.isArray(payload)) {\n const listMeta = LIST_WRAPPER_TOOLS[taskName];\n if (!listMeta) return undefined;\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'bare_array',\n expected_variant: `{ ${listMeta.wrapperKey}: [...] }`,\n instance_path: '',\n message:\n `${taskName} returned a bare array at the top level. ` +\n `Required: { ${listMeta.wrapperKey}: [...] }. ` +\n `Use ${listMeta.helper}() from @adcp/sdk/server.`,\n };\n }\n\n if (typeof payload !== 'object' || payload === null) return undefined;\n const p = payload as Record<string, unknown>;\n\n if (taskName === 'build_creative') {\n const hasManifest = 'creative_manifest' in p || 'creative_manifests' in p;\n const platformNativeKeys = ['tag_url', 'creative_id', 'media_type', 'tag_type'];\n const platformNativePresent = platformNativeKeys.filter(k => k in p);\n if (!hasManifest && platformNativePresent.length > 0) {\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'platform_native_fields',\n expected_variant: '{ creative_manifest: { format_id, assets } }',\n instance_path: '',\n message:\n `build_creative returned platform-native fields at the top level (${platformNativePresent.join(', ')}). ` +\n `Required: { creative_manifest: { format_id, assets } }. ` +\n `Use buildCreativeResponse() from @adcp/sdk/server.`,\n };\n }\n }\n\n if (taskName === 'sync_creatives') {\n const hasValidWrapper = 'creatives' in p || 'errors' in p || 'task_id' in p;\n const perItemKeys = ['creative_id', 'platform_id', 'action'];\n const perItemPresent = perItemKeys.filter(k => k in p);\n if (!hasValidWrapper && perItemPresent.length > 0) {\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'per_item_shape',\n expected_variant: '{ creatives: [{ creative_id, action, ... }] }',\n instance_path: '',\n message:\n `sync_creatives returned a single creative's inner shape at the top level (${perItemPresent.join(', ')}). ` +\n `Required: { creatives: [{ creative_id, action, ... }] } (or { errors: [...] } / { status: 'submitted', task_id }). ` +\n `Use syncCreativesResponse() from @adcp/sdk/server.`,\n };\n }\n\n const results = p.results;\n if (!hasValidWrapper && Array.isArray(results) && results.length > 0) {\n const firstRow = results[0];\n const looksLikeCreativeRow =\n firstRow != null && typeof firstRow === 'object' && ('creative_id' in firstRow || 'action' in firstRow);\n if (looksLikeCreativeRow) {\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'wrong_wrapper_key',\n expected_variant: '{ creatives: [{ creative_id, action, ... }] }',\n instance_path: '/results',\n message:\n `sync_creatives returned { results: [...] } instead of { creatives: [...] } — wrong wrapper key. ` +\n `Required: { creatives: [{ creative_id, action, ... }] }. ` +\n `Use syncCreativesResponse() from @adcp/sdk/server.`,\n };\n }\n }\n }\n\n if (taskName === 'preview_creative') {\n const hasValidWrapper = 'response_type' in p || 'previews' in p || 'results' in p;\n const rawRenderKeys = ['preview_url', 'preview_html', 'interactive_url'];\n const rawRenderPresent = rawRenderKeys.filter(k => k in p);\n const driftSignal = rawRenderPresent.filter(k => k !== 'interactive_url');\n if (!hasValidWrapper && driftSignal.length > 0) {\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'raw_render_fields',\n expected_variant: \"{ response_type: 'single', previews: [{ renders: [...] }], expires_at }\",\n instance_path: '',\n message:\n `preview_creative returned raw render fields at the top level (${driftSignal.join(', ')}). ` +\n `Required: { response_type: 'single', previews: [{ renders: [{ preview_url | preview_html }] }], expires_at }. ` +\n `Use previewCreativeResponse() from @adcp/sdk/server.`,\n };\n }\n }\n\n return undefined;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/lib/testing/storyboard/shape-drift-hints.ts"],"sourcesContent":["/**\n * Structured shape-drift hint detection (issue #935).\n *\n * The runner emits one `ShapeDriftHint` per response when it recognizes a\n * common payload-shape mistake — bare arrays from list tools, platform-\n * native fields from `build_creative`, missing wrappers on `sync_creatives`\n * / `preview_creative`. Each hint carries the same prose the legacy\n * `detectShapeDriftHint` returned, plus structured fields (`tool`,\n * `observed_variant`, `expected_variant`, `instance_path`) so renderers\n * (CLI, Addie, JUnit, SARIF) can build per-case fix plans without re-\n * parsing the message.\n *\n * The string-only `detectShapeDriftHint` in `validations.ts` is a thin\n * shim over this detector — kept so existing unit tests and external\n * callers keep working, but the canonical path is structured.\n *\n * Fires unconditionally (regardless of step pass/fail) — same gate as\n * `ValidationResult.warning` carried previously. The caller (`runner.ts`)\n * merges the result into `StoryboardStepResult.hints[]`.\n */\nimport type { ShapeDriftHint } from './types';\n\n/**\n * Minimum @adcp/client version in which each server-side helper first shipped.\n * Used to suffix shape-drift hints when the agent reports an older SDK version.\n * Keys match the helper name referenced in the hint `message`.\n */\nconst HELPER_MIN_VERSION: Record<string, string> = {\n legacyBuildCreativeResponse: '13.0.0',\n legacyListCreativesResponse: '13.0.0',\n legacyListCreativeFormatsResponse: '13.0.0',\n legacyListAccountsResponse: '13.0.0',\n legacyProductsResponse: '13.0.0',\n legacyGetMediaBuysResponse: '13.0.0',\n legacyGetSignalsResponse: '13.0.0',\n legacyListPropertyListsResponse: '13.0.0',\n legacyListCollectionListsResponse: '13.0.0',\n legacyListContentStandardsResponse: '13.0.0',\n legacyGetPlanAuditLogsResponse: '13.0.0',\n legacySyncCreativesResponse: '13.0.0',\n legacyPreviewCreativeResponse: '13.0.0',\n};\n\n/**\n * Compare two semver strings using numeric segment ordering.\n * Returns true when `a` is strictly less than `b`.\n * Handles `@adcp/client@X.Y.Z` format by stripping the package prefix.\n */\nfunction semverLessThan(a: string, b: string): boolean {\n // Strip package prefix (e.g. \"@adcp/client@\") and pre-release suffix (e.g. \"-beta.1\")\n const normalize = (v: string) => v.replace(/^.*@/, '').replace(/-.*$/, '');\n const segs = (v: string) =>\n normalize(v)\n .split('.')\n .map(s => parseInt(s, 10) || 0);\n const [aMaj = 0, aMin = 0, aPatch = 0] = segs(a);\n const [bMaj = 0, bMin = 0, bPatch = 0] = segs(b);\n if (aMaj !== bMaj) return aMaj < bMaj;\n if (aMin !== bMin) return aMin < bMin;\n return aPatch < bPatch;\n}\n\n/**\n * List-shaped tools where handlers commonly return the bare inner array\n * (`[{...}]`) at the top level instead of wrapping it in the required\n * object envelope. Each entry names the wrapper key and the response\n * helper that builds the correct shape.\n *\n * Helper names aren't uniformly prefixed — `get_products` uses\n * `legacyProductsResponse` (no `get` prefix) while `get_media_buys` uses\n * `legacyGetMediaBuysResponse`. Names match the explicit compatibility\n * aliases on `@adcp/sdk/server`.\n */\nexport const LIST_WRAPPER_TOOLS: Record<string, { wrapperKey: string; helper: string }> = {\n list_creatives: { wrapperKey: 'creatives', helper: 'legacyListCreativesResponse' },\n list_creative_formats: { wrapperKey: 'formats', helper: 'legacyListCreativeFormatsResponse' },\n list_accounts: { wrapperKey: 'accounts', helper: 'legacyListAccountsResponse' },\n get_products: { wrapperKey: 'products', helper: 'legacyProductsResponse' },\n get_media_buys: { wrapperKey: 'media_buys', helper: 'legacyGetMediaBuysResponse' },\n get_signals: { wrapperKey: 'signals', helper: 'legacyGetSignalsResponse' },\n list_property_lists: { wrapperKey: 'lists', helper: 'legacyListPropertyListsResponse' },\n list_collection_lists: { wrapperKey: 'lists', helper: 'legacyListCollectionListsResponse' },\n list_content_standards: { wrapperKey: 'standards', helper: 'legacyListContentStandardsResponse' },\n get_plan_audit_logs: { wrapperKey: 'plans', helper: 'legacyGetPlanAuditLogsResponse' },\n};\n\n/**\n * Detect shape-drift and return the structured hints that apply (zero or\n * one — the detector emits at most one hint per response, but returns an\n * array so callers can spread it into `step.hints[]` without a guard).\n *\n * @param taskName — tool name (snake_case) the storyboard dispatched under\n * @param payload — raw response payload, after the runner's `_message`\n * pre-strip. `unknown` rather than `Record<string, unknown>` so bare-\n * array payloads are recognizable at the top level; object branches\n * guard internally.\n * @param libraryVersion — optional SDK version string the agent self-reported\n * in `get_adcp_capabilities` (e.g. `\"@adcp/client@4.16.2\"`). When present\n * and below the helper's minimum version, the hint message is suffixed with\n * an upgrade note so developers know to update their SDK dep.\n */\nexport function detectShapeDriftHints(taskName: string, payload: unknown, libraryVersion?: string): ShapeDriftHint[] {\n const hint = detect(taskName, payload);\n if (!hint) return [];\n if (libraryVersion) hint.message = appendVersionSuffix(hint.message, libraryVersion);\n return [hint];\n}\n\n/**\n * If the hint message references a helper that requires a minimum SDK\n * version and the agent's reported version is below it, append an upgrade\n * note to the message. Returns the message unchanged if no version data or\n * no match.\n */\nfunction appendVersionSuffix(message: string, libraryVersion: string): string {\n // Skip non-numeric version strings (e.g. \"local-dev\") to avoid spurious suffixes\n const stripped = libraryVersion.replace(/^.*@/, '').replace(/-.*$/, '');\n if (!/^\\d+\\.\\d+/.test(stripped)) return message;\n for (const [helper, minVersion] of Object.entries(HELPER_MIN_VERSION)) {\n if (message.includes(helper) && semverLessThan(libraryVersion, minVersion)) {\n return (\n message +\n ` (Note: your agent reports ${libraryVersion} — ${helper}() ships in @adcp/client ≥${minVersion}. Upgrade your SDK dep.)`\n );\n }\n }\n return message;\n}\n\nfunction detect(taskName: string, payload: unknown): ShapeDriftHint | undefined {\n if (Array.isArray(payload)) {\n const listMeta = LIST_WRAPPER_TOOLS[taskName];\n if (!listMeta) return undefined;\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'bare_array',\n expected_variant: `{ ${listMeta.wrapperKey}: [...] }`,\n instance_path: '',\n message:\n `${taskName} returned a bare array at the top level. ` +\n `Required: { ${listMeta.wrapperKey}: [...] }. ` +\n `Use ${listMeta.helper}() from @adcp/sdk/server.`,\n };\n }\n\n if (typeof payload !== 'object' || payload === null) return undefined;\n const p = payload as Record<string, unknown>;\n\n if (taskName === 'build_creative') {\n const hasManifest = 'creative_manifest' in p || 'creative_manifests' in p;\n const platformNativeKeys = ['tag_url', 'creative_id', 'media_type', 'tag_type'];\n const platformNativePresent = platformNativeKeys.filter(k => k in p);\n if (!hasManifest && platformNativePresent.length > 0) {\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'platform_native_fields',\n expected_variant: '{ creative_manifest: { format_id, assets } }',\n instance_path: '',\n message:\n `build_creative returned platform-native fields at the top level (${platformNativePresent.join(', ')}). ` +\n `Required: { creative_manifest: { format_id, assets } }. ` +\n `Use legacyBuildCreativeResponse() from @adcp/sdk/server.`,\n };\n }\n }\n\n if (taskName === 'sync_creatives') {\n const hasValidWrapper = 'creatives' in p || 'errors' in p || 'task_id' in p;\n const perItemKeys = ['creative_id', 'platform_id', 'action'];\n const perItemPresent = perItemKeys.filter(k => k in p);\n if (!hasValidWrapper && perItemPresent.length > 0) {\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'per_item_shape',\n expected_variant: '{ creatives: [{ creative_id, action, ... }] }',\n instance_path: '',\n message:\n `sync_creatives returned a single creative's inner shape at the top level (${perItemPresent.join(', ')}). ` +\n `Required: { creatives: [{ creative_id, action, ... }] } (or { errors: [...] } / { status: 'submitted', task_id }). ` +\n `Use legacySyncCreativesResponse() from @adcp/sdk/server.`,\n };\n }\n\n const results = p.results;\n if (!hasValidWrapper && Array.isArray(results) && results.length > 0) {\n const firstRow = results[0];\n const looksLikeCreativeRow =\n firstRow != null && typeof firstRow === 'object' && ('creative_id' in firstRow || 'action' in firstRow);\n if (looksLikeCreativeRow) {\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'wrong_wrapper_key',\n expected_variant: '{ creatives: [{ creative_id, action, ... }] }',\n instance_path: '/results',\n message:\n `sync_creatives returned { results: [...] } instead of { creatives: [...] } — wrong wrapper key. ` +\n `Required: { creatives: [{ creative_id, action, ... }] }. ` +\n `Use legacySyncCreativesResponse() from @adcp/sdk/server.`,\n };\n }\n }\n }\n\n if (taskName === 'preview_creative') {\n const hasValidWrapper = 'response_type' in p || 'previews' in p || 'results' in p;\n const rawRenderKeys = ['preview_url', 'preview_html', 'interactive_url'];\n const rawRenderPresent = rawRenderKeys.filter(k => k in p);\n const driftSignal = rawRenderPresent.filter(k => k !== 'interactive_url');\n if (!hasValidWrapper && driftSignal.length > 0) {\n return {\n kind: 'shape_drift',\n tool: taskName,\n observed_variant: 'raw_render_fields',\n expected_variant: \"{ response_type: 'single', previews: [{ renders: [...] }], expires_at }\",\n instance_path: '',\n message:\n `preview_creative returned raw render fields at the top level (${driftSignal.join(', ')}). ` +\n `Required: { response_type: 'single', previews: [{ renders: [{ preview_url | preview_html }] }], expires_at }. ` +\n `Use legacyPreviewCreativeResponse() from @adcp/sdk/server.`,\n };\n }\n }\n\n return undefined;\n}\n"],"mappings":"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","names":[]}