Skip to content

feat: add universal creative format (multi-channel asset pool)#48

Open
bokelley wants to merge 2 commits intomainfrom
bokelley/universal-ad-format
Open

feat: add universal creative format (multi-channel asset pool)#48
bokelley wants to merge 2 commits intomainfrom
bokelley/universal-ad-format

Conversation

@bokelley
Copy link
Contributor

Summary

  • Adds a universal format modeled on Google's Performance Max asset groups: a multi-channel asset pool where publishers assemble placements themselves
  • Uses repeatable_group assets from the adcp library for pooled assets (headlines 1-15, descriptions 1-5, images up to 20 each, videos up to 15 each, logos up to 5 each)
  • Not a generative format — no output_format_ids, no accepts_parameters; build_creative returns the manifest as-is

Asset structure

Required individual assets: brand_name, click_url

Required repeatable groups: headlines (1-15, 30 chars), descriptions (1-5, 90 chars), images_landscape (1-20, 1.91:1), images_square (1-20, 1:1)

Optional groups: long_headlines, images_portrait, logos_square, logos_landscape, videos_landscape, videos_portrait, videos_square

Optional individual: cta, promoted_offerings, impression_tracker

Fixes included

  • _format_to_human_readable now surfaces repeatable group IDs to the LLM (was silently dropping them)
  • assets_required backward-compat field excludes repeatable groups (old 2.5.x clients don't understand item_type=repeatable_group)
  • filter_formats has_asset_type() handles repeatable groups via getattr

Known limitation (deferred to follow-up PR)

validate_manifest_assets does not yet enforce required repeatable groups — it only validates individual assets. This means a creative manifest missing required groups like headlines will not be rejected at validation time.

Test plan

  • tests/integration/test_universal_format.py — 16 new tests covering discovery, schema compliance, asset structure, repeatable group counts, and build behavior
  • All 281 existing tests pass
  • Pre-commit hooks pass (ruff, mypy)

🤖 Generated with Claude Code

bokelley and others added 2 commits February 19, 2026 06:25
Adds a 'universal' format similar to Google's Performance Max asset
groups. Publishers receive a pool of assets and assemble placements
themselves -- this is a submission container, not a generative format.

Asset pools use repeatable_group from the adcp library, supporting:
- headlines (1-15, 30 chars), long_headlines (0-5, 90 chars)
- descriptions (1-5, 90 chars)
- images_landscape/square/portrait (1-20 each)
- logos_square/landscape (0-5 each)
- videos_landscape/portrait (0-15), videos_square (0-5)
- Individual: brand_name, cta, promoted_offerings, click_url,
  impression_tracker

Also fixes:
- _format_to_human_readable now includes repeatable group IDs for LLMs
- assets_required backward compat excludes repeatable groups (old
  clients don't understand item_type=repeatable_group)
- filter_formats has_asset_type handles repeatable groups via getattr

Known limitation (deferred): validate_manifest_assets does not yet
enforce required repeatable groups.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
validate_manifest_assets now handles Assets5 (repeatable_group) entries:
- Required groups (headlines, descriptions, images_landscape, images_square)
  are checked for presence using asset_group_id
- min_count and max_count are enforced on submitted lists
- Each item in a group list is validated using the inner asset type
  (e.g. each headline item is validated as a text asset)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments