-
Notifications
You must be signed in to change notification settings - Fork 59
feat(creative): account-scoped creative transformers + build_creative multiplicity #5219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bokelley
wants to merge
14
commits into
main
Choose a base branch
from
account-specific-user-config
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
be1e36b
feat(creative): account-scoped creative transformers + build_creative…
bokelley df31975
feat(creative): pin build_variant_id as the leaf-level lineage anchor
bokelley e418f32
feat(creative): conversational refinement on build_creative
bokelley 95d1541
docs(creative): add creative-transformers migration guide + fix error…
bokelley 73b9770
Merge remote-tracking branch 'origin/main' into account-specific-user…
bokelley 124767f
feat(creative): resolve the four pre-GA review items on build_creative
bokelley 66dcdac
spec(creative): transformer refinement-retention + fan-out multiplici…
bokelley dc3b9e4
spec(creative): build_creative spend controls (max_spend cap + estima…
bokelley 4398146
fix(creative): address F1 spend-controls review (leaf-granular cap sh…
bokelley 336792d
spec(creative): generative-encoding safe additions (free_text params …
bokelley 63fc72e
spec(creative): address Nas review (build_variant_id on report_usage,…
bokelley e0b5a3b
feat(creative): F4 — creative-transformers conformance storyboard + l…
bokelley 4a7c273
fix(creative): add creative-transformers to ADCP_SPECIALISMS (taxonom…
bokelley 81776f3
fix(creative): regenerate OpenAPI registry for creative-transformers …
bokelley File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| --- | ||
| "adcontextprotocol": minor | ||
| --- | ||
|
|
||
| spec(creative): add build_creative spend controls — `max_spend` cap + `mode: "estimate"` dry-run. | ||
|
|
||
| Follow-on from the persona/scenario review: fan-out (`max_creatives` × `max_variants`) and refinement produce many independently-billed leaves, and `per_unit` pricing gives a rate but not the unit count in advance — so an autonomous buyer had no protocol brake on spend. Both additions are optional and gated by a new `creative.supports_spend_controls` capability. | ||
|
|
||
| - **`mode: "estimate"`** (request) → new `BuildCreativeEstimate` response shape (6th `oneOf` member): a dry run that produces and bills nothing and returns a `cost_low`/`cost_high` band computed against the request's actual inputs, with `basis` (`fixed` exact / `estimated_units` / `cpm_deferred`) and an optional per-leaf breakdown. Advisory/non-binding in this revision. | ||
| - **`max_spend: { amount, currency }`** (request) → a hard per-call ceiling: the agent stops before the next leaf would exceed it and returns the partial `BuildCreativeVariantSuccess` with new `budget_status: "capped"` and an advisory `BUDGET_CAP_REACHED` in `errors[]` (every returned leaf real and billed; `items_returned` < `items_total`). First-leaf-over-cap → terminal `BUDGET_CAP_REACHED`; currency mismatch → `INVALID_REQUEST`. | ||
| - New error code **`BUDGET_CAP_REACHED`** (distinct from `BUDGET_EXCEEDED`/`BUDGET_EXHAUSTED`), in both `enumDescriptions` and `enumMetadata`. | ||
| - New capability **`creative.supports_spend_controls`** (default false). | ||
|
|
||
| Deferred to the working group (flagged, not omitted): whether an estimate can be **binding**, and whether a refinement-**loop** bound is a protocol-level session budget vs. a buyer responsibility (documented as buyer-side for now). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| --- | ||
| "adcontextprotocol": minor | ||
| --- | ||
|
|
||
| spec(creative): add `list_transformers` task + account-scoped creative transformers, and extend `build_creative` for transformer selection and variant/catalog multiplicity. | ||
|
|
||
| A **transformer** is the creative analog of a media-buy product: an agent-offered, account-scoped, selectable unit of build capability (a voice, model, style, or director) with a typed configuration surface and per-account pricing. This makes account-specific render configuration — including custom values like cloned voices that exist only for one credential — discoverable from the agent rather than guessed, hung on a global format, or smuggled through `ext`. | ||
|
|
||
| Strictly additive. Existing `build_creative` callers are unaffected (all new request fields are optional; the shipped `BuildCreativeSuccess`/`BuildCreativeMultiSuccess` response shapes are unchanged — a new fifth member is added alongside them). | ||
|
|
||
| New: | ||
| - `list_transformers` task (creative protocol): account-scoped, brief-filterable, paginated discovery. An `expand_params` mode returns account-scoped enumerable option **values** (e.g. your configured voices) on the same tool — no separate options endpoint. | ||
| - Core schemas `transformer.json` and `transformer-param.json`. | ||
| - `get_adcp_capabilities` → `creative.supports_transformers` discriminator. | ||
|
|
||
| `build_creative` extensions: | ||
| - Request: `transformer_id` (select one transformer; target format(s) must be a subset of its `output_format_ids`), `config` (typed bag keyed to the transformer's params — agents MUST reject unknown/out-of-range values), `max_creatives` (catalog/item fan-out: N distinct creatives, one per item, with sampling), `max_variants` + `variant_axis` + `keep_mode` (alternatives per creative). | ||
| - Response: a new `BuildCreativeVariantSuccess` member — `creatives[]` each carrying `variants[]`, with a `build_variant_id` namespace (distinct from preview `preview_id` and served `variant_id`), per-leaf pricing receipt, and `items_total`/`items_returned`. Best-of-N is variants + `recommended`/`rank`. You pay for all produced variants (`per_unit` × N); a kept variant lazily earns a `creative_id` on trafficking, which flows to `report_usage`. Per-format atomic; per-item non-atomic. | ||
|
|
||
| `build_variant` lineage + refinement: | ||
| - `build_variant_id` is now the leaf-level lineage anchor (`x-entity: build_variant`): minted per produced variant, distinct from the call-level `build_creative_id`, lazily earning a durable `creative_id` only on trafficking. Untrafficked leaves are billed via the inline per-leaf `vendor_cost` only; `report_usage` reconciliation applies once a leaf earns a `creative_id`. | ||
| - Conversational refinement: `build_creative` gains `refine_from_build_variant_id` — re-build a prior leaf with a natural-language instruction in `message` plus an optional `config` delta, returning new lineage-linked variants (each with `parent_build_variant_id`); never a mutation. Composes with `max_variants`/`variant_axis`, mutually exclusive with `max_creatives`. Gated by the new `get_adcp_capabilities` → `creative.supports_refinement` discriminator (`UNSUPPORTED_FEATURE` when unsupported; `REFERENCE_NOT_FOUND` for an unknown/expired ref). | ||
|
|
||
| Pricing rides the existing `per_unit` model + inline receipt + `report_usage` unchanged — transformers carry `pricing_options` (reusing `vendor-pricing-option.json`). | ||
|
|
||
| Deprecations (deprecated in 3.1, removed at 4.0; SDKs MUST keep honoring them through 3.1–3.x): `Format.input_format_ids`, `Format.output_format_ids`, `Format.pricing_options`, and the `input_format_ids`/`output_format_ids` discovery filters on `list_creative_formats` — all superseded by `list_transformers`, which carries each transformer's own I/O signature and pricing. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| --- | ||
| "adcontextprotocol": minor | ||
| --- | ||
|
|
||
| spec(creative): generative-encoding safe additions — `free_text` params + per-output transformer pricing. | ||
|
|
||
| The additive half of the generative-agent (Veo/Imagen) encodings follow-on. The two *normative* rules it pairs with — generation count is owned by `max_variants`/`max_creatives` (never a config param), and `aspect_ratio` rides the format axis — are intentionally left to the working group; only the safe schema bits land here. | ||
|
|
||
| - `transformer-param.json` `value_source` gains **`free_text`** (an open buyer-authored string with no closed set — e.g. a `negative_prompt` or style note; `type` MUST be `string`, the closed-set fields MUST be absent) plus an optional **`max_length`**. The description also states that count/quantity knobs MUST NOT be params (count rides `max_variants`/`max_creatives`). | ||
| - `vendor-pricing-option.json` gains optional **`applies_to_output_format_ids`** so one creative transformer can price different outputs differently (e.g. a multi-publisher template charging per publisher format); an unscoped option is the default. Additive and inert for non-creative vendors (signals/governance) — **flagged for shared-schema owner ack**. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| --- | ||
| "adcontextprotocol": minor | ||
| --- | ||
|
|
||
| spec(creative): add pre-call discriminators for creative-transformer refinement retention and fan-out multiplicity. | ||
|
|
||
| Lets a buyer agent know — before sending — what a creative agent supports, instead of probing and handling failures. Additive and optional (all fields default to "unsupported / unbounded"), and the keystone the spend-control and conformance follow-ons build on. | ||
|
|
||
| - `get_adcp_capabilities` → `creative.refinable_retention_seconds` (integer): the guaranteed-minimum window a produced `build_variant_id` stays refinable. Replaces the prose-only "agent-defined window" with a machine-readable floor; omit to keep it agent-defined. | ||
| - `get_adcp_capabilities` → `creative.multiplicity` (object): `supports_catalog_fanout` + `max_creatives_limit`, `supports_variants` + `max_variants_limit`, and `variant_dimensions[]`. Over-limit `max_creatives`/`max_variants` are **clamped** to the ceilings (shortfall via `items_returned` < `items_total`), not rejected — consistent with `item_limit`'s "use the lesser" rule. Absent means no fan-out. | ||
| - `transformer.json` → optional `multiplicity` that narrows the agent-level object per transformer (ceilings ≤ agent, `variant_dimensions` ⊆ agent). | ||
| - `build_creative` docs note the clamp behavior on `max_creatives`/`max_variants`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the settlement model splits billing across two channels: trafficked leaves earn a
creative_idand flow here; untrafficked leaves settle via inlinevendor_coston thebuild_creativeresponse only. that works for charging, but when a variant IS trafficked and itscreative_idlands inreport_usage, there's nobuild_variant_idfield on the usage record. billing reconciliation can't link areport_usageentry back to the specific leaf for audit -pricing_option_idechoes back but it's not a unique identifier. seems likebuild_variant_idshould be an optional field on the usage record.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call — fixed in 63fc72e. Added an optional
build_variant_idto thereport_usageusage record so a trafficked leaf's usage entry links back to the exact produced leaf for audit (you're right thatpricing_option_idisn't unique across leaves). Kept it optional — creatives with no build-variant lineage just omit it.