adcp 2.2.0__py3-none-any.whl → 2.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. adcp/__init__.py +5 -1
  2. adcp/adagents.py +122 -0
  3. adcp/types/generated.py +36 -531
  4. adcp/types/generated_poc/__init__.py +1 -1
  5. adcp/types/generated_poc/activate_signal_request.py +5 -5
  6. adcp/types/generated_poc/activate_signal_response.py +9 -9
  7. adcp/types/generated_poc/activation_key.py +8 -8
  8. adcp/types/generated_poc/adagents.py +46 -46
  9. adcp/types/generated_poc/asset_type.py +19 -19
  10. adcp/types/generated_poc/audio_asset.py +6 -6
  11. adcp/types/generated_poc/brand_manifest.py +73 -73
  12. adcp/types/generated_poc/build_creative_request.py +6 -6
  13. adcp/types/generated_poc/build_creative_response.py +9 -9
  14. adcp/types/generated_poc/channels.py +10 -10
  15. adcp/types/generated_poc/cpc_option.py +12 -8
  16. adcp/types/generated_poc/cpcv_option.py +12 -8
  17. adcp/types/generated_poc/cpm_auction_option.py +17 -13
  18. adcp/types/generated_poc/cpm_fixed_option.py +12 -8
  19. adcp/types/generated_poc/cpp_option.py +17 -13
  20. adcp/types/generated_poc/cpv_option.py +16 -12
  21. adcp/types/generated_poc/create_media_buy_request.py +29 -29
  22. adcp/types/generated_poc/create_media_buy_response.py +11 -11
  23. adcp/types/generated_poc/creative_asset.py +13 -13
  24. adcp/types/generated_poc/creative_assignment.py +4 -4
  25. adcp/types/generated_poc/creative_manifest.py +4 -4
  26. adcp/types/generated_poc/creative_policy.py +11 -11
  27. adcp/types/generated_poc/creative_status.py +5 -5
  28. adcp/types/generated_poc/css_asset.py +3 -3
  29. adcp/types/generated_poc/daast_asset.py +30 -30
  30. adcp/types/generated_poc/delivery_metrics.py +33 -33
  31. adcp/types/generated_poc/delivery_type.py +3 -3
  32. adcp/types/generated_poc/deployment.py +21 -21
  33. adcp/types/generated_poc/destination.py +10 -10
  34. adcp/types/generated_poc/error.py +7 -7
  35. adcp/types/generated_poc/flat_rate_option.py +16 -16
  36. adcp/types/generated_poc/format.py +70 -70
  37. adcp/types/generated_poc/format_id.py +3 -3
  38. adcp/types/generated_poc/frequency_cap.py +3 -3
  39. adcp/types/generated_poc/frequency_cap_scope.py +4 -4
  40. adcp/types/generated_poc/get_media_buy_delivery_request.py +21 -21
  41. adcp/types/generated_poc/get_media_buy_delivery_response.py +46 -46
  42. adcp/types/generated_poc/get_products_request.py +23 -23
  43. adcp/types/generated_poc/get_products_response.py +5 -5
  44. adcp/types/generated_poc/get_signals_request.py +19 -19
  45. adcp/types/generated_poc/get_signals_response.py +20 -20
  46. adcp/types/generated_poc/html_asset.py +3 -3
  47. adcp/types/generated_poc/identifier_types.py +20 -20
  48. adcp/types/generated_poc/image_asset.py +7 -7
  49. adcp/types/generated_poc/javascript_asset.py +7 -7
  50. adcp/types/generated_poc/list_authorized_properties_request.py +5 -5
  51. adcp/types/generated_poc/list_authorized_properties_response.py +9 -9
  52. adcp/types/generated_poc/list_creative_formats_request.py +22 -22
  53. adcp/types/generated_poc/list_creative_formats_response.py +11 -11
  54. adcp/types/generated_poc/list_creatives_request.py +51 -51
  55. adcp/types/generated_poc/list_creatives_response.py +61 -61
  56. adcp/types/generated_poc/markdown_asset.py +7 -7
  57. adcp/types/generated_poc/measurement.py +9 -9
  58. adcp/types/generated_poc/media_buy.py +8 -8
  59. adcp/types/generated_poc/media_buy_status.py +5 -5
  60. adcp/types/generated_poc/pacing.py +4 -4
  61. adcp/types/generated_poc/package.py +8 -8
  62. adcp/types/generated_poc/package_request.py +7 -7
  63. adcp/types/generated_poc/package_status.py +5 -5
  64. adcp/types/generated_poc/performance_feedback.py +31 -31
  65. adcp/types/generated_poc/placement.py +4 -4
  66. adcp/types/generated_poc/preview_creative_request.py +28 -28
  67. adcp/types/generated_poc/preview_creative_response.py +31 -31
  68. adcp/types/generated_poc/preview_render.py +36 -28
  69. adcp/types/generated_poc/pricing_model.py +8 -8
  70. adcp/types/generated_poc/product.py +32 -31
  71. adcp/types/generated_poc/promoted_offerings.py +29 -29
  72. adcp/types/generated_poc/promoted_products.py +3 -3
  73. adcp/types/generated_poc/property.py +18 -18
  74. adcp/types/generated_poc/protocol_envelope.py +9 -9
  75. adcp/types/generated_poc/provide_performance_feedback_request.py +24 -24
  76. adcp/types/generated_poc/provide_performance_feedback_response.py +9 -9
  77. adcp/types/generated_poc/publisher_identifier_types.py +6 -6
  78. adcp/types/generated_poc/push_notification_config.py +9 -9
  79. adcp/types/generated_poc/reporting_capabilities.py +21 -21
  80. adcp/types/generated_poc/response.py +5 -5
  81. adcp/types/generated_poc/standard_format_ids.py +36 -36
  82. adcp/types/generated_poc/sub_asset.py +13 -13
  83. adcp/types/generated_poc/sync_creatives_request.py +11 -11
  84. adcp/types/generated_poc/sync_creatives_response.py +23 -23
  85. adcp/types/generated_poc/targeting.py +9 -9
  86. adcp/types/generated_poc/task_status.py +10 -10
  87. adcp/types/generated_poc/task_type.py +6 -6
  88. adcp/types/generated_poc/tasks_get_request.py +5 -5
  89. adcp/types/generated_poc/tasks_get_response.py +35 -35
  90. adcp/types/generated_poc/tasks_list_request.py +36 -36
  91. adcp/types/generated_poc/tasks_list_response.py +35 -35
  92. adcp/types/generated_poc/text_asset.py +3 -3
  93. adcp/types/generated_poc/update_media_buy_request.py +27 -27
  94. adcp/types/generated_poc/update_media_buy_response.py +11 -11
  95. adcp/types/generated_poc/url_asset.py +7 -7
  96. adcp/types/generated_poc/vast_asset.py +38 -38
  97. adcp/types/generated_poc/vcpm_auction_option.py +17 -13
  98. adcp/types/generated_poc/vcpm_fixed_option.py +12 -8
  99. adcp/types/generated_poc/video_asset.py +8 -8
  100. adcp/types/generated_poc/webhook_asset.py +19 -19
  101. adcp/types/generated_poc/webhook_payload.py +18 -18
  102. {adcp-2.2.0.dist-info → adcp-2.4.0.dist-info}/METADATA +38 -2
  103. adcp-2.4.0.dist-info/RECORD +132 -0
  104. adcp-2.2.0.dist-info/RECORD +0 -132
  105. {adcp-2.2.0.dist-info → adcp-2.4.0.dist-info}/WHEEL +0 -0
  106. {adcp-2.2.0.dist-info → adcp-2.4.0.dist-info}/entry_points.txt +0 -0
  107. {adcp-2.2.0.dist-info → adcp-2.4.0.dist-info}/licenses/LICENSE +0 -0
  108. {adcp-2.2.0.dist-info → adcp-2.4.0.dist-info}/top_level.txt +0 -0
adcp/__init__.py CHANGED
@@ -8,8 +8,10 @@ Supports both A2A and MCP protocols with full type safety.
8
8
  """
9
9
 
10
10
  from adcp.adagents import (
11
+ AuthorizationContext,
11
12
  domain_matches,
12
13
  fetch_adagents,
14
+ fetch_agent_authorizations,
13
15
  get_all_properties,
14
16
  get_all_tags,
15
17
  get_properties_by_agent,
@@ -134,7 +136,7 @@ from adcp.validation import (
134
136
  validate_publisher_properties_item,
135
137
  )
136
138
 
137
- __version__ = "2.2.0"
139
+ __version__ = "2.4.0"
138
140
 
139
141
  __all__ = [
140
142
  # Client classes
@@ -178,7 +180,9 @@ __all__ = [
178
180
  "Product",
179
181
  "Property",
180
182
  # Adagents validation
183
+ "AuthorizationContext",
181
184
  "fetch_adagents",
185
+ "fetch_agent_authorizations",
182
186
  "verify_agent_authorization",
183
187
  "verify_agent_for_property",
184
188
  "domain_matches",
adcp/adagents.py CHANGED
@@ -518,3 +518,125 @@ def get_properties_by_agent(adagents_data: dict[str, Any], agent_url: str) -> li
518
518
  return [p for p in properties if isinstance(p, dict)]
519
519
 
520
520
  return []
521
+
522
+
523
+ class AuthorizationContext:
524
+ """Authorization context for a publisher domain.
525
+
526
+ Attributes:
527
+ property_ids: List of property IDs the agent is authorized for
528
+ property_tags: List of property tags the agent is authorized for
529
+ raw_properties: Raw property data from adagents.json
530
+ """
531
+
532
+ def __init__(self, properties: list[dict[str, Any]]):
533
+ """Initialize from list of properties.
534
+
535
+ Args:
536
+ properties: List of property dictionaries from adagents.json
537
+ """
538
+ self.property_ids: list[str] = []
539
+ self.property_tags: list[str] = []
540
+ self.raw_properties = properties
541
+
542
+ # Extract property IDs and tags
543
+ for prop in properties:
544
+ if not isinstance(prop, dict):
545
+ continue
546
+
547
+ # Extract property ID
548
+ prop_id = prop.get("id")
549
+ if prop_id and isinstance(prop_id, str):
550
+ self.property_ids.append(prop_id)
551
+
552
+ # Extract tags
553
+ tags = prop.get("tags", [])
554
+ if isinstance(tags, list):
555
+ for tag in tags:
556
+ if isinstance(tag, str) and tag not in self.property_tags:
557
+ self.property_tags.append(tag)
558
+
559
+ def __repr__(self) -> str:
560
+ return (
561
+ f"AuthorizationContext("
562
+ f"property_ids={self.property_ids}, "
563
+ f"property_tags={self.property_tags})"
564
+ )
565
+
566
+
567
+ async def fetch_agent_authorizations(
568
+ agent_url: str,
569
+ publisher_domains: list[str],
570
+ timeout: float = 10.0,
571
+ client: httpx.AsyncClient | None = None,
572
+ ) -> dict[str, AuthorizationContext]:
573
+ """Fetch authorization contexts by checking publisher adagents.json files.
574
+
575
+ This function discovers what publishers have authorized your agent by fetching
576
+ their adagents.json files from the .well-known directory and extracting the
577
+ properties your agent can access.
578
+
579
+ This is the "pull" approach - you query publishers to see if they've authorized you.
580
+ For the "push" approach where the agent tells you what it's authorized for,
581
+ use the agent's list_authorized_properties endpoint via ADCPClient.
582
+
583
+ Args:
584
+ agent_url: URL of your sales agent
585
+ publisher_domains: List of publisher domains to check (e.g., ["nytimes.com", "wsj.com"])
586
+ timeout: Request timeout in seconds for each fetch
587
+ client: Optional httpx.AsyncClient for connection pooling
588
+
589
+ Returns:
590
+ Dictionary mapping publisher domain to AuthorizationContext.
591
+ Only includes domains where the agent is authorized.
592
+
593
+ Example:
594
+ >>> # "Pull" approach - check what publishers have authorized you
595
+ >>> contexts = await fetch_agent_authorizations(
596
+ ... "https://our-sales-agent.com",
597
+ ... ["nytimes.com", "wsj.com", "cnn.com"]
598
+ ... )
599
+ >>> for domain, ctx in contexts.items():
600
+ ... print(f"{domain}:")
601
+ ... print(f" Property IDs: {ctx.property_ids}")
602
+ ... print(f" Tags: {ctx.property_tags}")
603
+
604
+ See Also:
605
+ ADCPClient.list_authorized_properties: "Push" approach using the agent's API
606
+
607
+ Notes:
608
+ - Silently skips domains where adagents.json is not found or invalid
609
+ - Only returns domains where the agent is explicitly authorized
610
+ - For production use with many domains, pass a shared httpx.AsyncClient
611
+ to enable connection pooling
612
+ """
613
+ import asyncio
614
+
615
+ # Create tasks to fetch all adagents.json files in parallel
616
+ async def fetch_authorization_for_domain(
617
+ domain: str,
618
+ ) -> tuple[str, AuthorizationContext | None]:
619
+ """Fetch authorization context for a single domain."""
620
+ try:
621
+ adagents_data = await fetch_adagents(domain, timeout=timeout, client=client)
622
+
623
+ # Check if agent is authorized
624
+ if not verify_agent_authorization(adagents_data, agent_url):
625
+ return (domain, None)
626
+
627
+ # Get properties for this agent
628
+ properties = get_properties_by_agent(adagents_data, agent_url)
629
+
630
+ # Create authorization context
631
+ return (domain, AuthorizationContext(properties))
632
+
633
+ except (AdagentsNotFoundError, AdagentsValidationError, AdagentsTimeoutError):
634
+ # Silently skip domains with missing or invalid adagents.json
635
+ return (domain, None)
636
+
637
+ # Fetch all domains in parallel
638
+ tasks = [fetch_authorization_for_domain(domain) for domain in publisher_domains]
639
+ results = await asyncio.gather(*tasks)
640
+
641
+ # Build result dictionary, filtering out None values
642
+ return {domain: ctx for domain, ctx in results if ctx is not None}