adcp 2.7.0__tar.gz → 2.9.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.
- {adcp-2.7.0/src/adcp.egg-info → adcp-2.9.0}/PKG-INFO +172 -1
- {adcp-2.7.0 → adcp-2.9.0}/README.md +171 -0
- {adcp-2.7.0 → adcp-2.9.0}/pyproject.toml +1 -1
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/__init__.py +7 -4
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/__main__.py +31 -3
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/client.py +200 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/protocols/a2a.py +12 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/protocols/base.py +15 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/protocols/mcp.py +12 -0
- adcp-2.9.0/src/adcp/types/__init__.py +557 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/_generated.py +37 -38
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/aliases.py +251 -46
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/activate_signal_request.py +3 -3
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/activate_signal_response.py +2 -2
- adcp-2.9.0/src/adcp/types/generated_poc/asset_content_type.py +23 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/brand_manifest.py +8 -8
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/create_media_buy_response.py +16 -21
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/deployment.py +6 -6
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/destination.py +4 -4
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/format.py +5 -30
- adcp-2.9.0/src/adcp/types/generated_poc/format_category.py +17 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_signals_request.py +4 -4
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_signals_response.py +2 -2
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_creative_formats_request.py +4 -22
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/update_media_buy_response.py +15 -22
- adcp-2.9.0/src/adcp/types/stable.py +449 -0
- {adcp-2.7.0 → adcp-2.9.0/src/adcp.egg-info}/PKG-INFO +172 -1
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/SOURCES.txt +2 -1
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_cli.py +53 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_client.py +8 -2
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_type_aliases.py +2 -104
- adcp-2.7.0/src/adcp/types/__init__.py +0 -127
- adcp-2.7.0/src/adcp/types/generated_poc/asset_type.py +0 -100
- adcp-2.7.0/src/adcp/types/stable.py +0 -188
- {adcp-2.7.0 → adcp-2.9.0}/LICENSE +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/setup.cfg +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/adagents.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/config.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/exceptions.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/protocols/__init__.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/py.typed +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/simple.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/testing/__init__.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/testing/test_helpers.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/base.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/core.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/__init__.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/activation_key.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/adagents.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/audio_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/build_creative_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/build_creative_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/channels.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpc_option.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpcv_option.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpm_auction_option.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpm_fixed_option.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpp_option.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpv_option.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/create_media_buy_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_assignment.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_manifest.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_policy.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_status.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/css_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/daast_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/delivery_metrics.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/delivery_type.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/error.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/flat_rate_option.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/format_id.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/frequency_cap.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/frequency_cap_scope.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_media_buy_delivery_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_media_buy_delivery_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_products_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_products_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/html_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/identifier_types.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/image_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/javascript_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_authorized_properties_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_authorized_properties_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_creative_formats_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_creatives_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_creatives_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/markdown_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/measurement.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/media_buy.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/media_buy_status.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/pacing.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/package.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/package_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/package_status.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/performance_feedback.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/placement.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/preview_creative_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/preview_creative_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/preview_render.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/pricing_model.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/product.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/promoted_offerings.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/promoted_products.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/property.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/protocol_envelope.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/provide_performance_feedback_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/provide_performance_feedback_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/publisher_identifier_types.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/publisher_property_selector.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/push_notification_config.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/reporting_capabilities.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/standard_format_ids.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/sub_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/sync_creatives_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/sync_creatives_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/targeting.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/task_status.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/task_type.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/tasks_get_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/tasks_get_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/tasks_list_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/tasks_list_response.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/text_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/update_media_buy_request.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/url_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/vast_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/vcpm_auction_option.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/vcpm_fixed_option.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/video_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/webhook_asset.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/webhook_payload.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/utils/__init__.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/utils/operation_id.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/utils/preview_cache.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/utils/response_parser.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp/validation.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/dependency_links.txt +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/entry_points.txt +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/requires.txt +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/top_level.txt +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_adagents.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_code_generation.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_discriminated_unions.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_format_id_validation.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_helpers.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_preview_html.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_protocols.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_public_api.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_response_parser.py +0 -0
- {adcp-2.7.0 → adcp-2.9.0}/tests/test_simple_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: adcp
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.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
|
|
@@ -507,12 +507,183 @@ All AdCP tools with full type safety:
|
|
|
507
507
|
- `list_creatives()` - List creative assets
|
|
508
508
|
- `get_media_buy_delivery()` - Get delivery performance
|
|
509
509
|
|
|
510
|
+
**Creative Management:**
|
|
511
|
+
- `preview_creative()` - Preview creative before building
|
|
512
|
+
- `build_creative()` - Generate production-ready creative assets
|
|
513
|
+
|
|
510
514
|
**Audience & Targeting:**
|
|
511
515
|
- `list_authorized_properties()` - Get authorized properties
|
|
512
516
|
- `get_signals()` - Get audience signals
|
|
513
517
|
- `activate_signal()` - Activate audience signals
|
|
514
518
|
- `provide_performance_feedback()` - Send performance feedback
|
|
515
519
|
|
|
520
|
+
## Workflow Examples
|
|
521
|
+
|
|
522
|
+
### Complete Media Buy Workflow
|
|
523
|
+
|
|
524
|
+
A typical media buy workflow involves discovering products, creating the buy, and managing creatives:
|
|
525
|
+
|
|
526
|
+
```python
|
|
527
|
+
from adcp import ADCPClient, AgentConfig, GetProductsRequest, CreateMediaBuyRequest
|
|
528
|
+
from adcp import BrandManifest, PublisherPropertiesAll
|
|
529
|
+
|
|
530
|
+
# 1. Connect to agent
|
|
531
|
+
config = AgentConfig(id="sales_agent", agent_uri="https://...", protocol="mcp")
|
|
532
|
+
async with ADCPClient(config) as client:
|
|
533
|
+
|
|
534
|
+
# 2. Discover available products
|
|
535
|
+
products_result = await client.get_products(
|
|
536
|
+
GetProductsRequest(brief="Premium video inventory for coffee brand")
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
if products_result.success:
|
|
540
|
+
product = products_result.data.products[0]
|
|
541
|
+
print(f"Found product: {product.name}")
|
|
542
|
+
|
|
543
|
+
# 3. Create media buy reservation
|
|
544
|
+
media_buy_result = await client.create_media_buy(
|
|
545
|
+
CreateMediaBuyRequest(
|
|
546
|
+
brand_manifest=BrandManifest(
|
|
547
|
+
name="Coffee Co",
|
|
548
|
+
brand_url="https://coffeeco.com",
|
|
549
|
+
logo_url="https://coffeeco.com/logo.png",
|
|
550
|
+
# ... additional brand details
|
|
551
|
+
),
|
|
552
|
+
packages=[{
|
|
553
|
+
"package_id": product.packages[0].package_id,
|
|
554
|
+
"quantity": 1000000 # impressions
|
|
555
|
+
}],
|
|
556
|
+
publisher_properties=PublisherPropertiesAll(
|
|
557
|
+
selection_type="all" # Target all authorized properties
|
|
558
|
+
)
|
|
559
|
+
)
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
if media_buy_result.success:
|
|
563
|
+
media_buy_id = media_buy_result.data.media_buy_id
|
|
564
|
+
print(f"✅ Media buy created: {media_buy_id}")
|
|
565
|
+
|
|
566
|
+
# 4. Update media buy if needed
|
|
567
|
+
from adcp import UpdateMediaBuyPackagesRequest
|
|
568
|
+
|
|
569
|
+
update_result = await client.update_media_buy(
|
|
570
|
+
UpdateMediaBuyPackagesRequest(
|
|
571
|
+
media_buy_id=media_buy_id,
|
|
572
|
+
packages=[{
|
|
573
|
+
"package_id": product.packages[0].package_id,
|
|
574
|
+
"quantity": 1500000 # Increase budget
|
|
575
|
+
}]
|
|
576
|
+
)
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
if update_result.success:
|
|
580
|
+
print("✅ Media buy updated")
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Complete Creative Workflow
|
|
584
|
+
|
|
585
|
+
Build and deliver production-ready creatives:
|
|
586
|
+
|
|
587
|
+
```python
|
|
588
|
+
from adcp import ADCPClient, AgentConfig
|
|
589
|
+
from adcp import PreviewCreativeFormatRequest, BuildCreativeRequest
|
|
590
|
+
from adcp import CreativeManifest, PlatformDeployment
|
|
591
|
+
|
|
592
|
+
# 1. Connect to creative agent
|
|
593
|
+
config = AgentConfig(id="creative_agent", agent_uri="https://...", protocol="mcp")
|
|
594
|
+
async with ADCPClient(config) as client:
|
|
595
|
+
|
|
596
|
+
# 2. List available formats
|
|
597
|
+
formats_result = await client.list_creative_formats()
|
|
598
|
+
|
|
599
|
+
if formats_result.success:
|
|
600
|
+
format_id = formats_result.data.formats[0].format_id
|
|
601
|
+
print(f"Using format: {format_id.id}")
|
|
602
|
+
|
|
603
|
+
# 3. Preview creative (test before building)
|
|
604
|
+
preview_result = await client.preview_creative(
|
|
605
|
+
PreviewCreativeFormatRequest(
|
|
606
|
+
target_format_id=format_id.id,
|
|
607
|
+
inputs={
|
|
608
|
+
"headline": "Fresh Coffee Daily",
|
|
609
|
+
"cta": "Order Now"
|
|
610
|
+
},
|
|
611
|
+
output_format="url" # Get preview URL
|
|
612
|
+
)
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
if preview_result.success:
|
|
616
|
+
preview_url = preview_result.data.renders[0].url
|
|
617
|
+
print(f"Preview at: {preview_url}")
|
|
618
|
+
|
|
619
|
+
# 4. Build production creative
|
|
620
|
+
build_result = await client.build_creative(
|
|
621
|
+
BuildCreativeRequest(
|
|
622
|
+
manifest=CreativeManifest(
|
|
623
|
+
format_id=format_id,
|
|
624
|
+
brand_url="https://coffeeco.com",
|
|
625
|
+
# ... creative content
|
|
626
|
+
),
|
|
627
|
+
target_format_id=format_id.id,
|
|
628
|
+
deployment=PlatformDeployment(
|
|
629
|
+
type="platform",
|
|
630
|
+
platform_id="google_admanager"
|
|
631
|
+
)
|
|
632
|
+
)
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
if build_result.success:
|
|
636
|
+
vast_url = build_result.data.assets[0].url
|
|
637
|
+
print(f"✅ Creative ready: {vast_url}")
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### Integrated Workflow: Media Buy + Creatives
|
|
641
|
+
|
|
642
|
+
Combine both workflows for a complete campaign setup:
|
|
643
|
+
|
|
644
|
+
```python
|
|
645
|
+
from adcp import ADCPMultiAgentClient, AgentConfig
|
|
646
|
+
from adcp import GetProductsRequest, CreateMediaBuyRequest, BuildCreativeRequest
|
|
647
|
+
|
|
648
|
+
# Connect to both sales and creative agents
|
|
649
|
+
async with ADCPMultiAgentClient(
|
|
650
|
+
agents=[
|
|
651
|
+
AgentConfig(id="sales", agent_uri="https://sales-agent.com", protocol="mcp"),
|
|
652
|
+
AgentConfig(id="creative", agent_uri="https://creative-agent.com", protocol="mcp"),
|
|
653
|
+
]
|
|
654
|
+
) as client:
|
|
655
|
+
|
|
656
|
+
# 1. Get products from sales agent
|
|
657
|
+
sales_agent = client.agent("sales")
|
|
658
|
+
products = await sales_agent.simple.get_products(
|
|
659
|
+
brief="Premium video inventory"
|
|
660
|
+
)
|
|
661
|
+
|
|
662
|
+
# 2. Get creative formats from creative agent
|
|
663
|
+
creative_agent = client.agent("creative")
|
|
664
|
+
formats = await creative_agent.simple.list_creative_formats()
|
|
665
|
+
|
|
666
|
+
# 3. Build creative asset
|
|
667
|
+
creative_result = await creative_agent.build_creative(
|
|
668
|
+
BuildCreativeRequest(
|
|
669
|
+
manifest=creative_manifest,
|
|
670
|
+
target_format_id=formats.formats[0].format_id.id
|
|
671
|
+
)
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
# 4. Create media buy with creative
|
|
675
|
+
media_buy_result = await sales_agent.create_media_buy(
|
|
676
|
+
CreateMediaBuyRequest(
|
|
677
|
+
brand_manifest=brand_manifest,
|
|
678
|
+
packages=[{"package_id": products.products[0].packages[0].package_id}],
|
|
679
|
+
publisher_properties=publisher_properties,
|
|
680
|
+
creative_urls=[creative_result.data.assets[0].url]
|
|
681
|
+
)
|
|
682
|
+
)
|
|
683
|
+
|
|
684
|
+
print(f"✅ Campaign live: {media_buy_result.data.media_buy_id}")
|
|
685
|
+
```
|
|
686
|
+
|
|
516
687
|
## Property Discovery (AdCP v2.2.0)
|
|
517
688
|
|
|
518
689
|
Build agent registries by discovering properties agents can sell:
|
|
@@ -466,12 +466,183 @@ All AdCP tools with full type safety:
|
|
|
466
466
|
- `list_creatives()` - List creative assets
|
|
467
467
|
- `get_media_buy_delivery()` - Get delivery performance
|
|
468
468
|
|
|
469
|
+
**Creative Management:**
|
|
470
|
+
- `preview_creative()` - Preview creative before building
|
|
471
|
+
- `build_creative()` - Generate production-ready creative assets
|
|
472
|
+
|
|
469
473
|
**Audience & Targeting:**
|
|
470
474
|
- `list_authorized_properties()` - Get authorized properties
|
|
471
475
|
- `get_signals()` - Get audience signals
|
|
472
476
|
- `activate_signal()` - Activate audience signals
|
|
473
477
|
- `provide_performance_feedback()` - Send performance feedback
|
|
474
478
|
|
|
479
|
+
## Workflow Examples
|
|
480
|
+
|
|
481
|
+
### Complete Media Buy Workflow
|
|
482
|
+
|
|
483
|
+
A typical media buy workflow involves discovering products, creating the buy, and managing creatives:
|
|
484
|
+
|
|
485
|
+
```python
|
|
486
|
+
from adcp import ADCPClient, AgentConfig, GetProductsRequest, CreateMediaBuyRequest
|
|
487
|
+
from adcp import BrandManifest, PublisherPropertiesAll
|
|
488
|
+
|
|
489
|
+
# 1. Connect to agent
|
|
490
|
+
config = AgentConfig(id="sales_agent", agent_uri="https://...", protocol="mcp")
|
|
491
|
+
async with ADCPClient(config) as client:
|
|
492
|
+
|
|
493
|
+
# 2. Discover available products
|
|
494
|
+
products_result = await client.get_products(
|
|
495
|
+
GetProductsRequest(brief="Premium video inventory for coffee brand")
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
if products_result.success:
|
|
499
|
+
product = products_result.data.products[0]
|
|
500
|
+
print(f"Found product: {product.name}")
|
|
501
|
+
|
|
502
|
+
# 3. Create media buy reservation
|
|
503
|
+
media_buy_result = await client.create_media_buy(
|
|
504
|
+
CreateMediaBuyRequest(
|
|
505
|
+
brand_manifest=BrandManifest(
|
|
506
|
+
name="Coffee Co",
|
|
507
|
+
brand_url="https://coffeeco.com",
|
|
508
|
+
logo_url="https://coffeeco.com/logo.png",
|
|
509
|
+
# ... additional brand details
|
|
510
|
+
),
|
|
511
|
+
packages=[{
|
|
512
|
+
"package_id": product.packages[0].package_id,
|
|
513
|
+
"quantity": 1000000 # impressions
|
|
514
|
+
}],
|
|
515
|
+
publisher_properties=PublisherPropertiesAll(
|
|
516
|
+
selection_type="all" # Target all authorized properties
|
|
517
|
+
)
|
|
518
|
+
)
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
if media_buy_result.success:
|
|
522
|
+
media_buy_id = media_buy_result.data.media_buy_id
|
|
523
|
+
print(f"✅ Media buy created: {media_buy_id}")
|
|
524
|
+
|
|
525
|
+
# 4. Update media buy if needed
|
|
526
|
+
from adcp import UpdateMediaBuyPackagesRequest
|
|
527
|
+
|
|
528
|
+
update_result = await client.update_media_buy(
|
|
529
|
+
UpdateMediaBuyPackagesRequest(
|
|
530
|
+
media_buy_id=media_buy_id,
|
|
531
|
+
packages=[{
|
|
532
|
+
"package_id": product.packages[0].package_id,
|
|
533
|
+
"quantity": 1500000 # Increase budget
|
|
534
|
+
}]
|
|
535
|
+
)
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
if update_result.success:
|
|
539
|
+
print("✅ Media buy updated")
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### Complete Creative Workflow
|
|
543
|
+
|
|
544
|
+
Build and deliver production-ready creatives:
|
|
545
|
+
|
|
546
|
+
```python
|
|
547
|
+
from adcp import ADCPClient, AgentConfig
|
|
548
|
+
from adcp import PreviewCreativeFormatRequest, BuildCreativeRequest
|
|
549
|
+
from adcp import CreativeManifest, PlatformDeployment
|
|
550
|
+
|
|
551
|
+
# 1. Connect to creative agent
|
|
552
|
+
config = AgentConfig(id="creative_agent", agent_uri="https://...", protocol="mcp")
|
|
553
|
+
async with ADCPClient(config) as client:
|
|
554
|
+
|
|
555
|
+
# 2. List available formats
|
|
556
|
+
formats_result = await client.list_creative_formats()
|
|
557
|
+
|
|
558
|
+
if formats_result.success:
|
|
559
|
+
format_id = formats_result.data.formats[0].format_id
|
|
560
|
+
print(f"Using format: {format_id.id}")
|
|
561
|
+
|
|
562
|
+
# 3. Preview creative (test before building)
|
|
563
|
+
preview_result = await client.preview_creative(
|
|
564
|
+
PreviewCreativeFormatRequest(
|
|
565
|
+
target_format_id=format_id.id,
|
|
566
|
+
inputs={
|
|
567
|
+
"headline": "Fresh Coffee Daily",
|
|
568
|
+
"cta": "Order Now"
|
|
569
|
+
},
|
|
570
|
+
output_format="url" # Get preview URL
|
|
571
|
+
)
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
if preview_result.success:
|
|
575
|
+
preview_url = preview_result.data.renders[0].url
|
|
576
|
+
print(f"Preview at: {preview_url}")
|
|
577
|
+
|
|
578
|
+
# 4. Build production creative
|
|
579
|
+
build_result = await client.build_creative(
|
|
580
|
+
BuildCreativeRequest(
|
|
581
|
+
manifest=CreativeManifest(
|
|
582
|
+
format_id=format_id,
|
|
583
|
+
brand_url="https://coffeeco.com",
|
|
584
|
+
# ... creative content
|
|
585
|
+
),
|
|
586
|
+
target_format_id=format_id.id,
|
|
587
|
+
deployment=PlatformDeployment(
|
|
588
|
+
type="platform",
|
|
589
|
+
platform_id="google_admanager"
|
|
590
|
+
)
|
|
591
|
+
)
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
if build_result.success:
|
|
595
|
+
vast_url = build_result.data.assets[0].url
|
|
596
|
+
print(f"✅ Creative ready: {vast_url}")
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Integrated Workflow: Media Buy + Creatives
|
|
600
|
+
|
|
601
|
+
Combine both workflows for a complete campaign setup:
|
|
602
|
+
|
|
603
|
+
```python
|
|
604
|
+
from adcp import ADCPMultiAgentClient, AgentConfig
|
|
605
|
+
from adcp import GetProductsRequest, CreateMediaBuyRequest, BuildCreativeRequest
|
|
606
|
+
|
|
607
|
+
# Connect to both sales and creative agents
|
|
608
|
+
async with ADCPMultiAgentClient(
|
|
609
|
+
agents=[
|
|
610
|
+
AgentConfig(id="sales", agent_uri="https://sales-agent.com", protocol="mcp"),
|
|
611
|
+
AgentConfig(id="creative", agent_uri="https://creative-agent.com", protocol="mcp"),
|
|
612
|
+
]
|
|
613
|
+
) as client:
|
|
614
|
+
|
|
615
|
+
# 1. Get products from sales agent
|
|
616
|
+
sales_agent = client.agent("sales")
|
|
617
|
+
products = await sales_agent.simple.get_products(
|
|
618
|
+
brief="Premium video inventory"
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
# 2. Get creative formats from creative agent
|
|
622
|
+
creative_agent = client.agent("creative")
|
|
623
|
+
formats = await creative_agent.simple.list_creative_formats()
|
|
624
|
+
|
|
625
|
+
# 3. Build creative asset
|
|
626
|
+
creative_result = await creative_agent.build_creative(
|
|
627
|
+
BuildCreativeRequest(
|
|
628
|
+
manifest=creative_manifest,
|
|
629
|
+
target_format_id=formats.formats[0].format_id.id
|
|
630
|
+
)
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
# 4. Create media buy with creative
|
|
634
|
+
media_buy_result = await sales_agent.create_media_buy(
|
|
635
|
+
CreateMediaBuyRequest(
|
|
636
|
+
brand_manifest=brand_manifest,
|
|
637
|
+
packages=[{"package_id": products.products[0].packages[0].package_id}],
|
|
638
|
+
publisher_properties=publisher_properties,
|
|
639
|
+
creative_urls=[creative_result.data.assets[0].url]
|
|
640
|
+
)
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
print(f"✅ Campaign live: {media_buy_result.data.media_buy_id}")
|
|
644
|
+
```
|
|
645
|
+
|
|
475
646
|
## Property Discovery (AdCP v2.2.0)
|
|
476
647
|
|
|
477
648
|
Build agent registries by discovering properties agents can sell:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "adcp"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.9.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"}
|
|
@@ -65,7 +65,6 @@ from adcp.types.aliases import (
|
|
|
65
65
|
BothPreviewRender,
|
|
66
66
|
BuildCreativeErrorResponse,
|
|
67
67
|
BuildCreativeSuccessResponse,
|
|
68
|
-
CreatedPackageReference,
|
|
69
68
|
CreateMediaBuyErrorResponse,
|
|
70
69
|
CreateMediaBuySuccessResponse,
|
|
71
70
|
HtmlPreviewRender,
|
|
@@ -109,6 +108,8 @@ from adcp.types.stable import (
|
|
|
109
108
|
# Audience & Targeting
|
|
110
109
|
ActivateSignalRequest,
|
|
111
110
|
ActivateSignalResponse,
|
|
111
|
+
# Type enums from PR #222
|
|
112
|
+
AssetContentType,
|
|
112
113
|
# Core domain types
|
|
113
114
|
BrandManifest,
|
|
114
115
|
# Creative Operations
|
|
@@ -132,6 +133,7 @@ from adcp.types.stable import (
|
|
|
132
133
|
Error,
|
|
133
134
|
FlatRatePricingOption,
|
|
134
135
|
Format,
|
|
136
|
+
FormatCategory,
|
|
135
137
|
FormatId,
|
|
136
138
|
GetMediaBuyDeliveryRequest,
|
|
137
139
|
GetMediaBuyDeliveryResponse,
|
|
@@ -177,7 +179,7 @@ from adcp.validation import (
|
|
|
177
179
|
validate_publisher_properties_item,
|
|
178
180
|
)
|
|
179
181
|
|
|
180
|
-
__version__ = "2.
|
|
182
|
+
__version__ = "2.9.0"
|
|
181
183
|
|
|
182
184
|
__all__ = [
|
|
183
185
|
# Client classes
|
|
@@ -219,6 +221,9 @@ __all__ = [
|
|
|
219
221
|
"Error",
|
|
220
222
|
"Format",
|
|
221
223
|
"FormatId",
|
|
224
|
+
# New type enums from PR #222
|
|
225
|
+
"AssetContentType",
|
|
226
|
+
"FormatCategory",
|
|
222
227
|
"Product",
|
|
223
228
|
"Property",
|
|
224
229
|
# Core domain types (from stable API)
|
|
@@ -228,8 +233,6 @@ __all__ = [
|
|
|
228
233
|
"MediaBuy",
|
|
229
234
|
"Package",
|
|
230
235
|
"PackageRequest",
|
|
231
|
-
# Package type aliases
|
|
232
|
-
"CreatedPackageReference",
|
|
233
236
|
# Status enums (for control flow)
|
|
234
237
|
"CreativeStatus",
|
|
235
238
|
"MediaBuyStatus",
|
|
@@ -83,11 +83,17 @@ async def execute_tool(
|
|
|
83
83
|
|
|
84
84
|
# Tool dispatch mapping - single source of truth for ADCP methods
|
|
85
85
|
# Types are filled at runtime to avoid circular imports
|
|
86
|
+
# Special case: list_tools takes no parameters (None means no request type)
|
|
86
87
|
TOOL_DISPATCH: dict[str, tuple[str, type | None]] = {
|
|
88
|
+
"list_tools": ("list_tools", None), # Protocol introspection - no request type
|
|
87
89
|
"get_products": ("get_products", None),
|
|
88
90
|
"list_creative_formats": ("list_creative_formats", None),
|
|
91
|
+
"preview_creative": ("preview_creative", None),
|
|
92
|
+
"build_creative": ("build_creative", None),
|
|
89
93
|
"sync_creatives": ("sync_creatives", None),
|
|
90
94
|
"list_creatives": ("list_creatives", None),
|
|
95
|
+
"create_media_buy": ("create_media_buy", None),
|
|
96
|
+
"update_media_buy": ("update_media_buy", None),
|
|
91
97
|
"get_media_buy_delivery": ("get_media_buy_delivery", None),
|
|
92
98
|
"list_authorized_properties": ("list_authorized_properties", None),
|
|
93
99
|
"get_signals": ("get_signals", None),
|
|
@@ -122,8 +128,12 @@ async def _dispatch_tool(client: ADCPClient, tool_name: str, payload: dict[str,
|
|
|
122
128
|
"list_creative_formats",
|
|
123
129
|
gen.ListCreativeFormatsRequest,
|
|
124
130
|
)
|
|
131
|
+
TOOL_DISPATCH["preview_creative"] = ("preview_creative", gen.PreviewCreativeRequest)
|
|
132
|
+
TOOL_DISPATCH["build_creative"] = ("build_creative", gen.BuildCreativeRequest)
|
|
125
133
|
TOOL_DISPATCH["sync_creatives"] = ("sync_creatives", gen.SyncCreativesRequest)
|
|
126
134
|
TOOL_DISPATCH["list_creatives"] = ("list_creatives", gen.ListCreativesRequest)
|
|
135
|
+
TOOL_DISPATCH["create_media_buy"] = ("create_media_buy", gen.CreateMediaBuyRequest)
|
|
136
|
+
TOOL_DISPATCH["update_media_buy"] = ("update_media_buy", gen.UpdateMediaBuyRequest)
|
|
127
137
|
TOOL_DISPATCH["get_media_buy_delivery"] = (
|
|
128
138
|
"get_media_buy_delivery",
|
|
129
139
|
gen.GetMediaBuyDeliveryRequest,
|
|
@@ -144,21 +154,38 @@ async def _dispatch_tool(client: ADCPClient, tool_name: str, payload: dict[str,
|
|
|
144
154
|
available = ", ".join(sorted(TOOL_DISPATCH.keys()))
|
|
145
155
|
return TaskResult(
|
|
146
156
|
status=TaskStatus.FAILED,
|
|
157
|
+
success=False,
|
|
147
158
|
error=f"Unknown tool: {tool_name}. Available tools: {available}",
|
|
148
159
|
)
|
|
149
160
|
|
|
150
161
|
# Get method and request type
|
|
151
162
|
method_name, request_type = TOOL_DISPATCH[tool_name]
|
|
163
|
+
method = getattr(client, method_name)
|
|
152
164
|
|
|
153
|
-
#
|
|
165
|
+
# Special case: list_tools takes no parameters and returns list[str], not TaskResult
|
|
166
|
+
if tool_name == "list_tools":
|
|
167
|
+
try:
|
|
168
|
+
tools = await method()
|
|
169
|
+
return TaskResult(
|
|
170
|
+
status=TaskStatus.COMPLETED,
|
|
171
|
+
data={"tools": tools},
|
|
172
|
+
success=True,
|
|
173
|
+
)
|
|
174
|
+
except Exception as e:
|
|
175
|
+
return TaskResult(
|
|
176
|
+
status=TaskStatus.FAILED,
|
|
177
|
+
success=False,
|
|
178
|
+
error=f"Failed to list tools: {e}",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Type guard - request_type should be initialized by this point for non-list_tools
|
|
154
182
|
if request_type is None:
|
|
155
183
|
return TaskResult(
|
|
156
184
|
status=TaskStatus.FAILED,
|
|
185
|
+
success=False,
|
|
157
186
|
error=f"Internal error: {tool_name} request type not initialized",
|
|
158
187
|
)
|
|
159
188
|
|
|
160
|
-
method = getattr(client, method_name)
|
|
161
|
-
|
|
162
189
|
# Validate and invoke
|
|
163
190
|
try:
|
|
164
191
|
request = request_type(**payload)
|
|
@@ -173,6 +200,7 @@ async def _dispatch_tool(client: ADCPClient, tool_name: str, payload: dict[str,
|
|
|
173
200
|
|
|
174
201
|
return TaskResult(
|
|
175
202
|
status=TaskStatus.FAILED,
|
|
203
|
+
success=False,
|
|
176
204
|
error=f"Invalid request payload for {tool_name}:\n" + "\n".join(error_details),
|
|
177
205
|
)
|
|
178
206
|
|