Module adcp.decisioning.resolve

Async framework-mediated resource resolver for :class:RequestContext.

Defines:

  • :class:ResourceResolver — Protocol for async fetches of framework-validated resources (property lists, collection lists, creative formats). The framework owns the cache + validation; platform methods get pre-validated typed results.
  • :class:_NotYetWiredResolver — v6.0 stub. Raises :class:NotImplementedError on every call with a pointer to the v6.1 follow-up. Asymmetry vs. the state stub (which returns empty + warns) is deliberate: an empty :class:PropertyListReference in v6.0 vs. a real one in v6.1 is divergence the framework cannot silently paper over. See docs/proposals/decisioning-platform-dispatch-design.md#d15.

The :class:Format and :class:PropertyListReference types are re-exported from :mod:adcp.types.generated_poc so adopters import once from :mod:adcp.decisioning. :class:PropertyListReference and :class:CollectionList use the spec-defined wire shapes; the resolver returns the same Pydantic models adopters would construct themselves.

Classes

class CollectionList (**data: Any)
Expand source code
class CollectionList(AdCPBaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    list_id: Annotated[str, Field(description='Unique identifier for this collection list')]
    name: Annotated[str, Field(description='Human-readable name for the list')]
    description: Annotated[str | None, Field(description="Description of the list's purpose")] = (
        None
    )
    account: Annotated[
        account_ref.AccountReference | None,
        Field(
            description='Account that owns this list. Returned as account_id form (seller-assigned identifier).'
        ),
    ] = None
    base_collections: Annotated[
        list[base_collection_source.BaseCollectionSource] | None,
        Field(
            description="Array of collection sources to evaluate. Each entry is a discriminated union: distribution_ids (platform-independent identifiers), publisher_collections (publisher_domain + collection_ids), or publisher_genres (publisher_domain + genres). If omitted, queries the agent's entire collection database."
        ),
    ] = None
    filters: Annotated[
        collection_list_filters.CollectionListFilters | None,
        Field(description='Dynamic filters applied when resolving the list'),
    ] = None
    brand: Annotated[
        brand_ref.BrandReference | None,
        Field(
            description='Brand reference used to automatically apply appropriate rules. Resolved to full brand identity at execution time.'
        ),
    ] = None
    webhook_url: Annotated[
        AnyUrl | None,
        Field(description='URL to receive notifications when the resolved list changes'),
    ] = None
    cache_duration_hours: Annotated[
        int | None,
        Field(
            description='Recommended cache duration for resolved list. Consumers should re-fetch after this period. Defaults to 168 (one week) because collection metadata changes less frequently than property metadata.',
            ge=1,
        ),
    ] = 168
    created_at: Annotated[AwareDatetime | None, Field(description='When the list was created')] = (
        None
    )
    updated_at: Annotated[
        AwareDatetime | None, Field(description='When the list was last modified')
    ] = None
    collection_count: Annotated[
        int | None,
        Field(
            description='Number of collections in the resolved list (at time of last resolution)'
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var account : adcp.types.generated_poc.core.account_ref.AccountReference | None
var base_collections : list[adcp.types.generated_poc.collection.base_collection_source.BaseCollectionSource] | None
var brand : adcp.types.generated_poc.core.brand_ref.BrandReference | None
var cache_duration_hours : int | None
var collection_count : int | None
var created_at : pydantic.types.AwareDatetime | None
var description : str | None
var filters : adcp.types.generated_poc.collection.collection_list_filters.CollectionListFilters | None
var list_id : str
var model_config
var name : str
var updated_at : pydantic.types.AwareDatetime | None
var webhook_url : pydantic.networks.AnyUrl | None

Inherited members

class Format (**data: Any)
Expand source code
class Format(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    format_id: Annotated[
        format_id_1.FormatReferenceStructuredObject,
        Field(
            description="This format's own identifier — a structured object {agent_url, id}, not a string. See /schemas/core/format-id.json for the full shape."
        ),
    ]
    name: Annotated[str, Field(description='Human-readable format name')]
    description: Annotated[
        str | None,
        Field(
            description='Plain text explanation of what this format does and what assets it requires'
        ),
    ] = None
    example_url: Annotated[
        AnyUrl | None,
        Field(
            description='Optional URL to showcase page with examples and interactive demos of this format'
        ),
    ] = None
    accepts_parameters: Annotated[
        list[format_id_parameter.FormatIdParameter] | None,
        Field(
            description='List of parameters this format accepts in format_id. Template formats define which parameters (dimensions, duration, etc.) can be specified when instantiating the format. Empty or omitted means this is a concrete format with fixed parameters.'
        ),
    ] = None
    renders: Annotated[
        list[Renders | Renders1] | None,
        Field(
            description='Specification of rendered pieces for this format. Most formats produce a single render. Companion ad formats (video + banner), adaptive formats, and multi-placement formats produce multiple renders. Each render specifies its role and dimensions.',
            min_length=1,
        ),
    ] = None
    assets: Annotated[
        list[
            Assets
            | Assets10
            | Assets11
            | Assets12
            | Assets13
            | Assets14
            | Assets15
            | Assets16
            | Assets17
            | Assets18
            | Assets19
            | Assets20
            | Assets21
            | Assets22
            | Assets23
            | Assets24
        ]
        | None,
        Field(
            description="Array of all assets supported for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Use the 'required' boolean on each asset to indicate whether it's mandatory."
        ),
    ] = None
    delivery: Annotated[
        dict[str, Any] | None,
        Field(description='Delivery method specifications (e.g., hosted, VAST, third-party tags)'),
    ] = None
    supported_macros: Annotated[
        list[universal_macro.UniversalMacro | str] | None,
        Field(
            description='List of universal macros supported by this format (e.g., MEDIA_BUY_ID, CACHEBUSTER, DEVICE_ID). Used for validation and developer tooling. See docs/creative/universal-macros.mdx for full documentation.'
        ),
    ] = None
    input_format_ids: Annotated[
        list[format_id_1.FormatReferenceStructuredObject] | None,
        Field(
            deprecated=True,
            description='**DEPRECATED in 3.1. Removed at 4.0.** Use `list_transformers` instead — a transformer declares its own `input_format_ids`/`output_format_ids`, so build capability is a property of the transformer (the unit you select and that carries pricing), not a relationship hung on a format. Discover build capability via `list_transformers` (optionally filtered by `input_format_ids`/`output_format_ids`).\n\nMigration: sellers that expressed transform capability by hanging `input_format_ids` on a format SHOULD declare a transformer via `list_transformers` instead. Buyers SHOULD discover build capability via `list_transformers` rather than filtering formats.\n\n*Legacy behavior, retained for 3.1–3.x backward compatibility:* array of format IDs this format accepts as input creative manifests; when present, indicates this format can take existing creatives in these formats as input. SDKs reading 3.1 catalogs MUST continue to honor this field when present; 4.0+ SDKs MAY reject it. New code SHOULD NOT emit this field.',
        ),
    ] = None
    output_format_ids: Annotated[
        list[format_id_1.FormatReferenceStructuredObject] | None,
        Field(
            deprecated=True,
            description='**DEPRECATED in 3.1. Removed at 4.0.** Use `list_transformers` instead — a transformer declares its own `output_format_ids`, so what a builder can produce is a property of the transformer, not a relationship hung on a format. Discover via `list_transformers`.\n\nMigration: sellers that expressed multi-output build capability (e.g. a multi-publisher template) by hanging `output_format_ids` on a format SHOULD declare a transformer via `list_transformers` instead.\n\n*Legacy behavior, retained for 3.1–3.x backward compatibility:* array of format IDs this format can produce as output; when present, indicates this format can build creatives in these output formats. SDKs reading 3.1 catalogs MUST continue to honor this field when present; 4.0+ SDKs MAY reject it. New code SHOULD NOT emit this field.',
        ),
    ] = None
    format_card: Annotated[
        FormatCard | None,
        Field(
            description='Optional standard visual card (300x400px) for displaying this format in user interfaces. Can be rendered via preview_creative or pre-generated.'
        ),
    ] = None
    accessibility: Annotated[
        Accessibility | None,
        Field(
            description='Accessibility posture of this format. Declares the WCAG conformance level that creatives produced by this format will meet.'
        ),
    ] = None
    supported_disclosure_positions: Annotated[
        list[disclosure_position.DisclosurePosition] | None,
        Field(
            description='Disclosure positions this format can render. Buyers use this to determine whether a format can satisfy their compliance requirements before submitting a creative. When omitted, the format makes no disclosure rendering guarantees — creative agents SHOULD treat this as incompatible with briefs that require specific disclosure positions. Values correspond to positions on creative-brief.json required_disclosures.',
            min_length=1,
        ),
    ] = None
    disclosure_capabilities: Annotated[
        list[DisclosureCapability] | None,
        Field(
            description='Structured disclosure capabilities per position with persistence modes. Declares which persistence behaviors each disclosure position supports, enabling persistence-aware matching against provenance render guidance and brief requirements. When present, supersedes supported_disclosure_positions for persistence-aware queries. The flat supported_disclosure_positions field is retained for backward compatibility. Each position MUST appear at most once; validators and agents SHOULD reject duplicates.',
            min_length=1,
        ),
    ] = None
    format_card_detailed: Annotated[
        FormatCardDetailed | None,
        Field(
            description='Optional detailed card with carousel and full specifications. Provides rich format documentation similar to ad spec pages.'
        ),
    ] = None
    reported_metrics: Annotated[
        list[available_metric.AvailableMetric] | None,
        Field(
            description='Metrics this format can produce in delivery reporting. Buyers receive the intersection of format reported_metrics and product available_metrics. If omitted, the format defers entirely to product-level metric declarations.',
            min_length=1,
        ),
    ] = None
    pricing_options: Annotated[
        list[vendor_pricing_option.VendorPricingOption] | None,
        Field(
            deprecated=True,
            description='**DEPRECATED in 3.1. Removed at 4.0.** Use `transformer.pricing_options` (via `list_transformers`) instead — pricing belongs on the transformer (the unit selected and billed), exactly as it belongs on a media-buy product. Once formats only describe output shape, format-level pricing is vestigial.\n\nMigration: transformation/generation agents that charged via `format.pricing_options` SHOULD move the same `vendor-pricing-option` entries onto the corresponding transformer. The applied option is echoed per-leaf on the build_creative response and reconciled via report_usage, unchanged.\n\n*Legacy behavior, retained for 3.1–3.x backward compatibility:* pricing options for this format, used by transformation/generation agents that charge per format adapted, per image generated, or per unit of work; present when the request included include_pricing=true and account. SDKs reading 3.1 catalogs MUST continue to honor this field when present; 4.0+ SDKs MAY reject it. New code SHOULD NOT emit this field.',
            min_length=1,
        ),
    ] = None
    canonical: Annotated[
        canonical_projection_ref.CanonicalProjectionReference | None,
        Field(
            description='Optional v2 canonical-projection annotation. Always an object — bare-string shorthand (`canonical: "image"`) is not supported; the minimal form is `canonical: { "kind": "image" }`. Carries `kind` (which canonical the v1 format projects to) plus optional `asset_source` and `slots_override` for cases where the v1 format\'s shape doesn\'t follow the canonical\'s defaults (e.g., generative entries whose input is `generation_prompt: text` instead of `image_main: image`).\n\nWhen set, SDKs use this annotation as the authoritative v1 → v2 mapping for this format, bypassing the [v1 canonical mapping registry](/schemas/registries/v1-canonical-mapping.json) lookup. Combined with the slot-level `asset_group_id` declarations on each `assets[i]` entry, a v1 format declaration with `canonical` set is fully self-describing for v1↔v2 translation.\n\nResolution order for SDK projection from v1 wire shape to v2 (per RFC #3305 amendment #3767):\n1. If this `canonical` field is set, use it (seller-declared, highest priority). Apply `asset_source` and `slots_override` from the projection ref when present; otherwise inherit the canonical\'s defaults.\n2. Else, look up `format_id` in the canonical mapping registry\'s `format_id_glob` entries.\n3. Else, attempt structural match against the registry\'s `structural` entries (asset types, slot shape, vast_versions, etc.).\n4. Else, fail closed: SDK MUST NOT emit `format_options` for products carrying this format. Surface `FORMAT_PROJECTION_FAILED` on the response `errors[]` suggesting the seller add an explicit `canonical` annotation or file a registry entry.\n\nWhen `canonical.kind` is `custom`, the seller MUST also declare `canonical_format_shape` and `canonical_format_schema` (parallel to ProductFormatDeclaration\'s `format_shape` and `format_schema`) so buyer SDKs can fetch the seller\'s custom format schema.\n\nSee `canonical-projection-ref.json` for full projection semantics and examples (default-slot case, generative case, brief-driven case).'
        ),
    ] = None
    canonical_parameters: Annotated[
        product_format_declaration.ProductFormatDeclaration | None,
        Field(
            deprecated=True,
            description="**DEPRECATED in 3.1. Removed at 4.0.** Use `v1_format_ref` on the v2 `ProductFormatDeclaration` instead — the seller authors a v2 declaration (in `Product.format_options` or `creative.supported_formats`) and links it back to this v1 format via `v1_format_ref: { agent_url, id }`. The directional link from v2 → v1 is the same fact as `canonical_parameters` without the parallel-shape drift surface (v1 file and `canonical_parameters` were two declarations of the same thing; hand-authored, drifting silently).\n\nMigration: every seller currently authoring `canonical_parameters` SHOULD migrate to authoring a v2 declaration on the corresponding product (or capability) with `v1_format_ref` pointing back at this v1 format. v1 files become pure v1 again — no v2-shape mirroring.\n\n*Legacy behavior, retained for 3.1–3.x backward compatibility:* When `canonical` is set, this field carries the full ProductFormatDeclaration that the SDK projects this v1 format into. The `format_kind` MUST equal the `canonical` field value (validators enforce). When set, this is the authoritative source for SDK v1→v2 projection — the registry's structural-match parameter inference is bypassed. SDKs reading 3.1 catalogs MUST continue to honor `canonical_parameters` when present; 4.0+ SDKs MAY reject the field. New code SHOULD NOT emit this field.\n\n**Drift contract (still normative while supported).** Hand-authored `canonical_parameters` MUST satisfy the *narrows* relation against this v1 format's `requirements` and `assets[*]` shape (see canonical-formats.mdx 'Narrows — formal definition'). SDKs that read this v1 file SHOULD lint-time check the equivalence at build/load and emit `FORMAT_PROJECTION_FAILED` if the two disagree.",
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var accepts_parameters : list[adcp.types.generated_poc.enums.format_id_parameter.FormatIdParameter] | None
var accessibility : adcp.types.generated_poc.core.format.Accessibility | None
var assets : list[typing.Union[adcp.types.generated_poc.core.format.Assets, adcp.types.generated_poc.core.format.Assets10, adcp.types.generated_poc.core.format.Assets11, adcp.types.generated_poc.core.format.Assets12, adcp.types.generated_poc.core.format.Assets13, adcp.types.generated_poc.core.format.Assets14, adcp.types.generated_poc.core.format.Assets15, adcp.types.generated_poc.core.format.Assets16, adcp.types.generated_poc.core.format.Assets18, adcp.types.generated_poc.core.format.Assets19, adcp.types.generated_poc.core.format.Assets20, adcp.types.generated_poc.core.format.Assets21, adcp.types.generated_poc.core.format.Assets22, adcp.types.generated_poc.core.format.Assets23, adcp.types.generated_poc.core.format.Assets24, UnknownFormatAsset]] | None
var canonical : adcp.types.generated_poc.core.canonical_projection_ref.CanonicalProjectionReference | None
var delivery : dict[str, typing.Any] | None
var description : str | None
var disclosure_capabilities : list[adcp.types.generated_poc.core.format.DisclosureCapability] | None
var example_url : pydantic.networks.AnyUrl | None
var format_card : adcp.types.generated_poc.core.format.FormatCard | None
var format_card_detailed : adcp.types.generated_poc.core.format.FormatCardDetailed | None
var format_id : adcp.types.generated_poc.core.format_id.FormatReferenceStructuredObject
var model_config
var name : str
var renders : list[adcp.types.generated_poc.core.format.Renders | adcp.types.generated_poc.core.format.Renders1] | None
var reported_metrics : list[adcp.types.generated_poc.enums.available_metric.AvailableMetric] | None
var supported_disclosure_positions : list[adcp.types.generated_poc.enums.disclosure_position.DisclosurePosition] | None
var supported_macros : list[adcp.types.generated_poc.enums.universal_macro.UniversalMacro | str] | None

Instance variables

var canonical_parameters : adcp.types.generated_poc.core.product_format_declaration.ProductFormatDeclaration | None
Expand source code
def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any:
    if obj is None:
        if self.wrapped_property is not None:
            return self.wrapped_property.__get__(None, obj_type)
        raise AttributeError(self.field_name)

    warnings.warn(self.msg, DeprecationWarning, stacklevel=2)

    if self.wrapped_property is not None:
        return self.wrapped_property.__get__(obj, obj_type)
    return obj.__dict__[self.field_name]

Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.

Attributes

msg
The deprecation message to be emitted.
wrapped_property
The property instance if the deprecated field is a computed field, or None.
field_name
The name of the field being deprecated.
var input_format_ids : list[adcp.types.generated_poc.core.format_id.FormatReferenceStructuredObject] | None
Expand source code
def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any:
    if obj is None:
        if self.wrapped_property is not None:
            return self.wrapped_property.__get__(None, obj_type)
        raise AttributeError(self.field_name)

    warnings.warn(self.msg, DeprecationWarning, stacklevel=2)

    if self.wrapped_property is not None:
        return self.wrapped_property.__get__(obj, obj_type)
    return obj.__dict__[self.field_name]

Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.

Attributes

msg
The deprecation message to be emitted.
wrapped_property
The property instance if the deprecated field is a computed field, or None.
field_name
The name of the field being deprecated.
var output_format_ids : list[adcp.types.generated_poc.core.format_id.FormatReferenceStructuredObject] | None
Expand source code
def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any:
    if obj is None:
        if self.wrapped_property is not None:
            return self.wrapped_property.__get__(None, obj_type)
        raise AttributeError(self.field_name)

    warnings.warn(self.msg, DeprecationWarning, stacklevel=2)

    if self.wrapped_property is not None:
        return self.wrapped_property.__get__(obj, obj_type)
    return obj.__dict__[self.field_name]

Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.

Attributes

msg
The deprecation message to be emitted.
wrapped_property
The property instance if the deprecated field is a computed field, or None.
field_name
The name of the field being deprecated.
var pricing_options : list[adcp.types.generated_poc.core.vendor_pricing_option.VendorPricingOption] | None
Expand source code
def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any:
    if obj is None:
        if self.wrapped_property is not None:
            return self.wrapped_property.__get__(None, obj_type)
        raise AttributeError(self.field_name)

    warnings.warn(self.msg, DeprecationWarning, stacklevel=2)

    if self.wrapped_property is not None:
        return self.wrapped_property.__get__(obj, obj_type)
    return obj.__dict__[self.field_name]

Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.

Attributes

msg
The deprecation message to be emitted.
wrapped_property
The property instance if the deprecated field is a computed field, or None.
field_name
The name of the field being deprecated.

Inherited members

class FormatReferenceStructuredObject (**data: Any)
Expand source code
class FormatReferenceStructuredObject(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    agent_url: Annotated[
        AnyUrl,
        Field(
            description="URL of the agent that defines this format (e.g., 'https://creative.adcontextprotocol.org' for standard formats, or 'https://publisher.com/.well-known/adcp/sales' for custom formats). Callers comparing two `format-id` values MUST canonicalize `agent_url` per the AdCP URL canonicalization rules before treating two formats as the same. See docs/reference/url-canonicalization."
        ),
    ]
    id: Annotated[
        str,
        Field(
            description="Format identifier within the agent's namespace (e.g., 'display_static', 'video_hosted', 'audio_standard'). When used alone, references a template format. When combined with dimension/duration fields, creates a parameterized format ID for a specific variant.",
            pattern='^[a-zA-Z0-9_-]+$',
        ),
    ]
    width: Annotated[
        int | None,
        Field(
            description='Width in pixels for visual formats. When specified, height must also be specified. Both fields together create a parameterized format ID for dimension-specific variants.',
            ge=1,
        ),
    ] = None
    height: Annotated[
        int | None,
        Field(
            description='Height in pixels for visual formats. When specified, width must also be specified. Both fields together create a parameterized format ID for dimension-specific variants.',
            ge=1,
        ),
    ] = None
    duration_ms: Annotated[
        float | None,
        Field(
            description='Duration in milliseconds for time-based formats (video, audio). When specified, creates a parameterized format ID. Omit to reference a template format without parameters.',
            ge=1.0,
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var agent_url : pydantic.networks.AnyUrl
var duration_ms : float | None
var height : int | None
var id : str
var model_config
var width : int | None

Inherited members

class PropertyList (**data: Any)
Expand source code
class PropertyListReference(AdCPBaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    agent_url: Annotated[AnyUrl, Field(description='URL of the agent managing the property list')]
    list_id: Annotated[
        str, Field(description='Identifier for the property list within the agent', min_length=1)
    ]
    auth_token: Annotated[
        str | None,
        Field(
            description='JWT or other authorization token for accessing the list. Optional if the list is public or caller has implicit access.'
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var agent_url : pydantic.networks.AnyUrl
var auth_token : str | None
var list_id : str
var model_config
class PropertyListReference (**data: Any)
Expand source code
class PropertyListReference(AdCPBaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    agent_url: Annotated[AnyUrl, Field(description='URL of the agent managing the property list')]
    list_id: Annotated[
        str, Field(description='Identifier for the property list within the agent', min_length=1)
    ]
    auth_token: Annotated[
        str | None,
        Field(
            description='JWT or other authorization token for accessing the list. Optional if the list is public or caller has implicit access.'
        ),
    ] = None

Base model for AdCP types with spec-compliant serialization.

Defaults to extra='ignore' so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas set additionalProperties: true override this with extra='allow' in their own model_config.

Set ADCP_STRICT_VALIDATION=1 in the environment ("1", "true", "yes", "on" are accepted) to flip the default to extra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.

Important

The env var is resolved once at module import time. Set it in your shell or CI environment before import adcp runs — mutating os.environ["ADCP_STRICT_VALIDATION"] after the first adcp import has no effect on already-imported model classes (they captured the policy at class-body evaluation).

Consumers who want per-model strict validation can override model_config on their subclass.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Ancestors

Class variables

var agent_url : pydantic.networks.AnyUrl
var auth_token : str | None
var list_id : str
var model_config

Inherited members

class ResourceResolver (*args, **kwargs)
Expand source code
@runtime_checkable
class ResourceResolver(Protocol):
    """Async fetches of framework-mediated resources.

    Platforms call ``ctx.resolve.property_list(list_id)`` instead of
    fetching from their own DB; the framework returns a validated
    typed result. The resolver routes through
    ``capabilities.creative_agents`` for creative-format reads, hits
    the framework's local ``CreativePlatform.list_formats`` for
    self-hosted formats, and reads the seller's declared property /
    collection lists with id-validation built in.

    Framework-supplied; never constructed by adopter code. The
    ``RequestContext.resolve`` field is populated by the dispatch
    hydration helper. Adopters substituting test doubles use
    :func:`dataclasses.replace` on the context, not direct
    construction.

    Mirrors the TS-side ``ResourceResolver`` interface in
    ``src/lib/server/decisioning/context.ts``. v6.0 ships the contract
    + the no-op stub (raises ``NotImplementedError`` on every call);
    v6.1 lands the backing fetchers.

    .. note::
       :class:`runtime_checkable` Protocols only check attribute
       *presence*. Whether a method is ``async def`` is irrelevant to
       the runtime ``isinstance`` check — a sync method named
       ``property_list`` would pass the structural check but fail at
       ``await`` time. Use mypy to enforce ``async def`` signatures
       across adopter impls.
    """

    async def property_list(self, list_id: str) -> PropertyList:
        """Fetch a property list by id. Framework validates the id
        exists in the seller's declared lists before returning;
        consumers can trust the result."""
        ...

    async def collection_list(self, list_id: str) -> CollectionList:
        """Fetch a collection list by id. Same id-validation
        guarantee as :meth:`property_list`."""
        ...

    async def creative_format(
        self,
        format_id: FormatReferenceStructuredObject,
        *,
        revalidate: bool = False,
    ) -> Format:
        """Fetch a creative format definition.

        Routes through ``capabilities.creative_agents`` declaration
        with a framework-managed cache; self-hosted formats hit the
        local ``CreativePlatform.list_formats``. Returns the resolved
        :class:`Format` with full asset slot definitions.

        :param revalidate: When ``True``, bypasses the framework cache
            and re-fetches from the upstream creative-agent. Adopters
            with freshness needs (e.g., creative submission validating
            against the latest format spec) pass ``revalidate=True``;
            most reads use the default (``False``) to amortize the
            agent round-trip.

        Cache TTL is implementation detail (defaults to 1h on the
        reference impl); adopters who need stricter freshness use
        ``revalidate=True`` rather than depending on the TTL value.
        """
        ...

Async fetches of framework-mediated resources.

Platforms call ctx.resolve.property_list(list_id) instead of fetching from their own DB; the framework returns a validated typed result. The resolver routes through capabilities.creative_agents for creative-format reads, hits the framework's local CreativePlatform.list_formats for self-hosted formats, and reads the seller's declared property / collection lists with id-validation built in.

Framework-supplied; never constructed by adopter code. The RequestContext.resolve field is populated by the dispatch hydration helper. Adopters substituting test doubles use :func:dataclasses.replace on the context, not direct construction.

Mirrors the TS-side ResourceResolver interface in src/lib/server/decisioning/context.ts. v6.0 ships the contract + the no-op stub (raises NotImplementedError on every call); v6.1 lands the backing fetchers.

Note

:class:runtime_checkable Protocols only check attribute presence. Whether a method is async def is irrelevant to the runtime isinstance check — a sync method named property_list would pass the structural check but fail at await time. Use mypy to enforce async def signatures across adopter impls.

Ancestors

  • typing.Protocol
  • typing.Generic

Methods

async def collection_list(self, list_id: str) ‑> adcp.types.generated_poc.collection.collection_list.CollectionList
Expand source code
async def collection_list(self, list_id: str) -> CollectionList:
    """Fetch a collection list by id. Same id-validation
    guarantee as :meth:`property_list`."""
    ...

Fetch a collection list by id. Same id-validation guarantee as :meth:property_list.

async def creative_format(self,
format_id: FormatReferenceStructuredObject,
*,
revalidate: bool = False) ‑> adcp.types.generated_poc.core.format.Format
Expand source code
async def creative_format(
    self,
    format_id: FormatReferenceStructuredObject,
    *,
    revalidate: bool = False,
) -> Format:
    """Fetch a creative format definition.

    Routes through ``capabilities.creative_agents`` declaration
    with a framework-managed cache; self-hosted formats hit the
    local ``CreativePlatform.list_formats``. Returns the resolved
    :class:`Format` with full asset slot definitions.

    :param revalidate: When ``True``, bypasses the framework cache
        and re-fetches from the upstream creative-agent. Adopters
        with freshness needs (e.g., creative submission validating
        against the latest format spec) pass ``revalidate=True``;
        most reads use the default (``False``) to amortize the
        agent round-trip.

    Cache TTL is implementation detail (defaults to 1h on the
    reference impl); adopters who need stricter freshness use
    ``revalidate=True`` rather than depending on the TTL value.
    """
    ...

Fetch a creative format definition.

Routes through capabilities.creative_agents declaration with a framework-managed cache; self-hosted formats hit the local CreativePlatform.list_formats. Returns the resolved :class:Format with full asset slot definitions.

:param revalidate: When True, bypasses the framework cache and re-fetches from the upstream creative-agent. Adopters with freshness needs (e.g., creative submission validating against the latest format spec) pass revalidate=True; most reads use the default (False) to amortize the agent round-trip.

Cache TTL is implementation detail (defaults to 1h on the reference impl); adopters who need stricter freshness use revalidate=True rather than depending on the TTL value.

async def property_list(self, list_id: str) ‑> adcp.types.generated_poc.core.property_list_ref.PropertyListReference
Expand source code
async def property_list(self, list_id: str) -> PropertyList:
    """Fetch a property list by id. Framework validates the id
    exists in the seller's declared lists before returning;
    consumers can trust the result."""
    ...

Fetch a property list by id. Framework validates the id exists in the seller's declared lists before returning; consumers can trust the result.