adcp 2.16.0__py3-none-any.whl → 2.18.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.
Files changed (111) hide show
  1. adcp/ADCP_VERSION +1 -1
  2. adcp/__init__.py +22 -1
  3. adcp/__main__.py +72 -0
  4. adcp/types/_generated.py +7 -1
  5. adcp/types/generated_poc/adagents.py +14 -14
  6. adcp/types/generated_poc/core/activation_key.py +3 -3
  7. adcp/types/generated_poc/core/assets/audio_asset.py +2 -2
  8. adcp/types/generated_poc/core/assets/css_asset.py +2 -2
  9. adcp/types/generated_poc/core/assets/daast_asset.py +3 -3
  10. adcp/types/generated_poc/core/assets/html_asset.py +2 -2
  11. adcp/types/generated_poc/core/assets/image_asset.py +2 -2
  12. adcp/types/generated_poc/core/assets/javascript_asset.py +2 -2
  13. adcp/types/generated_poc/core/assets/text_asset.py +2 -2
  14. adcp/types/generated_poc/core/assets/url_asset.py +2 -2
  15. adcp/types/generated_poc/core/assets/vast_asset.py +3 -3
  16. adcp/types/generated_poc/core/assets/video_asset.py +2 -2
  17. adcp/types/generated_poc/core/assets/webhook_asset.py +2 -2
  18. adcp/types/generated_poc/core/brand_manifest.py +4 -4
  19. adcp/types/generated_poc/core/context.py +1 -2
  20. adcp/types/generated_poc/core/creative_asset.py +3 -3
  21. adcp/types/generated_poc/core/creative_assignment.py +2 -2
  22. adcp/types/generated_poc/core/creative_filters.py +2 -2
  23. adcp/types/generated_poc/core/creative_manifest.py +2 -2
  24. adcp/types/generated_poc/core/creative_policy.py +2 -2
  25. adcp/types/generated_poc/core/delivery_metrics.py +3 -3
  26. adcp/types/generated_poc/core/deployment.py +3 -3
  27. adcp/types/generated_poc/core/destination.py +3 -3
  28. adcp/types/generated_poc/core/error.py +5 -5
  29. adcp/types/generated_poc/core/ext.py +1 -2
  30. adcp/types/generated_poc/core/format.py +94 -7
  31. adcp/types/generated_poc/core/format_id.py +2 -2
  32. adcp/types/generated_poc/core/frequency_cap.py +2 -2
  33. adcp/types/generated_poc/core/measurement.py +2 -2
  34. adcp/types/generated_poc/core/media_buy.py +2 -2
  35. adcp/types/generated_poc/core/package.py +2 -2
  36. adcp/types/generated_poc/core/performance_feedback.py +3 -3
  37. adcp/types/generated_poc/core/placement.py +2 -2
  38. adcp/types/generated_poc/core/product.py +4 -4
  39. adcp/types/generated_poc/core/product_filters.py +4 -4
  40. adcp/types/generated_poc/core/promoted_offerings.py +4 -4
  41. adcp/types/generated_poc/core/promoted_products.py +2 -2
  42. adcp/types/generated_poc/core/property.py +3 -3
  43. adcp/types/generated_poc/core/protocol_envelope.py +2 -2
  44. adcp/types/generated_poc/core/publisher_property_selector.py +4 -4
  45. adcp/types/generated_poc/core/reporting_capabilities.py +2 -2
  46. adcp/types/generated_poc/core/response.py +2 -2
  47. adcp/types/generated_poc/core/signal_filters.py +2 -2
  48. adcp/types/generated_poc/core/sub_asset.py +3 -3
  49. adcp/types/generated_poc/core/targeting.py +2 -2
  50. adcp/types/generated_poc/creative/list_creative_formats_request.py +2 -2
  51. adcp/types/generated_poc/creative/list_creative_formats_response.py +2 -2
  52. adcp/types/generated_poc/creative/preview_creative_request.py +7 -7
  53. adcp/types/generated_poc/creative/preview_creative_response.py +3 -3
  54. adcp/types/generated_poc/creative/preview_render.py +4 -4
  55. adcp/types/generated_poc/media_buy/build_creative_request.py +2 -2
  56. adcp/types/generated_poc/media_buy/build_creative_response.py +3 -3
  57. adcp/types/generated_poc/media_buy/create_media_buy_async_response_input_required.py +2 -2
  58. adcp/types/generated_poc/media_buy/create_media_buy_async_response_submitted.py +2 -2
  59. adcp/types/generated_poc/media_buy/create_media_buy_async_response_working.py +2 -2
  60. adcp/types/generated_poc/media_buy/create_media_buy_request.py +47 -6
  61. adcp/types/generated_poc/media_buy/create_media_buy_response.py +3 -3
  62. adcp/types/generated_poc/media_buy/get_media_buy_delivery_request.py +2 -2
  63. adcp/types/generated_poc/media_buy/get_media_buy_delivery_response.py +6 -6
  64. adcp/types/generated_poc/media_buy/get_products_async_response_input_required.py +2 -2
  65. adcp/types/generated_poc/media_buy/get_products_async_response_submitted.py +2 -2
  66. adcp/types/generated_poc/media_buy/get_products_async_response_working.py +2 -2
  67. adcp/types/generated_poc/media_buy/get_products_request.py +2 -2
  68. adcp/types/generated_poc/media_buy/get_products_response.py +2 -2
  69. adcp/types/generated_poc/media_buy/list_authorized_properties_request.py +2 -2
  70. adcp/types/generated_poc/media_buy/list_authorized_properties_response.py +2 -2
  71. adcp/types/generated_poc/media_buy/list_creative_formats_request.py +2 -2
  72. adcp/types/generated_poc/media_buy/list_creative_formats_response.py +2 -2
  73. adcp/types/generated_poc/media_buy/list_creatives_request.py +4 -4
  74. adcp/types/generated_poc/media_buy/list_creatives_response.py +9 -9
  75. adcp/types/generated_poc/media_buy/package_request.py +2 -2
  76. adcp/types/generated_poc/media_buy/provide_performance_feedback_request.py +4 -4
  77. adcp/types/generated_poc/media_buy/provide_performance_feedback_response.py +3 -3
  78. adcp/types/generated_poc/media_buy/sync_creatives_async_response_input_required.py +2 -2
  79. adcp/types/generated_poc/media_buy/sync_creatives_async_response_submitted.py +2 -2
  80. adcp/types/generated_poc/media_buy/sync_creatives_async_response_working.py +2 -2
  81. adcp/types/generated_poc/media_buy/sync_creatives_request.py +2 -2
  82. adcp/types/generated_poc/media_buy/sync_creatives_response.py +4 -4
  83. adcp/types/generated_poc/media_buy/update_media_buy_async_response_input_required.py +2 -2
  84. adcp/types/generated_poc/media_buy/update_media_buy_async_response_submitted.py +2 -2
  85. adcp/types/generated_poc/media_buy/update_media_buy_async_response_working.py +2 -2
  86. adcp/types/generated_poc/media_buy/update_media_buy_request.py +5 -5
  87. adcp/types/generated_poc/media_buy/update_media_buy_response.py +3 -3
  88. adcp/types/generated_poc/pricing_options/cpc_option.py +2 -2
  89. adcp/types/generated_poc/pricing_options/cpcv_option.py +2 -2
  90. adcp/types/generated_poc/pricing_options/cpm_auction_option.py +2 -2
  91. adcp/types/generated_poc/pricing_options/cpm_fixed_option.py +2 -2
  92. adcp/types/generated_poc/pricing_options/cpp_option.py +3 -3
  93. adcp/types/generated_poc/pricing_options/cpv_option.py +4 -4
  94. adcp/types/generated_poc/pricing_options/flat_rate_option.py +3 -3
  95. adcp/types/generated_poc/pricing_options/vcpm_auction_option.py +2 -2
  96. adcp/types/generated_poc/pricing_options/vcpm_fixed_option.py +2 -2
  97. adcp/types/generated_poc/protocols/adcp_extension.py +2 -2
  98. adcp/types/generated_poc/signals/activate_signal_request.py +2 -2
  99. adcp/types/generated_poc/signals/activate_signal_response.py +3 -3
  100. adcp/types/generated_poc/signals/get_signals_request.py +3 -3
  101. adcp/types/generated_poc/signals/get_signals_response.py +4 -4
  102. adcp/utils/__init__.py +24 -1
  103. adcp/utils/format_assets.py +224 -0
  104. adcp/utils/preview_cache.py +29 -7
  105. adcp/utils/response_parser.py +81 -6
  106. {adcp-2.16.0.dist-info → adcp-2.18.0.dist-info}/METADATA +1 -1
  107. {adcp-2.16.0.dist-info → adcp-2.18.0.dist-info}/RECORD +111 -110
  108. {adcp-2.16.0.dist-info → adcp-2.18.0.dist-info}/WHEEL +0 -0
  109. {adcp-2.16.0.dist-info → adcp-2.18.0.dist-info}/entry_points.txt +0 -0
  110. {adcp-2.16.0.dist-info → adcp-2.18.0.dist-info}/licenses/LICENSE +0 -0
  111. {adcp-2.16.0.dist-info → adcp-2.18.0.dist-info}/top_level.txt +0 -0
adcp/ADCP_VERSION CHANGED
@@ -1 +1 @@
1
- 2.5.0
1
+ 2.6.0
adcp/__init__.py CHANGED
@@ -172,6 +172,17 @@ from adcp.types.aliases import (
172
172
  UrlVastAsset,
173
173
  )
174
174
  from adcp.types.core import AgentConfig, Protocol, TaskResult, TaskStatus, WebhookMetadata
175
+ from adcp.utils import (
176
+ get_asset_count,
177
+ get_format_assets,
178
+ get_individual_assets,
179
+ get_optional_assets,
180
+ get_repeatable_groups,
181
+ get_required_assets,
182
+ has_assets,
183
+ normalize_assets_required,
184
+ uses_deprecated_assets_field,
185
+ )
175
186
  from adcp.validation import (
176
187
  ValidationError,
177
188
  validate_adagents,
@@ -186,7 +197,7 @@ from adcp.webhooks import (
186
197
  get_adcp_signed_headers_for_webhook,
187
198
  )
188
199
 
189
- __version__ = "2.16.0"
200
+ __version__ = "2.18.0"
190
201
 
191
202
 
192
203
  def get_adcp_version() -> str:
@@ -333,6 +344,16 @@ __all__ = [
333
344
  "validate_agent_authorization",
334
345
  "validate_product",
335
346
  "validate_publisher_properties_item",
347
+ # Format asset utilities
348
+ "get_format_assets",
349
+ "normalize_assets_required",
350
+ "get_required_assets",
351
+ "get_optional_assets",
352
+ "get_individual_assets",
353
+ "get_repeatable_groups",
354
+ "uses_deprecated_assets_field",
355
+ "get_asset_count",
356
+ "has_assets",
336
357
  # Generated types modules
337
358
  "generated",
338
359
  "aliases",
adcp/__main__.py CHANGED
@@ -32,8 +32,80 @@ def print_json(data: Any) -> None:
32
32
  print(json.dumps(data, indent=2, default=str))
33
33
 
34
34
 
35
+ def _check_deprecated_fields(data: Any) -> None:
36
+ """Check response data for deprecated fields and emit warnings to stderr.
37
+
38
+ Uses Pydantic's Field(deprecated=True) metadata to generically detect
39
+ any deprecated fields that are populated in the response.
40
+ """
41
+ from pydantic import BaseModel
42
+
43
+ deprecated_found: set[str] = set()
44
+
45
+ def _find_deprecated_fields(obj: Any, visited: set[int] | None = None) -> None:
46
+ """Recursively find deprecated fields that are populated."""
47
+ if obj is None:
48
+ return
49
+
50
+ # Prevent infinite recursion on circular references
51
+ if visited is None:
52
+ visited = set()
53
+ obj_id = id(obj)
54
+ if obj_id in visited:
55
+ return
56
+ visited.add(obj_id)
57
+
58
+ # Check Pydantic models for deprecated fields
59
+ if isinstance(obj, BaseModel):
60
+ import warnings
61
+
62
+ # Access model_fields from the class, not the instance (Pydantic v2.11+)
63
+ model_fields = type(obj).model_fields
64
+
65
+ for field_name, field_info in model_fields.items():
66
+ if field_info.deprecated:
67
+ # Suppress Pydantic's DeprecationWarning when accessing deprecated fields
68
+ with warnings.catch_warnings():
69
+ warnings.simplefilter("ignore", DeprecationWarning)
70
+ value = getattr(obj, field_name, None)
71
+ if value is not None:
72
+ deprecated_found.add(field_name)
73
+
74
+ # Recursively check field values
75
+ for field_name in model_fields:
76
+ with warnings.catch_warnings():
77
+ warnings.simplefilter("ignore", DeprecationWarning)
78
+ value = getattr(obj, field_name, None)
79
+ if value is not None:
80
+ _find_deprecated_fields(value, visited)
81
+
82
+ # Check lists
83
+ elif isinstance(obj, list):
84
+ for item in obj:
85
+ _find_deprecated_fields(item, visited)
86
+
87
+ # Check dicts
88
+ elif isinstance(obj, dict):
89
+ for value in obj.values():
90
+ _find_deprecated_fields(value, visited)
91
+
92
+ _find_deprecated_fields(data)
93
+
94
+ if deprecated_found:
95
+ fields_list = ", ".join(f"'{f}'" for f in sorted(deprecated_found))
96
+ print(
97
+ f"\n⚠️ Warning: Response contains deprecated field(s): {fields_list}\n"
98
+ " See field descriptions or AdCP spec for migration details.\n",
99
+ file=sys.stderr,
100
+ )
101
+
102
+
35
103
  def print_result(result: Any, json_output: bool = False) -> None:
36
104
  """Print result in formatted or JSON mode."""
105
+ # Check for deprecated fields and warn (to stderr, so JSON output isn't affected)
106
+ if result.success and result.data:
107
+ _check_deprecated_fields(result.data)
108
+
37
109
  if json_output:
38
110
  # Match JavaScript client: output just the data for scripting
39
111
  if result.success and result.data:
adcp/types/_generated.py CHANGED
@@ -10,7 +10,7 @@ Auto-generated by datamodel-code-generator from JSON schemas.
10
10
  DO NOT EDIT MANUALLY.
11
11
 
12
12
  Generated from: https://github.com/adcontextprotocol/adcp/tree/main/schemas
13
- Generation date: 2025-12-18 20:00:25 UTC
13
+ Generation date: 2026-01-08 19:25:24 UTC
14
14
  """
15
15
 
16
16
  # ruff: noqa: E501, I001
@@ -75,6 +75,9 @@ from adcp.types.generated_poc.core.destination import Destination, Destination1,
75
75
  from adcp.types.generated_poc.core.error import Error
76
76
  from adcp.types.generated_poc.core.ext import ExtensionObject
77
77
  from adcp.types.generated_poc.core.format import (
78
+ Asset2,
79
+ Assets,
80
+ Assets1,
78
81
  AssetsRequired,
79
82
  AssetsRequired1,
80
83
  Dimensions,
@@ -399,9 +402,12 @@ __all__ = [
399
402
  "AdvertisingChannels",
400
403
  "AggregatedTotals",
401
404
  "Asset",
405
+ "Asset2",
402
406
  "AssetContentType",
403
407
  "AssetSelectors",
404
408
  "AssetType",
409
+ "Assets",
410
+ "Assets1",
405
411
  "AssetsRequired",
406
412
  "AssetsRequired1",
407
413
  "AssignedPackage",
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: adagents.json
3
- # timestamp: 2025-12-18T20:00:24+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -14,7 +14,7 @@ from .core import property, property_id, property_tag, publisher_property_select
14
14
 
15
15
  class AuthorizedSalesAgents1(AdCPBaseModel):
16
16
  model_config = ConfigDict(
17
- extra='forbid',
17
+ extra='allow',
18
18
  )
19
19
  field_schema: Annotated[
20
20
  str | None,
@@ -34,7 +34,7 @@ class AuthorizedSalesAgents1(AdCPBaseModel):
34
34
 
35
35
  class Contact(AdCPBaseModel):
36
36
  model_config = ConfigDict(
37
- extra='forbid',
37
+ extra='allow',
38
38
  )
39
39
  domain: Annotated[
40
40
  str | None,
@@ -79,7 +79,7 @@ class Contact(AdCPBaseModel):
79
79
 
80
80
  class Tags(AdCPBaseModel):
81
81
  model_config = ConfigDict(
82
- extra='forbid',
82
+ extra='allow',
83
83
  )
84
84
  description: Annotated[str, Field(description='Description of what this tag represents')]
85
85
  name: Annotated[str, Field(description='Human-readable name for this tag')]
@@ -87,7 +87,7 @@ class Tags(AdCPBaseModel):
87
87
 
88
88
  class AuthorizedAgents(AdCPBaseModel):
89
89
  model_config = ConfigDict(
90
- extra='forbid',
90
+ extra='allow',
91
91
  )
92
92
  authorization_type: Annotated[
93
93
  Literal['property_ids'],
@@ -113,7 +113,7 @@ class AuthorizedAgents(AdCPBaseModel):
113
113
 
114
114
  class AuthorizedAgents1(AdCPBaseModel):
115
115
  model_config = ConfigDict(
116
- extra='forbid',
116
+ extra='allow',
117
117
  )
118
118
  authorization_type: Annotated[
119
119
  Literal['property_tags'],
@@ -139,7 +139,7 @@ class AuthorizedAgents1(AdCPBaseModel):
139
139
 
140
140
  class AuthorizedAgents3(AdCPBaseModel):
141
141
  model_config = ConfigDict(
142
- extra='forbid',
142
+ extra='allow',
143
143
  )
144
144
  authorization_type: Annotated[
145
145
  Literal['publisher_properties'],
@@ -167,7 +167,7 @@ class AuthorizedAgents3(AdCPBaseModel):
167
167
 
168
168
  class AuthorizedAgents2(AdCPBaseModel):
169
169
  model_config = ConfigDict(
170
- extra='forbid',
170
+ extra='allow',
171
171
  )
172
172
  authorization_type: Annotated[
173
173
  Literal['inline_properties'],
@@ -193,7 +193,7 @@ class AuthorizedAgents2(AdCPBaseModel):
193
193
 
194
194
  class AuthorizedSalesAgents2(AdCPBaseModel):
195
195
  model_config = ConfigDict(
196
- extra='forbid',
196
+ extra='allow',
197
197
  )
198
198
  field_schema: Annotated[
199
199
  str | None,
@@ -238,12 +238,12 @@ class AuthorizedSalesAgents(RootModel[AuthorizedSalesAgents1 | AuthorizedSalesAg
238
238
  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.',
239
239
  examples=[
240
240
  {
241
- '$schema': '/schemas/latest/adagents.json',
241
+ '$schema': '/schemas/2.6.0/adagents.json',
242
242
  'authoritative_location': 'https://cdn.example.com/adagents/v2/adagents.json',
243
243
  'last_updated': '2025-01-15T10:00:00Z',
244
244
  },
245
245
  {
246
- '$schema': '/schemas/latest/adagents.json',
246
+ '$schema': '/schemas/2.6.0/adagents.json',
247
247
  'authorized_agents': [
248
248
  {
249
249
  'authorization_type': 'property_tags',
@@ -269,7 +269,7 @@ class AuthorizedSalesAgents(RootModel[AuthorizedSalesAgents1 | AuthorizedSalesAg
269
269
  },
270
270
  },
271
271
  {
272
- '$schema': '/schemas/latest/adagents.json',
272
+ '$schema': '/schemas/2.6.0/adagents.json',
273
273
  'authorized_agents': [
274
274
  {
275
275
  'authorization_type': 'property_tags',
@@ -334,7 +334,7 @@ class AuthorizedSalesAgents(RootModel[AuthorizedSalesAgents1 | AuthorizedSalesAg
334
334
  },
335
335
  },
336
336
  {
337
- '$schema': '/schemas/latest/adagents.json',
337
+ '$schema': '/schemas/2.6.0/adagents.json',
338
338
  'authorized_agents': [
339
339
  {
340
340
  'authorization_type': 'property_tags',
@@ -362,7 +362,7 @@ class AuthorizedSalesAgents(RootModel[AuthorizedSalesAgents1 | AuthorizedSalesAg
362
362
  },
363
363
  },
364
364
  {
365
- '$schema': '/schemas/latest/adagents.json',
365
+ '$schema': '/schemas/2.6.0/adagents.json',
366
366
  'authorized_agents': [
367
367
  {
368
368
  'authorization_type': 'publisher_properties',
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/activation_key.json
3
- # timestamp: 2025-12-11T15:09:37+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -12,7 +12,7 @@ from pydantic import ConfigDict, Field, RootModel
12
12
 
13
13
  class ActivationKey1(AdCPBaseModel):
14
14
  model_config = ConfigDict(
15
- extra='forbid',
15
+ extra='allow',
16
16
  )
17
17
  segment_id: Annotated[
18
18
  str,
@@ -23,7 +23,7 @@ class ActivationKey1(AdCPBaseModel):
23
23
 
24
24
  class ActivationKey2(AdCPBaseModel):
25
25
  model_config = ConfigDict(
26
- extra='forbid',
26
+ extra='allow',
27
27
  )
28
28
  key: Annotated[str, Field(description='The targeting parameter key')]
29
29
  type: Annotated[Literal['key_value'], Field(description='Key-value pair based targeting')]
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/audio_asset.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -12,7 +12,7 @@ from pydantic import AnyUrl, ConfigDict, Field
12
12
 
13
13
  class AudioAsset(AdCPBaseModel):
14
14
  model_config = ConfigDict(
15
- extra='forbid',
15
+ extra='allow',
16
16
  )
17
17
  bitrate_kbps: Annotated[
18
18
  int | None, Field(description='Audio bitrate in kilobits per second', ge=1)
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/css_asset.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -12,7 +12,7 @@ from pydantic import ConfigDict, Field
12
12
 
13
13
  class CssAsset(AdCPBaseModel):
14
14
  model_config = ConfigDict(
15
- extra='forbid',
15
+ extra='allow',
16
16
  )
17
17
  content: Annotated[str, Field(description='CSS content')]
18
18
  media: Annotated[
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/daast_asset.json
3
- # timestamp: 2025-12-11T15:09:37+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -15,7 +15,7 @@ from ...enums import daast_version as daast_version_1
15
15
 
16
16
  class DaastAsset1(AdCPBaseModel):
17
17
  model_config = ConfigDict(
18
- extra='forbid',
18
+ extra='allow',
19
19
  )
20
20
  companion_ads: Annotated[
21
21
  bool | None, Field(description='Whether companion display ads are included')
@@ -39,7 +39,7 @@ class DaastAsset1(AdCPBaseModel):
39
39
 
40
40
  class DaastAsset2(AdCPBaseModel):
41
41
  model_config = ConfigDict(
42
- extra='forbid',
42
+ extra='allow',
43
43
  )
44
44
  companion_ads: Annotated[
45
45
  bool | None, Field(description='Whether companion display ads are included')
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/html_asset.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -12,7 +12,7 @@ from pydantic import ConfigDict, Field
12
12
 
13
13
  class HtmlAsset(AdCPBaseModel):
14
14
  model_config = ConfigDict(
15
- extra='forbid',
15
+ extra='allow',
16
16
  )
17
17
  content: Annotated[str, Field(description='HTML content')]
18
18
  version: Annotated[str | None, Field(description="HTML version (e.g., 'HTML5')")] = None
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/image_asset.json
3
- # timestamp: 2025-12-18T20:00:24+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -12,7 +12,7 @@ from pydantic import AnyUrl, ConfigDict, Field
12
12
 
13
13
  class ImageAsset(AdCPBaseModel):
14
14
  model_config = ConfigDict(
15
- extra='forbid',
15
+ extra='allow',
16
16
  )
17
17
  alt_text: Annotated[str | None, Field(description='Alternative text for accessibility')] = None
18
18
  format: Annotated[
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/javascript_asset.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -14,7 +14,7 @@ from ...enums import javascript_module_type
14
14
 
15
15
  class JavascriptAsset(AdCPBaseModel):
16
16
  model_config = ConfigDict(
17
- extra='forbid',
17
+ extra='allow',
18
18
  )
19
19
  content: Annotated[str, Field(description='JavaScript content')]
20
20
  module_type: Annotated[
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/text_asset.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -12,7 +12,7 @@ from pydantic import ConfigDict, Field
12
12
 
13
13
  class TextAsset(AdCPBaseModel):
14
14
  model_config = ConfigDict(
15
- extra='forbid',
15
+ extra='allow',
16
16
  )
17
17
  content: Annotated[str, Field(description='Text content')]
18
18
  language: Annotated[str | None, Field(description="Language code (e.g., 'en', 'es', 'fr')")] = (
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/url_asset.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -14,7 +14,7 @@ from ...enums import url_asset_type
14
14
 
15
15
  class UrlAsset(AdCPBaseModel):
16
16
  model_config = ConfigDict(
17
- extra='forbid',
17
+ extra='allow',
18
18
  )
19
19
  description: Annotated[
20
20
  str | None, Field(description='Description of what this URL points to')
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/vast_asset.json
3
- # timestamp: 2025-12-11T15:09:37+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -15,7 +15,7 @@ from ...enums import vast_version as vast_version_1
15
15
 
16
16
  class VastAsset1(AdCPBaseModel):
17
17
  model_config = ConfigDict(
18
- extra='forbid',
18
+ extra='allow',
19
19
  )
20
20
  delivery_type: Annotated[
21
21
  Literal['url'],
@@ -40,7 +40,7 @@ class VastAsset1(AdCPBaseModel):
40
40
 
41
41
  class VastAsset2(AdCPBaseModel):
42
42
  model_config = ConfigDict(
43
- extra='forbid',
43
+ extra='allow',
44
44
  )
45
45
  content: Annotated[str, Field(description='Inline VAST XML content')]
46
46
  delivery_type: Annotated[
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/video_asset.json
3
- # timestamp: 2025-12-18T20:00:24+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -12,7 +12,7 @@ from pydantic import AnyUrl, ConfigDict, Field
12
12
 
13
13
  class VideoAsset(AdCPBaseModel):
14
14
  model_config = ConfigDict(
15
- extra='forbid',
15
+ extra='allow',
16
16
  )
17
17
  bitrate_kbps: Annotated[
18
18
  int | None, Field(description='Video bitrate in kilobits per second', ge=1)
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/assets/webhook_asset.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -26,7 +26,7 @@ class Security(AdCPBaseModel):
26
26
 
27
27
  class WebhookAsset(AdCPBaseModel):
28
28
  model_config = ConfigDict(
29
- extra='forbid',
29
+ extra='allow',
30
30
  )
31
31
  method: Annotated[http_method.HttpMethod | None, Field(description='HTTP method')] = (
32
32
  http_method.HttpMethod.POST
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/brand_manifest.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -15,7 +15,7 @@ from ..enums import asset_content_type
15
15
 
16
16
  class Asset(AdCPBaseModel):
17
17
  model_config = ConfigDict(
18
- extra='forbid',
18
+ extra='allow',
19
19
  )
20
20
  asset_id: Annotated[str, Field(description='Unique identifier for this asset')]
21
21
  asset_type: Annotated[
@@ -130,7 +130,7 @@ class UpdateFrequency(Enum):
130
130
 
131
131
  class ProductCatalog(AdCPBaseModel):
132
132
  model_config = ConfigDict(
133
- extra='forbid',
133
+ extra='allow',
134
134
  )
135
135
  categories: Annotated[
136
136
  list[str] | None,
@@ -150,7 +150,7 @@ class ProductCatalog(AdCPBaseModel):
150
150
 
151
151
  class BrandManifest(AdCPBaseModel):
152
152
  model_config = ConfigDict(
153
- extra='forbid',
153
+ extra='allow',
154
154
  )
155
155
  assets: Annotated[
156
156
  list[Asset] | None,
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/context.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -9,7 +9,6 @@ from pydantic import ConfigDict
9
9
 
10
10
 
11
11
  class ContextObject(AdCPBaseModel):
12
- pass
13
12
  model_config = ConfigDict(
14
13
  extra='allow',
15
14
  )
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/creative_asset.json
3
- # timestamp: 2025-12-11T15:09:37+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -27,7 +27,7 @@ from .assets import (
27
27
 
28
28
  class Input(AdCPBaseModel):
29
29
  model_config = ConfigDict(
30
- extra='forbid',
30
+ extra='allow',
31
31
  )
32
32
  context_description: Annotated[
33
33
  str | None,
@@ -41,7 +41,7 @@ class Input(AdCPBaseModel):
41
41
 
42
42
  class CreativeAsset(AdCPBaseModel):
43
43
  model_config = ConfigDict(
44
- extra='forbid',
44
+ extra='allow',
45
45
  )
46
46
  approved: Annotated[
47
47
  bool | None,
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/creative_assignment.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -12,7 +12,7 @@ from pydantic import ConfigDict, Field
12
12
 
13
13
  class CreativeAssignment(AdCPBaseModel):
14
14
  model_config = ConfigDict(
15
- extra='forbid',
15
+ extra='allow',
16
16
  )
17
17
  creative_id: Annotated[str, Field(description='Unique identifier for the creative')]
18
18
  placement_ids: Annotated[
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/creative_filters.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -14,7 +14,7 @@ from ..enums import creative_status
14
14
 
15
15
  class CreativeFilters(AdCPBaseModel):
16
16
  model_config = ConfigDict(
17
- extra='forbid',
17
+ extra='allow',
18
18
  )
19
19
  assigned_to_package: Annotated[
20
20
  str | None, Field(description='Filter creatives assigned to this specific package')
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/creative_manifest.json
3
- # timestamp: 2025-12-11T15:09:37+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -29,7 +29,7 @@ from .assets import (
29
29
 
30
30
  class CreativeManifest(AdCPBaseModel):
31
31
  model_config = ConfigDict(
32
- extra='forbid',
32
+ extra='allow',
33
33
  )
34
34
  assets: Annotated[
35
35
  dict[
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: core/creative_policy.json
3
- # timestamp: 2025-11-29T12:00:45+00:00
3
+ # timestamp: 2026-01-08T19:25:24+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -14,7 +14,7 @@ from ..enums import co_branding_requirement, landing_page_requirement
14
14
 
15
15
  class CreativePolicy(AdCPBaseModel):
16
16
  model_config = ConfigDict(
17
- extra='forbid',
17
+ extra='allow',
18
18
  )
19
19
  co_branding: Annotated[
20
20
  co_branding_requirement.CoBrandingRequirement, Field(description='Co-branding requirement')