Summary
Python seller/server helpers should make 3.0/3.1 version compatibility automatic:
- If the buyer omits an exact AdCP version, default to legacy 3.0 semantics.
- If the buyer explicitly requests 3.1, return the 3.1 response shape.
- Capabilities should advertise exact supported spec versions, not only
major_versions: [3], so buyers/storyboards can select the right contract.
Why this matters
AdCP 3.1 beta splits protocol envelope status from media-buy lifecycle status. For example, create_media_buy in 3.1 should return:
{
"status": "completed",
"media_buy_status": "pending_creatives"
}
Legacy 3.0 buyers/storyboards expect the media-buy lifecycle at top-level status:
{
"status": "pending_creatives"
}
If a seller always returns the 3.1 shape, 3.0 storyboards fail. If a seller always returns the 3.0 shape, 3.1 schemas fail. The server layer needs a consistent way to resolve the requested spec version and serialize the response accordingly.
Observed behavior
In a Sales Agent integration using Python SDK adcp==6.1.0b2:
adcp.__version__ = 6.1.0b2
get_adcp_spec_version() = 3.1.0-beta.3
Capabilities exposed to the JS storyboard runner contain only:
{
"adcp": {
"major_versions": [3]
}
}
That is not enough to distinguish 3.0.x from 3.1 beta.
When the seller returns the 3.1 shape unconditionally, the 3.0 storyboard runner (@adcp/sdk 7.10.2, schemas 3.0.12) fails on lifecycle status:
media_buy_seller/pending_creatives_to_start/create_buy_no_creatives:
Status is pending_creatives because no creatives supplied at /status
expected=pending_creatives actual=completed
The 3.1 beta runner (@adcp/sdk 8.1.0-beta.9, schemas 3.1.0-beta.3) no longer fails on that status/media_buy_status split.
Expected behavior
Python server/seller support should provide a standard version negotiation path:
- Resolve the buyer-requested AdCP version from request metadata/fields/headers using a single helper.
- Treat omitted version as legacy 3.0 compatibility, because 3.0 buyers predate exact 3.1 negotiation.
- Serialize create/update media-buy responses using top-level lifecycle
status for 3.0 buyers.
- Serialize create/update media-buy responses using envelope
status plus media_buy_status for 3.1 buyers.
- Advertise exact supported versions in capabilities if the 3.1 capability schema has a field for it, or add one if it does not.
Related JS runner issue
Filed the paired storyboard-runner issue here:
adcontextprotocol/adcp-client#1987
Summary
Python seller/server helpers should make 3.0/3.1 version compatibility automatic:
major_versions: [3], so buyers/storyboards can select the right contract.Why this matters
AdCP 3.1 beta splits protocol envelope status from media-buy lifecycle status. For example, create_media_buy in 3.1 should return:
{ "status": "completed", "media_buy_status": "pending_creatives" }Legacy 3.0 buyers/storyboards expect the media-buy lifecycle at top-level
status:{ "status": "pending_creatives" }If a seller always returns the 3.1 shape, 3.0 storyboards fail. If a seller always returns the 3.0 shape, 3.1 schemas fail. The server layer needs a consistent way to resolve the requested spec version and serialize the response accordingly.
Observed behavior
In a Sales Agent integration using Python SDK
adcp==6.1.0b2:Capabilities exposed to the JS storyboard runner contain only:
{ "adcp": { "major_versions": [3] } }That is not enough to distinguish 3.0.x from 3.1 beta.
When the seller returns the 3.1 shape unconditionally, the 3.0 storyboard runner (
@adcp/sdk 7.10.2, schemas3.0.12) fails on lifecycle status:The 3.1 beta runner (
@adcp/sdk 8.1.0-beta.9, schemas3.1.0-beta.3) no longer fails on that status/media_buy_status split.Expected behavior
Python server/seller support should provide a standard version negotiation path:
statusfor 3.0 buyers.statusplusmedia_buy_statusfor 3.1 buyers.Related JS runner issue
Filed the paired storyboard-runner issue here:
adcontextprotocol/adcp-client#1987