Skip to content

feat: AXE-27 add unified assets field for better asset discovery#361

Closed
BaiyuScope3 wants to merge 11 commits into
mainfrom
feature/assets-optional-discovery
Closed

feat: AXE-27 add unified assets field for better asset discovery#361
BaiyuScope3 wants to merge 11 commits into
mainfrom
feature/assets-optional-discovery

Conversation

@BaiyuScope3

@BaiyuScope3 BaiyuScope3 commented Dec 24, 2025

Copy link
Copy Markdown
Collaborator

Add unified assets field to format schema for better asset discovery

Ticket: https://linear.app/scope3-projects/issue/AXE-27/adcp-protocol-fix-fix-document-improve-assets-discovery-for-tracker

Problem

Currently, buyers and AI agents have no way to discover what optional assets a creative format supports. The assets_required array only tells them the minimum assets needed, but formats often support additional assets that enhance the creative:

  • Companion banners for video ads
  • Third-party impression trackers for measurement
  • End cards for video formats
  • Secondary logos or background images

Without asset discovery, AI agents building creatives miss opportunities to create richer experiences.

Solution

Since each asset in assets_required already has a required boolean field, we introduced a unified assets array:

  • required: true - Asset MUST be provided for a valid creative
  • required: false - Asset is optional, enhances the creative when provided

This is cleaner than having two separate arrays (assets_required + assets_optional).

Example

{
  "format_id": { "agent_url": "https://creative.adcontextprotocol.org", "id": "video_30s" },
  "assets": [
    { "item_type": "individual", "asset_id": "video_file", "asset_type": "video", "required": true },
    { "item_type": "individual", "asset_id": "end_card", "asset_type": "image", "required": false },
    { "item_type": "individual", "asset_id": "impression_tracker", "asset_type": "tracking_pixel", "required": false }
  ]
}

Changes

  • Schema: Add assets field, deprecate assets_required (still supported)
  • Server: Include both assets and assets_required in format responses
  • Documentation: Update format docs, asset-types, implementing-creative-agents, and task references
  • Version: Bump to 2.6.0

Migration

Non-breaking change. assets_required is deprecated but still supported for backward compatibility. New implementations should use assets.

!! `assets_required` field will be formally removed in next major version release

@BaiyuScope3 BaiyuScope3 requested review from EmmaLouise2018 and bokelley and removed request for EmmaLouise2018 and bokelley December 24, 2025 22:10
@BaiyuScope3 BaiyuScope3 marked this pull request as draft December 24, 2025 22:10
@bokelley

Copy link
Copy Markdown
Contributor

We have a "required" field already, so I think the better approach might be to rename assets_required to just assets, and have the required field determine which are needed. This would also let us do something like 'one of' in the future. I think we should deprecate assets_required but continue to support it until we fully migrate.

@BaiyuScope3

BaiyuScope3 commented Jan 2, 2026

Copy link
Copy Markdown
Collaborator Author

We have a "required" field already, so I think the better approach might be to rename assets_required to just assets, and have the required field determine which are needed. This would also let us do something like 'one of' in the future. I think we should deprecate assets_required but continue to support it until we fully migrate.

Definitely agree 👍 I hesitated initially since it’s a somewhat invasive change, but it’s clearly better to make this adjustment early. I'll update the PR
we can still preserve the old assets_required field for backward compatibility.

The adcp-client PR will be posted after this is merged :)
@bokelley could you also grant me the push permission for the creative-agent repo 🙏

@BaiyuScope3 BaiyuScope3 changed the title feat: add assets_optional field for better asset discovery feat: add assets field for better asset discovery Jan 2, 2026
@BaiyuScope3 BaiyuScope3 force-pushed the feature/assets-optional-discovery branch from dd50792 to d3ba7a8 Compare January 2, 2026 19:22
- Add new 'assets' array to format schema with 'required' boolean per asset
- Deprecate 'assets_required' (still supported for backward compatibility)
- Enables full asset discovery for buyers and AI agents
- Update server to include both fields in format responses
- Update documentation across creative and media-buy docs
- Bump version to 2.6.0
@BaiyuScope3 BaiyuScope3 force-pushed the feature/assets-optional-discovery branch from d3ba7a8 to a8723be Compare January 2, 2026 19:35
- Resolve package-lock.json version to 2.6.0
- Accept main's simplified media-buy/list_creative_formats (points to creative docs)
- Update creative/list_creative_formats with assets field
- Fix asset_type: use 'url' for tracking pixels (valid content type)
@BaiyuScope3 BaiyuScope3 marked this pull request as ready for review January 2, 2026 19:54
@BaiyuScope3 BaiyuScope3 changed the title feat: add assets field for better asset discovery feat: AXE-27 add assets field for better asset discovery Jan 2, 2026
@BaiyuScope3 BaiyuScope3 changed the title feat: AXE-27 add assets field for better asset discovery feat: AXE-27 add unified assets field for better asset discovery Jan 2, 2026

@bokelley bokelley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall - do we split out a 2.6.x branch so we can have ongoing patches to 2.5.x?

Comment thread docs/creative/task-reference/list_creative_formats.mdx
Comment thread docs/creative/asset-types.mdx
Comment thread server/src/http.ts
output_format_ids: format.output_format_ids,
agent_url: format.agent_url,
})),
formats: formats.map(format => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we have to do this map anyway? why can't we just return directly from the JS client here? and shouldn't it be smart about this and map assets_required to assets.required = true so the client is magically compatible?

@BaiyuScope3 BaiyuScope3 Jan 2, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I was wrong, this won't be used by any adcp client, this seems used in the member page (https://agenticadvertising.org/members), where when user on a creative agent in the member directory, it opens a modal and calls loadAgentFormats(url)

In the client there is no http call needed, everything enforced by the type(schema) already, we will add logic to make the migration happens behind scene.

  • So all historical data are automatically compatible
  • the new creatives will automatically mapped to the new field even if they're using the old spec

Comment thread static/schemas/source/core/format.json
Comment thread static/schemas/source/core/format.json Outdated
@BaiyuScope3

Copy link
Copy Markdown
Collaborator Author

This PR has been moved to #490
We’re creating a separate release branch for 2.6.x. The current main branch will remain as the patch branch for 2.5.x.

@BaiyuScope3 BaiyuScope3 closed this Jan 2, 2026
bokelley added a commit that referenced this pull request Mar 21, 2026
Includes fixes for comply() signal field names (#359), inline creative
creative_id (#360), and getPlatformTypesWithLabels (#361).

Adapt to stricter types: derive SpecialCategory from Episode, cast
params to Record<string, unknown>, narrow property description.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Mar 22, 2026
* feat: agent quality coaching tools and training agent type safety

Add evaluate_agent_quality and compare_media_kit tools to Addie's member
toolset for agent quality coaching. evaluate_agent_quality runs SDK comply()
and returns structured results for conversational coaching. compare_media_kit
lets publishers compare their stated inventory against what their agent
actually returns via get_products.

Refactor training agent to use SDK request types throughout instead of
Record<string, unknown> with manual casts. Handlers now cast args to typed
SDK requests at entry, eliminating ~50 individual field casts. Derive
extension types structurally (PackageUpdate, Destination, SignalFilters)
for SDK types not re-exported from the main entry point.

Type shared/formats.ts with TrainingFormat interface. Fix compare_media_kit
gap analysis reading non-existent p.channel/p.format fields (now correctly
iterates p.channels array and p.format_ids array). Add input validation
and data delimiters for prompt injection defense on user-provided content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: basic auth handling and parallel brief execution in agent tools

buildAuthOption now returns proper { type: 'basic', username, password }
for basic auth agents instead of incorrectly wrapping credentials as
bearer tokens. The SDK's comply() and AdCPClient both support basic auth
natively.

compare_media_kit now runs get_products briefs concurrently via
Promise.all instead of sequentially, reducing latency proportionally
to the number of verticals tested.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: invalid CPA event_type caught by quality evaluation smoke test

NovaMind AI publisher used event_type 'agent_session' which is not a
valid EventType in the AdCP schema. The SDK's comply() correctly
rejected this during schema validation, cascading failures across
media buy lifecycle tests.

Fix: change to 'custom' (valid EventType), tighten PricingTemplate.eventType
from string to EventType, and remove the unsafe cast in buildPricingOption.
Also fix smoke test health check to accept standalone agent responses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* merge main and fix all typecheck errors

Merge main into agent-test-framework branch, resolving conflicts in
training-agent files. Fix all pre-existing typecheck errors across the
codebase:

- testing/index.ts: add `type` keyword to type re-exports (isolatedModules)
- tsconfig.json: add paths for @adcp/client subpath exports
- billing.ts: narrow Stripe Customer|DeletedCustomer union after .deleted guard
- http.ts: same Stripe union narrowing
- stripe-client.ts: fix void truthiness check on Product.deleted
- bolt-app.ts: cast Slack streaming chunks (undocumented API feature)
- Test files: fix mock typing (jest.fn<any>), add missing required fields,
  remove unused @ts-expect-error directives

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: training agent compliance fixes from local testing

- Cross-session media buy lookup: get_media_buys and get_media_buy_delivery
  now search all sessions when explicit IDs aren't found locally, matching
  real seller behavior where media_buy_ids is a global lookup
- SDK field aliases: brief→signal_spec, signal_id→signal_agent_segment_id,
  singular destination, plural media_buy_ids on delivery endpoint
- include_snapshot support on get_media_buys response
- Bid price validation: auction pricing now requires bid_price
- activate_signal relaxed required fields for SDK-style calls
- get_adcp_capabilities now reports signals in supported_protocols
- creative_id validation: reject creatives without IDs per spec
  (buyer assigns creative_id, not seller)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update_media_buy cross-session lookup

Add cross-session fallback to handleUpdateMediaBuy, matching the pattern
already applied to get_media_buys and get_media_buy_delivery. The SDK's
compliance test creates and updates media buys in separate MCP requests,
which land in different sessions with the stateless transport.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: upgrade @adcp/client to 4.13.0

Includes fixes for comply() signal field names (#359), inline creative
creative_id (#360), and getPlatformTypesWithLabels (#361).

Adapt to stricter types: derive SpecialCategory from Episode, cast
params to Record<string, unknown>, narrow property description.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: L3 error compliance for training agent

- Use adcpError() from SDK for all error responses, providing L3
  transport (structuredContent.adcp_error + JSON text fallback + isError)
- Replace custom validation_error codes with standard AdCP error codes:
  PRODUCT_NOT_FOUND, BUDGET_TOO_LOW, INVALID_REQUEST, SERVICE_UNAVAILABLE
- Move budget validation before product lookup so negative budgets
  return BUDGET_TOO_LOW instead of PRODUCT_NOT_FOUND
- Add root POST route to standalone server for SDK error transport tests
- Remove tsconfig paths workaround (SDK 4.13.0 typesVersions handles it)

Error Compliance track: 0/3 → 3/3 passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: buyer-artifact-grounded agent testing tools

Replace compare_media_kit with two tools grounded in real buyer artifacts:

- test_rfp_response: Takes an RFP brief, calls get_products with brief
  mode, runs deterministic gap analysis (channels, formats, budget, KPIs).
  Supports publisher_response for comparison.

- test_io_execution: Takes IO line items, maps each to agent products via
  normalized channel/format/pricing scoring, constructs the exact
  create_media_buy JSON a buyer agent would send. Optional execute mode.

Training agent improvements:
- Channel-aware brief matching (+10 per channel match vs keyword)
- Proposal completion in brief mode (pulls missing allocated products)
- Fix viewpoint_multi_screen proposal suffix (premium → video_premium)
- Startup warning when proposals reference missing products
- invalidateCache now clears cachedProposals

Security hardening:
- SSRF protection: validateAgentUrl blocks metadata endpoints, private
  IPs, and requires HTTPS in production
- Boundary tags around external agent response data
- Error message truncation (500 char limit)
- Use original agentUrl in error messages (not resolved URL)

Also: upgrade @adcp/client to 4.14.0 (state machine compliance)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add changeset for buyer artifact testing tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add buyer artifact test scripts and spec

- scripts/test-buyer-artifacts.ts: e2e tests for test_rfp_response and
  test_io_execution against the training agent
- scripts/test-comply.ts: comply() test runner
- specs/buyer-artifact-testing.md: design spec for buyer artifact tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address code review and security review findings

- Add 30s timeout on all outbound executeTask calls (SSRF mitigation)
- Replace console.warn with structured logger in product-factory
- Fix stale dry_run reference in prompts.ts (renamed to execute)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address expert review feedback

- Add 'audio' → 'streaming_audio' alias to prevent false mismatches
- Remove unused quantity field from test_io_execution schema
- Update spec to use execute instead of dry_run

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 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.

2 participants