Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
# Changelog

## 2.5.2

### Minor Changes

- Add `assets_optional` field to format schema for better asset discovery

**Schema Changes:**

- **format.json**: Add `assets_optional` array field alongside existing `assets_required`

**Rationale:**

Formats often support optional assets that enhance the creative experience but aren't strictly required. Previously, there was no way to advertise these capabilities - buyers could only see required assets. The new `assets_optional` field enables:

- **Better asset discovery**: Buyers and AI agents can see the full range of assets a format supports
- **Richer creatives**: When optional assets are available, formats can produce enhanced experiences
- **Clear separation**: Required vs optional assets are explicitly distinguished

**Example:**

```json
{
"format_id": { "agent_url": "https://creative.adcontextprotocol.org", "id": "video_30s" },
"assets_required": [
{ "item_type": "individual", "asset_id": "video_file", "asset_type": "video" }
],
"assets_optional": [
{ "item_type": "individual", "asset_id": "end_card", "asset_type": "image" },
{ "item_type": "individual", "asset_id": "companion_banner", "asset_type": "image" },
{ "item_type": "individual", "asset_id": "impression_tracker", "asset_type": "tracking_pixel" }
]
}
```

**Migration:** Non-breaking change. Existing formats without `assets_optional` continue to work unchanged.

## 2.5.1

### Patch Changes
Expand Down
15 changes: 14 additions & 1 deletion docs/creative/asset-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,9 @@ The keys in the assets object correspond to the `asset_id` values defined in the

## Usage in Creative Formats

Creative formats specify their required assets using `assets_required` (an array):
Creative formats specify their assets using two arrays:
- **`assets_required`** - Assets that MUST be provided for a valid creative
- **`assets_optional`** - Assets that MAY be provided for enhanced experiences (e.g., companion banners, third-party tracking pixels)

```json
{
Expand All @@ -360,6 +362,17 @@ Creative formats specify their required assets using `assets_required` (an array
"max_file_size_mb": 30
}
}
],
"assets_optional": [
{
"item_type": "individual",
"asset_id": "impression_tracker",
"asset_type": "tracking_pixel",
"requirements": {
"format": ["url"],
"description": "Third-party impression tracking pixel URL"
}
}
]
}
```
Expand Down
45 changes: 44 additions & 1 deletion docs/creative/formats.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ Formats are JSON objects with the following key fields:
"type": "video",
"assets_required": [
{
"item_type": "individual",
"asset_id": "video_file",
"asset_type": "video",
"asset_role": "hero_video",
Expand All @@ -228,6 +229,38 @@ Formats are JSON objects with the following key fields:
"resolution": ["1920x1080", "1280x720"]
}
}
],
"assets_optional": [
{
"item_type": "individual",
"asset_id": "end_card_image",
"asset_type": "image",
"asset_role": "end_card",
"requirements": {
"dimensions": "1920x1080",
"format": ["PNG", "JPG"]
}
},
{
"item_type": "individual",
"asset_id": "companion_banner",
"asset_type": "image",
"asset_role": "companion",
"requirements": {
"dimensions": "300x250",
"format": ["PNG", "JPG", "GIF"]
}
},
{
"item_type": "individual",
"asset_id": "impression_tracker",
"asset_type": "tracking_pixel",
"asset_role": "third_party_tracking",
"requirements": {
"format": ["url"],
"description": "Third-party impression tracking pixel URL"
}
}
]
}
```
Expand All @@ -236,10 +269,20 @@ Formats are JSON objects with the following key fields:
- **format_id**: Unique identifier (may be namespaced with `domain:id`)
- **agent_url**: The creative agent authoritative for this format
- **type**: Category (video, display, audio, native, dooh, rich_media)
- **assets_required**: Array of asset specifications
- **assets_required**: Array of required asset specifications - creatives MUST provide these
- **assets_optional**: Array of optional asset specifications - creatives MAY provide these for enhanced experiences
- **asset_role**: Identifies asset purpose (hero_image, logo, cta_button, etc.)
- **renders**: Array of rendered outputs with dimensions - see below

### Asset Discovery

The `assets_required` and `assets_optional` arrays enable comprehensive asset discovery. Buyers can inspect a format to understand:

1. **What they must provide** (`assets_required`) - Minimum assets needed for a valid creative
2. **What they can provide** (`assets_optional`) - Additional assets that enhance the creative or addtional third-party tracking assets.

This separation helps creative tools and AI agents understand the full capabilities of a format, enabling richer creative experiences when optional assets are available while ensuring minimum requirements are always clear.

### Rendered Outputs and Dimensions

Formats specify their rendered outputs via the `renders` array. Most formats produce a single render, but some (companion ads, adaptive formats, multi-placement) produce multiple renders:
Expand Down
4 changes: 2 additions & 2 deletions docs/creative/implementing-creative-agents.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Creative agents must implement these two tasks:
Return all formats your agent defines. This is how buyers discover what creative formats you support.

**Key responsibilities:**
- Return complete format definitions with all `assets_required`
- Return complete format definitions with all `assets_required` and `assets_optional`
- Include your `agent_url` in each format
- Use proper namespacing for `format_id` values

Expand Down Expand Up @@ -169,7 +169,7 @@ When validating manifests:

When updating format definitions:

- **Additive changes** (new optional assets) are safe
- **Additive changes** (new optional assets in `assets_optional`) are safe
- **Breaking changes** (removing assets, changing requirements) require new format_id
- Consider versioning: `youragency.com:format_name_v2`
- Maintain backward compatibility when possible
Expand Down
3 changes: 2 additions & 1 deletion docs/media-buy/task-reference/list_creative_formats.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Formats may produce multiple rendered pieces (e.g., video + companion banner). D

| Field | Description |
|-------|-------------|
| `formats` | Array of full format definitions (format_id, name, type, requirements, assets_required, renders) |
| `formats` | Array of full format definitions (format_id, name, type, requirements, assets_required, assets_optional, renders) |
| `creative_agents` | Optional array of other creative agents providing additional formats |

See [Format schema](https://adcontextprotocol.org/schemas/v2/core/format.json) for complete format object structure.
Expand Down Expand Up @@ -406,6 +406,7 @@ Each format includes:
| `type` | Format type (audio, video, display, dooh) |
| `requirements` | Technical requirements (duration, file types, bitrate, etc.) |
| `assets_required` | Array of required assets with specifications |
| `assets_optional` | Array of optional assets for enhanced experiences (companion banners, tracking pixels, etc.) |
| `renders` | Array of rendered output pieces (dimensions, role) |

### Asset Roles
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "adcontextprotocol",
"version": "2.5.1",
"version": "2.5.2",
"private": true,
"scripts": {
"start": "bash -c 'source <(grep CONDUCTOR_PORT .env.local | sed \"s/^/export /\") && DOTENV_CONFIG_PATH=.env.local PORT=${CONDUCTOR_PORT:-3000} tsx watch server/src/index.ts'",
Expand Down
29 changes: 17 additions & 12 deletions server/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8334,18 +8334,23 @@ Disallow: /api/admin/

return res.json({
success: true,
formats: formats.map(format => ({
format_id: format.format_id,
name: format.name,
type: format.type,
description: format.description,
preview_image: format.preview_image,
example_url: format.example_url,
renders: format.renders,
assets_required: format.assets_required,
output_format_ids: format.output_format_ids,
agent_url: format.agent_url,
})),
formats: formats.map(format => {
// Cast to allow assets_optional (added in schema v2.5.2, @adcp/client may not have it yet)
const formatWithOptional = format as typeof format & { assets_optional?: unknown };
return {
format_id: format.format_id,
name: format.name,
type: format.type,
description: format.description,
preview_image: format.preview_image,
example_url: format.example_url,
renders: format.renders,
assets_required: format.assets_required,
assets_optional: formatWithOptional.assets_optional,
output_format_ids: format.output_format_ids,
agent_url: format.agent_url,
};
}),
});
} catch (error) {
logger.error({ err: error, url }, 'Agent formats fetch error');
Expand Down
90 changes: 90 additions & 0 deletions static/schemas/source/core/format.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,96 @@
]
}
},
"assets_optional": {
"type": "array",
"description": "Array of optional assets or asset groups for this format. These assets enhance the creative but are not required. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Useful for asset discovery and showing what additional assets a format can utilize.",
"items": {
"oneOf": [
{
"description": "Individual optional asset",
"type": "object",
"properties": {
"item_type": {
"type": "string",
"const": "individual",
"description": "Discriminator indicating this is an individual asset"
},
"asset_id": {
"type": "string",
"description": "Unique identifier for this asset. Creative manifests MUST use this exact value as the key in the assets object."
},
"asset_type": {
"$ref": "/schemas/enums/asset-content-type.json",
"description": "Type of asset"
},
"asset_role": {
"type": "string",
"description": "Optional descriptive label for this asset's purpose (e.g., 'background_image', 'secondary_logo'). Not used for referencing assets in manifests—use asset_id instead. This field is for human-readable documentation and UI display only."
},
"requirements": {
"type": "object",
"description": "Technical requirements for this asset (dimensions, file size, duration, etc.). For template formats, use parameters_from_format_id: true to indicate asset parameters must match the format_id parameters (width/height/unit and/or duration_ms).",
"additionalProperties": true
}
},
"required": ["item_type", "asset_id", "asset_type"]
},
{
"description": "Repeatable optional asset group (for additional carousel items, optional slides, etc.)",
"type": "object",
"properties": {
"item_type": {
"type": "string",
"const": "repeatable_group",
"description": "Discriminator indicating this is a repeatable asset group"
},
"asset_group_id": {
"type": "string",
"description": "Identifier for this asset group (e.g., 'optional_product', 'bonus_slide')"
},
"min_count": {
"type": "integer",
"description": "Minimum number of repetitions if this optional group is used (typically 0 or 1)",
"minimum": 0
},
"max_count": {
"type": "integer",
"description": "Maximum number of repetitions allowed",
"minimum": 1
},
"assets": {
"type": "array",
"description": "Assets within each repetition of this group",
"items": {
"type": "object",
"properties": {
"asset_id": {
"type": "string",
"description": "Identifier for this asset within the group"
},
"asset_type": {
"$ref": "/schemas/enums/asset-content-type.json",
"description": "Type of asset"
},
"asset_role": {
"type": "string",
"description": "Optional descriptive label for this asset's purpose. Not used for referencing assets in manifests—use asset_id instead. This field is for human-readable documentation and UI display only."
},
"requirements": {
"type": "object",
"description": "Technical requirements for this asset. For template formats, use parameters_from_format_id: true to indicate asset parameters must match the format_id parameters (width/height/unit and/or duration_ms).",
"additionalProperties": true
}
},
"required": ["asset_id", "asset_type"]
}
}
},
"required": ["item_type", "asset_group_id", "min_count", "max_count", "assets"]
}
]
}
},
"delivery": {
"type": "object",
"description": "Delivery method specifications (e.g., hosted, VAST, third-party tags)",
Expand Down
2 changes: 1 addition & 1 deletion static/schemas/source/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"title": "AdCP Schema Registry v1",
"version": "1.0.0",
"description": "Registry of all AdCP JSON schemas for validation and discovery",
"adcp_version": "2.5.1",
"adcp_version": "2.5.2",
"standard_formats_version": "2.0.0",
"versioning": {
"note": "AdCP uses path-based versioning. The schema URL path (/schemas/) indicates the version. Individual request/response schemas do NOT include adcp_version fields. Compatibility follows semantic versioning rules."
Expand Down
Loading