diff --git a/CLAUDE.md b/CLAUDE.md index 401532fc..83568140 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,31 +17,84 @@ FormatId = str PackageRequest = dict[str, Any] ``` -**Stable Public API Layer** +**Stable Public API Layer - Import Architecture** -**CRITICAL**: The `generated_poc` directory is internal implementation. **Never import directly from it**. +**CRITICAL**: Both `generated_poc/` and `_generated.py` are internal implementation. Source code must ONLY import from `stable.py` or `aliases.py`. -Generated types in `src/adcp/types/generated_poc/` may have: -- Numbered suffixes (e.g., `BrandManifest1`, `BrandManifest2`) due to schema evolution -- Structural changes between minor versions -- Files added/removed as schemas evolve +### Import Architecture -**Always use the stable API:** +The type system has a strict layering to prevent brittleness: + +``` +generated_poc/*.py (internal, auto-generated from schemas) + ↓ +_generated.py (internal consolidation, handles name collisions) + ↓ +stable.py (public API for base types) + aliases.py (public API for discriminated unions) + ↓ +__init__.py (user-facing exports) +``` + +### Import Rules for Source Code + +**✅ CORRECT - Public API only:** +```python +# For base types (requests, responses, domain models) +from adcp.types.stable import ( + GetProductsRequest, + GetProductsResponse, + Product, + Package, + BrandManifest, +) + +# For semantic aliases (discriminated unions) +from adcp.types.aliases import ( + CreateMediaBuySuccessResponse, + CreateMediaBuyErrorResponse, + PreviewCreativeFormatRequest, +) + +# Or from main package +from adcp import Product, CreateMediaBuySuccessResponse +``` + +**❌ WRONG - Internal implementation (brittle):** ```python -# ✅ CORRECT - Stable public API -from adcp.types import BrandManifest, Product, CpmFixedRatePricingOption -from adcp.types.stable import BrandManifest, Product +# Never import from _generated - it's internal consolidation +from adcp.types._generated import GetProductsRequest -# ❌ WRONG - Internal generated types (will break) -from adcp.types.generated_poc.brand_manifest import BrandManifest1 -from adcp.types._generated import BrandManifest1 +# Never import from generated_poc - it's internal generated code +from adcp.types.generated_poc.product import Product + +# Never import numbered types directly - use semantic aliases +from adcp.types._generated import CreateMediaBuyResponse1 ``` -The stable API (`src/adcp/types/stable.py`) provides: -1. **Clean names** - `BrandManifest` not `BrandManifest1` -2. **Stability** - Aliases are updated when schemas evolve -3. **Versioning** - Breaking changes require major version bumps -4. **Deprecation warnings** - Direct `generated_poc` imports trigger warnings +### Why This Matters + +1. **`generated_poc/`** may have: + - Numbered suffixes (e.g., `Response1`, `Response2`) + - Files added/removed as schemas evolve + - Name collisions between modules + +2. **`_generated.py`** may have: + - Collision-resolution qualifiers (e.g., `_PackageFromPackage`) + - Internal consolidation logic + - Changes when collision handling evolves + +3. **`stable.py` and `aliases.py`** provide: + - Clean, semantic names + - Stability guarantees within major versions + - Explicit public API + +### Special Cases + +**Only `stable.py` and `aliases.py` may import from `_generated.py`:** +- `stable.py`: Imports base types and re-exports with clean names +- `aliases.py`: Imports numbered discriminated union types and creates semantic aliases + +**All other source files must import from `stable.py` or `aliases.py`.** **NEVER Modify Generated Files Directly** diff --git a/schemas/cache/.hashes.json b/schemas/cache/.hashes.json index cbb29428..abd7830f 100644 --- a/schemas/cache/.hashes.json +++ b/schemas/cache/.hashes.json @@ -1,6 +1,6 @@ { - "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/index.json": "eed524f6ca3b7b8981035a74f3eaf339da6fadab85e4af9196c1c7c4d5150095", - "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/adagents.json": "bd0e7cd9189b191d827a3ab7fb9d4f9ef4913377c816c5aa27af30bfd20d3451", + "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/index.json": "46f68f0e55d63361c0eda1cc7ffff4f25c9416467dd3a04db2cca0973f086b7d", + "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/adagents.json": "f32e3778a454b7ae65f42952906f06466008bfd1208b83729e14d5f2164902d5", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/activation-key.json": "bb9c20c6200b651ce6db89f7160be60b9845dbbb4390a13363ea5b82c1c3c786", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/asset-type.json": "a61ac8e14a61adef64d10d6ab39c204d703c087f29efa45c69c527988c93cd3d", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/assets/audio-asset.json": "e25d688d22c8b130d9d1a2a09f9aa462cb7a5c83db6eea6f328cd937f8625a3f", @@ -34,11 +34,12 @@ "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/performance-feedback.json": "80384474042b6cda08b1128859143ec5822d6dcc907ba1fa3ecf81719e7644a7", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/placement.json": "ea814df6d878232bfdb1249fe199a1e32ec18598b7d3e3c57324d6e6120d9cf8", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/pricing-option.json": "cfaeff3d4fc49e0d3ae76364e246b3b7a772ef12cbda65b1cff400ab1f841bfa", - "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/product.json": "f3ef04e850cb61c2ba86e05da1d5a352b63031ddbb42fbdffbbbd6c8432ad5c5", + "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/product.json": "e1b4faa9029bd06baa537fbf534993e7830b1bdc2241279dea4806c134cea50d", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/promoted-offerings.json": "d8b4b92db0e2debc5c0ddbc0a8ff673f258f0bbc0348737df61be20a25827077", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/promoted-products.json": "77773b1dce91b219ec5043c091eb2977a82ba301e03aead3868ba704e625379e", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/property.json": "510458c96a93deb90d9fa3a4dfc11b63c113755dbec3de386690f6838213bc84", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/protocol-envelope.json": "c6096b4ed4330c5e2045989bfd5cdc64fa6587cf8b0d1d2c19e33c7434cdacb8", + "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/publisher-property-selector.json": "3e4870d0446a5825c16365a99d49932517223c1d9d3d46a4fbf413d377ed43dd", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/push-notification-config.json": "be2af5dbf7d398c958e59c70ab61a845e4a7d1f1e076412589d06d53454b64b0", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/reporting-capabilities.json": "c463c8d512c17b8ac7afde34d782b5e5f700ed9cf73a52992a328f85ad24d568", "https://raw.githubusercontent.com/adcontextprotocol/adcp/main/static/schemas/v1/core/response.json": "0ac624a30da08e1aa90d2a9379f8c1ed29b704c3f5399224b9684672d3df9723", diff --git a/schemas/cache/1.0.0/adagents.json b/schemas/cache/1.0.0/adagents.json index 7e142bac..c50e6a85 100644 --- a/schemas/cache/1.0.0/adagents.json +++ b/schemas/cache/1.0.0/adagents.json @@ -318,7 +318,7 @@ "properties": { "description": "Specific properties this agent is authorized for (alternative to property_ids/property_tags)", "items": { - "$ref": "property.json" + "$ref": "/schemas/v1/core/property.json" }, "minItems": 1, "type": "array" @@ -354,68 +354,7 @@ "publisher_properties": { "description": "Properties from other publisher domains this agent is authorized for. Each entry specifies a publisher domain and which of their properties this agent can sell", "items": { - "oneOf": [ - { - "additionalProperties": false, - "properties": { - "property_ids": { - "description": "Specific property IDs from the publisher's adagents.json properties array", - "items": { - "pattern": "^[a-z0-9_]+$", - "type": "string" - }, - "minItems": 1, - "type": "array" - }, - "publisher_domain": { - "description": "Domain where the publisher's adagents.json is hosted (e.g., 'cnn.com')", - "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$", - "type": "string" - }, - "selection_type": { - "const": "by_id", - "description": "Discriminator indicating selection by specific property IDs", - "type": "string" - } - }, - "required": [ - "publisher_domain", - "selection_type", - "property_ids" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "property_tags": { - "description": "Property tags from the publisher's adagents.json tags. Agent is authorized for all properties with these tags", - "items": { - "pattern": "^[a-z0-9_]+$", - "type": "string" - }, - "minItems": 1, - "type": "array" - }, - "publisher_domain": { - "description": "Domain where the publisher's adagents.json is hosted (e.g., 'cnn.com')", - "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$", - "type": "string" - }, - "selection_type": { - "const": "by_tag", - "description": "Discriminator indicating selection by property tags", - "type": "string" - } - }, - "required": [ - "publisher_domain", - "selection_type", - "property_tags" - ], - "type": "object" - } - ] + "$ref": "/schemas/v1/core/publisher-property-selector.json" }, "minItems": 1, "type": "array" @@ -487,7 +426,7 @@ "properties": { "description": "Array of all properties covered by this adagents.json file. Same structure as list_authorized_properties response.", "items": { - "$ref": "property.json" + "$ref": "/schemas/v1/core/property.json" }, "minItems": 1, "type": "array" diff --git a/schemas/cache/1.0.0/index.json b/schemas/cache/1.0.0/index.json index 62c1a1fa..03c248d4 100644 --- a/schemas/cache/1.0.0/index.json +++ b/schemas/cache/1.0.0/index.json @@ -1,17 +1,16 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/schemas/v1/index.json", - "title": "AdCP Schema Registry v1", - "version": "1.0.0", - "description": "Registry of all AdCP JSON schemas for validation and discovery", + "$schema": "http://json-schema.org/draft-07/schema#", "adcp_version": "2.4.0", - "standard_formats_version": "2.0.0", - "versioning": { - "note": "AdCP uses path-based versioning. The schema URL path (/schemas/v1/) indicates the version. Individual request/response schemas do NOT include adcp_version fields. Compatibility follows semantic versioning rules." - }, + "baseUrl": "/schemas/v1", "changelog": { + "1.8.0": { + "changes": [ + "Previous version with string-based dimensions" + ], + "date": "2025-10-13" + }, "2.0.0": { - "date": "2025-10-14", "breaking_changes": [ "Added renders array to Format schema with role and dimensions fields (replaces top-level dimensions)", "Formats now specify rendered outputs via renders array - enables companion ads, adaptive formats, and multi-placement", @@ -22,422 +21,427 @@ "Removed hints object from preview renders (use format lookup for render specifications instead)", "Changed preview render field names: output_id\u2192render_id, output_role\u2192role, added dimensions field" ], + "date": "2025-10-14", "rationale": "Renders array with structured dimensions eliminates parsing ambiguity and uniformly supports single and multi-render formats. Multi-render preview support enables companion ads and adaptive formats. Terminology changes prevent confusion between preview rendering and generative format outputs. Simplified schema removes redundant fields." - }, - "1.8.0": { - "date": "2025-10-13", - "changes": [ - "Previous version with string-based dimensions" - ] } }, + "description": "Registry of all AdCP JSON schemas for validation and discovery", + "examples": [ + { + "code": "const Ajv = require('ajv'); const ajv = new Ajv(); const schema = require('./schemas/v1/core/product.json'); const validate = ajv.compile(schema);", + "description": "JavaScript validation example", + "language": "javascript" + }, + { + "code": "import jsonschema; schema = {...}; jsonschema.validate(data, schema)", + "description": "Python validation example", + "language": "python" + }, + { + "code": "// Use everit-org/json-schema or similar library", + "description": "Java validation example", + "language": "java" + } + ], "lastUpdated": "2025-10-31", - "baseUrl": "/schemas/v1", "schemas": { + "adagents": { + "$ref": "/schemas/v1/adagents.json", + "description": "Authorized sales agents file format specification", + "file_location": "/.well-known/adagents.json", + "purpose": "Declares which sales agents are authorized to sell a publisher's advertising inventory" + }, "core": { "description": "Core data models used throughout AdCP", "schemas": { - "product": { - "$ref": "product.json", - "description": "Represents available advertising inventory" - }, - "media-buy": { - "$ref": "media-buy.json", - "description": "Represents a purchased advertising campaign" + "brand-manifest": { + "$ref": "/schemas/v1/core/brand-manifest.json", + "description": "Standardized brand information manifest for creative generation and media buying" }, - "package": { - "$ref": "package.json", - "description": "A specific product within a media buy (line item)" + "brand-manifest-ref": { + "$ref": "/schemas/v1/core/brand-manifest-ref.json", + "description": "Brand manifest reference (inline object or URL)" }, "creative-asset": { - "$ref": "creative-asset.json", + "$ref": "/schemas/v1/core/creative-asset.json", "description": "Creative asset for upload to library - supports static assets, generative formats, and third-party ad serving (VAST, DAAST, HTML, JavaScript)" }, - "targeting": { - "$ref": "targeting.json", - "description": "Audience targeting criteria" - }, - "frequency-cap": { - "$ref": "frequency-cap.json", - "description": "Frequency capping settings" + "creative-assignment": { + "$ref": "/schemas/v1/core/creative-assignment.json", + "description": "Assignment of a creative asset to a package" }, - "format": { - "$ref": "format.json", - "description": "Represents a creative format with its requirements" + "creative-manifest": { + "$ref": "/schemas/v1/core/creative-manifest.json", + "description": "Complete specification of a creative with all assets needed for rendering" }, - "measurement": { - "$ref": "measurement.json", - "description": "Measurement capabilities included with a product" + "creative-policy": { + "$ref": "/schemas/v1/core/creative-policy.json", + "description": "Creative requirements and restrictions for a product" }, "delivery-metrics": { - "$ref": "delivery-metrics.json", + "$ref": "/schemas/v1/core/delivery-metrics.json", "description": "Standard delivery metrics for reporting" }, - "creative-policy": { - "$ref": "creative-policy.json", - "description": "Creative requirements and restrictions for a product" + "deployment": { + "$ref": "/schemas/v1/core/deployment.json", + "description": "A signal deployment to a specific destination platform with activation status and key" }, - "response": { - "$ref": "response.json", - "description": "Standard response structure (MCP)" + "destination": { + "$ref": "/schemas/v1/core/destination.json", + "description": "A destination platform where signals can be activated (DSP, sales agent, etc.)" }, "error": { - "$ref": "error.json", + "$ref": "/schemas/v1/core/error.json", "description": "Standard error structure" }, - "sub-asset": { - "$ref": "sub-asset.json", - "description": "Sub-asset for multi-asset creative formats" + "format": { + "$ref": "/schemas/v1/core/format.json", + "description": "Represents a creative format with its requirements" }, - "creative-assignment": { - "$ref": "creative-assignment.json", - "description": "Assignment of a creative asset to a package" + "frequency-cap": { + "$ref": "/schemas/v1/core/frequency-cap.json", + "description": "Frequency capping settings" }, - "creative-manifest": { - "$ref": "creative-manifest.json", - "description": "Complete specification of a creative with all assets needed for rendering" + "measurement": { + "$ref": "/schemas/v1/core/measurement.json", + "description": "Measurement capabilities included with a product" + }, + "media-buy": { + "$ref": "/schemas/v1/core/media-buy.json", + "description": "Represents a purchased advertising campaign" + }, + "package": { + "$ref": "/schemas/v1/core/package.json", + "description": "A specific product within a media buy (line item)" }, "performance-feedback": { - "$ref": "performance-feedback.json", + "$ref": "/schemas/v1/core/performance-feedback.json", "description": "Performance feedback data for a media buy or package" }, - "property": { - "$ref": "property.json", - "description": "An advertising property that can be validated via adagents.json" + "placement": { + "$ref": "/schemas/v1/core/placement.json", + "description": "Represents a specific ad placement within a product's inventory" }, - "brand-manifest": { - "$ref": "brand-manifest.json", - "description": "Standardized brand information manifest for creative generation and media buying" + "pricing-option": { + "$ref": "/schemas/v1/core/pricing-option.json", + "description": "A pricing model option offered by a publisher for a product" }, - "brand-manifest-ref": { - "$ref": "brand-manifest-ref.json", - "description": "Brand manifest reference (inline object or URL)" + "product": { + "$ref": "/schemas/v1/core/product.json", + "description": "Represents available advertising inventory" }, "promoted-products": { - "$ref": "promoted-products.json", + "$ref": "/schemas/v1/core/promoted-products.json", "description": "Product or offering selection for campaigns with multiple selection methods" }, - "start-timing": { - "$ref": "start-timing.json", - "description": "Campaign start timing: 'asap' or ISO 8601 date-time" - }, - "pricing-option": { - "$ref": "pricing-option.json", - "description": "A pricing model option offered by a publisher for a product" + "property": { + "$ref": "/schemas/v1/core/property.json", + "description": "An advertising property that can be validated via adagents.json" }, "protocol-envelope": { - "$ref": "protocol-envelope.json", + "$ref": "/schemas/v1/core/protocol-envelope.json", "description": "Standard envelope structure added by protocol layer (MCP, A2A, REST) that wraps task response payloads with protocol-level fields like status, context_id, task_id, and message" }, - "placement": { - "$ref": "placement.json", - "description": "Represents a specific ad placement within a product's inventory" + "publisher-property-selector": { + "$ref": "/schemas/v1/core/publisher-property-selector.json", + "description": "Selects properties from a publisher's adagents.json - supports three patterns: all properties, specific IDs, or by tags" + }, + "response": { + "$ref": "/schemas/v1/core/response.json", + "description": "Standard response structure (MCP)" + }, + "start-timing": { + "$ref": "/schemas/v1/core/start-timing.json", + "description": "Campaign start timing: 'asap' or ISO 8601 date-time" + }, + "sub-asset": { + "$ref": "/schemas/v1/core/sub-asset.json", + "description": "Sub-asset for multi-asset creative formats" + }, + "targeting": { + "$ref": "/schemas/v1/core/targeting.json", + "description": "Audience targeting criteria" }, "webhook-payload": { - "$ref": "webhook-payload.json", + "$ref": "/schemas/v1/core/webhook-payload.json", "description": "Webhook payload structure sent when async task status changes - protocol-level fields at top-level (operation_id, task_type, status, etc.) and task-specific payload nested under 'result'" + } + } + }, + "creative": { + "asset_types": { + "$ref": "/schemas/v1/creative/asset-types/index.json", + "description": "Asset type definitions for creative manifests" + }, + "description": "Creative protocol task request/response schemas and asset type definitions", + "tasks": { + "build-creative": { + "request": { + "$ref": "/schemas/v1/media-buy/build-creative-request.json", + "description": "Request parameters for AI-powered creative generation" + }, + "response": { + "$ref": "/schemas/v1/media-buy/build-creative-response.json", + "description": "Response payload for build_creative task" + } }, - "destination": { - "$ref": "destination.json", - "description": "A destination platform where signals can be activated (DSP, sales agent, etc.)" + "list-creative-formats": { + "request": { + "$ref": "/schemas/v1/creative/list-creative-formats-request.json", + "description": "Request parameters for discovering creative formats from this creative agent" + }, + "response": { + "$ref": "/schemas/v1/creative/list-creative-formats-response.json", + "description": "Response payload with full format definitions - this is the authoritative source for format specifications" + } }, - "deployment": { - "$ref": "deployment.json", - "description": "A signal deployment to a specific destination platform with activation status and key" + "preview-creative": { + "request": { + "$ref": "/schemas/v1/creative/preview-creative-request.json", + "description": "Request parameters for generating creative previews" + }, + "response": { + "$ref": "/schemas/v1/creative/preview-creative-response.json", + "description": "Response payload for preview_creative task" + } } } }, "enums": { "description": "Enumerated types and constants", "schemas": { - "pricing-model": { - "$ref": "pricing-model.json", - "description": "Supported pricing models for advertising products" + "channels": { + "$ref": "/schemas/v1/enums/channels.json", + "description": "Advertising channels (display, video, dooh, ctv, audio, etc.)" + }, + "creative-status": { + "$ref": "/schemas/v1/enums/creative-status.json", + "description": "Status of a creative asset" }, "delivery-type": { - "$ref": "delivery-type.json", + "$ref": "/schemas/v1/enums/delivery-type.json", "description": "Type of inventory delivery" }, - "media-buy-status": { - "$ref": "media-buy-status.json", - "description": "Status of a media buy" + "frequency-cap-scope": { + "$ref": "/schemas/v1/enums/frequency-cap-scope.json", + "description": "Scope for frequency cap application" }, - "package-status": { - "$ref": "package-status.json", - "description": "Status of a package" + "identifier-types": { + "$ref": "/schemas/v1/enums/identifier-types.json", + "description": "Valid identifier types for property identification across different media types" }, - "creative-status": { - "$ref": "creative-status.json", - "description": "Status of a creative asset" + "media-buy-status": { + "$ref": "/schemas/v1/enums/media-buy-status.json", + "description": "Status of a media buy" }, "pacing": { - "$ref": "pacing.json", + "$ref": "/schemas/v1/enums/pacing.json", "description": "Budget pacing strategy" }, - "frequency-cap-scope": { - "$ref": "frequency-cap-scope.json", - "description": "Scope for frequency cap application" - }, - "standard-format-ids": { - "$ref": "standard-format-ids.json", - "description": "Enumeration of all standard creative format identifiers" + "package-status": { + "$ref": "/schemas/v1/enums/package-status.json", + "description": "Status of a package" }, - "identifier-types": { - "$ref": "identifier-types.json", - "description": "Valid identifier types for property identification across different media types" + "pricing-model": { + "$ref": "/schemas/v1/enums/pricing-model.json", + "description": "Supported pricing models for advertising products" }, "publisher-identifier-types": { - "$ref": "publisher-identifier-types.json", + "$ref": "/schemas/v1/enums/publisher-identifier-types.json", "description": "Valid identifier types for publisher/legal entity identification (TAG ID, DUNS, LEI, seller_id, GLN)" }, - "channels": { - "$ref": "channels.json", - "description": "Advertising channels (display, video, dooh, ctv, audio, etc.)" + "standard-format-ids": { + "$ref": "/schemas/v1/enums/standard-format-ids.json", + "description": "Enumeration of all standard creative format identifiers" }, "task-status": { - "$ref": "task-status.json", + "$ref": "/schemas/v1/enums/task-status.json", "description": "Standardized task status values based on A2A TaskState enum" }, "task-type": { - "$ref": "task-type.json", + "$ref": "/schemas/v1/enums/task-type.json", "description": "Valid AdCP task types across all domains (create_media_buy, update_media_buy, sync_creatives, activate_signal, get_signals)" } } }, - "pricing-options": { - "description": "Individual pricing model schemas with model-specific validation. CPM and vCPM support both fixed and auction pricing; all other models are fixed-rate only.", - "schemas": { - "cpm-fixed-option": { - "$ref": "cpm-fixed-option.json", - "description": "Cost Per Mille (CPM) fixed-rate pricing for direct/guaranteed deals" - }, - "cpm-auction-option": { - "$ref": "cpm-auction-option.json", - "description": "Cost Per Mille (CPM) auction-based pricing for programmatic/non-guaranteed inventory" - }, - "vcpm-fixed-option": { - "$ref": "vcpm-fixed-option.json", - "description": "Viewable Cost Per Mille (vCPM) fixed-rate pricing for viewability-guaranteed deals" - }, - "vcpm-auction-option": { - "$ref": "vcpm-auction-option.json", - "description": "Viewable Cost Per Mille (vCPM) auction-based pricing for programmatic inventory with viewability guarantee" - }, - "cpc-option": { - "$ref": "cpc-option.json", - "description": "Cost Per Click (CPC) fixed-rate pricing for performance campaigns" - }, - "cpcv-option": { - "$ref": "cpcv-option.json", - "description": "Cost Per Completed View (CPCV) fixed-rate pricing for video/audio" - }, - "cpv-option": { - "$ref": "cpv-option.json", - "description": "Cost Per View (CPV) fixed-rate pricing with threshold" - }, - "cpp-option": { - "$ref": "cpp-option.json", - "description": "Cost Per Point (CPP) fixed-rate pricing for TV/audio with demographic measurement" - }, - "flat-rate-option": { - "$ref": "flat-rate-option.json", - "description": "Flat rate pricing for DOOH and sponsorships" - } - } - }, "media-buy": { "description": "Media buy task request/response schemas", "supporting-schemas": { "package-request": { - "$ref": "package-request.json", + "$ref": "/schemas/v1/media-buy/package-request.json", "description": "Package configuration for media buy creation - used within create_media_buy request" } }, "tasks": { - "get-products": { - "request": { - "$ref": "get-products-request.json", - "description": "Request parameters for discovering available advertising products" - }, - "response": { - "$ref": "get-products-response.json", - "description": "Response payload for get_products task" - } - }, - "list-creative-formats": { - "request": { - "$ref": "list-creative-formats-request.json", - "description": "Request parameters for discovering format IDs and creative agents supported by this sales agent" - }, - "response": { - "$ref": "list-creative-formats-response.json", - "description": "Response payload with format_ids and creative_agents list. Sales agent returns which formats it supports and which creative agents provide those formats. Buyers query creative agents for full format specifications." - } - }, "create-media-buy": { "request": { - "$ref": "create-media-buy-request.json", + "$ref": "/schemas/v1/media-buy/create-media-buy-request.json", "description": "Request parameters for creating a media buy" }, "response": { - "$ref": "create-media-buy-response.json", + "$ref": "/schemas/v1/media-buy/create-media-buy-response.json", "description": "Response payload for create_media_buy task" } }, - "sync-creatives": { + "get-media-buy-delivery": { "request": { - "$ref": "sync-creatives-request.json", - "description": "Request parameters for syncing creative assets with upsert semantics" + "$ref": "/schemas/v1/media-buy/get-media-buy-delivery-request.json", + "description": "Request parameters for retrieving comprehensive delivery metrics" }, "response": { - "$ref": "sync-creatives-response.json", - "description": "Response payload for sync_creatives task" + "$ref": "/schemas/v1/media-buy/get-media-buy-delivery-response.json", + "description": "Response payload for get_media_buy_delivery task" } }, - "list-creatives": { + "get-products": { "request": { - "$ref": "list-creatives-request.json", - "description": "Request parameters for querying creative library with filtering and pagination" + "$ref": "/schemas/v1/media-buy/get-products-request.json", + "description": "Request parameters for discovering available advertising products" }, "response": { - "$ref": "list-creatives-response.json", - "description": "Response payload for list_creatives task" + "$ref": "/schemas/v1/media-buy/get-products-response.json", + "description": "Response payload for get_products task" } }, - "update-media-buy": { + "list-authorized-properties": { "request": { - "$ref": "update-media-buy-request.json", - "description": "Request parameters for updating campaign and package settings" + "$ref": "/schemas/v1/media-buy/list-authorized-properties-request.json", + "description": "Request parameters for discovering all properties this agent is authorized to represent" }, "response": { - "$ref": "update-media-buy-response.json", - "description": "Response payload for update_media_buy task" + "$ref": "/schemas/v1/media-buy/list-authorized-properties-response.json", + "description": "Response payload for list_authorized_properties task" } }, - "get-media-buy-delivery": { + "list-creative-formats": { "request": { - "$ref": "get-media-buy-delivery-request.json", - "description": "Request parameters for retrieving comprehensive delivery metrics" + "$ref": "/schemas/v1/media-buy/list-creative-formats-request.json", + "description": "Request parameters for discovering format IDs and creative agents supported by this sales agent" }, "response": { - "$ref": "get-media-buy-delivery-response.json", - "description": "Response payload for get_media_buy_delivery task" + "$ref": "/schemas/v1/media-buy/list-creative-formats-response.json", + "description": "Response payload with format_ids and creative_agents list. Sales agent returns which formats it supports and which creative agents provide those formats. Buyers query creative agents for full format specifications." } }, - "list-authorized-properties": { + "list-creatives": { "request": { - "$ref": "list-authorized-properties-request.json", - "description": "Request parameters for discovering all properties this agent is authorized to represent" + "$ref": "/schemas/v1/media-buy/list-creatives-request.json", + "description": "Request parameters for querying creative library with filtering and pagination" }, "response": { - "$ref": "list-authorized-properties-response.json", - "description": "Response payload for list_authorized_properties task" + "$ref": "/schemas/v1/media-buy/list-creatives-response.json", + "description": "Response payload for list_creatives task" } }, "provide-performance-feedback": { "request": { - "$ref": "provide-performance-feedback-request.json", + "$ref": "/schemas/v1/media-buy/provide-performance-feedback-request.json", "description": "Request parameters for sharing performance outcomes with publishers" }, "response": { - "$ref": "provide-performance-feedback-response.json", + "$ref": "/schemas/v1/media-buy/provide-performance-feedback-response.json", "description": "Response payload for provide_performance_feedback task" } - } - } - }, - "creative": { - "description": "Creative protocol task request/response schemas and asset type definitions", - "tasks": { - "build-creative": { - "request": { - "$ref": "build-creative-request.json", - "description": "Request parameters for AI-powered creative generation" - }, - "response": { - "$ref": "build-creative-response.json", - "description": "Response payload for build_creative task" - } }, - "preview-creative": { + "sync-creatives": { "request": { - "$ref": "preview-creative-request.json", - "description": "Request parameters for generating creative previews" + "$ref": "/schemas/v1/media-buy/sync-creatives-request.json", + "description": "Request parameters for syncing creative assets with upsert semantics" }, "response": { - "$ref": "preview-creative-response.json", - "description": "Response payload for preview_creative task" + "$ref": "/schemas/v1/media-buy/sync-creatives-response.json", + "description": "Response payload for sync_creatives task" } }, - "list-creative-formats": { + "update-media-buy": { "request": { - "$ref": "list-creative-formats-request.json", - "description": "Request parameters for discovering creative formats from this creative agent" + "$ref": "/schemas/v1/media-buy/update-media-buy-request.json", + "description": "Request parameters for updating campaign and package settings" }, "response": { - "$ref": "list-creative-formats-response.json", - "description": "Response payload with full format definitions - this is the authoritative source for format specifications" + "$ref": "/schemas/v1/media-buy/update-media-buy-response.json", + "description": "Response payload for update_media_buy task" } } - }, - "asset_types": { - "$ref": "index.json", - "description": "Asset type definitions for creative manifests" + } + }, + "pricing-options": { + "description": "Individual pricing model schemas with model-specific validation. CPM and vCPM support both fixed and auction pricing; all other models are fixed-rate only.", + "schemas": { + "cpc-option": { + "$ref": "/schemas/v1/pricing-options/cpc-option.json", + "description": "Cost Per Click (CPC) fixed-rate pricing for performance campaigns" + }, + "cpcv-option": { + "$ref": "/schemas/v1/pricing-options/cpcv-option.json", + "description": "Cost Per Completed View (CPCV) fixed-rate pricing for video/audio" + }, + "cpm-auction-option": { + "$ref": "/schemas/v1/pricing-options/cpm-auction-option.json", + "description": "Cost Per Mille (CPM) auction-based pricing for programmatic/non-guaranteed inventory" + }, + "cpm-fixed-option": { + "$ref": "/schemas/v1/pricing-options/cpm-fixed-option.json", + "description": "Cost Per Mille (CPM) fixed-rate pricing for direct/guaranteed deals" + }, + "cpp-option": { + "$ref": "/schemas/v1/pricing-options/cpp-option.json", + "description": "Cost Per Point (CPP) fixed-rate pricing for TV/audio with demographic measurement" + }, + "cpv-option": { + "$ref": "/schemas/v1/pricing-options/cpv-option.json", + "description": "Cost Per View (CPV) fixed-rate pricing with threshold" + }, + "flat-rate-option": { + "$ref": "/schemas/v1/pricing-options/flat-rate-option.json", + "description": "Flat rate pricing for DOOH and sponsorships" + }, + "vcpm-auction-option": { + "$ref": "/schemas/v1/pricing-options/vcpm-auction-option.json", + "description": "Viewable Cost Per Mille (vCPM) auction-based pricing for programmatic inventory with viewability guarantee" + }, + "vcpm-fixed-option": { + "$ref": "/schemas/v1/pricing-options/vcpm-fixed-option.json", + "description": "Viewable Cost Per Mille (vCPM) fixed-rate pricing for viewability-guaranteed deals" + } } }, "signals": { "description": "Signals protocol task request/response schemas", "tasks": { - "get-signals": { + "activate-signal": { "request": { - "$ref": "get-signals-request.json", - "description": "Request parameters for discovering signals based on description" + "$ref": "/schemas/v1/signals/activate-signal-request.json", + "description": "Request parameters for activating a signal on a specific platform/account" }, "response": { - "$ref": "get-signals-response.json", - "description": "Response payload for get_signals task" + "$ref": "/schemas/v1/signals/activate-signal-response.json", + "description": "Response payload for activate_signal task" } }, - "activate-signal": { + "get-signals": { "request": { - "$ref": "activate-signal-request.json", - "description": "Request parameters for activating a signal on a specific platform/account" + "$ref": "/schemas/v1/signals/get-signals-request.json", + "description": "Request parameters for discovering signals based on description" }, "response": { - "$ref": "activate-signal-response.json", - "description": "Response payload for activate_signal task" + "$ref": "/schemas/v1/signals/get-signals-response.json", + "description": "Response payload for get_signals task" } } } - }, - "adagents": { - "description": "Authorized sales agents file format specification", - "$ref": "adagents.json", - "file_location": "/.well-known/adagents.json", - "purpose": "Declares which sales agents are authorized to sell a publisher's advertising inventory" } }, + "standard_formats_version": "2.0.0", + "title": "AdCP Schema Registry v1", "usage": { - "validation": "Use these schemas to validate AdCP requests and responses", "codeGeneration": "Generate client SDKs using these schemas", "documentation": "Reference schemas for API documentation", - "testing": "Validate test fixtures and examples" + "testing": "Validate test fixtures and examples", + "validation": "Use these schemas to validate AdCP requests and responses" }, - "examples": [ - { - "language": "javascript", - "description": "JavaScript validation example", - "code": "const Ajv = require('ajv'); const ajv = new Ajv(); const schema = require('./schemas/v1/core/product.json'); const validate = ajv.compile(schema);" - }, - { - "language": "python", - "description": "Python validation example", - "code": "import jsonschema; schema = {...}; jsonschema.validate(data, schema)" - }, - { - "language": "java", - "description": "Java validation example", - "code": "// Use everit-org/json-schema or similar library" - } - ] + "version": "1.0.0", + "versioning": { + "note": "AdCP uses path-based versioning. The schema URL path (/schemas/v1/) indicates the version. Individual request/response schemas do NOT include adcp_version fields. Compatibility follows semantic versioning rules." + } } \ No newline at end of file diff --git a/schemas/cache/1.0.0/product.json b/schemas/cache/1.0.0/product.json index d569b5bb..9f762d9f 100644 --- a/schemas/cache/1.0.0/product.json +++ b/schemas/cache/1.0.0/product.json @@ -126,94 +126,7 @@ "publisher_properties": { "description": "Publisher properties covered by this product. Buyers fetch actual property definitions from each publisher's adagents.json and validate agent authorization. Selection patterns mirror the authorization patterns in adagents.json for consistency.", "items": { - "discriminator": { - "propertyName": "selection_type" - }, - "oneOf": [ - { - "additionalProperties": false, - "description": "Select all properties from the publisher domain", - "properties": { - "publisher_domain": { - "description": "Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", - "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$", - "type": "string" - }, - "selection_type": { - "const": "all", - "description": "Discriminator indicating all properties from this publisher are included", - "type": "string" - } - }, - "required": [ - "publisher_domain", - "selection_type" - ], - "type": "object" - }, - { - "additionalProperties": false, - "description": "Select specific properties by ID", - "properties": { - "property_ids": { - "description": "Specific property IDs from the publisher's adagents.json", - "items": { - "pattern": "^[a-z0-9_]+$", - "type": "string" - }, - "minItems": 1, - "type": "array" - }, - "publisher_domain": { - "description": "Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", - "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$", - "type": "string" - }, - "selection_type": { - "const": "by_id", - "description": "Discriminator indicating selection by specific property IDs", - "type": "string" - } - }, - "required": [ - "publisher_domain", - "selection_type", - "property_ids" - ], - "type": "object" - }, - { - "additionalProperties": false, - "description": "Select properties by tag membership", - "properties": { - "property_tags": { - "description": "Property tags from the publisher's adagents.json. Product covers all properties with these tags", - "items": { - "pattern": "^[a-z0-9_]+$", - "type": "string" - }, - "minItems": 1, - "type": "array" - }, - "publisher_domain": { - "description": "Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", - "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$", - "type": "string" - }, - "selection_type": { - "const": "by_tag", - "description": "Discriminator indicating selection by property tags", - "type": "string" - } - }, - "required": [ - "publisher_domain", - "selection_type", - "property_tags" - ], - "type": "object" - } - ] + "$ref": "/schemas/v1/core/publisher-property-selector.json" }, "minItems": 1, "type": "array" diff --git a/schemas/cache/1.0.0/publisher-property-selector.json b/schemas/cache/1.0.0/publisher-property-selector.json new file mode 100644 index 00000000..228e6b8d --- /dev/null +++ b/schemas/cache/1.0.0/publisher-property-selector.json @@ -0,0 +1,94 @@ +{ + "$id": "/schemas/v1/core/publisher-property-selector.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Selects properties from a publisher's adagents.json. Used for both product definitions and agent authorization. Supports three selection patterns: all properties, specific IDs, or by tags.", + "discriminator": { + "propertyName": "selection_type" + }, + "oneOf": [ + { + "additionalProperties": false, + "description": "Select all properties from the publisher domain", + "properties": { + "publisher_domain": { + "description": "Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", + "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$", + "type": "string" + }, + "selection_type": { + "const": "all", + "description": "Discriminator indicating all properties from this publisher are included", + "type": "string" + } + }, + "required": [ + "publisher_domain", + "selection_type" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "Select specific properties by ID", + "properties": { + "property_ids": { + "description": "Specific property IDs from the publisher's adagents.json", + "items": { + "pattern": "^[a-z0-9_]+$", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "publisher_domain": { + "description": "Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", + "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$", + "type": "string" + }, + "selection_type": { + "const": "by_id", + "description": "Discriminator indicating selection by specific property IDs", + "type": "string" + } + }, + "required": [ + "publisher_domain", + "selection_type", + "property_ids" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "Select properties by tag membership", + "properties": { + "property_tags": { + "description": "Property tags from the publisher's adagents.json. Selector covers all properties with these tags", + "items": { + "pattern": "^[a-z0-9_]+$", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "publisher_domain": { + "description": "Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", + "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$", + "type": "string" + }, + "selection_type": { + "const": "by_tag", + "description": "Discriminator indicating selection by property tags", + "type": "string" + } + }, + "required": [ + "publisher_domain", + "selection_type", + "property_tags" + ], + "type": "object" + } + ], + "title": "Publisher Property Selector" +} \ No newline at end of file diff --git a/scripts/consolidate_exports.py b/scripts/consolidate_exports.py index f1bc13dc..755de5c1 100644 --- a/scripts/consolidate_exports.py +++ b/scripts/consolidate_exports.py @@ -58,6 +58,15 @@ def generate_consolidated_exports() -> str: all_exports = set() collisions = [] + # Special handling for known collisions + # We need BOTH versions of these types available, so import them with qualified names + KNOWN_COLLISIONS = { + "Package": {"package", "create_media_buy_response"}, + } + + special_imports = [] + collision_modules_seen: dict[str, set[str]] = {name: set() for name in KNOWN_COLLISIONS} + for module_path in modules: module_name = module_path.stem exports = extract_exports_from_module(module_path) @@ -68,9 +77,15 @@ def generate_consolidated_exports() -> str: # Filter out names that collide with already-exported names unique_exports = set() for export_name in exports: + # Special case: Known collisions - track all modules that define them + if export_name in KNOWN_COLLISIONS and module_name in KNOWN_COLLISIONS[export_name]: + collision_modules_seen[export_name].add(module_name) + export_to_module[export_name] = module_name # Track that we've seen it + continue # Don't add to unique_exports, we'll handle specially + if export_name in export_to_module: - # Collision detected - skip this duplicate first_module = export_to_module[export_name] + # Collision detected - skip this duplicate collisions.append( f" {export_name}: defined in both {first_module} and {module_name} (using {first_module})" ) @@ -91,6 +106,20 @@ def generate_consolidated_exports() -> str: all_exports.update(unique_exports) + # Generate special imports for all known collisions + for type_name, modules_seen in collision_modules_seen.items(): + if not modules_seen: + continue + collisions.append( + f" {type_name}: defined in {sorted(modules_seen)} (all exported with qualified names)" + ) + for module_name in sorted(modules_seen): + qualified_name = f"_{type_name}From{module_name.replace('_', ' ').title().replace(' ', '')}" + special_imports.append( + f"from adcp.types.generated_poc.{module_name} import {type_name} as {qualified_name}" + ) + all_exports.add(qualified_name) + if collisions: print("\n⚠️ Name collisions detected (duplicates skipped):") for collision in sorted(collisions): @@ -121,6 +150,11 @@ def generate_consolidated_exports() -> str: lines.extend(import_lines) + # Add special imports for name collisions + if special_imports: + lines.extend(["", "# Special imports for name collisions (qualified names for types defined in multiple modules)"]) + lines.extend(special_imports) + # Add backward compatibility aliases (only if source exists) aliases = {} if "AdvertisingChannels" in all_exports: diff --git a/src/adcp/__init__.py b/src/adcp/__init__.py index d4444796..c82a66b9 100644 --- a/src/adcp/__init__.py +++ b/src/adcp/__init__.py @@ -56,47 +56,6 @@ from adcp.types import _generated as generated from adcp.types import aliases -# Re-export commonly-used request/response types for convenience -# Users should import from main package (e.g., `from adcp import GetProductsRequest`) -# rather than internal modules for better API stability -from adcp.types._generated import ( - # Audience & Targeting - ActivateSignalRequest, - ActivateSignalResponse, - # Creative Operations - BuildCreativeRequest, - BuildCreativeResponse, - # Media Buy Operations - CreateMediaBuyRequest, - CreateMediaBuyResponse, - # Common data types - Error, - Format, - GetMediaBuyDeliveryRequest, - GetMediaBuyDeliveryResponse, - GetProductsRequest, - GetProductsResponse, - GetSignalsRequest, - GetSignalsResponse, - ListAuthorizedPropertiesRequest, - ListAuthorizedPropertiesResponse, - ListCreativeFormatsRequest, - ListCreativeFormatsResponse, - ListCreativesRequest, - ListCreativesResponse, - PreviewCreativeRequest, - PreviewCreativeResponse, - Product, - Property, - ProvidePerformanceFeedbackRequest, - ProvidePerformanceFeedbackResponse, - SyncCreativesRequest, - SyncCreativesResponse, - UpdateMediaBuyRequest, - UpdateMediaBuyResponse, -) -from adcp.types._generated import TaskStatus as GeneratedTaskStatus - # Re-export semantic type aliases for better ergonomics from adcp.types.aliases import ( ActivateSignalErrorResponse, @@ -141,11 +100,20 @@ ) from adcp.types.core import AgentConfig, Protocol, TaskResult, TaskStatus, WebhookMetadata +# Re-export commonly-used request/response types for convenience +# Users should import from main package (e.g., `from adcp import GetProductsRequest`) +# rather than internal modules for better API stability # Re-export core domain types and pricing options from stable API # These are commonly used in typical workflows from adcp.types.stable import ( + # Audience & Targeting + ActivateSignalRequest, + ActivateSignalResponse, # Core domain types BrandManifest, + # Creative Operations + BuildCreativeRequest, + BuildCreativeResponse, # Pricing options (all 9 types for product creation) CpcPricingOption, CpcvPricingOption, @@ -153,19 +121,50 @@ CpmFixedRatePricingOption, CppPricingOption, CpvPricingOption, + # Media Buy Operations + CreateMediaBuyRequest, + CreateMediaBuyResponse, Creative, CreativeManifest, # Status enums (for control flow) CreativeStatus, + # Common data types + Error, FlatRatePricingOption, + Format, + GetMediaBuyDeliveryRequest, + GetMediaBuyDeliveryResponse, + GetProductsRequest, + GetProductsResponse, + GetSignalsRequest, + GetSignalsResponse, + ListAuthorizedPropertiesRequest, + ListAuthorizedPropertiesResponse, + ListCreativeFormatsRequest, + ListCreativeFormatsResponse, + ListCreativesRequest, + ListCreativesResponse, MediaBuy, MediaBuyStatus, Package, PackageStatus, + PreviewCreativeRequest, + PreviewCreativeResponse, PricingModel, + Product, + Property, + ProvidePerformanceFeedbackRequest, + ProvidePerformanceFeedbackResponse, + SyncCreativesRequest, + SyncCreativesResponse, + UpdateMediaBuyRequest, + UpdateMediaBuyResponse, VcpmAuctionPricingOption, VcpmFixedRatePricingOption, ) +from adcp.types.stable import ( + TaskStatus as GeneratedTaskStatus, +) from adcp.validation import ( ValidationError, validate_adagents, diff --git a/src/adcp/client.py b/src/adcp/client.py index 7b04128a..b02cc44c 100644 --- a/src/adcp/client.py +++ b/src/adcp/client.py @@ -17,7 +17,15 @@ from adcp.protocols.a2a import A2AAdapter from adcp.protocols.base import ProtocolAdapter from adcp.protocols.mcp import MCPAdapter -from adcp.types._generated import ( +from adcp.types.core import ( + Activity, + ActivityType, + AgentConfig, + Protocol, + TaskResult, + TaskStatus, +) +from adcp.types.stable import ( ActivateSignalRequest, ActivateSignalResponse, GetMediaBuyDeliveryRequest, @@ -40,15 +48,9 @@ SyncCreativesResponse, WebhookPayload, ) -from adcp.types.core import ( - Activity, - ActivityType, - AgentConfig, - Protocol, - TaskResult, - TaskStatus, +from adcp.types.stable import ( + TaskStatus as GeneratedTaskStatus, ) -from adcp.types.generated_poc.task_status import TaskStatus as GeneratedTaskStatus from adcp.utils.operation_id import create_operation_id logger = logging.getLogger(__name__) diff --git a/src/adcp/simple.py b/src/adcp/simple.py index 4e2090ba..6455eef4 100644 --- a/src/adcp/simple.py +++ b/src/adcp/simple.py @@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, Any from adcp.exceptions import ADCPSimpleAPIError -from adcp.types._generated import ( +from adcp.types.stable import ( ActivateSignalRequest, ActivateSignalResponse, GetMediaBuyDeliveryRequest, diff --git a/src/adcp/types/_generated.py b/src/adcp/types/_generated.py index fdb9471d..f2271134 100644 --- a/src/adcp/types/_generated.py +++ b/src/adcp/types/_generated.py @@ -10,7 +10,7 @@ DO NOT EDIT MANUALLY. Generated from: https://github.com/adcontextprotocol/adcp/tree/main/schemas -Generation date: 2025-11-18 12:52:17 UTC +Generation date: 2025-11-19 02:03:09 UTC """ # ruff: noqa: E501, I001 from __future__ import annotations @@ -19,7 +19,7 @@ from adcp.types.generated_poc.activate_signal_request import ActivateSignalRequest from adcp.types.generated_poc.activate_signal_response import ActivateSignalResponse, ActivateSignalResponse1, ActivateSignalResponse2 from adcp.types.generated_poc.activation_key import ActivationKey1, ActivationKey2 -from adcp.types.generated_poc.adagents import AuthorizedAgents, AuthorizedAgents1, AuthorizedAgents2, AuthorizedAgents3, AuthorizedSalesAgents, Contact, PropertyId, PropertyTag, PublisherProperties, PublisherProperties1, Tags +from adcp.types.generated_poc.adagents import AuthorizedAgents, AuthorizedAgents1, AuthorizedAgents2, AuthorizedAgents3, AuthorizedSalesAgents, Contact, PropertyId, PropertyTag, Tags from adcp.types.generated_poc.asset_type import AssetTypeSchema, ContentLength, Dimensions, Duration, FileSize, Quality, Requirements, Type from adcp.types.generated_poc.audio_asset import AudioAsset from adcp.types.generated_poc.brand_manifest import Asset, AssetType, BrandManifest, Colors, Disclaimer, FeedFormat, Fonts, Logo, Metadata, ProductCatalog, UpdateFrequency @@ -33,7 +33,7 @@ from adcp.types.generated_poc.cpp_option import CppPricingOption, Parameters from adcp.types.generated_poc.cpv_option import CpvPricingOption, ViewThreshold, ViewThreshold1 from adcp.types.generated_poc.create_media_buy_request import CreateMediaBuyRequest, ReportingFrequency, ReportingWebhook, RequestedMetric -from adcp.types.generated_poc.create_media_buy_response import CreateMediaBuyResponse, CreateMediaBuyResponse1, CreateMediaBuyResponse2, Package +from adcp.types.generated_poc.create_media_buy_response import CreateMediaBuyResponse, CreateMediaBuyResponse1, CreateMediaBuyResponse2 from adcp.types.generated_poc.creative_asset import CreativeAsset, Input from adcp.types.generated_poc.creative_assignment import CreativeAssignment from adcp.types.generated_poc.creative_manifest import CreativeManifest @@ -80,7 +80,7 @@ from adcp.types.generated_poc.preview_creative_response import Input4, Preview, Preview1, Preview2, PreviewCreativeResponse, PreviewCreativeResponse1, PreviewCreativeResponse2, Response, Response1, Results, Results1 from adcp.types.generated_poc.preview_render import Embedding, PreviewRender, PreviewRender1, PreviewRender2, PreviewRender3 from adcp.types.generated_poc.pricing_model import PricingModel -from adcp.types.generated_poc.product import DeliveryMeasurement, Product, ProductCard, ProductCardDetailed, PublisherProperties4, PublisherProperties5 +from adcp.types.generated_poc.product import DeliveryMeasurement, Product, ProductCard, ProductCardDetailed from adcp.types.generated_poc.promoted_offerings import AssetSelectors, Offering, PromotedOfferings from adcp.types.generated_poc.promoted_products import PromotedProducts from adcp.types.generated_poc.property import Identifier, Property, PropertyType, Tag @@ -88,6 +88,7 @@ from adcp.types.generated_poc.provide_performance_feedback_request import ProvidePerformanceFeedbackRequest from adcp.types.generated_poc.provide_performance_feedback_response import ProvidePerformanceFeedbackResponse, ProvidePerformanceFeedbackResponse1, ProvidePerformanceFeedbackResponse2 from adcp.types.generated_poc.publisher_identifier_types import PublisherIdentifierTypes +from adcp.types.generated_poc.publisher_property_selector import PublisherPropertySelector1, PublisherPropertySelector2, PublisherPropertySelector3 from adcp.types.generated_poc.push_notification_config import Authentication, PushNotificationConfig, Scheme from adcp.types.generated_poc.reporting_capabilities import AvailableMetric, AvailableReportingFrequency, ReportingCapabilities from adcp.types.generated_poc.response import ProtocolResponse @@ -113,6 +114,10 @@ from adcp.types.generated_poc.webhook_asset import Method, Method1, ResponseType, Security, WebhookAsset from adcp.types.generated_poc.webhook_payload import WebhookPayload +# Special imports for name collisions (qualified names for types defined in multiple modules) +from adcp.types.generated_poc.create_media_buy_response import Package as _PackageFromCreateMediaBuyResponse +from adcp.types.generated_poc.package import Package as _PackageFromPackage + # Backward compatibility aliases for renamed types Channels = AdvertisingChannels @@ -146,9 +151,9 @@ "ListCreativesResponse", "Logo", "MarkdownAsset", "MarkdownFlavor", "Measurement", "MeasurementPeriod", "MediaBuy", "MediaBuyDelivery", "MediaBuyStatus", "Metadata", "Method", "Method1", "MetricType", "ModuleType", "NotificationType", "Offering", "OutputFormat", - "Pacing", "Package", "PackageRequest", "PackageStatus", "Packages", "Packages1", "Packages2", - "Packages3", "Pagination", "Parameters", "Performance", "PerformanceFeedback", "Placement", - "Preview", "Preview1", "Preview2", "PreviewCreativeRequest", "PreviewCreativeRequest1", + "Pacing", "PackageRequest", "PackageStatus", "Packages", "Packages1", "Packages2", "Packages3", + "Pagination", "Parameters", "Performance", "PerformanceFeedback", "Placement", "Preview", + "Preview1", "Preview2", "PreviewCreativeRequest", "PreviewCreativeRequest1", "PreviewCreativeRequest2", "PreviewCreativeResponse", "PreviewCreativeResponse1", "PreviewCreativeResponse2", "PreviewRender", "PreviewRender1", "PreviewRender2", "PreviewRender3", "PriceGuidance", "Pricing", "PricingModel", "PrimaryCountry", "Product", @@ -157,7 +162,7 @@ "PropertyType", "ProtocolEnvelope", "ProtocolResponse", "ProvidePerformanceFeedbackRequest", "ProvidePerformanceFeedbackResponse", "ProvidePerformanceFeedbackResponse1", "ProvidePerformanceFeedbackResponse2", "PublisherDomain", "PublisherIdentifierTypes", - "PublisherProperties", "PublisherProperties1", "PublisherProperties4", "PublisherProperties5", + "PublisherPropertySelector1", "PublisherPropertySelector2", "PublisherPropertySelector3", "PushNotificationConfig", "Quality", "QuartileData", "QuerySummary", "Render", "ReportingCapabilities", "ReportingFrequency", "ReportingPeriod", "ReportingWebhook", "Request", "RequestedMetric", "Requirements", "Response", "Response1", "ResponseType", @@ -171,5 +176,6 @@ "UpdateMediaBuyResponse", "UpdateMediaBuyResponse1", "UpdateMediaBuyResponse2", "UrlAsset", "UrlType", "ValidationMode", "VastAsset1", "VastAsset2", "VastVersion", "VcpmAuctionPricingOption", "VcpmFixedRatePricingOption", "VenueBreakdownItem", "VideoAsset", - "ViewThreshold", "ViewThreshold1", "WebhookAsset", "WebhookPayload" + "ViewThreshold", "ViewThreshold1", "WebhookAsset", "WebhookPayload", + "_PackageFromCreateMediaBuyResponse", "_PackageFromPackage" ] diff --git a/src/adcp/types/aliases.py b/src/adcp/types/aliases.py index 6a3da58a..437221f0 100644 --- a/src/adcp/types/aliases.py +++ b/src/adcp/types/aliases.py @@ -31,7 +31,6 @@ from __future__ import annotations -# Import all generated types that need semantic aliases from adcp.types._generated import ( # Activation responses ActivateSignalResponse1, @@ -64,6 +63,9 @@ PreviewRender1, PreviewRender2, PreviewRender3, + # Publisher properties types + PropertyId, + PropertyTag, # Performance feedback responses ProvidePerformanceFeedbackResponse1, ProvidePerformanceFeedbackResponse2, @@ -83,26 +85,23 @@ VastAsset1, VastAsset2, ) - -# Import Package types directly from their modules to avoid collision issues -from adcp.types.generated_poc.create_media_buy_response import ( - Package as CreatedPackageInternal, +from adcp.types._generated import ( + PublisherPropertySelector1 as PublisherPropertiesInternal, ) -from adcp.types.generated_poc.package import Package as FullPackageInternal - -# Import PublisherProperties types and related types from product module -from adcp.types.generated_poc.product import ( - PropertyId, - PropertyTag, +from adcp.types._generated import ( + PublisherPropertySelector2 as PublisherPropertiesByIdInternal, ) -from adcp.types.generated_poc.product import ( - PublisherProperties as PublisherPropertiesInternal, +from adcp.types._generated import ( + PublisherPropertySelector3 as PublisherPropertiesByTagInternal, ) -from adcp.types.generated_poc.product import ( - PublisherProperties4 as PublisherPropertiesByIdInternal, + +# Import all generated types that need semantic aliases +from adcp.types._generated import ( + # Package types (from name collision resolution) + _PackageFromCreateMediaBuyResponse as CreatedPackageInternal, ) -from adcp.types.generated_poc.product import ( - PublisherProperties5 as PublisherPropertiesByTagInternal, +from adcp.types._generated import ( + _PackageFromPackage as FullPackageInternal, ) # ============================================================================ diff --git a/src/adcp/types/generated_poc/adagents.py b/src/adcp/types/generated_poc/adagents.py index b0549acc..6833985b 100644 --- a/src/adcp/types/generated_poc/adagents.py +++ b/src/adcp/types/generated_poc/adagents.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: adagents.json -# timestamp: 2025-11-18T03:35:10+00:00 +# timestamp: 2025-11-19T02:02:39+00:00 from __future__ import annotations @@ -9,7 +9,7 @@ from adcp.types.base import AdCPBaseModel from pydantic import AnyUrl, AwareDatetime, ConfigDict, EmailStr, Field, RootModel -from . import property +from . import property, publisher_property_selector class PropertyId(RootModel[str]): @@ -72,81 +72,6 @@ class AuthorizedAgents1(AdCPBaseModel): url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")] -class PublisherProperties(AdCPBaseModel): - model_config = ConfigDict( - extra='forbid', - ) - property_ids: Annotated[ - list[PropertyId], - Field( - description="Specific property IDs from the publisher's adagents.json properties array", - min_length=1, - ), - ] - publisher_domain: Annotated[ - str, - Field( - description="Domain where the publisher's adagents.json is hosted (e.g., 'cnn.com')", - pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', - ), - ] - selection_type: Annotated[ - Literal['by_id'], - Field(description='Discriminator indicating selection by specific property IDs'), - ] - - -class PublisherProperties1(AdCPBaseModel): - model_config = ConfigDict( - extra='forbid', - ) - property_tags: Annotated[ - list[PropertyTag], - Field( - description="Property tags from the publisher's adagents.json tags. Agent is authorized for all properties with these tags", - min_length=1, - ), - ] - publisher_domain: Annotated[ - str, - Field( - description="Domain where the publisher's adagents.json is hosted (e.g., 'cnn.com')", - pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', - ), - ] - selection_type: Annotated[ - Literal['by_tag'], Field(description='Discriminator indicating selection by property tags') - ] - - -class AuthorizedAgents3(AdCPBaseModel): - model_config = ConfigDict( - extra='forbid', - ) - authorization_type: Annotated[ - Literal['publisher_properties'], - Field( - description='Discriminator indicating authorization for properties from other publisher domains' - ), - ] - authorized_for: Annotated[ - str, - Field( - description='Human-readable description of what this agent is authorized to sell', - max_length=500, - min_length=1, - ), - ] - publisher_properties: Annotated[ - list[PublisherProperties | PublisherProperties1], - Field( - description='Properties from other publisher domains this agent is authorized for. Each entry specifies a publisher domain and which of their properties this agent can sell', - min_length=1, - ), - ] - url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")] - - class Contact(AdCPBaseModel): model_config = ConfigDict( extra='forbid', @@ -226,6 +151,38 @@ class AuthorizedAgents2(AdCPBaseModel): url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")] +class AuthorizedAgents3(AdCPBaseModel): + model_config = ConfigDict( + extra='forbid', + ) + authorization_type: Annotated[ + Literal['publisher_properties'], + Field( + description='Discriminator indicating authorization for properties from other publisher domains' + ), + ] + authorized_for: Annotated[ + str, + Field( + description='Human-readable description of what this agent is authorized to sell', + max_length=500, + min_length=1, + ), + ] + publisher_properties: Annotated[ + list[ + publisher_property_selector.PublisherPropertySelector1 + | publisher_property_selector.PublisherPropertySelector2 + | publisher_property_selector.PublisherPropertySelector3 + ], + Field( + description='Properties from other publisher domains this agent is authorized for. Each entry specifies a publisher domain and which of their properties this agent can sell', + min_length=1, + ), + ] + url: Annotated[AnyUrl, Field(description="The authorized agent's API endpoint URL")] + + class AuthorizedSalesAgents(AdCPBaseModel): model_config = ConfigDict( extra='forbid', diff --git a/src/adcp/types/generated_poc/product.py b/src/adcp/types/generated_poc/product.py index 474e6b03..35145efc 100644 --- a/src/adcp/types/generated_poc/product.py +++ b/src/adcp/types/generated_poc/product.py @@ -1,13 +1,13 @@ # generated by datamodel-codegen: # filename: product.json -# timestamp: 2025-11-18T05:05:53+00:00 +# timestamp: 2025-11-19T02:02:39+00:00 from __future__ import annotations -from typing import Annotated, Any, Literal +from typing import Annotated, Any from adcp.types.base import AdCPBaseModel -from pydantic import AwareDatetime, ConfigDict, Field, RootModel +from pydantic import AwareDatetime, ConfigDict, Field from . import cpc_option, cpcv_option, cpm_auction_option, cpm_fixed_option, cpp_option, cpv_option from . import creative_policy as creative_policy_1 @@ -15,7 +15,7 @@ from . import flat_rate_option from . import format_id as format_id_1 from . import measurement as measurement_1 -from . import placement +from . import placement, publisher_property_selector from . import reporting_capabilities as reporting_capabilities_1 from . import vcpm_auction_option, vcpm_fixed_option @@ -69,77 +69,6 @@ class ProductCardDetailed(AdCPBaseModel): ] -class PublisherProperties(AdCPBaseModel): - model_config = ConfigDict( - extra='forbid', - ) - publisher_domain: Annotated[ - str, - Field( - description="Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", - pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', - ), - ] - selection_type: Annotated[ - Literal['all'], - Field( - description='Discriminator indicating all properties from this publisher are included' - ), - ] - - -class PropertyId(RootModel[str]): - root: Annotated[str, Field(pattern='^[a-z0-9_]+$')] - - -class PublisherProperties4(AdCPBaseModel): - model_config = ConfigDict( - extra='forbid', - ) - property_ids: Annotated[ - list[PropertyId], - Field(description="Specific property IDs from the publisher's adagents.json", min_length=1), - ] - publisher_domain: Annotated[ - str, - Field( - description="Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", - pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', - ), - ] - selection_type: Annotated[ - Literal['by_id'], - Field(description='Discriminator indicating selection by specific property IDs'), - ] - - -class PropertyTag(PropertyId): - pass - - -class PublisherProperties5(AdCPBaseModel): - model_config = ConfigDict( - extra='forbid', - ) - property_tags: Annotated[ - list[PropertyTag], - Field( - description="Property tags from the publisher's adagents.json. Product covers all properties with these tags", - min_length=1, - ), - ] - publisher_domain: Annotated[ - str, - Field( - description="Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", - pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', - ), - ] - selection_type: Annotated[ - Literal['by_tag'], Field(description='Discriminator indicating selection by property tags') - ] - - class Product(AdCPBaseModel): model_config = ConfigDict( extra='forbid', @@ -212,7 +141,11 @@ class Product(AdCPBaseModel): ] = None product_id: Annotated[str, Field(description='Unique identifier for the product')] publisher_properties: Annotated[ - list[PublisherProperties | PublisherProperties4 | PublisherProperties5], + list[ + publisher_property_selector.PublisherPropertySelector1 + | publisher_property_selector.PublisherPropertySelector2 + | publisher_property_selector.PublisherPropertySelector3 + ], Field( description="Publisher properties covered by this product. Buyers fetch actual property definitions from each publisher's adagents.json and validate agent authorization. Selection patterns mirror the authorization patterns in adagents.json for consistency.", min_length=1, diff --git a/src/adcp/types/generated_poc/publisher_property_selector.py b/src/adcp/types/generated_poc/publisher_property_selector.py new file mode 100644 index 00000000..798d964f --- /dev/null +++ b/src/adcp/types/generated_poc/publisher_property_selector.py @@ -0,0 +1,81 @@ +# generated by datamodel-codegen: +# filename: publisher-property-selector.json +# timestamp: 2025-11-19T02:02:39+00:00 + +from __future__ import annotations + +from typing import Annotated, Literal + +from adcp.types.base import AdCPBaseModel +from pydantic import ConfigDict, Field, RootModel + + +class PublisherPropertySelector1(AdCPBaseModel): + model_config = ConfigDict( + extra='forbid', + ) + publisher_domain: Annotated[ + str, + Field( + description="Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", + pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', + ), + ] + selection_type: Annotated[ + Literal['all'], + Field( + description='Discriminator indicating all properties from this publisher are included' + ), + ] + + +class PropertyId(RootModel[str]): + root: Annotated[str, Field(pattern='^[a-z0-9_]+$')] + + +class PublisherPropertySelector2(AdCPBaseModel): + model_config = ConfigDict( + extra='forbid', + ) + property_ids: Annotated[ + list[PropertyId], + Field(description="Specific property IDs from the publisher's adagents.json", min_length=1), + ] + publisher_domain: Annotated[ + str, + Field( + description="Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", + pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', + ), + ] + selection_type: Annotated[ + Literal['by_id'], + Field(description='Discriminator indicating selection by specific property IDs'), + ] + + +class PropertyTag(PropertyId): + pass + + +class PublisherPropertySelector3(AdCPBaseModel): + model_config = ConfigDict( + extra='forbid', + ) + property_tags: Annotated[ + list[PropertyTag], + Field( + description="Property tags from the publisher's adagents.json. Selector covers all properties with these tags", + min_length=1, + ), + ] + publisher_domain: Annotated[ + str, + Field( + description="Domain where publisher's adagents.json is hosted (e.g., 'cnn.com')", + pattern='^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$', + ), + ] + selection_type: Annotated[ + Literal['by_tag'], Field(description='Discriminator indicating selection by property tags') + ] diff --git a/src/adcp/types/stable.py b/src/adcp/types/stable.py index 879e80d9..600e7591 100644 --- a/src/adcp/types/stable.py +++ b/src/adcp/types/stable.py @@ -90,11 +90,12 @@ VcpmFixedRatePricingOption, VideoAsset, WebhookAsset, + WebhookPayload, ) # Import all generated types from internal consolidated module -# Import Package directly from its module to avoid collision with Response Package -from adcp.types.generated_poc.package import Package +# Import Package from _generated (uses qualified name to avoid collision) +from adcp.types._generated import _PackageFromPackage as Package # Note: BrandManifest is currently split into BrandManifest1/2 due to upstream schema # using anyOf incorrectly. This will be fixed upstream to create a single BrandManifest type. @@ -174,4 +175,5 @@ "UrlAsset", "VideoAsset", "WebhookAsset", + "WebhookPayload", ] diff --git a/src/adcp/utils/preview_cache.py b/src/adcp/utils/preview_cache.py index ec1ffd78..401381f6 100644 --- a/src/adcp/utils/preview_cache.py +++ b/src/adcp/utils/preview_cache.py @@ -10,7 +10,7 @@ if TYPE_CHECKING: from adcp.client import ADCPClient - from adcp.types._generated import CreativeManifest, Format, FormatId, Product + from adcp.types.stable import CreativeManifest, Format, FormatId, Product logger = logging.getLogger(__name__) @@ -67,7 +67,7 @@ async def get_preview_data_for_manifest( Returns: Preview data with preview_url and metadata, or None if generation fails """ - from adcp.types._generated import PreviewCreativeRequest1 + from adcp.types.aliases import PreviewCreativeFormatRequest cache_key = _make_manifest_cache_key(format_id, manifest.model_dump(exclude_none=True)) @@ -75,7 +75,7 @@ async def get_preview_data_for_manifest( return self._preview_cache[cache_key] try: - request = PreviewCreativeRequest1( + request = PreviewCreativeFormatRequest( request_type="single", format_id=format_id, creative_manifest=manifest, @@ -123,7 +123,7 @@ async def get_preview_data_batch( Returns: List of preview data dicts (or None for failures), in same order as requests """ - from adcp.types._generated import PreviewCreativeRequest + from adcp.types.stable import PreviewCreativeRequest if not requests: return [] @@ -396,7 +396,7 @@ def _create_sample_manifest_for_format(fmt: Format) -> CreativeManifest | None: Returns: Sample CreativeManifest, or None if unable to create one """ - from adcp.types._generated import CreativeManifest + from adcp.types.stable import CreativeManifest if not fmt.assets_required: return None @@ -436,7 +436,7 @@ def _create_sample_manifest_for_format_id( Returns: Sample CreativeManifest with placeholder assets """ - from adcp.types._generated import CreativeManifest, ImageAsset, UrlAsset + from adcp.types.stable import CreativeManifest, ImageAsset, UrlAsset assets = { "primary_asset": ImageAsset(url="https://example.com/sample-image.jpg"), @@ -456,7 +456,7 @@ def _create_sample_asset(asset_type: str | None) -> Any: Returns: Sample asset object (Pydantic model) """ - from adcp.types._generated import ( + from adcp.types.stable import ( HtmlAsset, ImageAsset, TextAsset, diff --git a/tests/test_discriminated_unions.py b/tests/test_discriminated_unions.py index 3e05dc20..834cc6fd 100644 --- a/tests/test_discriminated_unions.py +++ b/tests/test_discriminated_unions.py @@ -22,8 +22,8 @@ UrlVastAsset, ) -# Keep using generated names for authorization/deployment/destination variants -# since these don't have semantic aliases yet +# Keep using generated names for authorization variants +# Deployment and Destination now have semantic aliases from adcp.types._generated import ( AuthorizedAgents, # property_ids variant AuthorizedAgents1, # property_tags variant @@ -33,10 +33,14 @@ Deployment2, # Agent Destination1, # Platform Destination2, # Agent - PublisherProperties4, # selection_type='by_id' - PublisherProperties5, # selection_type='by_tag' + PublisherPropertySelector2, # selection_type='by_id' (shared schema) + PublisherPropertySelector3, # selection_type='by_tag' (shared schema) ) +# Use shorter names for local aliases in this test +PublisherProperties4 = PublisherPropertySelector2 +PublisherProperties5 = PublisherPropertySelector3 + class TestAuthorizationDiscriminatedUnions: """Test authorization_type discriminated unions in adagents.json. diff --git a/tests/test_type_aliases.py b/tests/test_type_aliases.py index a449a840..044244c1 100644 --- a/tests/test_type_aliases.py +++ b/tests/test_type_aliases.py @@ -302,16 +302,16 @@ def test_package_type_aliases_imports(): def test_package_type_aliases_point_to_correct_modules(): """Test that Package aliases point to the correct generated types.""" from adcp import CreatedPackageReference, Package - from adcp.types.generated_poc.create_media_buy_response import ( - Package as ResponsePackage, + from adcp.types._generated import ( + _PackageFromCreateMediaBuyResponse, + _PackageFromPackage, ) - from adcp.types.generated_poc.package import Package as DomainPackage # Package should point to the full domain package - assert Package is DomainPackage + assert Package is _PackageFromPackage # CreatedPackageReference should point to the response package - assert CreatedPackageReference is ResponsePackage + assert CreatedPackageReference is _PackageFromCreateMediaBuyResponse # Verify they're different types assert Package is not CreatedPackageReference @@ -434,16 +434,16 @@ def test_publisher_properties_aliases_imports(): def test_publisher_properties_aliases_point_to_correct_types(): """Test that PublisherProperties aliases point to the correct generated types.""" from adcp import PublisherPropertiesAll, PublisherPropertiesById, PublisherPropertiesByTag - from adcp.types.generated_poc.product import ( - PublisherProperties, - PublisherProperties4, - PublisherProperties5, + from adcp.types._generated import ( + PublisherPropertySelector1, + PublisherPropertySelector2, + PublisherPropertySelector3, ) - # Verify aliases point to correct types - assert PublisherPropertiesAll is PublisherProperties - assert PublisherPropertiesById is PublisherProperties4 - assert PublisherPropertiesByTag is PublisherProperties5 + # Verify aliases point to correct types (from shared publisher_property_selector module) + assert PublisherPropertiesAll is PublisherPropertySelector1 + assert PublisherPropertiesById is PublisherPropertySelector2 + assert PublisherPropertiesByTag is PublisherPropertySelector3 # Verify they're different types assert PublisherPropertiesAll is not PublisherPropertiesById @@ -455,12 +455,7 @@ def test_publisher_properties_aliases_have_correct_discriminators(): """Test that PublisherProperties aliases have the correct discriminator values.""" from adcp import PublisherPropertiesAll, PublisherPropertiesById, PublisherPropertiesByTag - # Check that discriminator field has correct literal type - all_selection_type = PublisherPropertiesAll.__annotations__["selection_type"] - by_id_selection_type = PublisherPropertiesById.__annotations__["selection_type"] - by_tag_selection_type = PublisherPropertiesByTag.__annotations__["selection_type"] - - # Verify the annotations contain Literal types + # Verify the annotations contain selection_type discriminator field assert "selection_type" in PublisherPropertiesAll.__annotations__ assert "selection_type" in PublisherPropertiesById.__annotations__ assert "selection_type" in PublisherPropertiesByTag.__annotations__ @@ -469,8 +464,6 @@ def test_publisher_properties_aliases_have_correct_discriminators(): def test_publisher_properties_aliases_can_instantiate(): """Test that PublisherProperties aliases can be used to create instances.""" from adcp import ( - PropertyId, - PropertyTag, PublisherPropertiesAll, PublisherPropertiesById, PublisherPropertiesByTag, @@ -484,20 +477,22 @@ def test_publisher_properties_aliases_can_instantiate(): assert props_all.selection_type == "all" # Create PublisherPropertiesById + # Note: property_ids should be plain strings (PropertyId is a constrained string type) props_by_id = PublisherPropertiesById( publisher_domain="example.com", selection_type="by_id", - property_ids=[PropertyId("homepage"), PropertyId("sports")], + property_ids=["homepage", "sports"], ) assert props_by_id.publisher_domain == "example.com" assert props_by_id.selection_type == "by_id" assert len(props_by_id.property_ids) == 2 # Create PublisherPropertiesByTag + # Note: property_tags should be plain strings (PropertyTag is a constrained string type) props_by_tag = PublisherPropertiesByTag( publisher_domain="example.com", selection_type="by_tag", - property_tags=[PropertyTag("premium"), PropertyTag("video")], + property_tags=["premium", "video"], ) assert props_by_tag.publisher_domain == "example.com" assert props_by_tag.selection_type == "by_tag" @@ -578,8 +573,8 @@ def test_deployment_aliases_point_to_correct_types(): def test_deployment_aliases_can_instantiate(): """Test that Deployment aliases can be used to create instances.""" + from adcp import AgentDeployment, PlatformDeployment - from datetime import datetime, timezone # Create PlatformDeployment platform_deployment = PlatformDeployment(