@adcp/sdk 5.25.1 → 6.0.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 (288) hide show
  1. package/README.md +45 -7
  2. package/dist/lib/compliance-fixtures/index.d.ts +1 -1
  3. package/dist/lib/compliance-fixtures/index.js +1 -1
  4. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  5. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  6. package/dist/lib/core/SingleAgentClient.js +15 -0
  7. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  8. package/dist/lib/core/TaskExecutor.d.ts +7 -0
  9. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  10. package/dist/lib/core/TaskExecutor.js +9 -2
  11. package/dist/lib/core/TaskExecutor.js.map +1 -1
  12. package/dist/lib/index.d.ts +1 -1
  13. package/dist/lib/index.d.ts.map +1 -1
  14. package/dist/lib/index.js +7 -8
  15. package/dist/lib/index.js.map +1 -1
  16. package/dist/lib/schemas/index.d.ts +1 -1
  17. package/dist/lib/schemas/index.js +1 -1
  18. package/dist/lib/server/create-adcp-server.d.ts +129 -11
  19. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  20. package/dist/lib/server/create-adcp-server.js +112 -2
  21. package/dist/lib/server/create-adcp-server.js.map +1 -1
  22. package/dist/lib/server/ctx-metadata/backends/memory.d.ts +27 -0
  23. package/dist/lib/server/ctx-metadata/backends/memory.d.ts.map +1 -0
  24. package/dist/lib/server/ctx-metadata/backends/memory.js +72 -0
  25. package/dist/lib/server/ctx-metadata/backends/memory.js.map +1 -0
  26. package/dist/lib/server/ctx-metadata/backends/pg.d.ts +62 -0
  27. package/dist/lib/server/ctx-metadata/backends/pg.d.ts.map +1 -0
  28. package/dist/lib/server/ctx-metadata/backends/pg.js +145 -0
  29. package/dist/lib/server/ctx-metadata/backends/pg.js.map +1 -0
  30. package/dist/lib/server/ctx-metadata/index.d.ts +15 -0
  31. package/dist/lib/server/ctx-metadata/index.d.ts.map +1 -0
  32. package/dist/lib/server/ctx-metadata/index.js +28 -0
  33. package/dist/lib/server/ctx-metadata/index.js.map +1 -0
  34. package/dist/lib/server/ctx-metadata/store.d.ts +177 -0
  35. package/dist/lib/server/ctx-metadata/store.d.ts.map +1 -0
  36. package/dist/lib/server/ctx-metadata/store.js +327 -0
  37. package/dist/lib/server/ctx-metadata/store.js.map +1 -0
  38. package/dist/lib/server/ctx-metadata/wire-shape.d.ts +55 -0
  39. package/dist/lib/server/ctx-metadata/wire-shape.d.ts.map +1 -0
  40. package/dist/lib/server/ctx-metadata/wire-shape.js +121 -0
  41. package/dist/lib/server/ctx-metadata/wire-shape.js.map +1 -0
  42. package/dist/lib/server/decisioning/account.d.ts +309 -0
  43. package/dist/lib/server/decisioning/account.d.ts.map +1 -0
  44. package/dist/lib/server/decisioning/account.js +102 -0
  45. package/dist/lib/server/decisioning/account.js.map +1 -0
  46. package/dist/lib/server/decisioning/admin-router.d.ts +75 -0
  47. package/dist/lib/server/decisioning/admin-router.d.ts.map +1 -0
  48. package/dist/lib/server/decisioning/admin-router.js +120 -0
  49. package/dist/lib/server/decisioning/admin-router.js.map +1 -0
  50. package/dist/lib/server/decisioning/assembly-helpers.d.ts +204 -0
  51. package/dist/lib/server/decisioning/assembly-helpers.d.ts.map +1 -0
  52. package/dist/lib/server/decisioning/assembly-helpers.js +173 -0
  53. package/dist/lib/server/decisioning/assembly-helpers.js.map +1 -0
  54. package/dist/lib/server/decisioning/async-outcome.d.ts +154 -0
  55. package/dist/lib/server/decisioning/async-outcome.d.ts.map +1 -0
  56. package/dist/lib/server/decisioning/async-outcome.js +239 -0
  57. package/dist/lib/server/decisioning/async-outcome.js.map +1 -0
  58. package/dist/lib/server/decisioning/capabilities.d.ts +251 -0
  59. package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -0
  60. package/dist/lib/server/decisioning/capabilities.js +16 -0
  61. package/dist/lib/server/decisioning/capabilities.js.map +1 -0
  62. package/dist/lib/server/decisioning/context.d.ts +212 -0
  63. package/dist/lib/server/decisioning/context.d.ts.map +1 -0
  64. package/dist/lib/server/decisioning/context.js +26 -0
  65. package/dist/lib/server/decisioning/context.js.map +1 -0
  66. package/dist/lib/server/decisioning/errors-typed.d.ts +104 -0
  67. package/dist/lib/server/decisioning/errors-typed.d.ts.map +1 -0
  68. package/dist/lib/server/decisioning/errors-typed.js +304 -0
  69. package/dist/lib/server/decisioning/errors-typed.js.map +1 -0
  70. package/dist/lib/server/decisioning/helpers.d.ts +131 -0
  71. package/dist/lib/server/decisioning/helpers.d.ts.map +1 -0
  72. package/dist/lib/server/decisioning/helpers.js +134 -0
  73. package/dist/lib/server/decisioning/helpers.js.map +1 -0
  74. package/dist/lib/server/decisioning/index.d.ts +46 -0
  75. package/dist/lib/server/decisioning/index.d.ts.map +1 -0
  76. package/dist/lib/server/decisioning/index.js +120 -0
  77. package/dist/lib/server/decisioning/index.js.map +1 -0
  78. package/dist/lib/server/decisioning/list-helpers.d.ts +53 -0
  79. package/dist/lib/server/decisioning/list-helpers.d.ts.map +1 -0
  80. package/dist/lib/server/decisioning/list-helpers.js +96 -0
  81. package/dist/lib/server/decisioning/list-helpers.js.map +1 -0
  82. package/dist/lib/server/decisioning/manifest-helpers.d.ts +56 -0
  83. package/dist/lib/server/decisioning/manifest-helpers.d.ts.map +1 -0
  84. package/dist/lib/server/decisioning/manifest-helpers.js +78 -0
  85. package/dist/lib/server/decisioning/manifest-helpers.js.map +1 -0
  86. package/dist/lib/server/decisioning/pagination.d.ts +21 -0
  87. package/dist/lib/server/decisioning/pagination.d.ts.map +1 -0
  88. package/dist/lib/server/decisioning/pagination.js +12 -0
  89. package/dist/lib/server/decisioning/pagination.js.map +1 -0
  90. package/dist/lib/server/decisioning/platform.d.ts +188 -0
  91. package/dist/lib/server/decisioning/platform.d.ts.map +1 -0
  92. package/dist/lib/server/decisioning/platform.js +19 -0
  93. package/dist/lib/server/decisioning/platform.js.map +1 -0
  94. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +510 -0
  95. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -0
  96. package/dist/lib/server/decisioning/runtime/from-platform.js +2196 -0
  97. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -0
  98. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +114 -0
  99. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts.map +1 -0
  100. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +247 -0
  101. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js.map +1 -0
  102. package/dist/lib/server/decisioning/runtime/protocol-for-tool.d.ts +32 -0
  103. package/dist/lib/server/decisioning/runtime/protocol-for-tool.d.ts.map +1 -0
  104. package/dist/lib/server/decisioning/runtime/protocol-for-tool.js +127 -0
  105. package/dist/lib/server/decisioning/runtime/protocol-for-tool.js.map +1 -0
  106. package/dist/lib/server/decisioning/runtime/task-registry.d.ts +105 -0
  107. package/dist/lib/server/decisioning/runtime/task-registry.d.ts.map +1 -0
  108. package/dist/lib/server/decisioning/runtime/task-registry.js +96 -0
  109. package/dist/lib/server/decisioning/runtime/task-registry.js.map +1 -0
  110. package/dist/lib/server/decisioning/runtime/to-context.d.ts +54 -0
  111. package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -0
  112. package/dist/lib/server/decisioning/runtime/to-context.js +166 -0
  113. package/dist/lib/server/decisioning/runtime/to-context.js.map +1 -0
  114. package/dist/lib/server/decisioning/runtime/validate-platform.d.ts +20 -0
  115. package/dist/lib/server/decisioning/runtime/validate-platform.d.ts.map +1 -0
  116. package/dist/lib/server/decisioning/runtime/validate-platform.js +93 -0
  117. package/dist/lib/server/decisioning/runtime/validate-platform.js.map +1 -0
  118. package/dist/lib/server/decisioning/specialisms/audiences.d.ts +72 -0
  119. package/dist/lib/server/decisioning/specialisms/audiences.d.ts.map +1 -0
  120. package/dist/lib/server/decisioning/specialisms/audiences.js +15 -0
  121. package/dist/lib/server/decisioning/specialisms/audiences.js.map +1 -0
  122. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts +92 -0
  123. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts.map +1 -0
  124. package/dist/lib/server/decisioning/specialisms/brand-rights.js +28 -0
  125. package/dist/lib/server/decisioning/specialisms/brand-rights.js.map +1 -0
  126. package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts +67 -0
  127. package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts.map +1 -0
  128. package/dist/lib/server/decisioning/specialisms/campaign-governance.js +31 -0
  129. package/dist/lib/server/decisioning/specialisms/campaign-governance.js.map +1 -0
  130. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts +78 -0
  131. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts.map +1 -0
  132. package/dist/lib/server/decisioning/specialisms/content-standards.js +35 -0
  133. package/dist/lib/server/decisioning/specialisms/content-standards.js.map +1 -0
  134. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +81 -0
  135. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -0
  136. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js +28 -0
  137. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -0
  138. package/dist/lib/server/decisioning/specialisms/creative.d.ts +144 -0
  139. package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -0
  140. package/dist/lib/server/decisioning/specialisms/creative.js +19 -0
  141. package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -0
  142. package/dist/lib/server/decisioning/specialisms/lists.d.ts +61 -0
  143. package/dist/lib/server/decisioning/specialisms/lists.d.ts.map +1 -0
  144. package/dist/lib/server/decisioning/specialisms/lists.js +30 -0
  145. package/dist/lib/server/decisioning/specialisms/lists.js.map +1 -0
  146. package/dist/lib/server/decisioning/specialisms/sales.d.ts +163 -0
  147. package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -0
  148. package/dist/lib/server/decisioning/specialisms/sales.js +64 -0
  149. package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -0
  150. package/dist/lib/server/decisioning/specialisms/signals.d.ts +64 -0
  151. package/dist/lib/server/decisioning/specialisms/signals.d.ts.map +1 -0
  152. package/dist/lib/server/decisioning/specialisms/signals.js +28 -0
  153. package/dist/lib/server/decisioning/specialisms/signals.js.map +1 -0
  154. package/dist/lib/server/decisioning/start-time.d.ts +76 -0
  155. package/dist/lib/server/decisioning/start-time.d.ts.map +1 -0
  156. package/dist/lib/server/decisioning/start-time.js +81 -0
  157. package/dist/lib/server/decisioning/start-time.js.map +1 -0
  158. package/dist/lib/server/decisioning/status-changes.d.ts +165 -0
  159. package/dist/lib/server/decisioning/status-changes.d.ts.map +1 -0
  160. package/dist/lib/server/decisioning/status-changes.js +131 -0
  161. package/dist/lib/server/decisioning/status-changes.js.map +1 -0
  162. package/dist/lib/server/decisioning/status-mappers.d.ts +46 -0
  163. package/dist/lib/server/decisioning/status-mappers.d.ts.map +1 -0
  164. package/dist/lib/server/decisioning/status-mappers.js +46 -0
  165. package/dist/lib/server/decisioning/status-mappers.js.map +1 -0
  166. package/dist/lib/server/decisioning/tenant-registry.d.ts +289 -0
  167. package/dist/lib/server/decisioning/tenant-registry.d.ts.map +1 -0
  168. package/dist/lib/server/decisioning/tenant-registry.js +503 -0
  169. package/dist/lib/server/decisioning/tenant-registry.js.map +1 -0
  170. package/dist/lib/server/express-adapter.d.ts +1 -1
  171. package/dist/lib/server/express-adapter.js +1 -1
  172. package/dist/lib/server/governance.d.ts +1 -1
  173. package/dist/lib/server/governance.js +1 -1
  174. package/dist/lib/server/idempotency/store.d.ts +1 -1
  175. package/dist/lib/server/idempotency/store.js +1 -1
  176. package/dist/lib/server/index.d.ts +9 -2
  177. package/dist/lib/server/index.d.ts.map +1 -1
  178. package/dist/lib/server/index.js +79 -4
  179. package/dist/lib/server/index.js.map +1 -1
  180. package/dist/lib/server/legacy/v5/index.d.ts +38 -0
  181. package/dist/lib/server/legacy/v5/index.d.ts.map +1 -0
  182. package/dist/lib/server/legacy/v5/index.js +60 -0
  183. package/dist/lib/server/legacy/v5/index.js.map +1 -0
  184. package/dist/lib/server/normalize-errors.d.ts +88 -0
  185. package/dist/lib/server/normalize-errors.d.ts.map +1 -0
  186. package/dist/lib/server/normalize-errors.js +146 -0
  187. package/dist/lib/server/normalize-errors.js.map +1 -0
  188. package/dist/lib/server/pick-safe-details.d.ts +90 -0
  189. package/dist/lib/server/pick-safe-details.d.ts.map +1 -0
  190. package/dist/lib/server/pick-safe-details.js +148 -0
  191. package/dist/lib/server/pick-safe-details.js.map +1 -0
  192. package/dist/lib/server/postgres-state-store.d.ts +1 -1
  193. package/dist/lib/server/postgres-state-store.js +1 -1
  194. package/dist/lib/server/responses.d.ts +38 -0
  195. package/dist/lib/server/responses.d.ts.map +1 -1
  196. package/dist/lib/server/responses.js +38 -0
  197. package/dist/lib/server/responses.js.map +1 -1
  198. package/dist/lib/server/state-store.d.ts +1 -1
  199. package/dist/lib/server/state-store.js +1 -1
  200. package/dist/lib/server/test-controller.d.ts +10 -3
  201. package/dist/lib/server/test-controller.d.ts.map +1 -1
  202. package/dist/lib/server/test-controller.js +10 -3
  203. package/dist/lib/server/test-controller.js.map +1 -1
  204. package/dist/lib/testing/comply-controller.d.ts +47 -1
  205. package/dist/lib/testing/comply-controller.d.ts.map +1 -1
  206. package/dist/lib/testing/comply-controller.js +11 -4
  207. package/dist/lib/testing/comply-controller.js.map +1 -1
  208. package/dist/lib/testing/index.d.ts +1 -1
  209. package/dist/lib/testing/index.d.ts.map +1 -1
  210. package/dist/lib/testing/index.js.map +1 -1
  211. package/dist/lib/testing/personas/index.d.ts +143 -0
  212. package/dist/lib/testing/personas/index.d.ts.map +1 -0
  213. package/dist/lib/testing/personas/index.js +190 -0
  214. package/dist/lib/testing/personas/index.js.map +1 -0
  215. package/dist/lib/testing/storyboard/index.d.ts +1 -1
  216. package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
  217. package/dist/lib/testing/storyboard/index.js +3 -2
  218. package/dist/lib/testing/storyboard/index.js.map +1 -1
  219. package/dist/lib/testing/storyboard/runner.d.ts +13 -0
  220. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  221. package/dist/lib/testing/storyboard/runner.js +179 -7
  222. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  223. package/dist/lib/types/asset-instances.d.ts +1 -0
  224. package/dist/lib/types/asset-instances.d.ts.map +1 -1
  225. package/dist/lib/types/core.generated.d.ts +203 -98
  226. package/dist/lib/types/core.generated.d.ts.map +1 -1
  227. package/dist/lib/types/core.generated.js +1 -1
  228. package/dist/lib/types/index.d.ts +1 -0
  229. package/dist/lib/types/index.d.ts.map +1 -1
  230. package/dist/lib/types/index.js.map +1 -1
  231. package/dist/lib/types/schemas.generated.d.ts +599 -159
  232. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  233. package/dist/lib/types/schemas.generated.js +175 -94
  234. package/dist/lib/types/schemas.generated.js.map +1 -1
  235. package/dist/lib/types/tools.generated.d.ts +315 -46
  236. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  237. package/dist/lib/utils/capabilities.d.ts +1 -1
  238. package/dist/lib/utils/capabilities.d.ts.map +1 -1
  239. package/dist/lib/utils/capabilities.js +6 -0
  240. package/dist/lib/utils/capabilities.js.map +1 -1
  241. package/dist/lib/validation/schema-validator.d.ts +13 -0
  242. package/dist/lib/validation/schema-validator.d.ts.map +1 -1
  243. package/dist/lib/validation/schema-validator.js +240 -3
  244. package/dist/lib/validation/schema-validator.js.map +1 -1
  245. package/dist/lib/version.d.ts +3 -3
  246. package/dist/lib/version.d.ts.map +1 -1
  247. package/dist/lib/version.js +3 -3
  248. package/dist/lib/version.js.map +1 -1
  249. package/docs/guides/BUILD-AN-AGENT.md +30 -5
  250. package/docs/llms.txt +28 -17
  251. package/examples/README.md +3 -1
  252. package/examples/decisioning-platform-broadcast-tv.ts +300 -0
  253. package/examples/decisioning-platform-identity-graph.ts +214 -0
  254. package/examples/decisioning-platform-mock-seller.ts +332 -0
  255. package/examples/decisioning-platform-multi-tenant.ts +128 -0
  256. package/examples/decisioning-platform-programmatic.ts +254 -0
  257. package/examples/signals-agent.ts +1 -1
  258. package/package.json +13 -2
  259. package/skills/build-brand-rights-agent/SKILL.md +10 -3
  260. package/skills/build-creative-agent/SKILL.md +94 -64
  261. package/skills/build-decisioning-creative-template/SKILL.md +554 -0
  262. package/skills/build-decisioning-platform/SKILL.md +304 -0
  263. package/skills/build-decisioning-platform/advanced/BRAND-RIGHTS.md +25 -0
  264. package/skills/build-decisioning-platform/advanced/COMPLIANCE.md +23 -0
  265. package/skills/build-decisioning-platform/advanced/GOVERNANCE.md +24 -0
  266. package/skills/build-decisioning-platform/advanced/HITL.md +34 -0
  267. package/skills/build-decisioning-platform/advanced/IDEMPOTENCY.md +52 -0
  268. package/skills/build-decisioning-platform/advanced/MULTI-TENANT.md +47 -0
  269. package/skills/build-decisioning-platform/advanced/OAUTH.md +22 -0
  270. package/skills/build-decisioning-platform/advanced/REFERENCE.md +991 -0
  271. package/skills/build-decisioning-platform/advanced/SANDBOX.md +24 -0
  272. package/skills/build-decisioning-platform/advanced/STATE-MACHINE.md +52 -0
  273. package/skills/build-decisioning-signal-marketplace/SKILL.md +269 -0
  274. package/skills/build-generative-seller-agent/SKILL.md +89 -53
  275. package/skills/build-governance-agent/SKILL.md +76 -45
  276. package/skills/build-retail-media-agent/SKILL.md +87 -62
  277. package/skills/build-seller-agent/SKILL.md +384 -255
  278. package/skills/build-seller-agent/deployment.md +5 -3
  279. package/skills/build-seller-agent/specialisms/audience-sync.md +0 -2
  280. package/skills/build-seller-agent/specialisms/sales-broadcast-tv.md +0 -2
  281. package/skills/build-seller-agent/specialisms/sales-guaranteed.md +0 -2
  282. package/skills/build-seller-agent/specialisms/sales-non-guaranteed.md +0 -2
  283. package/skills/build-seller-agent/specialisms/sales-proposal-mode.md +0 -2
  284. package/skills/build-seller-agent/specialisms/sales-social.md +0 -2
  285. package/skills/build-seller-agent/specialisms/signed-requests.md +0 -2
  286. package/skills/build-si-agent/SKILL.md +40 -32
  287. package/skills/build-signals-agent/SKILL.md +139 -92
  288. package/skills/call-adcp-agent.previous/SKILL.md +5 -0
@@ -0,0 +1,554 @@
1
+ ---
2
+ name: build-decisioning-creative-template
3
+ description: Build an AdCP v6.0 creative-template decisioning platform — a stateless creative transform service (TTS, watermarking, format conversion, template fill). Use when the user wants the v6.0 DecisioningPlatform shape; for the lower-level handler-bag API, use `build-creative-agent` instead.
4
+ ---
5
+
6
+ # Build a Creative-Template Decisioning Platform (v6.0)
7
+
8
+ You're building a **stateless creative transform** service that fits the AdCP `creative-template` specialism: take an input creative manifest + format spec, produce an output creative manifest. No library, no review queue, no persisting state. Examples: TTS audio synthesis, image watermarking, video format conversion, template-based ad generation.
9
+
10
+ ## When this skill applies
11
+
12
+ - User wants a creative-template service on the **v6.0 DecisioningPlatform** surface
13
+ - Specialism: `creative-template` (stateless transform; not `creative-ad-server` which is stateful, not `creative-generative` which is brief-driven — though `creative-template` and `creative-generative` share the same `CreativeBuilderPlatform` interface; pick the specialism ID that matches your behavior)
14
+ - SDK package: `@adcp/sdk` 6.0+
15
+
16
+ **Wrong skill if:**
17
+
18
+ - User wants the lower-level handler-bag API → `skills/build-creative-agent/`
19
+ - User wants stateful creative library/ad-server → `skills/build-creative-agent/` § creative-ad-server
20
+ - User wants brief-to-creative generation → same skill as this one (Builder covers both); declare `'creative-generative'` instead of `'creative-template'`
21
+ - User wants to sell media inventory → `skills/build-seller-agent/`
22
+
23
+ ## The whole shape (read this first)
24
+
25
+ A v6.0 creative-template platform is a **single class** implementing `DecisioningPlatform` with a `creative` field of type `CreativeBuilderPlatform`. The framework dispatches each tool call to the right method. (`CreativeTemplatePlatform` and `CreativeGenerativePlatform` are deprecated aliases of `CreativeBuilderPlatform` for source compat.)
26
+
27
+ ### Key fact: `CreativeManifest.assets` is a **keyed map**, not an array
28
+
29
+ Every example below depends on this — it's the most common day-1 trip-up:
30
+
31
+ ```ts
32
+ // ✅ CORRECT — assets is { [asset_id]: ImageAsset | AudioAsset | VideoAsset | ... }
33
+ const url = req.creative_manifest?.assets?.['source_image']?.url;
34
+
35
+ // ❌ WRONG — there is no manifest_id; assets is not an array
36
+ const url = req.creative_manifest?.assets?.[0]?.url;
37
+ ```
38
+
39
+ Asset values are **discriminated by `asset_type`** (`'image' | 'audio' | 'video' | 'vast' | 'text' | 'url' | 'html' | ...`). TypeScript will narrow them for you when you check the discriminator — no casting needed.
40
+
41
+ ### Minimal worked example — image watermark service
42
+
43
+ Takes an image asset by id, applies a brand watermark, returns a manifest with the watermarked asset:
44
+
45
+ ```ts
46
+ import {
47
+ AdcpError,
48
+ createAdcpServerFromPlatform,
49
+ getAsset,
50
+ requireAsset,
51
+ type DecisioningPlatform,
52
+ type AccountStore,
53
+ type CreativeBuilderPlatform,
54
+ } from '@adcp/sdk/server';
55
+ import type {
56
+ BuildCreativeRequest,
57
+ CreativeManifest,
58
+ PreviewCreativeRequest,
59
+ PreviewCreativeResponse,
60
+ CreativeAsset,
61
+ AccountReference,
62
+ ImageAsset,
63
+ } from '@adcp/sdk/types';
64
+ import { serve } from '@adcp/sdk/server';
65
+
66
+ interface WatermarkConfig {
67
+ watermarkUrl: string;
68
+ }
69
+
70
+ interface WatermarkMeta {
71
+ brand_id: string;
72
+ }
73
+
74
+ class WatermarkPlatform implements DecisioningPlatform<WatermarkConfig, WatermarkMeta> {
75
+ capabilities = {
76
+ specialisms: ['creative-template'] as const,
77
+ creative_agents: [],
78
+ channels: ['display'] as const,
79
+ pricingModels: ['cpm'] as const,
80
+ config: {
81
+ watermarkUrl: 'https://cdn.example.com/brand-watermark.png',
82
+ } satisfies WatermarkConfig,
83
+ };
84
+
85
+ // statusMappers + AccountStore.upsert/list are now optional. Stateless
86
+ // platforms (creative-template, signal-marketplace proxies) typically
87
+ // omit them; framework returns UNSUPPORTED_FEATURE to buyers calling
88
+ // sync_accounts / list_accounts on platforms that don't implement them.
89
+
90
+ accounts: AccountStore<WatermarkMeta> = {
91
+ resolve: async (ref: AccountReference) => {
92
+ const id = 'account_id' in ref ? ref.account_id : 'wm_acc_default';
93
+ return {
94
+ id,
95
+ name: 'Watermark default', // required by wire Account
96
+ status: 'active', // required by wire Account
97
+ operator: 'watermark.example.com',
98
+ metadata: { brand_id: 'brand_default' },
99
+ authInfo: { kind: 'api_key' },
100
+ };
101
+ },
102
+ // upsert / list omitted — stateless platform doesn't manage accounts.
103
+ };
104
+
105
+ creative: CreativeBuilderPlatform<WatermarkMeta> = {
106
+ /** Sync transform — fast operation, return result immediately. */
107
+ buildCreative: async (req: BuildCreativeRequest): Promise<CreativeManifest> => {
108
+ // requireAsset throws AdcpError with field path if missing/wrong type.
109
+ // After the call, TS narrows `source` to `ImageAsset` — no cast needed.
110
+ const source = requireAsset(req.creative_manifest, 'source_image', 'image');
111
+ const watermarkedUrl = await applyWatermark(source.url, this.capabilities.config.watermarkUrl);
112
+
113
+ const formatId = req.target_format_id;
114
+ if (!formatId) {
115
+ throw new AdcpError('INVALID_REQUEST', {
116
+ recovery: 'correctable',
117
+ message: 'target_format_id is required',
118
+ field: 'target_format_id',
119
+ });
120
+ }
121
+
122
+ const watermarked: ImageAsset = {
123
+ asset_type: 'image',
124
+ url: watermarkedUrl,
125
+ width: source.width,
126
+ height: source.height,
127
+ };
128
+ return {
129
+ format_id: formatId,
130
+ assets: { watermarked_image: watermarked },
131
+ };
132
+ },
133
+
134
+ /** Always sync — preview is just a sandbox URL. */
135
+ previewCreative: async (req: PreviewCreativeRequest): Promise<PreviewCreativeResponse> => {
136
+ // Soft-form helper — preview is best-effort even if source is missing.
137
+ const source = getAsset(req.creative_manifest, 'source_image', 'image');
138
+ const sourceUrl = source?.url ?? '';
139
+ // PreviewCreativeResponse is a discriminated union by `response_type`.
140
+ // Use `'single'` for one preview-per-request (the common case for
141
+ // stateless template platforms).
142
+ return {
143
+ response_type: 'single',
144
+ previews: [
145
+ {
146
+ preview_id: `pv_${Date.now()}`,
147
+ input: { name: 'default' },
148
+ renders: [
149
+ {
150
+ render_id: 'r1',
151
+ output_format: 'url',
152
+ role: 'primary',
153
+ preview_url: `https://watermark.example.com/preview?src=${encodeURIComponent(sourceUrl)}`,
154
+ },
155
+ ],
156
+ },
157
+ ],
158
+ expires_at: new Date(Date.now() + 3600_000).toISOString(),
159
+ };
160
+ },
161
+
162
+ /**
163
+ * Stateless template platforms typically auto-approve. Each row is the
164
+ * wire `SyncCreativesSuccess.creatives[]` shape: `action` is required
165
+ * (CRUD outcome — what your platform did), `status` is optional (review
166
+ * state). Stateless transforms use `action: 'unchanged'` since they
167
+ * don't persist; review state is `'approved'` since auto-approving.
168
+ */
169
+ syncCreatives: async (creatives: CreativeAsset[]) => {
170
+ return creatives.map(c => ({
171
+ creative_id: c.creative_id ?? `cr_${Math.random()}`,
172
+ action: 'unchanged' as const,
173
+ status: 'approved' as const,
174
+ }));
175
+ },
176
+ };
177
+ }
178
+
179
+ async function applyWatermark(src: string, mark: string): Promise<string> {
180
+ // Real impl calls your imaging service. Stub for the example.
181
+ return `${src}?watermark=${encodeURIComponent(mark)}`;
182
+ }
183
+
184
+ // Boot — bind HTTP, dispatch tool calls into the platform.
185
+ const platform = new WatermarkPlatform();
186
+ const server = createAdcpServerFromPlatform(platform, {
187
+ name: 'watermark',
188
+ version: '1.0.0',
189
+ validation: { requests: 'strict', responses: 'strict' },
190
+ });
191
+ serve(() => server, { publicUrl: 'https://watermark.example.com' });
192
+ ```
193
+
194
+ That's the entire shape. **No `as never` casts in adopter code** — the wire types are typed. Discriminators do narrowing for you. The rest of this skill is the rules around it.
195
+
196
+ ## Two wire shapes that trip people up
197
+
198
+ ### `target_format_id` is a `FormatID` object, not a bare string
199
+
200
+ ```ts
201
+ // ❌ WRONG
202
+ if (req.target_format_id === 'audio_30s') { ... }
203
+
204
+ // ✅ CORRECT — FormatID is { id: string; agent_url: string }
205
+ if (req.target_format_id?.id === 'audio_30s') { ... }
206
+ ```
207
+
208
+ The wire schema separates format identity (`id`) from the creative agent that hosts the format definition (`agent_url`). Always read `.id` for the literal format identifier.
209
+
210
+ ### `PreviewCreativeResponse` is a discriminated union — pick `'single'`
211
+
212
+ ```ts
213
+ // 3 variants by `response_type`: 'single' | 'batch' | 'variant'
214
+ // For stateless creative-template platforms, return `'single'`. Always.
215
+ return {
216
+ response_type: 'single',
217
+ previews: [{ preview_id, input: { name: 'default' }, renders: [...] }],
218
+ expires_at,
219
+ };
220
+ ```
221
+
222
+ `batch` and `variant` are for advanced post-flight workflows you don't need. The full union exists because the spec covers ad servers that produce per-impression preview variants — irrelevant for transform platforms. **If you're a creative-template platform, always return `'single'`.**
223
+
224
+ (See [#3268](https://github.com/adcontextprotocol/adcp/issues/3268) — proposing to hoist `preview_url` to the top level for the single-render case.)
225
+
226
+ ## The interface you implement
227
+
228
+ `CreativeBuilderPlatform` has 5 method slots. **For each method-pair you implement EXACTLY ONE — sync OR `*Task`** — `validatePlatform()` will throw at construction if you provide both.
229
+
230
+ | Slot | Sync variant | HITL `*Task` variant | Required? |
231
+ | ---------------- | ------------------------------- | ------------------------------------------- | ------------ |
232
+ | build creative | `buildCreative(req, ctx)` | `buildCreativeTask(taskId, req, ctx)` | One required |
233
+ | preview creative | `previewCreative(req, ctx)` | — (always sync) | Required |
234
+ | sync creatives | `syncCreatives(creatives, ctx)` | `syncCreativesTask(taskId, creatives, ctx)` | One required |
235
+
236
+ ### Sync vs `*Task` — pick by latency, not by preference
237
+
238
+ | Your operation typically takes... | Pick |
239
+ | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
240
+ | Under ~5 seconds (image manipulation, simple template fill) | **Sync** (`buildCreative`) |
241
+ | 10-60 seconds (TTS, audio mixing, video transcode) | **Sync** is fine — buyer awaits in the request |
242
+ | 1-30 minutes (heavy generation, multi-pass rendering) | **HITL** (`buildCreativeTask`) — buyer immediately gets a `submitted` envelope with `task_id` |
243
+ | Unknown / variable | Pick sync; switch to `*Task` only if observed latency > 30s |
244
+
245
+ **Critical**: when you pick HITL (`*Task`), the buyer cannot poll task status over the wire today (`tasks/get` integration is post-6.0-rc.1). The framework records terminal state in its task registry, but exposing it to the buyer is preview-incomplete. Default to sync unless your operation truly cannot be awaited.
246
+
247
+ ## Reading typed assets out of `creative_manifest`
248
+
249
+ `req.creative_manifest?.assets?.[asset_id]` returns a discriminated union (`ImageAsset | AudioAsset | VideoAsset | VASTAsset | TextAsset | URLAsset | HTMLAsset | JavaScriptAsset | WebhookAsset | CSSAsset | DAASTAsset | MarkdownAsset | BriefAsset | CatalogAsset`). Use the `asset_type` discriminator to narrow:
250
+
251
+ ```ts
252
+ const asset = req.creative_manifest?.assets?.['script'];
253
+ if (asset?.asset_type === 'text') {
254
+ // TS narrows to TextAsset — `.content`, `.language` available without cast
255
+ const scriptText = asset.content;
256
+ }
257
+ if (asset?.asset_type === 'audio') {
258
+ // TS narrows to AudioAsset — `.url`, `.duration_ms`, `.codec` etc.
259
+ const audioUrl = asset.url;
260
+ }
261
+ ```
262
+
263
+ **Field names matter** — `TextAsset.content` (not `.text`), `ImageAsset.url`, `AudioAsset.url`, `VideoAsset.url`, `HTMLAsset.content`, `URLAsset.url`. Use IntelliSense after the discriminator narrows; don't guess.
264
+
265
+ Likewise when _returning_ a manifest, type the asset value to its concrete shape and TypeScript will validate it against the manifest's union:
266
+
267
+ ```ts
268
+ const audio: AudioAsset = {
269
+ asset_type: 'audio',
270
+ url: 'https://cdn.example.com/render.mp3',
271
+ duration_ms: 30_000,
272
+ container_format: 'mp3',
273
+ codec: 'mp3',
274
+ };
275
+ return {
276
+ format_id: req.target_format_id!,
277
+ assets: { rendered_audio: audio },
278
+ };
279
+ ```
280
+
281
+ **Do not write `as any` or `as never` on platform code.** If you find yourself reaching for those, you almost certainly want to `import type` the right asset from `@adcp/sdk/types` and use the discriminator instead.
282
+
283
+ The asset types are generated from the spec; full list at `src/lib/types/tools.generated.ts`. Each carries `asset_type` as a literal-typed discriminator.
284
+
285
+ ### Helpers — `getAsset` and `requireAsset`
286
+
287
+ Most platform methods do the same null-check + discriminator-check + extract pattern over and over. The SDK ships two helpers that collapse it:
288
+
289
+ ```ts
290
+ import { getAsset, requireAsset } from '@adcp/sdk/server';
291
+
292
+ // Soft form — returns undefined if missing or wrong asset_type
293
+ const optionalVoice = getAsset(req.creative_manifest, 'voice', 'text');
294
+ // ^^^^^^^^^^^^^ TextAsset | undefined
295
+
296
+ // Throw form — throws AdcpError('INVALID_REQUEST') with a field path
297
+ // if missing or wrong asset_type. Use when the asset is required for
298
+ // the platform method to proceed.
299
+ const script = requireAsset(req.creative_manifest, 'script', 'text');
300
+ // ^^^^^^ TextAsset (never undefined past this line)
301
+
302
+ await audioStackClient.synthesize({ text: script.content });
303
+ ```
304
+
305
+ Both helpers preserve the discriminator narrowing — `script.content` types correctly without a cast. `requireAsset` throws an `AdcpError` with a precomposed field path (e.g., `creative_manifest.assets.script`) so the buyer sees actionable feedback. Pass `messageOverride` if the default doesn't fit.
306
+
307
+ ## Errors — `throw new AdcpError(...)`
308
+
309
+ Every method either returns its success type OR throws `AdcpError` for structured rejection. Generic thrown errors map to `SERVICE_UNAVAILABLE` with `recovery: 'transient'`.
310
+
311
+ ```ts
312
+ buildCreative: async req => {
313
+ if (!req.format_id?.id?.startsWith('image_')) {
314
+ throw new AdcpError('UNSUPPORTED_FEATURE', {
315
+ recovery: 'terminal',
316
+ message: 'WatermarkPlatform only supports image_* formats',
317
+ field: 'format_id.id',
318
+ });
319
+ }
320
+ if ((req as any).creative_manifest?.assets?.length > 10) {
321
+ throw new AdcpError('INVALID_REQUEST', {
322
+ recovery: 'correctable',
323
+ message: 'Maximum 10 assets per build_creative call',
324
+ field: 'creative_manifest.assets',
325
+ suggestion: 'Split into multiple requests',
326
+ });
327
+ }
328
+ // ... happy path
329
+ };
330
+ ```
331
+
332
+ `AdcpError` constructor:
333
+
334
+ ```ts
335
+ new AdcpError(code: ErrorCode | string, options: {
336
+ recovery: 'transient' | 'correctable' | 'terminal'; // REQUIRED
337
+ message: string; // REQUIRED
338
+ field?: string; // path like 'packages[0].targeting'
339
+ suggestion?: string; // human-readable fix
340
+ retry_after?: number; // seconds; for transient
341
+ details?: Record<string, unknown>; // for multi-error pre-flight, etc.
342
+ })
343
+ ```
344
+
345
+ Common codes for creative-template: `INVALID_REQUEST`, `UNSUPPORTED_FEATURE`, `VALIDATION_ERROR`, `RATE_LIMITED`, `SERVICE_UNAVAILABLE`, `CREATIVE_REJECTED`. The full vocabulary is in `@adcp/sdk/server`'s `ErrorCode` type — return any spec code OR your own platform-specific string (agents fall back to `recovery` classification on unknowns).
346
+
347
+ ## Idempotency — the framework dedupes; you thread the key downstream
348
+
349
+ The framework consumes `idempotency_key` on every mutating request before dispatching to your platform method. Replays come back from the framework's idempotency store; **you never see duplicate calls** for the same `(idempotency_key, account)` pair.
350
+
351
+ What you SHOULD do: pass `req.idempotency_key` to your upstream API's idempotency parameter when you call into GAM / Snap / Meta / your internal services. That makes the dedupe story end-to-end — if the AdCP layer dedupes a request, your upstream platform won't double-charge a CPM either.
352
+
353
+ ```ts
354
+ buildCreative: async req => {
355
+ // Framework already deduped for the (idempotency_key, account) pair.
356
+ // Thread the same key into the upstream call so YOUR platform's API
357
+ // also dedupes if the same key arrives twice (defensive).
358
+ const job = await audioStackClient.synthesize({
359
+ text: scriptText,
360
+ idempotency_key: req.idempotency_key,
361
+ });
362
+ return { format_id: req.target_format_id!, assets: { rendered_audio: job.asset } };
363
+ };
364
+ ```
365
+
366
+ You do NOT need to maintain your own replay table. The framework owns that.
367
+
368
+ ## Account resolution
369
+
370
+ `accounts.resolve(ref)` is called by the framework BEFORE any creative method. Whatever you return becomes `ctx.account` inside your methods. `AccountReference` is a discriminated union:
371
+
372
+ ```ts
373
+ type AccountReference =
374
+ | { account_id: string; sandbox?: boolean }
375
+ | { brand_domain: string; sandbox?: boolean }
376
+ | { agency_buyer: { brand_domain: string }; advertiser: { brand_domain: string }; sandbox?: boolean };
377
+ ```
378
+
379
+ Throw `AccountNotFoundError` (importable from `@adcp/sdk/server`) when you can't resolve — the framework projects to the wire `ACCOUNT_NOT_FOUND` envelope.
380
+
381
+ `sandbox: true` — the buyer is asking you to validate against your platform without actually transacting. Route reads/writes to your sandbox backend if you have one; otherwise just return realistic-shaped responses without persisting.
382
+
383
+ ## Serving the agent
384
+
385
+ <!-- skill-example-skip: continuation of the watermark example above; re-uses identifiers defined there -->
386
+
387
+ ```ts
388
+ import { serve } from '@adcp/sdk/server';
389
+
390
+ const platform = new WatermarkPlatform();
391
+ const server = createAdcpServerFromPlatform(platform, {
392
+ name: 'watermark',
393
+ version: '1.0.0',
394
+ validation: { requests: 'strict', responses: 'strict' },
395
+ });
396
+
397
+ serve(() => server, {
398
+ publicUrl: 'https://watermark.example.com',
399
+ // For multi-host: pass a function `(host) => server` and branch.
400
+ });
401
+ ```
402
+
403
+ `createAdcpServerFromPlatform`:
404
+
405
+ - Calls `validatePlatform()` — throws if you advertise a specialism but don't implement it, or define both halves of a method-pair
406
+ - Wraps each method with `AdcpError`-catch + `submitted`-envelope projection for HITL
407
+ - Returns a `DecisioningAdcpServer` (extends `AdcpServer`) with `getTaskState(taskId)` + `awaitTask(taskId)` for HITL inspection
408
+
409
+ `serve()` is unchanged from v5.x; it accepts the server and binds HTTP transport for both MCP and A2A.
410
+
411
+ ## Capabilities — declare what you support
412
+
413
+ ```ts
414
+ capabilities = {
415
+ specialisms: ['creative-template'] as const, // single literal in the const tuple
416
+ creative_agents: [], // not used by template platforms
417
+ channels: ['display', 'video', 'audio'] as const,
418
+ pricingModels: ['cpm'] as const,
419
+ config: {
420
+ /* your platform-specific config */
421
+ } satisfies YourConfig,
422
+ };
423
+ ```
424
+
425
+ The `as const` is load-bearing — it preserves the literal types so `RequiredPlatformsFor<S>` can compile-check that you provide `creative: CreativeBuilderPlatform`.
426
+
427
+ ## Scaffolding — minimum viable project
428
+
429
+ ```
430
+ my-creative-template-agent/
431
+ ├── package.json # depends on @adcp/sdk ^5.18.0
432
+ ├── tsconfig.json # strict: true
433
+ ├── src/
434
+ │ ├── platform.ts # MyPlatform implements DecisioningPlatform
435
+ │ └── serve.ts # createAdcpServerFromPlatform + serve()
436
+ └── README.md
437
+ ```
438
+
439
+ `package.json`:
440
+
441
+ ```json
442
+ {
443
+ "name": "my-creative-template-agent",
444
+ "type": "module",
445
+ "scripts": { "start": "tsx src/serve.ts" },
446
+ "dependencies": { "@adcp/sdk": "^5.18.0" },
447
+ "devDependencies": { "tsx": "^4", "typescript": "^5" }
448
+ }
449
+ ```
450
+
451
+ ## Testing your platform
452
+
453
+ The fastest test loop: instantiate your platform, build a server, and dispatch a fake tool call without binding HTTP:
454
+
455
+ ```ts
456
+ import { AudioStackPlatform } from './platform';
457
+ import { createAdcpServerFromPlatform } from '@adcp/sdk/server';
458
+
459
+ const platform = new AudioStackPlatform();
460
+ const server = createAdcpServerFromPlatform(platform, {
461
+ name: 'audiostack-test',
462
+ version: '0.0.1',
463
+ validation: { requests: 'off', responses: 'off' },
464
+ });
465
+
466
+ const result = await server.dispatchTestRequest({
467
+ method: 'tools/call',
468
+ params: {
469
+ name: 'build_creative',
470
+ arguments: {
471
+ target_format_id: { id: 'audio_30s', agent_url: 'https://x' },
472
+ creative_manifest: {
473
+ format_id: { id: 'audio_30s', agent_url: 'https://x' },
474
+ assets: { script: { asset_type: 'text', text: 'Hello world.' } },
475
+ },
476
+ account: { account_id: 'test_acc' },
477
+ },
478
+ },
479
+ });
480
+ console.log(result.structuredContent);
481
+ ```
482
+
483
+ `dispatchTestRequest` is the canonical loop for unit-testing platform behavior without HTTP. It's available on `DecisioningAdcpServer` (the type returned by `createAdcpServerFromPlatform`). Set `validation: { requests: 'off' }` while iterating; turn it back to `strict` for end-to-end tests.
484
+
485
+ For HITL platforms, `server.awaitTask(taskId)` settles the background promise; `server.getTaskState(taskId)` reads terminal status.
486
+
487
+ ## What NOT to do
488
+
489
+ ❌ **Don't import from `@adcp/sdk/server` for the platform shape.** That's the v5.x handler-style API. Use `@adcp/sdk/server` for v6.0.
490
+
491
+ ❌ **Don't use `ctx.runAsync(...)` or `ctx.startTask(...)`.** Those were in earlier preview drops; they're gone in v2.1. The async story is dual-method (`xxx` vs `xxxTask`), period.
492
+
493
+ ❌ **Don't define both `buildCreative` and `buildCreativeTask`.** `validatePlatform()` will throw with a clear diagnostic. Pick one.
494
+
495
+ ❌ **Don't return error envelopes manually.** Throw `AdcpError`; the framework projects to the wire shape.
496
+
497
+ ❌ **Don't write `as never` or `as any` on platform code.** The wire types are typed, including `creative_manifest.assets[asset_id]` as a discriminated union. If you reach for a cast, you're missing an `import type` or skipping a discriminator check.
498
+
499
+ ❌ **Don't treat `creative_manifest.assets` as an array.** It's a keyed map: `{ [asset_id: string]: ImageAsset | AudioAsset | ... }`. Look up by asset_id, not by index.
500
+
501
+ ❌ **Don't try to write to the buyer's `media_buy_status_changes` channel** (or any other resource type). Creative-template platforms don't emit lifecycle events; they're stateless.
502
+
503
+ ❌ **Don't implement `getMediaBuyDelivery` / `createMediaBuy` / etc.** Those are sales-shaped tools. Creative-template only implements `creative.*`.
504
+
505
+ ## Reference: imports cheat sheet
506
+
507
+ ```ts
508
+ // From @adcp/sdk/server
509
+ import {
510
+ AdcpError,
511
+ AccountNotFoundError,
512
+ createAdcpServerFromPlatform,
513
+ // Manifest accessors that preserve discriminator narrowing
514
+ getAsset,
515
+ requireAsset,
516
+ type DecisioningPlatform,
517
+ type AccountStore,
518
+ type Account,
519
+ type CreativeBuilderPlatform,
520
+ type CreativeReviewResult,
521
+ type RequestContext,
522
+ type ErrorCode,
523
+ type AdcpStructuredError,
524
+ } from '@adcp/sdk/server';
525
+
526
+ // From @adcp/sdk/types — wire schemas (auto-generated)
527
+ import type {
528
+ BuildCreativeRequest,
529
+ CreativeManifest,
530
+ PreviewCreativeRequest,
531
+ PreviewCreativeResponse,
532
+ CreativeAsset,
533
+ AccountReference,
534
+ // Asset types for narrowing — pull only the ones you produce/consume
535
+ ImageAsset,
536
+ AudioAsset,
537
+ VideoAsset,
538
+ TextAsset,
539
+ URLAsset,
540
+ HTMLAsset,
541
+ VASTAsset,
542
+ } from '@adcp/sdk/types';
543
+
544
+ // From @adcp/sdk/server — HTTP serving
545
+ import { serve } from '@adcp/sdk/server';
546
+ ```
547
+
548
+ ## When you're stuck
549
+
550
+ - `validatePlatform()` threw at construction → check the diagnostic; usually you advertised a specialism without implementing the matching field, or defined both sync and `*Task` for the same pair.
551
+ - TS compiler complains about `RequiredPlatformsFor<S>` constraint → you claimed `creative-template` but your `creative:` field doesn't match `CreativeBuilderPlatform`. Re-check the method signatures.
552
+ - Wire request doesn't reach your method → check the framework's `validation: 'strict'` config; the request may be failing schema validation before dispatch. Set `validation: { requests: 'off' }` temporarily to diagnose.
553
+
554
+ For fuller protocol context (request/response shapes, AdCP error vocabulary): read `docs/llms.txt`. For the v6.0 design rationale: `docs/proposals/decisioning-platform-v2-hitl-split.md`.