adcp 1.2.0__tar.gz → 1.3.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 (40) hide show
  1. {adcp-1.2.0/src/adcp.egg-info → adcp-1.3.0}/PKG-INFO +138 -1
  2. {adcp-1.2.0 → adcp-1.3.0}/README.md +137 -0
  3. {adcp-1.2.0 → adcp-1.3.0}/pyproject.toml +1 -1
  4. adcp-1.3.0/src/adcp/__init__.py +289 -0
  5. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/client.py +12 -5
  6. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/protocols/base.py +5 -2
  7. adcp-1.3.0/src/adcp/testing/__init__.py +38 -0
  8. adcp-1.3.0/src/adcp/testing/test_helpers.py +311 -0
  9. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/types/generated.py +464 -55
  10. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/utils/response_parser.py +64 -15
  11. {adcp-1.2.0 → adcp-1.3.0/src/adcp.egg-info}/PKG-INFO +138 -1
  12. {adcp-1.2.0 → adcp-1.3.0}/src/adcp.egg-info/SOURCES.txt +4 -0
  13. {adcp-1.2.0 → adcp-1.3.0}/tests/test_client.py +4 -1
  14. adcp-1.3.0/tests/test_discriminated_unions.py +404 -0
  15. adcp-1.3.0/tests/test_helpers.py +239 -0
  16. {adcp-1.2.0 → adcp-1.3.0}/tests/test_preview_html.py +38 -13
  17. {adcp-1.2.0 → adcp-1.3.0}/tests/test_protocols.py +0 -1
  18. adcp-1.2.0/src/adcp/__init__.py +0 -96
  19. {adcp-1.2.0 → adcp-1.3.0}/LICENSE +0 -0
  20. {adcp-1.2.0 → adcp-1.3.0}/setup.cfg +0 -0
  21. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/__main__.py +0 -0
  22. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/config.py +0 -0
  23. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/exceptions.py +0 -0
  24. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/protocols/__init__.py +0 -0
  25. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/protocols/a2a.py +0 -0
  26. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/protocols/mcp.py +0 -0
  27. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/types/__init__.py +0 -0
  28. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/types/core.py +0 -0
  29. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/types/tasks.py +0 -0
  30. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/utils/__init__.py +0 -0
  31. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/utils/operation_id.py +0 -0
  32. {adcp-1.2.0 → adcp-1.3.0}/src/adcp/utils/preview_cache.py +0 -0
  33. {adcp-1.2.0 → adcp-1.3.0}/src/adcp.egg-info/dependency_links.txt +0 -0
  34. {adcp-1.2.0 → adcp-1.3.0}/src/adcp.egg-info/entry_points.txt +0 -0
  35. {adcp-1.2.0 → adcp-1.3.0}/src/adcp.egg-info/requires.txt +0 -0
  36. {adcp-1.2.0 → adcp-1.3.0}/src/adcp.egg-info/top_level.txt +0 -0
  37. {adcp-1.2.0 → adcp-1.3.0}/tests/test_cli.py +0 -0
  38. {adcp-1.2.0 → adcp-1.3.0}/tests/test_code_generation.py +0 -0
  39. {adcp-1.2.0 → adcp-1.3.0}/tests/test_format_id_validation.py +0 -0
  40. {adcp-1.2.0 → adcp-1.3.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.2.0
3
+ Version: 1.3.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
@@ -59,8 +59,45 @@ AdCP operations are **distributed and asynchronous by default**. An agent might:
59
59
  pip install adcp
60
60
  ```
61
61
 
62
+ > **Note**: This client requires Python 3.10 or later and supports both synchronous and asynchronous workflows.
63
+
64
+ ## Quick Start: Test Helpers
65
+
66
+ The fastest way to get started is using the pre-configured test agents:
67
+
68
+ ```python
69
+ from adcp.testing import test_agent
70
+ from adcp.types.generated import GetProductsRequest
71
+
72
+ # Zero configuration - just import and use!
73
+ result = await test_agent.get_products(
74
+ GetProductsRequest(
75
+ brief="Coffee subscription service",
76
+ promoted_offering="Premium coffee deliveries"
77
+ )
78
+ )
79
+
80
+ if result.success:
81
+ print(f"Found {len(result.data.products)} products")
82
+ ```
83
+
84
+ Test helpers include:
85
+ - **`test_agent`**: Pre-configured MCP test agent with authentication
86
+ - **`test_agent_a2a`**: Pre-configured A2A test agent with authentication
87
+ - **`test_agent_no_auth`**: Pre-configured MCP test agent WITHOUT authentication
88
+ - **`test_agent_a2a_no_auth`**: Pre-configured A2A test agent WITHOUT authentication
89
+ - **`creative_agent`**: Reference creative agent for preview functionality
90
+ - **`test_agent_client`**: Multi-agent client with both protocols
91
+ - **`create_test_agent()`**: Factory for custom test configurations
92
+
93
+ > **Note**: Test agents are rate-limited and for testing/examples only. DO NOT use in production.
94
+
95
+ See [examples/test_helpers_demo.py](examples/test_helpers_demo.py) for more examples.
96
+
62
97
  ## Quick Start: Distributed Operations
63
98
 
99
+ For production use, configure your own agents:
100
+
64
101
  ```python
65
102
  from adcp import ADCPMultiAgentClient, AgentConfig, GetProductsRequest
66
103
 
@@ -110,6 +147,66 @@ async with ADCPMultiAgentClient(
110
147
 
111
148
  ## Features
112
149
 
150
+ ### Test Helpers
151
+
152
+ Pre-configured test agents for instant prototyping and testing:
153
+
154
+ ```python
155
+ from adcp.testing import (
156
+ test_agent, test_agent_a2a,
157
+ test_agent_no_auth, test_agent_a2a_no_auth,
158
+ creative_agent, test_agent_client, create_test_agent
159
+ )
160
+ from adcp.types.generated import GetProductsRequest, PreviewCreativeRequest
161
+
162
+ # 1. Single agent with authentication (MCP)
163
+ result = await test_agent.get_products(
164
+ GetProductsRequest(brief="Coffee brands")
165
+ )
166
+
167
+ # 2. Single agent with authentication (A2A)
168
+ result = await test_agent_a2a.get_products(
169
+ GetProductsRequest(brief="Coffee brands")
170
+ )
171
+
172
+ # 3. Single agent WITHOUT authentication (MCP)
173
+ # Useful for testing unauthenticated behavior
174
+ result = await test_agent_no_auth.get_products(
175
+ GetProductsRequest(brief="Coffee brands")
176
+ )
177
+
178
+ # 4. Single agent WITHOUT authentication (A2A)
179
+ result = await test_agent_a2a_no_auth.get_products(
180
+ GetProductsRequest(brief="Coffee brands")
181
+ )
182
+
183
+ # 5. Creative agent (preview functionality, no auth required)
184
+ result = await creative_agent.preview_creative(
185
+ PreviewCreativeRequest(
186
+ manifest={"format_id": "banner_300x250", "assets": {...}}
187
+ )
188
+ )
189
+
190
+ # 6. Multi-agent (parallel execution with both protocols)
191
+ results = await test_agent_client.get_products(
192
+ GetProductsRequest(brief="Coffee brands")
193
+ )
194
+
195
+ # 7. Custom configuration
196
+ from adcp.client import ADCPClient
197
+ config = create_test_agent(id="my-test", timeout=60.0)
198
+ client = ADCPClient(config)
199
+ ```
200
+
201
+ **Use cases:**
202
+ - Quick prototyping and experimentation
203
+ - Example code and documentation
204
+ - Integration testing without mock servers
205
+ - Testing authentication behavior (comparing auth vs no-auth results)
206
+ - Learning AdCP concepts
207
+
208
+ **Important:** Test agents are public, rate-limited, and for testing only. Never use in production.
209
+
113
210
  ### Full Protocol Support
114
211
  - **A2A Protocol**: Native support for Agent-to-Agent protocol
115
212
  - **MCP Protocol**: Native support for Model Context Protocol
@@ -375,6 +472,46 @@ uvx adcp --json myagent get_products '{"brief":"TV ads"}'
375
472
  uvx adcp --debug myagent get_products '{"brief":"TV ads"}'
376
473
  ```
377
474
 
475
+ ### Using Test Agents from CLI
476
+
477
+ The CLI provides easy access to public test agents without configuration:
478
+
479
+ ```bash
480
+ # Use test agent with authentication (MCP)
481
+ uvx adcp https://test-agent.adcontextprotocol.org/mcp/ \
482
+ --auth 1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ \
483
+ get_products '{"brief":"Coffee brands"}'
484
+
485
+ # Use test agent WITHOUT authentication (MCP)
486
+ uvx adcp https://test-agent.adcontextprotocol.org/mcp/ \
487
+ get_products '{"brief":"Coffee brands"}'
488
+
489
+ # Use test agent with authentication (A2A)
490
+ uvx adcp --protocol a2a \
491
+ --auth 1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ \
492
+ https://test-agent.adcontextprotocol.org \
493
+ get_products '{"brief":"Coffee brands"}'
494
+
495
+ # Save test agent for easier access
496
+ uvx adcp --save-auth test-agent https://test-agent.adcontextprotocol.org/mcp/ mcp
497
+ # Enter token when prompted: 1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ
498
+
499
+ # Now use saved config
500
+ uvx adcp test-agent get_products '{"brief":"Coffee brands"}'
501
+
502
+ # Use creative agent (no auth required)
503
+ uvx adcp https://creative.adcontextprotocol.org/mcp \
504
+ preview_creative @creative_manifest.json
505
+ ```
506
+
507
+ **Test Agent Details:**
508
+ - **URL (MCP)**: `https://test-agent.adcontextprotocol.org/mcp/`
509
+ - **URL (A2A)**: `https://test-agent.adcontextprotocol.org`
510
+ - **Auth Token**: `1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ` (optional, public token)
511
+ - **Rate Limited**: For testing only, not for production
512
+ - **No Auth Mode**: Omit `--auth` flag to test unauthenticated behavior
513
+ ```
514
+
378
515
  ### Configuration Management
379
516
 
380
517
  ```bash
@@ -22,8 +22,45 @@ AdCP operations are **distributed and asynchronous by default**. An agent might:
22
22
  pip install adcp
23
23
  ```
24
24
 
25
+ > **Note**: This client requires Python 3.10 or later and supports both synchronous and asynchronous workflows.
26
+
27
+ ## Quick Start: Test Helpers
28
+
29
+ The fastest way to get started is using the pre-configured test agents:
30
+
31
+ ```python
32
+ from adcp.testing import test_agent
33
+ from adcp.types.generated import GetProductsRequest
34
+
35
+ # Zero configuration - just import and use!
36
+ result = await test_agent.get_products(
37
+ GetProductsRequest(
38
+ brief="Coffee subscription service",
39
+ promoted_offering="Premium coffee deliveries"
40
+ )
41
+ )
42
+
43
+ if result.success:
44
+ print(f"Found {len(result.data.products)} products")
45
+ ```
46
+
47
+ Test helpers include:
48
+ - **`test_agent`**: Pre-configured MCP test agent with authentication
49
+ - **`test_agent_a2a`**: Pre-configured A2A test agent with authentication
50
+ - **`test_agent_no_auth`**: Pre-configured MCP test agent WITHOUT authentication
51
+ - **`test_agent_a2a_no_auth`**: Pre-configured A2A test agent WITHOUT authentication
52
+ - **`creative_agent`**: Reference creative agent for preview functionality
53
+ - **`test_agent_client`**: Multi-agent client with both protocols
54
+ - **`create_test_agent()`**: Factory for custom test configurations
55
+
56
+ > **Note**: Test agents are rate-limited and for testing/examples only. DO NOT use in production.
57
+
58
+ See [examples/test_helpers_demo.py](examples/test_helpers_demo.py) for more examples.
59
+
25
60
  ## Quick Start: Distributed Operations
26
61
 
62
+ For production use, configure your own agents:
63
+
27
64
  ```python
28
65
  from adcp import ADCPMultiAgentClient, AgentConfig, GetProductsRequest
29
66
 
@@ -73,6 +110,66 @@ async with ADCPMultiAgentClient(
73
110
 
74
111
  ## Features
75
112
 
113
+ ### Test Helpers
114
+
115
+ Pre-configured test agents for instant prototyping and testing:
116
+
117
+ ```python
118
+ from adcp.testing import (
119
+ test_agent, test_agent_a2a,
120
+ test_agent_no_auth, test_agent_a2a_no_auth,
121
+ creative_agent, test_agent_client, create_test_agent
122
+ )
123
+ from adcp.types.generated import GetProductsRequest, PreviewCreativeRequest
124
+
125
+ # 1. Single agent with authentication (MCP)
126
+ result = await test_agent.get_products(
127
+ GetProductsRequest(brief="Coffee brands")
128
+ )
129
+
130
+ # 2. Single agent with authentication (A2A)
131
+ result = await test_agent_a2a.get_products(
132
+ GetProductsRequest(brief="Coffee brands")
133
+ )
134
+
135
+ # 3. Single agent WITHOUT authentication (MCP)
136
+ # Useful for testing unauthenticated behavior
137
+ result = await test_agent_no_auth.get_products(
138
+ GetProductsRequest(brief="Coffee brands")
139
+ )
140
+
141
+ # 4. Single agent WITHOUT authentication (A2A)
142
+ result = await test_agent_a2a_no_auth.get_products(
143
+ GetProductsRequest(brief="Coffee brands")
144
+ )
145
+
146
+ # 5. Creative agent (preview functionality, no auth required)
147
+ result = await creative_agent.preview_creative(
148
+ PreviewCreativeRequest(
149
+ manifest={"format_id": "banner_300x250", "assets": {...}}
150
+ )
151
+ )
152
+
153
+ # 6. Multi-agent (parallel execution with both protocols)
154
+ results = await test_agent_client.get_products(
155
+ GetProductsRequest(brief="Coffee brands")
156
+ )
157
+
158
+ # 7. Custom configuration
159
+ from adcp.client import ADCPClient
160
+ config = create_test_agent(id="my-test", timeout=60.0)
161
+ client = ADCPClient(config)
162
+ ```
163
+
164
+ **Use cases:**
165
+ - Quick prototyping and experimentation
166
+ - Example code and documentation
167
+ - Integration testing without mock servers
168
+ - Testing authentication behavior (comparing auth vs no-auth results)
169
+ - Learning AdCP concepts
170
+
171
+ **Important:** Test agents are public, rate-limited, and for testing only. Never use in production.
172
+
76
173
  ### Full Protocol Support
77
174
  - **A2A Protocol**: Native support for Agent-to-Agent protocol
78
175
  - **MCP Protocol**: Native support for Model Context Protocol
@@ -338,6 +435,46 @@ uvx adcp --json myagent get_products '{"brief":"TV ads"}'
338
435
  uvx adcp --debug myagent get_products '{"brief":"TV ads"}'
339
436
  ```
340
437
 
438
+ ### Using Test Agents from CLI
439
+
440
+ The CLI provides easy access to public test agents without configuration:
441
+
442
+ ```bash
443
+ # Use test agent with authentication (MCP)
444
+ uvx adcp https://test-agent.adcontextprotocol.org/mcp/ \
445
+ --auth 1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ \
446
+ get_products '{"brief":"Coffee brands"}'
447
+
448
+ # Use test agent WITHOUT authentication (MCP)
449
+ uvx adcp https://test-agent.adcontextprotocol.org/mcp/ \
450
+ get_products '{"brief":"Coffee brands"}'
451
+
452
+ # Use test agent with authentication (A2A)
453
+ uvx adcp --protocol a2a \
454
+ --auth 1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ \
455
+ https://test-agent.adcontextprotocol.org \
456
+ get_products '{"brief":"Coffee brands"}'
457
+
458
+ # Save test agent for easier access
459
+ uvx adcp --save-auth test-agent https://test-agent.adcontextprotocol.org/mcp/ mcp
460
+ # Enter token when prompted: 1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ
461
+
462
+ # Now use saved config
463
+ uvx adcp test-agent get_products '{"brief":"Coffee brands"}'
464
+
465
+ # Use creative agent (no auth required)
466
+ uvx adcp https://creative.adcontextprotocol.org/mcp \
467
+ preview_creative @creative_manifest.json
468
+ ```
469
+
470
+ **Test Agent Details:**
471
+ - **URL (MCP)**: `https://test-agent.adcontextprotocol.org/mcp/`
472
+ - **URL (A2A)**: `https://test-agent.adcontextprotocol.org`
473
+ - **Auth Token**: `1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ` (optional, public token)
474
+ - **Rate Limited**: For testing only, not for production
475
+ - **No Auth Mode**: Omit `--auth` flag to test unauthenticated behavior
476
+ ```
477
+
341
478
  ### Configuration Management
342
479
 
343
480
  ```bash
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "adcp"
7
- version = "1.2.0"
7
+ version = "1.3.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"}
@@ -0,0 +1,289 @@
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.client import ADCPClient, ADCPMultiAgentClient
11
+ from adcp.exceptions import (
12
+ ADCPAuthenticationError,
13
+ ADCPConnectionError,
14
+ ADCPError,
15
+ ADCPProtocolError,
16
+ ADCPTimeoutError,
17
+ ADCPToolNotFoundError,
18
+ ADCPWebhookError,
19
+ ADCPWebhookSignatureError,
20
+ )
21
+
22
+ # Test helpers
23
+ from adcp.testing import (
24
+ CREATIVE_AGENT_CONFIG,
25
+ TEST_AGENT_A2A_CONFIG,
26
+ TEST_AGENT_MCP_CONFIG,
27
+ TEST_AGENT_TOKEN,
28
+ create_test_agent,
29
+ creative_agent,
30
+ test_agent,
31
+ test_agent_a2a,
32
+ test_agent_client,
33
+ )
34
+ from adcp.types.core import AgentConfig, Protocol, TaskResult, TaskStatus, WebhookMetadata
35
+ from adcp.types.generated import (
36
+ ActivateSignalError,
37
+ # Request/Response types
38
+ ActivateSignalRequest,
39
+ ActivateSignalResponse,
40
+ ActivateSignalSuccess,
41
+ ActivationKey,
42
+ AgentDeployment,
43
+ AgentDestination,
44
+ BothPreviewRender,
45
+ # Brand types
46
+ BrandManifest,
47
+ BrandManifestRef,
48
+ BuildCreativeRequest,
49
+ BuildCreativeResponse,
50
+ # Channel types
51
+ Channels,
52
+ CreateMediaBuyError,
53
+ CreateMediaBuyRequest,
54
+ CreateMediaBuyResponse,
55
+ CreateMediaBuySuccess,
56
+ # Creative types
57
+ CreativeAsset,
58
+ CreativeAssignment,
59
+ CreativeManifest,
60
+ CreativePolicy,
61
+ DaastAsset,
62
+ # Metrics types
63
+ DeliveryMetrics,
64
+ # Delivery types
65
+ DeliveryType,
66
+ Deployment,
67
+ # Deployment types
68
+ Destination,
69
+ Error,
70
+ Format,
71
+ FormatId,
72
+ FrequencyCap,
73
+ GetMediaBuyDeliveryRequest,
74
+ GetMediaBuyDeliveryResponse,
75
+ GetProductsRequest,
76
+ GetProductsResponse,
77
+ GetSignalsRequest,
78
+ GetSignalsResponse,
79
+ HtmlPreviewRender,
80
+ InlineDaastAsset,
81
+ InlineVastAsset,
82
+ Key_valueActivationKey,
83
+ ListAuthorizedPropertiesRequest,
84
+ ListAuthorizedPropertiesResponse,
85
+ ListCreativeFormatsRequest,
86
+ ListCreativeFormatsResponse,
87
+ ListCreativesRequest,
88
+ ListCreativesResponse,
89
+ Measurement,
90
+ # Core domain types
91
+ MediaBuy,
92
+ # Status enums
93
+ MediaBuyStatus,
94
+ # Sub-asset types
95
+ MediaSubAsset,
96
+ Pacing,
97
+ Package,
98
+ PackageStatus,
99
+ PerformanceFeedback,
100
+ Placement,
101
+ PlatformDeployment,
102
+ PlatformDestination,
103
+ PreviewCreativeRequest,
104
+ PreviewCreativeResponse,
105
+ # Preview render types
106
+ PreviewRender,
107
+ PricingModel,
108
+ # Pricing types
109
+ PricingOption,
110
+ Product,
111
+ PromotedProducts,
112
+ # Property and placement types
113
+ Property,
114
+ ProtocolEnvelope,
115
+ ProvidePerformanceFeedbackRequest,
116
+ ProvidePerformanceFeedbackResponse,
117
+ PushNotificationConfig,
118
+ ReportingCapabilities,
119
+ Response,
120
+ Segment_idActivationKey,
121
+ StandardFormatIds,
122
+ StartTiming,
123
+ SubAsset,
124
+ SyncCreativesError,
125
+ SyncCreativesRequest,
126
+ SyncCreativesResponse,
127
+ SyncCreativesSuccess,
128
+ # Targeting types
129
+ Targeting,
130
+ # Task types
131
+ TaskType,
132
+ TextSubAsset,
133
+ UpdateMediaBuyError,
134
+ UpdateMediaBuyRequest,
135
+ UpdateMediaBuyResponse,
136
+ UpdateMediaBuySuccess,
137
+ UrlDaastAsset,
138
+ UrlPreviewRender,
139
+ UrlVastAsset,
140
+ # Asset delivery types (VAST/DAAST)
141
+ VastAsset,
142
+ # Protocol types
143
+ WebhookPayload,
144
+ )
145
+ from adcp.types.generated import (
146
+ TaskStatus as GeneratedTaskStatus,
147
+ )
148
+
149
+ __version__ = "1.3.0"
150
+
151
+ __all__ = [
152
+ # Client classes
153
+ "ADCPClient",
154
+ "ADCPMultiAgentClient",
155
+ # Core types
156
+ "AgentConfig",
157
+ "Protocol",
158
+ "TaskResult",
159
+ "TaskStatus",
160
+ "WebhookMetadata",
161
+ # Test helpers
162
+ "test_agent",
163
+ "test_agent_a2a",
164
+ "creative_agent",
165
+ "test_agent_client",
166
+ "create_test_agent",
167
+ "TEST_AGENT_TOKEN",
168
+ "TEST_AGENT_MCP_CONFIG",
169
+ "TEST_AGENT_A2A_CONFIG",
170
+ "CREATIVE_AGENT_CONFIG",
171
+ # Exceptions
172
+ "ADCPError",
173
+ "ADCPConnectionError",
174
+ "ADCPAuthenticationError",
175
+ "ADCPTimeoutError",
176
+ "ADCPProtocolError",
177
+ "ADCPToolNotFoundError",
178
+ "ADCPWebhookError",
179
+ "ADCPWebhookSignatureError",
180
+ # Request/Response types
181
+ "ActivateSignalRequest",
182
+ "ActivateSignalResponse",
183
+ "ActivateSignalSuccess",
184
+ "ActivateSignalError",
185
+ "ActivationKey",
186
+ "Segment_idActivationKey",
187
+ "Key_valueActivationKey",
188
+ "BuildCreativeRequest",
189
+ "BuildCreativeResponse",
190
+ "CreateMediaBuyRequest",
191
+ "CreateMediaBuyResponse",
192
+ "CreateMediaBuySuccess",
193
+ "CreateMediaBuyError",
194
+ "GetMediaBuyDeliveryRequest",
195
+ "GetMediaBuyDeliveryResponse",
196
+ "GetProductsRequest",
197
+ "GetProductsResponse",
198
+ "GetSignalsRequest",
199
+ "GetSignalsResponse",
200
+ "ListAuthorizedPropertiesRequest",
201
+ "ListAuthorizedPropertiesResponse",
202
+ "ListCreativeFormatsRequest",
203
+ "ListCreativeFormatsResponse",
204
+ "ListCreativesRequest",
205
+ "ListCreativesResponse",
206
+ "PreviewCreativeRequest",
207
+ "PreviewCreativeResponse",
208
+ "ProvidePerformanceFeedbackRequest",
209
+ "ProvidePerformanceFeedbackResponse",
210
+ "SyncCreativesRequest",
211
+ "SyncCreativesResponse",
212
+ "SyncCreativesSuccess",
213
+ "SyncCreativesError",
214
+ "UpdateMediaBuyRequest",
215
+ "UpdateMediaBuyResponse",
216
+ "UpdateMediaBuySuccess",
217
+ "UpdateMediaBuyError",
218
+ # Core domain types
219
+ "MediaBuy",
220
+ "Product",
221
+ "Package",
222
+ "Error",
223
+ # Creative types
224
+ "CreativeAsset",
225
+ "CreativeManifest",
226
+ "CreativeAssignment",
227
+ "CreativePolicy",
228
+ "Format",
229
+ "FormatId",
230
+ # Property and placement types
231
+ "Property",
232
+ "Placement",
233
+ # Targeting types
234
+ "Targeting",
235
+ "FrequencyCap",
236
+ "Pacing",
237
+ # Brand types
238
+ "BrandManifest",
239
+ "BrandManifestRef",
240
+ # Metrics types
241
+ "DeliveryMetrics",
242
+ "Measurement",
243
+ "PerformanceFeedback",
244
+ # Status enums
245
+ "MediaBuyStatus",
246
+ "PackageStatus",
247
+ # Pricing types
248
+ "PricingOption",
249
+ "PricingModel",
250
+ # Delivery types
251
+ "DeliveryType",
252
+ "StartTiming",
253
+ # Channel types
254
+ "Channels",
255
+ "StandardFormatIds",
256
+ # Protocol types
257
+ "WebhookPayload",
258
+ "ProtocolEnvelope",
259
+ "Response",
260
+ "PromotedProducts",
261
+ "PushNotificationConfig",
262
+ "ReportingCapabilities",
263
+ # Deployment types
264
+ "Destination",
265
+ "Deployment",
266
+ "PlatformDestination",
267
+ "AgentDestination",
268
+ "PlatformDeployment",
269
+ "AgentDeployment",
270
+ # Sub-asset types
271
+ "MediaSubAsset",
272
+ "SubAsset",
273
+ "TextSubAsset",
274
+ # Asset delivery types (VAST/DAAST)
275
+ "VastAsset",
276
+ "UrlVastAsset",
277
+ "InlineVastAsset",
278
+ "DaastAsset",
279
+ "UrlDaastAsset",
280
+ "InlineDaastAsset",
281
+ # Preview render types
282
+ "PreviewRender",
283
+ "UrlPreviewRender",
284
+ "HtmlPreviewRender",
285
+ "BothPreviewRender",
286
+ # Task types
287
+ "TaskType",
288
+ "GeneratedTaskStatus",
289
+ ]
@@ -11,6 +11,8 @@ from collections.abc import Callable
11
11
  from datetime import datetime, timezone
12
12
  from typing import Any
13
13
 
14
+ from pydantic import BaseModel
15
+
14
16
  from adcp.exceptions import ADCPWebhookSignatureError
15
17
  from adcp.protocols.a2a import A2AAdapter
16
18
  from adcp.protocols.base import ProtocolAdapter
@@ -154,7 +156,9 @@ class ADCPClient:
154
156
  )
155
157
  )
156
158
 
157
- result = self.adapter._parse_response(raw_result, GetProductsResponse)
159
+ result: TaskResult[GetProductsResponse] = self.adapter._parse_response(
160
+ raw_result, GetProductsResponse
161
+ )
158
162
 
159
163
  if fetch_previews and result.success and result.data and creative_agent_client:
160
164
  from adcp.utils.preview_cache import add_preview_urls_to_products
@@ -215,7 +219,9 @@ class ADCPClient:
215
219
  )
216
220
  )
217
221
 
218
- result = self.adapter._parse_response(raw_result, ListCreativeFormatsResponse)
222
+ result: TaskResult[ListCreativeFormatsResponse] = self.adapter._parse_response(
223
+ raw_result, ListCreativeFormatsResponse
224
+ )
219
225
 
220
226
  if fetch_previews and result.success and result.data:
221
227
  from adcp.utils.preview_cache import add_preview_urls_to_formats
@@ -617,15 +623,16 @@ class ADCPClient:
617
623
  from adcp.utils.response_parser import parse_json_or_text
618
624
 
619
625
  # Map task types to their response types (using string literals, not enum)
620
- response_type_map: dict[str, type] = {
626
+ # Note: Some response types are Union types (e.g., ActivateSignalResponse = Success | Error)
627
+ response_type_map: dict[str, type[BaseModel] | Any] = {
621
628
  "get_products": GetProductsResponse,
622
629
  "list_creative_formats": ListCreativeFormatsResponse,
623
- "sync_creatives": SyncCreativesResponse,
630
+ "sync_creatives": SyncCreativesResponse, # Union type
624
631
  "list_creatives": ListCreativesResponse,
625
632
  "get_media_buy_delivery": GetMediaBuyDeliveryResponse,
626
633
  "list_authorized_properties": ListAuthorizedPropertiesResponse,
627
634
  "get_signals": GetSignalsResponse,
628
- "activate_signal": ActivateSignalResponse,
635
+ "activate_signal": ActivateSignalResponse, # Union type
629
636
  "provide_performance_feedback": ProvidePerformanceFeedbackResponse,
630
637
  }
631
638
 
@@ -30,15 +30,18 @@ class ProtocolAdapter(ABC):
30
30
  # Helper methods for response parsing
31
31
  # ========================================================================
32
32
 
33
- def _parse_response(self, raw_result: TaskResult[Any], response_type: type[T]) -> TaskResult[T]:
33
+ def _parse_response(
34
+ self, raw_result: TaskResult[Any], response_type: type[T] | Any
35
+ ) -> TaskResult[T]:
34
36
  """
35
37
  Parse raw TaskResult into typed TaskResult.
36
38
 
37
39
  Handles both MCP content arrays and A2A dict responses.
40
+ Supports both single types and Union types (for oneOf discriminated unions).
38
41
 
39
42
  Args:
40
43
  raw_result: Raw TaskResult from adapter
41
- response_type: Expected Pydantic response type
44
+ response_type: Expected Pydantic response type (can be a Union type)
42
45
 
43
46
  Returns:
44
47
  Typed TaskResult