@adcp/client 4.21.0 → 4.22.1
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.
- package/AGENTS.md +278 -0
- package/README.md +96 -61
- package/bin/adcp.js +342 -4
- package/dist/lib/agents/index.generated.d.ts +9 -1
- package/dist/lib/agents/index.generated.d.ts.map +1 -1
- package/dist/lib/agents/index.generated.js +12 -0
- package/dist/lib/agents/index.generated.js.map +1 -1
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.ts +2 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +10 -1
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/discovery/property-crawler.d.ts +4 -0
- package/dist/lib/discovery/property-crawler.d.ts.map +1 -1
- package/dist/lib/discovery/property-crawler.js +10 -2
- package/dist/lib/discovery/property-crawler.js.map +1 -1
- package/dist/lib/index.d.ts +4 -4
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +6 -4
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/protocols/index.d.ts.map +1 -1
- package/dist/lib/protocols/index.js +8 -6
- package/dist/lib/protocols/index.js.map +1 -1
- package/dist/lib/protocols/mcp.d.ts.map +1 -1
- package/dist/lib/protocols/mcp.js +24 -11
- package/dist/lib/protocols/mcp.js.map +1 -1
- package/dist/lib/server/index.d.ts +2 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +3 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/serve.d.ts +73 -0
- package/dist/lib/server/serve.d.ts.map +1 -0
- package/dist/lib/server/serve.js +94 -0
- package/dist/lib/server/serve.js.map +1 -0
- package/dist/lib/testing/client.d.ts.map +1 -1
- package/dist/lib/testing/client.js +1 -0
- package/dist/lib/testing/client.js.map +1 -1
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +48 -63
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts +24 -0
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js +157 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -0
- package/dist/lib/testing/compliance/types.d.ts +1 -1
- package/dist/lib/testing/compliance/types.d.ts.map +1 -1
- package/dist/lib/testing/index.d.ts +1 -0
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js +23 -1
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/orchestrator.d.ts +8 -0
- package/dist/lib/testing/orchestrator.d.ts.map +1 -1
- package/dist/lib/testing/orchestrator.js +8 -0
- package/dist/lib/testing/orchestrator.js.map +1 -1
- package/dist/lib/testing/storyboard/context.d.ts +34 -0
- package/dist/lib/testing/storyboard/context.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/context.js +257 -0
- package/dist/lib/testing/storyboard/context.js.map +1 -0
- package/dist/lib/testing/storyboard/index.d.ts +15 -0
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/index.js +48 -0
- package/dist/lib/testing/storyboard/index.js.map +1 -0
- package/dist/lib/testing/storyboard/loader.d.ts +53 -0
- package/dist/lib/testing/storyboard/loader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/loader.js +114 -0
- package/dist/lib/testing/storyboard/loader.js.map +1 -0
- package/dist/lib/testing/storyboard/path.d.ts +29 -0
- package/dist/lib/testing/storyboard/path.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/path.js +121 -0
- package/dist/lib/testing/storyboard/path.js.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts +28 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.js +410 -0
- package/dist/lib/testing/storyboard/request-builder.js.map +1 -0
- package/dist/lib/testing/storyboard/runner.d.ts +24 -0
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/runner.js +280 -0
- package/dist/lib/testing/storyboard/runner.js.map +1 -0
- package/dist/lib/testing/storyboard/task-map.d.ts +21 -0
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/task-map.js +84 -0
- package/dist/lib/testing/storyboard/task-map.js.map +1 -0
- package/dist/lib/testing/storyboard/types.d.ts +156 -0
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/types.js +10 -0
- package/dist/lib/testing/storyboard/types.js.map +1 -0
- package/dist/lib/testing/storyboard/validations.d.ts +17 -0
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/validations.js +166 -0
- package/dist/lib/testing/storyboard/validations.js.map +1 -0
- package/dist/lib/testing/types.d.ts +2 -0
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/types/core.generated.d.ts +2 -2
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js +1 -1
- package/dist/lib/types/schemas.generated.d.ts +193 -34
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +87 -5
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/tools.generated.d.ts +280 -3
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.js +34 -3
- package/dist/lib/utils/response-schemas.js.map +1 -1
- package/dist/lib/utils/validate-user-agent.d.ts +8 -0
- package/dist/lib/utils/validate-user-agent.d.ts.map +1 -0
- package/dist/lib/utils/validate-user-agent.js +15 -0
- package/dist/lib/utils/validate-user-agent.js.map +1 -0
- package/dist/lib/version.d.ts +6 -0
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +7 -1
- package/dist/lib/version.js.map +1 -1
- package/docs/README.md +42 -0
- package/docs/guides/BUILD-AN-AGENT.md +294 -0
- package/docs/llms.txt +634 -0
- package/examples/README.md +106 -0
- package/examples/adcp.config.json +30 -0
- package/examples/basic-a2a.ts +76 -0
- package/examples/basic-mcp.ts +50 -0
- package/examples/batch-preview-test.ts +266 -0
- package/examples/conversation-client.ts +291 -0
- package/examples/debug-preview-response.ts +73 -0
- package/examples/debug-preview-with-logging.ts +50 -0
- package/examples/easy-config-demo.ts +242 -0
- package/examples/env-config.ts +51 -0
- package/examples/error-compliant-server.ts +237 -0
- package/examples/generative-creative-demo.ts +205 -0
- package/examples/inspect-card-formats.ts +161 -0
- package/examples/logger-usage.ts +165 -0
- package/examples/oauth-cli-example.ts +154 -0
- package/examples/pr78-async-patterns-demo.ts +247 -0
- package/examples/signals-agent.ts +163 -0
- package/examples/simple-getting-started.ts +225 -0
- package/examples/simple-protocol-demo.ts +75 -0
- package/examples/test-helpers-demo.ts +239 -0
- package/examples/zod-validation-example.ts +126 -0
- package/package.json +12 -2
- package/skills/adcp/SKILL.md +13 -2
- package/storyboards/audience_sync.yaml +199 -0
- package/storyboards/behavioral_analysis.yaml +244 -0
- package/storyboards/brand_rights.yaml +131 -0
- package/storyboards/creative_ad_server.yaml +171 -0
- package/storyboards/creative_sales_agent.yaml +169 -0
- package/storyboards/creative_template.yaml +306 -0
- package/storyboards/deterministic_testing.yaml +925 -0
- package/storyboards/error_compliance.yaml +231 -0
- package/storyboards/governance_content_standards.yaml +213 -0
- package/storyboards/governance_property_lists.yaml +372 -0
- package/storyboards/media_buy_catalog_creative.yaml +457 -0
- package/storyboards/media_buy_governance_escalation.yaml +467 -0
- package/storyboards/media_buy_guaranteed_approval.yaml +396 -0
- package/storyboards/media_buy_non_guaranteed.yaml +288 -0
- package/storyboards/media_buy_proposal_mode.yaml +369 -0
- package/storyboards/media_buy_seller.yaml +560 -0
- package/storyboards/media_buy_state_machine.yaml +254 -0
- package/storyboards/schema.yaml +65 -0
- package/storyboards/schema_validation.yaml +166 -0
- package/storyboards/si_session.yaml +384 -0
- package/storyboards/signal_marketplace.yaml +283 -0
- package/storyboards/signal_owned.yaml +211 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
id: media_buy_state_machine
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Media buy state machine lifecycle"
|
|
4
|
+
category: media_buy_seller
|
|
5
|
+
track: media_buy
|
|
6
|
+
summary: "Validates media buy state transitions: create, pause, resume, cancel, and terminal state enforcement."
|
|
7
|
+
|
|
8
|
+
required_tools:
|
|
9
|
+
- create_media_buy
|
|
10
|
+
- update_media_buy
|
|
11
|
+
|
|
12
|
+
narrative: |
|
|
13
|
+
A media buy has a well-defined state machine: draft, pending_approval, confirmed, active,
|
|
14
|
+
paused, completed, canceled. Transitions between states must follow the spec — you cannot
|
|
15
|
+
resume a canceled buy or pause a completed one.
|
|
16
|
+
|
|
17
|
+
This storyboard creates a media buy, walks it through pause/resume/cancel transitions, then
|
|
18
|
+
verifies that the agent rejects updates to a buy in a terminal state (canceled or completed).
|
|
19
|
+
It also tests package-level pause/resume independent of the media buy status.
|
|
20
|
+
|
|
21
|
+
The state machine is the backbone of media buy reliability. If an agent allows invalid
|
|
22
|
+
transitions, buyers cannot trust the status field and automation breaks down.
|
|
23
|
+
|
|
24
|
+
agent:
|
|
25
|
+
interaction_model: media_buy_seller
|
|
26
|
+
capabilities:
|
|
27
|
+
- sells_media
|
|
28
|
+
- accepts_briefs
|
|
29
|
+
examples:
|
|
30
|
+
- "Any AdCP seller with media buy support"
|
|
31
|
+
|
|
32
|
+
caller:
|
|
33
|
+
role: buyer_agent
|
|
34
|
+
example: "Scope3 (DSP)"
|
|
35
|
+
|
|
36
|
+
prerequisites:
|
|
37
|
+
description: |
|
|
38
|
+
The caller needs a brand identity for account setup. The test creates a media buy
|
|
39
|
+
using discovered products, then exercises state transitions.
|
|
40
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
41
|
+
|
|
42
|
+
phases:
|
|
43
|
+
- id: setup
|
|
44
|
+
title: "Create a media buy"
|
|
45
|
+
narrative: |
|
|
46
|
+
Discover products and create a media buy to use for state transition testing.
|
|
47
|
+
The media buy ID is captured and passed to subsequent phases via context.
|
|
48
|
+
|
|
49
|
+
steps:
|
|
50
|
+
- id: discover_products
|
|
51
|
+
title: "Discover products for media buy"
|
|
52
|
+
narrative: |
|
|
53
|
+
Send a brief to get available products with pricing options. The first product
|
|
54
|
+
with a pricing option will be used to create the test media buy.
|
|
55
|
+
task: get_products
|
|
56
|
+
requires_tool: get_products
|
|
57
|
+
stateful: false
|
|
58
|
+
expected: |
|
|
59
|
+
Return products with:
|
|
60
|
+
- product_id
|
|
61
|
+
- pricing_options with pricing_option_id
|
|
62
|
+
sample_request:
|
|
63
|
+
buying_mode: "brief"
|
|
64
|
+
brief: "Display advertising products for state machine testing"
|
|
65
|
+
brand:
|
|
66
|
+
domain: "acmeoutdoor.com"
|
|
67
|
+
context_outputs:
|
|
68
|
+
- path: "products[0].product_id"
|
|
69
|
+
key: "product_id"
|
|
70
|
+
- path: "products[0].pricing_options[0].pricing_option_id"
|
|
71
|
+
key: "pricing_option_id"
|
|
72
|
+
validations:
|
|
73
|
+
- check: response_schema
|
|
74
|
+
description: "Response matches get-products-response.json schema"
|
|
75
|
+
- check: field_present
|
|
76
|
+
path: "products[0].product_id"
|
|
77
|
+
description: "At least one product with a product_id"
|
|
78
|
+
|
|
79
|
+
- id: create_buy
|
|
80
|
+
title: "Create the test media buy"
|
|
81
|
+
narrative: |
|
|
82
|
+
Create a media buy using the discovered product. The media_buy_id is captured
|
|
83
|
+
for use in all subsequent state transition steps.
|
|
84
|
+
task: create_media_buy
|
|
85
|
+
requires_tool: create_media_buy
|
|
86
|
+
stateful: true
|
|
87
|
+
expected: |
|
|
88
|
+
Return a media buy with:
|
|
89
|
+
- media_buy_id: platform-assigned identifier
|
|
90
|
+
- status: confirmed, active, or pending_approval
|
|
91
|
+
sample_request:
|
|
92
|
+
account:
|
|
93
|
+
brand:
|
|
94
|
+
domain: "acmeoutdoor.com"
|
|
95
|
+
operator: "pinnacle-agency.com"
|
|
96
|
+
brand:
|
|
97
|
+
domain: "acmeoutdoor.com"
|
|
98
|
+
start_time: "2026-05-01T00:00:00Z"
|
|
99
|
+
end_time: "2026-05-31T23:59:59Z"
|
|
100
|
+
packages:
|
|
101
|
+
- product_id: "$context.product_id"
|
|
102
|
+
budget: 5000
|
|
103
|
+
pricing_option_id: "$context.pricing_option_id"
|
|
104
|
+
context_outputs:
|
|
105
|
+
- path: "media_buy_id"
|
|
106
|
+
key: "media_buy_id"
|
|
107
|
+
- path: "media_buy.media_buy_id"
|
|
108
|
+
key: "media_buy_id"
|
|
109
|
+
validations:
|
|
110
|
+
- check: response_schema
|
|
111
|
+
description: "Response matches create-media-buy-response.json schema"
|
|
112
|
+
- check: field_present
|
|
113
|
+
path: "media_buy_id"
|
|
114
|
+
description: "Response contains a media_buy_id"
|
|
115
|
+
|
|
116
|
+
- id: state_transitions
|
|
117
|
+
title: "State transitions: pause, resume, cancel"
|
|
118
|
+
narrative: |
|
|
119
|
+
Exercise the core state transitions on the media buy. Pause puts the buy on hold
|
|
120
|
+
(status becomes paused), resume reactivates it (status becomes active), and cancel
|
|
121
|
+
terminates it permanently (status becomes canceled).
|
|
122
|
+
|
|
123
|
+
Each transition is validated by checking the returned status field.
|
|
124
|
+
|
|
125
|
+
steps:
|
|
126
|
+
- id: pause_buy
|
|
127
|
+
title: "Pause the media buy"
|
|
128
|
+
narrative: |
|
|
129
|
+
Pause the active media buy. The status should transition to paused.
|
|
130
|
+
This is a reversible operation — the buy can be resumed later.
|
|
131
|
+
task: update_media_buy
|
|
132
|
+
requires_tool: update_media_buy
|
|
133
|
+
stateful: true
|
|
134
|
+
expected: |
|
|
135
|
+
Return the media buy with status: paused.
|
|
136
|
+
sample_request:
|
|
137
|
+
media_buy_id: "$context.media_buy_id"
|
|
138
|
+
paused: true
|
|
139
|
+
validations:
|
|
140
|
+
- check: field_value
|
|
141
|
+
path: "status"
|
|
142
|
+
value: "paused"
|
|
143
|
+
description: "Media buy status is paused"
|
|
144
|
+
|
|
145
|
+
- id: resume_buy
|
|
146
|
+
title: "Resume the media buy"
|
|
147
|
+
narrative: |
|
|
148
|
+
Resume the paused media buy. The status should transition back to active
|
|
149
|
+
(or pending_activation on some platforms).
|
|
150
|
+
task: update_media_buy
|
|
151
|
+
requires_tool: update_media_buy
|
|
152
|
+
stateful: true
|
|
153
|
+
expected: |
|
|
154
|
+
Return the media buy with status: active or pending_activation.
|
|
155
|
+
sample_request:
|
|
156
|
+
media_buy_id: "$context.media_buy_id"
|
|
157
|
+
paused: false
|
|
158
|
+
validations:
|
|
159
|
+
- check: field_present
|
|
160
|
+
path: "status"
|
|
161
|
+
description: "Response contains a status field after resume"
|
|
162
|
+
|
|
163
|
+
- id: cancel_buy
|
|
164
|
+
title: "Cancel the media buy"
|
|
165
|
+
narrative: |
|
|
166
|
+
Cancel the media buy permanently. The status should transition to canceled.
|
|
167
|
+
This is a terminal state — no further transitions are allowed.
|
|
168
|
+
task: update_media_buy
|
|
169
|
+
requires_tool: update_media_buy
|
|
170
|
+
stateful: true
|
|
171
|
+
expected: |
|
|
172
|
+
Return the media buy with status: canceled.
|
|
173
|
+
sample_request:
|
|
174
|
+
media_buy_id: "$context.media_buy_id"
|
|
175
|
+
canceled: true
|
|
176
|
+
cancellation_reason: "AdCP compliance test — state machine scenario"
|
|
177
|
+
validations:
|
|
178
|
+
- check: field_value
|
|
179
|
+
path: "status"
|
|
180
|
+
value: "canceled"
|
|
181
|
+
description: "Media buy status is canceled"
|
|
182
|
+
|
|
183
|
+
- id: terminal_enforcement
|
|
184
|
+
title: "Terminal state enforcement"
|
|
185
|
+
narrative: |
|
|
186
|
+
Once a media buy is canceled or completed, the agent must reject any further
|
|
187
|
+
state changes. Attempting to pause, resume, or re-cancel a terminated buy should
|
|
188
|
+
return an error — typically INVALID_STATE_TRANSITION or INVALID_STATE.
|
|
189
|
+
|
|
190
|
+
This validates that the state machine is properly enforced and buyers can trust
|
|
191
|
+
that terminal states are final.
|
|
192
|
+
|
|
193
|
+
steps:
|
|
194
|
+
- id: pause_canceled_buy
|
|
195
|
+
title: "Pause a canceled media buy (expect rejection)"
|
|
196
|
+
narrative: |
|
|
197
|
+
Attempt to pause the canceled media buy. The agent should reject this with
|
|
198
|
+
an error indicating the state transition is invalid.
|
|
199
|
+
task: update_media_buy
|
|
200
|
+
requires_tool: update_media_buy
|
|
201
|
+
expect_error: true
|
|
202
|
+
stateful: true
|
|
203
|
+
expected: |
|
|
204
|
+
Reject with an error containing:
|
|
205
|
+
- code: INVALID_STATE_TRANSITION, INVALID_STATE, or similar
|
|
206
|
+
- The buy must remain in canceled status
|
|
207
|
+
sample_request:
|
|
208
|
+
media_buy_id: "$context.media_buy_id"
|
|
209
|
+
paused: true
|
|
210
|
+
validations:
|
|
211
|
+
- check: error_code
|
|
212
|
+
value: "INVALID_STATE_TRANSITION"
|
|
213
|
+
description: "Error code indicates invalid state transition"
|
|
214
|
+
|
|
215
|
+
- id: resume_canceled_buy
|
|
216
|
+
title: "Resume a canceled media buy (expect rejection)"
|
|
217
|
+
narrative: |
|
|
218
|
+
Attempt to resume the canceled media buy. The agent should reject this —
|
|
219
|
+
canceled is a terminal state and cannot be reversed.
|
|
220
|
+
task: update_media_buy
|
|
221
|
+
requires_tool: update_media_buy
|
|
222
|
+
expect_error: true
|
|
223
|
+
stateful: true
|
|
224
|
+
expected: |
|
|
225
|
+
Reject with an error. Canceled media buys cannot be resumed.
|
|
226
|
+
sample_request:
|
|
227
|
+
media_buy_id: "$context.media_buy_id"
|
|
228
|
+
paused: false
|
|
229
|
+
validations:
|
|
230
|
+
- check: error_code
|
|
231
|
+
value: "INVALID_STATE_TRANSITION"
|
|
232
|
+
description: "Error code indicates invalid state transition"
|
|
233
|
+
|
|
234
|
+
- id: recancel_buy
|
|
235
|
+
title: "Re-cancel an already canceled media buy"
|
|
236
|
+
narrative: |
|
|
237
|
+
Attempt to cancel a buy that is already canceled. The agent may either
|
|
238
|
+
reject with INVALID_STATE_TRANSITION or accept idempotently. Both are
|
|
239
|
+
acceptable — what matters is no crash or unstructured error.
|
|
240
|
+
task: update_media_buy
|
|
241
|
+
requires_tool: update_media_buy
|
|
242
|
+
stateful: true
|
|
243
|
+
expected: |
|
|
244
|
+
Either:
|
|
245
|
+
- Reject with INVALID_STATE_TRANSITION (strict)
|
|
246
|
+
- Accept idempotently and return status: canceled (permissive)
|
|
247
|
+
Both are acceptable behaviors.
|
|
248
|
+
sample_request:
|
|
249
|
+
media_buy_id: "$context.media_buy_id"
|
|
250
|
+
canceled: true
|
|
251
|
+
validations:
|
|
252
|
+
- check: field_present
|
|
253
|
+
path: "status"
|
|
254
|
+
description: "Response contains a status field (canceled) or a structured error"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Storyboard Definition Schema
|
|
2
|
+
#
|
|
3
|
+
# Storyboards are narrative test workflows that walk agent builders through
|
|
4
|
+
# the sequence of calls their agent will receive, with context at each step.
|
|
5
|
+
#
|
|
6
|
+
# Each storyboard targets a specific agent interaction model and
|
|
7
|
+
# describes the flow from a caller's perspective.
|
|
8
|
+
|
|
9
|
+
# --- Schema definition ---
|
|
10
|
+
|
|
11
|
+
# A storyboard file must conform to this structure:
|
|
12
|
+
#
|
|
13
|
+
# id: string (unique identifier, e.g., "creative_template")
|
|
14
|
+
# version: string (semver, e.g., "1.0.0")
|
|
15
|
+
# title: string (human-readable title)
|
|
16
|
+
# category: enum (creative_template | creative_ad_server | creative_sales_agent | creative_generative | media_buy_seller | media_buy_guaranteed_approval | media_buy_non_guaranteed | media_buy_proposal_mode | media_buy_governance_escalation | media_buy_catalog_creative | signal_marketplace | signal_owned)
|
|
17
|
+
# summary: string (one-line description for listings)
|
|
18
|
+
# narrative: string (paragraph explaining the overall flow)
|
|
19
|
+
#
|
|
20
|
+
# agent:
|
|
21
|
+
# interaction_model: enum (stateless_transform | stateful_preloaded | stateful_push | stateless_generate | media_buy_seller | marketplace_catalog | owned_signals)
|
|
22
|
+
# capabilities: string[] (AdCP capability flags: supports_transformation, has_creative_library, supports_generation, sells_media, accepts_briefs, supports_guaranteed, supports_non_guaranteed, catalog_signals)
|
|
23
|
+
# examples: string[] (real-world examples: "Celtra", "Innovid")
|
|
24
|
+
#
|
|
25
|
+
# caller:
|
|
26
|
+
# role: string (who initiates the calls: "buyer_agent", "orchestrator", "dsp")
|
|
27
|
+
# example: string (e.g., "Scope3", "Pinnacle Agency")
|
|
28
|
+
#
|
|
29
|
+
# prerequisites:
|
|
30
|
+
# description: string (what must be true before running this storyboard)
|
|
31
|
+
# test_kit: string (reference to a test kit file, e.g., "test-kits/acme-outdoor.yaml")
|
|
32
|
+
#
|
|
33
|
+
# phases: array of Phase objects
|
|
34
|
+
#
|
|
35
|
+
# --- Phase ---
|
|
36
|
+
#
|
|
37
|
+
# id: string (unique within storyboard)
|
|
38
|
+
# title: string (human-readable phase title)
|
|
39
|
+
# narrative: string (paragraph explaining this phase from the caller's perspective)
|
|
40
|
+
#
|
|
41
|
+
# steps: array of Step objects
|
|
42
|
+
#
|
|
43
|
+
# --- Step ---
|
|
44
|
+
#
|
|
45
|
+
# id: string (unique within phase)
|
|
46
|
+
# title: string (human-readable step title)
|
|
47
|
+
# narrative: string (what's happening and why)
|
|
48
|
+
# task: string (AdCP task name: list_creative_formats, preview_creative, build_creative, get_products, create_media_buy, sync_accounts, etc.)
|
|
49
|
+
# schema_ref: string (path to request schema, e.g., "creative/list-creative-formats-request.json" or "media-buy/get-products-request.json")
|
|
50
|
+
# response_schema_ref: string (path to response schema)
|
|
51
|
+
# doc_ref: string (path to documentation page)
|
|
52
|
+
# comply_scenario: string (maps to @adcp/client testing scenario, e.g., "creative_sync")
|
|
53
|
+
# expected: string (human-readable description of expected behavior)
|
|
54
|
+
# stateful: boolean (does this step depend on state from a previous step?)
|
|
55
|
+
#
|
|
56
|
+
# sample_request: object (optional — example request payload for this step)
|
|
57
|
+
# sample_response: object (optional — example expected response)
|
|
58
|
+
#
|
|
59
|
+
# validations: array of Validation objects (optional)
|
|
60
|
+
#
|
|
61
|
+
# --- Validation ---
|
|
62
|
+
#
|
|
63
|
+
# check: string (what to validate: "response_schema", "field_present", "field_value", "status_code")
|
|
64
|
+
# path: string (JSON path to the field, e.g., "formats[0].format_id")
|
|
65
|
+
# description: string (human-readable description of validation)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
id: schema_validation
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Schema compliance and temporal validation"
|
|
4
|
+
category: media_buy_seller
|
|
5
|
+
track: core
|
|
6
|
+
summary: "Validates that agent responses conform to AdCP schemas and that temporal constraints are enforced."
|
|
7
|
+
|
|
8
|
+
required_tools:
|
|
9
|
+
- get_products
|
|
10
|
+
|
|
11
|
+
narrative: |
|
|
12
|
+
Every AdCP agent must return responses that match the published JSON schemas. Fields defined
|
|
13
|
+
in the spec — product_id, delivery_type, pricing_options — must be present and correctly typed.
|
|
14
|
+
Agents must also enforce temporal constraints: flight dates must be logically consistent
|
|
15
|
+
(end after start) and start dates should not be in the past.
|
|
16
|
+
|
|
17
|
+
This storyboard checks schema compliance on get_products responses and validates that
|
|
18
|
+
create_media_buy rejects temporally invalid requests. These are foundational requirements
|
|
19
|
+
that every agent must satisfy regardless of platform type.
|
|
20
|
+
|
|
21
|
+
agent:
|
|
22
|
+
interaction_model: media_buy_seller
|
|
23
|
+
capabilities:
|
|
24
|
+
- sells_media
|
|
25
|
+
examples:
|
|
26
|
+
- "Any AdCP seller agent"
|
|
27
|
+
|
|
28
|
+
caller:
|
|
29
|
+
role: buyer_agent
|
|
30
|
+
example: "Compliance test harness"
|
|
31
|
+
|
|
32
|
+
phases:
|
|
33
|
+
- id: schema_compliance
|
|
34
|
+
title: "Response schema compliance"
|
|
35
|
+
narrative: |
|
|
36
|
+
The buyer sends a standard get_products request and validates that the response
|
|
37
|
+
matches the published schema. Each product must have the required fields defined
|
|
38
|
+
in the AdCP spec: product_id, delivery_type, and pricing information.
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- id: get_products_schema
|
|
42
|
+
title: "Validate get_products response schema"
|
|
43
|
+
narrative: |
|
|
44
|
+
Send a brief and validate the response structure. Every product in the response
|
|
45
|
+
must conform to the get-products-response.json schema, with required v3 fields
|
|
46
|
+
present.
|
|
47
|
+
task: get_products
|
|
48
|
+
requires_tool: get_products
|
|
49
|
+
stateful: false
|
|
50
|
+
expected: |
|
|
51
|
+
Return products matching the brief. Each product must have:
|
|
52
|
+
- product_id: unique identifier
|
|
53
|
+
- name: human-readable name
|
|
54
|
+
- delivery_type: guaranteed or non_guaranteed
|
|
55
|
+
- pricing_options: at least one pricing option
|
|
56
|
+
sample_request:
|
|
57
|
+
buying_mode: "brief"
|
|
58
|
+
brief: "Show all available advertising products"
|
|
59
|
+
brand:
|
|
60
|
+
domain: "acmeoutdoor.com"
|
|
61
|
+
validations:
|
|
62
|
+
- check: response_schema
|
|
63
|
+
description: "Response matches get-products-response.json schema"
|
|
64
|
+
- check: field_present
|
|
65
|
+
path: "products"
|
|
66
|
+
description: "Response contains a products array"
|
|
67
|
+
- check: field_present
|
|
68
|
+
path: "products[0].product_id"
|
|
69
|
+
description: "Each product has a product_id"
|
|
70
|
+
- check: field_present
|
|
71
|
+
path: "products[0].delivery_type"
|
|
72
|
+
description: "Each product declares guaranteed or non_guaranteed delivery"
|
|
73
|
+
- check: field_present
|
|
74
|
+
path: "products[0].name"
|
|
75
|
+
description: "Each product has a name"
|
|
76
|
+
|
|
77
|
+
- id: pricing_options_present
|
|
78
|
+
title: "Validate pricing options structure"
|
|
79
|
+
narrative: |
|
|
80
|
+
Check that products include pricing_options with the required fields:
|
|
81
|
+
pricing_option_id and pricing_model. These are essential for buyers to
|
|
82
|
+
construct valid create_media_buy requests.
|
|
83
|
+
task: get_products
|
|
84
|
+
requires_tool: get_products
|
|
85
|
+
stateful: false
|
|
86
|
+
expected: |
|
|
87
|
+
Products include pricing_options with:
|
|
88
|
+
- pricing_option_id: unique identifier for the pricing option
|
|
89
|
+
- pricing_model: CPM, CPC, flat_fee, etc.
|
|
90
|
+
sample_request:
|
|
91
|
+
buying_mode: "brief"
|
|
92
|
+
brief: "Products with detailed pricing information"
|
|
93
|
+
brand:
|
|
94
|
+
domain: "acmeoutdoor.com"
|
|
95
|
+
validations:
|
|
96
|
+
- check: field_present
|
|
97
|
+
path: "products[0].pricing_options"
|
|
98
|
+
description: "Products include pricing_options array"
|
|
99
|
+
- check: field_present
|
|
100
|
+
path: "products[0].pricing_options[0].pricing_option_id"
|
|
101
|
+
description: "Pricing options have a pricing_option_id"
|
|
102
|
+
- check: field_present
|
|
103
|
+
path: "products[0].pricing_options[0].pricing_model"
|
|
104
|
+
description: "Pricing options declare a pricing_model"
|
|
105
|
+
|
|
106
|
+
- id: temporal_validation
|
|
107
|
+
title: "Temporal constraint enforcement"
|
|
108
|
+
narrative: |
|
|
109
|
+
Flight dates are a fundamental constraint in media buying. The start date must come
|
|
110
|
+
before the end date, and agents should validate this before accepting a media buy.
|
|
111
|
+
Some agents also reject start dates in the past, though this is platform-dependent.
|
|
112
|
+
|
|
113
|
+
steps:
|
|
114
|
+
- id: reversed_dates
|
|
115
|
+
title: "Reject reversed date range"
|
|
116
|
+
narrative: |
|
|
117
|
+
Send a create_media_buy with end_time before start_time. The agent must reject
|
|
118
|
+
this — a campaign cannot end before it starts.
|
|
119
|
+
task: create_media_buy
|
|
120
|
+
requires_tool: create_media_buy
|
|
121
|
+
expect_error: true
|
|
122
|
+
stateful: false
|
|
123
|
+
expected: |
|
|
124
|
+
Reject with an error containing:
|
|
125
|
+
- code: INVALID_REQUEST
|
|
126
|
+
- recovery: correctable
|
|
127
|
+
The agent must not accept a media buy where end_time precedes start_time.
|
|
128
|
+
sample_request:
|
|
129
|
+
idempotency_key: "temporal-test-reversed"
|
|
130
|
+
start_time: "2026-05-31T23:59:59Z"
|
|
131
|
+
end_time: "2026-05-01T00:00:00Z"
|
|
132
|
+
packages:
|
|
133
|
+
- product_id: "test-product"
|
|
134
|
+
budget: 1000
|
|
135
|
+
pricing_option_id: "test-pricing"
|
|
136
|
+
validations:
|
|
137
|
+
- check: error_code
|
|
138
|
+
value: "INVALID_REQUEST"
|
|
139
|
+
description: "Error code is INVALID_REQUEST for reversed date range"
|
|
140
|
+
|
|
141
|
+
- id: past_start_date
|
|
142
|
+
title: "Handle start date in the past"
|
|
143
|
+
narrative: |
|
|
144
|
+
Send a create_media_buy with a start_time in the past. Some agents reject this
|
|
145
|
+
outright, others accept it and auto-adjust the start date. Both behaviors are
|
|
146
|
+
acceptable — what matters is that the response is structured and intentional.
|
|
147
|
+
task: create_media_buy
|
|
148
|
+
requires_tool: create_media_buy
|
|
149
|
+
stateful: false
|
|
150
|
+
expected: |
|
|
151
|
+
Either:
|
|
152
|
+
- Reject with INVALID_REQUEST (strict validation)
|
|
153
|
+
- Accept and auto-adjust the start date (permissive)
|
|
154
|
+
Both are acceptable. The agent should not silently accept a past date without
|
|
155
|
+
adjusting it or warning the buyer.
|
|
156
|
+
sample_request:
|
|
157
|
+
idempotency_key: "temporal-test-past-start"
|
|
158
|
+
start_time: "2025-01-01T00:00:00Z"
|
|
159
|
+
end_time: "2026-12-31T23:59:59Z"
|
|
160
|
+
packages:
|
|
161
|
+
- product_id: "test-product"
|
|
162
|
+
budget: 1000
|
|
163
|
+
pricing_option_id: "test-pricing"
|
|
164
|
+
validations:
|
|
165
|
+
- check: response_schema
|
|
166
|
+
description: "Response is a valid create-media-buy-response or structured error"
|