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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
128 changes: 127 additions & 1 deletion SCHEMA_DELTAS.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions examples/minimal_sales_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ async def create_media_buy(
return CreateMediaBuySuccessResponse(
media_buy_id=media_buy_id,
buyer_ref=buyer_ref,
confirmed_at="2026-05-01T00:00:00Z",
revision=1,
packages=confirmed_packages,
).model_dump(mode="json", exclude_none=True)

Expand Down
11 changes: 10 additions & 1 deletion examples/sales_proposal_mode_seller/src/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class _MediaBuy:
total_budget: float
start_time: datetime
end_time: datetime
confirmed_at: str
revision: int = 1
status: str = "active"
recipes_seen: dict[str, str] | None = None # product_id -> line_item_template_id

Expand Down Expand Up @@ -139,6 +141,7 @@ def create_media_buy(
total_budget = float(_dotted(req, "total_budget.amount", 0.0) or 0.0)
start_time = _read_datetime(getattr(req, "start_time", None))
end_time = _read_datetime(getattr(req, "end_time", None))
confirmed_at = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")

with self._lock:
self._buys[media_buy_id] = _MediaBuy(
Expand All @@ -147,6 +150,7 @@ def create_media_buy(
total_budget=total_budget,
start_time=start_time,
end_time=end_time,
confirmed_at=confirmed_at,
recipes_seen=recipes_seen,
)

Expand All @@ -156,7 +160,8 @@ def create_media_buy(
"media_buy_id": media_buy_id,
"buyer_ref": getattr(req, "buyer_ref", None),
"status": "active",
"confirmed_at": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
"confirmed_at": confirmed_at,
"revision": 1,
"proposal_id": str(proposal_id) if proposal_id else None,
"packages": [
{
Expand Down Expand Up @@ -203,10 +208,12 @@ def update_media_buy(
),
recovery="terminal",
)
buy.revision += 1
return {
"media_buy_id": media_buy_id,
"buyer_ref": buy.proposal_id,
"status": buy.status,
"revision": buy.revision,
"packages": [],
}

Expand Down Expand Up @@ -269,6 +276,8 @@ def get_media_buys(self, req: Any, ctx: RequestContext[Any]) -> dict[str, Any]:
"media_buy_id": b.media_buy_id,
"status": b.status,
"buyer_ref": b.proposal_id,
"confirmed_at": b.confirmed_at,
"revision": b.revision,
"packages": [],
}
for b in buys
Expand Down
12 changes: 11 additions & 1 deletion examples/seller_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -619,10 +619,12 @@ async def create_media_buy(self, params: dict[str, Any], context: Any = None) ->
status = "active" if has_creatives else "pending_creatives"

mb_id = f"mb-{uuid.uuid4().hex[:8]}"
confirmed_at = _now_z()
media_buys[mb_id] = {
"status": status,
"currency": "USD",
"packages": packages,
"confirmed_at": confirmed_at,
"revision": 1,
}
# Pull valid_actions from the SDK's authoritative state machine —
Expand All @@ -631,6 +633,8 @@ async def create_media_buy(self, params: dict[str, Any], context: Any = None) ->
mb_id,
packages,
status=status,
revision=1,
confirmed_at=confirmed_at,
valid_actions=valid_actions_for_status(status) or None,
)

Expand All @@ -645,6 +649,8 @@ async def get_media_buys(self, params: dict[str, Any], context: Any = None) -> d
{
"media_buy_id": mb_id,
"status": mb["status"],
"confirmed_at": mb.get("confirmed_at") or _now_z(),
"revision": mb.get("revision", 1),
"currency": mb.get("currency", "USD"),
"packages": mb.get("packages", []),
"total_budget": total_budget,
Expand Down Expand Up @@ -710,7 +716,8 @@ async def update_media_buy(self, params: dict[str, Any], context: Any = None) ->
if status in ("completed", "rejected", "canceled"):
return adcp_error("NOT_CANCELLABLE", f"Cannot cancel a {status} media buy")
mb["status"] = "canceled"
return cancel_media_buy_response(mb_id, "buyer")
mb["revision"] = mb.get("revision", 1) + 1
return cancel_media_buy_response(mb_id, "buyer", revision=mb["revision"])

mb["revision"] = mb.get("revision", 1) + 1
return update_media_buy_response(
Expand Down Expand Up @@ -797,6 +804,7 @@ async def sync_creatives(self, params: dict[str, Any], context: Any = None) -> d
if mb.get("status") == "pending_creatives":
mb["status"] = "pending_start"
mb["revision"] = mb.get("revision", 1) + 1
mb.setdefault("confirmed_at", _now_z())
return sync_creatives_response(results)

async def list_creatives(self, params: dict[str, Any], context: Any = None) -> dict[str, Any]:
Expand Down Expand Up @@ -1138,6 +1146,8 @@ async def seed_media_buy(
data.setdefault("status", "active")
data.setdefault("currency", "USD")
data.setdefault("packages", [])
data.setdefault("confirmed_at", _now_z())
data.setdefault("revision", 1)
media_buys[mb_id] = data
return {"media_buy_id": mb_id}

Expand Down
2 changes: 2 additions & 0 deletions examples/type_aliases_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ def handle_create_media_buy_response(
success = CreateMediaBuySuccessResponse(
media_buy_id="mb_12345",
buyer_ref="ref_67890",
confirmed_at="2026-05-01T00:00:00Z",
revision=1,
packages=[],
)
handle_create_media_buy_response(success)
Expand Down
13 changes: 13 additions & 0 deletions examples/v3_reference_seller/src/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@
logger = logging.getLogger(__name__)


def _order_confirmed_at(order: dict[str, Any]) -> str:
"""Return a wire timestamp for the buy confirmation moment."""
value = order.get("confirmed_at") or order.get("updated_at") or order.get("created_at")
if value is not None:
return str(value)
return datetime.now(timezone.utc).isoformat()


# ---------------------------------------------------------------------------
# AccountStore — explicit (wire ref drives lookup)
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -1193,6 +1201,7 @@ async def _project_create_success(
wire_status = "pending_creatives"
order_id = order["order_id"]
buy_state = self._buy_state.setdefault(order_id, {"packages": {}, "canceled": False})
revision = self._buy_revisions.setdefault(order_id, 1)
response_packages: list[dict[str, Any]] = []
for idx, pkg in enumerate(req_packages):
line_item = await upstream_helpers.add_line_item(
Expand All @@ -1217,6 +1226,8 @@ async def _project_create_success(
{
"media_buy_id": order_id,
"status": wire_status,
"confirmed_at": _order_confirmed_at(order),
"revision": revision,
"packages": response_packages,
"invoice_recipient": (
invoice_recipient.model_dump(mode="json", exclude_none=True)
Expand Down Expand Up @@ -1676,6 +1687,8 @@ async def get_media_buys(
{
"media_buy_id": order_id,
"status": wire_status,
"confirmed_at": _order_confirmed_at(order),
"revision": self._buy_revisions.setdefault(order_id, 1),
"currency": order.get("currency", "USD"),
"total_budget": float(order.get("budget", 0.0)),
"packages": packages,
Expand Down
80 changes: 80 additions & 0 deletions schemas/cache/3.1.0-beta.7/a2ui/bound-value.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "A2UI Bound Value",
"description": "A value that can be a literal or bound to a path in the data model",
"oneOf": [
{
"type": "object",
"description": "Literal string value",
"properties": {
"literalString": {
"type": "string",
"description": "Static string value"
}
},
"required": [
"literalString"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Literal number value",
"properties": {
"literalNumber": {
"type": "number",
"description": "Static number value"
}
},
"required": [
"literalNumber"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Literal boolean value",
"properties": {
"literalBoolean": {
"type": "boolean",
"description": "Static boolean value"
}
},
"required": [
"literalBoolean"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Path to data model value",
"properties": {
"path": {
"type": "string",
"description": "JSON pointer path to value in data model (e.g., '/products/0/title')"
}
},
"required": [
"path"
],
"additionalProperties": false
},
{
"type": "object",
"description": "Literal with path binding (sets default and binds)",
"properties": {
"literalString": {
"type": "string"
},
"path": {
"type": "string"
}
},
"required": [
"literalString",
"path"
],
"additionalProperties": false
}
]
}
31 changes: 31 additions & 0 deletions schemas/cache/3.1.0-beta.7/a2ui/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "A2UI Component",
"description": "A component in an A2UI surface",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for this component within the surface"
},
"parentId": {
"type": "string",
"description": "ID of the parent component (null for root)"
},
"component": {
"type": "object",
"description": "Component definition (keyed by component type)",
"minProperties": 1,
"maxProperties": 1,
"additionalProperties": {
"type": "object",
"description": "Component properties"
}
}
},
"required": [
"id",
"component"
],
"additionalProperties": true
}
Loading
Loading