@adcp/sdk 12.1.0 → 13.0.0-rc.0
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.
- package/README.md +19 -3
- package/bin/adcp-fuzz.js +3 -1
- package/dist/lib/adapters/content-standards-adapter.d.mts +9 -9
- package/dist/lib/adapters/content-standards-adapter.d.ts +9 -9
- package/dist/lib/adapters/content-standards-adapter.d.ts.map +1 -1
- package/dist/lib/adapters/content-standards-adapter.js +22 -22
- package/dist/lib/adapters/content-standards-adapter.js.map +1 -1
- package/dist/lib/adapters/content-standards-adapter.mjs +18 -18
- package/dist/lib/adapters/content-standards-adapter.mjs.map +1 -1
- package/dist/lib/adapters/index.d.mts +2 -2
- package/dist/lib/adapters/index.d.ts +2 -2
- package/dist/lib/adapters/index.d.ts.map +1 -1
- package/dist/lib/adapters/index.js +10 -10
- package/dist/lib/adapters/index.js.map +1 -1
- package/dist/lib/adapters/index.mjs +9 -9
- package/dist/lib/adapters/index.mjs.map +1 -1
- package/dist/lib/auth/oauth/authorization-required.d.mts +3 -0
- package/dist/lib/auth/oauth/authorization-required.d.ts +3 -0
- package/dist/lib/auth/oauth/authorization-required.d.ts.map +1 -1
- package/dist/lib/auth/oauth/authorization-required.js +12 -9
- package/dist/lib/auth/oauth/authorization-required.js.map +1 -1
- package/dist/lib/auth/oauth/authorization-required.mjs +12 -9
- package/dist/lib/auth/oauth/authorization-required.mjs.map +1 -1
- package/dist/lib/auth/oauth/provider-cache.d.mts +7 -0
- package/dist/lib/auth/oauth/provider-cache.d.ts +8 -0
- package/dist/lib/auth/oauth/provider-cache.d.ts.map +1 -0
- package/dist/lib/auth/oauth/provider-cache.js +44 -0
- package/dist/lib/auth/oauth/provider-cache.js.map +1 -0
- package/dist/lib/auth/oauth/provider-cache.mjs +19 -0
- package/dist/lib/auth/oauth/provider-cache.mjs.map +1 -0
- package/dist/lib/conformance/invariants/uniformError.js +1 -1
- package/dist/lib/conformance/invariants/uniformError.js.map +1 -1
- package/dist/lib/conformance/invariants/uniformError.mjs +1 -1
- package/dist/lib/conformance/invariants/uniformError.mjs.map +1 -1
- package/dist/lib/conformance/runners.js +1 -1
- package/dist/lib/conformance/runners.js.map +1 -1
- package/dist/lib/conformance/runners.mjs +1 -1
- package/dist/lib/conformance/runners.mjs.map +1 -1
- package/dist/lib/conformance/seeder.js +5 -5
- package/dist/lib/conformance/seeder.js.map +1 -1
- package/dist/lib/conformance/seeder.mjs +5 -5
- package/dist/lib/conformance/seeder.mjs.map +1 -1
- package/dist/lib/core/ADCPMultiAgentClient.d.mts +26 -29
- package/dist/lib/core/ADCPMultiAgentClient.d.ts +26 -29
- package/dist/lib/core/ADCPMultiAgentClient.d.ts.map +1 -1
- package/dist/lib/core/ADCPMultiAgentClient.js +27 -19
- package/dist/lib/core/ADCPMultiAgentClient.js.map +1 -1
- package/dist/lib/core/ADCPMultiAgentClient.mjs +27 -19
- package/dist/lib/core/ADCPMultiAgentClient.mjs.map +1 -1
- package/dist/lib/core/AgentClient.d.mts +148 -138
- package/dist/lib/core/AgentClient.d.ts +148 -138
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/AgentClient.js +174 -85
- package/dist/lib/core/AgentClient.js.map +1 -1
- package/dist/lib/core/AgentClient.mjs +174 -85
- package/dist/lib/core/AgentClient.mjs.map +1 -1
- package/dist/lib/core/AsyncHandler.d.mts +18 -16
- package/dist/lib/core/AsyncHandler.d.ts +18 -16
- package/dist/lib/core/AsyncHandler.d.ts.map +1 -1
- package/dist/lib/core/AsyncHandler.js +22 -1
- package/dist/lib/core/AsyncHandler.js.map +1 -1
- package/dist/lib/core/AsyncHandler.mjs +22 -1
- package/dist/lib/core/AsyncHandler.mjs.map +1 -1
- package/dist/lib/core/ConversationTypes.d.mts +6 -2
- package/dist/lib/core/ConversationTypes.d.ts +6 -2
- package/dist/lib/core/ConversationTypes.d.ts.map +1 -1
- package/dist/lib/core/ConversationTypes.js.map +1 -1
- package/dist/lib/core/CreativeAgentClient.d.mts +41 -17
- package/dist/lib/core/CreativeAgentClient.d.ts +41 -17
- package/dist/lib/core/CreativeAgentClient.d.ts.map +1 -1
- package/dist/lib/core/CreativeAgentClient.js +39 -12
- package/dist/lib/core/CreativeAgentClient.js.map +1 -1
- package/dist/lib/core/CreativeAgentClient.mjs +39 -12
- package/dist/lib/core/CreativeAgentClient.mjs.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.mts +129 -52
- package/dist/lib/core/SingleAgentClient.d.ts +129 -52
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +1748 -218
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/core/SingleAgentClient.mjs +1758 -218
- package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
- package/dist/lib/core/TaskExecutor.d.mts +9 -0
- package/dist/lib/core/TaskExecutor.d.ts +9 -0
- package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
- package/dist/lib/core/TaskExecutor.js +137 -44
- package/dist/lib/core/TaskExecutor.js.map +1 -1
- package/dist/lib/core/TaskExecutor.mjs +137 -44
- package/dist/lib/core/TaskExecutor.mjs.map +1 -1
- package/dist/lib/index.d.mts +111 -17
- package/dist/lib/index.d.ts +111 -17
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +94 -94
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +93 -94
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/net/ssrf-fetch.d.mts +13 -1
- package/dist/lib/net/ssrf-fetch.d.ts +13 -1
- package/dist/lib/net/ssrf-fetch.d.ts.map +1 -1
- package/dist/lib/net/ssrf-fetch.js +14 -7
- package/dist/lib/net/ssrf-fetch.js.map +1 -1
- package/dist/lib/net/ssrf-fetch.mjs +14 -7
- package/dist/lib/net/ssrf-fetch.mjs.map +1 -1
- package/dist/lib/protocols/a2a.d.mts +2 -2
- package/dist/lib/protocols/a2a.d.ts +2 -2
- package/dist/lib/protocols/a2a.d.ts.map +1 -1
- package/dist/lib/protocols/a2a.js +14 -9
- package/dist/lib/protocols/a2a.js.map +1 -1
- package/dist/lib/protocols/a2a.mjs +14 -9
- package/dist/lib/protocols/a2a.mjs.map +1 -1
- package/dist/lib/protocols/index.d.mts +20 -3
- package/dist/lib/protocols/index.d.ts +20 -3
- package/dist/lib/protocols/index.d.ts.map +1 -1
- package/dist/lib/protocols/index.js +44 -31
- package/dist/lib/protocols/index.js.map +1 -1
- package/dist/lib/protocols/index.mjs +44 -32
- package/dist/lib/protocols/index.mjs.map +1 -1
- package/dist/lib/protocols/mcp-modern.d.ts.map +1 -1
- package/dist/lib/protocols/mcp-modern.js +87 -12
- package/dist/lib/protocols/mcp-modern.js.map +1 -1
- package/dist/lib/protocols/mcp-modern.mjs +89 -12
- package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
- package/dist/lib/protocols/mcp-tasks.d.mts +3 -0
- package/dist/lib/protocols/mcp-tasks.d.ts +3 -0
- package/dist/lib/protocols/mcp-tasks.d.ts.map +1 -1
- package/dist/lib/protocols/mcp-tasks.js +21 -11
- package/dist/lib/protocols/mcp-tasks.js.map +1 -1
- package/dist/lib/protocols/mcp-tasks.mjs +21 -11
- package/dist/lib/protocols/mcp-tasks.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +6 -0
- package/dist/lib/server/create-adcp-server.d.ts +6 -0
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +295 -48
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.mjs +301 -50
- package/dist/lib/server/create-adcp-server.mjs.map +1 -1
- package/dist/lib/server/decisioning/assembly-helpers.d.mts +27 -13
- package/dist/lib/server/decisioning/assembly-helpers.d.ts +27 -13
- package/dist/lib/server/decisioning/assembly-helpers.d.ts.map +1 -1
- package/dist/lib/server/decisioning/assembly-helpers.js +136 -14
- package/dist/lib/server/decisioning/assembly-helpers.js.map +1 -1
- package/dist/lib/server/decisioning/assembly-helpers.mjs +134 -13
- package/dist/lib/server/decisioning/assembly-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/index.d.mts +13 -12
- package/dist/lib/server/decisioning/index.d.ts +13 -12
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js +6 -0
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/index.mjs +9 -3
- package/dist/lib/server/decisioning/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/list-helpers.d.mts +13 -3
- package/dist/lib/server/decisioning/list-helpers.d.ts +13 -3
- package/dist/lib/server/decisioning/list-helpers.d.ts.map +1 -1
- package/dist/lib/server/decisioning/list-helpers.js +13 -3
- package/dist/lib/server/decisioning/list-helpers.js.map +1 -1
- package/dist/lib/server/decisioning/list-helpers.mjs +11 -2
- package/dist/lib/server/decisioning/list-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.d.mts +5 -3
- package/dist/lib/server/decisioning/manifest-helpers.d.ts +5 -3
- package/dist/lib/server/decisioning/manifest-helpers.d.ts.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.js.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/dispatch.d.mts +2 -2
- package/dist/lib/server/decisioning/proposal/dispatch.d.ts +2 -2
- package/dist/lib/server/decisioning/proposal/dispatch.d.ts.map +1 -1
- package/dist/lib/server/decisioning/proposal/dispatch.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/dispatch.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/index.d.mts +1 -1
- package/dist/lib/server/decisioning/proposal/index.d.ts +1 -1
- package/dist/lib/server/decisioning/proposal/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/proposal/index.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/lifecycle.d.mts +3 -2
- package/dist/lib/server/decisioning/proposal/lifecycle.d.ts +3 -2
- package/dist/lib/server/decisioning/proposal/lifecycle.d.ts.map +1 -1
- package/dist/lib/server/decisioning/proposal/lifecycle.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/lifecycle.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/mock-manager.d.mts +3 -3
- package/dist/lib/server/decisioning/proposal/mock-manager.d.ts +3 -3
- package/dist/lib/server/decisioning/proposal/mock-manager.d.ts.map +1 -1
- package/dist/lib/server/decisioning/proposal/mock-manager.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/mock-manager.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.d.mts +10 -6
- package/dist/lib/server/decisioning/proposal/types.d.ts +10 -6
- package/dist/lib/server/decisioning/proposal/types.d.ts.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +21 -2
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +21 -2
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +754 -81
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +763 -81
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/brand-rights.d.mts +9 -9
- package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts +9 -9
- package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/brand-rights.js.map +1 -1
- package/dist/lib/server/decisioning/specialisms/content-standards.d.mts +16 -16
- package/dist/lib/server/decisioning/specialisms/content-standards.d.ts +16 -16
- package/dist/lib/server/decisioning/specialisms/content-standards.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/content-standards.js.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.mts +15 -13
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +15 -13
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative.d.mts +12 -11
- package/dist/lib/server/decisioning/specialisms/creative.d.ts +12 -11
- package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.mts +25 -15
- package/dist/lib/server/decisioning/specialisms/sales.d.ts +25 -15
- package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
- package/dist/lib/server/index.d.mts +3 -3
- package/dist/lib/server/index.d.ts +3 -3
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +72 -72
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/index.mjs +36 -36
- package/dist/lib/server/index.mjs.map +1 -1
- package/dist/lib/server/legacy/v5/index.d.mts +1 -0
- package/dist/lib/server/legacy/v5/index.d.ts +1 -0
- package/dist/lib/server/legacy/v5/index.d.ts.map +1 -1
- package/dist/lib/server/legacy/v5/index.js +74 -1
- package/dist/lib/server/legacy/v5/index.js.map +1 -1
- package/dist/lib/server/legacy/v5/index.mjs +75 -1
- package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
- package/dist/lib/server/responses.d.mts +2 -2
- package/dist/lib/server/responses.d.ts +2 -2
- package/dist/lib/server/responses.js.map +1 -1
- package/dist/lib/server/responses.mjs.map +1 -1
- package/dist/lib/testing/client.d.ts.map +1 -1
- package/dist/lib/testing/client.js +13 -5
- package/dist/lib/testing/client.js.map +1 -1
- package/dist/lib/testing/client.mjs +13 -5
- package/dist/lib/testing/client.mjs.map +1 -1
- package/dist/lib/testing/compliance/comply.d.mts +1 -1
- package/dist/lib/testing/compliance/comply.d.ts +1 -1
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +16 -6
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/comply.mjs +16 -6
- package/dist/lib/testing/compliance/comply.mjs.map +1 -1
- package/dist/lib/testing/scenarios/brand-rights.js +6 -6
- package/dist/lib/testing/scenarios/brand-rights.js.map +1 -1
- package/dist/lib/testing/scenarios/brand-rights.mjs +6 -6
- package/dist/lib/testing/scenarios/brand-rights.mjs.map +1 -1
- package/dist/lib/testing/scenarios/creative.js +7 -7
- package/dist/lib/testing/scenarios/creative.js.map +1 -1
- package/dist/lib/testing/scenarios/creative.mjs +7 -7
- package/dist/lib/testing/scenarios/creative.mjs.map +1 -1
- package/dist/lib/testing/scenarios/discovery.js +2 -2
- package/dist/lib/testing/scenarios/discovery.js.map +1 -1
- package/dist/lib/testing/scenarios/discovery.mjs +2 -2
- package/dist/lib/testing/scenarios/discovery.mjs.map +1 -1
- package/dist/lib/testing/scenarios/edge-cases.js +11 -11
- package/dist/lib/testing/scenarios/edge-cases.js.map +1 -1
- package/dist/lib/testing/scenarios/edge-cases.mjs +11 -11
- package/dist/lib/testing/scenarios/edge-cases.mjs.map +1 -1
- package/dist/lib/testing/scenarios/governance.d.ts.map +1 -1
- package/dist/lib/testing/scenarios/governance.js +16 -22
- package/dist/lib/testing/scenarios/governance.js.map +1 -1
- package/dist/lib/testing/scenarios/governance.mjs +16 -22
- package/dist/lib/testing/scenarios/governance.mjs.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.js +5 -5
- package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.mjs +5 -5
- package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
- package/dist/lib/testing/scenarios/schema-compliance.js +1 -1
- package/dist/lib/testing/scenarios/schema-compliance.js.map +1 -1
- package/dist/lib/testing/scenarios/schema-compliance.mjs +1 -1
- package/dist/lib/testing/scenarios/schema-compliance.mjs.map +1 -1
- package/dist/lib/testing/scenarios/trusted-match.d.ts.map +1 -1
- package/dist/lib/testing/scenarios/trusted-match.js +4 -3
- package/dist/lib/testing/scenarios/trusted-match.js.map +1 -1
- package/dist/lib/testing/scenarios/trusted-match.mjs +4 -3
- package/dist/lib/testing/scenarios/trusted-match.mjs.map +1 -1
- package/dist/lib/testing/storyboard/probes.d.mts +6 -0
- package/dist/lib/testing/storyboard/probes.d.ts +6 -0
- package/dist/lib/testing/storyboard/probes.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/probes.js +16 -5
- package/dist/lib/testing/storyboard/probes.js.map +1 -1
- package/dist/lib/testing/storyboard/probes.mjs +16 -5
- package/dist/lib/testing/storyboard/probes.mjs.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +6 -2
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.mjs +6 -2
- package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
- package/dist/lib/testing/storyboard/shape-drift-hints.d.mts +3 -4
- package/dist/lib/testing/storyboard/shape-drift-hints.d.ts +3 -4
- package/dist/lib/testing/storyboard/shape-drift-hints.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/shape-drift-hints.js +27 -27
- package/dist/lib/testing/storyboard/shape-drift-hints.js.map +1 -1
- package/dist/lib/testing/storyboard/shape-drift-hints.mjs +27 -27
- package/dist/lib/testing/storyboard/shape-drift-hints.mjs.map +1 -1
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/task-map.js +43 -5
- package/dist/lib/testing/storyboard/task-map.js.map +1 -1
- package/dist/lib/testing/storyboard/task-map.mjs +43 -5
- package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
- package/dist/lib/testing/test-helpers.d.mts +2 -2
- package/dist/lib/testing/test-helpers.d.ts +2 -2
- package/dist/lib/testing/test-helpers.js.map +1 -1
- package/dist/lib/testing/test-helpers.mjs.map +1 -1
- package/dist/lib/testing/types.d.mts +7 -1
- package/dist/lib/testing/types.d.ts +7 -1
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/testing/types.js.map +1 -1
- package/dist/lib/types/adcp.d.mts +14 -14
- package/dist/lib/types/adcp.d.ts +14 -14
- package/dist/lib/types/adcp.d.ts.map +1 -1
- package/dist/lib/types/adcp.js.map +1 -1
- package/dist/lib/types/adcp.mjs.map +1 -1
- package/dist/lib/types/index.d.mts +2 -2
- package/dist/lib/types/index.d.ts +2 -2
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/types/index.mjs.map +1 -1
- package/dist/lib/utils/capabilities.d.mts +6 -0
- package/dist/lib/utils/capabilities.d.ts +6 -0
- package/dist/lib/utils/capabilities.d.ts.map +1 -1
- package/dist/lib/utils/capabilities.js +4 -0
- package/dist/lib/utils/capabilities.js.map +1 -1
- package/dist/lib/utils/capabilities.mjs +4 -0
- package/dist/lib/utils/capabilities.mjs.map +1 -1
- package/dist/lib/utils/creative-delivery.d.mts +52 -10
- package/dist/lib/utils/creative-delivery.d.ts +52 -10
- package/dist/lib/utils/creative-delivery.d.ts.map +1 -1
- package/dist/lib/utils/creative-delivery.js +104 -9
- package/dist/lib/utils/creative-delivery.js.map +1 -1
- package/dist/lib/utils/creative-delivery.mjs +104 -8
- package/dist/lib/utils/creative-delivery.mjs.map +1 -1
- package/dist/lib/utils/format-assets.d.mts +41 -38
- package/dist/lib/utils/format-assets.d.ts +41 -38
- package/dist/lib/utils/format-assets.d.ts.map +1 -1
- package/dist/lib/utils/format-assets.js +3 -1
- package/dist/lib/utils/format-assets.js.map +1 -1
- package/dist/lib/utils/format-assets.mjs +3 -1
- package/dist/lib/utils/format-assets.mjs.map +1 -1
- package/dist/lib/utils/index.d.mts +8 -8
- package/dist/lib/utils/index.d.ts +8 -8
- package/dist/lib/utils/index.d.ts.map +1 -1
- package/dist/lib/utils/index.js +11 -9
- package/dist/lib/utils/index.js.map +1 -1
- package/dist/lib/utils/index.mjs +9 -8
- package/dist/lib/utils/index.mjs.map +1 -1
- package/dist/lib/utils/preview-utils.d.mts +11 -8
- package/dist/lib/utils/preview-utils.d.ts +11 -8
- package/dist/lib/utils/preview-utils.d.ts.map +1 -1
- package/dist/lib/utils/preview-utils.js +4 -4
- package/dist/lib/utils/preview-utils.js.map +1 -1
- package/dist/lib/utils/preview-utils.mjs +3 -3
- package/dist/lib/utils/preview-utils.mjs.map +1 -1
- package/dist/lib/utils/tool-request-schemas.d.mts +2 -2
- package/dist/lib/utils/tool-request-schemas.d.ts +2 -2
- package/dist/lib/v2/projection/aao-reference-formats.json +492 -0
- package/dist/lib/v2/projection/augment-response.d.mts +31 -11
- package/dist/lib/v2/projection/augment-response.d.ts +31 -11
- package/dist/lib/v2/projection/augment-response.d.ts.map +1 -1
- package/dist/lib/v2/projection/augment-response.js +233 -27
- package/dist/lib/v2/projection/augment-response.js.map +1 -1
- package/dist/lib/v2/projection/augment-response.mjs +232 -27
- package/dist/lib/v2/projection/augment-response.mjs.map +1 -1
- package/dist/lib/v2/projection/builders.d.mts +7 -6
- package/dist/lib/v2/projection/builders.d.ts +7 -6
- package/dist/lib/v2/projection/builders.d.ts.map +1 -1
- package/dist/lib/v2/projection/builders.js +11 -8
- package/dist/lib/v2/projection/builders.js.map +1 -1
- package/dist/lib/v2/projection/builders.mjs +9 -6
- package/dist/lib/v2/projection/builders.mjs.map +1 -1
- package/dist/lib/v2/projection/catalog-snapshot.d.mts +47 -0
- package/dist/lib/v2/projection/catalog-snapshot.d.ts +48 -0
- package/dist/lib/v2/projection/catalog-snapshot.d.ts.map +1 -0
- package/dist/lib/v2/projection/catalog-snapshot.js +291 -0
- package/dist/lib/v2/projection/catalog-snapshot.js.map +1 -0
- package/dist/lib/v2/projection/catalog-snapshot.mjs +265 -0
- package/dist/lib/v2/projection/catalog-snapshot.mjs.map +1 -0
- package/dist/lib/v2/projection/catalog.d.mts +23 -2
- package/dist/lib/v2/projection/catalog.d.ts +23 -2
- package/dist/lib/v2/projection/catalog.d.ts.map +1 -1
- package/dist/lib/v2/projection/catalog.js +34 -10
- package/dist/lib/v2/projection/catalog.js.map +1 -1
- package/dist/lib/v2/projection/catalog.mjs +33 -10
- package/dist/lib/v2/projection/catalog.mjs.map +1 -1
- package/dist/lib/v2/projection/creative-delivery.d.mts +157 -0
- package/dist/lib/v2/projection/creative-delivery.d.ts +158 -0
- package/dist/lib/v2/projection/creative-delivery.d.ts.map +1 -0
- package/dist/lib/v2/projection/creative-delivery.js +967 -0
- package/dist/lib/v2/projection/creative-delivery.js.map +1 -0
- package/dist/lib/v2/projection/creative-delivery.mjs +941 -0
- package/dist/lib/v2/projection/creative-delivery.mjs.map +1 -0
- package/dist/lib/v2/projection/index.d.mts +8 -6
- package/dist/lib/v2/projection/index.d.ts +8 -6
- package/dist/lib/v2/projection/index.d.ts.map +1 -1
- package/dist/lib/v2/projection/index.js +26 -4
- package/dist/lib/v2/projection/index.js.map +1 -1
- package/dist/lib/v2/projection/index.mjs +28 -4
- package/dist/lib/v2/projection/index.mjs.map +1 -1
- package/dist/lib/v2/projection/legacy-metadata.d.mts +21 -0
- package/dist/lib/v2/projection/legacy-metadata.d.ts +22 -0
- package/dist/lib/v2/projection/legacy-metadata.d.ts.map +1 -0
- package/dist/lib/v2/projection/legacy-metadata.js +73 -0
- package/dist/lib/v2/projection/legacy-metadata.js.map +1 -0
- package/dist/lib/v2/projection/legacy-metadata.mjs +45 -0
- package/dist/lib/v2/projection/legacy-metadata.mjs.map +1 -0
- package/dist/lib/v2/projection/types.d.mts +29 -23
- package/dist/lib/v2/projection/types.d.ts +29 -23
- package/dist/lib/v2/projection/types.d.ts.map +1 -1
- package/dist/lib/v2/projection/types.js.map +1 -1
- package/dist/lib/v2/projection/v1-to-v2.d.mts +29 -6
- package/dist/lib/v2/projection/v1-to-v2.d.ts +29 -6
- package/dist/lib/v2/projection/v1-to-v2.d.ts.map +1 -1
- package/dist/lib/v2/projection/v1-to-v2.js +218 -9
- package/dist/lib/v2/projection/v1-to-v2.js.map +1 -1
- package/dist/lib/v2/projection/v1-to-v2.mjs +219 -10
- package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
- package/dist/lib/v2/projection/v2-to-v1.d.mts +31 -2
- package/dist/lib/v2/projection/v2-to-v1.d.ts +31 -2
- package/dist/lib/v2/projection/v2-to-v1.d.ts.map +1 -1
- package/dist/lib/v2/projection/v2-to-v1.js +138 -7
- package/dist/lib/v2/projection/v2-to-v1.js.map +1 -1
- package/dist/lib/v2/projection/v2-to-v1.mjs +135 -6
- package/dist/lib/v2/projection/v2-to-v1.mjs.map +1 -1
- package/dist/lib/v2/projection/write-side.d.mts +12 -13
- package/dist/lib/v2/projection/write-side.d.ts +12 -13
- package/dist/lib/v2/projection/write-side.d.ts.map +1 -1
- package/dist/lib/v2/projection/write-side.js +16 -12
- package/dist/lib/v2/projection/write-side.js.map +1 -1
- package/dist/lib/v2/projection/write-side.mjs +16 -12
- package/dist/lib/v2/projection/write-side.mjs.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/version.mjs.map +1 -1
- package/docs/guides/BUILD-AN-AGENT.md +7 -2
- package/docs/guides/PREVIEW-ASSET-DURABILITY.md +6 -2
- package/docs/llms.txt +1 -0
- package/examples/README.md +1 -1
- package/examples/batch-preview-test.ts +3 -3
- package/examples/conversation-client.ts +2 -2
- package/examples/debug-preview-response.ts +1 -1
- package/examples/decisioning-platform-broadcast-tv.ts +10 -4
- package/examples/decisioning-platform-mock-seller.ts +16 -9
- package/examples/decisioning-platform-programmatic.ts +18 -7
- package/examples/error-compliant-server.ts +26 -16
- package/examples/generative-creative-demo.ts +7 -19
- package/examples/hello_creative_adapter_ad_server.ts +37 -16
- package/examples/hello_creative_adapter_template.ts +12 -10
- package/examples/hello_seller_adapter_guaranteed.ts +52 -23
- package/examples/hello_seller_adapter_multi_tenant.ts +6 -3
- package/examples/hello_seller_adapter_non_guaranteed.ts +54 -26
- package/examples/hello_seller_adapter_proposal_mode.ts +40 -14
- package/examples/hello_seller_adapter_social.ts +2 -7
- package/examples/inspect-card-formats.ts +1 -1
- package/examples/simple-getting-started.ts +1 -1
- package/examples/test-helpers-demo.ts +1 -1
- package/package.json +2 -2
- package/skills/build-decisioning-creative-template/SKILL.md +11 -11
- package/skills/build-decisioning-platform/advanced/REFERENCE.md +8 -2
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
TASK_FEATURE_MAP
|
|
58
58
|
} from "../utils/capabilities.mjs";
|
|
59
59
|
import { normalizeRequestParams } from "../utils/request-normalizer.mjs";
|
|
60
|
+
import { globalAsyncLocalStorage } from "../utils/global-async-local-storage.mjs";
|
|
60
61
|
import { validateUserAgent } from "../utils/validate-user-agent.mjs";
|
|
61
62
|
import { resolveWebhookUrl, selectWebhookTemplate } from "./webhook-url.mjs";
|
|
62
63
|
import { getV25Adapter } from "../adapters/legacy/v2-5/index.mjs";
|
|
@@ -65,6 +66,388 @@ import {
|
|
|
65
66
|
validateProductsAgainstPropertyPolicy
|
|
66
67
|
} from "../media-buy/property-policy.mjs";
|
|
67
68
|
import { resolvePropertyList } from "../server/targeting-helpers.mjs";
|
|
69
|
+
import {
|
|
70
|
+
CreativeFormatCapabilityError,
|
|
71
|
+
CreativeFormatProjectionError,
|
|
72
|
+
projectMediaBuyCreativesForDelivery,
|
|
73
|
+
projectCreativeForDelivery,
|
|
74
|
+
projectSyncCreativesForDelivery,
|
|
75
|
+
resolveCreativeFormatWireMode,
|
|
76
|
+
stripLegacyCreativeIdentity
|
|
77
|
+
} from "../v2/projection/creative-delivery.mjs";
|
|
78
|
+
import {
|
|
79
|
+
legacyFormatConverterFromCatalogSnapshots
|
|
80
|
+
} from "../v2/projection/catalog-snapshot.mjs";
|
|
81
|
+
import { toCanonicalOnlyResponse } from "../v2/projection/augment-response.mjs";
|
|
82
|
+
import { legacyFormatRefsForDeclaration } from "../v2/projection/legacy-metadata.mjs";
|
|
83
|
+
import { canonicalize as canonicalizeJson } from "../utils/jcs.mjs";
|
|
84
|
+
const CAPABILITY_DISCOVERY_CONTEXT = /* @__PURE__ */ Symbol("capabilityDiscoveryContext");
|
|
85
|
+
function creativeSchemaSupport(value, depth = 0) {
|
|
86
|
+
if (depth > 24 || value === null || typeof value !== "object") return "unknown";
|
|
87
|
+
if (Array.isArray(value)) {
|
|
88
|
+
let legacy2 = false;
|
|
89
|
+
for (const item of value) {
|
|
90
|
+
const support = creativeSchemaSupport(item, depth + 1);
|
|
91
|
+
if (support === "canonical") return support;
|
|
92
|
+
if (support === "legacy") legacy2 = true;
|
|
93
|
+
}
|
|
94
|
+
return legacy2 ? "legacy" : "unknown";
|
|
95
|
+
}
|
|
96
|
+
const object = value;
|
|
97
|
+
const properties = object.properties;
|
|
98
|
+
if (properties !== null && typeof properties === "object" && !Array.isArray(properties)) {
|
|
99
|
+
const keys = properties;
|
|
100
|
+
if ("creative_id" in keys && "format_kind" in keys) return "canonical";
|
|
101
|
+
if ("creative_id" in keys && "format_id" in keys) return "legacy";
|
|
102
|
+
}
|
|
103
|
+
let legacy = false;
|
|
104
|
+
for (const child of Object.values(object)) {
|
|
105
|
+
const support = creativeSchemaSupport(child, depth + 1);
|
|
106
|
+
if (support === "canonical") return support;
|
|
107
|
+
if (support === "legacy") legacy = true;
|
|
108
|
+
}
|
|
109
|
+
return legacy ? "legacy" : "unknown";
|
|
110
|
+
}
|
|
111
|
+
function hasMediaBuyCreativeFormatData(request) {
|
|
112
|
+
if (request === null || typeof request !== "object" || Array.isArray(request)) return false;
|
|
113
|
+
const record = request;
|
|
114
|
+
return ["packages", "new_packages"].some((key) => {
|
|
115
|
+
const packages = record[key];
|
|
116
|
+
return Array.isArray(packages) && packages.some((pkg) => {
|
|
117
|
+
if (pkg === null || typeof pkg !== "object" || Array.isArray(pkg)) return false;
|
|
118
|
+
const packageRecord = pkg;
|
|
119
|
+
return Array.isArray(packageRecord.creatives) || Array.isArray(packageRecord.format_option_refs) || Array.isArray(packageRecord.format_ids) || typeof packageRecord.format_kind === "string" || Object.getOwnPropertySymbols(packageRecord).length > 0;
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const CANONICAL_CREATIVE_ACTIVITY_TASKS = /* @__PURE__ */ new Set([
|
|
124
|
+
"get_products",
|
|
125
|
+
"create_media_buy",
|
|
126
|
+
"update_media_buy",
|
|
127
|
+
"sync_creatives",
|
|
128
|
+
"list_creatives",
|
|
129
|
+
"get_media_buys",
|
|
130
|
+
"get_media_buy_delivery",
|
|
131
|
+
"get_creative_delivery"
|
|
132
|
+
]);
|
|
133
|
+
const TASK_SCOPED_STATE_LIMIT = 1e4;
|
|
134
|
+
const CANONICAL_PACKAGE_ROUTE_TASKS = /* @__PURE__ */ new Set(["create_media_buy", "update_media_buy", "get_media_buys"]);
|
|
135
|
+
const canonicalCreativeRoutingSnapshots = /* @__PURE__ */ new WeakSet();
|
|
136
|
+
function canonicalAccountRoutingSnapshot(value) {
|
|
137
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
138
|
+
const account = value;
|
|
139
|
+
if (typeof account.account_id === "string") return Object.freeze({ account_id: account.account_id });
|
|
140
|
+
if (!account.brand || typeof account.brand !== "object" || Array.isArray(account.brand) || typeof account.operator !== "string") {
|
|
141
|
+
return void 0;
|
|
142
|
+
}
|
|
143
|
+
const sourceBrand = account.brand;
|
|
144
|
+
if (typeof sourceBrand.domain !== "string") return void 0;
|
|
145
|
+
const brand = Object.freeze({
|
|
146
|
+
domain: sourceBrand.domain,
|
|
147
|
+
...typeof sourceBrand.brand_id === "string" ? { brand_id: sourceBrand.brand_id } : {}
|
|
148
|
+
});
|
|
149
|
+
return Object.freeze({
|
|
150
|
+
brand,
|
|
151
|
+
operator: account.operator,
|
|
152
|
+
...typeof account.sandbox === "boolean" ? { sandbox: account.sandbox } : {}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function canonicalOptionRefRoutingSnapshot(value) {
|
|
156
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
157
|
+
const ref = value;
|
|
158
|
+
if (typeof ref.format_option_id !== "string") return void 0;
|
|
159
|
+
if (ref.scope === "publisher" || typeof ref.publisher_domain === "string") {
|
|
160
|
+
if (typeof ref.publisher_domain !== "string") return void 0;
|
|
161
|
+
return Object.freeze({
|
|
162
|
+
scope: "publisher",
|
|
163
|
+
publisher_domain: ref.publisher_domain,
|
|
164
|
+
format_option_id: ref.format_option_id
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return Object.freeze({ scope: "product", format_option_id: ref.format_option_id });
|
|
168
|
+
}
|
|
169
|
+
function canonicalPackageRouteSelectorSnapshot(value) {
|
|
170
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
171
|
+
const selector = value;
|
|
172
|
+
const formatOptionRefs = Array.isArray(selector.format_option_refs) ? selector.format_option_refs.map(canonicalOptionRefRoutingSnapshot).filter((ref) => ref !== void 0) : [];
|
|
173
|
+
const snapshot = {
|
|
174
|
+
...typeof selector.package_id === "string" ? { package_id: selector.package_id } : {},
|
|
175
|
+
...typeof selector.product_id === "string" ? { product_id: selector.product_id } : {},
|
|
176
|
+
...formatOptionRefs.length > 0 ? { format_option_refs: Object.freeze(formatOptionRefs) } : {}
|
|
177
|
+
};
|
|
178
|
+
return Object.keys(snapshot).length > 0 ? Object.freeze(snapshot) : void 0;
|
|
179
|
+
}
|
|
180
|
+
function canonicalCreativeRoutingSnapshot(taskType, request) {
|
|
181
|
+
if (!CANONICAL_PACKAGE_ROUTE_TASKS.has(taskType) || !request || typeof request !== "object" || Array.isArray(request)) {
|
|
182
|
+
return void 0;
|
|
183
|
+
}
|
|
184
|
+
if (canonicalCreativeRoutingSnapshots.has(request)) {
|
|
185
|
+
return request;
|
|
186
|
+
}
|
|
187
|
+
const record = request;
|
|
188
|
+
const account = canonicalAccountRoutingSnapshot(record.account);
|
|
189
|
+
if (!account) return void 0;
|
|
190
|
+
const packageSnapshots = (key) => Object.freeze(
|
|
191
|
+
(Array.isArray(record[key]) ? record[key] : []).map(canonicalPackageRouteSelectorSnapshot).filter((selector) => selector !== void 0)
|
|
192
|
+
);
|
|
193
|
+
const packages = packageSnapshots("packages");
|
|
194
|
+
const newPackages = packageSnapshots("new_packages");
|
|
195
|
+
const snapshot = Object.freeze({
|
|
196
|
+
account,
|
|
197
|
+
...packages.length > 0 ? { packages } : {},
|
|
198
|
+
...newPackages.length > 0 ? { new_packages: newPackages } : {}
|
|
199
|
+
});
|
|
200
|
+
canonicalCreativeRoutingSnapshots.add(snapshot);
|
|
201
|
+
return snapshot;
|
|
202
|
+
}
|
|
203
|
+
const canonicalCreativeExecutionStorage = globalAsyncLocalStorage("canonicalCreativeExecution");
|
|
204
|
+
function prepareCanonicalCreativePayload(value, taskType, active = /* @__PURE__ */ new WeakSet(), prepared = /* @__PURE__ */ new WeakMap()) {
|
|
205
|
+
if (value === null || typeof value !== "object") return value;
|
|
206
|
+
for (let owner = value; owner !== null; owner = Object.getPrototypeOf(owner)) {
|
|
207
|
+
const toJSON = Object.getOwnPropertyDescriptor(owner, "toJSON");
|
|
208
|
+
if (toJSON && (!("value" in toJSON) || typeof toJSON.value === "function")) {
|
|
209
|
+
throw new CreativeFormatProjectionError(
|
|
210
|
+
taskType,
|
|
211
|
+
"(response:toJSON)",
|
|
212
|
+
"custom or accessor toJSON hooks cannot cross the canonical creative boundary safely"
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (active.has(value)) {
|
|
217
|
+
throw new CreativeFormatProjectionError(
|
|
218
|
+
taskType,
|
|
219
|
+
"(response:cycle)",
|
|
220
|
+
"cyclic values cannot cross the canonical creative boundary"
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
const cached = prepared.get(value);
|
|
224
|
+
if (cached !== void 0) return cached;
|
|
225
|
+
active.add(value);
|
|
226
|
+
try {
|
|
227
|
+
const isArray = Array.isArray(value);
|
|
228
|
+
const prototype = Object.getPrototypeOf(value);
|
|
229
|
+
const plain = isArray ? prototype === Array.prototype : prototype === Object.prototype || prototype === null;
|
|
230
|
+
const output = isArray ? [] : Object.create(prototype === null ? null : Object.prototype);
|
|
231
|
+
prepared.set(value, output);
|
|
232
|
+
let changed = !plain;
|
|
233
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
234
|
+
if (isArray && key === "length") continue;
|
|
235
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
236
|
+
if (!descriptor) continue;
|
|
237
|
+
if (!("value" in descriptor)) {
|
|
238
|
+
throw new CreativeFormatProjectionError(
|
|
239
|
+
taskType,
|
|
240
|
+
`(response:${String(key)})`,
|
|
241
|
+
"accessors cannot cross the canonical creative boundary safely"
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
if (!descriptor.enumerable) continue;
|
|
245
|
+
const safe = prepareCanonicalCreativePayload(descriptor.value, taskType, active, prepared);
|
|
246
|
+
if (safe !== descriptor.value) changed = true;
|
|
247
|
+
Object.defineProperty(output, key, { ...descriptor, value: safe });
|
|
248
|
+
}
|
|
249
|
+
if (!changed) {
|
|
250
|
+
prepared.set(value, value);
|
|
251
|
+
return value;
|
|
252
|
+
}
|
|
253
|
+
return output;
|
|
254
|
+
} finally {
|
|
255
|
+
active.delete(value);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function projectPreparedCanonicalCreativeResponseValue(value, taskType, legacyFormatConverter, selectorContainer = {}) {
|
|
259
|
+
if (Array.isArray(value)) {
|
|
260
|
+
return value.map(
|
|
261
|
+
(item) => projectPreparedCanonicalCreativeResponseValue(item, taskType, legacyFormatConverter, selectorContainer)
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
if (!value || typeof value !== "object") return value;
|
|
265
|
+
let projected = value;
|
|
266
|
+
const isProduct = typeof projected.product_id === "string" && ("name" in projected || "description" in projected) && (Array.isArray(projected.format_ids) || Array.isArray(projected.format_options));
|
|
267
|
+
if (isProduct) {
|
|
268
|
+
const canonical = toCanonicalOnlyResponse(
|
|
269
|
+
{ products: [projected] },
|
|
270
|
+
{ legacyFormatConverter }
|
|
271
|
+
);
|
|
272
|
+
if (canonical.diagnostics.length > 0 || canonical.response.products.length !== 1) {
|
|
273
|
+
throw new CreativeFormatProjectionError(
|
|
274
|
+
taskType,
|
|
275
|
+
`(product:${String(projected.product_id)})`,
|
|
276
|
+
"legacy product formats in the response have no complete canonical representation"
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
projected = canonical.response.products[0];
|
|
280
|
+
} else if ((typeof projected.package_id === "string" || typeof projected.product_id === "string") && Array.isArray(projected.format_ids)) {
|
|
281
|
+
projected = projectMediaBuyCreativesForDelivery(
|
|
282
|
+
{ packages: [projected] },
|
|
283
|
+
"canonical",
|
|
284
|
+
taskType === "update_media_buy" ? "update_media_buy" : "create_media_buy",
|
|
285
|
+
legacyFormatConverter
|
|
286
|
+
).packages[0];
|
|
287
|
+
}
|
|
288
|
+
if (typeof projected.creative_id === "string" && (projected.format_id !== void 0 || typeof projected.format_kind === "string")) {
|
|
289
|
+
projected = projectCreativeForDelivery(
|
|
290
|
+
projected,
|
|
291
|
+
selectorContainer,
|
|
292
|
+
"canonical",
|
|
293
|
+
taskType,
|
|
294
|
+
legacyFormatConverter
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
const nextSelector = Array.isArray(projected.format_ids) || Array.isArray(projected.format_options) || Array.isArray(projected.format_option_refs) ? projected : selectorContainer;
|
|
298
|
+
let changed = projected !== value;
|
|
299
|
+
const next = { ...projected };
|
|
300
|
+
for (const [key, child] of Object.entries(projected)) {
|
|
301
|
+
const childProjected = projectPreparedCanonicalCreativeResponseValue(
|
|
302
|
+
child,
|
|
303
|
+
taskType,
|
|
304
|
+
legacyFormatConverter,
|
|
305
|
+
nextSelector
|
|
306
|
+
);
|
|
307
|
+
if (childProjected !== child) {
|
|
308
|
+
next[key] = childProjected;
|
|
309
|
+
changed = true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return changed ? next : projected;
|
|
313
|
+
}
|
|
314
|
+
function projectCanonicalCreativeResponseValue(value, taskType, legacyFormatConverter, selectorContainer = {}) {
|
|
315
|
+
return projectPreparedCanonicalCreativeResponseValue(
|
|
316
|
+
prepareCanonicalCreativePayload(value, taskType),
|
|
317
|
+
taskType,
|
|
318
|
+
legacyFormatConverter,
|
|
319
|
+
selectorContainer
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
function projectCanonicalCreativeAncillaryValue(value, taskType, legacyFormatConverter) {
|
|
323
|
+
try {
|
|
324
|
+
return stripLegacyCreativeIdentity(projectCanonicalCreativeResponseValue(value, taskType, legacyFormatConverter));
|
|
325
|
+
} catch (error) {
|
|
326
|
+
if (!(error instanceof CreativeFormatProjectionError)) throw error;
|
|
327
|
+
return { omitted: true, reason: "canonical creative payload unavailable" };
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function canonicalCreativeActivity(activity) {
|
|
331
|
+
const active = canonicalCreativeExecutionStorage.getStore();
|
|
332
|
+
const effectiveTaskType = active?.taskType && CANONICAL_CREATIVE_ACTIVITY_TASKS.has(active.taskType) ? active.taskType : activity.task_type;
|
|
333
|
+
if (!CANONICAL_CREATIVE_ACTIVITY_TASKS.has(effectiveTaskType) || activity.payload === void 0) {
|
|
334
|
+
return activity;
|
|
335
|
+
}
|
|
336
|
+
const converter = active?.taskType === effectiveTaskType ? active.legacyFormatConverter : void 0;
|
|
337
|
+
const source = activity.type === "protocol_request" && active?.taskType === effectiveTaskType && active.canonicalRequest !== void 0 ? { params: active.canonicalRequest } : activity.payload;
|
|
338
|
+
try {
|
|
339
|
+
return {
|
|
340
|
+
...activity,
|
|
341
|
+
payload: stripLegacyCreativeIdentity(projectCanonicalCreativeResponseValue(source, effectiveTaskType, converter))
|
|
342
|
+
};
|
|
343
|
+
} catch (error) {
|
|
344
|
+
if (!(error instanceof CreativeFormatProjectionError)) throw error;
|
|
345
|
+
return { ...activity, payload: { omitted: true, reason: "canonical creative payload unavailable" } };
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
function canonicalCreativeDiagnosticBody(body, taskType) {
|
|
349
|
+
if (body === void 0) return void 0;
|
|
350
|
+
try {
|
|
351
|
+
const active = canonicalCreativeExecutionStorage.getStore();
|
|
352
|
+
const converter = active?.taskType === taskType ? active.legacyFormatConverter : void 0;
|
|
353
|
+
return JSON.stringify(
|
|
354
|
+
stripLegacyCreativeIdentity(projectCanonicalCreativeResponseValue(JSON.parse(body), taskType, converter))
|
|
355
|
+
);
|
|
356
|
+
} catch {
|
|
357
|
+
return "[canonical creative payload omitted]";
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function canonicalCreativeTransportActivity(event) {
|
|
361
|
+
const active = canonicalCreativeExecutionStorage.getStore();
|
|
362
|
+
const taskType = active?.taskType && CANONICAL_CREATIVE_ACTIVITY_TASKS.has(active.taskType) ? active.taskType : event.taskType ?? event.tool;
|
|
363
|
+
if (!taskType || !CANONICAL_CREATIVE_ACTIVITY_TASKS.has(taskType)) return event;
|
|
364
|
+
return {
|
|
365
|
+
...event,
|
|
366
|
+
...event.requestBody !== void 0 && {
|
|
367
|
+
requestBody: canonicalCreativeDiagnosticBody(event.requestBody, taskType)
|
|
368
|
+
},
|
|
369
|
+
...event.responseBody !== void 0 && {
|
|
370
|
+
responseBody: canonicalCreativeDiagnosticBody(event.responseBody, taskType)
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function canonicalCreativeErrorInstance(error, legacySource) {
|
|
375
|
+
const own = {};
|
|
376
|
+
const descriptors = Object.getOwnPropertyDescriptors(error);
|
|
377
|
+
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
378
|
+
if ("value" in descriptor) own[key] = descriptor.value;
|
|
379
|
+
}
|
|
380
|
+
const { legacySource: _dropLegacySource, own: safeOwn } = stripLegacyCreativeIdentity({ own, legacySource });
|
|
381
|
+
void _dropLegacySource;
|
|
382
|
+
const clone = Object.create(Object.getPrototypeOf(error));
|
|
383
|
+
for (const [key, value] of Object.entries(safeOwn)) {
|
|
384
|
+
const descriptor = descriptors[key];
|
|
385
|
+
if (!descriptor || !("value" in descriptor)) continue;
|
|
386
|
+
Object.defineProperty(clone, key, { ...descriptor, value });
|
|
387
|
+
}
|
|
388
|
+
for (const symbol of Object.getOwnPropertySymbols(error)) {
|
|
389
|
+
const descriptor = Object.getOwnPropertyDescriptor(error, symbol);
|
|
390
|
+
if (!descriptor || !("value" in descriptor)) continue;
|
|
391
|
+
const safe = stripLegacyCreativeIdentity({ value: descriptor.value, legacySource });
|
|
392
|
+
Object.defineProperty(clone, symbol, { ...descriptor, value: safe.value });
|
|
393
|
+
}
|
|
394
|
+
return stripLegacyCreativeIdentity(clone);
|
|
395
|
+
}
|
|
396
|
+
const PRIMARY_ADCP_TASK_NAMES = {
|
|
397
|
+
get_products: true,
|
|
398
|
+
create_media_buy: true,
|
|
399
|
+
update_media_buy: true,
|
|
400
|
+
sync_creatives: true,
|
|
401
|
+
list_creatives: true,
|
|
402
|
+
get_media_buys: true,
|
|
403
|
+
get_media_buy_delivery: true,
|
|
404
|
+
get_creative_delivery: true,
|
|
405
|
+
provide_performance_feedback: true,
|
|
406
|
+
get_signals: true,
|
|
407
|
+
activate_signal: true,
|
|
408
|
+
get_adcp_capabilities: true,
|
|
409
|
+
list_accounts: true,
|
|
410
|
+
sync_accounts: true,
|
|
411
|
+
sync_audiences: true,
|
|
412
|
+
create_property_list: true,
|
|
413
|
+
get_property_list: true,
|
|
414
|
+
update_property_list: true,
|
|
415
|
+
list_property_lists: true,
|
|
416
|
+
delete_property_list: true,
|
|
417
|
+
si_get_offering: true,
|
|
418
|
+
si_initiate_session: true,
|
|
419
|
+
si_send_message: true,
|
|
420
|
+
si_terminate_session: true,
|
|
421
|
+
get_brand_identity: true,
|
|
422
|
+
sync_plans: true,
|
|
423
|
+
check_governance: true,
|
|
424
|
+
report_plan_outcome: true,
|
|
425
|
+
get_plan_audit_logs: true,
|
|
426
|
+
context_match: true,
|
|
427
|
+
identity_match: true
|
|
428
|
+
};
|
|
429
|
+
const STANDARD_ADCP_TASK_NAMES = /* @__PURE__ */ new Set([
|
|
430
|
+
...Object.keys(PRIMARY_ADCP_TASK_NAMES),
|
|
431
|
+
"list_creative_formats",
|
|
432
|
+
"list_transformers",
|
|
433
|
+
"preview_creative",
|
|
434
|
+
"build_creative",
|
|
435
|
+
// These standard protocol tools still carry legacy creative `format_id`
|
|
436
|
+
// identity through artifacts, manifests, standards, or rights constraints.
|
|
437
|
+
// They are available only through explicitly named *Legacy APIs until a
|
|
438
|
+
// lossless canonical projection exists.
|
|
439
|
+
"list_content_standards",
|
|
440
|
+
"get_content_standards",
|
|
441
|
+
"create_content_standards",
|
|
442
|
+
"update_content_standards",
|
|
443
|
+
"calibrate_content",
|
|
444
|
+
"validate_content_delivery",
|
|
445
|
+
"get_media_buy_artifacts",
|
|
446
|
+
"get_creative_features",
|
|
447
|
+
"get_rights",
|
|
448
|
+
"acquire_rights",
|
|
449
|
+
"update_rights"
|
|
450
|
+
]);
|
|
68
451
|
class UnsupportedFeatureError extends Error {
|
|
69
452
|
constructor(feature, serverVersion, message) {
|
|
70
453
|
super(message || `Feature '${feature}' requires AdCP v3 but server is ${serverVersion}`);
|
|
@@ -135,6 +518,14 @@ function propertyListReferenceFromRequest(params) {
|
|
|
135
518
|
...typeof ref.auth_token === "string" ? { auth_token: ref.auth_token } : {}
|
|
136
519
|
};
|
|
137
520
|
}
|
|
521
|
+
function productPolicyRequestSnapshot(requestParams) {
|
|
522
|
+
const account = canonicalAccountRoutingSnapshot(requestParams.account);
|
|
523
|
+
const propertyList = propertyListReferenceFromRequest(requestParams);
|
|
524
|
+
return Object.freeze({
|
|
525
|
+
...account ? { account } : {},
|
|
526
|
+
...propertyList ? { property_list: Object.freeze(propertyList) } : {}
|
|
527
|
+
});
|
|
528
|
+
}
|
|
138
529
|
function hasProductPropertyPolicyRules(policy) {
|
|
139
530
|
return Boolean(
|
|
140
531
|
policy.allowedDomains?.length || policy.allowedPropertyIdentifiers?.length || policy.requireAllowedPropertyMatch || policy.excludedDomains?.length || policy.excludedPropertyIds?.length || policy.strict || policy.unknownSelectorBehavior || policy.missingPublisherPropertiesBehavior
|
|
@@ -195,8 +586,8 @@ class SingleAgentClient {
|
|
|
195
586
|
...config.validation?.requests != null && { requests: config.validation.requests },
|
|
196
587
|
...config.validation?.responses != null && { responses: config.validation.responses }
|
|
197
588
|
},
|
|
198
|
-
onActivity: config.onActivity,
|
|
199
|
-
onTransportActivity: config.onTransportActivity,
|
|
589
|
+
onActivity: config.onActivity ? (activity) => config.onActivity(canonicalCreativeActivity(activity)) : void 0,
|
|
590
|
+
onTransportActivity: config.onTransportActivity ? (event) => config.onTransportActivity(canonicalCreativeTransportActivity(event)) : void 0,
|
|
200
591
|
governance: config.governance,
|
|
201
592
|
adcpVersion: this.resolvedAdcpVersion,
|
|
202
593
|
...config.wireAdcpVersion !== void 0 && { wireAdcpVersion: config.wireAdcpVersion },
|
|
@@ -231,7 +622,237 @@ class SingleAgentClient {
|
|
|
231
622
|
_syntheticV2WarningFired = false;
|
|
232
623
|
// Gate: emit the synthetic-v2 warning once per client instance
|
|
233
624
|
productPolicyRequestParamsByTask = /* @__PURE__ */ new Map();
|
|
625
|
+
canonicalCreativeTaskAssociations = /* @__PURE__ */ new Map();
|
|
626
|
+
canonicalLegacyRoutes = /* @__PURE__ */ new Map();
|
|
234
627
|
resolvedAdcpVersion;
|
|
628
|
+
resolveLegacyFormatConverter(override, projectionCatalogs = this.config.projectionCatalogs) {
|
|
629
|
+
return legacyFormatConverterFromCatalogSnapshots(projectionCatalogs, override ?? this.config.legacyFormatConverter);
|
|
630
|
+
}
|
|
631
|
+
canonicalAccountScope(account) {
|
|
632
|
+
if (account === void 0) return "none";
|
|
633
|
+
return canonicalizeJson(canonicalAccountRoutingSnapshot(account) ?? account);
|
|
634
|
+
}
|
|
635
|
+
canonicalLegacyRouteKey(account, productId, ref) {
|
|
636
|
+
return canonicalizeJson([
|
|
637
|
+
this.canonicalAccountScope(account),
|
|
638
|
+
productId,
|
|
639
|
+
ref.scope,
|
|
640
|
+
ref.scope === "publisher" ? ref.publisher_domain.toLowerCase() : "",
|
|
641
|
+
ref.format_option_id
|
|
642
|
+
]);
|
|
643
|
+
}
|
|
644
|
+
canonicalLegacyPackageRouteKey(account, packageId) {
|
|
645
|
+
return canonicalizeJson([this.canonicalAccountScope(account), "package", packageId]);
|
|
646
|
+
}
|
|
647
|
+
sameCanonicalOptionRef(left, right) {
|
|
648
|
+
return left.scope === right.scope && left.format_option_id === right.format_option_id && (left.scope !== "publisher" || right.scope === "publisher" && left.publisher_domain.toLowerCase() === right.publisher_domain.toLowerCase());
|
|
649
|
+
}
|
|
650
|
+
rememberCanonicalLegacyRoute(key, route) {
|
|
651
|
+
this.canonicalLegacyRoutes.delete(key);
|
|
652
|
+
this.canonicalLegacyRoutes.set(key, {
|
|
653
|
+
...route,
|
|
654
|
+
refs: Object.freeze(route.refs.map((ref) => Object.freeze({ ...ref })))
|
|
655
|
+
});
|
|
656
|
+
while (this.canonicalLegacyRoutes.size > TASK_SCOPED_STATE_LIMIT) {
|
|
657
|
+
const oldest = this.canonicalLegacyRoutes.keys().next().value;
|
|
658
|
+
if (oldest === void 0) break;
|
|
659
|
+
this.canonicalLegacyRoutes.delete(oldest);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
invalidateCanonicalProductRoutes(products, account) {
|
|
663
|
+
const accountScope = this.canonicalAccountScope(account);
|
|
664
|
+
const productIds = /* @__PURE__ */ new Set();
|
|
665
|
+
for (const value of products) {
|
|
666
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
667
|
+
const productId = value.product_id;
|
|
668
|
+
if (typeof productId === "string") productIds.add(productId);
|
|
669
|
+
}
|
|
670
|
+
if (productIds.size === 0) return;
|
|
671
|
+
for (const [key, route] of this.canonicalLegacyRoutes) {
|
|
672
|
+
if (route.kind === "product" && route.accountScope === accountScope && productIds.has(route.productId)) {
|
|
673
|
+
this.canonicalLegacyRoutes.delete(key);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
rememberCanonicalProductRoutes(products, account, authoritativeProducts = products) {
|
|
678
|
+
this.invalidateCanonicalProductRoutes(authoritativeProducts, account);
|
|
679
|
+
const accountScope = this.canonicalAccountScope(account);
|
|
680
|
+
for (const value of products) {
|
|
681
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
682
|
+
const product = value;
|
|
683
|
+
if (typeof product.product_id !== "string" || !Array.isArray(product.format_options)) continue;
|
|
684
|
+
for (const optionValue of product.format_options) {
|
|
685
|
+
if (!optionValue || typeof optionValue !== "object" || Array.isArray(optionValue)) continue;
|
|
686
|
+
const option = optionValue;
|
|
687
|
+
if (typeof option.format_option_id !== "string") continue;
|
|
688
|
+
const ref = typeof option.publisher_domain === "string" ? {
|
|
689
|
+
scope: "publisher",
|
|
690
|
+
publisher_domain: option.publisher_domain,
|
|
691
|
+
format_option_id: option.format_option_id
|
|
692
|
+
} : { scope: "product", format_option_id: option.format_option_id };
|
|
693
|
+
const refs = legacyFormatRefsForDeclaration(option);
|
|
694
|
+
if (refs.length === 0) continue;
|
|
695
|
+
this.rememberCanonicalLegacyRoute(this.canonicalLegacyRouteKey(account, product.product_id, ref), {
|
|
696
|
+
kind: "product",
|
|
697
|
+
accountScope,
|
|
698
|
+
productId: product.product_id,
|
|
699
|
+
optionRef: ref,
|
|
700
|
+
refs
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
routeForOption(account, productId, optionRef) {
|
|
706
|
+
const accountScope = this.canonicalAccountScope(account);
|
|
707
|
+
const exactKey = this.canonicalLegacyRouteKey(account, productId, optionRef);
|
|
708
|
+
const exact = this.canonicalLegacyRoutes.get(exactKey);
|
|
709
|
+
if (exact) {
|
|
710
|
+
this.canonicalLegacyRoutes.delete(exactKey);
|
|
711
|
+
this.canonicalLegacyRoutes.set(exactKey, exact);
|
|
712
|
+
return exact;
|
|
713
|
+
}
|
|
714
|
+
const candidates = [...this.canonicalLegacyRoutes.entries()].filter(
|
|
715
|
+
([, route]) => route.kind === "product" && route.productId === productId && this.sameCanonicalOptionRef(route.optionRef, optionRef)
|
|
716
|
+
);
|
|
717
|
+
if (candidates.length !== 1) return void 0;
|
|
718
|
+
const [key, candidate] = candidates[0];
|
|
719
|
+
if (accountScope === "none" || candidate.accountScope !== "none") return void 0;
|
|
720
|
+
this.canonicalLegacyRoutes.delete(key);
|
|
721
|
+
this.canonicalLegacyRoutes.set(key, candidate);
|
|
722
|
+
return candidate;
|
|
723
|
+
}
|
|
724
|
+
routeForPackage(account, packageId) {
|
|
725
|
+
const exactKey = this.canonicalLegacyPackageRouteKey(account, packageId);
|
|
726
|
+
const exact = this.canonicalLegacyRoutes.get(exactKey);
|
|
727
|
+
if (exact) {
|
|
728
|
+
this.canonicalLegacyRoutes.delete(exactKey);
|
|
729
|
+
this.canonicalLegacyRoutes.set(exactKey, exact);
|
|
730
|
+
return exact;
|
|
731
|
+
}
|
|
732
|
+
return void 0;
|
|
733
|
+
}
|
|
734
|
+
packageIdsFromSelector(selector) {
|
|
735
|
+
const ids = /* @__PURE__ */ new Set();
|
|
736
|
+
if (typeof selector.package_id === "string") ids.add(selector.package_id);
|
|
737
|
+
if (Array.isArray(selector.selector_containers)) {
|
|
738
|
+
for (const value of selector.selector_containers) {
|
|
739
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
740
|
+
for (const id of this.packageIdsFromSelector(value)) ids.add(id);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
return [...ids];
|
|
744
|
+
}
|
|
745
|
+
cachedCanonicalLegacyRefs(context, account) {
|
|
746
|
+
const selector = context.source === "product" ? context.declaration : context.source === "creative" ? context.selector : context.selector;
|
|
747
|
+
const productId = context.source === "product" ? context.productId : typeof selector.product_id === "string" ? selector.product_id : void 0;
|
|
748
|
+
if (!productId) {
|
|
749
|
+
const packageIds = this.packageIdsFromSelector(selector);
|
|
750
|
+
if (packageIds.length === 0) return void 0;
|
|
751
|
+
const routes = packageIds.map((packageId) => this.routeForPackage(account, packageId));
|
|
752
|
+
if (routes.some((route) => route === void 0)) return void 0;
|
|
753
|
+
const normalized = routes.map(
|
|
754
|
+
(route) => canonicalizeJson(
|
|
755
|
+
route.refs.map((ref) => ({ ...ref })).sort((left, right) => canonicalizeJson(left).localeCompare(canonicalizeJson(right)))
|
|
756
|
+
)
|
|
757
|
+
);
|
|
758
|
+
if (!normalized.every((value) => value === normalized[0])) return void 0;
|
|
759
|
+
return routes[0].refs.map((value) => ({ ...value }));
|
|
760
|
+
}
|
|
761
|
+
const rawRefs = [];
|
|
762
|
+
if (context.source === "product") rawRefs.push(context.declaration);
|
|
763
|
+
if (context.source === "creative" && context.creative.format_option_ref !== void 0) {
|
|
764
|
+
rawRefs.push(context.creative.format_option_ref);
|
|
765
|
+
} else if (Array.isArray(selector.format_option_refs)) {
|
|
766
|
+
rawRefs.push(...selector.format_option_refs);
|
|
767
|
+
}
|
|
768
|
+
const optionRefs = [];
|
|
769
|
+
for (const value of rawRefs) {
|
|
770
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
771
|
+
const record = value;
|
|
772
|
+
if (typeof record.format_option_id !== "string") continue;
|
|
773
|
+
if (record.scope === "publisher" || typeof record.publisher_domain === "string") {
|
|
774
|
+
if (typeof record.publisher_domain !== "string") continue;
|
|
775
|
+
optionRefs.push({
|
|
776
|
+
scope: "publisher",
|
|
777
|
+
publisher_domain: record.publisher_domain,
|
|
778
|
+
format_option_id: record.format_option_id
|
|
779
|
+
});
|
|
780
|
+
} else {
|
|
781
|
+
optionRefs.push({ scope: "product", format_option_id: record.format_option_id });
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (optionRefs.length === 0) return void 0;
|
|
785
|
+
const resolved = [];
|
|
786
|
+
for (const ref of optionRefs) {
|
|
787
|
+
const route = this.routeForOption(account, productId, ref);
|
|
788
|
+
if (!route) return void 0;
|
|
789
|
+
resolved.push(...route.refs.map((value) => ({ ...value })));
|
|
790
|
+
}
|
|
791
|
+
return resolved;
|
|
792
|
+
}
|
|
793
|
+
rememberCanonicalPackageRoutes(response, request) {
|
|
794
|
+
if (!response || typeof response !== "object" || Array.isArray(response)) return;
|
|
795
|
+
const requestRecord = request && typeof request === "object" && !Array.isArray(request) ? request : void 0;
|
|
796
|
+
const account = requestRecord?.account;
|
|
797
|
+
if (account === void 0) return;
|
|
798
|
+
const accountScope = this.canonicalAccountScope(account);
|
|
799
|
+
const requestPackages = ["packages", "new_packages"].flatMap(
|
|
800
|
+
(key) => Array.isArray(requestRecord?.[key]) ? requestRecord[key].filter(
|
|
801
|
+
(value) => Boolean(value && typeof value === "object" && !Array.isArray(value))
|
|
802
|
+
) : []
|
|
803
|
+
);
|
|
804
|
+
const responsePackages = [];
|
|
805
|
+
const visit = (value, depth = 0) => {
|
|
806
|
+
if (depth > 8 || !value || typeof value !== "object") return;
|
|
807
|
+
if (Array.isArray(value)) {
|
|
808
|
+
for (const item of value) visit(item, depth + 1);
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
const record = value;
|
|
812
|
+
if (typeof record.package_id === "string") responsePackages.push(record);
|
|
813
|
+
for (const key of ["packages", "affected_packages", "media_buys"]) {
|
|
814
|
+
if (record[key] !== void 0) visit(record[key], depth + 1);
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
visit(response);
|
|
818
|
+
for (const pkg of responsePackages) {
|
|
819
|
+
const packageId = pkg.package_id;
|
|
820
|
+
let selector = pkg;
|
|
821
|
+
let refs = this.cachedCanonicalLegacyRefs(
|
|
822
|
+
{ source: "selector", selector, operation: "package_route", field: packageId },
|
|
823
|
+
account
|
|
824
|
+
);
|
|
825
|
+
if (!refs) {
|
|
826
|
+
const byPackageId = requestPackages.filter((value) => value.package_id === packageId);
|
|
827
|
+
const productId = typeof pkg.product_id === "string" ? pkg.product_id : void 0;
|
|
828
|
+
const byProduct = productId ? requestPackages.filter((value) => value.product_id === productId) : [];
|
|
829
|
+
const matches = byPackageId.length === 1 ? byPackageId : byProduct.length === 1 ? byProduct : [];
|
|
830
|
+
selector = matches[0];
|
|
831
|
+
if (selector) {
|
|
832
|
+
refs = this.cachedCanonicalLegacyRefs(
|
|
833
|
+
{ source: "selector", selector, operation: "package_route", field: packageId },
|
|
834
|
+
account
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (!refs || refs.length === 0) continue;
|
|
839
|
+
this.rememberCanonicalLegacyRoute(this.canonicalLegacyPackageRouteKey(account, packageId), {
|
|
840
|
+
kind: "package",
|
|
841
|
+
accountScope,
|
|
842
|
+
packageId,
|
|
843
|
+
refs
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
rememberCanonicalPackageRoutesForTask(taskType, response, request) {
|
|
848
|
+
if (taskType === "create_media_buy" || taskType === "update_media_buy" || taskType === "get_media_buys") {
|
|
849
|
+
this.rememberCanonicalPackageRoutes(response, request);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
resolveCanonicalFormatLegacyResolver(override, account) {
|
|
853
|
+
const configured = this.config.canonicalFormatLegacyResolver;
|
|
854
|
+
return (context) => override?.(context) ?? this.cachedCanonicalLegacyRefs(context, account) ?? configured?.(context);
|
|
855
|
+
}
|
|
235
856
|
/**
|
|
236
857
|
* Returns the AdCP protocol version this client is configured to speak.
|
|
237
858
|
*
|
|
@@ -255,25 +876,52 @@ class SingleAgentClient {
|
|
|
255
876
|
async ensureEndpointDiscovered(options) {
|
|
256
877
|
throwIfAborted(options?.signal);
|
|
257
878
|
const needsDiscovery = this.normalizedAgent._needsDiscovery;
|
|
879
|
+
const transport = options?.transport ?? this.config.transport;
|
|
880
|
+
const usesScopedFetch = transport?.fetchFn !== void 0;
|
|
258
881
|
if (!needsDiscovery) {
|
|
259
882
|
return this.normalizedAgent;
|
|
260
883
|
}
|
|
261
|
-
if (this.discoveredAgent) {
|
|
884
|
+
if (!usesScopedFetch && this.discoveredAgent) {
|
|
262
885
|
return this.discoveredAgent;
|
|
263
886
|
}
|
|
264
|
-
if (this.discoveredEndpoint) {
|
|
887
|
+
if (!usesScopedFetch && this.discoveredEndpoint) {
|
|
265
888
|
this.discoveredAgent = {
|
|
266
889
|
...this.normalizedAgent,
|
|
267
890
|
agent_uri: this.discoveredEndpoint
|
|
268
891
|
};
|
|
892
|
+
if (this.normalizedAgent.oauth_tokens && !this.normalizedAgent.oauth_client_credentials) {
|
|
893
|
+
const { shareNonInteractiveOAuthProvider } = await import("../auth/oauth/provider-cache.mjs");
|
|
894
|
+
shareNonInteractiveOAuthProvider(this.normalizedAgent, this.discoveredAgent);
|
|
895
|
+
}
|
|
269
896
|
return this.discoveredAgent;
|
|
270
897
|
}
|
|
271
|
-
|
|
898
|
+
if (this.normalizedAgent.oauth_client_credentials) {
|
|
899
|
+
const { ensureClientCredentialsTokens, getAgentStorage } = await import("../auth/oauth/index.mjs");
|
|
900
|
+
await ensureClientCredentialsTokens(this.normalizedAgent, {
|
|
901
|
+
storage: getAgentStorage(this.normalizedAgent),
|
|
902
|
+
allowPrivateIp: isLikelyPrivateUrl(this.normalizedAgent.agent_uri),
|
|
903
|
+
fetch: transport?.fetchFn
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
const discoveredEndpoint = await this.discoverMCPEndpoint(this.normalizedAgent.agent_uri, options);
|
|
907
|
+
if (usesScopedFetch) {
|
|
908
|
+
const discoveredAgent = { ...this.normalizedAgent, agent_uri: discoveredEndpoint };
|
|
909
|
+
if (this.normalizedAgent.oauth_tokens && !this.normalizedAgent.oauth_client_credentials) {
|
|
910
|
+
const { shareNonInteractiveOAuthProvider } = await import("../auth/oauth/provider-cache.mjs");
|
|
911
|
+
shareNonInteractiveOAuthProvider(this.normalizedAgent, discoveredAgent);
|
|
912
|
+
}
|
|
913
|
+
return discoveredAgent;
|
|
914
|
+
}
|
|
915
|
+
this.discoveredEndpoint = discoveredEndpoint;
|
|
272
916
|
this.canonicalBaseUrl = this.computeBaseUrl(this.discoveredEndpoint);
|
|
273
917
|
this.discoveredAgent = {
|
|
274
918
|
...this.normalizedAgent,
|
|
275
919
|
agent_uri: this.discoveredEndpoint
|
|
276
920
|
};
|
|
921
|
+
if (this.normalizedAgent.oauth_tokens && !this.normalizedAgent.oauth_client_credentials) {
|
|
922
|
+
const { shareNonInteractiveOAuthProvider } = await import("../auth/oauth/provider-cache.mjs");
|
|
923
|
+
shareNonInteractiveOAuthProvider(this.normalizedAgent, this.discoveredAgent);
|
|
924
|
+
}
|
|
277
925
|
return this.discoveredAgent;
|
|
278
926
|
}
|
|
279
927
|
/**
|
|
@@ -285,17 +933,27 @@ class SingleAgentClient {
|
|
|
285
933
|
async ensureCanonicalUrlResolved(options) {
|
|
286
934
|
throwIfAborted(options?.signal);
|
|
287
935
|
const needsCanonicalUrl = this.normalizedAgent._needsCanonicalUrl;
|
|
936
|
+
const transport = options?.transport ?? this.config.transport;
|
|
937
|
+
const usesScopedFetch = transport?.fetchFn !== void 0;
|
|
288
938
|
if (!needsCanonicalUrl) {
|
|
289
939
|
return this.normalizedAgent;
|
|
290
940
|
}
|
|
291
|
-
if (this.canonicalBaseUrl) {
|
|
941
|
+
if (!usesScopedFetch && this.canonicalBaseUrl) {
|
|
292
942
|
return {
|
|
293
943
|
...this.normalizedAgent,
|
|
294
944
|
agent_uri: this.canonicalBaseUrl
|
|
295
945
|
};
|
|
296
946
|
}
|
|
947
|
+
if (this.normalizedAgent.oauth_client_credentials) {
|
|
948
|
+
const { ensureClientCredentialsTokens, getAgentStorage } = await import("../auth/oauth/index.mjs");
|
|
949
|
+
await ensureClientCredentialsTokens(this.normalizedAgent, {
|
|
950
|
+
storage: getAgentStorage(this.normalizedAgent),
|
|
951
|
+
allowPrivateIp: isLikelyPrivateUrl(this.normalizedAgent.agent_uri),
|
|
952
|
+
fetch: transport?.fetchFn
|
|
953
|
+
});
|
|
954
|
+
}
|
|
297
955
|
const canonicalUrl = await this.fetchA2ACanonicalUrl(this.normalizedAgent.agent_uri, options);
|
|
298
|
-
this.canonicalBaseUrl = canonicalUrl;
|
|
956
|
+
if (!usesScopedFetch) this.canonicalBaseUrl = canonicalUrl;
|
|
299
957
|
return {
|
|
300
958
|
...this.normalizedAgent,
|
|
301
959
|
agent_uri: canonicalUrl
|
|
@@ -313,8 +971,10 @@ class SingleAgentClient {
|
|
|
313
971
|
const transport = readOptions?.transport ?? this.config.transport;
|
|
314
972
|
const maxResponseBytes = transport?.maxResponseBytes;
|
|
315
973
|
const requestTimeoutMs = resolveRequestTimeoutMs(transport?.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS);
|
|
316
|
-
const sizeLimitedFetch = wrapFetchWithSizeLimit(
|
|
317
|
-
|
|
974
|
+
const sizeLimitedFetch = wrapFetchWithSizeLimit(
|
|
975
|
+
(input, init) => transport?.fetchFn ? transport.fetchFn(input, init) : fetch(input, init)
|
|
976
|
+
);
|
|
977
|
+
const authToken = this.normalizedAgent.oauth_client_credentials ? this.normalizedAgent.oauth_tokens?.access_token : this.normalizedAgent.auth_token;
|
|
318
978
|
let got401 = false;
|
|
319
979
|
const fetchImpl = async (url, requestInit) => {
|
|
320
980
|
const headers = {
|
|
@@ -362,13 +1022,17 @@ class SingleAgentClient {
|
|
|
362
1022
|
} catch (error) {
|
|
363
1023
|
if (is401Error(error, got401)) {
|
|
364
1024
|
const requirements = await discoverAuthorizationRequirements(agentUri, {
|
|
365
|
-
allowPrivateIp: isLikelyPrivateUrl(agentUri)
|
|
1025
|
+
allowPrivateIp: isLikelyPrivateUrl(agentUri),
|
|
1026
|
+
fetchFn: transport?.fetchFn
|
|
366
1027
|
});
|
|
367
1028
|
if (requirements) {
|
|
368
1029
|
throw new NeedsAuthorizationError(requirements);
|
|
369
1030
|
}
|
|
370
|
-
const challenge = await probeAuthChallenge(agentUri, {
|
|
371
|
-
|
|
1031
|
+
const challenge = await probeAuthChallenge(agentUri, {
|
|
1032
|
+
allowPrivateIp: isLikelyPrivateUrl(agentUri),
|
|
1033
|
+
fetchFn: transport?.fetchFn
|
|
1034
|
+
});
|
|
1035
|
+
const oauthMetadata = await discoverOAuthMetadata(agentUri, { fetch: transport?.fetchFn });
|
|
372
1036
|
throw new AuthenticationRequiredError(agentUri, oauthMetadata || void 0, void 0, challenge ?? void 0);
|
|
373
1037
|
}
|
|
374
1038
|
throw error;
|
|
@@ -409,31 +1073,47 @@ class SingleAgentClient {
|
|
|
409
1073
|
throwIfAborted(options?.signal);
|
|
410
1074
|
const { connectMCPWithFallback } = await import("../protocols/mcp.mjs");
|
|
411
1075
|
const { probeModernMCPConnection } = await import("../protocols/mcp-modern.mjs");
|
|
412
|
-
const
|
|
1076
|
+
const usesScopedFetch = (options?.transport ?? this.config.transport)?.fetchFn !== void 0;
|
|
1077
|
+
const authToken = this.normalizedAgent.oauth_client_credentials ? this.normalizedAgent.oauth_tokens?.access_token : this.agent.auth_token;
|
|
413
1078
|
const agentHeaders = this.agent.headers;
|
|
414
1079
|
const authHeaders = { ...agentHeaders, ...createMCPAuthHeaders(authToken) };
|
|
415
|
-
const
|
|
416
|
-
|
|
1080
|
+
const oauth = this.normalizedAgent.oauth_tokens && !this.normalizedAgent.oauth_client_credentials ? await import("../auth/oauth/index.mjs") : void 0;
|
|
1081
|
+
const authProvider = oauth ? (await import("../auth/oauth/provider-cache.mjs")).getNonInteractiveOAuthProvider(this.normalizedAgent, {
|
|
1082
|
+
agentHint: this.normalizedAgent.id,
|
|
1083
|
+
storage: oauth.getAgentStorage(this.normalizedAgent),
|
|
1084
|
+
allowHttp: isLikelyPrivateUrl(this.normalizedAgent.agent_uri)
|
|
417
1085
|
}) : void 0;
|
|
418
1086
|
const testEndpoint = async (url) => {
|
|
419
1087
|
try {
|
|
420
1088
|
const modern = await probeModernMCPConnection(url, authToken, agentHeaders, {
|
|
421
1089
|
authProvider,
|
|
422
1090
|
signal: options?.signal,
|
|
423
|
-
requestTimeoutMs: options?.transport?.requestTimeoutMs ?? this.config.transport?.requestTimeoutMs
|
|
1091
|
+
requestTimeoutMs: options?.transport?.requestTimeoutMs ?? this.config.transport?.requestTimeoutMs,
|
|
1092
|
+
fetchFn: options?.transport?.fetchFn ?? this.config.transport?.fetchFn
|
|
424
1093
|
});
|
|
425
1094
|
if (modern.connected) {
|
|
426
|
-
|
|
427
|
-
|
|
1095
|
+
if (!usesScopedFetch) {
|
|
1096
|
+
this.discoveredMcpEra = modern.era;
|
|
1097
|
+
this.discoveredMcpEraAt = Date.now();
|
|
1098
|
+
}
|
|
428
1099
|
return { success: true };
|
|
429
1100
|
}
|
|
430
|
-
const client = await connectMCPWithFallback(
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
1101
|
+
const client = await connectMCPWithFallback(
|
|
1102
|
+
new URL(url),
|
|
1103
|
+
authHeaders,
|
|
1104
|
+
[],
|
|
1105
|
+
"endpoint discovery",
|
|
1106
|
+
options?.transport?.fetchFn ?? this.config.transport?.fetchFn,
|
|
1107
|
+
{
|
|
1108
|
+
signal: options?.signal,
|
|
1109
|
+
requestTimeoutMs: options?.transport?.requestTimeoutMs ?? this.config.transport?.requestTimeoutMs
|
|
1110
|
+
}
|
|
1111
|
+
);
|
|
434
1112
|
await client.close();
|
|
435
|
-
|
|
436
|
-
|
|
1113
|
+
if (!usesScopedFetch) {
|
|
1114
|
+
this.discoveredMcpEra = "legacy";
|
|
1115
|
+
this.discoveredMcpEraAt = Date.now();
|
|
1116
|
+
}
|
|
437
1117
|
return { success: true };
|
|
438
1118
|
} catch (error) {
|
|
439
1119
|
if (isAbortOrTimeoutError(error)) {
|
|
@@ -475,13 +1155,19 @@ class SingleAgentClient {
|
|
|
475
1155
|
}
|
|
476
1156
|
if (got401) {
|
|
477
1157
|
const requirements = await discoverAuthorizationRequirements(providedUri, {
|
|
478
|
-
allowPrivateIp: isLikelyPrivateUrl(providedUri)
|
|
1158
|
+
allowPrivateIp: isLikelyPrivateUrl(providedUri),
|
|
1159
|
+
fetchFn: options?.transport?.fetchFn ?? this.config.transport?.fetchFn
|
|
479
1160
|
});
|
|
480
1161
|
if (requirements) {
|
|
481
1162
|
throw new NeedsAuthorizationError(requirements);
|
|
482
1163
|
}
|
|
483
|
-
const challenge = await probeAuthChallenge(providedUri, {
|
|
484
|
-
|
|
1164
|
+
const challenge = await probeAuthChallenge(providedUri, {
|
|
1165
|
+
allowPrivateIp: isLikelyPrivateUrl(providedUri),
|
|
1166
|
+
fetchFn: options?.transport?.fetchFn ?? this.config.transport?.fetchFn
|
|
1167
|
+
});
|
|
1168
|
+
const oauthMetadata = await discoverOAuthMetadata(providedUri, {
|
|
1169
|
+
fetch: options?.transport?.fetchFn ?? this.config.transport?.fetchFn
|
|
1170
|
+
});
|
|
485
1171
|
throw new AuthenticationRequiredError(providedUri, oauthMetadata || void 0, void 0, challenge ?? void 0);
|
|
486
1172
|
}
|
|
487
1173
|
throw new Error(
|
|
@@ -592,8 +1278,9 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
592
1278
|
* This is the lower-level receiver primitive for integrations that need to
|
|
593
1279
|
* map malformed webhooks to precise HTTP responses. It verifies the legacy
|
|
594
1280
|
* HMAC profile when `webhookSecret` is configured, parses raw JSON bodies,
|
|
595
|
-
* validates the transport envelope shape, and returns the
|
|
596
|
-
* result plus routing metadata.
|
|
1281
|
+
* validates the transport envelope shape, and returns the canonicalized
|
|
1282
|
+
* AdCP result plus routing metadata. Legacy wire inspection is intentionally
|
|
1283
|
+
* confined to the transport adapter and is not returned by this primary API.
|
|
597
1284
|
*/
|
|
598
1285
|
async verifyAndParseWebhook(options) {
|
|
599
1286
|
const rawBody = options.rawBody ?? rawBodyFromUnknown(options.body);
|
|
@@ -625,37 +1312,107 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
625
1312
|
if (!parsedPayload.ok) {
|
|
626
1313
|
return parsedPayload;
|
|
627
1314
|
}
|
|
1315
|
+
const parsedTaskType = isObjectRecord(parsedPayload.payload) && typeof parsedPayload.payload.task_type === "string" ? parsedPayload.payload.task_type : void 0;
|
|
1316
|
+
const payloadRecord = isObjectRecord(parsedPayload.payload) ? parsedPayload.payload : void 0;
|
|
1317
|
+
const associatedTaskTypes = new Set(
|
|
1318
|
+
[
|
|
1319
|
+
options.operationId,
|
|
1320
|
+
typeof payloadRecord?.operation_id === "string" ? payloadRecord.operation_id : void 0,
|
|
1321
|
+
typeof payloadRecord?.task_id === "string" ? payloadRecord.task_id : void 0,
|
|
1322
|
+
typeof payloadRecord?.context_id === "string" ? payloadRecord.context_id : void 0
|
|
1323
|
+
].flatMap((id) => {
|
|
1324
|
+
const taskType = this.canonicalCreativeTaskAssociation(id)?.taskType;
|
|
1325
|
+
return taskType ? [taskType] : [];
|
|
1326
|
+
})
|
|
1327
|
+
);
|
|
1328
|
+
const associatedTaskType = associatedTaskTypes.size === 1 ? [...associatedTaskTypes][0] : void 0;
|
|
1329
|
+
const routedTaskType = options.taskType === "unknown" ? void 0 : options.taskType;
|
|
1330
|
+
const declaredTaskType = routedTaskType ?? parsedTaskType;
|
|
1331
|
+
if (associatedTaskTypes.size > 1 || associatedTaskType !== void 0 && declaredTaskType !== void 0 && associatedTaskType !== declaredTaskType) {
|
|
1332
|
+
return {
|
|
1333
|
+
ok: false,
|
|
1334
|
+
code: "webhook_envelope_invalid",
|
|
1335
|
+
message: "Webhook task_type does not match the locally tracked task association."
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
let normalizedTaskType = associatedTaskType ?? declaredTaskType;
|
|
628
1339
|
try {
|
|
629
1340
|
const normalizedPayload = this.normalizeWebhookPayload(
|
|
630
1341
|
parsedPayload.payload,
|
|
631
|
-
|
|
1342
|
+
normalizedTaskType ?? "unknown",
|
|
632
1343
|
options.operationId ?? "unknown"
|
|
633
1344
|
);
|
|
1345
|
+
normalizedTaskType = normalizedPayload.task_type;
|
|
1346
|
+
if (associatedTaskType !== void 0 && normalizedPayload.task_type !== associatedTaskType) {
|
|
1347
|
+
return {
|
|
1348
|
+
ok: false,
|
|
1349
|
+
code: "webhook_envelope_invalid",
|
|
1350
|
+
message: "Webhook task_type does not match the locally tracked task association."
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
const metadata = {
|
|
1354
|
+
operation_id: normalizedPayload.operation_id,
|
|
1355
|
+
context_id: normalizedPayload.context_id,
|
|
1356
|
+
task_id: normalizedPayload.task_id,
|
|
1357
|
+
agent_id: this.agent.id,
|
|
1358
|
+
task_type: normalizedPayload.task_type,
|
|
1359
|
+
status: normalizedPayload.status,
|
|
1360
|
+
message: normalizedPayload.message,
|
|
1361
|
+
timestamp: normalizedPayload.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
1362
|
+
idempotency_key: normalizedPayload.idempotency_key,
|
|
1363
|
+
protocol: normalizedPayload.protocol ?? "mcp"
|
|
1364
|
+
};
|
|
1365
|
+
const canonicalResult = this.canonicalizeWebhookCreativeResult(metadata, normalizedPayload.result);
|
|
1366
|
+
const canonicalCreativeTask = CANONICAL_CREATIVE_ACTIVITY_TASKS.has(normalizedPayload.task_type);
|
|
1367
|
+
const legacyFormatConverter = this.legacyFormatConverterForWebhook(metadata);
|
|
1368
|
+
const canonicalEnvelope = canonicalCreativeTask ? stripLegacyCreativeIdentity(
|
|
1369
|
+
projectCanonicalCreativeResponseValue(
|
|
1370
|
+
parsedPayload.payload,
|
|
1371
|
+
normalizedPayload.task_type,
|
|
1372
|
+
legacyFormatConverter
|
|
1373
|
+
)
|
|
1374
|
+
) : parsedPayload.payload;
|
|
1375
|
+
const canonicalMessage = canonicalCreativeTask ? stripLegacyCreativeIdentity({
|
|
1376
|
+
message: normalizedPayload.message,
|
|
1377
|
+
legacySource: parsedPayload.payload
|
|
1378
|
+
}).message : normalizedPayload.message;
|
|
634
1379
|
return {
|
|
635
1380
|
ok: true,
|
|
636
1381
|
protocol: normalizedPayload.protocol ?? "mcp",
|
|
637
|
-
envelope:
|
|
638
|
-
result:
|
|
1382
|
+
envelope: canonicalEnvelope,
|
|
1383
|
+
result: canonicalResult,
|
|
639
1384
|
metadata: {
|
|
640
1385
|
operationId: normalizedPayload.operation_id,
|
|
641
1386
|
contextId: normalizedPayload.context_id,
|
|
642
1387
|
taskId: normalizedPayload.task_id,
|
|
643
1388
|
taskType: normalizedPayload.task_type,
|
|
644
1389
|
status: normalizedPayload.status,
|
|
645
|
-
message:
|
|
1390
|
+
message: canonicalMessage,
|
|
646
1391
|
timestamp: normalizedPayload.timestamp,
|
|
647
1392
|
idempotencyKey: normalizedPayload.idempotency_key
|
|
648
1393
|
}
|
|
649
1394
|
};
|
|
650
1395
|
} catch (error) {
|
|
1396
|
+
const canonicalCreativeTask = normalizedTaskType !== void 0 && CANONICAL_CREATIVE_ACTIVITY_TASKS.has(normalizedTaskType);
|
|
651
1397
|
if (error instanceof WebhookDispatchError) {
|
|
652
|
-
|
|
1398
|
+
if (!canonicalCreativeTask) {
|
|
1399
|
+
return { ok: false, code: error.code, message: error.message };
|
|
1400
|
+
}
|
|
1401
|
+
const safe = stripLegacyCreativeIdentity({
|
|
1402
|
+
message: error.message,
|
|
1403
|
+
legacySource: parsedPayload.payload
|
|
1404
|
+
});
|
|
1405
|
+
return { ok: false, code: error.code, message: safe.message };
|
|
1406
|
+
}
|
|
1407
|
+
const message = error instanceof Error ? error.message : "Webhook payload could not be normalized.";
|
|
1408
|
+
if (canonicalCreativeTask) {
|
|
1409
|
+
const safe = stripLegacyCreativeIdentity({ message, legacySource: parsedPayload.payload });
|
|
1410
|
+
return { ok: false, code: "webhook_result_invalid", message: safe.message };
|
|
653
1411
|
}
|
|
654
1412
|
return {
|
|
655
1413
|
ok: false,
|
|
656
1414
|
code: "webhook_result_invalid",
|
|
657
|
-
message:
|
|
658
|
-
cause: error
|
|
1415
|
+
message: "Webhook payload could not be normalized."
|
|
659
1416
|
};
|
|
660
1417
|
}
|
|
661
1418
|
}
|
|
@@ -671,36 +1428,88 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
671
1428
|
timestamp: parsed.metadata.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
672
1429
|
idempotency_key: parsed.metadata.idempotencyKey,
|
|
673
1430
|
protocol: parsed.protocol,
|
|
674
|
-
rawHTTPPayload: parsed.envelope
|
|
1431
|
+
rawHTTPPayload: CANONICAL_CREATIVE_ACTIVITY_TASKS.has(parsed.metadata.taskType) ? stripLegacyCreativeIdentity(parsed.envelope) : parsed.envelope
|
|
675
1432
|
};
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
metadata
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
1433
|
+
this.rememberCanonicalCreativeWebhookContext(metadata);
|
|
1434
|
+
try {
|
|
1435
|
+
const canonicalResult = this.canonicalizeWebhookCreativeResult(metadata, parsed.result);
|
|
1436
|
+
const policyDispatch = await this.applyProductPropertyPolicyToWebhookResult(
|
|
1437
|
+
canonicalResult,
|
|
1438
|
+
metadata
|
|
1439
|
+
);
|
|
1440
|
+
const webhookResult = policyDispatch.result;
|
|
1441
|
+
metadata = policyDispatch.metadata;
|
|
1442
|
+
await this.config.onActivity?.(
|
|
1443
|
+
canonicalCreativeActivity({
|
|
1444
|
+
type: "webhook_received",
|
|
1445
|
+
operation_id: metadata.operation_id,
|
|
1446
|
+
agent_id: metadata.agent_id,
|
|
1447
|
+
context_id: metadata.context_id,
|
|
1448
|
+
task_id: metadata.task_id,
|
|
1449
|
+
task_type: metadata.task_type,
|
|
1450
|
+
status: metadata.status,
|
|
1451
|
+
payload: canonicalResult,
|
|
1452
|
+
timestamp: metadata.timestamp
|
|
1453
|
+
})
|
|
1454
|
+
);
|
|
1455
|
+
if (policyDispatch.suppressHandler) return true;
|
|
1456
|
+
if (this.asyncHandler) {
|
|
1457
|
+
await this.asyncHandler.handleWebhook({ result: webhookResult, metadata });
|
|
1458
|
+
return true;
|
|
1459
|
+
}
|
|
1460
|
+
return false;
|
|
1461
|
+
} finally {
|
|
1462
|
+
this.executor.observeExternalTaskStatus(
|
|
1463
|
+
metadata.operation_id,
|
|
1464
|
+
metadata.status,
|
|
1465
|
+
metadata.rawHTTPPayload
|
|
1466
|
+
);
|
|
694
1467
|
this.forgetProductPolicyRequestParams(metadata);
|
|
695
|
-
return true;
|
|
696
1468
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
1469
|
+
}
|
|
1470
|
+
rememberCanonicalCreativeWebhookContext(metadata) {
|
|
1471
|
+
if (!metadata.context_id || !CANONICAL_CREATIVE_ACTIVITY_TASKS.has(metadata.task_type)) return;
|
|
1472
|
+
const association = this.canonicalCreativeTaskAssociation(metadata.operation_id) ?? this.canonicalCreativeTaskAssociation(metadata.task_id) ?? this.canonicalCreativeTaskAssociation(metadata.context_id);
|
|
1473
|
+
if (!association) return;
|
|
1474
|
+
this.rememberCanonicalCreativeTaskAssociation(
|
|
1475
|
+
metadata.context_id,
|
|
1476
|
+
association.taskType,
|
|
1477
|
+
association.legacyFormatConverter,
|
|
1478
|
+
association.routingSnapshot
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
canonicalizeWebhookCreativeResult(metadata, result) {
|
|
1482
|
+
if (!result || typeof result !== "object" || Array.isArray(result)) return result;
|
|
1483
|
+
const taskType = metadata.task_type;
|
|
1484
|
+
const legacyFormatConverter = this.legacyFormatConverterForWebhook(metadata);
|
|
1485
|
+
const response = result;
|
|
1486
|
+
if (taskType === "get_products" && Array.isArray(response.products)) {
|
|
1487
|
+
const { response: canonical2, diagnostics } = toCanonicalOnlyResponse(
|
|
1488
|
+
response,
|
|
1489
|
+
{ legacyFormatConverter }
|
|
1490
|
+
);
|
|
1491
|
+
const requestParams = this.productPolicyRequestParamsForWebhook(metadata);
|
|
1492
|
+
this.rememberCanonicalProductRoutes(canonical2.products, requestParams.account, response.products);
|
|
1493
|
+
const { _message: _dropLegacyMessage, ...safe } = canonical2;
|
|
1494
|
+
void _dropLegacyMessage;
|
|
1495
|
+
return stripLegacyCreativeIdentity({ ...safe, projection: { diagnostics } });
|
|
1496
|
+
}
|
|
1497
|
+
if (taskType === "list_creatives" && Array.isArray(response.creatives)) {
|
|
1498
|
+
const { _message: _dropLegacyMessage, ...safe } = response;
|
|
1499
|
+
void _dropLegacyMessage;
|
|
1500
|
+
return stripLegacyCreativeIdentity({
|
|
1501
|
+
...safe,
|
|
1502
|
+
creatives: response.creatives.map(
|
|
1503
|
+
(creative) => projectCreativeForDelivery(creative, {}, "canonical", "list_creatives", legacyFormatConverter)
|
|
1504
|
+
)
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
const canonical = CANONICAL_CREATIVE_ACTIVITY_TASKS.has(taskType) ? stripLegacyCreativeIdentity(projectCanonicalCreativeResponseValue(result, taskType, legacyFormatConverter)) : result;
|
|
1508
|
+
const association = this.canonicalCreativeTaskAssociation(metadata.operation_id) ?? this.canonicalCreativeTaskAssociation(metadata.task_id) ?? this.canonicalCreativeTaskAssociation(metadata.context_id);
|
|
1509
|
+
if (metadata.status === "completed") {
|
|
1510
|
+
this.rememberCanonicalPackageRoutesForTask(taskType, canonical, association?.routingSnapshot);
|
|
701
1511
|
}
|
|
702
|
-
|
|
703
|
-
return false;
|
|
1512
|
+
return canonical;
|
|
704
1513
|
}
|
|
705
1514
|
/**
|
|
706
1515
|
* Normalize webhook payload - handles both MCP and A2A webhook formats
|
|
@@ -739,7 +1548,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
739
1548
|
if (typeof payload.status !== "string" || !WEBHOOK_TASK_STATUSES.has(payload.status)) {
|
|
740
1549
|
throw new WebhookDispatchError(
|
|
741
1550
|
"webhook_envelope_invalid",
|
|
742
|
-
`Invalid MCP webhook envelope: unsupported top-level status
|
|
1551
|
+
`Invalid MCP webhook envelope: unsupported top-level status. Expected one of ${Array.from(WEBHOOK_TASK_STATUSES).join(", ")}.`
|
|
743
1552
|
);
|
|
744
1553
|
}
|
|
745
1554
|
if (typeof payload.timestamp !== "string" || Number.isNaN(Date.parse(payload.timestamp))) {
|
|
@@ -779,7 +1588,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
779
1588
|
} catch (error) {
|
|
780
1589
|
throw new WebhookDispatchError(
|
|
781
1590
|
"webhook_result_invalid",
|
|
782
|
-
|
|
1591
|
+
"Failed to unwrap A2A webhook payload artifacts.",
|
|
783
1592
|
error
|
|
784
1593
|
);
|
|
785
1594
|
}
|
|
@@ -811,7 +1620,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
811
1620
|
}
|
|
812
1621
|
throw new WebhookDispatchError(
|
|
813
1622
|
"webhook_unsupported_payload",
|
|
814
|
-
|
|
1623
|
+
"Unsupported webhook payload format. Expected an MCP webhook envelope with top-level idempotency_key, operation_id, task_id, task_type, status, timestamp, and result, or an A2A Task/TaskStatusUpdateEvent with AdCP data nested in status.message.parts[].data or task artifacts."
|
|
815
1624
|
);
|
|
816
1625
|
}
|
|
817
1626
|
/**
|
|
@@ -952,7 +1761,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
952
1761
|
*
|
|
953
1762
|
* Automatically adapts requests for v2 servers and normalizes responses.
|
|
954
1763
|
*/
|
|
955
|
-
async executeAndHandle(taskType, handlerName, params, inputHandler, options) {
|
|
1764
|
+
async executeAndHandle(taskType, handlerName, params, inputHandler, options, transformCompletedResponse, legacyFormatConverter, canonicalRequest) {
|
|
956
1765
|
throwIfAborted(options?.signal);
|
|
957
1766
|
let normalizedParams = normalizeRequestParams(taskType, params, {
|
|
958
1767
|
skipIdempotencyAutoInject: options?.skipIdempotencyAutoInject,
|
|
@@ -981,26 +1790,36 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
981
1790
|
if (!options?.skipIdempotencyAutoInject && !options?.skipAccountValidation) {
|
|
982
1791
|
this.executor.validateRequest(taskType, normalizedParams);
|
|
983
1792
|
}
|
|
984
|
-
const
|
|
1793
|
+
const capabilityDiscoveryContext = {};
|
|
1794
|
+
const detectionOptions = {
|
|
1795
|
+
...options,
|
|
1796
|
+
[CAPABILITY_DISCOVERY_CONTEXT]: capabilityDiscoveryContext
|
|
1797
|
+
};
|
|
1798
|
+
const serverVersion = await this.detectServerVersion(detectionOptions);
|
|
985
1799
|
const inputSchemaStripLogs = [];
|
|
986
1800
|
const { params: adaptedParams, driftLogs: adaptDriftLogs } = this.adaptRequest(
|
|
987
1801
|
taskType,
|
|
988
1802
|
normalizedParams,
|
|
989
1803
|
serverVersion,
|
|
990
|
-
inputSchemaStripLogs
|
|
1804
|
+
inputSchemaStripLogs,
|
|
1805
|
+
capabilityDiscoveryContext.toolSchemas
|
|
991
1806
|
);
|
|
992
1807
|
const v25DriftLogs = [...adaptDriftLogs];
|
|
993
1808
|
if (webhookDriftLog) v25DriftLogs.push(webhookDriftLog);
|
|
994
1809
|
if (serverVersion === "v2") {
|
|
995
1810
|
this.executor.validateAdaptedRequestAgainstV2(taskType, adaptedParams, v25DriftLogs);
|
|
996
1811
|
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
taskType,
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1812
|
+
const canonicalInputHandler = this.canonicalCreativeInputHandler(taskType, inputHandler);
|
|
1813
|
+
let result = await canonicalCreativeExecutionStorage.run(
|
|
1814
|
+
{ taskType, legacyFormatConverter, canonicalRequest: canonicalRequest ?? normalizedParams },
|
|
1815
|
+
() => this.executor.executeTask(
|
|
1816
|
+
agent,
|
|
1817
|
+
taskType,
|
|
1818
|
+
adaptedParams,
|
|
1819
|
+
canonicalInputHandler,
|
|
1820
|
+
effectiveOptions,
|
|
1821
|
+
serverVersion
|
|
1822
|
+
)
|
|
1004
1823
|
);
|
|
1005
1824
|
const postAdapterLogs = [...inputSchemaStripLogs, ...v25DriftLogs];
|
|
1006
1825
|
if (postAdapterLogs.length > 0) {
|
|
@@ -1009,9 +1828,26 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1009
1828
|
if (result.success && result.data) {
|
|
1010
1829
|
result.data = this.normalizeResponseToV3(taskType, result.data);
|
|
1011
1830
|
}
|
|
1012
|
-
result = this.wrapProductPolicySubmittedContinuation(result, taskType, normalizedParams);
|
|
1013
|
-
|
|
1831
|
+
result = this.wrapProductPolicySubmittedContinuation(result, taskType, normalizedParams, options);
|
|
1832
|
+
if (result.status === "working") {
|
|
1833
|
+
this.rememberProductPolicyRequestParams(taskType, normalizedParams, result, options);
|
|
1834
|
+
}
|
|
1835
|
+
this.rememberLegacyFormatConverter(taskType, legacyFormatConverter, result, options);
|
|
1014
1836
|
result = await this.applyProductPropertyPolicy(result, taskType, normalizedParams);
|
|
1837
|
+
if (CANONICAL_CREATIVE_ACTIVITY_TASKS.has(taskType)) {
|
|
1838
|
+
const routingSnapshot = canonicalCreativeRoutingSnapshot(taskType, canonicalRequest ?? normalizedParams);
|
|
1839
|
+
result = this.canonicalizeCreativeTaskResult(result, taskType, transformCompletedResponse, legacyFormatConverter);
|
|
1840
|
+
result = this.wrapCanonicalCreativeContinuations(
|
|
1841
|
+
result,
|
|
1842
|
+
taskType,
|
|
1843
|
+
transformCompletedResponse,
|
|
1844
|
+
legacyFormatConverter,
|
|
1845
|
+
routingSnapshot
|
|
1846
|
+
);
|
|
1847
|
+
this.rememberCanonicalCreativeTaskIds(result, taskType, legacyFormatConverter, routingSnapshot);
|
|
1848
|
+
} else if (result.status === "completed" && result.success && result.data && transformCompletedResponse) {
|
|
1849
|
+
result = { ...result, data: transformCompletedResponse(result.data) };
|
|
1850
|
+
}
|
|
1015
1851
|
if (result.status === "completed" && result.success && this.asyncHandler) {
|
|
1016
1852
|
const handler = this.config.handlers?.[handlerName];
|
|
1017
1853
|
if (handler) {
|
|
@@ -1021,6 +1857,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1021
1857
|
task_id: result.metadata.taskId,
|
|
1022
1858
|
agent_id: this.agent.id,
|
|
1023
1859
|
task_type: taskType,
|
|
1860
|
+
status: result.status,
|
|
1024
1861
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1025
1862
|
};
|
|
1026
1863
|
await handler(result.data, metadata);
|
|
@@ -1028,6 +1865,255 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1028
1865
|
}
|
|
1029
1866
|
return result;
|
|
1030
1867
|
}
|
|
1868
|
+
canonicalCreativeInputHandler(taskType, inputHandler) {
|
|
1869
|
+
if (!inputHandler || !CANONICAL_CREATIVE_ACTIVITY_TASKS.has(taskType)) return inputHandler;
|
|
1870
|
+
return async (context) => {
|
|
1871
|
+
const active = canonicalCreativeExecutionStorage.getStore();
|
|
1872
|
+
const converter = this.resolveLegacyFormatConverter(
|
|
1873
|
+
active?.taskType === taskType ? active.legacyFormatConverter : void 0
|
|
1874
|
+
);
|
|
1875
|
+
const project = (value) => projectCanonicalCreativeAncillaryValue(value, taskType, converter);
|
|
1876
|
+
const messages = context.messages.map((message) => ({
|
|
1877
|
+
...message,
|
|
1878
|
+
content: project(message.content)
|
|
1879
|
+
}));
|
|
1880
|
+
const safeContext = {
|
|
1881
|
+
...context,
|
|
1882
|
+
messages,
|
|
1883
|
+
inputRequest: project(context.inputRequest),
|
|
1884
|
+
getSummary: () => messages.map((message) => `${message.role}: ${JSON.stringify(message.content)}`).join("\n"),
|
|
1885
|
+
getPreviousResponse: (field) => project(context.getPreviousResponse(field))
|
|
1886
|
+
};
|
|
1887
|
+
return inputHandler(safeContext);
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
projectCanonicalCreativeData(taskType, data, transform, legacyFormatConverter) {
|
|
1891
|
+
let projected = this.normalizeResponseToV3(taskType, data);
|
|
1892
|
+
const record = projected && typeof projected === "object" ? projected : void 0;
|
|
1893
|
+
const canProjectRead = taskType === "get_products" ? Array.isArray(record?.products) : taskType === "list_creatives" ? Array.isArray(record?.creatives) : true;
|
|
1894
|
+
if (transform && canProjectRead) {
|
|
1895
|
+
projected = transform(projected);
|
|
1896
|
+
} else if (canProjectRead && taskType === "get_products" && record) {
|
|
1897
|
+
const active = canonicalCreativeExecutionStorage.getStore();
|
|
1898
|
+
const { response, diagnostics } = toCanonicalOnlyResponse(record, {
|
|
1899
|
+
legacyFormatConverter: this.resolveLegacyFormatConverter(
|
|
1900
|
+
legacyFormatConverter ?? (active?.taskType === taskType ? active.legacyFormatConverter : void 0)
|
|
1901
|
+
),
|
|
1902
|
+
projectionCatalogs: this.config.projectionCatalogs
|
|
1903
|
+
});
|
|
1904
|
+
const { _message: _dropLegacyMessage, ...canonical } = response;
|
|
1905
|
+
void _dropLegacyMessage;
|
|
1906
|
+
projected = { ...canonical, projection: { diagnostics } };
|
|
1907
|
+
} else if (canProjectRead && taskType === "list_creatives" && record) {
|
|
1908
|
+
const active = canonicalCreativeExecutionStorage.getStore();
|
|
1909
|
+
const activeLegacyFormatConverter = this.resolveLegacyFormatConverter(
|
|
1910
|
+
legacyFormatConverter ?? (active?.taskType === taskType ? active.legacyFormatConverter : void 0)
|
|
1911
|
+
);
|
|
1912
|
+
const { _message: _dropLegacyMessage, ...safe } = record;
|
|
1913
|
+
void _dropLegacyMessage;
|
|
1914
|
+
projected = {
|
|
1915
|
+
...safe,
|
|
1916
|
+
creatives: record.creatives.map(
|
|
1917
|
+
(creative) => projectCreativeForDelivery(
|
|
1918
|
+
creative,
|
|
1919
|
+
{},
|
|
1920
|
+
"canonical",
|
|
1921
|
+
"list_creatives",
|
|
1922
|
+
activeLegacyFormatConverter
|
|
1923
|
+
)
|
|
1924
|
+
)
|
|
1925
|
+
};
|
|
1926
|
+
} else if (canProjectRead && CANONICAL_CREATIVE_ACTIVITY_TASKS.has(taskType)) {
|
|
1927
|
+
const active = canonicalCreativeExecutionStorage.getStore();
|
|
1928
|
+
projected = projectCanonicalCreativeResponseValue(
|
|
1929
|
+
projected,
|
|
1930
|
+
taskType,
|
|
1931
|
+
this.resolveLegacyFormatConverter(
|
|
1932
|
+
legacyFormatConverter ?? (active?.taskType === taskType ? active.legacyFormatConverter : void 0)
|
|
1933
|
+
)
|
|
1934
|
+
);
|
|
1935
|
+
}
|
|
1936
|
+
return stripLegacyCreativeIdentity(projected);
|
|
1937
|
+
}
|
|
1938
|
+
canonicalizeCreativeTaskResult(result, taskType, transform, legacyFormatConverter) {
|
|
1939
|
+
const projectedData = result.data !== void 0 ? this.projectCanonicalCreativeData(taskType, result.data, transform, legacyFormatConverter) : void 0;
|
|
1940
|
+
const errorInstance = result.errorInstance;
|
|
1941
|
+
const converter = this.resolveLegacyFormatConverter(legacyFormatConverter);
|
|
1942
|
+
const metadataRecord = result.metadata;
|
|
1943
|
+
const semanticMetadata = {
|
|
1944
|
+
...metadataRecord,
|
|
1945
|
+
...metadataRecord.inputRequest !== void 0 && {
|
|
1946
|
+
inputRequest: projectCanonicalCreativeAncillaryValue(metadataRecord.inputRequest, taskType, converter)
|
|
1947
|
+
}
|
|
1948
|
+
};
|
|
1949
|
+
const semanticConversation = result.conversation?.map((message) => ({
|
|
1950
|
+
...message,
|
|
1951
|
+
content: projectCanonicalCreativeAncillaryValue(message.content, taskType, converter)
|
|
1952
|
+
}));
|
|
1953
|
+
const safe = stripLegacyCreativeIdentity({
|
|
1954
|
+
data: projectedData,
|
|
1955
|
+
metadata: semanticMetadata,
|
|
1956
|
+
conversation: semanticConversation,
|
|
1957
|
+
debug_logs: result.debug_logs,
|
|
1958
|
+
adcpError: result.adcpError,
|
|
1959
|
+
error: result.error,
|
|
1960
|
+
governance: result.governance,
|
|
1961
|
+
governanceOutcome: result.governanceOutcome,
|
|
1962
|
+
governanceOutcomeError: result.governanceOutcomeError,
|
|
1963
|
+
deferredQuestion: result.deferred?.question,
|
|
1964
|
+
// Token source only: discarded below, but lets the sanitizer remove exact
|
|
1965
|
+
// legacy IDs/URLs when the seller repeats them in messages or diagnostics.
|
|
1966
|
+
legacySource: result.data
|
|
1967
|
+
});
|
|
1968
|
+
const safeErrorInstance = errorInstance ? canonicalCreativeErrorInstance(errorInstance, result.data) : void 0;
|
|
1969
|
+
const safeDeferred = result.deferred ? { ...result.deferred, ...result.deferred.question !== void 0 && { question: safe.deferredQuestion } } : void 0;
|
|
1970
|
+
return attachMatch({
|
|
1971
|
+
...result,
|
|
1972
|
+
...result.data !== void 0 && { data: safe.data },
|
|
1973
|
+
metadata: safe.metadata,
|
|
1974
|
+
...result.conversation !== void 0 && { conversation: safe.conversation },
|
|
1975
|
+
...result.debug_logs !== void 0 && { debug_logs: safe.debug_logs },
|
|
1976
|
+
...result.adcpError !== void 0 && { adcpError: safe.adcpError },
|
|
1977
|
+
...result.error !== void 0 && { error: safe.error },
|
|
1978
|
+
...result.governance !== void 0 && { governance: safe.governance },
|
|
1979
|
+
...result.governanceOutcome !== void 0 && { governanceOutcome: safe.governanceOutcome },
|
|
1980
|
+
...result.governanceOutcomeError !== void 0 && { governanceOutcomeError: safe.governanceOutcomeError },
|
|
1981
|
+
...safeDeferred !== void 0 && { deferred: safeDeferred },
|
|
1982
|
+
...safeErrorInstance !== void 0 && { errorInstance: safeErrorInstance }
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
canonicalizeCreativeTaskInfo(taskInfo, taskType, transform, legacyFormatConverter) {
|
|
1986
|
+
const source = taskInfo.result;
|
|
1987
|
+
const projected = source !== void 0 ? this.projectCanonicalCreativeData(taskType, source, transform, legacyFormatConverter) : void 0;
|
|
1988
|
+
const { legacySource: _dropLegacySource, ...safe } = stripLegacyCreativeIdentity({
|
|
1989
|
+
...taskInfo,
|
|
1990
|
+
taskType,
|
|
1991
|
+
...source !== void 0 && { result: projected },
|
|
1992
|
+
legacySource: source
|
|
1993
|
+
});
|
|
1994
|
+
void _dropLegacySource;
|
|
1995
|
+
return safe;
|
|
1996
|
+
}
|
|
1997
|
+
wrapCanonicalCreativeContinuations(result, taskType, transform, legacyFormatConverter, routingRequest) {
|
|
1998
|
+
const routingSnapshot = canonicalCreativeRoutingSnapshot(taskType, routingRequest);
|
|
1999
|
+
if (result.submitted) {
|
|
2000
|
+
const submitted = result.submitted;
|
|
2001
|
+
result = {
|
|
2002
|
+
...result,
|
|
2003
|
+
submitted: {
|
|
2004
|
+
...submitted,
|
|
2005
|
+
track: async (transport) => {
|
|
2006
|
+
const canonical = this.canonicalizeCreativeTaskInfo(
|
|
2007
|
+
await canonicalCreativeExecutionStorage.run(
|
|
2008
|
+
{ taskType, legacyFormatConverter },
|
|
2009
|
+
() => submitted.track(transport)
|
|
2010
|
+
),
|
|
2011
|
+
taskType,
|
|
2012
|
+
transform,
|
|
2013
|
+
legacyFormatConverter
|
|
2014
|
+
);
|
|
2015
|
+
if (canonical.status === "completed" && canonical.result !== void 0) {
|
|
2016
|
+
this.rememberCanonicalPackageRoutesForTask(taskType, canonical.result, routingSnapshot);
|
|
2017
|
+
}
|
|
2018
|
+
return canonical;
|
|
2019
|
+
},
|
|
2020
|
+
waitForCompletion: async (pollInterval, signal) => {
|
|
2021
|
+
const completed = await canonicalCreativeExecutionStorage.run(
|
|
2022
|
+
{ taskType, legacyFormatConverter },
|
|
2023
|
+
() => submitted.waitForCompletion(pollInterval, signal)
|
|
2024
|
+
);
|
|
2025
|
+
const canonical = this.canonicalizeCreativeTaskResult(
|
|
2026
|
+
completed,
|
|
2027
|
+
taskType,
|
|
2028
|
+
transform,
|
|
2029
|
+
legacyFormatConverter
|
|
2030
|
+
);
|
|
2031
|
+
if (canonical.success && canonical.status === "completed" && canonical.data !== void 0) {
|
|
2032
|
+
this.rememberCanonicalPackageRoutesForTask(taskType, canonical.data, routingSnapshot);
|
|
2033
|
+
}
|
|
2034
|
+
this.rememberCanonicalCreativeTaskIds(canonical, taskType, legacyFormatConverter, routingSnapshot);
|
|
2035
|
+
return this.wrapCanonicalCreativeContinuations(
|
|
2036
|
+
canonical,
|
|
2037
|
+
taskType,
|
|
2038
|
+
transform,
|
|
2039
|
+
legacyFormatConverter,
|
|
2040
|
+
routingSnapshot
|
|
2041
|
+
);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
if (result.deferred) {
|
|
2047
|
+
const deferred = result.deferred;
|
|
2048
|
+
result = {
|
|
2049
|
+
...result,
|
|
2050
|
+
deferred: {
|
|
2051
|
+
...deferred,
|
|
2052
|
+
resume: async (input) => {
|
|
2053
|
+
const resumed = await canonicalCreativeExecutionStorage.run(
|
|
2054
|
+
{ taskType, legacyFormatConverter },
|
|
2055
|
+
() => deferred.resume(input)
|
|
2056
|
+
);
|
|
2057
|
+
const canonical = this.canonicalizeCreativeTaskResult(resumed, taskType, transform, legacyFormatConverter);
|
|
2058
|
+
if (canonical.success && canonical.status === "completed" && canonical.data !== void 0) {
|
|
2059
|
+
this.rememberCanonicalPackageRoutesForTask(taskType, canonical.data, routingSnapshot);
|
|
2060
|
+
}
|
|
2061
|
+
this.rememberCanonicalCreativeTaskIds(canonical, taskType, legacyFormatConverter, routingSnapshot);
|
|
2062
|
+
return this.wrapCanonicalCreativeContinuations(
|
|
2063
|
+
canonical,
|
|
2064
|
+
taskType,
|
|
2065
|
+
transform,
|
|
2066
|
+
legacyFormatConverter,
|
|
2067
|
+
routingSnapshot
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
return attachMatch(result);
|
|
2074
|
+
}
|
|
2075
|
+
rememberCanonicalCreativeTaskIds(result, taskType, legacyFormatConverter, routingRequest) {
|
|
2076
|
+
const routingSnapshot = canonicalCreativeRoutingSnapshot(taskType, routingRequest);
|
|
2077
|
+
const keys = [
|
|
2078
|
+
result.metadata.taskId,
|
|
2079
|
+
result.metadata.contextId,
|
|
2080
|
+
result.metadata.serverTaskId,
|
|
2081
|
+
result.submitted?.taskId
|
|
2082
|
+
];
|
|
2083
|
+
for (const key of keys) {
|
|
2084
|
+
if (!key) continue;
|
|
2085
|
+
this.rememberCanonicalCreativeTaskAssociation(key, taskType, legacyFormatConverter, routingSnapshot);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
rememberCanonicalCreativeTaskAssociation(key, taskType, legacyFormatConverter, canonicalRequest) {
|
|
2089
|
+
const previous = this.canonicalCreativeTaskAssociations.get(key);
|
|
2090
|
+
const routingSnapshot = canonicalCreativeRoutingSnapshot(taskType, canonicalRequest);
|
|
2091
|
+
const effectiveRoutingSnapshot = routingSnapshot ?? (previous?.taskType === taskType ? previous.routingSnapshot : void 0);
|
|
2092
|
+
this.canonicalCreativeTaskAssociations.delete(key);
|
|
2093
|
+
this.canonicalCreativeTaskAssociations.set(key, {
|
|
2094
|
+
taskType,
|
|
2095
|
+
legacyFormatConverter,
|
|
2096
|
+
...effectiveRoutingSnapshot ? { routingSnapshot: effectiveRoutingSnapshot } : {}
|
|
2097
|
+
});
|
|
2098
|
+
while (this.canonicalCreativeTaskAssociations.size > TASK_SCOPED_STATE_LIMIT) {
|
|
2099
|
+
const oldest = this.canonicalCreativeTaskAssociations.keys().next().value;
|
|
2100
|
+
if (oldest === void 0) break;
|
|
2101
|
+
this.canonicalCreativeTaskAssociations.delete(oldest);
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
canonicalCreativeTaskAssociation(key) {
|
|
2105
|
+
if (!key) return void 0;
|
|
2106
|
+
const association = this.canonicalCreativeTaskAssociations.get(key);
|
|
2107
|
+
if (!association) return void 0;
|
|
2108
|
+
this.canonicalCreativeTaskAssociations.delete(key);
|
|
2109
|
+
this.canonicalCreativeTaskAssociations.set(key, association);
|
|
2110
|
+
return association;
|
|
2111
|
+
}
|
|
2112
|
+
forgetCanonicalCreativeTaskAssociationKeys(keys) {
|
|
2113
|
+
for (const key of keys) {
|
|
2114
|
+
if (key) this.canonicalCreativeTaskAssociations.delete(key);
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
1031
2117
|
/**
|
|
1032
2118
|
* Drop products that arrive without a usable `pricing_options[]` array from a
|
|
1033
2119
|
* completed `get_products` response. `pricing_options` is required and
|
|
@@ -1238,20 +2324,62 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1238
2324
|
return result;
|
|
1239
2325
|
}
|
|
1240
2326
|
rememberProductPolicyRequestParams(taskType, requestParams, result, options) {
|
|
2327
|
+
this.rememberProductPolicyRequestState(
|
|
2328
|
+
taskType,
|
|
2329
|
+
{ request: productPolicyRequestSnapshot(requestParams) },
|
|
2330
|
+
result,
|
|
2331
|
+
options
|
|
2332
|
+
);
|
|
2333
|
+
}
|
|
2334
|
+
rememberProductPolicyRequestState(taskType, requestState, result, options) {
|
|
1241
2335
|
if (taskType !== "get_products") return;
|
|
1242
2336
|
if (result.status !== "submitted" && result.status !== "working") return;
|
|
1243
2337
|
const keys = /* @__PURE__ */ new Set();
|
|
1244
2338
|
if (result.metadata.taskId) keys.add(result.metadata.taskId);
|
|
1245
2339
|
if (result.metadata.contextId) keys.add(result.metadata.contextId);
|
|
1246
2340
|
if (result.metadata.serverTaskId) keys.add(result.metadata.serverTaskId);
|
|
2341
|
+
if (result.submitted?.taskId) keys.add(result.submitted.taskId);
|
|
1247
2342
|
if (options?.taskId) keys.add(options.taskId);
|
|
1248
2343
|
if (options?.contextId) keys.add(options.contextId);
|
|
1249
2344
|
for (const key of keys) {
|
|
1250
|
-
this.productPolicyRequestParamsByTask.
|
|
2345
|
+
this.productPolicyRequestParamsByTask.delete(key);
|
|
2346
|
+
this.productPolicyRequestParamsByTask.set(key, requestState);
|
|
2347
|
+
while (this.productPolicyRequestParamsByTask.size > TASK_SCOPED_STATE_LIMIT) {
|
|
2348
|
+
const oldest = this.productPolicyRequestParamsByTask.keys().next().value;
|
|
2349
|
+
if (oldest === void 0) break;
|
|
2350
|
+
this.productPolicyRequestParamsByTask.delete(oldest);
|
|
2351
|
+
}
|
|
1251
2352
|
}
|
|
1252
2353
|
}
|
|
2354
|
+
rememberLegacyFormatConverter(taskType, converter, result, options) {
|
|
2355
|
+
if (!converter || taskType !== "get_products" && taskType !== "list_creatives") return;
|
|
2356
|
+
const metadata = result.metadata;
|
|
2357
|
+
const keys = [
|
|
2358
|
+
metadata.operationId,
|
|
2359
|
+
metadata.taskId,
|
|
2360
|
+
metadata.contextId,
|
|
2361
|
+
metadata.serverTaskId,
|
|
2362
|
+
options?.taskId,
|
|
2363
|
+
options?.contextId
|
|
2364
|
+
];
|
|
2365
|
+
for (const key of keys) {
|
|
2366
|
+
if (key) this.rememberCanonicalCreativeTaskAssociation(key, taskType, converter);
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
legacyFormatConverterForWebhook(metadata) {
|
|
2370
|
+
return this.canonicalCreativeTaskAssociation(metadata.operation_id)?.legacyFormatConverter ?? this.canonicalCreativeTaskAssociation(metadata.task_id)?.legacyFormatConverter ?? this.canonicalCreativeTaskAssociation(metadata.context_id)?.legacyFormatConverter ?? this.resolveLegacyFormatConverter();
|
|
2371
|
+
}
|
|
1253
2372
|
forgetProductPolicyRequestParams(metadata) {
|
|
1254
|
-
|
|
2373
|
+
const aliases = [metadata.operation_id, metadata.task_id, metadata.context_id];
|
|
2374
|
+
const states = new Set(
|
|
2375
|
+
aliases.filter((key) => key !== void 0).map((key) => this.productPolicyRequestParamsByTask.get(key)).filter((value) => value !== void 0)
|
|
2376
|
+
);
|
|
2377
|
+
for (const state of states) state.request = void 0;
|
|
2378
|
+
this.forgetProductPolicyRequestParamKeys(aliases);
|
|
2379
|
+
if (states.size === 0) return;
|
|
2380
|
+
for (const [key, state] of this.productPolicyRequestParamsByTask) {
|
|
2381
|
+
if (states.has(state)) this.productPolicyRequestParamsByTask.delete(key);
|
|
2382
|
+
}
|
|
1255
2383
|
}
|
|
1256
2384
|
forgetProductPolicyRequestParamKeys(keys) {
|
|
1257
2385
|
for (const key of keys) {
|
|
@@ -1259,38 +2387,61 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1259
2387
|
this.productPolicyRequestParamsByTask.delete(key);
|
|
1260
2388
|
}
|
|
1261
2389
|
}
|
|
1262
|
-
wrapProductPolicySubmittedContinuation(result, taskType, requestParams) {
|
|
2390
|
+
wrapProductPolicySubmittedContinuation(result, taskType, requestParams, options) {
|
|
1263
2391
|
if (taskType !== "get_products" || result.status !== "submitted" || !result.submitted) return result;
|
|
1264
2392
|
const submitted = result.submitted;
|
|
2393
|
+
const policyState = {
|
|
2394
|
+
request: productPolicyRequestSnapshot(requestParams)
|
|
2395
|
+
};
|
|
2396
|
+
this.rememberProductPolicyRequestState(taskType, policyState, result, options);
|
|
2397
|
+
const retainedKeys = [
|
|
2398
|
+
result.metadata.taskId,
|
|
2399
|
+
result.metadata.contextId,
|
|
2400
|
+
result.metadata.serverTaskId,
|
|
2401
|
+
submitted.taskId,
|
|
2402
|
+
options?.taskId,
|
|
2403
|
+
options?.contextId
|
|
2404
|
+
];
|
|
1265
2405
|
result.submitted = {
|
|
1266
2406
|
...submitted,
|
|
1267
2407
|
track: async (transport) => {
|
|
1268
2408
|
const taskInfo = await submitted.track(transport);
|
|
1269
|
-
const
|
|
1270
|
-
|
|
1271
|
-
this.
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
2409
|
+
const terminal = ["completed", "failed", "rejected", "canceled"].includes(taskInfo.status);
|
|
2410
|
+
try {
|
|
2411
|
+
return await this.applyProductPropertyPolicyToTaskInfo(
|
|
2412
|
+
taskInfo,
|
|
2413
|
+
taskType,
|
|
2414
|
+
policyState.request ?? {}
|
|
2415
|
+
);
|
|
2416
|
+
} finally {
|
|
2417
|
+
if (terminal) {
|
|
2418
|
+
policyState.request = void 0;
|
|
2419
|
+
this.forgetProductPolicyRequestParamKeys([...retainedKeys, taskInfo.taskId]);
|
|
2420
|
+
}
|
|
1276
2421
|
}
|
|
1277
|
-
return processed;
|
|
1278
2422
|
},
|
|
1279
2423
|
waitForCompletion: async (pollInterval, signal) => {
|
|
1280
2424
|
let completed = await submitted.waitForCompletion(pollInterval, signal);
|
|
1281
2425
|
if (completed.success && completed.data) {
|
|
1282
2426
|
completed.data = this.normalizeResponseToV3(taskType, completed.data);
|
|
1283
2427
|
}
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
this.
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
2428
|
+
const terminal = completed.status === "completed" || completed.status === "failed";
|
|
2429
|
+
try {
|
|
2430
|
+
return await this.applyProductPropertyPolicy(
|
|
2431
|
+
completed,
|
|
2432
|
+
taskType,
|
|
2433
|
+
policyState.request ?? {}
|
|
2434
|
+
);
|
|
2435
|
+
} finally {
|
|
2436
|
+
if (terminal) {
|
|
2437
|
+
policyState.request = void 0;
|
|
2438
|
+
this.forgetProductPolicyRequestParamKeys([
|
|
2439
|
+
...retainedKeys,
|
|
2440
|
+
completed.metadata.taskId,
|
|
2441
|
+
completed.metadata.serverTaskId
|
|
2442
|
+
]);
|
|
2443
|
+
}
|
|
1292
2444
|
}
|
|
1293
|
-
return processed;
|
|
1294
2445
|
}
|
|
1295
2446
|
};
|
|
1296
2447
|
return result;
|
|
@@ -1328,7 +2479,15 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1328
2479
|
};
|
|
1329
2480
|
}
|
|
1330
2481
|
productPolicyRequestParamsForWebhook(metadata) {
|
|
1331
|
-
return this.executor.getRequestParams(metadata.operation_id) ?? this.executor.getRequestParams(metadata.task_id) ?? this.
|
|
2482
|
+
return this.executor.getRequestParams(metadata.operation_id) ?? this.executor.getRequestParams(metadata.task_id) ?? this.productPolicyRequestParamsForKey(metadata.operation_id) ?? this.productPolicyRequestParamsForKey(metadata.task_id) ?? this.productPolicyRequestParamsForKey(metadata.context_id) ?? {};
|
|
2483
|
+
}
|
|
2484
|
+
productPolicyRequestParamsForKey(key) {
|
|
2485
|
+
if (!key) return void 0;
|
|
2486
|
+
const state = this.productPolicyRequestParamsByTask.get(key);
|
|
2487
|
+
if (!state?.request) return void 0;
|
|
2488
|
+
this.productPolicyRequestParamsByTask.delete(key);
|
|
2489
|
+
this.productPolicyRequestParamsByTask.set(key, state);
|
|
2490
|
+
return state.request;
|
|
1332
2491
|
}
|
|
1333
2492
|
async applyProductPropertyPolicyToWebhookResult(result, metadata) {
|
|
1334
2493
|
if (metadata.task_type !== "get_products" || metadata.status !== "completed" || !result) {
|
|
@@ -1373,17 +2532,17 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1373
2532
|
* 3.1-only fields for a 3.0 seller). Returns the adapted params and any
|
|
1374
2533
|
* drift log entries describing what was changed.
|
|
1375
2534
|
*
|
|
1376
|
-
* Runs after `detectServerVersion` so
|
|
1377
|
-
*
|
|
2535
|
+
* Runs after `detectServerVersion` so capabilities are available and the
|
|
2536
|
+
* current call's tool schemas can be supplied without cross-tenant caching.
|
|
1378
2537
|
*/
|
|
1379
|
-
adaptRequest(taskType, params, serverVersion, debugLogs) {
|
|
2538
|
+
adaptRequest(taskType, params, serverVersion, debugLogs, perCallToolSchemas) {
|
|
1380
2539
|
const driftLogs = [];
|
|
1381
2540
|
let adapted = params;
|
|
1382
2541
|
if (serverVersion !== "v3") {
|
|
1383
2542
|
const pair = getV25Adapter(taskType);
|
|
1384
2543
|
if (pair) adapted = pair.adaptRequest(adapted);
|
|
1385
2544
|
}
|
|
1386
|
-
const toolSchema = this.cachedToolSchemas?.get(taskType);
|
|
2545
|
+
const toolSchema = (perCallToolSchemas ?? this.cachedToolSchemas)?.get(taskType);
|
|
1387
2546
|
if (toolSchema && Object.keys(toolSchema).length > 0) {
|
|
1388
2547
|
const declaredFields = new Set(Object.keys(toolSchema));
|
|
1389
2548
|
const adapterAliases = [["brand_manifest", "brand"]];
|
|
@@ -1523,30 +2682,57 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1523
2682
|
* ```
|
|
1524
2683
|
*/
|
|
1525
2684
|
async getProducts(params, inputHandler, options) {
|
|
2685
|
+
const { legacyFormatConverter, projectionCatalogs, ...taskOptions } = options ?? {};
|
|
2686
|
+
const effectiveLegacyFormatConverter = this.resolveLegacyFormatConverter(
|
|
2687
|
+
legacyFormatConverter,
|
|
2688
|
+
projectionCatalogs ?? this.config.projectionCatalogs
|
|
2689
|
+
);
|
|
2690
|
+
const account = canonicalAccountRoutingSnapshot(params.account);
|
|
1526
2691
|
return this.executeAndHandle(
|
|
1527
2692
|
"get_products",
|
|
1528
2693
|
"onGetProductsStatusChange",
|
|
1529
2694
|
params,
|
|
1530
2695
|
inputHandler,
|
|
1531
|
-
|
|
2696
|
+
taskOptions,
|
|
2697
|
+
(data) => {
|
|
2698
|
+
const { response, diagnostics } = toCanonicalOnlyResponse(data, {
|
|
2699
|
+
legacyFormatConverter: effectiveLegacyFormatConverter,
|
|
2700
|
+
projectionCatalogs: projectionCatalogs ?? this.config.projectionCatalogs
|
|
2701
|
+
});
|
|
2702
|
+
const authoritativeProducts = Array.isArray(data.products) ? data.products : response.products;
|
|
2703
|
+
this.rememberCanonicalProductRoutes(response.products, account, authoritativeProducts);
|
|
2704
|
+
const { _message: _dropLegacyMessage, ...canonical } = response;
|
|
2705
|
+
void _dropLegacyMessage;
|
|
2706
|
+
return { ...canonical, projection: { diagnostics } };
|
|
2707
|
+
},
|
|
2708
|
+
effectiveLegacyFormatConverter
|
|
1532
2709
|
);
|
|
1533
2710
|
}
|
|
2711
|
+
/** @deprecated Explicit raw-wire escape hatch for migration tooling. */
|
|
2712
|
+
async getProductsLegacy(params, inputHandler, options) {
|
|
2713
|
+
return this.executeTaskUnprojected("get_products", params, inputHandler, options);
|
|
2714
|
+
}
|
|
1534
2715
|
/**
|
|
1535
|
-
* List
|
|
2716
|
+
* List a legacy named-format catalog for migration tooling.
|
|
1536
2717
|
*
|
|
1537
2718
|
* @param params - Format listing parameters
|
|
1538
2719
|
* @param inputHandler - Handler for clarification requests
|
|
1539
2720
|
* @param options - Task execution options
|
|
2721
|
+
* @deprecated Canonical applications discover `format_options[]` through `getProducts()`.
|
|
1540
2722
|
*/
|
|
1541
|
-
async
|
|
2723
|
+
async listCreativeFormatsLegacy(params, inputHandler, options) {
|
|
1542
2724
|
return this.executeAndHandle(
|
|
1543
2725
|
"list_creative_formats",
|
|
1544
|
-
"
|
|
2726
|
+
"onListCreativeFormatsLegacyStatusChange",
|
|
1545
2727
|
params,
|
|
1546
2728
|
inputHandler,
|
|
1547
2729
|
options
|
|
1548
2730
|
);
|
|
1549
2731
|
}
|
|
2732
|
+
/** @deprecated Migration-only access to legacy creative transformer declarations. */
|
|
2733
|
+
async listTransformersLegacy(params, inputHandler, options) {
|
|
2734
|
+
return this.executeTaskUnprojected("list_transformers", params, inputHandler, options);
|
|
2735
|
+
}
|
|
1550
2736
|
/**
|
|
1551
2737
|
* Create a new media buy
|
|
1552
2738
|
*
|
|
@@ -1555,6 +2741,23 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1555
2741
|
* @param options - Task execution options
|
|
1556
2742
|
*/
|
|
1557
2743
|
async createMediaBuy(params, inputHandler, options) {
|
|
2744
|
+
const { legacyFormatConverter, projectionCatalogs, canonicalFormatLegacyResolver, ...taskOptions } = options ?? {};
|
|
2745
|
+
const effectiveLegacyFormatConverter = this.resolveLegacyFormatConverter(
|
|
2746
|
+
legacyFormatConverter,
|
|
2747
|
+
projectionCatalogs ?? this.config.projectionCatalogs
|
|
2748
|
+
);
|
|
2749
|
+
const effectiveCanonicalFormatLegacyResolver = this.resolveCanonicalFormatLegacyResolver(
|
|
2750
|
+
canonicalFormatLegacyResolver,
|
|
2751
|
+
params.account
|
|
2752
|
+
);
|
|
2753
|
+
const hasCreativeFormatData = hasMediaBuyCreativeFormatData(params);
|
|
2754
|
+
if (hasCreativeFormatData) {
|
|
2755
|
+
this.validateBeforeCreativeCapabilityProbe("create_media_buy", params, taskOptions);
|
|
2756
|
+
}
|
|
2757
|
+
const wireMode = hasCreativeFormatData ? this.resolveCreativeFormatWireMode(
|
|
2758
|
+
"create_media_buy",
|
|
2759
|
+
await this.getCapabilities({ signal: taskOptions.signal, transport: taskOptions.transport })
|
|
2760
|
+
) : "canonical";
|
|
1558
2761
|
if (this.config.webhookUrlTemplate && !options?.disableWebhook) {
|
|
1559
2762
|
const now = /* @__PURE__ */ new Date();
|
|
1560
2763
|
const year = now.getUTCFullYear();
|
|
@@ -1589,9 +2792,28 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1589
2792
|
};
|
|
1590
2793
|
}
|
|
1591
2794
|
}
|
|
1592
|
-
|
|
2795
|
+
const result = await this.executeAndHandle(
|
|
1593
2796
|
"create_media_buy",
|
|
1594
2797
|
"onCreateMediaBuyStatusChange",
|
|
2798
|
+
projectMediaBuyCreativesForDelivery(
|
|
2799
|
+
params,
|
|
2800
|
+
wireMode,
|
|
2801
|
+
"create_media_buy",
|
|
2802
|
+
effectiveLegacyFormatConverter,
|
|
2803
|
+
effectiveCanonicalFormatLegacyResolver
|
|
2804
|
+
),
|
|
2805
|
+
inputHandler,
|
|
2806
|
+
taskOptions,
|
|
2807
|
+
void 0,
|
|
2808
|
+
effectiveLegacyFormatConverter,
|
|
2809
|
+
params
|
|
2810
|
+
);
|
|
2811
|
+
if (result.data !== void 0) this.rememberCanonicalPackageRoutes(result.data, params);
|
|
2812
|
+
return result;
|
|
2813
|
+
}
|
|
2814
|
+
/** @deprecated Compatibility-only entry point for callers still holding legacy creative `format_id` values. */
|
|
2815
|
+
async createMediaBuyLegacy(params, inputHandler, options) {
|
|
2816
|
+
return await this.createMediaBuy(
|
|
1595
2817
|
params,
|
|
1596
2818
|
inputHandler,
|
|
1597
2819
|
options
|
|
@@ -1605,9 +2827,45 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1605
2827
|
* @param options - Task execution options
|
|
1606
2828
|
*/
|
|
1607
2829
|
async updateMediaBuy(params, inputHandler, options) {
|
|
1608
|
-
|
|
2830
|
+
const { legacyFormatConverter, projectionCatalogs, canonicalFormatLegacyResolver, ...taskOptions } = options ?? {};
|
|
2831
|
+
const effectiveLegacyFormatConverter = this.resolveLegacyFormatConverter(
|
|
2832
|
+
legacyFormatConverter,
|
|
2833
|
+
projectionCatalogs ?? this.config.projectionCatalogs
|
|
2834
|
+
);
|
|
2835
|
+
const effectiveCanonicalFormatLegacyResolver = this.resolveCanonicalFormatLegacyResolver(
|
|
2836
|
+
canonicalFormatLegacyResolver,
|
|
2837
|
+
params.account
|
|
2838
|
+
);
|
|
2839
|
+
const hasCreativeFormatData = hasMediaBuyCreativeFormatData(params);
|
|
2840
|
+
if (hasCreativeFormatData) {
|
|
2841
|
+
this.validateBeforeCreativeCapabilityProbe("update_media_buy", params, taskOptions);
|
|
2842
|
+
}
|
|
2843
|
+
const wireMode = hasCreativeFormatData ? this.resolveCreativeFormatWireMode(
|
|
2844
|
+
"update_media_buy",
|
|
2845
|
+
await this.getCapabilities({ signal: taskOptions.signal, transport: taskOptions.transport })
|
|
2846
|
+
) : "canonical";
|
|
2847
|
+
const result = await this.executeAndHandle(
|
|
1609
2848
|
"update_media_buy",
|
|
1610
2849
|
"onUpdateMediaBuyStatusChange",
|
|
2850
|
+
projectMediaBuyCreativesForDelivery(
|
|
2851
|
+
params,
|
|
2852
|
+
wireMode,
|
|
2853
|
+
"update_media_buy",
|
|
2854
|
+
effectiveLegacyFormatConverter,
|
|
2855
|
+
effectiveCanonicalFormatLegacyResolver
|
|
2856
|
+
),
|
|
2857
|
+
inputHandler,
|
|
2858
|
+
taskOptions,
|
|
2859
|
+
void 0,
|
|
2860
|
+
effectiveLegacyFormatConverter,
|
|
2861
|
+
params
|
|
2862
|
+
);
|
|
2863
|
+
if (result.data !== void 0) this.rememberCanonicalPackageRoutes(result.data, params);
|
|
2864
|
+
return result;
|
|
2865
|
+
}
|
|
2866
|
+
/** @deprecated Compatibility-only entry point for callers still holding legacy creative `format_id` values. */
|
|
2867
|
+
async updateMediaBuyLegacy(params, inputHandler, options) {
|
|
2868
|
+
return await this.updateMediaBuy(
|
|
1611
2869
|
params,
|
|
1612
2870
|
inputHandler,
|
|
1613
2871
|
options
|
|
@@ -1621,41 +2879,149 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1621
2879
|
* @param options - Task execution options
|
|
1622
2880
|
*/
|
|
1623
2881
|
async syncCreatives(params, inputHandler, options) {
|
|
2882
|
+
const {
|
|
2883
|
+
creativeFormatProjection,
|
|
2884
|
+
legacyFormatConverter,
|
|
2885
|
+
projectionCatalogs,
|
|
2886
|
+
canonicalFormatLegacyResolver,
|
|
2887
|
+
...taskOptions
|
|
2888
|
+
} = options ?? {};
|
|
2889
|
+
const effectiveCanonicalFormatLegacyResolver = this.resolveCanonicalFormatLegacyResolver(
|
|
2890
|
+
canonicalFormatLegacyResolver,
|
|
2891
|
+
params.account
|
|
2892
|
+
);
|
|
2893
|
+
const effectiveLegacyFormatConverter = this.resolveLegacyFormatConverter(
|
|
2894
|
+
creativeFormatProjection?.legacyFormatConverter ?? legacyFormatConverter,
|
|
2895
|
+
projectionCatalogs ?? this.config.projectionCatalogs
|
|
2896
|
+
);
|
|
2897
|
+
this.validateBeforeCreativeCapabilityProbe("sync_creatives", params, taskOptions);
|
|
2898
|
+
const wireMode = this.resolveCreativeFormatWireMode(
|
|
2899
|
+
"sync_creatives",
|
|
2900
|
+
await this.getCapabilities({ signal: taskOptions.signal, transport: taskOptions.transport })
|
|
2901
|
+
);
|
|
2902
|
+
const configuredSelectorContainers = [
|
|
2903
|
+
...creativeFormatProjection?.selectorContainers ?? []
|
|
2904
|
+
];
|
|
2905
|
+
const configuredPackageIds = new Set(
|
|
2906
|
+
configuredSelectorContainers.flatMap(
|
|
2907
|
+
(container) => typeof container.package_id === "string" ? [container.package_id] : []
|
|
2908
|
+
)
|
|
2909
|
+
);
|
|
2910
|
+
const assignmentPackageContainers = Array.isArray(params.assignments) ? params.assignments.flatMap(
|
|
2911
|
+
(assignment) => typeof assignment.package_id === "string" && !configuredPackageIds.has(assignment.package_id) ? [{ package_id: assignment.package_id }] : []
|
|
2912
|
+
) : [];
|
|
2913
|
+
const wireParams = projectSyncCreativesForDelivery(
|
|
2914
|
+
params,
|
|
2915
|
+
[...configuredSelectorContainers, ...assignmentPackageContainers],
|
|
2916
|
+
wireMode,
|
|
2917
|
+
effectiveLegacyFormatConverter,
|
|
2918
|
+
effectiveCanonicalFormatLegacyResolver
|
|
2919
|
+
);
|
|
1624
2920
|
return this.executeAndHandle(
|
|
1625
2921
|
"sync_creatives",
|
|
1626
2922
|
"onSyncCreativesStatusChange",
|
|
2923
|
+
wireParams,
|
|
2924
|
+
inputHandler,
|
|
2925
|
+
taskOptions,
|
|
2926
|
+
void 0,
|
|
2927
|
+
effectiveLegacyFormatConverter,
|
|
2928
|
+
params
|
|
2929
|
+
);
|
|
2930
|
+
}
|
|
2931
|
+
/** @deprecated Compatibility-only entry point for callers still holding legacy creative `format_id` values. */
|
|
2932
|
+
async syncCreativesLegacy(params, inputHandler, options) {
|
|
2933
|
+
return await this.syncCreatives(
|
|
1627
2934
|
params,
|
|
1628
2935
|
inputHandler,
|
|
1629
2936
|
options
|
|
1630
2937
|
);
|
|
1631
2938
|
}
|
|
2939
|
+
resolveCreativeFormatWireMode(taskType, capabilities) {
|
|
2940
|
+
const wireRelease = this.config.wireAdcpVersion ?? this.resolvedAdcpVersion;
|
|
2941
|
+
const declared = resolveCreativeFormatWireMode(capabilities, wireRelease);
|
|
2942
|
+
const schema = creativeSchemaSupport(this.cachedToolSchemas?.get(taskType));
|
|
2943
|
+
if (declared !== "unknown" && schema !== "unknown" && declared !== schema) {
|
|
2944
|
+
throw new CreativeFormatCapabilityError(
|
|
2945
|
+
`Seller capability and ${taskType} input schema disagree about canonical creative support`
|
|
2946
|
+
);
|
|
2947
|
+
}
|
|
2948
|
+
const resolved = declared !== "unknown" ? declared : schema;
|
|
2949
|
+
const release = /^v?(\d+)\.(\d+)(?:\.|-|$)/.exec(wireRelease.trim());
|
|
2950
|
+
const canonicalRequiredByBuyerPin = release !== null && (Number(release[1]) > 3 || Number(release[1]) === 3 && Number(release[2]) >= 2);
|
|
2951
|
+
if (resolved === "unknown" && canonicalRequiredByBuyerPin) {
|
|
2952
|
+
throw new CreativeFormatCapabilityError(
|
|
2953
|
+
`Cannot prove which AdCP release the seller serves for ${taskType}; a 3.2+ client will not guess a legacy creative wire shape`
|
|
2954
|
+
);
|
|
2955
|
+
}
|
|
2956
|
+
return resolved;
|
|
2957
|
+
}
|
|
2958
|
+
/** Validate malformed creative payloads before capability discovery can perform I/O. */
|
|
2959
|
+
validateBeforeCreativeCapabilityProbe(taskType, params, options) {
|
|
2960
|
+
if (options.skipIdempotencyAutoInject || options.skipAccountValidation) return;
|
|
2961
|
+
let normalizedParams = normalizeRequestParams(taskType, params);
|
|
2962
|
+
if (isMutatingTask(taskType) && normalizedParams && typeof normalizedParams === "object" && !normalizedParams.idempotency_key) {
|
|
2963
|
+
normalizedParams = { ...normalizedParams, idempotency_key: generateIdempotencyKey() };
|
|
2964
|
+
}
|
|
2965
|
+
this.validateRequest(taskType, normalizedParams);
|
|
2966
|
+
}
|
|
1632
2967
|
/**
|
|
1633
|
-
* List
|
|
2968
|
+
* List creatives through the canonical SDK boundary.
|
|
2969
|
+
*
|
|
2970
|
+
* Legacy format filters are rejected and returned creative identities are
|
|
2971
|
+
* projected to `format_kind` / `format_option_ref`. Migration tooling that
|
|
2972
|
+
* needs the negotiated raw wire shape must call `listCreativesLegacy()`.
|
|
1634
2973
|
*
|
|
1635
2974
|
* @param params - Creative listing parameters
|
|
1636
2975
|
* @param inputHandler - Handler for clarification requests
|
|
1637
2976
|
* @param options - Task execution options
|
|
1638
2977
|
*/
|
|
1639
2978
|
async listCreatives(params, inputHandler, options) {
|
|
2979
|
+
const { legacyFormatConverter, projectionCatalogs, ...taskOptions } = options ?? {};
|
|
2980
|
+
const effectiveLegacyFormatConverter = this.resolveLegacyFormatConverter(
|
|
2981
|
+
legacyFormatConverter,
|
|
2982
|
+
projectionCatalogs ?? this.config.projectionCatalogs
|
|
2983
|
+
);
|
|
1640
2984
|
return this.executeAndHandle(
|
|
1641
2985
|
"list_creatives",
|
|
1642
2986
|
"onListCreativesStatusChange",
|
|
1643
2987
|
params,
|
|
1644
2988
|
inputHandler,
|
|
1645
|
-
|
|
2989
|
+
taskOptions,
|
|
2990
|
+
(data) => {
|
|
2991
|
+
const { _message: _dropLegacyMessage, ...safe } = data;
|
|
2992
|
+
void _dropLegacyMessage;
|
|
2993
|
+
return {
|
|
2994
|
+
...safe,
|
|
2995
|
+
creatives: data.creatives.map(
|
|
2996
|
+
(creative) => projectCreativeForDelivery(
|
|
2997
|
+
creative,
|
|
2998
|
+
{},
|
|
2999
|
+
"canonical",
|
|
3000
|
+
"list_creatives",
|
|
3001
|
+
effectiveLegacyFormatConverter
|
|
3002
|
+
)
|
|
3003
|
+
)
|
|
3004
|
+
};
|
|
3005
|
+
},
|
|
3006
|
+
effectiveLegacyFormatConverter
|
|
1646
3007
|
);
|
|
1647
3008
|
}
|
|
3009
|
+
/** @deprecated Explicit raw-wire escape hatch for migration tooling. */
|
|
3010
|
+
async listCreativesLegacy(params, inputHandler, options) {
|
|
3011
|
+
return this.executeTaskUnprojected("list_creatives", params, inputHandler, options);
|
|
3012
|
+
}
|
|
1648
3013
|
/**
|
|
1649
|
-
* Preview a creative
|
|
3014
|
+
* Preview a creative through the legacy named-format protocol.
|
|
1650
3015
|
*
|
|
1651
3016
|
* @param params - Preview creative parameters
|
|
1652
3017
|
* @param inputHandler - Handler for clarification requests
|
|
1653
3018
|
* @param options - Task execution options
|
|
3019
|
+
* @deprecated Migration-only access to `format_id`-based creative preview.
|
|
1654
3020
|
*/
|
|
1655
|
-
async
|
|
3021
|
+
async previewCreativeLegacy(params, inputHandler, options) {
|
|
1656
3022
|
return this.executeAndHandle(
|
|
1657
3023
|
"preview_creative",
|
|
1658
|
-
"
|
|
3024
|
+
"onPreviewCreativeLegacyStatusChange",
|
|
1659
3025
|
params,
|
|
1660
3026
|
inputHandler,
|
|
1661
3027
|
options
|
|
@@ -1669,13 +3035,18 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1669
3035
|
* @param options - Task execution options
|
|
1670
3036
|
*/
|
|
1671
3037
|
async getMediaBuys(params, inputHandler, options) {
|
|
1672
|
-
|
|
3038
|
+
const { legacyFormatConverter, projectionCatalogs, ...taskOptions } = options ?? {};
|
|
3039
|
+
const result = await this.executeAndHandle(
|
|
1673
3040
|
"get_media_buys",
|
|
1674
3041
|
"onGetMediaBuysStatusChange",
|
|
1675
3042
|
params,
|
|
1676
3043
|
inputHandler,
|
|
1677
|
-
|
|
3044
|
+
taskOptions,
|
|
3045
|
+
void 0,
|
|
3046
|
+
this.resolveLegacyFormatConverter(legacyFormatConverter, projectionCatalogs ?? this.config.projectionCatalogs)
|
|
1678
3047
|
);
|
|
3048
|
+
if (result.data !== void 0) this.rememberCanonicalPackageRoutes(result.data, params);
|
|
3049
|
+
return result;
|
|
1679
3050
|
}
|
|
1680
3051
|
/**
|
|
1681
3052
|
* Get media buy delivery information
|
|
@@ -1685,12 +3056,28 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1685
3056
|
* @param options - Task execution options
|
|
1686
3057
|
*/
|
|
1687
3058
|
async getMediaBuyDelivery(params, inputHandler, options) {
|
|
3059
|
+
const { legacyFormatConverter, projectionCatalogs, ...taskOptions } = options ?? {};
|
|
1688
3060
|
return this.executeAndHandle(
|
|
1689
3061
|
"get_media_buy_delivery",
|
|
1690
3062
|
"onGetMediaBuyDeliveryStatusChange",
|
|
1691
3063
|
params,
|
|
1692
3064
|
inputHandler,
|
|
1693
|
-
|
|
3065
|
+
taskOptions,
|
|
3066
|
+
void 0,
|
|
3067
|
+
this.resolveLegacyFormatConverter(legacyFormatConverter, projectionCatalogs ?? this.config.projectionCatalogs)
|
|
3068
|
+
);
|
|
3069
|
+
}
|
|
3070
|
+
/** Retrieve canonical creative-level and variant-level delivery metrics. */
|
|
3071
|
+
async getCreativeDelivery(params, inputHandler, options) {
|
|
3072
|
+
const { legacyFormatConverter, ...taskOptions } = options ?? {};
|
|
3073
|
+
return this.executeAndHandle(
|
|
3074
|
+
"get_creative_delivery",
|
|
3075
|
+
"onGetCreativeDeliveryStatusChange",
|
|
3076
|
+
params,
|
|
3077
|
+
inputHandler,
|
|
3078
|
+
taskOptions,
|
|
3079
|
+
void 0,
|
|
3080
|
+
legacyFormatConverter
|
|
1694
3081
|
);
|
|
1695
3082
|
}
|
|
1696
3083
|
/**
|
|
@@ -1817,12 +3204,13 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1817
3204
|
}
|
|
1818
3205
|
// ====== CREATIVE BUILD TASKS ======
|
|
1819
3206
|
/**
|
|
1820
|
-
* Build a creative
|
|
3207
|
+
* Build a creative through the legacy named-format protocol.
|
|
3208
|
+
* @deprecated Migration-only access to `target_format_id`-based creative building.
|
|
1821
3209
|
*/
|
|
1822
|
-
async
|
|
3210
|
+
async buildCreativeLegacy(params, inputHandler, options) {
|
|
1823
3211
|
return this.executeAndHandle(
|
|
1824
3212
|
"build_creative",
|
|
1825
|
-
"
|
|
3213
|
+
"onBuildCreativeLegacyStatusChange",
|
|
1826
3214
|
params,
|
|
1827
3215
|
inputHandler,
|
|
1828
3216
|
options
|
|
@@ -1929,10 +3317,10 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1929
3317
|
/**
|
|
1930
3318
|
* List content standards
|
|
1931
3319
|
*/
|
|
1932
|
-
async
|
|
3320
|
+
async listContentStandardsLegacy(params, inputHandler, options) {
|
|
1933
3321
|
return this.executeAndHandle(
|
|
1934
3322
|
"list_content_standards",
|
|
1935
|
-
"
|
|
3323
|
+
"onListContentStandardsLegacyStatusChange",
|
|
1936
3324
|
params,
|
|
1937
3325
|
inputHandler,
|
|
1938
3326
|
options
|
|
@@ -1941,10 +3329,10 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1941
3329
|
/**
|
|
1942
3330
|
* Get content standards
|
|
1943
3331
|
*/
|
|
1944
|
-
async
|
|
3332
|
+
async getContentStandardsLegacy(params, inputHandler, options) {
|
|
1945
3333
|
return this.executeAndHandle(
|
|
1946
3334
|
"get_content_standards",
|
|
1947
|
-
"
|
|
3335
|
+
"onGetContentStandardsLegacyStatusChange",
|
|
1948
3336
|
params,
|
|
1949
3337
|
inputHandler,
|
|
1950
3338
|
options
|
|
@@ -1953,10 +3341,10 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1953
3341
|
/**
|
|
1954
3342
|
* Calibrate content against standards
|
|
1955
3343
|
*/
|
|
1956
|
-
async
|
|
3344
|
+
async calibrateContentLegacy(params, inputHandler, options) {
|
|
1957
3345
|
return this.executeAndHandle(
|
|
1958
3346
|
"calibrate_content",
|
|
1959
|
-
"
|
|
3347
|
+
"onCalibrateContentLegacyStatusChange",
|
|
1960
3348
|
params,
|
|
1961
3349
|
inputHandler,
|
|
1962
3350
|
options
|
|
@@ -1965,10 +3353,10 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
1965
3353
|
/**
|
|
1966
3354
|
* Validate content delivery
|
|
1967
3355
|
*/
|
|
1968
|
-
async
|
|
3356
|
+
async validateContentDeliveryLegacy(params, inputHandler, options) {
|
|
1969
3357
|
return this.executeAndHandle(
|
|
1970
3358
|
"validate_content_delivery",
|
|
1971
|
-
"
|
|
3359
|
+
"onValidateContentDeliveryLegacyStatusChange",
|
|
1972
3360
|
params,
|
|
1973
3361
|
inputHandler,
|
|
1974
3362
|
options
|
|
@@ -2023,25 +3411,62 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2023
3411
|
options
|
|
2024
3412
|
);
|
|
2025
3413
|
}
|
|
2026
|
-
|
|
3414
|
+
async executeTask(taskName, params, inputHandler, options) {
|
|
3415
|
+
switch (taskName) {
|
|
3416
|
+
case "get_products":
|
|
3417
|
+
return this.getProducts(params, inputHandler, options);
|
|
3418
|
+
case "create_media_buy":
|
|
3419
|
+
return await this.createMediaBuy(
|
|
3420
|
+
params,
|
|
3421
|
+
inputHandler,
|
|
3422
|
+
options
|
|
3423
|
+
);
|
|
3424
|
+
case "update_media_buy":
|
|
3425
|
+
return await this.updateMediaBuy(
|
|
3426
|
+
params,
|
|
3427
|
+
inputHandler,
|
|
3428
|
+
options
|
|
3429
|
+
);
|
|
3430
|
+
case "sync_creatives":
|
|
3431
|
+
return await this.syncCreatives(
|
|
3432
|
+
params,
|
|
3433
|
+
inputHandler,
|
|
3434
|
+
options
|
|
3435
|
+
);
|
|
3436
|
+
case "list_creatives":
|
|
3437
|
+
return this.listCreatives(params, inputHandler, options);
|
|
3438
|
+
case "get_media_buys":
|
|
3439
|
+
return this.getMediaBuys(params, inputHandler, options);
|
|
3440
|
+
case "get_media_buy_delivery":
|
|
3441
|
+
return this.getMediaBuyDelivery(params, inputHandler, options);
|
|
3442
|
+
case "get_creative_delivery":
|
|
3443
|
+
return this.getCreativeDelivery(params, inputHandler, options);
|
|
3444
|
+
}
|
|
3445
|
+
return this.executeTaskUnprojected(taskName, params, inputHandler, options);
|
|
3446
|
+
}
|
|
2027
3447
|
/**
|
|
2028
|
-
* Execute
|
|
2029
|
-
*
|
|
2030
|
-
* @param taskName - Name of the task to execute
|
|
2031
|
-
* @param params - Task parameters
|
|
2032
|
-
* @param inputHandler - Handler for clarification requests
|
|
2033
|
-
* @param options - Task execution options
|
|
3448
|
+
* Execute an extension task that is not part of the standard AdCP task set.
|
|
2034
3449
|
*
|
|
2035
|
-
*
|
|
2036
|
-
*
|
|
2037
|
-
*
|
|
2038
|
-
* 'get_products',
|
|
2039
|
-
* { brief: 'Coffee brands' },
|
|
2040
|
-
* handler
|
|
2041
|
-
* );
|
|
2042
|
-
* ```
|
|
3450
|
+
* Keeping custom tasks on an explicitly named API prevents a response-type
|
|
3451
|
+
* generic from weakening the canonical request types enforced by
|
|
3452
|
+
* `executeTask()` for standard creative-boundary tasks.
|
|
2043
3453
|
*/
|
|
2044
|
-
async
|
|
3454
|
+
async executeCustomTask(taskName, params, inputHandler, options) {
|
|
3455
|
+
if (STANDARD_ADCP_TASK_NAMES.has(taskName)) {
|
|
3456
|
+
throw new Error(
|
|
3457
|
+
`executeCustomTask() cannot execute standard AdCP task "${taskName}". Use its typed primary method, or an explicitly named *Legacy method for legacy creative tools.`
|
|
3458
|
+
);
|
|
3459
|
+
}
|
|
3460
|
+
return this.executeTaskUnprojected(taskName, params, inputHandler, options);
|
|
3461
|
+
}
|
|
3462
|
+
/**
|
|
3463
|
+
* Explicit raw-task compatibility escape hatch for conformance and migration tooling.
|
|
3464
|
+
* @deprecated Application code should use typed primary methods or `executeTask()`.
|
|
3465
|
+
*/
|
|
3466
|
+
async executeTaskLegacy(taskName, params, inputHandler, options) {
|
|
3467
|
+
return this.executeTaskUnprojected(taskName, params, inputHandler, options);
|
|
3468
|
+
}
|
|
3469
|
+
async executeTaskUnprojected(taskName, params, inputHandler, options) {
|
|
2045
3470
|
throwIfAborted(options?.signal);
|
|
2046
3471
|
const startTime = Date.now();
|
|
2047
3472
|
try {
|
|
@@ -2062,13 +3487,19 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2062
3487
|
if (!options?.skipIdempotencyAutoInject && !options?.skipAccountValidation) {
|
|
2063
3488
|
this.executor.validateRequest(taskName, normalizedParams);
|
|
2064
3489
|
}
|
|
2065
|
-
const
|
|
3490
|
+
const capabilityDiscoveryContext = {};
|
|
3491
|
+
const detectionOptions = {
|
|
3492
|
+
...options,
|
|
3493
|
+
[CAPABILITY_DISCOVERY_CONTEXT]: capabilityDiscoveryContext
|
|
3494
|
+
};
|
|
3495
|
+
const serverVersion = await this.detectServerVersion(detectionOptions);
|
|
2066
3496
|
const inputSchemaStripLogs = [];
|
|
2067
3497
|
const { params: adaptedParams, driftLogs: adaptDriftLogs } = this.adaptRequest(
|
|
2068
3498
|
taskName,
|
|
2069
3499
|
normalizedParams,
|
|
2070
3500
|
serverVersion,
|
|
2071
|
-
inputSchemaStripLogs
|
|
3501
|
+
inputSchemaStripLogs,
|
|
3502
|
+
capabilityDiscoveryContext.toolSchemas
|
|
2072
3503
|
);
|
|
2073
3504
|
const v25DriftLogs = [...adaptDriftLogs];
|
|
2074
3505
|
if (webhookDriftLog) v25DriftLogs.push(webhookDriftLog);
|
|
@@ -2090,8 +3521,10 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2090
3521
|
if (result.success && result.data) {
|
|
2091
3522
|
result.data = this.normalizeResponseToV3(taskName, result.data);
|
|
2092
3523
|
}
|
|
2093
|
-
result = this.wrapProductPolicySubmittedContinuation(result, taskName, normalizedParams);
|
|
2094
|
-
|
|
3524
|
+
result = this.wrapProductPolicySubmittedContinuation(result, taskName, normalizedParams, options);
|
|
3525
|
+
if (result.status === "working") {
|
|
3526
|
+
this.rememberProductPolicyRequestParams(taskName, normalizedParams, result, options);
|
|
3527
|
+
}
|
|
2095
3528
|
result = await this.applyProductPropertyPolicy(result, taskName, normalizedParams);
|
|
2096
3529
|
return result;
|
|
2097
3530
|
} catch (error) {
|
|
@@ -2169,19 +3602,58 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2169
3602
|
*/
|
|
2170
3603
|
async continueConversation(message, contextId, inputHandler) {
|
|
2171
3604
|
const agent = await this.ensureEndpointDiscovered();
|
|
2172
|
-
|
|
3605
|
+
const creativeAssociation = this.canonicalCreativeTaskAssociation(contextId);
|
|
3606
|
+
if (!creativeAssociation) {
|
|
3607
|
+
return this.executor.executeTask(agent, "continue_conversation", { message }, inputHandler, { contextId });
|
|
3608
|
+
}
|
|
3609
|
+
const { taskType: creativeTaskType } = creativeAssociation;
|
|
3610
|
+
const legacyFormatConverter = this.resolveLegacyFormatConverter(creativeAssociation.legacyFormatConverter);
|
|
3611
|
+
const result = await canonicalCreativeExecutionStorage.run(
|
|
3612
|
+
{ taskType: creativeTaskType, legacyFormatConverter },
|
|
3613
|
+
() => this.executor.executeTask(
|
|
3614
|
+
agent,
|
|
3615
|
+
"continue_conversation",
|
|
3616
|
+
{ message },
|
|
3617
|
+
this.canonicalCreativeInputHandler(creativeTaskType, inputHandler),
|
|
3618
|
+
{ contextId }
|
|
3619
|
+
)
|
|
3620
|
+
);
|
|
3621
|
+
const canonical = this.canonicalizeCreativeTaskResult(result, creativeTaskType, void 0, legacyFormatConverter);
|
|
3622
|
+
this.rememberCanonicalCreativeTaskIds(
|
|
3623
|
+
canonical,
|
|
3624
|
+
creativeTaskType,
|
|
3625
|
+
legacyFormatConverter,
|
|
3626
|
+
creativeAssociation.routingSnapshot
|
|
3627
|
+
);
|
|
3628
|
+
return this.wrapCanonicalCreativeContinuations(
|
|
3629
|
+
canonical,
|
|
3630
|
+
creativeTaskType,
|
|
3631
|
+
void 0,
|
|
3632
|
+
legacyFormatConverter,
|
|
3633
|
+
creativeAssociation.routingSnapshot
|
|
3634
|
+
);
|
|
2173
3635
|
}
|
|
2174
3636
|
/**
|
|
2175
3637
|
* Get conversation history for a task
|
|
2176
3638
|
*/
|
|
2177
3639
|
getConversationHistory(taskId) {
|
|
2178
|
-
|
|
3640
|
+
const history = this.executor.getConversationHistory(taskId);
|
|
3641
|
+
const association = this.canonicalCreativeTaskAssociation(taskId);
|
|
3642
|
+
if (!association) return history;
|
|
3643
|
+
const { taskType } = association;
|
|
3644
|
+
const converter = this.resolveLegacyFormatConverter(association.legacyFormatConverter);
|
|
3645
|
+
return history?.map((message) => ({
|
|
3646
|
+
...message,
|
|
3647
|
+
content: projectCanonicalCreativeAncillaryValue(message.content, taskType, converter)
|
|
3648
|
+
}));
|
|
2179
3649
|
}
|
|
2180
3650
|
/**
|
|
2181
3651
|
* Clear conversation history for a task
|
|
2182
3652
|
*/
|
|
2183
3653
|
clearConversationHistory(taskId) {
|
|
2184
3654
|
this.executor.clearConversationHistory(taskId);
|
|
3655
|
+
this.forgetCanonicalCreativeTaskAssociationKeys([taskId]);
|
|
3656
|
+
this.productPolicyRequestParamsByTask.delete(taskId);
|
|
2185
3657
|
}
|
|
2186
3658
|
// ====== AGENT INFORMATION ======
|
|
2187
3659
|
/**
|
|
@@ -2322,7 +3794,23 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2322
3794
|
* Get active tasks for this agent
|
|
2323
3795
|
*/
|
|
2324
3796
|
getActiveTasks() {
|
|
2325
|
-
return this.executor.getActiveTasks().filter((task) => task.agent.id === this.agent.id)
|
|
3797
|
+
return this.executor.getActiveTasks().filter((task) => task.agent.id === this.agent.id).map((task) => {
|
|
3798
|
+
if (!CANONICAL_CREATIVE_ACTIVITY_TASKS.has(task.taskName)) return task;
|
|
3799
|
+
const converter = this.resolveLegacyFormatConverter(
|
|
3800
|
+
this.canonicalCreativeTaskAssociation(task.taskId)?.legacyFormatConverter
|
|
3801
|
+
);
|
|
3802
|
+
return stripLegacyCreativeIdentity({
|
|
3803
|
+
...task,
|
|
3804
|
+
params: projectCanonicalCreativeAncillaryValue(task.params, task.taskName, converter),
|
|
3805
|
+
messages: task.messages.map((message) => ({
|
|
3806
|
+
...message,
|
|
3807
|
+
content: projectCanonicalCreativeAncillaryValue(message.content, task.taskName, converter)
|
|
3808
|
+
})),
|
|
3809
|
+
...task.pendingInput !== void 0 && {
|
|
3810
|
+
pendingInput: projectCanonicalCreativeAncillaryValue(task.pendingInput, task.taskName, converter)
|
|
3811
|
+
}
|
|
3812
|
+
});
|
|
3813
|
+
});
|
|
2326
3814
|
}
|
|
2327
3815
|
// ====== TASK MANAGEMENT & NOTIFICATIONS ======
|
|
2328
3816
|
/**
|
|
@@ -2339,7 +3827,15 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2339
3827
|
* ```
|
|
2340
3828
|
*/
|
|
2341
3829
|
async listTasks() {
|
|
2342
|
-
|
|
3830
|
+
const tasks = await this.executor.getTaskList(this.agent.id);
|
|
3831
|
+
return tasks.map(
|
|
3832
|
+
(task) => CANONICAL_CREATIVE_ACTIVITY_TASKS.has(task.taskType) ? this.canonicalizeCreativeTaskInfo(
|
|
3833
|
+
task,
|
|
3834
|
+
task.taskType,
|
|
3835
|
+
void 0,
|
|
3836
|
+
this.resolveLegacyFormatConverter(this.canonicalCreativeTaskAssociation(task.taskId)?.legacyFormatConverter)
|
|
3837
|
+
) : task
|
|
3838
|
+
);
|
|
2343
3839
|
}
|
|
2344
3840
|
/**
|
|
2345
3841
|
* Get detailed information about a specific task
|
|
@@ -2348,7 +3844,13 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2348
3844
|
* @returns Promise resolving to task information
|
|
2349
3845
|
*/
|
|
2350
3846
|
async getTaskInfo(taskId) {
|
|
2351
|
-
|
|
3847
|
+
const task = await this.executor.getTaskInfo(taskId);
|
|
3848
|
+
return task && CANONICAL_CREATIVE_ACTIVITY_TASKS.has(task.taskType) ? this.canonicalizeCreativeTaskInfo(
|
|
3849
|
+
task,
|
|
3850
|
+
task.taskType,
|
|
3851
|
+
void 0,
|
|
3852
|
+
this.resolveLegacyFormatConverter(this.canonicalCreativeTaskAssociation(task.taskId)?.legacyFormatConverter)
|
|
3853
|
+
) : task;
|
|
2352
3854
|
}
|
|
2353
3855
|
/**
|
|
2354
3856
|
* Subscribe to task notifications for this agent
|
|
@@ -2370,7 +3872,19 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2370
3872
|
* ```
|
|
2371
3873
|
*/
|
|
2372
3874
|
onTaskUpdate(callback) {
|
|
2373
|
-
return this.executor.onTaskUpdate(
|
|
3875
|
+
return this.executor.onTaskUpdate(
|
|
3876
|
+
this.agent.id,
|
|
3877
|
+
(task) => callback(
|
|
3878
|
+
CANONICAL_CREATIVE_ACTIVITY_TASKS.has(task.taskType) ? this.canonicalizeCreativeTaskInfo(
|
|
3879
|
+
task,
|
|
3880
|
+
task.taskType,
|
|
3881
|
+
void 0,
|
|
3882
|
+
this.resolveLegacyFormatConverter(
|
|
3883
|
+
this.canonicalCreativeTaskAssociation(task.taskId)?.legacyFormatConverter
|
|
3884
|
+
)
|
|
3885
|
+
) : task
|
|
3886
|
+
)
|
|
3887
|
+
);
|
|
2374
3888
|
}
|
|
2375
3889
|
/**
|
|
2376
3890
|
* Subscribe to all task events (create, update, complete, error)
|
|
@@ -2379,7 +3893,23 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2379
3893
|
* @returns Unsubscribe function
|
|
2380
3894
|
*/
|
|
2381
3895
|
onTaskEvents(callbacks) {
|
|
2382
|
-
|
|
3896
|
+
const safe = (task) => CANONICAL_CREATIVE_ACTIVITY_TASKS.has(task.taskType) ? this.canonicalizeCreativeTaskInfo(
|
|
3897
|
+
task,
|
|
3898
|
+
task.taskType,
|
|
3899
|
+
void 0,
|
|
3900
|
+
this.resolveLegacyFormatConverter(this.canonicalCreativeTaskAssociation(task.taskId)?.legacyFormatConverter)
|
|
3901
|
+
) : task;
|
|
3902
|
+
return this.executor.onTaskEvents(this.agent.id, {
|
|
3903
|
+
...callbacks.onTaskCreated && { onTaskCreated: (task) => callbacks.onTaskCreated(safe(task)) },
|
|
3904
|
+
...callbacks.onTaskUpdated && { onTaskUpdated: (task) => callbacks.onTaskUpdated(safe(task)) },
|
|
3905
|
+
...callbacks.onTaskCompleted && { onTaskCompleted: (task) => callbacks.onTaskCompleted(safe(task)) },
|
|
3906
|
+
...callbacks.onTaskFailed && {
|
|
3907
|
+
onTaskFailed: (task, error) => {
|
|
3908
|
+
const safeTask = safe(task);
|
|
3909
|
+
callbacks.onTaskFailed(safeTask, safeTask.error ?? stripLegacyCreativeIdentity(error));
|
|
3910
|
+
}
|
|
3911
|
+
}
|
|
3912
|
+
});
|
|
2383
3913
|
}
|
|
2384
3914
|
/**
|
|
2385
3915
|
* Register webhook URL for receiving task notifications
|
|
@@ -2443,6 +3973,16 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2443
3973
|
...options?.signal && { signal: options.signal },
|
|
2444
3974
|
...clientRequestTimeoutMs !== void 0 && { timeout: clientRequestTimeoutMs }
|
|
2445
3975
|
};
|
|
3976
|
+
const ensureReadAuthToken = async () => {
|
|
3977
|
+
if (!this.normalizedAgent.oauth_client_credentials) return this.normalizedAgent.auth_token;
|
|
3978
|
+
const { ensureClientCredentialsTokens, getAgentStorage } = await import("../auth/oauth/index.mjs");
|
|
3979
|
+
await ensureClientCredentialsTokens(this.normalizedAgent, {
|
|
3980
|
+
storage: getAgentStorage(this.normalizedAgent),
|
|
3981
|
+
allowPrivateIp: isLikelyPrivateUrl(this.normalizedAgent.agent_uri),
|
|
3982
|
+
fetch: transport?.fetchFn
|
|
3983
|
+
});
|
|
3984
|
+
return this.normalizedAgent.oauth_tokens?.access_token;
|
|
3985
|
+
};
|
|
2446
3986
|
if (this.normalizedAgent.protocol === "mcp") {
|
|
2447
3987
|
if (this.normalizedAgent._inProcessMcpClient) {
|
|
2448
3988
|
const mcpClient2 = this.normalizedAgent._inProcessMcpClient;
|
|
@@ -2464,6 +4004,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2464
4004
|
tools
|
|
2465
4005
|
};
|
|
2466
4006
|
}
|
|
4007
|
+
const readAuthToken = await ensureReadAuthToken();
|
|
2467
4008
|
const agent = await this.ensureEndpointDiscovered(options);
|
|
2468
4009
|
const { connectMCP } = await import("../protocols/mcp.mjs");
|
|
2469
4010
|
const { tryListModernMCPTools } = await import("../protocols/mcp-modern.mjs");
|
|
@@ -2474,25 +4015,32 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2474
4015
|
if (transport?.requestTimeoutMs !== void 0) {
|
|
2475
4016
|
connectOptions.requestTimeoutMs = transport.requestTimeoutMs;
|
|
2476
4017
|
}
|
|
4018
|
+
if (transport?.fetchFn) {
|
|
4019
|
+
connectOptions.fetchFn = transport.fetchFn;
|
|
4020
|
+
}
|
|
2477
4021
|
if (this.normalizedAgent.headers && Object.keys(this.normalizedAgent.headers).length > 0) {
|
|
2478
4022
|
connectOptions.customHeaders = this.normalizedAgent.headers;
|
|
2479
4023
|
}
|
|
2480
4024
|
let authProvider;
|
|
2481
|
-
if (this.normalizedAgent.oauth_tokens) {
|
|
2482
|
-
const {
|
|
2483
|
-
|
|
2484
|
-
|
|
4025
|
+
if (this.normalizedAgent.oauth_tokens && !this.normalizedAgent.oauth_client_credentials) {
|
|
4026
|
+
const { getAgentStorage } = await import("../auth/oauth/index.mjs");
|
|
4027
|
+
const { getNonInteractiveOAuthProvider } = await import("../auth/oauth/provider-cache.mjs");
|
|
4028
|
+
authProvider = getNonInteractiveOAuthProvider(this.normalizedAgent, {
|
|
4029
|
+
agentHint: this.normalizedAgent.id,
|
|
4030
|
+
storage: getAgentStorage(this.normalizedAgent),
|
|
4031
|
+
allowHttp: isLikelyPrivateUrl(this.normalizedAgent.agent_uri)
|
|
2485
4032
|
});
|
|
2486
4033
|
connectOptions.authProvider = authProvider;
|
|
2487
|
-
} else if (
|
|
2488
|
-
connectOptions.authToken =
|
|
4034
|
+
} else if (readAuthToken) {
|
|
4035
|
+
connectOptions.authToken = readAuthToken;
|
|
2489
4036
|
}
|
|
2490
|
-
const modernTools = this.discoveredMcpEra === "legacy" && Date.now() - this.discoveredMcpEraAt < 5 * 60 * 1e3 ? { handled: false } : await withResponseSizeLimit(
|
|
4037
|
+
const modernTools = !transport?.fetchFn && this.discoveredMcpEra === "legacy" && Date.now() - this.discoveredMcpEraAt < 5 * 60 * 1e3 ? { handled: false } : await withResponseSizeLimit(
|
|
2491
4038
|
maxResponseBytes,
|
|
2492
|
-
() => tryListModernMCPTools(agent.agent_uri,
|
|
4039
|
+
() => tryListModernMCPTools(agent.agent_uri, readAuthToken, this.normalizedAgent.headers, {
|
|
2493
4040
|
authProvider,
|
|
2494
4041
|
signal: options?.signal,
|
|
2495
|
-
requestTimeoutMs: transport?.requestTimeoutMs
|
|
4042
|
+
requestTimeoutMs: transport?.requestTimeoutMs,
|
|
4043
|
+
fetchFn: transport?.fetchFn
|
|
2496
4044
|
})
|
|
2497
4045
|
);
|
|
2498
4046
|
if (modernTools.handled) {
|
|
@@ -2537,9 +4085,11 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2537
4085
|
}
|
|
2538
4086
|
} else if (this.normalizedAgent.protocol === "a2a") {
|
|
2539
4087
|
const { wrapFetchWithSizeLimit } = await import("../protocols/responseSizeLimit.mjs");
|
|
2540
|
-
const authToken =
|
|
4088
|
+
const authToken = await ensureReadAuthToken();
|
|
2541
4089
|
const agentHeaders = this.normalizedAgent.headers ?? {};
|
|
2542
|
-
const sizeLimitedFetch = wrapFetchWithSizeLimit(
|
|
4090
|
+
const sizeLimitedFetch = wrapFetchWithSizeLimit(
|
|
4091
|
+
(input, init) => transport?.fetchFn ? transport.fetchFn(input, init) : fetch(input, init)
|
|
4092
|
+
);
|
|
2543
4093
|
const normalizeHeaders = (headers) => {
|
|
2544
4094
|
const normalized = {};
|
|
2545
4095
|
if (!headers) return normalized;
|
|
@@ -2630,7 +4180,10 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2630
4180
|
*/
|
|
2631
4181
|
async getCapabilities(options) {
|
|
2632
4182
|
throwIfAborted(options?.signal);
|
|
2633
|
-
|
|
4183
|
+
const discoveryContext = options?.[CAPABILITY_DISCOVERY_CONTEXT];
|
|
4184
|
+
const usesScopedFetch = (options?.transport ?? this.config.transport)?.fetchFn !== void 0;
|
|
4185
|
+
if (!usesScopedFetch && this.cachedCapabilities) {
|
|
4186
|
+
if (discoveryContext) discoveryContext.toolSchemas = this.cachedToolSchemas;
|
|
2634
4187
|
this.maybeWarnV2Sunset(this.cachedCapabilities);
|
|
2635
4188
|
return this.cachedCapabilities;
|
|
2636
4189
|
}
|
|
@@ -2639,10 +4192,14 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2639
4192
|
name: t.name,
|
|
2640
4193
|
description: t.description
|
|
2641
4194
|
}));
|
|
2642
|
-
|
|
4195
|
+
const discoveredToolSchemas = new Map(
|
|
2643
4196
|
agentInfo.tools.filter((t) => t.inputSchema?.properties).map((t) => [t.name, t.inputSchema.properties])
|
|
2644
4197
|
);
|
|
2645
|
-
|
|
4198
|
+
if (discoveryContext) discoveryContext.toolSchemas = discoveredToolSchemas;
|
|
4199
|
+
if (!usesScopedFetch) this.cachedToolSchemas = discoveredToolSchemas;
|
|
4200
|
+
const advertisesCapabilitiesTool = tools.some((t) => t.name === "get_adcp_capabilities");
|
|
4201
|
+
const officialA2ALifecycle = this.normalizedAgent.protocol === "a2a" && tools.some((tool) => ["tasks/get", "get_task_status", "list_tasks"].includes(tool.name));
|
|
4202
|
+
const hasCapabilitiesTool = advertisesCapabilitiesTool || officialA2ALifecycle;
|
|
2646
4203
|
if (hasCapabilitiesTool) {
|
|
2647
4204
|
try {
|
|
2648
4205
|
const agent = await this.ensureEndpointDiscovered(options);
|
|
@@ -2655,9 +4212,13 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2655
4212
|
throw createTimeoutError(requestTimeoutMs);
|
|
2656
4213
|
}
|
|
2657
4214
|
if (result.success && result.data) {
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
4215
|
+
const capabilities2 = augmentCapabilitiesFromTools(parseCapabilitiesResponse(result.data), tools);
|
|
4216
|
+
if (!usesScopedFetch) this.cachedCapabilities = capabilities2;
|
|
4217
|
+
this.maybeWarnV2Sunset(capabilities2);
|
|
4218
|
+
return capabilities2;
|
|
4219
|
+
}
|
|
4220
|
+
if (!advertisesCapabilitiesTool) {
|
|
4221
|
+
throw new Error("unadvertised official A2A capability probe was not supported");
|
|
2661
4222
|
}
|
|
2662
4223
|
if (result.data && looksLikeV3Capabilities(result.data)) {
|
|
2663
4224
|
console.warn(
|
|
@@ -2670,9 +4231,10 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2670
4231
|
version: "v3",
|
|
2671
4232
|
majorVersions: parsed.majorVersions.includes(3) ? parsed.majorVersions : [3]
|
|
2672
4233
|
};
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
4234
|
+
const capabilities2 = augmentCapabilitiesFromTools(v3Capabilities, tools);
|
|
4235
|
+
if (!usesScopedFetch) this.cachedCapabilities = capabilities2;
|
|
4236
|
+
this.maybeWarnV2Sunset(capabilities2);
|
|
4237
|
+
return capabilities2;
|
|
2676
4238
|
}
|
|
2677
4239
|
console.warn(
|
|
2678
4240
|
`[AdCP] Agent "${this.agent.id}" advertises get_adcp_capabilities but the call returned non-success and the response is not v3-shaped \u2014 treating as v3 (synthetic) since the agent has the v3-only discovery tool. This client routes to v3 adapters, but calls reading capability details (idempotency TTL, supported_versions, feature flags) will fail until the agent operator fixes the capabilities endpoint.`,
|
|
@@ -2686,19 +4248,25 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
2686
4248
|
if (error instanceof AuthenticationRequiredError || error instanceof TaskTimeoutError || isAbortOrTimeoutError(error)) {
|
|
2687
4249
|
throw error;
|
|
2688
4250
|
}
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
4251
|
+
if (advertisesCapabilitiesTool) {
|
|
4252
|
+
console.warn(
|
|
4253
|
+
`[AdCP] Agent "${this.agent.id}" advertises get_adcp_capabilities but the call threw \u2014 treating as v3 (synthetic) since the agent has the v3-only discovery tool. This client routes to v3 adapters, but calls reading capability details (idempotency TTL, supported_versions, feature flags) will fail until the agent operator fixes the capabilities endpoint.`
|
|
4254
|
+
);
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
if (advertisesCapabilitiesTool) {
|
|
4258
|
+
const capabilities2 = augmentCapabilitiesFromTools(buildSyntheticV3Capabilities(tools), tools);
|
|
4259
|
+
if (!usesScopedFetch) this.cachedCapabilities = capabilities2;
|
|
4260
|
+
this.maybeWarnV2Sunset(capabilities2);
|
|
4261
|
+
return capabilities2;
|
|
2692
4262
|
}
|
|
2693
|
-
this.cachedCapabilities = augmentCapabilitiesFromTools(buildSyntheticV3Capabilities(tools), tools);
|
|
2694
|
-
this.maybeWarnV2Sunset(this.cachedCapabilities);
|
|
2695
|
-
return this.cachedCapabilities;
|
|
2696
4263
|
}
|
|
2697
4264
|
console.warn(
|
|
2698
4265
|
`[AdCP] Agent "${this.agent.id}" detected as v2 (no get_adcp_capabilities tool). Tools: [${tools.map((t) => t.name).join(", ")}]`
|
|
2699
4266
|
);
|
|
2700
|
-
|
|
2701
|
-
|
|
4267
|
+
const capabilities = buildSyntheticCapabilities(tools);
|
|
4268
|
+
if (!usesScopedFetch) this.cachedCapabilities = capabilities;
|
|
4269
|
+
return capabilities;
|
|
2702
4270
|
}
|
|
2703
4271
|
/**
|
|
2704
4272
|
* Emit a one-time warning when the agent reports v2 capabilities.
|
|
@@ -3011,38 +4579,18 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
3011
4579
|
}
|
|
3012
4580
|
// ====== STATIC HELPER METHODS ======
|
|
3013
4581
|
/**
|
|
3014
|
-
* Query a creative
|
|
4582
|
+
* Query a legacy creative-agent named-format catalog.
|
|
3015
4583
|
*
|
|
3016
|
-
*
|
|
3017
|
-
* (
|
|
3018
|
-
* before creating a media buy.
|
|
4584
|
+
* Canonical applications discover seller-supported declarations through
|
|
4585
|
+
* `AgentClient.getProducts()` and consume `format_options[]` instead.
|
|
3019
4586
|
*
|
|
3020
4587
|
* @param creativeAgentUrl - URL of the creative agent (e.g., 'https://creative.adcontextprotocol.org/mcp')
|
|
3021
4588
|
* @param protocol - Protocol to use ('mcp' or 'a2a'), defaults to 'mcp'
|
|
3022
4589
|
* @returns Promise resolving to the list of available formats
|
|
3023
4590
|
*
|
|
3024
|
-
* @
|
|
3025
|
-
* ```typescript
|
|
3026
|
-
* // Discover formats from the standard creative agent
|
|
3027
|
-
* const formats = await SingleAgentClient.discoverCreativeFormats(
|
|
3028
|
-
* 'https://creative.adcontextprotocol.org/mcp'
|
|
3029
|
-
* );
|
|
3030
|
-
*
|
|
3031
|
-
* // Find a specific format
|
|
3032
|
-
* const banner = formats.find(f => f.format_id.id === 'display_300x250_image');
|
|
3033
|
-
*
|
|
3034
|
-
* // Use the format in a media buy
|
|
3035
|
-
* await salesAgent.createMediaBuy({
|
|
3036
|
-
* packages: [{
|
|
3037
|
-
* format_ids: [{
|
|
3038
|
-
* agent_url: banner.format_id.agent_url,
|
|
3039
|
-
* id: banner.format_id.id
|
|
3040
|
-
* }]
|
|
3041
|
-
* }]
|
|
3042
|
-
* });
|
|
3043
|
-
* ```
|
|
4591
|
+
* @deprecated Migration-only helper for the legacy named-format protocol.
|
|
3044
4592
|
*/
|
|
3045
|
-
static async
|
|
4593
|
+
static async discoverCreativeFormatsLegacy(creativeAgentUrl, protocol = "mcp") {
|
|
3046
4594
|
const client = new SingleAgentClient(
|
|
3047
4595
|
{
|
|
3048
4596
|
id: "creative_agent_discovery",
|
|
@@ -3052,7 +4600,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
3052
4600
|
},
|
|
3053
4601
|
{}
|
|
3054
4602
|
);
|
|
3055
|
-
const result = await client.
|
|
4603
|
+
const result = await client.listCreativeFormatsLegacy({});
|
|
3056
4604
|
if (!result.success || !result.data) {
|
|
3057
4605
|
throw new Error(`Failed to discover creative formats: ${result.error || "Unknown error"}`);
|
|
3058
4606
|
}
|
|
@@ -3132,12 +4680,11 @@ function parseWebhookBody(value) {
|
|
|
3132
4680
|
const raw = Buffer.isBuffer(value) || value instanceof Uint8Array ? Buffer.from(value).toString("utf8") : value;
|
|
3133
4681
|
try {
|
|
3134
4682
|
return { ok: true, payload: JSON.parse(raw) };
|
|
3135
|
-
} catch
|
|
4683
|
+
} catch {
|
|
3136
4684
|
return {
|
|
3137
4685
|
ok: false,
|
|
3138
4686
|
code: "webhook_envelope_invalid",
|
|
3139
|
-
message: "Webhook body must be valid JSON."
|
|
3140
|
-
cause: error
|
|
4687
|
+
message: "Webhook body must be valid JSON."
|
|
3141
4688
|
};
|
|
3142
4689
|
}
|
|
3143
4690
|
}
|
|
@@ -3158,13 +4705,6 @@ function missingMcpWebhookFields(payload) {
|
|
|
3158
4705
|
return typeof value !== "string" || value.length === 0;
|
|
3159
4706
|
});
|
|
3160
4707
|
}
|
|
3161
|
-
function safeJsonPreview(value) {
|
|
3162
|
-
try {
|
|
3163
|
-
return JSON.stringify(value).substring(0, 200);
|
|
3164
|
-
} catch {
|
|
3165
|
-
return "[unserializable payload]";
|
|
3166
|
-
}
|
|
3167
|
-
}
|
|
3168
4708
|
function webhookErrorHttpStatus(error) {
|
|
3169
4709
|
if (error instanceof WebhookDispatchError) {
|
|
3170
4710
|
if (error.code === "webhook_signature_invalid" || error.code === "webhook_timestamp_invalid") {
|