Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions src/a2a_server/adcp_a2a_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1362,12 +1362,12 @@ async def _handle_create_media_buy_skill(self, parameters: dict, auth_token: str
"""Handle explicit create_media_buy skill invocation.

IMPORTANT: This handler ONLY accepts AdCP spec-compliant format:
- packages[] (required)
- budget{} (required)
- packages[] (required) - each package must have budget
- brand_manifest (required)
- start_time (required)
- end_time (required)
- promoted_offering (required)

Per AdCP v2.2.0 spec, budget is specified at the PACKAGE level, not top level.
Legacy format (product_ids, total_budget, start_date, end_date) is NOT supported.
"""
try:
Expand All @@ -1377,11 +1377,10 @@ async def _handle_create_media_buy_skill(self, parameters: dict, auth_token: str
tool_name="create_media_buy",
)

# Validate AdCP spec required parameters
# Validate AdCP spec required parameters (per AdCP v2.2.0)
required_params = [
"brand_manifest",
"packages",
"budget",
"start_time",
"end_time",
]
Expand All @@ -1406,14 +1405,15 @@ async def _handle_create_media_buy_skill(self, parameters: dict, auth_token: str
}

# Call core function with AdCP spec-compliant parameters
# Note: budget is NOT passed at top level per AdCP v2.2.0 - it's in packages
response = await core_create_media_buy_tool(
brand_manifest=parameters["brand_manifest"],
po_number=parameters.get("po_number", f"A2A-{uuid.uuid4().hex[:8]}"),
buyer_ref=parameters.get("buyer_ref", f"A2A-{tool_context.principal_id}"),
packages=parameters["packages"],
start_time=parameters["start_time"],
end_time=parameters["end_time"],
budget=parameters["budget"],
budget=parameters.get("budget"), # Optional legacy field - ignored if provided
targeting_overlay=parameters.get("custom_targeting", {}),
push_notification_config=parameters.get("push_notification_config"),
context=self._tool_context_to_mcp_context(tool_context),
Expand Down Expand Up @@ -2134,20 +2134,22 @@ async def _create_media_buy(self, request: str, auth_token: str | None) -> dict:

return {
"success": False,
"message": f"Authentication successful for {tool_context.principal_id}. To create a media buy, use explicit skill invocation with AdCP v2.4 spec-compliant format.",
"required_fields": ["promoted_offering", "packages", "budget", "start_time", "end_time"],
"message": f"Authentication successful for {tool_context.principal_id}. To create a media buy, use explicit skill invocation with AdCP v2.2.0 spec-compliant format.",
"required_fields": ["brand_manifest", "packages", "start_time", "end_time"],
"note": "Per AdCP v2.2.0 spec, budget is specified at the PACKAGE level, not top level",
"authenticated_tenant": tool_context.tenant_id,
"authenticated_principal": tool_context.principal_id,
"example": {
"promoted_offering": "https://example.com/product",
"brand_manifest": "https://example.com/brand-manifest.json",
"packages": [
{
"buyer_ref": "pkg_1",
"products": ["video_premium"],
"budget": {"total": 10000, "currency": "USD"},
"product_id": "video_premium",
"budget": 10000.0, # Budget is per package (required)
"pricing_option_id": "cpm-fixed",
}
],
"budget": {"total": 10000, "currency": "USD"},
# Note: NO top-level budget field per AdCP v2.2.0 spec
"start_time": "2025-02-01T00:00:00Z",
"end_time": "2025-02-28T23:59:59Z",
},
Expand Down
4 changes: 2 additions & 2 deletions src/core/tools/media_buy_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -1200,7 +1200,7 @@ async def _create_media_buy_impl(
packages: Array of packages with products and budgets (REQUIRED)
start_time: Campaign start time ISO 8601 or 'asap' (REQUIRED)
end_time: Campaign end time ISO 8601 (REQUIRED)
budget: Overall campaign budget (REQUIRED)
budget: DEPRECATED - Budget is at package level only per AdCP v2.2.0 (ignored if provided)
po_number: Purchase order number (optional)
product_ids: Legacy: Product IDs (converted to packages)
start_date: Legacy: Start date (converted to start_time)
Expand Down Expand Up @@ -3314,7 +3314,7 @@ async def create_media_buy_raw(
packages: List of media packages (REQUIRED)
start_time: Campaign start time ISO 8601 or 'asap' (REQUIRED)
end_time: Campaign end time ISO 8601 (REQUIRED)
budget: Overall campaign budget (REQUIRED)
budget: DEPRECATED - Budget is at package level only per AdCP v2.2.0 (ignored if provided)
po_number: Purchase order number (optional)
product_ids: Legacy: Product IDs (converted to packages)
total_budget: Legacy: Total budget (converted to Budget object)
Expand Down