adcp 1.6.1__tar.gz → 2.1.0__tar.gz

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.
Files changed (154) hide show
  1. {adcp-1.6.1/src/adcp.egg-info → adcp-2.1.0}/PKG-INFO +42 -3
  2. {adcp-1.6.1 → adcp-2.1.0}/README.md +39 -2
  3. {adcp-1.6.1 → adcp-2.1.0}/pyproject.toml +17 -2
  4. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/__init__.py +110 -189
  5. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/adagents.py +11 -12
  6. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/client.py +16 -11
  7. adcp-2.1.0/src/adcp/py.typed +0 -0
  8. adcp-2.1.0/src/adcp/types/aliases.py +209 -0
  9. adcp-2.1.0/src/adcp/types/generated.py +614 -0
  10. adcp-2.1.0/src/adcp/types/generated_poc/__init__.py +3 -0
  11. adcp-2.1.0/src/adcp/types/generated_poc/activate_signal_request.py +34 -0
  12. adcp-2.1.0/src/adcp/types/generated_poc/activate_signal_response.py +57 -0
  13. adcp-2.1.0/src/adcp/types/generated_poc/activation_key.py +30 -0
  14. adcp-2.1.0/src/adcp/types/generated_poc/adagents.py +266 -0
  15. adcp-2.1.0/src/adcp/types/generated_poc/asset_type.py +100 -0
  16. adcp-2.1.0/src/adcp/types/generated_poc/audio_asset.py +26 -0
  17. adcp-2.1.0/src/adcp/types/generated_poc/brand_manifest.py +260 -0
  18. adcp-2.1.0/src/adcp/types/generated_poc/brand_manifest_ref.py +361 -0
  19. adcp-2.1.0/src/adcp/types/generated_poc/build_creative_request.py +43 -0
  20. adcp-2.1.0/src/adcp/types/generated_poc/build_creative_response.py +57 -0
  21. adcp-2.1.0/src/adcp/types/generated_poc/channels.py +19 -0
  22. adcp-2.1.0/src/adcp/types/generated_poc/cpc_option.py +39 -0
  23. adcp-2.1.0/src/adcp/types/generated_poc/cpcv_option.py +41 -0
  24. adcp-2.1.0/src/adcp/types/generated_poc/cpm_auction_option.py +54 -0
  25. adcp-2.1.0/src/adcp/types/generated_poc/cpm_fixed_option.py +39 -0
  26. adcp-2.1.0/src/adcp/types/generated_poc/cpp_option.py +60 -0
  27. adcp-2.1.0/src/adcp/types/generated_poc/cpv_option.py +73 -0
  28. adcp-2.1.0/src/adcp/types/generated_poc/create_media_buy_request.py +96 -0
  29. adcp-2.1.0/src/adcp/types/generated_poc/create_media_buy_response.py +66 -0
  30. adcp-2.1.0/src/adcp/types/generated_poc/creative_asset.py +83 -0
  31. adcp-2.1.0/src/adcp/types/generated_poc/creative_assignment.py +27 -0
  32. adcp-2.1.0/src/adcp/types/generated_poc/creative_manifest.py +61 -0
  33. adcp-2.1.0/src/adcp/types/generated_poc/creative_policy.py +34 -0
  34. adcp-2.1.0/src/adcp/types/generated_poc/creative_status.py +14 -0
  35. adcp-2.1.0/src/adcp/types/generated_poc/css_asset.py +20 -0
  36. adcp-2.1.0/src/adcp/types/generated_poc/daast_asset.py +76 -0
  37. adcp-2.1.0/src/adcp/types/generated_poc/delivery_metrics.py +111 -0
  38. adcp-2.1.0/src/adcp/types/generated_poc/delivery_type.py +12 -0
  39. adcp-2.1.0/src/adcp/types/generated_poc/deployment.py +78 -0
  40. adcp-2.1.0/src/adcp/types/generated_poc/destination.py +43 -0
  41. adcp-2.1.0/src/adcp/types/generated_poc/error.py +29 -0
  42. adcp-2.1.0/src/adcp/types/generated_poc/flat_rate_option.py +93 -0
  43. adcp-2.1.0/src/adcp/types/generated_poc/format.py +260 -0
  44. adcp-2.1.0/src/adcp/types/generated_poc/format_id.py +29 -0
  45. adcp-2.1.0/src/adcp/types/generated_poc/frequency_cap.py +19 -0
  46. adcp-2.1.0/src/adcp/types/generated_poc/frequency_cap_scope.py +16 -0
  47. adcp-2.1.0/src/adcp/types/generated_poc/get_media_buy_delivery_request.py +65 -0
  48. adcp-2.1.0/src/adcp/types/generated_poc/get_media_buy_delivery_response.py +220 -0
  49. adcp-2.1.0/src/adcp/types/generated_poc/get_products_request.py +83 -0
  50. adcp-2.1.0/src/adcp/types/generated_poc/get_products_response.py +29 -0
  51. adcp-2.1.0/src/adcp/types/generated_poc/get_signals_request.py +77 -0
  52. adcp-2.1.0/src/adcp/types/generated_poc/get_signals_response.py +65 -0
  53. adcp-2.1.0/src/adcp/types/generated_poc/html_asset.py +18 -0
  54. adcp-2.1.0/src/adcp/types/generated_poc/identifier_types.py +29 -0
  55. adcp-2.1.0/src/adcp/types/generated_poc/image_asset.py +23 -0
  56. adcp-2.1.0/src/adcp/types/generated_poc/index.py +17 -0
  57. adcp-2.1.0/src/adcp/types/generated_poc/javascript_asset.py +25 -0
  58. adcp-2.1.0/src/adcp/types/generated_poc/list_authorized_properties_request.py +39 -0
  59. adcp-2.1.0/src/adcp/types/generated_poc/list_authorized_properties_response.py +85 -0
  60. adcp-2.1.0/src/adcp/types/generated_poc/list_creative_formats_request.py +93 -0
  61. adcp-2.1.0/src/adcp/types/generated_poc/list_creative_formats_response.py +63 -0
  62. adcp-2.1.0/src/adcp/types/generated_poc/list_creatives_request.py +154 -0
  63. adcp-2.1.0/src/adcp/types/generated_poc/list_creatives_response.py +234 -0
  64. adcp-2.1.0/src/adcp/types/generated_poc/markdown_asset.py +43 -0
  65. adcp-2.1.0/src/adcp/types/generated_poc/measurement.py +40 -0
  66. adcp-2.1.0/src/adcp/types/generated_poc/media_buy.py +37 -0
  67. adcp-2.1.0/src/adcp/types/generated_poc/media_buy_status.py +14 -0
  68. adcp-2.1.0/src/adcp/types/generated_poc/pacing.py +13 -0
  69. adcp-2.1.0/src/adcp/types/generated_poc/package.py +61 -0
  70. adcp-2.1.0/src/adcp/types/generated_poc/package_request.py +61 -0
  71. adcp-2.1.0/src/adcp/types/generated_poc/package_status.py +14 -0
  72. adcp-2.1.0/src/adcp/types/generated_poc/performance_feedback.py +89 -0
  73. adcp-2.1.0/src/adcp/types/generated_poc/placement.py +37 -0
  74. adcp-2.1.0/src/adcp/types/generated_poc/preview_creative_request.py +163 -0
  75. adcp-2.1.0/src/adcp/types/generated_poc/preview_creative_response.py +175 -0
  76. adcp-2.1.0/src/adcp/types/generated_poc/preview_render.py +144 -0
  77. adcp-2.1.0/src/adcp/types/generated_poc/pricing_model.py +17 -0
  78. adcp-2.1.0/src/adcp/types/generated_poc/pricing_option.py +365 -0
  79. adcp-2.1.0/src/adcp/types/generated_poc/product.py +211 -0
  80. adcp-2.1.0/src/adcp/types/generated_poc/promoted_offerings.py +102 -0
  81. adcp-2.1.0/src/adcp/types/generated_poc/promoted_products.py +38 -0
  82. adcp-2.1.0/src/adcp/types/generated_poc/property.py +79 -0
  83. adcp-2.1.0/src/adcp/types/generated_poc/protocol_envelope.py +61 -0
  84. adcp-2.1.0/src/adcp/types/generated_poc/provide_performance_feedback_request.py +85 -0
  85. adcp-2.1.0/src/adcp/types/generated_poc/provide_performance_feedback_response.py +59 -0
  86. adcp-2.1.0/src/adcp/types/generated_poc/publisher_identifier_types.py +15 -0
  87. adcp-2.1.0/src/adcp/types/generated_poc/push_notification_config.py +55 -0
  88. adcp-2.1.0/src/adcp/types/generated_poc/reporting_capabilities.py +68 -0
  89. adcp-2.1.0/src/adcp/types/generated_poc/response.py +24 -0
  90. adcp-2.1.0/src/adcp/types/generated_poc/standard_format_ids.py +45 -0
  91. adcp-2.1.0/src/adcp/types/generated_poc/start_timing.py +13 -0
  92. adcp-2.1.0/src/adcp/types/generated_poc/sub_asset.py +55 -0
  93. adcp-2.1.0/src/adcp/types/generated_poc/sync_creatives_request.py +69 -0
  94. adcp-2.1.0/src/adcp/types/generated_poc/sync_creatives_response.py +117 -0
  95. adcp-2.1.0/src/adcp/types/generated_poc/targeting.py +53 -0
  96. adcp-2.1.0/src/adcp/types/generated_poc/task_status.py +19 -0
  97. adcp-2.1.0/src/adcp/types/generated_poc/task_type.py +15 -0
  98. adcp-2.1.0/src/adcp/types/generated_poc/tasks_get_request.py +29 -0
  99. adcp-2.1.0/src/adcp/types/generated_poc/tasks_get_response.py +112 -0
  100. adcp-2.1.0/src/adcp/types/generated_poc/tasks_list_request.py +121 -0
  101. adcp-2.1.0/src/adcp/types/generated_poc/tasks_list_response.py +122 -0
  102. adcp-2.1.0/src/adcp/types/generated_poc/text_asset.py +20 -0
  103. adcp-2.1.0/src/adcp/types/generated_poc/update_media_buy_request.py +160 -0
  104. adcp-2.1.0/src/adcp/types/generated_poc/update_media_buy_response.py +67 -0
  105. adcp-2.1.0/src/adcp/types/generated_poc/url_asset.py +33 -0
  106. adcp-2.1.0/src/adcp/types/generated_poc/vast_asset.py +86 -0
  107. adcp-2.1.0/src/adcp/types/generated_poc/vcpm_auction_option.py +57 -0
  108. adcp-2.1.0/src/adcp/types/generated_poc/vcpm_fixed_option.py +43 -0
  109. adcp-2.1.0/src/adcp/types/generated_poc/video_asset.py +28 -0
  110. adcp-2.1.0/src/adcp/types/generated_poc/webhook_asset.py +65 -0
  111. adcp-2.1.0/src/adcp/types/generated_poc/webhook_payload.py +102 -0
  112. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/utils/preview_cache.py +54 -41
  113. adcp-2.1.0/src/adcp/validation.py +172 -0
  114. {adcp-1.6.1 → adcp-2.1.0/src/adcp.egg-info}/PKG-INFO +42 -3
  115. adcp-2.1.0/src/adcp.egg-info/SOURCES.txt +147 -0
  116. {adcp-1.6.1 → adcp-2.1.0}/src/adcp.egg-info/requires.txt +2 -0
  117. {adcp-1.6.1 → adcp-2.1.0}/tests/test_adagents.py +58 -18
  118. {adcp-1.6.1 → adcp-2.1.0}/tests/test_client.py +19 -2
  119. adcp-2.1.0/tests/test_code_generation.py +64 -0
  120. adcp-2.1.0/tests/test_discriminated_unions.py +450 -0
  121. {adcp-1.6.1 → adcp-2.1.0}/tests/test_format_id_validation.py +5 -6
  122. {adcp-1.6.1 → adcp-2.1.0}/tests/test_preview_html.py +123 -56
  123. {adcp-1.6.1 → adcp-2.1.0}/tests/test_protocols.py +3 -1
  124. {adcp-1.6.1 → adcp-2.1.0}/tests/test_simple_api.py +30 -7
  125. adcp-2.1.0/tests/test_type_aliases.py +179 -0
  126. adcp-1.6.1/src/adcp/types/generated.py +0 -1208
  127. adcp-1.6.1/src/adcp/types/tasks.py +0 -511
  128. adcp-1.6.1/src/adcp.egg-info/SOURCES.txt +0 -42
  129. adcp-1.6.1/tests/test_code_generation.py +0 -400
  130. adcp-1.6.1/tests/test_discriminated_unions.py +0 -404
  131. {adcp-1.6.1 → adcp-2.1.0}/LICENSE +0 -0
  132. {adcp-1.6.1 → adcp-2.1.0}/setup.cfg +0 -0
  133. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/__main__.py +0 -0
  134. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/config.py +0 -0
  135. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/exceptions.py +0 -0
  136. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/protocols/__init__.py +0 -0
  137. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/protocols/a2a.py +0 -0
  138. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/protocols/base.py +0 -0
  139. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/protocols/mcp.py +0 -0
  140. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/simple.py +0 -0
  141. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/testing/__init__.py +0 -0
  142. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/testing/test_helpers.py +0 -0
  143. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/types/__init__.py +0 -0
  144. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/types/base.py +0 -0
  145. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/types/core.py +0 -0
  146. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/utils/__init__.py +0 -0
  147. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/utils/operation_id.py +0 -0
  148. {adcp-1.6.1 → adcp-2.1.0}/src/adcp/utils/response_parser.py +0 -0
  149. {adcp-1.6.1 → adcp-2.1.0}/src/adcp.egg-info/dependency_links.txt +0 -0
  150. {adcp-1.6.1 → adcp-2.1.0}/src/adcp.egg-info/entry_points.txt +0 -0
  151. {adcp-1.6.1 → adcp-2.1.0}/src/adcp.egg-info/top_level.txt +0 -0
  152. {adcp-1.6.1 → adcp-2.1.0}/tests/test_cli.py +0 -0
  153. {adcp-1.6.1 → adcp-2.1.0}/tests/test_helpers.py +0 -0
  154. {adcp-1.6.1 → adcp-2.1.0}/tests/test_response_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: adcp
3
- Version: 1.6.1
3
+ Version: 2.1.0
4
4
  Summary: Official Python client for the Ad Context Protocol (AdCP)
5
5
  Author-email: AdCP Community <maintainers@adcontextprotocol.org>
6
6
  License: Apache-2.0
@@ -33,6 +33,8 @@ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
33
33
  Requires-Dist: mypy>=1.0.0; extra == "dev"
34
34
  Requires-Dist: black>=23.0.0; extra == "dev"
35
35
  Requires-Dist: ruff>=0.1.0; extra == "dev"
36
+ Requires-Dist: datamodel-code-generator[http]>=0.35.0; extra == "dev"
37
+ Requires-Dist: email-validator>=2.0.0; extra == "dev"
36
38
  Dynamic: license-file
37
39
 
38
40
  # adcp - Python Client for Ad Context Protocol
@@ -92,7 +94,7 @@ print(products.products[0].name)
92
94
  **Standard API** (`client.*`) - Recommended for production:
93
95
  ```python
94
96
  from adcp.testing import test_agent
95
- from adcp.types.generated import GetProductsRequest
97
+ from adcp import GetProductsRequest
96
98
 
97
99
  # Explicit request objects and TaskResult wrapper
98
100
  request = GetProductsRequest(brief='Coffee brands')
@@ -122,6 +124,8 @@ Pre-configured agents (all include `.simple` accessor):
122
124
 
123
125
  See [examples/simple_api_demo.py](examples/simple_api_demo.py) for a complete comparison.
124
126
 
127
+ > **Tip**: Import types from the main `adcp` package (e.g., `from adcp import GetProductsRequest`) rather than `adcp.types.generated` for better API stability.
128
+
125
129
  ## Quick Start: Distributed Operations
126
130
 
127
131
  For production use, configure your own agents:
@@ -185,7 +189,7 @@ from adcp.testing import (
185
189
  test_agent_no_auth, test_agent_a2a_no_auth,
186
190
  creative_agent, test_agent_client, create_test_agent
187
191
  )
188
- from adcp.types.generated import GetProductsRequest, PreviewCreativeRequest
192
+ from adcp import GetProductsRequest, PreviewCreativeRequest
189
193
 
190
194
  # 1. Single agent with authentication (MCP)
191
195
  result = await test_agent.get_products(
@@ -241,6 +245,7 @@ client = ADCPClient(config)
241
245
  - **Auto-detection**: Automatically detect which protocol an agent uses
242
246
 
243
247
  ### Type Safety
248
+
244
249
  Full type hints with Pydantic validation and auto-generated types from the AdCP spec:
245
250
 
246
251
  ```python
@@ -256,6 +261,40 @@ if result.success:
256
261
  print(product.name, product.pricing_options) # Full IDE autocomplete!
257
262
  ```
258
263
 
264
+ #### Semantic Type Aliases
265
+
266
+ For discriminated union types (success/error responses), use semantic aliases for clearer code:
267
+
268
+ ```python
269
+ from adcp import (
270
+ CreateMediaBuySuccessResponse, # Clear: this is the success case
271
+ CreateMediaBuyErrorResponse, # Clear: this is the error case
272
+ )
273
+
274
+ def handle_response(
275
+ response: CreateMediaBuySuccessResponse | CreateMediaBuyErrorResponse
276
+ ) -> None:
277
+ if isinstance(response, CreateMediaBuySuccessResponse):
278
+ print(f"✅ Media buy created: {response.media_buy_id}")
279
+ else:
280
+ print(f"❌ Errors: {response.errors}")
281
+ ```
282
+
283
+ **Available semantic aliases:**
284
+ - Response types: `*SuccessResponse` / `*ErrorResponse` (e.g., `CreateMediaBuySuccessResponse`)
285
+ - Request variants: `*FormatRequest` / `*ManifestRequest` (e.g., `PreviewCreativeFormatRequest`)
286
+ - Preview renders: `PreviewRenderImage` / `PreviewRenderHtml` / `PreviewRenderIframe`
287
+ - Activation keys: `PropertyIdActivationKey` / `PropertyTagActivationKey`
288
+
289
+ See `examples/type_aliases_demo.py` for more examples.
290
+
291
+ **Import guidelines:**
292
+ - ✅ **DO**: Import from main package: `from adcp import GetProductsRequest`
293
+ - ✅ **DO**: Use semantic aliases: `from adcp import CreateMediaBuySuccessResponse`
294
+ - ⚠️ **AVOID**: Import from internal modules: `from adcp.types.generated import CreateMediaBuyResponse1`
295
+
296
+ The main package exports provide a stable API while internal generated types may change.
297
+
259
298
  ### Multi-Agent Operations
260
299
  Execute across multiple agents simultaneously:
261
300
 
@@ -55,7 +55,7 @@ print(products.products[0].name)
55
55
  **Standard API** (`client.*`) - Recommended for production:
56
56
  ```python
57
57
  from adcp.testing import test_agent
58
- from adcp.types.generated import GetProductsRequest
58
+ from adcp import GetProductsRequest
59
59
 
60
60
  # Explicit request objects and TaskResult wrapper
61
61
  request = GetProductsRequest(brief='Coffee brands')
@@ -85,6 +85,8 @@ Pre-configured agents (all include `.simple` accessor):
85
85
 
86
86
  See [examples/simple_api_demo.py](examples/simple_api_demo.py) for a complete comparison.
87
87
 
88
+ > **Tip**: Import types from the main `adcp` package (e.g., `from adcp import GetProductsRequest`) rather than `adcp.types.generated` for better API stability.
89
+
88
90
  ## Quick Start: Distributed Operations
89
91
 
90
92
  For production use, configure your own agents:
@@ -148,7 +150,7 @@ from adcp.testing import (
148
150
  test_agent_no_auth, test_agent_a2a_no_auth,
149
151
  creative_agent, test_agent_client, create_test_agent
150
152
  )
151
- from adcp.types.generated import GetProductsRequest, PreviewCreativeRequest
153
+ from adcp import GetProductsRequest, PreviewCreativeRequest
152
154
 
153
155
  # 1. Single agent with authentication (MCP)
154
156
  result = await test_agent.get_products(
@@ -204,6 +206,7 @@ client = ADCPClient(config)
204
206
  - **Auto-detection**: Automatically detect which protocol an agent uses
205
207
 
206
208
  ### Type Safety
209
+
207
210
  Full type hints with Pydantic validation and auto-generated types from the AdCP spec:
208
211
 
209
212
  ```python
@@ -219,6 +222,40 @@ if result.success:
219
222
  print(product.name, product.pricing_options) # Full IDE autocomplete!
220
223
  ```
221
224
 
225
+ #### Semantic Type Aliases
226
+
227
+ For discriminated union types (success/error responses), use semantic aliases for clearer code:
228
+
229
+ ```python
230
+ from adcp import (
231
+ CreateMediaBuySuccessResponse, # Clear: this is the success case
232
+ CreateMediaBuyErrorResponse, # Clear: this is the error case
233
+ )
234
+
235
+ def handle_response(
236
+ response: CreateMediaBuySuccessResponse | CreateMediaBuyErrorResponse
237
+ ) -> None:
238
+ if isinstance(response, CreateMediaBuySuccessResponse):
239
+ print(f"✅ Media buy created: {response.media_buy_id}")
240
+ else:
241
+ print(f"❌ Errors: {response.errors}")
242
+ ```
243
+
244
+ **Available semantic aliases:**
245
+ - Response types: `*SuccessResponse` / `*ErrorResponse` (e.g., `CreateMediaBuySuccessResponse`)
246
+ - Request variants: `*FormatRequest` / `*ManifestRequest` (e.g., `PreviewCreativeFormatRequest`)
247
+ - Preview renders: `PreviewRenderImage` / `PreviewRenderHtml` / `PreviewRenderIframe`
248
+ - Activation keys: `PropertyIdActivationKey` / `PropertyTagActivationKey`
249
+
250
+ See `examples/type_aliases_demo.py` for more examples.
251
+
252
+ **Import guidelines:**
253
+ - ✅ **DO**: Import from main package: `from adcp import GetProductsRequest`
254
+ - ✅ **DO**: Use semantic aliases: `from adcp import CreateMediaBuySuccessResponse`
255
+ - ⚠️ **AVOID**: Import from internal modules: `from adcp.types.generated import CreateMediaBuyResponse1`
256
+
257
+ The main package exports provide a stable API while internal generated types may change.
258
+
222
259
  ### Multi-Agent Operations
223
260
  Execute across multiple agents simultaneously:
224
261
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "adcp"
7
- version = "1.6.1"
7
+ version = "2.1.0"
8
8
  description = "Official Python client for the Ad Context Protocol (AdCP)"
9
9
  authors = [
10
10
  {name = "AdCP Community", email = "maintainers@adcontextprotocol.org"}
@@ -44,6 +44,8 @@ dev = [
44
44
  "mypy>=1.0.0",
45
45
  "black>=23.0.0",
46
46
  "ruff>=0.1.0",
47
+ "datamodel-code-generator[http]>=0.35.0",
48
+ "email-validator>=2.0.0",
47
49
  ]
48
50
 
49
51
  [project.urls]
@@ -55,6 +57,9 @@ Issues = "https://github.com/adcontextprotocol/adcp-client-python/issues"
55
57
  [tool.setuptools.packages.find]
56
58
  where = ["src"]
57
59
 
60
+ [tool.setuptools.package-data]
61
+ adcp = ["py.typed"]
62
+
58
63
  [tool.black]
59
64
  line-length = 100
60
65
  target-version = ["py310", "py311", "py312"]
@@ -63,7 +68,11 @@ extend-exclude = "/(generated|tasks)\\.py$"
63
68
  [tool.ruff]
64
69
  line-length = 100
65
70
  target-version = "py310"
66
- extend-exclude = ["src/adcp/types/generated.py", "src/adcp/types/tasks.py"]
71
+ extend-exclude = [
72
+ "src/adcp/types/generated.py",
73
+ "src/adcp/types/tasks.py",
74
+ "src/adcp/types/generated_poc/",
75
+ ]
67
76
 
68
77
  [tool.ruff.lint]
69
78
  select = ["E", "F", "I", "N", "W", "UP"]
@@ -86,3 +95,9 @@ ignore_errors = true
86
95
  [tool.pytest.ini_options]
87
96
  testpaths = ["tests"]
88
97
  asyncio_mode = "auto"
98
+
99
+ [dependency-groups]
100
+ dev = [
101
+ "datamodel-code-generator>=0.35.0",
102
+ "pre-commit>=4.4.0",
103
+ ]
@@ -48,122 +48,87 @@ from adcp.testing import (
48
48
  test_agent_client,
49
49
  test_agent_no_auth,
50
50
  )
51
+
52
+ # Import all generated types - users can import what they need from adcp.types.generated
53
+ from adcp.types import aliases, generated
54
+
55
+ # Re-export semantic type aliases for better ergonomics
56
+ from adcp.types.aliases import (
57
+ ActivateSignalErrorResponse,
58
+ ActivateSignalSuccessResponse,
59
+ BuildCreativeErrorResponse,
60
+ BuildCreativeSuccessResponse,
61
+ CreateMediaBuyErrorResponse,
62
+ CreateMediaBuySuccessResponse,
63
+ PreviewCreativeFormatRequest,
64
+ PreviewCreativeInteractiveResponse,
65
+ PreviewCreativeManifestRequest,
66
+ PreviewCreativeStaticResponse,
67
+ PreviewRenderHtml,
68
+ PreviewRenderIframe,
69
+ PreviewRenderImage,
70
+ PropertyIdActivationKey,
71
+ PropertyTagActivationKey,
72
+ ProvidePerformanceFeedbackErrorResponse,
73
+ ProvidePerformanceFeedbackSuccessResponse,
74
+ SyncCreativesErrorResponse,
75
+ SyncCreativesSuccessResponse,
76
+ UpdateMediaBuyErrorResponse,
77
+ UpdateMediaBuyPackagesRequest,
78
+ UpdateMediaBuyPropertiesRequest,
79
+ UpdateMediaBuySuccessResponse,
80
+ )
51
81
  from adcp.types.core import AgentConfig, Protocol, TaskResult, TaskStatus, WebhookMetadata
82
+
83
+ # Re-export commonly-used request/response types for convenience
84
+ # Users should import from main package (e.g., `from adcp import GetProductsRequest`)
85
+ # rather than internal modules for better API stability
52
86
  from adcp.types.generated import (
53
- ActivateSignalError,
54
- # Request/Response types
87
+ # Audience & Targeting
55
88
  ActivateSignalRequest,
56
89
  ActivateSignalResponse,
57
- ActivateSignalSuccess,
58
- ActivationKey,
59
- AgentDeployment,
60
- AgentDestination,
61
- BothPreviewRender,
62
- # Brand types
63
- BrandManifest,
64
- BrandManifestRef,
90
+ # Creative Operations
65
91
  BuildCreativeRequest,
66
92
  BuildCreativeResponse,
67
- # Channel types
68
- Channels,
69
- CreateMediaBuyError,
93
+ # Media Buy Operations
70
94
  CreateMediaBuyRequest,
71
95
  CreateMediaBuyResponse,
72
- CreateMediaBuySuccess,
73
- # Creative types
74
- CreativeAsset,
75
- CreativeAssignment,
76
- CreativeManifest,
77
- CreativePolicy,
78
- DaastAsset,
79
- # Metrics types
80
- DeliveryMetrics,
81
- # Delivery types
82
- DeliveryType,
83
- Deployment,
84
- # Deployment types
85
- Destination,
96
+ # Common data types
86
97
  Error,
87
98
  Format,
88
- FormatId,
89
- FrequencyCap,
90
99
  GetMediaBuyDeliveryRequest,
91
100
  GetMediaBuyDeliveryResponse,
92
101
  GetProductsRequest,
93
102
  GetProductsResponse,
94
103
  GetSignalsRequest,
95
104
  GetSignalsResponse,
96
- HtmlPreviewRender,
97
- InlineDaastAsset,
98
- InlineVastAsset,
99
- Key_valueActivationKey,
100
105
  ListAuthorizedPropertiesRequest,
101
106
  ListAuthorizedPropertiesResponse,
102
107
  ListCreativeFormatsRequest,
103
108
  ListCreativeFormatsResponse,
104
109
  ListCreativesRequest,
105
110
  ListCreativesResponse,
106
- Measurement,
107
- # Core domain types
108
- MediaBuy,
109
- # Status enums
110
- MediaBuyStatus,
111
- # Sub-asset types
112
- MediaSubAsset,
113
- Pacing,
114
- Package,
115
- PackageStatus,
116
- PerformanceFeedback,
117
- Placement,
118
- PlatformDeployment,
119
- PlatformDestination,
120
111
  PreviewCreativeRequest,
121
112
  PreviewCreativeResponse,
122
- # Preview render types
123
- PreviewRender,
124
- PricingModel,
125
- # Pricing types
126
- PricingOption,
127
113
  Product,
128
- PromotedProducts,
129
- # Property and placement types
130
114
  Property,
131
- ProtocolEnvelope,
132
115
  ProvidePerformanceFeedbackRequest,
133
116
  ProvidePerformanceFeedbackResponse,
134
- PushNotificationConfig,
135
- ReportingCapabilities,
136
- Response,
137
- Segment_idActivationKey,
138
- StandardFormatIds,
139
- StartTiming,
140
- SubAsset,
141
- SyncCreativesError,
142
117
  SyncCreativesRequest,
143
118
  SyncCreativesResponse,
144
- SyncCreativesSuccess,
145
- # Targeting types
146
- Targeting,
147
- # Task types
148
- TaskType,
149
- TextSubAsset,
150
- UpdateMediaBuyError,
151
119
  UpdateMediaBuyRequest,
152
120
  UpdateMediaBuyResponse,
153
- UpdateMediaBuySuccess,
154
- UrlDaastAsset,
155
- UrlPreviewRender,
156
- UrlVastAsset,
157
- # Asset delivery types (VAST/DAAST)
158
- VastAsset,
159
- # Protocol types
160
- WebhookPayload,
161
121
  )
162
- from adcp.types.generated import (
163
- TaskStatus as GeneratedTaskStatus,
122
+ from adcp.types.generated import TaskStatus as GeneratedTaskStatus
123
+ from adcp.validation import (
124
+ ValidationError,
125
+ validate_adagents,
126
+ validate_agent_authorization,
127
+ validate_product,
128
+ validate_publisher_properties_item,
164
129
  )
165
130
 
166
- __version__ = "1.6.1"
131
+ __version__ = "2.1.0"
167
132
 
168
133
  __all__ = [
169
134
  # Client classes
@@ -175,6 +140,37 @@ __all__ = [
175
140
  "TaskResult",
176
141
  "TaskStatus",
177
142
  "WebhookMetadata",
143
+ # Common request/response types (re-exported for convenience)
144
+ "CreateMediaBuyRequest",
145
+ "CreateMediaBuyResponse",
146
+ "GetMediaBuyDeliveryRequest",
147
+ "GetMediaBuyDeliveryResponse",
148
+ "GetProductsRequest",
149
+ "GetProductsResponse",
150
+ "UpdateMediaBuyRequest",
151
+ "UpdateMediaBuyResponse",
152
+ "BuildCreativeRequest",
153
+ "BuildCreativeResponse",
154
+ "ListCreativeFormatsRequest",
155
+ "ListCreativeFormatsResponse",
156
+ "ListCreativesRequest",
157
+ "ListCreativesResponse",
158
+ "PreviewCreativeRequest",
159
+ "PreviewCreativeResponse",
160
+ "SyncCreativesRequest",
161
+ "SyncCreativesResponse",
162
+ "ActivateSignalRequest",
163
+ "ActivateSignalResponse",
164
+ "GetSignalsRequest",
165
+ "GetSignalsResponse",
166
+ "ListAuthorizedPropertiesRequest",
167
+ "ListAuthorizedPropertiesResponse",
168
+ "ProvidePerformanceFeedbackRequest",
169
+ "ProvidePerformanceFeedbackResponse",
170
+ "Error",
171
+ "Format",
172
+ "Product",
173
+ "Property",
178
174
  # Adagents validation
179
175
  "fetch_adagents",
180
176
  "verify_agent_authorization",
@@ -210,113 +206,38 @@ __all__ = [
210
206
  "AdagentsValidationError",
211
207
  "AdagentsNotFoundError",
212
208
  "AdagentsTimeoutError",
213
- # Request/Response types
214
- "ActivateSignalRequest",
215
- "ActivateSignalResponse",
216
- "ActivateSignalSuccess",
217
- "ActivateSignalError",
218
- "ActivationKey",
219
- "Segment_idActivationKey",
220
- "Key_valueActivationKey",
221
- "BuildCreativeRequest",
222
- "BuildCreativeResponse",
223
- "CreateMediaBuyRequest",
224
- "CreateMediaBuyResponse",
225
- "CreateMediaBuySuccess",
226
- "CreateMediaBuyError",
227
- "GetMediaBuyDeliveryRequest",
228
- "GetMediaBuyDeliveryResponse",
229
- "GetProductsRequest",
230
- "GetProductsResponse",
231
- "GetSignalsRequest",
232
- "GetSignalsResponse",
233
- "ListAuthorizedPropertiesRequest",
234
- "ListAuthorizedPropertiesResponse",
235
- "ListCreativeFormatsRequest",
236
- "ListCreativeFormatsResponse",
237
- "ListCreativesRequest",
238
- "ListCreativesResponse",
239
- "PreviewCreativeRequest",
240
- "PreviewCreativeResponse",
241
- "ProvidePerformanceFeedbackRequest",
242
- "ProvidePerformanceFeedbackResponse",
243
- "SyncCreativesRequest",
244
- "SyncCreativesResponse",
245
- "SyncCreativesSuccess",
246
- "SyncCreativesError",
247
- "UpdateMediaBuyRequest",
248
- "UpdateMediaBuyResponse",
249
- "UpdateMediaBuySuccess",
250
- "UpdateMediaBuyError",
251
- # Core domain types
252
- "MediaBuy",
253
- "Product",
254
- "Package",
255
- "Error",
256
- # Creative types
257
- "CreativeAsset",
258
- "CreativeManifest",
259
- "CreativeAssignment",
260
- "CreativePolicy",
261
- "Format",
262
- "FormatId",
263
- # Property and placement types
264
- "Property",
265
- "Placement",
266
- # Targeting types
267
- "Targeting",
268
- "FrequencyCap",
269
- "Pacing",
270
- # Brand types
271
- "BrandManifest",
272
- "BrandManifestRef",
273
- # Metrics types
274
- "DeliveryMetrics",
275
- "Measurement",
276
- "PerformanceFeedback",
277
- # Status enums
278
- "MediaBuyStatus",
279
- "PackageStatus",
280
- # Pricing types
281
- "PricingOption",
282
- "PricingModel",
283
- # Delivery types
284
- "DeliveryType",
285
- "StartTiming",
286
- # Channel types
287
- "Channels",
288
- "StandardFormatIds",
289
- # Protocol types
290
- "WebhookPayload",
291
- "ProtocolEnvelope",
292
- "Response",
293
- "PromotedProducts",
294
- "PushNotificationConfig",
295
- "ReportingCapabilities",
296
- # Deployment types
297
- "Destination",
298
- "Deployment",
299
- "PlatformDestination",
300
- "AgentDestination",
301
- "PlatformDeployment",
302
- "AgentDeployment",
303
- # Sub-asset types
304
- "MediaSubAsset",
305
- "SubAsset",
306
- "TextSubAsset",
307
- # Asset delivery types (VAST/DAAST)
308
- "VastAsset",
309
- "UrlVastAsset",
310
- "InlineVastAsset",
311
- "DaastAsset",
312
- "UrlDaastAsset",
313
- "InlineDaastAsset",
314
- # Preview render types
315
- "PreviewRender",
316
- "UrlPreviewRender",
317
- "HtmlPreviewRender",
318
- "BothPreviewRender",
319
- # Task types
320
- "TaskType",
209
+ # Validation utilities
210
+ "ValidationError",
211
+ "validate_adagents",
212
+ "validate_agent_authorization",
213
+ "validate_product",
214
+ "validate_publisher_properties_item",
215
+ # Generated types modules
216
+ "generated",
217
+ "aliases",
321
218
  "GeneratedTaskStatus",
219
+ # Semantic type aliases (for better API ergonomics)
220
+ "ActivateSignalSuccessResponse",
221
+ "ActivateSignalErrorResponse",
222
+ "BuildCreativeSuccessResponse",
223
+ "BuildCreativeErrorResponse",
224
+ "CreateMediaBuySuccessResponse",
225
+ "CreateMediaBuyErrorResponse",
226
+ "ProvidePerformanceFeedbackSuccessResponse",
227
+ "ProvidePerformanceFeedbackErrorResponse",
228
+ "SyncCreativesSuccessResponse",
229
+ "SyncCreativesErrorResponse",
230
+ "UpdateMediaBuySuccessResponse",
231
+ "UpdateMediaBuyErrorResponse",
232
+ "PreviewCreativeFormatRequest",
233
+ "PreviewCreativeManifestRequest",
234
+ "PreviewCreativeStaticResponse",
235
+ "PreviewCreativeInteractiveResponse",
236
+ "PreviewRenderImage",
237
+ "PreviewRenderHtml",
238
+ "PreviewRenderIframe",
239
+ "PropertyIdActivationKey",
240
+ "PropertyTagActivationKey",
241
+ "UpdateMediaBuyPackagesRequest",
242
+ "UpdateMediaBuyPropertiesRequest",
322
243
  ]
@@ -14,6 +14,7 @@ from urllib.parse import urlparse
14
14
  import httpx
15
15
 
16
16
  from adcp.exceptions import AdagentsNotFoundError, AdagentsTimeoutError, AdagentsValidationError
17
+ from adcp.validation import ValidationError, validate_adagents
17
18
 
18
19
 
19
20
  def _normalize_domain(domain: str) -> str:
@@ -56,9 +57,7 @@ def _validate_publisher_domain(domain: str) -> str:
56
57
  suspicious_chars = ["\\", "@", "\n", "\r", "\t"]
57
58
  for char in suspicious_chars:
58
59
  if char in domain:
59
- raise AdagentsValidationError(
60
- f"Invalid character in publisher domain: {char!r}"
61
- )
60
+ raise AdagentsValidationError(f"Invalid character in publisher domain: {char!r}")
62
61
 
63
62
  domain = domain.strip()
64
63
 
@@ -70,9 +69,7 @@ def _validate_publisher_domain(domain: str) -> str:
70
69
 
71
70
  # Check for spaces after stripping leading/trailing whitespace
72
71
  if " " in domain:
73
- raise AdagentsValidationError(
74
- "Invalid character in publisher domain: ' '"
75
- )
72
+ raise AdagentsValidationError("Invalid character in publisher domain: ' '")
76
73
 
77
74
  # Remove protocol if present (common user error) - do this BEFORE checking for slashes
78
75
  if "://" in domain:
@@ -87,9 +84,7 @@ def _validate_publisher_domain(domain: str) -> str:
87
84
 
88
85
  # Final validation - must look like a domain
89
86
  if "." not in domain:
90
- raise AdagentsValidationError(
91
- f"Publisher domain must contain at least one dot: {domain!r}"
92
- )
87
+ raise AdagentsValidationError(f"Publisher domain must contain at least one dot: {domain!r}")
93
88
 
94
89
  return domain
95
90
 
@@ -359,13 +354,17 @@ async def fetch_adagents(
359
354
  raise AdagentsValidationError("adagents.json must be a JSON object")
360
355
 
361
356
  if "authorized_agents" not in data:
362
- raise AdagentsValidationError(
363
- "adagents.json must have 'authorized_agents' field"
364
- )
357
+ raise AdagentsValidationError("adagents.json must have 'authorized_agents' field")
365
358
 
366
359
  if not isinstance(data["authorized_agents"], list):
367
360
  raise AdagentsValidationError("'authorized_agents' must be an array")
368
361
 
362
+ # Validate mutual exclusivity constraints
363
+ try:
364
+ validate_adagents(data)
365
+ except ValidationError as e:
366
+ raise AdagentsValidationError(f"Invalid adagents.json structure: {e}") from e
367
+
369
368
  return data
370
369
 
371
370
  except httpx.TimeoutException as e: