adcp 1.6.0__tar.gz → 2.0.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 (152) hide show
  1. {adcp-1.6.0/src/adcp.egg-info → adcp-2.0.0}/PKG-INFO +3 -1
  2. {adcp-1.6.0 → adcp-2.0.0}/pyproject.toml +14 -2
  3. adcp-2.0.0/src/adcp/__init__.py +120 -0
  4. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/adagents.py +11 -12
  5. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/client.py +16 -11
  6. adcp-2.0.0/src/adcp/types/generated.py +614 -0
  7. adcp-2.0.0/src/adcp/types/generated_poc/__init__.py +3 -0
  8. adcp-2.0.0/src/adcp/types/generated_poc/activate_signal_request.py +34 -0
  9. adcp-2.0.0/src/adcp/types/generated_poc/activate_signal_response.py +57 -0
  10. adcp-2.0.0/src/adcp/types/generated_poc/activation_key.py +30 -0
  11. adcp-2.0.0/src/adcp/types/generated_poc/adagents.py +266 -0
  12. adcp-2.0.0/src/adcp/types/generated_poc/asset_type.py +100 -0
  13. adcp-2.0.0/src/adcp/types/generated_poc/audio_asset.py +26 -0
  14. adcp-2.0.0/src/adcp/types/generated_poc/brand_manifest.py +260 -0
  15. adcp-2.0.0/src/adcp/types/generated_poc/brand_manifest_ref.py +361 -0
  16. adcp-2.0.0/src/adcp/types/generated_poc/build_creative_request.py +43 -0
  17. adcp-2.0.0/src/adcp/types/generated_poc/build_creative_response.py +57 -0
  18. adcp-2.0.0/src/adcp/types/generated_poc/channels.py +19 -0
  19. adcp-2.0.0/src/adcp/types/generated_poc/cpc_option.py +39 -0
  20. adcp-2.0.0/src/adcp/types/generated_poc/cpcv_option.py +41 -0
  21. adcp-2.0.0/src/adcp/types/generated_poc/cpm_auction_option.py +54 -0
  22. adcp-2.0.0/src/adcp/types/generated_poc/cpm_fixed_option.py +39 -0
  23. adcp-2.0.0/src/adcp/types/generated_poc/cpp_option.py +60 -0
  24. adcp-2.0.0/src/adcp/types/generated_poc/cpv_option.py +73 -0
  25. adcp-2.0.0/src/adcp/types/generated_poc/create_media_buy_request.py +96 -0
  26. adcp-2.0.0/src/adcp/types/generated_poc/create_media_buy_response.py +66 -0
  27. adcp-2.0.0/src/adcp/types/generated_poc/creative_asset.py +83 -0
  28. adcp-2.0.0/src/adcp/types/generated_poc/creative_assignment.py +27 -0
  29. adcp-2.0.0/src/adcp/types/generated_poc/creative_manifest.py +61 -0
  30. adcp-2.0.0/src/adcp/types/generated_poc/creative_policy.py +34 -0
  31. adcp-2.0.0/src/adcp/types/generated_poc/creative_status.py +14 -0
  32. adcp-2.0.0/src/adcp/types/generated_poc/css_asset.py +20 -0
  33. adcp-2.0.0/src/adcp/types/generated_poc/daast_asset.py +76 -0
  34. adcp-2.0.0/src/adcp/types/generated_poc/delivery_metrics.py +111 -0
  35. adcp-2.0.0/src/adcp/types/generated_poc/delivery_type.py +12 -0
  36. adcp-2.0.0/src/adcp/types/generated_poc/deployment.py +78 -0
  37. adcp-2.0.0/src/adcp/types/generated_poc/destination.py +43 -0
  38. adcp-2.0.0/src/adcp/types/generated_poc/error.py +29 -0
  39. adcp-2.0.0/src/adcp/types/generated_poc/flat_rate_option.py +93 -0
  40. adcp-2.0.0/src/adcp/types/generated_poc/format.py +260 -0
  41. adcp-2.0.0/src/adcp/types/generated_poc/format_id.py +29 -0
  42. adcp-2.0.0/src/adcp/types/generated_poc/frequency_cap.py +19 -0
  43. adcp-2.0.0/src/adcp/types/generated_poc/frequency_cap_scope.py +16 -0
  44. adcp-2.0.0/src/adcp/types/generated_poc/get_media_buy_delivery_request.py +65 -0
  45. adcp-2.0.0/src/adcp/types/generated_poc/get_media_buy_delivery_response.py +220 -0
  46. adcp-2.0.0/src/adcp/types/generated_poc/get_products_request.py +83 -0
  47. adcp-2.0.0/src/adcp/types/generated_poc/get_products_response.py +29 -0
  48. adcp-2.0.0/src/adcp/types/generated_poc/get_signals_request.py +77 -0
  49. adcp-2.0.0/src/adcp/types/generated_poc/get_signals_response.py +65 -0
  50. adcp-2.0.0/src/adcp/types/generated_poc/html_asset.py +18 -0
  51. adcp-2.0.0/src/adcp/types/generated_poc/identifier_types.py +29 -0
  52. adcp-2.0.0/src/adcp/types/generated_poc/image_asset.py +23 -0
  53. adcp-2.0.0/src/adcp/types/generated_poc/index.py +17 -0
  54. adcp-2.0.0/src/adcp/types/generated_poc/javascript_asset.py +25 -0
  55. adcp-2.0.0/src/adcp/types/generated_poc/list_authorized_properties_request.py +39 -0
  56. adcp-2.0.0/src/adcp/types/generated_poc/list_authorized_properties_response.py +85 -0
  57. adcp-2.0.0/src/adcp/types/generated_poc/list_creative_formats_request.py +93 -0
  58. adcp-2.0.0/src/adcp/types/generated_poc/list_creative_formats_response.py +63 -0
  59. adcp-2.0.0/src/adcp/types/generated_poc/list_creatives_request.py +154 -0
  60. adcp-2.0.0/src/adcp/types/generated_poc/list_creatives_response.py +234 -0
  61. adcp-2.0.0/src/adcp/types/generated_poc/markdown_asset.py +43 -0
  62. adcp-2.0.0/src/adcp/types/generated_poc/measurement.py +40 -0
  63. adcp-2.0.0/src/adcp/types/generated_poc/media_buy.py +37 -0
  64. adcp-2.0.0/src/adcp/types/generated_poc/media_buy_status.py +14 -0
  65. adcp-2.0.0/src/adcp/types/generated_poc/pacing.py +13 -0
  66. adcp-2.0.0/src/adcp/types/generated_poc/package.py +61 -0
  67. adcp-2.0.0/src/adcp/types/generated_poc/package_request.py +61 -0
  68. adcp-2.0.0/src/adcp/types/generated_poc/package_status.py +14 -0
  69. adcp-2.0.0/src/adcp/types/generated_poc/performance_feedback.py +89 -0
  70. adcp-2.0.0/src/adcp/types/generated_poc/placement.py +37 -0
  71. adcp-2.0.0/src/adcp/types/generated_poc/preview_creative_request.py +163 -0
  72. adcp-2.0.0/src/adcp/types/generated_poc/preview_creative_response.py +175 -0
  73. adcp-2.0.0/src/adcp/types/generated_poc/preview_render.py +144 -0
  74. adcp-2.0.0/src/adcp/types/generated_poc/pricing_model.py +17 -0
  75. adcp-2.0.0/src/adcp/types/generated_poc/pricing_option.py +365 -0
  76. adcp-2.0.0/src/adcp/types/generated_poc/product.py +211 -0
  77. adcp-2.0.0/src/adcp/types/generated_poc/promoted_offerings.py +102 -0
  78. adcp-2.0.0/src/adcp/types/generated_poc/promoted_products.py +38 -0
  79. adcp-2.0.0/src/adcp/types/generated_poc/property.py +79 -0
  80. adcp-2.0.0/src/adcp/types/generated_poc/protocol_envelope.py +61 -0
  81. adcp-2.0.0/src/adcp/types/generated_poc/provide_performance_feedback_request.py +85 -0
  82. adcp-2.0.0/src/adcp/types/generated_poc/provide_performance_feedback_response.py +59 -0
  83. adcp-2.0.0/src/adcp/types/generated_poc/publisher_identifier_types.py +15 -0
  84. adcp-2.0.0/src/adcp/types/generated_poc/push_notification_config.py +55 -0
  85. adcp-2.0.0/src/adcp/types/generated_poc/reporting_capabilities.py +68 -0
  86. adcp-2.0.0/src/adcp/types/generated_poc/response.py +24 -0
  87. adcp-2.0.0/src/adcp/types/generated_poc/standard_format_ids.py +45 -0
  88. adcp-2.0.0/src/adcp/types/generated_poc/start_timing.py +13 -0
  89. adcp-2.0.0/src/adcp/types/generated_poc/sub_asset.py +55 -0
  90. adcp-2.0.0/src/adcp/types/generated_poc/sync_creatives_request.py +69 -0
  91. adcp-2.0.0/src/adcp/types/generated_poc/sync_creatives_response.py +117 -0
  92. adcp-2.0.0/src/adcp/types/generated_poc/targeting.py +53 -0
  93. adcp-2.0.0/src/adcp/types/generated_poc/task_status.py +19 -0
  94. adcp-2.0.0/src/adcp/types/generated_poc/task_type.py +15 -0
  95. adcp-2.0.0/src/adcp/types/generated_poc/tasks_get_request.py +29 -0
  96. adcp-2.0.0/src/adcp/types/generated_poc/tasks_get_response.py +112 -0
  97. adcp-2.0.0/src/adcp/types/generated_poc/tasks_list_request.py +121 -0
  98. adcp-2.0.0/src/adcp/types/generated_poc/tasks_list_response.py +122 -0
  99. adcp-2.0.0/src/adcp/types/generated_poc/text_asset.py +20 -0
  100. adcp-2.0.0/src/adcp/types/generated_poc/update_media_buy_request.py +160 -0
  101. adcp-2.0.0/src/adcp/types/generated_poc/update_media_buy_response.py +67 -0
  102. adcp-2.0.0/src/adcp/types/generated_poc/url_asset.py +33 -0
  103. adcp-2.0.0/src/adcp/types/generated_poc/vast_asset.py +86 -0
  104. adcp-2.0.0/src/adcp/types/generated_poc/vcpm_auction_option.py +57 -0
  105. adcp-2.0.0/src/adcp/types/generated_poc/vcpm_fixed_option.py +43 -0
  106. adcp-2.0.0/src/adcp/types/generated_poc/video_asset.py +28 -0
  107. adcp-2.0.0/src/adcp/types/generated_poc/webhook_asset.py +65 -0
  108. adcp-2.0.0/src/adcp/types/generated_poc/webhook_payload.py +102 -0
  109. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/utils/preview_cache.py +57 -39
  110. adcp-2.0.0/src/adcp/validation.py +172 -0
  111. {adcp-1.6.0 → adcp-2.0.0/src/adcp.egg-info}/PKG-INFO +3 -1
  112. adcp-2.0.0/src/adcp.egg-info/SOURCES.txt +144 -0
  113. {adcp-1.6.0 → adcp-2.0.0}/src/adcp.egg-info/requires.txt +2 -0
  114. {adcp-1.6.0 → adcp-2.0.0}/tests/test_adagents.py +58 -18
  115. {adcp-1.6.0 → adcp-2.0.0}/tests/test_client.py +19 -2
  116. adcp-2.0.0/tests/test_code_generation.py +64 -0
  117. adcp-2.0.0/tests/test_discriminated_unions.py +444 -0
  118. {adcp-1.6.0 → adcp-2.0.0}/tests/test_format_id_validation.py +5 -6
  119. {adcp-1.6.0 → adcp-2.0.0}/tests/test_preview_html.py +123 -56
  120. {adcp-1.6.0 → adcp-2.0.0}/tests/test_protocols.py +3 -1
  121. {adcp-1.6.0 → adcp-2.0.0}/tests/test_simple_api.py +30 -7
  122. adcp-1.6.0/src/adcp/__init__.py +0 -322
  123. adcp-1.6.0/src/adcp/types/generated.py +0 -1203
  124. adcp-1.6.0/src/adcp/types/tasks.py +0 -511
  125. adcp-1.6.0/src/adcp.egg-info/SOURCES.txt +0 -42
  126. adcp-1.6.0/tests/test_code_generation.py +0 -400
  127. adcp-1.6.0/tests/test_discriminated_unions.py +0 -404
  128. {adcp-1.6.0 → adcp-2.0.0}/LICENSE +0 -0
  129. {adcp-1.6.0 → adcp-2.0.0}/README.md +0 -0
  130. {adcp-1.6.0 → adcp-2.0.0}/setup.cfg +0 -0
  131. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/__main__.py +0 -0
  132. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/config.py +0 -0
  133. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/exceptions.py +0 -0
  134. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/protocols/__init__.py +0 -0
  135. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/protocols/a2a.py +0 -0
  136. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/protocols/base.py +0 -0
  137. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/protocols/mcp.py +0 -0
  138. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/simple.py +0 -0
  139. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/testing/__init__.py +0 -0
  140. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/testing/test_helpers.py +0 -0
  141. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/types/__init__.py +0 -0
  142. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/types/base.py +0 -0
  143. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/types/core.py +0 -0
  144. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/utils/__init__.py +0 -0
  145. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/utils/operation_id.py +0 -0
  146. {adcp-1.6.0 → adcp-2.0.0}/src/adcp/utils/response_parser.py +0 -0
  147. {adcp-1.6.0 → adcp-2.0.0}/src/adcp.egg-info/dependency_links.txt +0 -0
  148. {adcp-1.6.0 → adcp-2.0.0}/src/adcp.egg-info/entry_points.txt +0 -0
  149. {adcp-1.6.0 → adcp-2.0.0}/src/adcp.egg-info/top_level.txt +0 -0
  150. {adcp-1.6.0 → adcp-2.0.0}/tests/test_cli.py +0 -0
  151. {adcp-1.6.0 → adcp-2.0.0}/tests/test_helpers.py +0 -0
  152. {adcp-1.6.0 → adcp-2.0.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.0
3
+ Version: 2.0.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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "adcp"
7
- version = "1.6.0"
7
+ version = "2.0.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]
@@ -63,7 +65,11 @@ extend-exclude = "/(generated|tasks)\\.py$"
63
65
  [tool.ruff]
64
66
  line-length = 100
65
67
  target-version = "py310"
66
- extend-exclude = ["src/adcp/types/generated.py", "src/adcp/types/tasks.py"]
68
+ extend-exclude = [
69
+ "src/adcp/types/generated.py",
70
+ "src/adcp/types/tasks.py",
71
+ "src/adcp/types/generated_poc/",
72
+ ]
67
73
 
68
74
  [tool.ruff.lint]
69
75
  select = ["E", "F", "I", "N", "W", "UP"]
@@ -86,3 +92,9 @@ ignore_errors = true
86
92
  [tool.pytest.ini_options]
87
93
  testpaths = ["tests"]
88
94
  asyncio_mode = "auto"
95
+
96
+ [dependency-groups]
97
+ dev = [
98
+ "datamodel-code-generator>=0.35.0",
99
+ "pre-commit>=4.4.0",
100
+ ]
@@ -0,0 +1,120 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ AdCP Python Client Library
5
+
6
+ Official Python client for the Ad Context Protocol (AdCP).
7
+ Supports both A2A and MCP protocols with full type safety.
8
+ """
9
+
10
+ from adcp.adagents import (
11
+ domain_matches,
12
+ fetch_adagents,
13
+ get_all_properties,
14
+ get_all_tags,
15
+ get_properties_by_agent,
16
+ identifiers_match,
17
+ verify_agent_authorization,
18
+ verify_agent_for_property,
19
+ )
20
+ from adcp.client import ADCPClient, ADCPMultiAgentClient
21
+ from adcp.exceptions import (
22
+ AdagentsNotFoundError,
23
+ AdagentsTimeoutError,
24
+ AdagentsValidationError,
25
+ ADCPAuthenticationError,
26
+ ADCPConnectionError,
27
+ ADCPError,
28
+ ADCPProtocolError,
29
+ ADCPTimeoutError,
30
+ ADCPToolNotFoundError,
31
+ ADCPWebhookError,
32
+ ADCPWebhookSignatureError,
33
+ )
34
+
35
+ # Test helpers
36
+ from adcp.testing import (
37
+ CREATIVE_AGENT_CONFIG,
38
+ TEST_AGENT_A2A_CONFIG,
39
+ TEST_AGENT_A2A_NO_AUTH_CONFIG,
40
+ TEST_AGENT_MCP_CONFIG,
41
+ TEST_AGENT_MCP_NO_AUTH_CONFIG,
42
+ TEST_AGENT_TOKEN,
43
+ create_test_agent,
44
+ creative_agent,
45
+ test_agent,
46
+ test_agent_a2a,
47
+ test_agent_a2a_no_auth,
48
+ test_agent_client,
49
+ test_agent_no_auth,
50
+ )
51
+
52
+ # Import all generated types - users can import what they need from adcp.types.generated
53
+ from adcp.types import generated
54
+ from adcp.types.core import AgentConfig, Protocol, TaskResult, TaskStatus, WebhookMetadata
55
+ from adcp.types.generated import TaskStatus as GeneratedTaskStatus
56
+ from adcp.validation import (
57
+ ValidationError,
58
+ validate_adagents,
59
+ validate_agent_authorization,
60
+ validate_product,
61
+ validate_publisher_properties_item,
62
+ )
63
+
64
+ __version__ = "2.0.0"
65
+
66
+ __all__ = [
67
+ # Client classes
68
+ "ADCPClient",
69
+ "ADCPMultiAgentClient",
70
+ # Core types
71
+ "AgentConfig",
72
+ "Protocol",
73
+ "TaskResult",
74
+ "TaskStatus",
75
+ "WebhookMetadata",
76
+ # Adagents validation
77
+ "fetch_adagents",
78
+ "verify_agent_authorization",
79
+ "verify_agent_for_property",
80
+ "domain_matches",
81
+ "identifiers_match",
82
+ "get_all_properties",
83
+ "get_all_tags",
84
+ "get_properties_by_agent",
85
+ # Test helpers
86
+ "test_agent",
87
+ "test_agent_a2a",
88
+ "test_agent_no_auth",
89
+ "test_agent_a2a_no_auth",
90
+ "creative_agent",
91
+ "test_agent_client",
92
+ "create_test_agent",
93
+ "TEST_AGENT_TOKEN",
94
+ "TEST_AGENT_MCP_CONFIG",
95
+ "TEST_AGENT_A2A_CONFIG",
96
+ "TEST_AGENT_MCP_NO_AUTH_CONFIG",
97
+ "TEST_AGENT_A2A_NO_AUTH_CONFIG",
98
+ "CREATIVE_AGENT_CONFIG",
99
+ # Exceptions
100
+ "ADCPError",
101
+ "ADCPConnectionError",
102
+ "ADCPAuthenticationError",
103
+ "ADCPTimeoutError",
104
+ "ADCPProtocolError",
105
+ "ADCPToolNotFoundError",
106
+ "ADCPWebhookError",
107
+ "ADCPWebhookSignatureError",
108
+ "AdagentsValidationError",
109
+ "AdagentsNotFoundError",
110
+ "AdagentsTimeoutError",
111
+ # Validation utilities
112
+ "ValidationError",
113
+ "validate_adagents",
114
+ "validate_agent_authorization",
115
+ "validate_product",
116
+ "validate_publisher_properties_item",
117
+ # Generated types module
118
+ "generated",
119
+ "GeneratedTaskStatus",
120
+ ]
@@ -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:
@@ -23,6 +23,7 @@ from adcp.types.core import (
23
23
  AgentConfig,
24
24
  Protocol,
25
25
  TaskResult,
26
+ TaskStatus,
26
27
  )
27
28
  from adcp.types.generated import (
28
29
  ActivateSignalRequest,
@@ -47,6 +48,7 @@ from adcp.types.generated import (
47
48
  SyncCreativesResponse,
48
49
  WebhookPayload,
49
50
  )
51
+ from adcp.types.generated_poc.task_status import TaskStatus as GeneratedTaskStatus
50
52
  from adcp.utils.operation_id import create_operation_id
51
53
 
52
54
  logger = logging.getLogger(__name__)
@@ -624,7 +626,6 @@ class ADCPClient:
624
626
  Returns:
625
627
  TaskResult with task-specific typed response data
626
628
  """
627
- from adcp.types.core import TaskStatus
628
629
  from adcp.utils.response_parser import parse_json_or_text
629
630
 
630
631
  # Map task types to their response types (using string literals, not enum)
@@ -643,8 +644,8 @@ class ADCPClient:
643
644
 
644
645
  # Handle completed tasks with result parsing
645
646
 
646
- if webhook.status == "completed" and webhook.result is not None:
647
- response_type = response_type_map.get(webhook.task_type)
647
+ if webhook.status == GeneratedTaskStatus.completed and webhook.result is not None:
648
+ response_type = response_type_map.get(webhook.task_type.value)
648
649
  if response_type:
649
650
  try:
650
651
  parsed_result: Any = parse_json_or_text(webhook.result, response_type)
@@ -664,17 +665,21 @@ class ADCPClient:
664
665
  # Fall through to untyped result
665
666
 
666
667
  # Handle failed, input-required, or unparseable results
667
- # Convert webhook status string to TaskStatus enum
668
- try:
669
- task_status = TaskStatus(webhook.status)
670
- except ValueError:
671
- # Fallback to FAILED for unknown statuses
672
- task_status = TaskStatus.FAILED
668
+ # Convert webhook status to core TaskStatus enum
669
+ # Map generated enum values to core enum values
670
+ status_map = {
671
+ GeneratedTaskStatus.completed: TaskStatus.COMPLETED,
672
+ GeneratedTaskStatus.submitted: TaskStatus.SUBMITTED,
673
+ GeneratedTaskStatus.working: TaskStatus.WORKING,
674
+ GeneratedTaskStatus.failed: TaskStatus.FAILED,
675
+ GeneratedTaskStatus.input_required: TaskStatus.NEEDS_INPUT,
676
+ }
677
+ task_status = status_map.get(webhook.status, TaskStatus.FAILED)
673
678
 
674
679
  return TaskResult[Any](
675
680
  status=task_status,
676
681
  data=webhook.result,
677
- success=webhook.status == "completed",
682
+ success=webhook.status == GeneratedTaskStatus.completed,
678
683
  error=webhook.error if isinstance(webhook.error, str) else None,
679
684
  metadata={
680
685
  "task_id": webhook.task_id,
@@ -732,7 +737,7 @@ class ADCPClient:
732
737
  type=ActivityType.WEBHOOK_RECEIVED,
733
738
  operation_id=webhook.operation_id or "unknown",
734
739
  agent_id=self.agent_config.id,
735
- task_type=webhook.task_type,
740
+ task_type=webhook.task_type.value,
736
741
  timestamp=datetime.now(timezone.utc).isoformat(),
737
742
  metadata={"payload": payload},
738
743
  )