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.
Files changed (152) hide show
  1. {adcp-2.7.0/src/adcp.egg-info → adcp-2.9.0}/PKG-INFO +172 -1
  2. {adcp-2.7.0 → adcp-2.9.0}/README.md +171 -0
  3. {adcp-2.7.0 → adcp-2.9.0}/pyproject.toml +1 -1
  4. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/__init__.py +7 -4
  5. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/__main__.py +31 -3
  6. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/client.py +200 -0
  7. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/protocols/a2a.py +12 -0
  8. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/protocols/base.py +15 -0
  9. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/protocols/mcp.py +12 -0
  10. adcp-2.9.0/src/adcp/types/__init__.py +557 -0
  11. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/_generated.py +37 -38
  12. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/aliases.py +251 -46
  13. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/activate_signal_request.py +3 -3
  14. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/activate_signal_response.py +2 -2
  15. adcp-2.9.0/src/adcp/types/generated_poc/asset_content_type.py +23 -0
  16. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/brand_manifest.py +8 -8
  17. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/create_media_buy_response.py +16 -21
  18. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/deployment.py +6 -6
  19. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/destination.py +4 -4
  20. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/format.py +5 -30
  21. adcp-2.9.0/src/adcp/types/generated_poc/format_category.py +17 -0
  22. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_signals_request.py +4 -4
  23. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_signals_response.py +2 -2
  24. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_creative_formats_request.py +4 -22
  25. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/update_media_buy_response.py +15 -22
  26. adcp-2.9.0/src/adcp/types/stable.py +449 -0
  27. {adcp-2.7.0 → adcp-2.9.0/src/adcp.egg-info}/PKG-INFO +172 -1
  28. {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/SOURCES.txt +2 -1
  29. {adcp-2.7.0 → adcp-2.9.0}/tests/test_cli.py +53 -0
  30. {adcp-2.7.0 → adcp-2.9.0}/tests/test_client.py +8 -2
  31. {adcp-2.7.0 → adcp-2.9.0}/tests/test_type_aliases.py +2 -104
  32. adcp-2.7.0/src/adcp/types/__init__.py +0 -127
  33. adcp-2.7.0/src/adcp/types/generated_poc/asset_type.py +0 -100
  34. adcp-2.7.0/src/adcp/types/stable.py +0 -188
  35. {adcp-2.7.0 → adcp-2.9.0}/LICENSE +0 -0
  36. {adcp-2.7.0 → adcp-2.9.0}/setup.cfg +0 -0
  37. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/adagents.py +0 -0
  38. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/config.py +0 -0
  39. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/exceptions.py +0 -0
  40. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/protocols/__init__.py +0 -0
  41. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/py.typed +0 -0
  42. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/simple.py +0 -0
  43. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/testing/__init__.py +0 -0
  44. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/testing/test_helpers.py +0 -0
  45. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/base.py +0 -0
  46. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/core.py +0 -0
  47. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/__init__.py +0 -0
  48. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/activation_key.py +0 -0
  49. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/adagents.py +0 -0
  50. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/audio_asset.py +0 -0
  51. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/build_creative_request.py +0 -0
  52. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/build_creative_response.py +0 -0
  53. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/channels.py +0 -0
  54. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpc_option.py +0 -0
  55. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpcv_option.py +0 -0
  56. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpm_auction_option.py +0 -0
  57. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpm_fixed_option.py +0 -0
  58. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpp_option.py +0 -0
  59. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/cpv_option.py +0 -0
  60. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/create_media_buy_request.py +0 -0
  61. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_asset.py +0 -0
  62. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_assignment.py +0 -0
  63. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_manifest.py +0 -0
  64. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_policy.py +0 -0
  65. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/creative_status.py +0 -0
  66. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/css_asset.py +0 -0
  67. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/daast_asset.py +0 -0
  68. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/delivery_metrics.py +0 -0
  69. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/delivery_type.py +0 -0
  70. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/error.py +0 -0
  71. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/flat_rate_option.py +0 -0
  72. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/format_id.py +0 -0
  73. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/frequency_cap.py +0 -0
  74. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/frequency_cap_scope.py +0 -0
  75. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_media_buy_delivery_request.py +0 -0
  76. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_media_buy_delivery_response.py +0 -0
  77. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_products_request.py +0 -0
  78. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/get_products_response.py +0 -0
  79. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/html_asset.py +0 -0
  80. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/identifier_types.py +0 -0
  81. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/image_asset.py +0 -0
  82. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/javascript_asset.py +0 -0
  83. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_authorized_properties_request.py +0 -0
  84. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_authorized_properties_response.py +0 -0
  85. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_creative_formats_response.py +0 -0
  86. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_creatives_request.py +0 -0
  87. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/list_creatives_response.py +0 -0
  88. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/markdown_asset.py +0 -0
  89. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/measurement.py +0 -0
  90. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/media_buy.py +0 -0
  91. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/media_buy_status.py +0 -0
  92. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/pacing.py +0 -0
  93. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/package.py +0 -0
  94. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/package_request.py +0 -0
  95. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/package_status.py +0 -0
  96. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/performance_feedback.py +0 -0
  97. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/placement.py +0 -0
  98. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/preview_creative_request.py +0 -0
  99. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/preview_creative_response.py +0 -0
  100. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/preview_render.py +0 -0
  101. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/pricing_model.py +0 -0
  102. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/product.py +0 -0
  103. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/promoted_offerings.py +0 -0
  104. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/promoted_products.py +0 -0
  105. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/property.py +0 -0
  106. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/protocol_envelope.py +0 -0
  107. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/provide_performance_feedback_request.py +0 -0
  108. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/provide_performance_feedback_response.py +0 -0
  109. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/publisher_identifier_types.py +0 -0
  110. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/publisher_property_selector.py +0 -0
  111. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/push_notification_config.py +0 -0
  112. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/reporting_capabilities.py +0 -0
  113. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/response.py +0 -0
  114. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/standard_format_ids.py +0 -0
  115. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/sub_asset.py +0 -0
  116. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/sync_creatives_request.py +0 -0
  117. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/sync_creatives_response.py +0 -0
  118. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/targeting.py +0 -0
  119. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/task_status.py +0 -0
  120. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/task_type.py +0 -0
  121. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/tasks_get_request.py +0 -0
  122. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/tasks_get_response.py +0 -0
  123. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/tasks_list_request.py +0 -0
  124. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/tasks_list_response.py +0 -0
  125. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/text_asset.py +0 -0
  126. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/update_media_buy_request.py +0 -0
  127. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/url_asset.py +0 -0
  128. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/vast_asset.py +0 -0
  129. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/vcpm_auction_option.py +0 -0
  130. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/vcpm_fixed_option.py +0 -0
  131. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/video_asset.py +0 -0
  132. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/webhook_asset.py +0 -0
  133. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/types/generated_poc/webhook_payload.py +0 -0
  134. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/utils/__init__.py +0 -0
  135. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/utils/operation_id.py +0 -0
  136. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/utils/preview_cache.py +0 -0
  137. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/utils/response_parser.py +0 -0
  138. {adcp-2.7.0 → adcp-2.9.0}/src/adcp/validation.py +0 -0
  139. {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/dependency_links.txt +0 -0
  140. {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/entry_points.txt +0 -0
  141. {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/requires.txt +0 -0
  142. {adcp-2.7.0 → adcp-2.9.0}/src/adcp.egg-info/top_level.txt +0 -0
  143. {adcp-2.7.0 → adcp-2.9.0}/tests/test_adagents.py +0 -0
  144. {adcp-2.7.0 → adcp-2.9.0}/tests/test_code_generation.py +0 -0
  145. {adcp-2.7.0 → adcp-2.9.0}/tests/test_discriminated_unions.py +0 -0
  146. {adcp-2.7.0 → adcp-2.9.0}/tests/test_format_id_validation.py +0 -0
  147. {adcp-2.7.0 → adcp-2.9.0}/tests/test_helpers.py +0 -0
  148. {adcp-2.7.0 → adcp-2.9.0}/tests/test_preview_html.py +0 -0
  149. {adcp-2.7.0 → adcp-2.9.0}/tests/test_protocols.py +0 -0
  150. {adcp-2.7.0 → adcp-2.9.0}/tests/test_public_api.py +0 -0
  151. {adcp-2.7.0 → adcp-2.9.0}/tests/test_response_parser.py +0 -0
  152. {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.7.0
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.0"
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.7.0"
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
- # Type guard - request_type should be initialized by this point
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