adcp 2.12.0__py3-none-any.whl
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.
- adcp/__init__.py +364 -0
- adcp/__main__.py +440 -0
- adcp/adagents.py +642 -0
- adcp/client.py +1057 -0
- adcp/config.py +82 -0
- adcp/exceptions.py +185 -0
- adcp/protocols/__init__.py +9 -0
- adcp/protocols/a2a.py +484 -0
- adcp/protocols/base.py +190 -0
- adcp/protocols/mcp.py +440 -0
- adcp/py.typed +0 -0
- adcp/simple.py +451 -0
- adcp/testing/__init__.py +53 -0
- adcp/testing/test_helpers.py +311 -0
- adcp/types/__init__.py +561 -0
- adcp/types/_generated.py +237 -0
- adcp/types/aliases.py +748 -0
- adcp/types/base.py +26 -0
- adcp/types/core.py +174 -0
- adcp/types/generated_poc/__init__.py +3 -0
- adcp/types/generated_poc/adagents.py +411 -0
- adcp/types/generated_poc/core/__init__.py +3 -0
- adcp/types/generated_poc/core/activation_key.py +30 -0
- adcp/types/generated_poc/core/assets/__init__.py +3 -0
- adcp/types/generated_poc/core/assets/audio_asset.py +26 -0
- adcp/types/generated_poc/core/assets/css_asset.py +20 -0
- adcp/types/generated_poc/core/assets/daast_asset.py +61 -0
- adcp/types/generated_poc/core/assets/html_asset.py +18 -0
- adcp/types/generated_poc/core/assets/image_asset.py +19 -0
- adcp/types/generated_poc/core/assets/javascript_asset.py +23 -0
- adcp/types/generated_poc/core/assets/text_asset.py +20 -0
- adcp/types/generated_poc/core/assets/url_asset.py +28 -0
- adcp/types/generated_poc/core/assets/vast_asset.py +63 -0
- adcp/types/generated_poc/core/assets/video_asset.py +24 -0
- adcp/types/generated_poc/core/assets/webhook_asset.py +53 -0
- adcp/types/generated_poc/core/brand_manifest.py +201 -0
- adcp/types/generated_poc/core/context.py +15 -0
- adcp/types/generated_poc/core/creative_asset.py +102 -0
- adcp/types/generated_poc/core/creative_assignment.py +27 -0
- adcp/types/generated_poc/core/creative_filters.py +86 -0
- adcp/types/generated_poc/core/creative_manifest.py +68 -0
- adcp/types/generated_poc/core/creative_policy.py +28 -0
- adcp/types/generated_poc/core/delivery_metrics.py +111 -0
- adcp/types/generated_poc/core/deployment.py +78 -0
- adcp/types/generated_poc/core/destination.py +43 -0
- adcp/types/generated_poc/core/dimensions.py +18 -0
- adcp/types/generated_poc/core/error.py +29 -0
- adcp/types/generated_poc/core/ext.py +15 -0
- adcp/types/generated_poc/core/format.py +260 -0
- adcp/types/generated_poc/core/format_id.py +50 -0
- adcp/types/generated_poc/core/frequency_cap.py +19 -0
- adcp/types/generated_poc/core/measurement.py +40 -0
- adcp/types/generated_poc/core/media_buy.py +40 -0
- adcp/types/generated_poc/core/package.py +68 -0
- adcp/types/generated_poc/core/performance_feedback.py +78 -0
- adcp/types/generated_poc/core/placement.py +37 -0
- adcp/types/generated_poc/core/product.py +164 -0
- adcp/types/generated_poc/core/product_filters.py +97 -0
- adcp/types/generated_poc/core/promoted_offerings.py +102 -0
- adcp/types/generated_poc/core/promoted_products.py +38 -0
- adcp/types/generated_poc/core/property.py +64 -0
- adcp/types/generated_poc/core/property_id.py +21 -0
- adcp/types/generated_poc/core/property_tag.py +21 -0
- adcp/types/generated_poc/core/protocol_envelope.py +61 -0
- adcp/types/generated_poc/core/publisher_property_selector.py +75 -0
- adcp/types/generated_poc/core/push_notification_config.py +51 -0
- adcp/types/generated_poc/core/reporting_capabilities.py +51 -0
- adcp/types/generated_poc/core/response.py +24 -0
- adcp/types/generated_poc/core/signal_filters.py +29 -0
- adcp/types/generated_poc/core/sub_asset.py +55 -0
- adcp/types/generated_poc/core/targeting.py +53 -0
- adcp/types/generated_poc/core/webhook_payload.py +96 -0
- adcp/types/generated_poc/creative/__init__.py +3 -0
- adcp/types/generated_poc/creative/list_creative_formats_request.py +88 -0
- adcp/types/generated_poc/creative/list_creative_formats_response.py +55 -0
- adcp/types/generated_poc/creative/preview_creative_request.py +153 -0
- adcp/types/generated_poc/creative/preview_creative_response.py +169 -0
- adcp/types/generated_poc/creative/preview_render.py +152 -0
- adcp/types/generated_poc/enums/__init__.py +3 -0
- adcp/types/generated_poc/enums/adcp_domain.py +12 -0
- adcp/types/generated_poc/enums/asset_content_type.py +23 -0
- adcp/types/generated_poc/enums/auth_scheme.py +12 -0
- adcp/types/generated_poc/enums/available_metric.py +19 -0
- adcp/types/generated_poc/enums/channels.py +19 -0
- adcp/types/generated_poc/enums/co_branding_requirement.py +13 -0
- adcp/types/generated_poc/enums/creative_action.py +15 -0
- adcp/types/generated_poc/enums/creative_agent_capability.py +14 -0
- adcp/types/generated_poc/enums/creative_sort_field.py +16 -0
- adcp/types/generated_poc/enums/creative_status.py +14 -0
- adcp/types/generated_poc/enums/daast_tracking_event.py +21 -0
- adcp/types/generated_poc/enums/daast_version.py +12 -0
- adcp/types/generated_poc/enums/delivery_type.py +12 -0
- adcp/types/generated_poc/enums/dimension_unit.py +14 -0
- adcp/types/generated_poc/enums/feed_format.py +13 -0
- adcp/types/generated_poc/enums/feedback_source.py +14 -0
- adcp/types/generated_poc/enums/format_category.py +17 -0
- adcp/types/generated_poc/enums/format_id_parameter.py +12 -0
- adcp/types/generated_poc/enums/frequency_cap_scope.py +16 -0
- adcp/types/generated_poc/enums/history_entry_type.py +12 -0
- adcp/types/generated_poc/enums/http_method.py +12 -0
- adcp/types/generated_poc/enums/identifier_types.py +29 -0
- adcp/types/generated_poc/enums/javascript_module_type.py +13 -0
- adcp/types/generated_poc/enums/landing_page_requirement.py +13 -0
- adcp/types/generated_poc/enums/markdown_flavor.py +12 -0
- adcp/types/generated_poc/enums/media_buy_status.py +14 -0
- adcp/types/generated_poc/enums/metric_type.py +18 -0
- adcp/types/generated_poc/enums/notification_type.py +14 -0
- adcp/types/generated_poc/enums/pacing.py +13 -0
- adcp/types/generated_poc/enums/preview_output_format.py +12 -0
- adcp/types/generated_poc/enums/pricing_model.py +17 -0
- adcp/types/generated_poc/enums/property_type.py +17 -0
- adcp/types/generated_poc/enums/publisher_identifier_types.py +15 -0
- adcp/types/generated_poc/enums/reporting_frequency.py +13 -0
- adcp/types/generated_poc/enums/signal_catalog_type.py +13 -0
- adcp/types/generated_poc/enums/sort_direction.py +12 -0
- adcp/types/generated_poc/enums/standard_format_ids.py +45 -0
- adcp/types/generated_poc/enums/task_status.py +19 -0
- adcp/types/generated_poc/enums/task_type.py +15 -0
- adcp/types/generated_poc/enums/update_frequency.py +14 -0
- adcp/types/generated_poc/enums/url_asset_type.py +13 -0
- adcp/types/generated_poc/enums/validation_mode.py +12 -0
- adcp/types/generated_poc/enums/vast_tracking_event.py +26 -0
- adcp/types/generated_poc/enums/vast_version.py +15 -0
- adcp/types/generated_poc/enums/webhook_response_type.py +14 -0
- adcp/types/generated_poc/enums/webhook_security_method.py +13 -0
- adcp/types/generated_poc/media_buy/__init__.py +3 -0
- adcp/types/generated_poc/media_buy/build_creative_request.py +41 -0
- adcp/types/generated_poc/media_buy/build_creative_response.py +51 -0
- adcp/types/generated_poc/media_buy/create_media_buy_request.py +94 -0
- adcp/types/generated_poc/media_buy/create_media_buy_response.py +56 -0
- adcp/types/generated_poc/media_buy/get_media_buy_delivery_request.py +47 -0
- adcp/types/generated_poc/media_buy/get_media_buy_delivery_response.py +235 -0
- adcp/types/generated_poc/media_buy/get_products_request.py +48 -0
- adcp/types/generated_poc/media_buy/get_products_response.py +28 -0
- adcp/types/generated_poc/media_buy/list_authorized_properties_request.py +38 -0
- adcp/types/generated_poc/media_buy/list_authorized_properties_response.py +84 -0
- adcp/types/generated_poc/media_buy/list_creative_formats_request.py +74 -0
- adcp/types/generated_poc/media_buy/list_creative_formats_response.py +56 -0
- adcp/types/generated_poc/media_buy/list_creatives_request.py +76 -0
- adcp/types/generated_poc/media_buy/list_creatives_response.py +214 -0
- adcp/types/generated_poc/media_buy/package_request.py +63 -0
- adcp/types/generated_poc/media_buy/provide_performance_feedback_request.py +125 -0
- adcp/types/generated_poc/media_buy/provide_performance_feedback_response.py +53 -0
- adcp/types/generated_poc/media_buy/sync_creatives_request.py +63 -0
- adcp/types/generated_poc/media_buy/sync_creatives_response.py +105 -0
- adcp/types/generated_poc/media_buy/update_media_buy_request.py +195 -0
- adcp/types/generated_poc/media_buy/update_media_buy_response.py +55 -0
- adcp/types/generated_poc/pricing_options/__init__.py +3 -0
- adcp/types/generated_poc/pricing_options/cpc_option.py +43 -0
- adcp/types/generated_poc/pricing_options/cpcv_option.py +45 -0
- adcp/types/generated_poc/pricing_options/cpm_auction_option.py +58 -0
- adcp/types/generated_poc/pricing_options/cpm_fixed_option.py +43 -0
- adcp/types/generated_poc/pricing_options/cpp_option.py +64 -0
- adcp/types/generated_poc/pricing_options/cpv_option.py +77 -0
- adcp/types/generated_poc/pricing_options/flat_rate_option.py +93 -0
- adcp/types/generated_poc/pricing_options/vcpm_auction_option.py +61 -0
- adcp/types/generated_poc/pricing_options/vcpm_fixed_option.py +47 -0
- adcp/types/generated_poc/protocols/__init__.py +3 -0
- adcp/types/generated_poc/protocols/adcp_extension.py +37 -0
- adcp/types/generated_poc/signals/__init__.py +3 -0
- adcp/types/generated_poc/signals/activate_signal_request.py +32 -0
- adcp/types/generated_poc/signals/activate_signal_response.py +51 -0
- adcp/types/generated_poc/signals/get_signals_request.py +53 -0
- adcp/types/generated_poc/signals/get_signals_response.py +59 -0
- adcp/utils/__init__.py +7 -0
- adcp/utils/operation_id.py +15 -0
- adcp/utils/preview_cache.py +491 -0
- adcp/utils/response_parser.py +171 -0
- adcp/validation.py +172 -0
- adcp-2.12.0.data/data/ADCP_VERSION +1 -0
- adcp-2.12.0.dist-info/METADATA +992 -0
- adcp-2.12.0.dist-info/RECORD +176 -0
- adcp-2.12.0.dist-info/WHEEL +5 -0
- adcp-2.12.0.dist-info/entry_points.txt +2 -0
- adcp-2.12.0.dist-info/licenses/LICENSE +17 -0
- adcp-2.12.0.dist-info/top_level.txt +1 -0
adcp/types/base.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""Base model for AdCP types with spec-compliant serialization."""
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AdCPBaseModel(BaseModel):
|
|
11
|
+
"""Base model for AdCP types with spec-compliant serialization.
|
|
12
|
+
|
|
13
|
+
AdCP JSON schemas use additionalProperties: false and do not allow null
|
|
14
|
+
for optional fields. Therefore, optional fields must be omitted entirely
|
|
15
|
+
when not present (not sent as null).
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def model_dump(self, **kwargs: Any) -> dict[str, Any]:
|
|
19
|
+
if "exclude_none" not in kwargs:
|
|
20
|
+
kwargs["exclude_none"] = True
|
|
21
|
+
return super().model_dump(**kwargs)
|
|
22
|
+
|
|
23
|
+
def model_dump_json(self, **kwargs: Any) -> str:
|
|
24
|
+
if "exclude_none" not in kwargs:
|
|
25
|
+
kwargs["exclude_none"] = True
|
|
26
|
+
return super().model_dump_json(**kwargs)
|
adcp/types/core.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""Core type definitions."""
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Any, Generic, Literal, TypeVar
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Protocol(str, Enum):
|
|
12
|
+
"""Supported protocols."""
|
|
13
|
+
|
|
14
|
+
A2A = "a2a"
|
|
15
|
+
MCP = "mcp"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AgentConfig(BaseModel):
|
|
19
|
+
"""Agent configuration."""
|
|
20
|
+
|
|
21
|
+
id: str
|
|
22
|
+
agent_uri: str
|
|
23
|
+
protocol: Protocol
|
|
24
|
+
auth_token: str | None = None
|
|
25
|
+
requires_auth: bool = False
|
|
26
|
+
auth_header: str = "x-adcp-auth" # Header name for authentication
|
|
27
|
+
auth_type: str = "token" # "token" for direct value, "bearer" for "Bearer {token}"
|
|
28
|
+
timeout: float = 30.0 # Request timeout in seconds
|
|
29
|
+
mcp_transport: str = (
|
|
30
|
+
"streamable_http" # "streamable_http" (default, modern) or "sse" (legacy fallback)
|
|
31
|
+
)
|
|
32
|
+
debug: bool = False # Enable debug mode to capture request/response details
|
|
33
|
+
|
|
34
|
+
@field_validator("agent_uri")
|
|
35
|
+
@classmethod
|
|
36
|
+
def validate_agent_uri(cls, v: str) -> str:
|
|
37
|
+
"""Validate agent URI format."""
|
|
38
|
+
if not v:
|
|
39
|
+
raise ValueError("agent_uri cannot be empty")
|
|
40
|
+
|
|
41
|
+
if not v.startswith(("http://", "https://")):
|
|
42
|
+
raise ValueError(
|
|
43
|
+
f"agent_uri must start with http:// or https://, got: {v}\n"
|
|
44
|
+
"Example: https://agent.example.com"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Remove trailing slash for consistency
|
|
48
|
+
return v.rstrip("/")
|
|
49
|
+
|
|
50
|
+
@field_validator("timeout")
|
|
51
|
+
@classmethod
|
|
52
|
+
def validate_timeout(cls, v: float) -> float:
|
|
53
|
+
"""Validate timeout is reasonable."""
|
|
54
|
+
if v <= 0:
|
|
55
|
+
raise ValueError(f"timeout must be positive, got: {v}")
|
|
56
|
+
|
|
57
|
+
if v > 300: # 5 minutes
|
|
58
|
+
raise ValueError(
|
|
59
|
+
f"timeout is very large ({v}s). Consider a value under 300 seconds.\n"
|
|
60
|
+
"Large timeouts can cause long hangs if agent is unresponsive."
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return v
|
|
64
|
+
|
|
65
|
+
@field_validator("mcp_transport")
|
|
66
|
+
@classmethod
|
|
67
|
+
def validate_mcp_transport(cls, v: str) -> str:
|
|
68
|
+
"""Validate MCP transport type."""
|
|
69
|
+
valid_transports = ["streamable_http", "sse"]
|
|
70
|
+
if v not in valid_transports:
|
|
71
|
+
raise ValueError(
|
|
72
|
+
f"mcp_transport must be one of {valid_transports}, got: {v}\n"
|
|
73
|
+
"Use 'streamable_http' for modern agents (recommended)"
|
|
74
|
+
)
|
|
75
|
+
return v
|
|
76
|
+
|
|
77
|
+
@field_validator("auth_type")
|
|
78
|
+
@classmethod
|
|
79
|
+
def validate_auth_type(cls, v: str) -> str:
|
|
80
|
+
"""Validate auth type."""
|
|
81
|
+
valid_types = ["token", "bearer"]
|
|
82
|
+
if v not in valid_types:
|
|
83
|
+
raise ValueError(
|
|
84
|
+
f"auth_type must be one of {valid_types}, got: {v}\n"
|
|
85
|
+
"Use 'bearer' for OAuth2/standard Authorization header"
|
|
86
|
+
)
|
|
87
|
+
return v
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class TaskStatus(str, Enum):
|
|
91
|
+
"""Task execution status."""
|
|
92
|
+
|
|
93
|
+
COMPLETED = "completed"
|
|
94
|
+
SUBMITTED = "submitted"
|
|
95
|
+
NEEDS_INPUT = "needs_input"
|
|
96
|
+
FAILED = "failed"
|
|
97
|
+
WORKING = "working"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
T = TypeVar("T")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class SubmittedInfo(BaseModel):
|
|
104
|
+
"""Information about submitted async task."""
|
|
105
|
+
|
|
106
|
+
webhook_url: str
|
|
107
|
+
operation_id: str
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class NeedsInputInfo(BaseModel):
|
|
111
|
+
"""Information when agent needs clarification."""
|
|
112
|
+
|
|
113
|
+
message: str
|
|
114
|
+
field: str | None = None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class DebugInfo(BaseModel):
|
|
118
|
+
"""Debug information for troubleshooting."""
|
|
119
|
+
|
|
120
|
+
request: dict[str, Any]
|
|
121
|
+
response: dict[str, Any]
|
|
122
|
+
duration_ms: float | None = None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TaskResult(BaseModel, Generic[T]):
|
|
126
|
+
"""Result from task execution."""
|
|
127
|
+
|
|
128
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
129
|
+
|
|
130
|
+
status: TaskStatus
|
|
131
|
+
data: T | None = None
|
|
132
|
+
message: str | None = None # Human-readable message from agent (e.g., MCP content text)
|
|
133
|
+
submitted: SubmittedInfo | None = None
|
|
134
|
+
needs_input: NeedsInputInfo | None = None
|
|
135
|
+
error: str | None = None
|
|
136
|
+
success: bool = Field(default=True)
|
|
137
|
+
metadata: dict[str, Any] | None = None
|
|
138
|
+
debug_info: DebugInfo | None = None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class ActivityType(str, Enum):
|
|
142
|
+
"""Types of activity events."""
|
|
143
|
+
|
|
144
|
+
PROTOCOL_REQUEST = "protocol_request"
|
|
145
|
+
PROTOCOL_RESPONSE = "protocol_response"
|
|
146
|
+
WEBHOOK_RECEIVED = "webhook_received"
|
|
147
|
+
HANDLER_CALLED = "handler_called"
|
|
148
|
+
STATUS_CHANGE = "status_change"
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class Activity(BaseModel):
|
|
152
|
+
"""Activity event for observability."""
|
|
153
|
+
|
|
154
|
+
model_config = {"frozen": True}
|
|
155
|
+
|
|
156
|
+
type: ActivityType
|
|
157
|
+
operation_id: str
|
|
158
|
+
agent_id: str
|
|
159
|
+
task_type: str
|
|
160
|
+
status: TaskStatus | None = None
|
|
161
|
+
timestamp: str
|
|
162
|
+
metadata: dict[str, Any] | None = None
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class WebhookMetadata(BaseModel):
|
|
166
|
+
"""Metadata passed to webhook handlers."""
|
|
167
|
+
|
|
168
|
+
operation_id: str
|
|
169
|
+
agent_id: str
|
|
170
|
+
task_type: str
|
|
171
|
+
status: TaskStatus
|
|
172
|
+
sequence_number: int | None = None
|
|
173
|
+
notification_type: Literal["scheduled", "final", "delayed"] | None = None
|
|
174
|
+
timestamp: str
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# generated by datamodel-codegen:
|
|
2
|
+
# filename: adagents.json
|
|
3
|
+
# timestamp: 2025-11-22T15:23:24+00:00
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Annotated, Literal
|
|
8
|
+
|
|
9
|
+
from adcp.types.base import AdCPBaseModel
|
|
10
|
+
from pydantic import AnyUrl, AwareDatetime, ConfigDict, EmailStr, Field, RootModel
|
|
11
|
+
|
|
12
|
+
from .core import property, property_id, property_tag, publisher_property_selector
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AuthorizedSalesAgents1(AdCPBaseModel):
|
|
16
|
+
model_config = ConfigDict(
|
|
17
|
+
extra='forbid',
|
|
18
|
+
)
|
|
19
|
+
field_schema: Annotated[
|
|
20
|
+
str | None,
|
|
21
|
+
Field(alias='$schema', description='JSON Schema identifier for this adagents.json file'),
|
|
22
|
+
] = 'https://adcontextprotocol.org/schemas/adagents.json'
|
|
23
|
+
authoritative_location: Annotated[
|
|
24
|
+
AnyUrl,
|
|
25
|
+
Field(
|
|
26
|
+
description='HTTPS URL of the authoritative adagents.json file. When present, this file is a reference and the authoritative location contains the actual agent authorization data.'
|
|
27
|
+
),
|
|
28
|
+
]
|
|
29
|
+
last_updated: Annotated[
|
|
30
|
+
AwareDatetime | None,
|
|
31
|
+
Field(description='ISO 8601 timestamp indicating when this reference was last updated'),
|
|
32
|
+
] = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Contact(AdCPBaseModel):
|
|
36
|
+
model_config = ConfigDict(
|
|
37
|
+
extra='forbid',
|
|
38
|
+
)
|
|
39
|
+
domain: Annotated[
|
|
40
|
+
str | None,
|
|
41
|
+
Field(
|
|
42
|
+
description='Primary domain of the entity managing this file',
|
|
43
|
+
pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$',
|
|
44
|
+
),
|
|
45
|
+
] = None
|
|
46
|
+
email: Annotated[
|
|
47
|
+
EmailStr | None,
|
|
48
|
+
Field(
|
|
49
|
+
description='Contact email for questions or issues with this authorization file',
|
|
50
|
+
max_length=255,
|
|
51
|
+
min_length=1,
|
|
52
|
+
),
|
|
53
|
+
] = None
|
|
54
|
+
name: Annotated[
|
|
55
|
+
str,
|
|
56
|
+
Field(
|
|
57
|
+
description="Name of the entity managing this file (e.g., 'Meta Advertising Operations', 'Clear Channel Digital')",
|
|
58
|
+
max_length=255,
|
|
59
|
+
min_length=1,
|
|
60
|
+
),
|
|
61
|
+
]
|
|
62
|
+
seller_id: Annotated[
|
|
63
|
+
str | None,
|
|
64
|
+
Field(
|
|
65
|
+
description='Seller ID from IAB Tech Lab sellers.json (if applicable)',
|
|
66
|
+
max_length=255,
|
|
67
|
+
min_length=1,
|
|
68
|
+
),
|
|
69
|
+
] = None
|
|
70
|
+
tag_id: Annotated[
|
|
71
|
+
str | None,
|
|
72
|
+
Field(
|
|
73
|
+
description='TAG Certified Against Fraud ID for verification (if applicable)',
|
|
74
|
+
max_length=100,
|
|
75
|
+
min_length=1,
|
|
76
|
+
),
|
|
77
|
+
] = None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Tags(AdCPBaseModel):
|
|
81
|
+
model_config = ConfigDict(
|
|
82
|
+
extra='forbid',
|
|
83
|
+
)
|
|
84
|
+
description: Annotated[str, Field(description='Description of what this tag represents')]
|
|
85
|
+
name: Annotated[str, Field(description='Human-readable name for this tag')]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class AuthorizedAgents(AdCPBaseModel):
|
|
89
|
+
model_config = ConfigDict(
|
|
90
|
+
extra='forbid',
|
|
91
|
+
)
|
|
92
|
+
authorization_type: Annotated[
|
|
93
|
+
Literal['property_ids'],
|
|
94
|
+
Field(description='Discriminator indicating authorization by specific property IDs'),
|
|
95
|
+
]
|
|
96
|
+
authorized_for: Annotated[
|
|
97
|
+
str,
|
|
98
|
+
Field(
|
|
99
|
+
description='Human-readable description of what this agent is authorized to sell',
|
|
100
|
+
max_length=500,
|
|
101
|
+
min_length=1,
|
|
102
|
+
),
|
|
103
|
+
]
|
|
104
|
+
property_ids: Annotated[
|
|
105
|
+
list[property_id.PropertyId],
|
|
106
|
+
Field(
|
|
107
|
+
description='Property IDs this agent is authorized for. Resolved against the top-level properties array in this file',
|
|
108
|
+
min_length=1,
|
|
109
|
+
),
|
|
110
|
+
]
|
|
111
|
+
url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class AuthorizedAgents1(AdCPBaseModel):
|
|
115
|
+
model_config = ConfigDict(
|
|
116
|
+
extra='forbid',
|
|
117
|
+
)
|
|
118
|
+
authorization_type: Annotated[
|
|
119
|
+
Literal['property_tags'],
|
|
120
|
+
Field(description='Discriminator indicating authorization by property tags'),
|
|
121
|
+
]
|
|
122
|
+
authorized_for: Annotated[
|
|
123
|
+
str,
|
|
124
|
+
Field(
|
|
125
|
+
description='Human-readable description of what this agent is authorized to sell',
|
|
126
|
+
max_length=500,
|
|
127
|
+
min_length=1,
|
|
128
|
+
),
|
|
129
|
+
]
|
|
130
|
+
property_tags: Annotated[
|
|
131
|
+
list[property_tag.PropertyTag],
|
|
132
|
+
Field(
|
|
133
|
+
description='Tags identifying which properties this agent is authorized for. Resolved against the top-level properties array in this file using tag matching',
|
|
134
|
+
min_length=1,
|
|
135
|
+
),
|
|
136
|
+
]
|
|
137
|
+
url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class AuthorizedAgents3(AdCPBaseModel):
|
|
141
|
+
model_config = ConfigDict(
|
|
142
|
+
extra='forbid',
|
|
143
|
+
)
|
|
144
|
+
authorization_type: Annotated[
|
|
145
|
+
Literal['publisher_properties'],
|
|
146
|
+
Field(
|
|
147
|
+
description='Discriminator indicating authorization for properties from other publisher domains'
|
|
148
|
+
),
|
|
149
|
+
]
|
|
150
|
+
authorized_for: Annotated[
|
|
151
|
+
str,
|
|
152
|
+
Field(
|
|
153
|
+
description='Human-readable description of what this agent is authorized to sell',
|
|
154
|
+
max_length=500,
|
|
155
|
+
min_length=1,
|
|
156
|
+
),
|
|
157
|
+
]
|
|
158
|
+
publisher_properties: Annotated[
|
|
159
|
+
list[
|
|
160
|
+
publisher_property_selector.PublisherPropertySelector1
|
|
161
|
+
| publisher_property_selector.PublisherPropertySelector2
|
|
162
|
+
| publisher_property_selector.PublisherPropertySelector3
|
|
163
|
+
],
|
|
164
|
+
Field(
|
|
165
|
+
description='Properties from other publisher domains this agent is authorized for. Each entry specifies a publisher domain and which of their properties this agent can sell',
|
|
166
|
+
min_length=1,
|
|
167
|
+
),
|
|
168
|
+
]
|
|
169
|
+
url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")]
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class AuthorizedAgents2(AdCPBaseModel):
|
|
173
|
+
model_config = ConfigDict(
|
|
174
|
+
extra='forbid',
|
|
175
|
+
)
|
|
176
|
+
authorization_type: Annotated[
|
|
177
|
+
Literal['inline_properties'],
|
|
178
|
+
Field(description='Discriminator indicating authorization by inline property definitions'),
|
|
179
|
+
]
|
|
180
|
+
authorized_for: Annotated[
|
|
181
|
+
str,
|
|
182
|
+
Field(
|
|
183
|
+
description='Human-readable description of what this agent is authorized to sell',
|
|
184
|
+
max_length=500,
|
|
185
|
+
min_length=1,
|
|
186
|
+
),
|
|
187
|
+
]
|
|
188
|
+
properties: Annotated[
|
|
189
|
+
list[property.Property],
|
|
190
|
+
Field(
|
|
191
|
+
description='Specific properties this agent is authorized for (alternative to property_ids/property_tags)',
|
|
192
|
+
min_length=1,
|
|
193
|
+
),
|
|
194
|
+
]
|
|
195
|
+
url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")]
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class AuthorizedSalesAgents2(AdCPBaseModel):
|
|
199
|
+
model_config = ConfigDict(
|
|
200
|
+
extra='forbid',
|
|
201
|
+
)
|
|
202
|
+
field_schema: Annotated[
|
|
203
|
+
str | None,
|
|
204
|
+
Field(alias='$schema', description='JSON Schema identifier for this adagents.json file'),
|
|
205
|
+
] = 'https://adcontextprotocol.org/schemas/adagents.json'
|
|
206
|
+
authorized_agents: Annotated[
|
|
207
|
+
list[AuthorizedAgents | AuthorizedAgents1 | AuthorizedAgents2 | AuthorizedAgents3],
|
|
208
|
+
Field(
|
|
209
|
+
description='Array of sales agents authorized to sell inventory for properties in this file',
|
|
210
|
+
min_length=1,
|
|
211
|
+
),
|
|
212
|
+
]
|
|
213
|
+
contact: Annotated[
|
|
214
|
+
Contact | None,
|
|
215
|
+
Field(
|
|
216
|
+
description='Contact information for the entity managing this adagents.json file (may be publisher or third-party operator)'
|
|
217
|
+
),
|
|
218
|
+
] = None
|
|
219
|
+
last_updated: Annotated[
|
|
220
|
+
AwareDatetime | None,
|
|
221
|
+
Field(description='ISO 8601 timestamp indicating when this file was last updated'),
|
|
222
|
+
] = None
|
|
223
|
+
properties: Annotated[
|
|
224
|
+
list[property.Property] | None,
|
|
225
|
+
Field(
|
|
226
|
+
description='Array of all properties covered by this adagents.json file. Defines the canonical property list that authorized agents reference.',
|
|
227
|
+
min_length=1,
|
|
228
|
+
),
|
|
229
|
+
] = None
|
|
230
|
+
tags: Annotated[
|
|
231
|
+
dict[str, Tags] | None,
|
|
232
|
+
Field(
|
|
233
|
+
description='Metadata for each tag referenced by properties. Provides human-readable context for property tag values.'
|
|
234
|
+
),
|
|
235
|
+
] = None
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class AuthorizedSalesAgents(RootModel[AuthorizedSalesAgents1 | AuthorizedSalesAgents2]):
|
|
239
|
+
root: Annotated[
|
|
240
|
+
AuthorizedSalesAgents1 | AuthorizedSalesAgents2,
|
|
241
|
+
Field(
|
|
242
|
+
description='Declaration of authorized sales agents for advertising inventory. Hosted at /.well-known/adagents.json on publisher domains. Can either contain the full structure inline or reference an authoritative URL.',
|
|
243
|
+
examples=[
|
|
244
|
+
{
|
|
245
|
+
'$schema': 'https://adcontextprotocol.org/schemas/adagents.json',
|
|
246
|
+
'authoritative_location': 'https://cdn.example.com/adagents/v2/adagents.json',
|
|
247
|
+
'last_updated': '2025-01-15T10:00:00Z',
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
'$schema': 'https://adcontextprotocol.org/schemas/adagents.json',
|
|
251
|
+
'authorized_agents': [
|
|
252
|
+
{
|
|
253
|
+
'authorization_type': 'property_tags',
|
|
254
|
+
'authorized_for': 'Official sales agent',
|
|
255
|
+
'property_tags': ['all'],
|
|
256
|
+
'url': 'https://agent.example.com',
|
|
257
|
+
}
|
|
258
|
+
],
|
|
259
|
+
'last_updated': '2025-01-10T12:00:00Z',
|
|
260
|
+
'properties': [
|
|
261
|
+
{
|
|
262
|
+
'identifiers': [{'type': 'domain', 'value': 'example.com'}],
|
|
263
|
+
'name': 'Example Site',
|
|
264
|
+
'property_type': 'website',
|
|
265
|
+
'publisher_domain': 'example.com',
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
'tags': {
|
|
269
|
+
'all': {
|
|
270
|
+
'description': 'All properties in this file',
|
|
271
|
+
'name': 'All Properties',
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
'$schema': 'https://adcontextprotocol.org/schemas/adagents.json',
|
|
277
|
+
'authorized_agents': [
|
|
278
|
+
{
|
|
279
|
+
'authorization_type': 'property_tags',
|
|
280
|
+
'authorized_for': 'All Meta properties',
|
|
281
|
+
'property_tags': ['meta_network'],
|
|
282
|
+
'url': 'https://meta-ads.com',
|
|
283
|
+
}
|
|
284
|
+
],
|
|
285
|
+
'contact': {
|
|
286
|
+
'domain': 'meta.com',
|
|
287
|
+
'email': 'adops@meta.com',
|
|
288
|
+
'name': 'Meta Advertising Operations',
|
|
289
|
+
'seller_id': 'pub-meta-12345',
|
|
290
|
+
'tag_id': '12345',
|
|
291
|
+
},
|
|
292
|
+
'last_updated': '2025-01-10T15:30:00Z',
|
|
293
|
+
'properties': [
|
|
294
|
+
{
|
|
295
|
+
'identifiers': [
|
|
296
|
+
{'type': 'ios_bundle', 'value': 'com.burbn.instagram'},
|
|
297
|
+
{'type': 'android_package', 'value': 'com.instagram.android'},
|
|
298
|
+
],
|
|
299
|
+
'name': 'Instagram',
|
|
300
|
+
'property_type': 'mobile_app',
|
|
301
|
+
'publisher_domain': 'instagram.com',
|
|
302
|
+
'tags': ['meta_network', 'social_media'],
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
'identifiers': [
|
|
306
|
+
{'type': 'ios_bundle', 'value': 'com.facebook.Facebook'},
|
|
307
|
+
{'type': 'android_package', 'value': 'com.facebook.katana'},
|
|
308
|
+
],
|
|
309
|
+
'name': 'Facebook',
|
|
310
|
+
'property_type': 'mobile_app',
|
|
311
|
+
'publisher_domain': 'facebook.com',
|
|
312
|
+
'tags': ['meta_network', 'social_media'],
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
'identifiers': [
|
|
316
|
+
{'type': 'ios_bundle', 'value': 'net.whatsapp.WhatsApp'},
|
|
317
|
+
{'type': 'android_package', 'value': 'com.whatsapp'},
|
|
318
|
+
],
|
|
319
|
+
'name': 'WhatsApp',
|
|
320
|
+
'property_type': 'mobile_app',
|
|
321
|
+
'publisher_domain': 'whatsapp.com',
|
|
322
|
+
'tags': ['meta_network', 'messaging'],
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
'tags': {
|
|
326
|
+
'messaging': {
|
|
327
|
+
'description': 'Messaging and communication apps',
|
|
328
|
+
'name': 'Messaging Apps',
|
|
329
|
+
},
|
|
330
|
+
'meta_network': {
|
|
331
|
+
'description': 'All Meta-owned properties',
|
|
332
|
+
'name': 'Meta Network',
|
|
333
|
+
},
|
|
334
|
+
'social_media': {
|
|
335
|
+
'description': 'Social networking applications',
|
|
336
|
+
'name': 'Social Media Apps',
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
'$schema': 'https://adcontextprotocol.org/schemas/adagents.json',
|
|
342
|
+
'authorized_agents': [
|
|
343
|
+
{
|
|
344
|
+
'authorization_type': 'property_tags',
|
|
345
|
+
'authorized_for': 'Tumblr corporate properties only',
|
|
346
|
+
'property_tags': ['corporate'],
|
|
347
|
+
'url': 'https://tumblr-sales.com',
|
|
348
|
+
}
|
|
349
|
+
],
|
|
350
|
+
'contact': {'name': 'Tumblr Advertising'},
|
|
351
|
+
'last_updated': '2025-01-10T16:00:00Z',
|
|
352
|
+
'properties': [
|
|
353
|
+
{
|
|
354
|
+
'identifiers': [{'type': 'domain', 'value': 'tumblr.com'}],
|
|
355
|
+
'name': 'Tumblr Corporate',
|
|
356
|
+
'property_type': 'website',
|
|
357
|
+
'publisher_domain': 'tumblr.com',
|
|
358
|
+
'tags': ['corporate'],
|
|
359
|
+
}
|
|
360
|
+
],
|
|
361
|
+
'tags': {
|
|
362
|
+
'corporate': {
|
|
363
|
+
'description': 'Tumblr-owned corporate properties (not user blogs)',
|
|
364
|
+
'name': 'Corporate Properties',
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
'$schema': 'https://adcontextprotocol.org/schemas/adagents.json',
|
|
370
|
+
'authorized_agents': [
|
|
371
|
+
{
|
|
372
|
+
'authorization_type': 'publisher_properties',
|
|
373
|
+
'authorized_for': 'CNN CTV properties via publisher authorization',
|
|
374
|
+
'publisher_properties': [
|
|
375
|
+
{
|
|
376
|
+
'property_ids': ['cnn_ctv_app'],
|
|
377
|
+
'publisher_domain': 'cnn.com',
|
|
378
|
+
'selection_type': 'by_id',
|
|
379
|
+
}
|
|
380
|
+
],
|
|
381
|
+
'url': 'https://agent.example/api',
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
'authorization_type': 'publisher_properties',
|
|
385
|
+
'authorized_for': 'All CTV properties from multiple publishers',
|
|
386
|
+
'publisher_properties': [
|
|
387
|
+
{
|
|
388
|
+
'property_tags': ['ctv'],
|
|
389
|
+
'publisher_domain': 'cnn.com',
|
|
390
|
+
'selection_type': 'by_tag',
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
'property_tags': ['ctv'],
|
|
394
|
+
'publisher_domain': 'espn.com',
|
|
395
|
+
'selection_type': 'by_tag',
|
|
396
|
+
},
|
|
397
|
+
],
|
|
398
|
+
'url': 'https://agent.example/api',
|
|
399
|
+
},
|
|
400
|
+
],
|
|
401
|
+
'contact': {
|
|
402
|
+
'domain': 'agent.example',
|
|
403
|
+
'email': 'sales@agent.example',
|
|
404
|
+
'name': 'Example Third-Party Sales Agent',
|
|
405
|
+
},
|
|
406
|
+
'last_updated': '2025-01-10T17:00:00Z',
|
|
407
|
+
},
|
|
408
|
+
],
|
|
409
|
+
title='Authorized Sales Agents',
|
|
410
|
+
),
|
|
411
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# generated by datamodel-codegen:
|
|
2
|
+
# filename: core/activation_key.json
|
|
3
|
+
# timestamp: 2025-11-22T15:23:24+00:00
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Annotated, Literal
|
|
8
|
+
|
|
9
|
+
from adcp.types.base import AdCPBaseModel
|
|
10
|
+
from pydantic import ConfigDict, Field
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ActivationKey1(AdCPBaseModel):
|
|
14
|
+
model_config = ConfigDict(
|
|
15
|
+
extra='forbid',
|
|
16
|
+
)
|
|
17
|
+
segment_id: Annotated[
|
|
18
|
+
str,
|
|
19
|
+
Field(description='The platform-specific segment identifier to use in campaign targeting'),
|
|
20
|
+
]
|
|
21
|
+
type: Annotated[Literal['segment_id'], Field(description='Segment ID based targeting')]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ActivationKey2(AdCPBaseModel):
|
|
25
|
+
model_config = ConfigDict(
|
|
26
|
+
extra='forbid',
|
|
27
|
+
)
|
|
28
|
+
key: Annotated[str, Field(description='The targeting parameter key')]
|
|
29
|
+
type: Annotated[Literal['key_value'], Field(description='Key-value pair based targeting')]
|
|
30
|
+
value: Annotated[str, Field(description='The targeting parameter value')]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# generated by datamodel-codegen:
|
|
2
|
+
# filename: core/assets/audio_asset.json
|
|
3
|
+
# timestamp: 2025-11-22T15:23:24+00:00
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
from adcp.types.base import AdCPBaseModel
|
|
10
|
+
from pydantic import AnyUrl, ConfigDict, Field
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AudioAsset(AdCPBaseModel):
|
|
14
|
+
model_config = ConfigDict(
|
|
15
|
+
extra='forbid',
|
|
16
|
+
)
|
|
17
|
+
bitrate_kbps: Annotated[
|
|
18
|
+
int | None, Field(description='Audio bitrate in kilobits per second', ge=1)
|
|
19
|
+
] = None
|
|
20
|
+
duration_ms: Annotated[
|
|
21
|
+
int | None, Field(description='Audio duration in milliseconds', ge=0)
|
|
22
|
+
] = None
|
|
23
|
+
format: Annotated[str | None, Field(description='Audio file format (mp3, wav, aac, etc.)')] = (
|
|
24
|
+
None
|
|
25
|
+
)
|
|
26
|
+
url: Annotated[AnyUrl, Field(description='URL to the audio asset')]
|