@adcp/sdk 15.9.5 → 15.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/lib/core/AgentClient.d.mts +4 -2
  2. package/dist/lib/core/AgentClient.d.ts +4 -2
  3. package/dist/lib/core/AgentClient.js +4 -2
  4. package/dist/lib/core/AgentClient.mjs +4 -2
  5. package/dist/lib/core/SingleAgentClient.d.mts +7 -3
  6. package/dist/lib/core/SingleAgentClient.d.ts +7 -3
  7. package/dist/lib/core/SingleAgentClient.js +204 -13
  8. package/dist/lib/core/SingleAgentClient.mjs +209 -13
  9. package/dist/lib/core/product-cache.d.mts +3 -1
  10. package/dist/lib/core/product-cache.d.ts +3 -1
  11. package/dist/lib/core/product-cache.js +2 -1
  12. package/dist/lib/core/product-cache.mjs +2 -1
  13. package/dist/lib/registry/types.d.mts +3 -2
  14. package/dist/lib/registry/types.d.ts +3 -2
  15. package/dist/lib/registry/types.generated.d.mts +21 -9
  16. package/dist/lib/registry/types.generated.d.ts +21 -9
  17. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  18. package/dist/lib/server/decisioning/runtime/from-platform.js +6 -2
  19. package/dist/lib/server/decisioning/runtime/from-platform.mjs +6 -2
  20. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  21. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  22. package/dist/lib/v2/projection/augment-response.js +6 -3
  23. package/dist/lib/v2/projection/augment-response.mjs +8 -5
  24. package/dist/lib/v2/projection/creative-delivery.d.mts +2 -0
  25. package/dist/lib/v2/projection/creative-delivery.d.ts +2 -0
  26. package/dist/lib/v2/projection/creative-delivery.js +36 -17
  27. package/dist/lib/v2/projection/creative-delivery.mjs +37 -18
  28. package/dist/lib/v2/projection/legacy-metadata.d.mts +12 -0
  29. package/dist/lib/v2/projection/legacy-metadata.d.ts +12 -0
  30. package/dist/lib/v2/projection/legacy-metadata.js +41 -1
  31. package/dist/lib/v2/projection/legacy-metadata.mjs +37 -1
  32. package/dist/lib/v2/projection/v1-to-v2.d.mts +7 -0
  33. package/dist/lib/v2/projection/v1-to-v2.d.ts +7 -0
  34. package/dist/lib/v2/projection/v1-to-v2.js +83 -2
  35. package/dist/lib/v2/projection/v1-to-v2.mjs +86 -1
  36. package/dist/lib/version.d.mts +3 -3
  37. package/dist/lib/version.d.ts +3 -3
  38. package/dist/lib/version.js +3 -3
  39. package/dist/lib/version.mjs +3 -3
  40. package/docs/TYPE-SUMMARY.md +2 -2
  41. package/docs/guides/CREATIVE-DELIVERY.md +45 -6
  42. package/docs/llms.txt +2 -2
  43. package/docs/migration-14.x-rc-worksheet.md +4 -4
  44. package/package.json +1 -1
@@ -536,8 +536,10 @@ export declare class AgentClient {
536
536
  /**
537
537
  * Resolve the creative wire mode used by canonical writes without sending a
538
538
  * mutation. Uses capabilities, this tool's input schema, and the client wire
539
- * pin. Older peers with insufficient evidence return `unknown` and require
540
- * an unambiguous legacy reference during projection; conflicting evidence
539
+ * pin. Older peers with insufficient evidence return `unknown`; a matching
540
+ * seller-advertised product option can establish canonical delivery for an
541
+ * individual 3.1 write. Otherwise projection requires an unambiguous legacy
542
+ * reference. Conflicting evidence
541
543
  * or unproven support with a 3.2+ buyer pin throws `CreativeFormatCapabilityError`.
542
544
  */
543
545
  resolveCreativeFormatWireMode(taskType: 'sync_creatives' | 'create_media_buy' | 'update_media_buy', options?: Pick<TaskOptions, 'signal' | 'transport'>): Promise<CreativeFormatWireMode>;
@@ -536,8 +536,10 @@ export declare class AgentClient {
536
536
  /**
537
537
  * Resolve the creative wire mode used by canonical writes without sending a
538
538
  * mutation. Uses capabilities, this tool's input schema, and the client wire
539
- * pin. Older peers with insufficient evidence return `unknown` and require
540
- * an unambiguous legacy reference during projection; conflicting evidence
539
+ * pin. Older peers with insufficient evidence return `unknown`; a matching
540
+ * seller-advertised product option can establish canonical delivery for an
541
+ * individual 3.1 write. Otherwise projection requires an unambiguous legacy
542
+ * reference. Conflicting evidence
541
543
  * or unproven support with a 3.2+ buyer pin throws `CreativeFormatCapabilityError`.
542
544
  */
543
545
  resolveCreativeFormatWireMode(taskType: 'sync_creatives' | 'create_media_buy' | 'update_media_buy', options?: Pick<TaskOptions, 'signal' | 'transport'>): Promise<CreativeFormatWireMode>;
@@ -794,8 +794,10 @@ class AgentClient {
794
794
  /**
795
795
  * Resolve the creative wire mode used by canonical writes without sending a
796
796
  * mutation. Uses capabilities, this tool's input schema, and the client wire
797
- * pin. Older peers with insufficient evidence return `unknown` and require
798
- * an unambiguous legacy reference during projection; conflicting evidence
797
+ * pin. Older peers with insufficient evidence return `unknown`; a matching
798
+ * seller-advertised product option can establish canonical delivery for an
799
+ * individual 3.1 write. Otherwise projection requires an unambiguous legacy
800
+ * reference. Conflicting evidence
799
801
  * or unproven support with a 3.2+ buyer pin throws `CreativeFormatCapabilityError`.
800
802
  */
801
803
  async resolveCreativeFormatWireMode(taskType, options) {
@@ -762,8 +762,10 @@ class AgentClient {
762
762
  /**
763
763
  * Resolve the creative wire mode used by canonical writes without sending a
764
764
  * mutation. Uses capabilities, this tool's input schema, and the client wire
765
- * pin. Older peers with insufficient evidence return `unknown` and require
766
- * an unambiguous legacy reference during projection; conflicting evidence
765
+ * pin. Older peers with insufficient evidence return `unknown`; a matching
766
+ * seller-advertised product option can establish canonical delivery for an
767
+ * individual 3.1 write. Otherwise projection requires an unambiguous legacy
768
+ * reference. Conflicting evidence
767
769
  * or unproven support with a 3.2+ buyer pin throws `CreativeFormatCapabilityError`.
768
770
  */
769
771
  async resolveCreativeFormatWireMode(taskType, options) {
@@ -1012,14 +1012,18 @@ export declare class SingleAgentClient {
1012
1012
  * sending a mutation. Discovers capabilities and the current tool's input
1013
1013
  * schema, or reuses fresh cached/primed evidence, with this client's wire pin.
1014
1014
  *
1015
- * `unknown` preserves the conservative legacy projection for older peers
1016
- * whose capabilities and schema do not establish support. Projection still
1017
- * requires an unambiguous legacy reference for each creative in that case.
1015
+ * This context-free check returns `unknown` when capabilities and schema do
1016
+ * not establish support. A write to a proven 3.1 seller can still select
1017
+ * canonical delivery from matching seller-advertised product options;
1018
+ * otherwise projection requires an unambiguous legacy reference.
1018
1019
  * Conflicting evidence and unproven support with a 3.2+ buyer pin throw
1019
1020
  * `CreativeFormatCapabilityError`, just as they do during a write.
1020
1021
  */
1021
1022
  resolveCreativeFormatWireMode(taskType: 'sync_creatives' | 'create_media_buy' | 'update_media_buy', options?: ReadRequestOptions): Promise<CreativeFormatWireMode>;
1022
1023
  private resolveCreativeWireMode;
1024
+ private usesScopedDiscoveryTransport;
1025
+ /** Product evidence applies to this request only; it must never prime a tool-wide capability. */
1026
+ private productOptionsSupportCanonicalWire;
1023
1027
  /** Validate malformed creative payloads before capability discovery can perform I/O. */
1024
1028
  private validateBeforeCreativeCapabilityProbe;
1025
1029
  /**
@@ -1012,14 +1012,18 @@ export declare class SingleAgentClient {
1012
1012
  * sending a mutation. Discovers capabilities and the current tool's input
1013
1013
  * schema, or reuses fresh cached/primed evidence, with this client's wire pin.
1014
1014
  *
1015
- * `unknown` preserves the conservative legacy projection for older peers
1016
- * whose capabilities and schema do not establish support. Projection still
1017
- * requires an unambiguous legacy reference for each creative in that case.
1015
+ * This context-free check returns `unknown` when capabilities and schema do
1016
+ * not establish support. A write to a proven 3.1 seller can still select
1017
+ * canonical delivery from matching seller-advertised product options;
1018
+ * otherwise projection requires an unambiguous legacy reference.
1018
1019
  * Conflicting evidence and unproven support with a 3.2+ buyer pin throw
1019
1020
  * `CreativeFormatCapabilityError`, just as they do during a write.
1020
1021
  */
1021
1022
  resolveCreativeFormatWireMode(taskType: 'sync_creatives' | 'create_media_buy' | 'update_media_buy', options?: ReadRequestOptions): Promise<CreativeFormatWireMode>;
1022
1023
  private resolveCreativeWireMode;
1024
+ private usesScopedDiscoveryTransport;
1025
+ /** Product evidence applies to this request only; it must never prime a tool-wide capability. */
1026
+ private productOptionsSupportCanonicalWire;
1023
1027
  /** Validate malformed creative payloads before capability discovery can perform I/O. */
1024
1028
  private validateBeforeCreativeCapabilityProbe;
1025
1029
  /**
@@ -215,6 +215,56 @@ const RECORDLESS_HMAC_READ_ONLY_TASKS = /* @__PURE__ */ new Set([
215
215
  ]);
216
216
  const TASK_SCOPED_STATE_LIMIT = 1e4;
217
217
  const WEBHOOK_JWKS_RESOLVER_LIMIT = 1024;
218
+ function creativeMatchesProductOption(creative, declaration) {
219
+ const params = isPlainRecord(declaration.params) ? declaration.params : {};
220
+ const assets = isPlainRecord(creative.assets) ? creative.assets : {};
221
+ const slots = Array.isArray(params.slots) ? params.slots : [];
222
+ if (!slots.every((slot) => {
223
+ if (!isPlainRecord(slot) || typeof slot.asset_group_id !== "string") return false;
224
+ const value = assets[slot.asset_group_id];
225
+ const entries = value === void 0 ? [] : Array.isArray(value) ? value : [value];
226
+ const minimum = Math.max(typeof slot.min === "number" ? slot.min : 0, slot.required === true ? 1 : 0);
227
+ if (entries.length < minimum || typeof slot.max === "number" && entries.length > slot.max) return false;
228
+ return entries.every(
229
+ (asset) => isPlainRecord(asset) && (typeof slot.asset_type !== "string" || asset.asset_type === slot.asset_type)
230
+ );
231
+ }))
232
+ return false;
233
+ const formatParams = isPlainRecord(creative.format_parameters) ? creative.format_parameters : {};
234
+ const kind = String(creative.format_kind);
235
+ const mediaType = kind.startsWith("image") ? "image" : kind.startsWith("video") ? "video" : kind.startsWith("audio") ? "audio" : kind === "html5" ? "html" : void 0;
236
+ const assetTypes = mediaType === "video" ? ["video", "vast"] : mediaType === "audio" ? ["audio", "vast", "daast"] : mediaType === "html" ? ["html", "zip"] : mediaType ? [mediaType] : ["image", "video", "audio", "html", "zip", "vast", "daast"];
237
+ const requiredMediaSlots = slots.filter(
238
+ (slot) => isPlainRecord(slot) && (slot.required === true || typeof slot.min === "number" && slot.min > 0) && assetTypes.includes(String(slot.asset_type))
239
+ );
240
+ const preferredGroups = mediaType ? [`${mediaType}_main`, mediaType, kind, ...assetTypes] : [];
241
+ const primaryGroup = (requiredMediaSlots.length === 1 ? String(requiredMediaSlots[0].asset_group_id) : void 0) ?? preferredGroups.find((group) => assets[group] !== void 0);
242
+ const sourceAssets = primaryGroup ? [assets[primaryGroup]] : Object.values(assets);
243
+ const dimensionalAssets = sourceAssets.flatMap((value) => Array.isArray(value) ? value : [value]).filter(
244
+ (value) => isPlainRecord(value) && assetTypes.includes(String(value.asset_type))
245
+ );
246
+ return (dimensionalAssets.length > 0 ? dimensionalAssets : [{}]).every((asset) => {
247
+ const actual = { ...asset, ...formatParams };
248
+ for (const key of ["width", "height"]) {
249
+ if (typeof params[key] === "number" && actual[key] !== params[key]) return false;
250
+ const min = params[`min_${key}`];
251
+ const max = params[`max_${key}`];
252
+ if (typeof min === "number" && (typeof actual[key] !== "number" || actual[key] < min)) return false;
253
+ if (typeof max === "number" && (typeof actual[key] !== "number" || actual[key] > max)) return false;
254
+ }
255
+ if (Array.isArray(params.sizes) && !params.sizes.some((size) => isPlainRecord(size) && size.width === actual.width && size.height === actual.height))
256
+ return false;
257
+ const duration = actual.duration_ms ?? actual.duration_ms_exact;
258
+ const exact = params.duration_ms_exact ?? params.duration_ms;
259
+ if (typeof exact === "number" && duration !== exact) return false;
260
+ if (typeof exact !== "number" && Array.isArray(params.duration_ms_range)) {
261
+ const [min, max] = params.duration_ms_range;
262
+ if (typeof duration !== "number" || typeof min === "number" && duration < min || typeof max === "number" && duration > max)
263
+ return false;
264
+ }
265
+ return true;
266
+ });
267
+ }
218
268
  function isDeferredClientFinalizationContext(value) {
219
269
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
220
270
  const context = value;
@@ -1347,7 +1397,7 @@ class SingleAgentClient {
1347
1397
  }
1348
1398
  }
1349
1399
  }
1350
- rememberCanonicalProductRoutes(products, account, authoritativeProducts) {
1400
+ rememberCanonicalProductRoutes(products, account, authoritativeProducts, evidence) {
1351
1401
  this.invalidateCanonicalProductRoutes(authoritativeProducts ?? products, account);
1352
1402
  const accountScope = this.canonicalAccountScope(account);
1353
1403
  const declaredOptions = authoritativeProducts ? this.sellerDeclaredFormatOptions(authoritativeProducts) : void 0;
@@ -1367,12 +1417,15 @@ class SingleAgentClient {
1367
1417
  const refs = (0, import_legacy_metadata.legacyFormatRefsForDeclaration)(option);
1368
1418
  const declared = declaredOptions ? declaredOptions.get(product.product_id)?.some((declaredRef) => this.sameCanonicalOptionRef(declaredRef, ref)) : (0, import_legacy_metadata.sellerDeclaredFormatOption)(option);
1369
1419
  if (declared !== void 0) (0, import_legacy_metadata.rememberSellerDeclaredFormatOption)(option, declared);
1420
+ if (declared === true && evidence)
1421
+ (0, import_legacy_metadata.rememberSellerFormatEvidence)(option, { ...evidence, productId: product.product_id });
1370
1422
  this.rememberCanonicalLegacyRoute(this.canonicalLegacyRouteKey(account, product.product_id, ref), {
1371
1423
  kind: "product",
1372
1424
  accountScope,
1373
1425
  productId: product.product_id,
1374
1426
  optionRef: ref,
1375
1427
  refs,
1428
+ ...declared === true && (0, import_legacy_metadata.sellerFormatEvidence)(option) ? { declaration: (0, import_legacy_metadata.structuredCloneWithLegacyCreativeMetadata)(option) } : {},
1376
1429
  ...declared === false ? { undeclaredSelector: (0, import_legacy_routes.undeclaredFormatOptionSelector)(option) } : {}
1377
1430
  });
1378
1431
  }
@@ -4582,6 +4635,13 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4582
4635
  }
4583
4636
  }
4584
4637
  const conditionalSnapshot = skipCacheRead ? void 0 : cache?.read(cacheScope, cacheParams, true);
4638
+ const productEvidence = this.usesScopedDiscoveryTransport(
4639
+ effectiveOptions
4640
+ ) ? void 0 : {
4641
+ scopeKey: this.getCapabilityEvidenceScope().scopeKey,
4642
+ accountScope: this.canonicalAccountScope(account),
4643
+ expiresAt: Date.now() + (0, import_agent_discovery_cache.resolveAgentDiscoveryTtlMs)(this.config.discoveryCache?.ttlMs)
4644
+ };
4585
4645
  const result = await this.executeAndHandle(
4586
4646
  "get_products",
4587
4647
  "onGetProductsStatusChange",
@@ -4594,7 +4654,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4594
4654
  projectionCatalogs: projectionCatalogs ?? this.config.projectionCatalogs
4595
4655
  });
4596
4656
  const authoritativeProducts = Array.isArray(data.products) ? data.products : response.products;
4597
- this.rememberCanonicalProductRoutes(response.products, account, authoritativeProducts);
4657
+ this.rememberCanonicalProductRoutes(response.products, account, authoritativeProducts, productEvidence);
4598
4658
  const { _message: _dropLegacyMessage, ...canonical } = response;
4599
4659
  void _dropLegacyMessage;
4600
4660
  return { ...canonical, projection: { diagnostics } };
@@ -4605,7 +4665,9 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4605
4665
  );
4606
4666
  const finishCache = async (completed) => {
4607
4667
  if (!cache) return completed;
4608
- const cachedResult = cache.write(cacheScope, cacheParams, completed, conditionalSnapshot);
4668
+ const cachedResult = cache.write(cacheScope, cacheParams, completed, conditionalSnapshot, (materialized) => {
4669
+ this.rememberCanonicalProductRoutes(materialized.data?.products ?? [], account, void 0, productEvidence);
4670
+ });
4609
4671
  if (cachedResult.success && cachedResult.status === "completed") {
4610
4672
  if (!skipCacheRead && cacheParams.if_wholesale_feed_version === void 0 && cacheParams.if_pricing_version === void 0 && cachedResult.data.unchanged === true) {
4611
4673
  return this.getProducts(params, inputHandler, {
@@ -4765,7 +4827,12 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4765
4827
  if (hasCreativeFormatData) {
4766
4828
  this.validateBeforeCreativeCapabilityProbe("create_media_buy", params, taskOptions);
4767
4829
  }
4768
- const wireMode = hasCreativeFormatData ? await this.resolveCreativeFormatWireMode("create_media_buy", taskOptions) : "canonical";
4830
+ const wireMode = hasCreativeFormatData ? await this.resolveCreativeWireMode(
4831
+ "create_media_buy",
4832
+ taskOptions,
4833
+ true,
4834
+ () => this.productOptionsSupportCanonicalWire("create_media_buy", params, [], options)
4835
+ ) : "canonical";
4769
4836
  const wireParams = params;
4770
4837
  const result = await this.executeAndHandle(
4771
4838
  "create_media_buy",
@@ -4853,7 +4920,12 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4853
4920
  if (hasCreativeFormatData) {
4854
4921
  this.validateBeforeCreativeCapabilityProbe("update_media_buy", params, taskOptions);
4855
4922
  }
4856
- const wireMode = hasCreativeFormatData ? await this.resolveCreativeFormatWireMode("update_media_buy", taskOptions) : "canonical";
4923
+ const wireMode = hasCreativeFormatData ? await this.resolveCreativeWireMode(
4924
+ "update_media_buy",
4925
+ taskOptions,
4926
+ true,
4927
+ () => this.productOptionsSupportCanonicalWire("update_media_buy", params, [], options)
4928
+ ) : "canonical";
4857
4929
  const result = await this.executeAndHandle(
4858
4930
  "update_media_buy",
4859
4931
  "onUpdateMediaBuyStatusChange",
@@ -4942,7 +5014,6 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4942
5014
  projectionCatalogs ?? this.config.projectionCatalogs
4943
5015
  );
4944
5016
  this.validateBeforeCreativeCapabilityProbe("sync_creatives", params, taskOptions);
4945
- const wireMode = await this.resolveCreativeFormatWireMode("sync_creatives", taskOptions);
4946
5017
  const configuredSelectorContainers = [
4947
5018
  ...creativeFormatProjection?.selectorContainers ?? []
4948
5019
  ];
@@ -4954,10 +5025,17 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4954
5025
  const assignmentPackageContainers = Array.isArray(params.assignments) ? params.assignments.flatMap(
4955
5026
  (assignment) => typeof assignment.package_id === "string" && !configuredPackageIds.has(assignment.package_id) ? [{ package_id: assignment.package_id }] : []
4956
5027
  ) : [];
5028
+ const selectorContainers = [...configuredSelectorContainers, ...assignmentPackageContainers];
5029
+ const wireMode = await this.resolveCreativeWireMode(
5030
+ "sync_creatives",
5031
+ taskOptions,
5032
+ true,
5033
+ () => this.productOptionsSupportCanonicalWire("sync_creatives", params, selectorContainers, options)
5034
+ );
4957
5035
  const wireParams = this.projectUndeclaredFormatOptions(
4958
5036
  (0, import_creative_delivery.projectSyncCreativesForDelivery)(
4959
5037
  params,
4960
- [...configuredSelectorContainers, ...assignmentPackageContainers],
5038
+ selectorContainers,
4961
5039
  wireMode,
4962
5040
  effectiveLegacyFormatConverter,
4963
5041
  effectiveCanonicalFormatLegacyResolver
@@ -4997,16 +5075,17 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
4997
5075
  * sending a mutation. Discovers capabilities and the current tool's input
4998
5076
  * schema, or reuses fresh cached/primed evidence, with this client's wire pin.
4999
5077
  *
5000
- * `unknown` preserves the conservative legacy projection for older peers
5001
- * whose capabilities and schema do not establish support. Projection still
5002
- * requires an unambiguous legacy reference for each creative in that case.
5078
+ * This context-free check returns `unknown` when capabilities and schema do
5079
+ * not establish support. A write to a proven 3.1 seller can still select
5080
+ * canonical delivery from matching seller-advertised product options;
5081
+ * otherwise projection requires an unambiguous legacy reference.
5003
5082
  * Conflicting evidence and unproven support with a 3.2+ buyer pin throw
5004
5083
  * `CreativeFormatCapabilityError`, just as they do during a write.
5005
5084
  */
5006
5085
  async resolveCreativeFormatWireMode(taskType, options) {
5007
5086
  return this.resolveCreativeWireMode(taskType, options, true);
5008
5087
  }
5009
- async resolveCreativeWireMode(taskType, options, canRediscover) {
5088
+ async resolveCreativeWireMode(taskType, options, canRediscover, matchingProductOptions) {
5010
5089
  const discoveryContext = {};
5011
5090
  const capabilities = await this.getCapabilities({
5012
5091
  ...options,
@@ -5025,13 +5104,16 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
5025
5104
  `Seller capability and ${taskType} input schema disagree about canonical creative support`
5026
5105
  );
5027
5106
  }
5028
- const resolved = declared !== "unknown" ? declared : schema;
5107
+ let resolved = declared !== "unknown" ? declared : schema;
5108
+ if (resolved === "unknown" && (0, import_creative_delivery.canUseProductOptionsForCreativeWire)(capabilities, wireRelease) && matchingProductOptions?.()) {
5109
+ resolved = "canonical";
5110
+ }
5029
5111
  const release = /^v?(\d+)\.(\d+)(?:\.|-|$)/.exec(wireRelease.trim());
5030
5112
  const canonicalRequiredByBuyerPin = release !== null && (Number(release[1]) > 3 || Number(release[1]) === 3 && Number(release[2]) >= 2);
5031
5113
  if (resolved === "unknown" && canonicalRequiredByBuyerPin) {
5032
5114
  if (canRediscover && !usesScopedFetch && this.normalizedAgent.protocol === "mcp" && this.capabilitiesFromSharedCache && toolSchemas?.has(taskType) && !toolInputSchemasByProperties.has(toolSchemas)) {
5033
5115
  await this.invalidateDiscoveryCache(options);
5034
- return this.resolveCreativeWireMode(taskType, options, false);
5116
+ return this.resolveCreativeWireMode(taskType, options, false, matchingProductOptions);
5035
5117
  }
5036
5118
  throw new import_creative_delivery.CreativeFormatCapabilityError(
5037
5119
  `Cannot prove which AdCP release the seller serves for ${taskType}; a 3.2+ client will not guess a legacy creative wire shape`
@@ -5039,6 +5121,115 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
5039
5121
  }
5040
5122
  return resolved;
5041
5123
  }
5124
+ usesScopedDiscoveryTransport(options) {
5125
+ return (0, import_protocols.normalizeTransportOptions)(options?.transport ?? this.config.transport)?.trustedFetchFn !== void 0;
5126
+ }
5127
+ /** Product evidence applies to this request only; it must never prime a tool-wide capability. */
5128
+ productOptionsSupportCanonicalWire(taskType, request, selectorContainers = [], options) {
5129
+ if (!isPlainRecord(request) || this.usesScopedDiscoveryTransport(options)) return false;
5130
+ const scopeKey = this.getCapabilityEvidenceScope().scopeKey;
5131
+ const accountScope = this.canonicalAccountScope(request.account);
5132
+ const optionRef = (value) => {
5133
+ if (!isPlainRecord(value) || typeof value.format_option_id !== "string" || !value.format_option_id) {
5134
+ return void 0;
5135
+ }
5136
+ if (typeof value.publisher_domain === "string") {
5137
+ return {
5138
+ scope: "publisher",
5139
+ publisher_domain: value.publisher_domain,
5140
+ format_option_id: value.format_option_id
5141
+ };
5142
+ }
5143
+ if (value.scope !== void 0 && value.scope !== "product") return void 0;
5144
+ return { scope: "product", format_option_id: value.format_option_id };
5145
+ };
5146
+ const accepts = (container, creative, depth = 0) => {
5147
+ if (depth > 32) return false;
5148
+ if (Array.isArray(container.selector_containers)) {
5149
+ return container.selector_containers.length > 0 && container.selector_containers.every((nested) => accepts(nested, creative, depth + 1));
5150
+ }
5151
+ const refs = Array.isArray(container.format_option_refs) ? container.format_option_refs.map(optionRef) : [];
5152
+ if (refs.some((ref) => ref === void 0)) return false;
5153
+ const creativeRef = isPlainRecord(creative) ? optionRef(creative.format_option_ref) : void 0;
5154
+ if (isPlainRecord(creative) && creative.format_option_ref !== void 0 && !creativeRef) return false;
5155
+ const isSellerDeclaration = (value) => {
5156
+ if (!isPlainRecord(value) || (0, import_legacy_metadata.sellerDeclaredFormatOption)(value) !== true || (0, import_legacy_metadata.isSynthesizedFormatOption)(value)) {
5157
+ return false;
5158
+ }
5159
+ const evidence2 = (0, import_legacy_metadata.sellerFormatEvidence)(value);
5160
+ if (!evidence2 || evidence2.scopeKey !== scopeKey || typeof container.product_id === "string" && evidence2.productId !== container.product_id || evidence2.expiresAt <= Date.now() || evidence2.accountScope !== accountScope && evidence2.accountScope !== "none")
5161
+ return false;
5162
+ const ref = optionRef(value);
5163
+ if (ref && (0, import_legacy_routes.formatOptionOriginFromRoutes)(
5164
+ options?.canonicalFormatLegacyResolver,
5165
+ ref,
5166
+ typeof container.product_id === "string" ? container.product_id : void 0
5167
+ )?.seller_declared === false)
5168
+ return false;
5169
+ return !ref || typeof container.product_id !== "string" || this.cachedFormatOptionOrigin(request.account, ref, container.product_id)?.seller_declared !== false;
5170
+ };
5171
+ const declarations = [
5172
+ ...(Array.isArray(container.format_options) ? container.format_options : []).filter(isSellerDeclaration),
5173
+ ...(0, import_legacy_metadata.selectedFormatOptions)(container).filter(isSellerDeclaration)
5174
+ ];
5175
+ if (typeof container.product_id === "string") {
5176
+ for (const ref of [...refs, ...creativeRef ? [creativeRef] : []]) {
5177
+ if (!ref) continue;
5178
+ const route = this.routeForOption(request.account, container.product_id, ref);
5179
+ if (route?.kind === "product" && route.declaration && isSellerDeclaration(route.declaration))
5180
+ declarations.push(route.declaration);
5181
+ }
5182
+ }
5183
+ const available = declarations.filter((declaration) => declaration.experimental !== true);
5184
+ const matchesRef = (declaration, ref) => {
5185
+ const declaredRef = optionRef(declaration);
5186
+ return declaredRef !== void 0 && this.sameCanonicalOptionRef(declaredRef, ref);
5187
+ };
5188
+ if (!refs.every((ref) => available.some((declaration) => matchesRef(declaration, ref)))) return false;
5189
+ const selected = available.filter(
5190
+ (declaration) => refs.length === 0 || refs.some((ref) => matchesRef(declaration, ref))
5191
+ );
5192
+ if (creative === void 0) return refs.length > 0 && selected.length > 0;
5193
+ if (!isPlainRecord(creative) || typeof creative.format_kind !== "string" || creative.format_id !== void 0)
5194
+ return false;
5195
+ return selected.some(
5196
+ (declaration) => declaration.format_kind === creative.format_kind && (!creativeRef || matchesRef(declaration, creativeRef)) && creativeMatchesProductOption(creative, declaration)
5197
+ );
5198
+ };
5199
+ if (taskType === "sync_creatives") {
5200
+ if (!Array.isArray(request.creatives) || request.creatives.length === 0) return false;
5201
+ const creatives = request.creatives;
5202
+ const assignments = Array.isArray(request.assignments) ? request.assignments : [];
5203
+ if (!assignments.every(
5204
+ (value) => isPlainRecord(value) && typeof value.package_id === "string" && typeof value.creative_id === "string" && creatives.some((creative) => isPlainRecord(creative) && creative.creative_id === value.creative_id)
5205
+ ))
5206
+ return false;
5207
+ return creatives.every((creative) => {
5208
+ if (!isPlainRecord(creative)) return false;
5209
+ const assigned = new Set(
5210
+ assignments.flatMap(
5211
+ (value) => isPlainRecord(value) && value.creative_id === creative.creative_id && typeof value.package_id === "string" ? [value.package_id] : []
5212
+ )
5213
+ );
5214
+ const relevant = assigned.size === 0 ? selectorContainers : selectorContainers.filter(
5215
+ (container) => typeof container.package_id === "string" && assigned.has(container.package_id)
5216
+ );
5217
+ return relevant.length > 0 && [...assigned].every((id) => relevant.some((container) => container.package_id === id)) && relevant.every((container) => accepts(container, creative));
5218
+ });
5219
+ }
5220
+ const packages = ["packages", "new_packages"].flatMap((key) => Array.isArray(request[key]) ? request[key] : []);
5221
+ let evidence = false;
5222
+ return packages.length > 0 && packages.every((pkg) => {
5223
+ if (!isPlainRecord(pkg)) return false;
5224
+ const creatives = Array.isArray(pkg.creatives) ? pkg.creatives : [];
5225
+ const hasSelectors = Array.isArray(pkg.format_option_refs) && pkg.format_option_refs.length > 0;
5226
+ if (!hasSelectors && creatives.length === 0) {
5227
+ return pkg.format_kind === void 0 && pkg.format_ids === void 0;
5228
+ }
5229
+ evidence = true;
5230
+ return (!hasSelectors || accepts(pkg)) && creatives.every((creative) => accepts(pkg, creative));
5231
+ }) && evidence;
5232
+ }
5042
5233
  /** Validate malformed creative payloads before capability discovery can perform I/O. */
5043
5234
  validateBeforeCreativeCapabilityProbe(taskType, params, options) {
5044
5235
  if (options.skipIdempotencyAutoInject || options.skipAccountValidation || options.skipRequestValidation) return;