@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
|
@@ -189,7 +189,7 @@ async function testSchemaCompliance(agentUrl, options) {
|
|
|
189
189
|
const { result: formatsResult, step: formatsStep } = await (0, import_client.runStep)(
|
|
190
190
|
"Get creative formats (check assets structure)",
|
|
191
191
|
"list_creative_formats",
|
|
192
|
-
async () => client.
|
|
192
|
+
async () => client.listCreativeFormatsLegacy({})
|
|
193
193
|
);
|
|
194
194
|
if (formatsResult?.success && formatsResult?.data) {
|
|
195
195
|
steps.push((0, import_client.validateResponseSchema)("list_creative_formats", formatsResult.data));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/testing/scenarios/schema-compliance.ts"],"sourcesContent":["/**\n * Schema Compliance Testing\n *\n * Validates that an agent's responses use correct v3 field names and enum values.\n * Uses GET-only operations — no writes required.\n *\n * Checks:\n * - Channel enum values (hard fail on invalid values)\n * - Pricing field names: fixed_price (not fixed_rate), floor_price top-level\n * - Format assets: assets array with required boolean (not assets_required)\n */\n\nimport type { Product } from '../../types/core.generated';\nimport type {\n GetProductsResponse,\n GetSignalsResponse,\n ListCreativeFormatsResponse,\n Format,\n} from '../../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile, validateResponseSchema } from '../client';\n\n// v3 channel taxonomy — 19 channels\nconst V3_CHANNELS = new Set([\n 'display',\n 'olv',\n 'social',\n 'search',\n 'ctv',\n 'linear_tv',\n 'radio',\n 'streaming_audio',\n 'podcast',\n 'dooh',\n 'ooh',\n 'print',\n 'cinema',\n 'email',\n 'gaming',\n 'retail_media',\n 'influencer',\n 'affiliate',\n 'product_placement',\n]);\n\nexport async function testSchemaCompliance(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n if (!profile.tools.includes('get_products') && !profile.tools.includes('get_signals')) {\n // Path A: no supported discovery tool — skip field-shape checks gracefully\n steps.push({\n step: 'Schema compliance check support',\n passed: true,\n duration_ms: 0,\n details: 'Agent does not advertise get_products or get_signals — discovery field-shape checks skipped',\n warnings: ['Schema compliance: no supported discovery tool (get_products, get_signals) found; checks skipped'],\n });\n // Fall through to list_creative_formats check below\n } else if (profile.tools.includes('get_signals') && !profile.tools.includes('get_products')) {\n // Path B: signals agent — validate GetSignalsResponse schema and field semantics\n const { result: signalsResult, step: signalsStep } = await runStep<TaskResult>(\n 'Get signals (schema compliance)',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Schema compliance test — retrieve all available signals',\n }) as Promise<TaskResult>\n );\n\n if (!signalsResult?.success || !signalsResult?.data) {\n signalsStep.passed = false;\n signalsStep.error = signalsResult?.error || 'get_signals returned no data';\n steps.push(signalsStep);\n return { steps, profile };\n }\n steps.push(signalsStep);\n\n const signalsData = signalsResult.data as GetSignalsResponse;\n // Zod schema validation covers required-field presence (signal_agent_segment_id, name, signal_type).\n steps.push(validateResponseSchema('get_signals', signalsData));\n\n const signals = signalsData.signals ?? [];\n steps.push({\n step: 'Validate signal required fields',\n passed: true,\n duration_ms: 0,\n details:\n signals.length === 0\n ? 'Agent returned no signals — field-shape checks skipped'\n : `${signals.length} signal(s) validated via schema check (signal_agent_segment_id, name, signal_type)`,\n warnings:\n signals.length === 0\n ? ['No signals returned; cannot validate signal_agent_segment_id, name, signal_type fields']\n : undefined,\n });\n // Fall through to list_creative_formats check below\n } else {\n // Path C: get_products present — existing product catalog checks\n const { result: productsResult, step: productsStep } = await runStep<TaskResult>(\n 'Get products (schema compliance)',\n 'get_products',\n async () =>\n client.getProducts({\n buying_mode: 'brief',\n brief: options.brief || 'Schema compliance test — retrieve all available products',\n brand: options.brand,\n }) as Promise<TaskResult>\n );\n\n if (!productsResult?.success || !productsResult?.data) {\n productsStep.passed = false;\n productsStep.error = productsResult?.error || 'get_products returned no data';\n steps.push(productsStep);\n return { steps, profile };\n }\n steps.push(productsStep);\n\n const data = productsResult.data as GetProductsResponse;\n const products: Product[] = data.products || [];\n\n // --- Zod schema validation (catches missing required fields + invalid enum values) ---\n steps.push(validateResponseSchema('get_products', data));\n\n if (products.length === 0) {\n steps.push({\n step: 'Schema compliance: no products to validate',\n passed: true,\n duration_ms: 0,\n details: 'Agent returned no products — schema compliance checks skipped',\n warnings: ['No products returned; cannot validate channel, pricing, or format field schemas'],\n });\n return { steps, profile };\n }\n\n // --- Channel enum validation (hard fail) ---\n const invalidChannels: string[] = [];\n const allChannels = new Set<string>();\n\n for (const product of products) {\n for (const channel of product.channels || []) {\n allChannels.add(channel);\n if (!V3_CHANNELS.has(channel)) {\n invalidChannels.push(`\"${channel}\" in product ${product.product_id}`);\n }\n }\n }\n\n steps.push({\n step: 'Validate channel enum values',\n passed: invalidChannels.length === 0,\n duration_ms: 0,\n details:\n invalidChannels.length === 0\n ? `All ${allChannels.size} channel value(s) are valid v3 channels: ${Array.from(allChannels).join(', ')}`\n : `Invalid channel values detected (not in v3 taxonomy): ${invalidChannels.join('; ')}`,\n error:\n invalidChannels.length > 0\n ? `Channel enum violations: ${invalidChannels.join('; ')}. Valid channels: ${Array.from(V3_CHANNELS).join(', ')}`\n : undefined,\n response_preview: JSON.stringify(\n {\n channels_found: Array.from(allChannels),\n invalid_channels: invalidChannels,\n },\n null,\n 2\n ),\n });\n\n // --- Pricing field name validation (warn, not fail) ---\n const pricingIssues: string[] = [];\n const pricingChecked: string[] = [];\n let fixedPriceFound = false;\n\n for (const product of products) {\n for (const option of product.pricing_options || []) {\n const optionId = option.pricing_option_id || '(unknown)';\n // Cast to Record for deprecated-field checks — compliance testing intentionally\n // probes fields that may not exist on the generated PricingOption union\n const raw = option as unknown as Record<string, unknown>;\n\n // Check for deprecated fixed_rate field\n if ('fixed_rate' in raw) {\n pricingIssues.push(`pricing_option ${optionId} uses deprecated \"fixed_rate\" — should be \"fixed_price\"`);\n }\n if ('fixed_price' in raw) {\n fixedPriceFound = true;\n pricingChecked.push(optionId);\n }\n\n // Check for floor_price inside price_guidance (deprecated location)\n const pg = raw.price_guidance as Record<string, unknown> | undefined;\n if (pg && 'floor' in pg) {\n pricingIssues.push(\n `pricing_option ${optionId} has \"floor\" inside price_guidance — should be top-level \"floor_price\"`\n );\n }\n if ('floor_price' in raw) {\n pricingChecked.push(`${optionId} (floor_price)`);\n }\n }\n }\n\n const pricingPassed = pricingIssues.length === 0;\n const pricingDetails =\n pricingIssues.length > 0\n ? `Pricing field issues: ${pricingIssues.join('; ')}`\n : fixedPriceFound\n ? `Pricing fields valid (checked ${pricingChecked.length} option(s))`\n : 'No fixed-price products found to validate (agent may be auction-only — cannot confirm field names)';\n\n steps.push({\n step: 'Validate pricing field names',\n passed: pricingPassed,\n duration_ms: 0,\n details: pricingDetails,\n error: pricingIssues.length > 0 ? pricingIssues.join('; ') : undefined,\n warnings:\n !fixedPriceFound && pricingIssues.length === 0\n ? [\n 'No fixed-price products found. If agent supports fixed pricing, verify it uses \"fixed_price\" (not \"fixed_rate\") and \"floor_price\" at the pricing option level (not inside price_guidance).',\n ]\n : undefined,\n response_preview: JSON.stringify(\n {\n issues: pricingIssues,\n options_checked: pricingChecked,\n },\n null,\n 2\n ),\n });\n }\n\n // --- Format assets structure (optional: list_creative_formats) ---\n // Runs for all agent types that advertise list_creative_formats, regardless of discovery path\n if (profile.tools.includes('list_creative_formats')) {\n const { result: formatsResult, step: formatsStep } = await runStep<TaskResult>(\n 'Get creative formats (check assets structure)',\n 'list_creative_formats',\n async () => client.listCreativeFormats({}) as Promise<TaskResult>\n );\n\n if (formatsResult?.success && formatsResult?.data) {\n steps.push(validateResponseSchema('list_creative_formats', formatsResult.data));\n const formatsData = formatsResult.data as ListCreativeFormatsResponse;\n const formats: Format[] = formatsData.formats || [];\n const assetsIssues: string[] = [];\n let formatsChecked = 0;\n\n for (const format of formats) {\n formatsChecked++;\n const formatIdStr = typeof format.format_id === 'object' ? format.format_id.id : String(format.format_id);\n // Check for deprecated assets_required field\n if ('assets_required' in format) {\n assetsIssues.push(\n `format ${formatIdStr} uses deprecated \"assets_required\" — should be \"assets\" array with \"required\" boolean`\n );\n }\n // Validate assets array structure\n if (Array.isArray(format.assets)) {\n for (const asset of format.assets) {\n if (!('required' in asset)) {\n assetsIssues.push(`format ${formatIdStr} asset missing \"required\" boolean field`);\n }\n }\n }\n }\n\n formatsStep.details =\n assetsIssues.length === 0\n ? `Format assets valid across ${formatsChecked} format(s)`\n : `Format asset issues: ${assetsIssues.join('; ')}`;\n formatsStep.passed = assetsIssues.length === 0;\n formatsStep.error = assetsIssues.length > 0 ? assetsIssues.join('; ') : undefined;\n }\n steps.push(formatsStep);\n }\n\n return { steps, profile };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/testing/scenarios/schema-compliance.ts"],"sourcesContent":["/**\n * Schema Compliance Testing\n *\n * Validates that an agent's responses use correct v3 field names and enum values.\n * Uses GET-only operations — no writes required.\n *\n * Checks:\n * - Channel enum values (hard fail on invalid values)\n * - Pricing field names: fixed_price (not fixed_rate), floor_price top-level\n * - Format assets: assets array with required boolean (not assets_required)\n */\n\nimport type { Product } from '../../types/core.generated';\nimport type {\n GetProductsResponse,\n GetSignalsResponse,\n ListCreativeFormatsResponse,\n Format,\n} from '../../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile, validateResponseSchema } from '../client';\n\n// v3 channel taxonomy — 19 channels\nconst V3_CHANNELS = new Set([\n 'display',\n 'olv',\n 'social',\n 'search',\n 'ctv',\n 'linear_tv',\n 'radio',\n 'streaming_audio',\n 'podcast',\n 'dooh',\n 'ooh',\n 'print',\n 'cinema',\n 'email',\n 'gaming',\n 'retail_media',\n 'influencer',\n 'affiliate',\n 'product_placement',\n]);\n\nexport async function testSchemaCompliance(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n if (!profile.tools.includes('get_products') && !profile.tools.includes('get_signals')) {\n // Path A: no supported discovery tool — skip field-shape checks gracefully\n steps.push({\n step: 'Schema compliance check support',\n passed: true,\n duration_ms: 0,\n details: 'Agent does not advertise get_products or get_signals — discovery field-shape checks skipped',\n warnings: ['Schema compliance: no supported discovery tool (get_products, get_signals) found; checks skipped'],\n });\n // Fall through to list_creative_formats check below\n } else if (profile.tools.includes('get_signals') && !profile.tools.includes('get_products')) {\n // Path B: signals agent — validate GetSignalsResponse schema and field semantics\n const { result: signalsResult, step: signalsStep } = await runStep<TaskResult>(\n 'Get signals (schema compliance)',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Schema compliance test — retrieve all available signals',\n }) as Promise<TaskResult>\n );\n\n if (!signalsResult?.success || !signalsResult?.data) {\n signalsStep.passed = false;\n signalsStep.error = signalsResult?.error || 'get_signals returned no data';\n steps.push(signalsStep);\n return { steps, profile };\n }\n steps.push(signalsStep);\n\n const signalsData = signalsResult.data as GetSignalsResponse;\n // Zod schema validation covers required-field presence (signal_agent_segment_id, name, signal_type).\n steps.push(validateResponseSchema('get_signals', signalsData));\n\n const signals = signalsData.signals ?? [];\n steps.push({\n step: 'Validate signal required fields',\n passed: true,\n duration_ms: 0,\n details:\n signals.length === 0\n ? 'Agent returned no signals — field-shape checks skipped'\n : `${signals.length} signal(s) validated via schema check (signal_agent_segment_id, name, signal_type)`,\n warnings:\n signals.length === 0\n ? ['No signals returned; cannot validate signal_agent_segment_id, name, signal_type fields']\n : undefined,\n });\n // Fall through to list_creative_formats check below\n } else {\n // Path C: get_products present — existing product catalog checks\n const { result: productsResult, step: productsStep } = await runStep<TaskResult>(\n 'Get products (schema compliance)',\n 'get_products',\n async () =>\n client.getProducts({\n buying_mode: 'brief',\n brief: options.brief || 'Schema compliance test — retrieve all available products',\n brand: options.brand,\n }) as Promise<TaskResult>\n );\n\n if (!productsResult?.success || !productsResult?.data) {\n productsStep.passed = false;\n productsStep.error = productsResult?.error || 'get_products returned no data';\n steps.push(productsStep);\n return { steps, profile };\n }\n steps.push(productsStep);\n\n const data = productsResult.data as GetProductsResponse;\n const products: Product[] = data.products || [];\n\n // --- Zod schema validation (catches missing required fields + invalid enum values) ---\n steps.push(validateResponseSchema('get_products', data));\n\n if (products.length === 0) {\n steps.push({\n step: 'Schema compliance: no products to validate',\n passed: true,\n duration_ms: 0,\n details: 'Agent returned no products — schema compliance checks skipped',\n warnings: ['No products returned; cannot validate channel, pricing, or format field schemas'],\n });\n return { steps, profile };\n }\n\n // --- Channel enum validation (hard fail) ---\n const invalidChannels: string[] = [];\n const allChannels = new Set<string>();\n\n for (const product of products) {\n for (const channel of product.channels || []) {\n allChannels.add(channel);\n if (!V3_CHANNELS.has(channel)) {\n invalidChannels.push(`\"${channel}\" in product ${product.product_id}`);\n }\n }\n }\n\n steps.push({\n step: 'Validate channel enum values',\n passed: invalidChannels.length === 0,\n duration_ms: 0,\n details:\n invalidChannels.length === 0\n ? `All ${allChannels.size} channel value(s) are valid v3 channels: ${Array.from(allChannels).join(', ')}`\n : `Invalid channel values detected (not in v3 taxonomy): ${invalidChannels.join('; ')}`,\n error:\n invalidChannels.length > 0\n ? `Channel enum violations: ${invalidChannels.join('; ')}. Valid channels: ${Array.from(V3_CHANNELS).join(', ')}`\n : undefined,\n response_preview: JSON.stringify(\n {\n channels_found: Array.from(allChannels),\n invalid_channels: invalidChannels,\n },\n null,\n 2\n ),\n });\n\n // --- Pricing field name validation (warn, not fail) ---\n const pricingIssues: string[] = [];\n const pricingChecked: string[] = [];\n let fixedPriceFound = false;\n\n for (const product of products) {\n for (const option of product.pricing_options || []) {\n const optionId = option.pricing_option_id || '(unknown)';\n // Cast to Record for deprecated-field checks — compliance testing intentionally\n // probes fields that may not exist on the generated PricingOption union\n const raw = option as unknown as Record<string, unknown>;\n\n // Check for deprecated fixed_rate field\n if ('fixed_rate' in raw) {\n pricingIssues.push(`pricing_option ${optionId} uses deprecated \"fixed_rate\" — should be \"fixed_price\"`);\n }\n if ('fixed_price' in raw) {\n fixedPriceFound = true;\n pricingChecked.push(optionId);\n }\n\n // Check for floor_price inside price_guidance (deprecated location)\n const pg = raw.price_guidance as Record<string, unknown> | undefined;\n if (pg && 'floor' in pg) {\n pricingIssues.push(\n `pricing_option ${optionId} has \"floor\" inside price_guidance — should be top-level \"floor_price\"`\n );\n }\n if ('floor_price' in raw) {\n pricingChecked.push(`${optionId} (floor_price)`);\n }\n }\n }\n\n const pricingPassed = pricingIssues.length === 0;\n const pricingDetails =\n pricingIssues.length > 0\n ? `Pricing field issues: ${pricingIssues.join('; ')}`\n : fixedPriceFound\n ? `Pricing fields valid (checked ${pricingChecked.length} option(s))`\n : 'No fixed-price products found to validate (agent may be auction-only — cannot confirm field names)';\n\n steps.push({\n step: 'Validate pricing field names',\n passed: pricingPassed,\n duration_ms: 0,\n details: pricingDetails,\n error: pricingIssues.length > 0 ? pricingIssues.join('; ') : undefined,\n warnings:\n !fixedPriceFound && pricingIssues.length === 0\n ? [\n 'No fixed-price products found. If agent supports fixed pricing, verify it uses \"fixed_price\" (not \"fixed_rate\") and \"floor_price\" at the pricing option level (not inside price_guidance).',\n ]\n : undefined,\n response_preview: JSON.stringify(\n {\n issues: pricingIssues,\n options_checked: pricingChecked,\n },\n null,\n 2\n ),\n });\n }\n\n // --- Format assets structure (optional: list_creative_formats) ---\n // Runs for all agent types that advertise list_creative_formats, regardless of discovery path\n if (profile.tools.includes('list_creative_formats')) {\n const { result: formatsResult, step: formatsStep } = await runStep<TaskResult>(\n 'Get creative formats (check assets structure)',\n 'list_creative_formats',\n async () => client.listCreativeFormatsLegacy({}) as Promise<TaskResult>\n );\n\n if (formatsResult?.success && formatsResult?.data) {\n steps.push(validateResponseSchema('list_creative_formats', formatsResult.data));\n const formatsData = formatsResult.data as ListCreativeFormatsResponse;\n const formats: Format[] = formatsData.formats || [];\n const assetsIssues: string[] = [];\n let formatsChecked = 0;\n\n for (const format of formats) {\n formatsChecked++;\n const formatIdStr = typeof format.format_id === 'object' ? format.format_id.id : String(format.format_id);\n // Check for deprecated assets_required field\n if ('assets_required' in format) {\n assetsIssues.push(\n `format ${formatIdStr} uses deprecated \"assets_required\" — should be \"assets\" array with \"required\" boolean`\n );\n }\n // Validate assets array structure\n if (Array.isArray(format.assets)) {\n for (const asset of format.assets) {\n if (!('required' in asset)) {\n assetsIssues.push(`format ${formatIdStr} asset missing \"required\" boolean field`);\n }\n }\n }\n }\n\n formatsStep.details =\n assetsIssues.length === 0\n ? `Format assets valid across ${formatsChecked} format(s)`\n : `Format asset issues: ${assetsIssues.join('; ')}`;\n formatsStep.passed = assetsIssues.length === 0;\n formatsStep.error = assetsIssues.length > 0 ? assetsIssues.join('; ') : undefined;\n }\n steps.push(formatsStep);\n }\n\n return { steps, profile };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBA,oBAAyF;AAGzF,MAAM,cAAc,oBAAI,IAAI;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,eAAsB,qBACpB,UACA,SAC8D;AAC9D,QAAM,QAA0B,CAAC;AACjC,QAAM,aAAS,iCAAkB,UAAU,OAAO;AAElD,QAAM,EAAE,SAAS,MAAM,YAAY,IAAI,UAAM,oCAAqB,QAAQ,OAAO;AACjF,QAAM,KAAK,WAAW;AAEtB,MAAI,CAAC,YAAY,QAAQ;AACvB,WAAO,EAAE,OAAO,QAAQ;AAAA,EAC1B;AAEA,MAAI,CAAC,QAAQ,MAAM,SAAS,cAAc,KAAK,CAAC,QAAQ,MAAM,SAAS,aAAa,GAAG;AAErF,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,SAAS;AAAA,MACT,UAAU,CAAC,kGAAkG;AAAA,IAC/G,CAAC;AAAA,EAEH,WAAW,QAAQ,MAAM,SAAS,aAAa,KAAK,CAAC,QAAQ,MAAM,SAAS,cAAc,GAAG;AAE3F,UAAM,EAAE,QAAQ,eAAe,MAAM,YAAY,IAAI,UAAM;AAAA,MACzD;AAAA,MACA;AAAA,MACA,YACE,OAAO,WAAW;AAAA,QAChB,aAAa,QAAQ,SAAS;AAAA,MAChC,CAAC;AAAA,IACL;AAEA,QAAI,CAAC,eAAe,WAAW,CAAC,eAAe,MAAM;AACnD,kBAAY,SAAS;AACrB,kBAAY,QAAQ,eAAe,SAAS;AAC5C,YAAM,KAAK,WAAW;AACtB,aAAO,EAAE,OAAO,QAAQ;AAAA,IAC1B;AACA,UAAM,KAAK,WAAW;AAEtB,UAAM,cAAc,cAAc;AAElC,UAAM,SAAK,sCAAuB,eAAe,WAAW,CAAC;AAE7D,UAAM,UAAU,YAAY,WAAW,CAAC;AACxC,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,SACE,QAAQ,WAAW,IACf,gEACA,GAAG,QAAQ,MAAM;AAAA,MACvB,UACE,QAAQ,WAAW,IACf,CAAC,wFAAwF,IACzF;AAAA,IACR,CAAC;AAAA,EAEH,OAAO;AAEL,UAAM,EAAE,QAAQ,gBAAgB,MAAM,aAAa,IAAI,UAAM;AAAA,MAC3D;AAAA,MACA;AAAA,MACA,YACE,OAAO,YAAY;AAAA,QACjB,aAAa;AAAA,QACb,OAAO,QAAQ,SAAS;AAAA,QACxB,OAAO,QAAQ;AAAA,MACjB,CAAC;AAAA,IACL;AAEA,QAAI,CAAC,gBAAgB,WAAW,CAAC,gBAAgB,MAAM;AACrD,mBAAa,SAAS;AACtB,mBAAa,QAAQ,gBAAgB,SAAS;AAC9C,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,OAAO,QAAQ;AAAA,IAC1B;AACA,UAAM,KAAK,YAAY;AAEvB,UAAM,OAAO,eAAe;AAC5B,UAAM,WAAsB,KAAK,YAAY,CAAC;AAG9C,UAAM,SAAK,sCAAuB,gBAAgB,IAAI,CAAC;AAEvD,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,SAAS;AAAA,QACT,UAAU,CAAC,iFAAiF;AAAA,MAC9F,CAAC;AACD,aAAO,EAAE,OAAO,QAAQ;AAAA,IAC1B;AAGA,UAAM,kBAA4B,CAAC;AACnC,UAAM,cAAc,oBAAI,IAAY;AAEpC,eAAW,WAAW,UAAU;AAC9B,iBAAW,WAAW,QAAQ,YAAY,CAAC,GAAG;AAC5C,oBAAY,IAAI,OAAO;AACvB,YAAI,CAAC,YAAY,IAAI,OAAO,GAAG;AAC7B,0BAAgB,KAAK,IAAI,OAAO,gBAAgB,QAAQ,UAAU,EAAE;AAAA,QACtE;AAAA,MACF;AAAA,IACF;AAEA,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ,gBAAgB,WAAW;AAAA,MACnC,aAAa;AAAA,MACb,SACE,gBAAgB,WAAW,IACvB,OAAO,YAAY,IAAI,4CAA4C,MAAM,KAAK,WAAW,EAAE,KAAK,IAAI,CAAC,KACrG,yDAAyD,gBAAgB,KAAK,IAAI,CAAC;AAAA,MACzF,OACE,gBAAgB,SAAS,IACrB,4BAA4B,gBAAgB,KAAK,IAAI,CAAC,qBAAqB,MAAM,KAAK,WAAW,EAAE,KAAK,IAAI,CAAC,KAC7G;AAAA,MACN,kBAAkB,KAAK;AAAA,QACrB;AAAA,UACE,gBAAgB,MAAM,KAAK,WAAW;AAAA,UACtC,kBAAkB;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAGD,UAAM,gBAA0B,CAAC;AACjC,UAAM,iBAA2B,CAAC;AAClC,QAAI,kBAAkB;AAEtB,eAAW,WAAW,UAAU;AAC9B,iBAAW,UAAU,QAAQ,mBAAmB,CAAC,GAAG;AAClD,cAAM,WAAW,OAAO,qBAAqB;AAG7C,cAAM,MAAM;AAGZ,YAAI,gBAAgB,KAAK;AACvB,wBAAc,KAAK,kBAAkB,QAAQ,8DAAyD;AAAA,QACxG;AACA,YAAI,iBAAiB,KAAK;AACxB,4BAAkB;AAClB,yBAAe,KAAK,QAAQ;AAAA,QAC9B;AAGA,cAAM,KAAK,IAAI;AACf,YAAI,MAAM,WAAW,IAAI;AACvB,wBAAc;AAAA,YACZ,kBAAkB,QAAQ;AAAA,UAC5B;AAAA,QACF;AACA,YAAI,iBAAiB,KAAK;AACxB,yBAAe,KAAK,GAAG,QAAQ,gBAAgB;AAAA,QACjD;AAAA,MACF;AAAA,IACF;AAEA,UAAM,gBAAgB,cAAc,WAAW;AAC/C,UAAM,iBACJ,cAAc,SAAS,IACnB,yBAAyB,cAAc,KAAK,IAAI,CAAC,KACjD,kBACE,iCAAiC,eAAe,MAAM,gBACtD;AAER,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,SAAS;AAAA,MACT,OAAO,cAAc,SAAS,IAAI,cAAc,KAAK,IAAI,IAAI;AAAA,MAC7D,UACE,CAAC,mBAAmB,cAAc,WAAW,IACzC;AAAA,QACE;AAAA,MACF,IACA;AAAA,MACN,kBAAkB,KAAK;AAAA,QACrB;AAAA,UACE,QAAQ;AAAA,UACR,iBAAiB;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAIA,MAAI,QAAQ,MAAM,SAAS,uBAAuB,GAAG;AACnD,UAAM,EAAE,QAAQ,eAAe,MAAM,YAAY,IAAI,UAAM;AAAA,MACzD;AAAA,MACA;AAAA,MACA,YAAY,OAAO,0BAA0B,CAAC,CAAC;AAAA,IACjD;AAEA,QAAI,eAAe,WAAW,eAAe,MAAM;AACjD,YAAM,SAAK,sCAAuB,yBAAyB,cAAc,IAAI,CAAC;AAC9E,YAAM,cAAc,cAAc;AAClC,YAAM,UAAoB,YAAY,WAAW,CAAC;AAClD,YAAM,eAAyB,CAAC;AAChC,UAAI,iBAAiB;AAErB,iBAAW,UAAU,SAAS;AAC5B;AACA,cAAM,cAAc,OAAO,OAAO,cAAc,WAAW,OAAO,UAAU,KAAK,OAAO,OAAO,SAAS;AAExG,YAAI,qBAAqB,QAAQ;AAC/B,uBAAa;AAAA,YACX,UAAU,WAAW;AAAA,UACvB;AAAA,QACF;AAEA,YAAI,MAAM,QAAQ,OAAO,MAAM,GAAG;AAChC,qBAAW,SAAS,OAAO,QAAQ;AACjC,gBAAI,EAAE,cAAc,QAAQ;AAC1B,2BAAa,KAAK,UAAU,WAAW,yCAAyC;AAAA,YAClF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,kBAAY,UACV,aAAa,WAAW,IACpB,8BAA8B,cAAc,eAC5C,wBAAwB,aAAa,KAAK,IAAI,CAAC;AACrD,kBAAY,SAAS,aAAa,WAAW;AAC7C,kBAAY,QAAQ,aAAa,SAAS,IAAI,aAAa,KAAK,IAAI,IAAI;AAAA,IAC1E;AACA,UAAM,KAAK,WAAW;AAAA,EACxB;AAEA,SAAO,EAAE,OAAO,QAAQ;AAC1B;","names":[]}
|
|
@@ -166,7 +166,7 @@ async function testSchemaCompliance(agentUrl, options) {
|
|
|
166
166
|
const { result: formatsResult, step: formatsStep } = await runStep(
|
|
167
167
|
"Get creative formats (check assets structure)",
|
|
168
168
|
"list_creative_formats",
|
|
169
|
-
async () => client.
|
|
169
|
+
async () => client.listCreativeFormatsLegacy({})
|
|
170
170
|
);
|
|
171
171
|
if (formatsResult?.success && formatsResult?.data) {
|
|
172
172
|
steps.push(validateResponseSchema("list_creative_formats", formatsResult.data));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/testing/scenarios/schema-compliance.ts"],"sourcesContent":["/**\n * Schema Compliance Testing\n *\n * Validates that an agent's responses use correct v3 field names and enum values.\n * Uses GET-only operations — no writes required.\n *\n * Checks:\n * - Channel enum values (hard fail on invalid values)\n * - Pricing field names: fixed_price (not fixed_rate), floor_price top-level\n * - Format assets: assets array with required boolean (not assets_required)\n */\n\nimport type { Product } from '../../types/core.generated';\nimport type {\n GetProductsResponse,\n GetSignalsResponse,\n ListCreativeFormatsResponse,\n Format,\n} from '../../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile, validateResponseSchema } from '../client';\n\n// v3 channel taxonomy — 19 channels\nconst V3_CHANNELS = new Set([\n 'display',\n 'olv',\n 'social',\n 'search',\n 'ctv',\n 'linear_tv',\n 'radio',\n 'streaming_audio',\n 'podcast',\n 'dooh',\n 'ooh',\n 'print',\n 'cinema',\n 'email',\n 'gaming',\n 'retail_media',\n 'influencer',\n 'affiliate',\n 'product_placement',\n]);\n\nexport async function testSchemaCompliance(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n if (!profile.tools.includes('get_products') && !profile.tools.includes('get_signals')) {\n // Path A: no supported discovery tool — skip field-shape checks gracefully\n steps.push({\n step: 'Schema compliance check support',\n passed: true,\n duration_ms: 0,\n details: 'Agent does not advertise get_products or get_signals — discovery field-shape checks skipped',\n warnings: ['Schema compliance: no supported discovery tool (get_products, get_signals) found; checks skipped'],\n });\n // Fall through to list_creative_formats check below\n } else if (profile.tools.includes('get_signals') && !profile.tools.includes('get_products')) {\n // Path B: signals agent — validate GetSignalsResponse schema and field semantics\n const { result: signalsResult, step: signalsStep } = await runStep<TaskResult>(\n 'Get signals (schema compliance)',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Schema compliance test — retrieve all available signals',\n }) as Promise<TaskResult>\n );\n\n if (!signalsResult?.success || !signalsResult?.data) {\n signalsStep.passed = false;\n signalsStep.error = signalsResult?.error || 'get_signals returned no data';\n steps.push(signalsStep);\n return { steps, profile };\n }\n steps.push(signalsStep);\n\n const signalsData = signalsResult.data as GetSignalsResponse;\n // Zod schema validation covers required-field presence (signal_agent_segment_id, name, signal_type).\n steps.push(validateResponseSchema('get_signals', signalsData));\n\n const signals = signalsData.signals ?? [];\n steps.push({\n step: 'Validate signal required fields',\n passed: true,\n duration_ms: 0,\n details:\n signals.length === 0\n ? 'Agent returned no signals — field-shape checks skipped'\n : `${signals.length} signal(s) validated via schema check (signal_agent_segment_id, name, signal_type)`,\n warnings:\n signals.length === 0\n ? ['No signals returned; cannot validate signal_agent_segment_id, name, signal_type fields']\n : undefined,\n });\n // Fall through to list_creative_formats check below\n } else {\n // Path C: get_products present — existing product catalog checks\n const { result: productsResult, step: productsStep } = await runStep<TaskResult>(\n 'Get products (schema compliance)',\n 'get_products',\n async () =>\n client.getProducts({\n buying_mode: 'brief',\n brief: options.brief || 'Schema compliance test — retrieve all available products',\n brand: options.brand,\n }) as Promise<TaskResult>\n );\n\n if (!productsResult?.success || !productsResult?.data) {\n productsStep.passed = false;\n productsStep.error = productsResult?.error || 'get_products returned no data';\n steps.push(productsStep);\n return { steps, profile };\n }\n steps.push(productsStep);\n\n const data = productsResult.data as GetProductsResponse;\n const products: Product[] = data.products || [];\n\n // --- Zod schema validation (catches missing required fields + invalid enum values) ---\n steps.push(validateResponseSchema('get_products', data));\n\n if (products.length === 0) {\n steps.push({\n step: 'Schema compliance: no products to validate',\n passed: true,\n duration_ms: 0,\n details: 'Agent returned no products — schema compliance checks skipped',\n warnings: ['No products returned; cannot validate channel, pricing, or format field schemas'],\n });\n return { steps, profile };\n }\n\n // --- Channel enum validation (hard fail) ---\n const invalidChannels: string[] = [];\n const allChannels = new Set<string>();\n\n for (const product of products) {\n for (const channel of product.channels || []) {\n allChannels.add(channel);\n if (!V3_CHANNELS.has(channel)) {\n invalidChannels.push(`\"${channel}\" in product ${product.product_id}`);\n }\n }\n }\n\n steps.push({\n step: 'Validate channel enum values',\n passed: invalidChannels.length === 0,\n duration_ms: 0,\n details:\n invalidChannels.length === 0\n ? `All ${allChannels.size} channel value(s) are valid v3 channels: ${Array.from(allChannels).join(', ')}`\n : `Invalid channel values detected (not in v3 taxonomy): ${invalidChannels.join('; ')}`,\n error:\n invalidChannels.length > 0\n ? `Channel enum violations: ${invalidChannels.join('; ')}. Valid channels: ${Array.from(V3_CHANNELS).join(', ')}`\n : undefined,\n response_preview: JSON.stringify(\n {\n channels_found: Array.from(allChannels),\n invalid_channels: invalidChannels,\n },\n null,\n 2\n ),\n });\n\n // --- Pricing field name validation (warn, not fail) ---\n const pricingIssues: string[] = [];\n const pricingChecked: string[] = [];\n let fixedPriceFound = false;\n\n for (const product of products) {\n for (const option of product.pricing_options || []) {\n const optionId = option.pricing_option_id || '(unknown)';\n // Cast to Record for deprecated-field checks — compliance testing intentionally\n // probes fields that may not exist on the generated PricingOption union\n const raw = option as unknown as Record<string, unknown>;\n\n // Check for deprecated fixed_rate field\n if ('fixed_rate' in raw) {\n pricingIssues.push(`pricing_option ${optionId} uses deprecated \"fixed_rate\" — should be \"fixed_price\"`);\n }\n if ('fixed_price' in raw) {\n fixedPriceFound = true;\n pricingChecked.push(optionId);\n }\n\n // Check for floor_price inside price_guidance (deprecated location)\n const pg = raw.price_guidance as Record<string, unknown> | undefined;\n if (pg && 'floor' in pg) {\n pricingIssues.push(\n `pricing_option ${optionId} has \"floor\" inside price_guidance — should be top-level \"floor_price\"`\n );\n }\n if ('floor_price' in raw) {\n pricingChecked.push(`${optionId} (floor_price)`);\n }\n }\n }\n\n const pricingPassed = pricingIssues.length === 0;\n const pricingDetails =\n pricingIssues.length > 0\n ? `Pricing field issues: ${pricingIssues.join('; ')}`\n : fixedPriceFound\n ? `Pricing fields valid (checked ${pricingChecked.length} option(s))`\n : 'No fixed-price products found to validate (agent may be auction-only — cannot confirm field names)';\n\n steps.push({\n step: 'Validate pricing field names',\n passed: pricingPassed,\n duration_ms: 0,\n details: pricingDetails,\n error: pricingIssues.length > 0 ? pricingIssues.join('; ') : undefined,\n warnings:\n !fixedPriceFound && pricingIssues.length === 0\n ? [\n 'No fixed-price products found. If agent supports fixed pricing, verify it uses \"fixed_price\" (not \"fixed_rate\") and \"floor_price\" at the pricing option level (not inside price_guidance).',\n ]\n : undefined,\n response_preview: JSON.stringify(\n {\n issues: pricingIssues,\n options_checked: pricingChecked,\n },\n null,\n 2\n ),\n });\n }\n\n // --- Format assets structure (optional: list_creative_formats) ---\n // Runs for all agent types that advertise list_creative_formats, regardless of discovery path\n if (profile.tools.includes('list_creative_formats')) {\n const { result: formatsResult, step: formatsStep } = await runStep<TaskResult>(\n 'Get creative formats (check assets structure)',\n 'list_creative_formats',\n async () => client.listCreativeFormats({}) as Promise<TaskResult>\n );\n\n if (formatsResult?.success && formatsResult?.data) {\n steps.push(validateResponseSchema('list_creative_formats', formatsResult.data));\n const formatsData = formatsResult.data as ListCreativeFormatsResponse;\n const formats: Format[] = formatsData.formats || [];\n const assetsIssues: string[] = [];\n let formatsChecked = 0;\n\n for (const format of formats) {\n formatsChecked++;\n const formatIdStr = typeof format.format_id === 'object' ? format.format_id.id : String(format.format_id);\n // Check for deprecated assets_required field\n if ('assets_required' in format) {\n assetsIssues.push(\n `format ${formatIdStr} uses deprecated \"assets_required\" — should be \"assets\" array with \"required\" boolean`\n );\n }\n // Validate assets array structure\n if (Array.isArray(format.assets)) {\n for (const asset of format.assets) {\n if (!('required' in asset)) {\n assetsIssues.push(`format ${formatIdStr} asset missing \"required\" boolean field`);\n }\n }\n }\n }\n\n formatsStep.details =\n assetsIssues.length === 0\n ? `Format assets valid across ${formatsChecked} format(s)`\n : `Format asset issues: ${assetsIssues.join('; ')}`;\n formatsStep.passed = assetsIssues.length === 0;\n formatsStep.error = assetsIssues.length > 0 ? assetsIssues.join('; ') : undefined;\n }\n steps.push(formatsStep);\n }\n\n return { steps, profile };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/testing/scenarios/schema-compliance.ts"],"sourcesContent":["/**\n * Schema Compliance Testing\n *\n * Validates that an agent's responses use correct v3 field names and enum values.\n * Uses GET-only operations — no writes required.\n *\n * Checks:\n * - Channel enum values (hard fail on invalid values)\n * - Pricing field names: fixed_price (not fixed_rate), floor_price top-level\n * - Format assets: assets array with required boolean (not assets_required)\n */\n\nimport type { Product } from '../../types/core.generated';\nimport type {\n GetProductsResponse,\n GetSignalsResponse,\n ListCreativeFormatsResponse,\n Format,\n} from '../../types/tools.generated';\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile, validateResponseSchema } from '../client';\n\n// v3 channel taxonomy — 19 channels\nconst V3_CHANNELS = new Set([\n 'display',\n 'olv',\n 'social',\n 'search',\n 'ctv',\n 'linear_tv',\n 'radio',\n 'streaming_audio',\n 'podcast',\n 'dooh',\n 'ooh',\n 'print',\n 'cinema',\n 'email',\n 'gaming',\n 'retail_media',\n 'influencer',\n 'affiliate',\n 'product_placement',\n]);\n\nexport async function testSchemaCompliance(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n if (!profile.tools.includes('get_products') && !profile.tools.includes('get_signals')) {\n // Path A: no supported discovery tool — skip field-shape checks gracefully\n steps.push({\n step: 'Schema compliance check support',\n passed: true,\n duration_ms: 0,\n details: 'Agent does not advertise get_products or get_signals — discovery field-shape checks skipped',\n warnings: ['Schema compliance: no supported discovery tool (get_products, get_signals) found; checks skipped'],\n });\n // Fall through to list_creative_formats check below\n } else if (profile.tools.includes('get_signals') && !profile.tools.includes('get_products')) {\n // Path B: signals agent — validate GetSignalsResponse schema and field semantics\n const { result: signalsResult, step: signalsStep } = await runStep<TaskResult>(\n 'Get signals (schema compliance)',\n 'get_signals',\n async () =>\n client.getSignals({\n signal_spec: options.brief || 'Schema compliance test — retrieve all available signals',\n }) as Promise<TaskResult>\n );\n\n if (!signalsResult?.success || !signalsResult?.data) {\n signalsStep.passed = false;\n signalsStep.error = signalsResult?.error || 'get_signals returned no data';\n steps.push(signalsStep);\n return { steps, profile };\n }\n steps.push(signalsStep);\n\n const signalsData = signalsResult.data as GetSignalsResponse;\n // Zod schema validation covers required-field presence (signal_agent_segment_id, name, signal_type).\n steps.push(validateResponseSchema('get_signals', signalsData));\n\n const signals = signalsData.signals ?? [];\n steps.push({\n step: 'Validate signal required fields',\n passed: true,\n duration_ms: 0,\n details:\n signals.length === 0\n ? 'Agent returned no signals — field-shape checks skipped'\n : `${signals.length} signal(s) validated via schema check (signal_agent_segment_id, name, signal_type)`,\n warnings:\n signals.length === 0\n ? ['No signals returned; cannot validate signal_agent_segment_id, name, signal_type fields']\n : undefined,\n });\n // Fall through to list_creative_formats check below\n } else {\n // Path C: get_products present — existing product catalog checks\n const { result: productsResult, step: productsStep } = await runStep<TaskResult>(\n 'Get products (schema compliance)',\n 'get_products',\n async () =>\n client.getProducts({\n buying_mode: 'brief',\n brief: options.brief || 'Schema compliance test — retrieve all available products',\n brand: options.brand,\n }) as Promise<TaskResult>\n );\n\n if (!productsResult?.success || !productsResult?.data) {\n productsStep.passed = false;\n productsStep.error = productsResult?.error || 'get_products returned no data';\n steps.push(productsStep);\n return { steps, profile };\n }\n steps.push(productsStep);\n\n const data = productsResult.data as GetProductsResponse;\n const products: Product[] = data.products || [];\n\n // --- Zod schema validation (catches missing required fields + invalid enum values) ---\n steps.push(validateResponseSchema('get_products', data));\n\n if (products.length === 0) {\n steps.push({\n step: 'Schema compliance: no products to validate',\n passed: true,\n duration_ms: 0,\n details: 'Agent returned no products — schema compliance checks skipped',\n warnings: ['No products returned; cannot validate channel, pricing, or format field schemas'],\n });\n return { steps, profile };\n }\n\n // --- Channel enum validation (hard fail) ---\n const invalidChannels: string[] = [];\n const allChannels = new Set<string>();\n\n for (const product of products) {\n for (const channel of product.channels || []) {\n allChannels.add(channel);\n if (!V3_CHANNELS.has(channel)) {\n invalidChannels.push(`\"${channel}\" in product ${product.product_id}`);\n }\n }\n }\n\n steps.push({\n step: 'Validate channel enum values',\n passed: invalidChannels.length === 0,\n duration_ms: 0,\n details:\n invalidChannels.length === 0\n ? `All ${allChannels.size} channel value(s) are valid v3 channels: ${Array.from(allChannels).join(', ')}`\n : `Invalid channel values detected (not in v3 taxonomy): ${invalidChannels.join('; ')}`,\n error:\n invalidChannels.length > 0\n ? `Channel enum violations: ${invalidChannels.join('; ')}. Valid channels: ${Array.from(V3_CHANNELS).join(', ')}`\n : undefined,\n response_preview: JSON.stringify(\n {\n channels_found: Array.from(allChannels),\n invalid_channels: invalidChannels,\n },\n null,\n 2\n ),\n });\n\n // --- Pricing field name validation (warn, not fail) ---\n const pricingIssues: string[] = [];\n const pricingChecked: string[] = [];\n let fixedPriceFound = false;\n\n for (const product of products) {\n for (const option of product.pricing_options || []) {\n const optionId = option.pricing_option_id || '(unknown)';\n // Cast to Record for deprecated-field checks — compliance testing intentionally\n // probes fields that may not exist on the generated PricingOption union\n const raw = option as unknown as Record<string, unknown>;\n\n // Check for deprecated fixed_rate field\n if ('fixed_rate' in raw) {\n pricingIssues.push(`pricing_option ${optionId} uses deprecated \"fixed_rate\" — should be \"fixed_price\"`);\n }\n if ('fixed_price' in raw) {\n fixedPriceFound = true;\n pricingChecked.push(optionId);\n }\n\n // Check for floor_price inside price_guidance (deprecated location)\n const pg = raw.price_guidance as Record<string, unknown> | undefined;\n if (pg && 'floor' in pg) {\n pricingIssues.push(\n `pricing_option ${optionId} has \"floor\" inside price_guidance — should be top-level \"floor_price\"`\n );\n }\n if ('floor_price' in raw) {\n pricingChecked.push(`${optionId} (floor_price)`);\n }\n }\n }\n\n const pricingPassed = pricingIssues.length === 0;\n const pricingDetails =\n pricingIssues.length > 0\n ? `Pricing field issues: ${pricingIssues.join('; ')}`\n : fixedPriceFound\n ? `Pricing fields valid (checked ${pricingChecked.length} option(s))`\n : 'No fixed-price products found to validate (agent may be auction-only — cannot confirm field names)';\n\n steps.push({\n step: 'Validate pricing field names',\n passed: pricingPassed,\n duration_ms: 0,\n details: pricingDetails,\n error: pricingIssues.length > 0 ? pricingIssues.join('; ') : undefined,\n warnings:\n !fixedPriceFound && pricingIssues.length === 0\n ? [\n 'No fixed-price products found. If agent supports fixed pricing, verify it uses \"fixed_price\" (not \"fixed_rate\") and \"floor_price\" at the pricing option level (not inside price_guidance).',\n ]\n : undefined,\n response_preview: JSON.stringify(\n {\n issues: pricingIssues,\n options_checked: pricingChecked,\n },\n null,\n 2\n ),\n });\n }\n\n // --- Format assets structure (optional: list_creative_formats) ---\n // Runs for all agent types that advertise list_creative_formats, regardless of discovery path\n if (profile.tools.includes('list_creative_formats')) {\n const { result: formatsResult, step: formatsStep } = await runStep<TaskResult>(\n 'Get creative formats (check assets structure)',\n 'list_creative_formats',\n async () => client.listCreativeFormatsLegacy({}) as Promise<TaskResult>\n );\n\n if (formatsResult?.success && formatsResult?.data) {\n steps.push(validateResponseSchema('list_creative_formats', formatsResult.data));\n const formatsData = formatsResult.data as ListCreativeFormatsResponse;\n const formats: Format[] = formatsData.formats || [];\n const assetsIssues: string[] = [];\n let formatsChecked = 0;\n\n for (const format of formats) {\n formatsChecked++;\n const formatIdStr = typeof format.format_id === 'object' ? format.format_id.id : String(format.format_id);\n // Check for deprecated assets_required field\n if ('assets_required' in format) {\n assetsIssues.push(\n `format ${formatIdStr} uses deprecated \"assets_required\" — should be \"assets\" array with \"required\" boolean`\n );\n }\n // Validate assets array structure\n if (Array.isArray(format.assets)) {\n for (const asset of format.assets) {\n if (!('required' in asset)) {\n assetsIssues.push(`format ${formatIdStr} asset missing \"required\" boolean field`);\n }\n }\n }\n }\n\n formatsStep.details =\n assetsIssues.length === 0\n ? `Format assets valid across ${formatsChecked} format(s)`\n : `Format asset issues: ${assetsIssues.join('; ')}`;\n formatsStep.passed = assetsIssues.length === 0;\n formatsStep.error = assetsIssues.length > 0 ? assetsIssues.join('; ') : undefined;\n }\n steps.push(formatsStep);\n }\n\n return { steps, profile };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trusted-match.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAc,MAAM,UAAU,CAAC;AAItF;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"trusted-match.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAc,MAAM,UAAU,CAAC;AAItF;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,CAAC,CA6H9D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAE7D"}
|
|
@@ -51,8 +51,9 @@ async function testTrustedMatchFlow(agentUrl, options) {
|
|
|
51
51
|
type: "context_match_request",
|
|
52
52
|
request_id: `e2e-ctx-${Date.now()}`,
|
|
53
53
|
property_rid: "00000000-0000-7000-0000-000000000001",
|
|
54
|
-
property_type: "
|
|
54
|
+
property_type: "website",
|
|
55
55
|
placement_id: "e2e-test-placement",
|
|
56
|
+
seller_agent_url: agentUrl,
|
|
56
57
|
context_signals: {
|
|
57
58
|
topics: ["632"],
|
|
58
59
|
taxonomy_source: "iab",
|
|
@@ -100,8 +101,8 @@ async function testTrustedMatchFlow(agentUrl, options) {
|
|
|
100
101
|
async () => client.executeTask("identity_match", {
|
|
101
102
|
type: "identity_match_request",
|
|
102
103
|
request_id: `e2e-id-${Date.now()}`,
|
|
103
|
-
|
|
104
|
-
uid_type: "publisher_first_party",
|
|
104
|
+
seller_agent_url: agentUrl,
|
|
105
|
+
identities: [{ user_token: "e2e-test-opaque-token", uid_type: "publisher_first_party" }],
|
|
105
106
|
package_ids: ["e2e-test-package-001", "e2e-test-package-002"],
|
|
106
107
|
consent: {
|
|
107
108
|
gdpr: false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"sourcesContent":["/**\n * Trusted Match Protocol (TMP) Testing Scenarios (v3)\n *\n * Tests TMP agent capabilities including:\n * - context_match — evaluates packages against content context (no user identity)\n * - identity_match — evaluates user eligibility for packages using an opaque identity token (no page context)\n */\n\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile } from '../client';\nimport { TRUSTED_MATCH_TOOLS } from '../../utils/capabilities';\n\n/**\n * Test: Trusted Match Flow\n *\n * Flow: discover profile -> check TMP tools -> context_match -> identity_match\n */\nexport async function testTrustedMatchFlow(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n // Discover agent profile\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n // Check if agent supports any TMP tools\n const hasTMP = TRUSTED_MATCH_TOOLS.some(t => profile.tools.includes(t));\n if (!hasTMP) {\n steps.push({\n step: 'TMP support check',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support Trusted Match Protocol tools',\n details: `Required tools: ${TRUSTED_MATCH_TOOLS.join(', ')}. Available: ${profile.tools.join(', ')}`,\n });\n return { steps, profile };\n }\n\n // Test: context_match\n if (profile.tools.includes('context_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Context match: evaluate packages against page context',\n 'context_match',\n async () =>\n client.executeTask('context_match', {\n type: 'context_match_request',\n request_id: `e2e-ctx-${Date.now()}`,\n property_rid: '00000000-0000-7000-0000-000000000001',\n property_type: '
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"sourcesContent":["/**\n * Trusted Match Protocol (TMP) Testing Scenarios (v3)\n *\n * Tests TMP agent capabilities including:\n * - context_match — evaluates packages against content context (no user identity)\n * - identity_match — evaluates user eligibility for packages using an opaque identity token (no page context)\n */\n\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile } from '../client';\nimport { TRUSTED_MATCH_TOOLS } from '../../utils/capabilities';\n\n/**\n * Test: Trusted Match Flow\n *\n * Flow: discover profile -> check TMP tools -> context_match -> identity_match\n */\nexport async function testTrustedMatchFlow(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n // Discover agent profile\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n // Check if agent supports any TMP tools\n const hasTMP = TRUSTED_MATCH_TOOLS.some(t => profile.tools.includes(t));\n if (!hasTMP) {\n steps.push({\n step: 'TMP support check',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support Trusted Match Protocol tools',\n details: `Required tools: ${TRUSTED_MATCH_TOOLS.join(', ')}. Available: ${profile.tools.join(', ')}`,\n });\n return { steps, profile };\n }\n\n // Test: context_match\n if (profile.tools.includes('context_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Context match: evaluate packages against page context',\n 'context_match',\n async () =>\n client.executeTask('context_match', {\n type: 'context_match_request',\n request_id: `e2e-ctx-${Date.now()}`,\n property_rid: '00000000-0000-7000-0000-000000000001',\n property_type: 'website',\n placement_id: 'e2e-test-placement',\n seller_agent_url: agentUrl,\n context_signals: {\n topics: ['632'],\n taxonomy_source: 'iab',\n taxonomy_id: 7,\n sentiment: 'positive',\n keywords: ['technology', 'innovation'],\n language: 'en',\n },\n geo: {\n country: 'US',\n region: 'US-CA',\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const offers = Array.isArray(data['offers']) ? data['offers'] : [];\n step.details = `Context match returned ${offers.length} offer(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n offers_count: offers.length,\n cache_ttl: data['cache_ttl'],\n has_signals: !!data['signals'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Context match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'context_match failed';\n }\n }\n steps.push(step);\n }\n\n // Test: identity_match\n if (profile.tools.includes('identity_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Identity match: evaluate user eligibility for packages',\n 'identity_match',\n async () =>\n client.executeTask('identity_match', {\n type: 'identity_match_request',\n request_id: `e2e-id-${Date.now()}`,\n seller_agent_url: agentUrl,\n identities: [{ user_token: 'e2e-test-opaque-token', uid_type: 'publisher_first_party' }],\n package_ids: ['e2e-test-package-001', 'e2e-test-package-002'],\n consent: {\n gdpr: false,\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const eligibleIds = Array.isArray(data['eligible_package_ids']) ? data['eligible_package_ids'] : [];\n step.details = `Identity match returned ${eligibleIds.length} eligible package(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n eligible_package_ids: eligibleIds,\n ttl_sec: data['ttl_sec'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Identity match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'identity_match failed';\n }\n }\n steps.push(step);\n }\n\n return { steps, profile };\n}\n\n/**\n * Check if agent has any TMP tools\n */\nexport function hasTrustedMatchTools(tools: string[]): boolean {\n return TRUSTED_MATCH_TOOLS.some(t => tools.includes(t));\n}\n"],"mappings":"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","names":[]}
|
|
@@ -27,8 +27,9 @@ async function testTrustedMatchFlow(agentUrl, options) {
|
|
|
27
27
|
type: "context_match_request",
|
|
28
28
|
request_id: `e2e-ctx-${Date.now()}`,
|
|
29
29
|
property_rid: "00000000-0000-7000-0000-000000000001",
|
|
30
|
-
property_type: "
|
|
30
|
+
property_type: "website",
|
|
31
31
|
placement_id: "e2e-test-placement",
|
|
32
|
+
seller_agent_url: agentUrl,
|
|
32
33
|
context_signals: {
|
|
33
34
|
topics: ["632"],
|
|
34
35
|
taxonomy_source: "iab",
|
|
@@ -76,8 +77,8 @@ async function testTrustedMatchFlow(agentUrl, options) {
|
|
|
76
77
|
async () => client.executeTask("identity_match", {
|
|
77
78
|
type: "identity_match_request",
|
|
78
79
|
request_id: `e2e-id-${Date.now()}`,
|
|
79
|
-
|
|
80
|
-
uid_type: "publisher_first_party",
|
|
80
|
+
seller_agent_url: agentUrl,
|
|
81
|
+
identities: [{ user_token: "e2e-test-opaque-token", uid_type: "publisher_first_party" }],
|
|
81
82
|
package_ids: ["e2e-test-package-001", "e2e-test-package-002"],
|
|
82
83
|
consent: {
|
|
83
84
|
gdpr: false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"sourcesContent":["/**\n * Trusted Match Protocol (TMP) Testing Scenarios (v3)\n *\n * Tests TMP agent capabilities including:\n * - context_match — evaluates packages against content context (no user identity)\n * - identity_match — evaluates user eligibility for packages using an opaque identity token (no page context)\n */\n\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile } from '../client';\nimport { TRUSTED_MATCH_TOOLS } from '../../utils/capabilities';\n\n/**\n * Test: Trusted Match Flow\n *\n * Flow: discover profile -> check TMP tools -> context_match -> identity_match\n */\nexport async function testTrustedMatchFlow(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n // Discover agent profile\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n // Check if agent supports any TMP tools\n const hasTMP = TRUSTED_MATCH_TOOLS.some(t => profile.tools.includes(t));\n if (!hasTMP) {\n steps.push({\n step: 'TMP support check',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support Trusted Match Protocol tools',\n details: `Required tools: ${TRUSTED_MATCH_TOOLS.join(', ')}. Available: ${profile.tools.join(', ')}`,\n });\n return { steps, profile };\n }\n\n // Test: context_match\n if (profile.tools.includes('context_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Context match: evaluate packages against page context',\n 'context_match',\n async () =>\n client.executeTask('context_match', {\n type: 'context_match_request',\n request_id: `e2e-ctx-${Date.now()}`,\n property_rid: '00000000-0000-7000-0000-000000000001',\n property_type: '
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/testing/scenarios/trusted-match.ts"],"sourcesContent":["/**\n * Trusted Match Protocol (TMP) Testing Scenarios (v3)\n *\n * Tests TMP agent capabilities including:\n * - context_match — evaluates packages against content context (no user identity)\n * - identity_match — evaluates user eligibility for packages using an opaque identity token (no page context)\n */\n\nimport type { TestOptions, TestStepResult, AgentProfile, TaskResult } from '../types';\nimport { getOrCreateClient, runStep, getOrDiscoverProfile } from '../client';\nimport { TRUSTED_MATCH_TOOLS } from '../../utils/capabilities';\n\n/**\n * Test: Trusted Match Flow\n *\n * Flow: discover profile -> check TMP tools -> context_match -> identity_match\n */\nexport async function testTrustedMatchFlow(\n agentUrl: string,\n options: TestOptions\n): Promise<{ steps: TestStepResult[]; profile?: AgentProfile }> {\n const steps: TestStepResult[] = [];\n const client = getOrCreateClient(agentUrl, options);\n\n // Discover agent profile\n const { profile, step: profileStep } = await getOrDiscoverProfile(client, options);\n steps.push(profileStep);\n\n if (!profileStep.passed) {\n return { steps, profile };\n }\n\n // Check if agent supports any TMP tools\n const hasTMP = TRUSTED_MATCH_TOOLS.some(t => profile.tools.includes(t));\n if (!hasTMP) {\n steps.push({\n step: 'TMP support check',\n passed: false,\n duration_ms: 0,\n error: 'Agent does not support Trusted Match Protocol tools',\n details: `Required tools: ${TRUSTED_MATCH_TOOLS.join(', ')}. Available: ${profile.tools.join(', ')}`,\n });\n return { steps, profile };\n }\n\n // Test: context_match\n if (profile.tools.includes('context_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Context match: evaluate packages against page context',\n 'context_match',\n async () =>\n client.executeTask('context_match', {\n type: 'context_match_request',\n request_id: `e2e-ctx-${Date.now()}`,\n property_rid: '00000000-0000-7000-0000-000000000001',\n property_type: 'website',\n placement_id: 'e2e-test-placement',\n seller_agent_url: agentUrl,\n context_signals: {\n topics: ['632'],\n taxonomy_source: 'iab',\n taxonomy_id: 7,\n sentiment: 'positive',\n keywords: ['technology', 'innovation'],\n language: 'en',\n },\n geo: {\n country: 'US',\n region: 'US-CA',\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const offers = Array.isArray(data['offers']) ? data['offers'] : [];\n step.details = `Context match returned ${offers.length} offer(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n offers_count: offers.length,\n cache_ttl: data['cache_ttl'],\n has_signals: !!data['signals'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Context match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'context_match failed';\n }\n }\n steps.push(step);\n }\n\n // Test: identity_match\n if (profile.tools.includes('identity_match')) {\n const { result, step } = await runStep<TaskResult>(\n 'Identity match: evaluate user eligibility for packages',\n 'identity_match',\n async () =>\n client.executeTask('identity_match', {\n type: 'identity_match_request',\n request_id: `e2e-id-${Date.now()}`,\n seller_agent_url: agentUrl,\n identities: [{ user_token: 'e2e-test-opaque-token', uid_type: 'publisher_first_party' }],\n package_ids: ['e2e-test-package-001', 'e2e-test-package-002'],\n consent: {\n gdpr: false,\n },\n }) as Promise<TaskResult>\n );\n\n if (result?.success && result?.data) {\n const data = result.data as Record<string, unknown>;\n const eligibleIds = Array.isArray(data['eligible_package_ids']) ? data['eligible_package_ids'] : [];\n step.details = `Identity match returned ${eligibleIds.length} eligible package(s)`;\n step.response_preview = JSON.stringify(\n {\n request_id: data['request_id'],\n eligible_package_ids: eligibleIds,\n ttl_sec: data['ttl_sec'],\n },\n null,\n 2\n );\n } else if (result && !result.success) {\n const error = result.error || '';\n if (error.includes('not supported') || error.includes('not implemented')) {\n step.passed = true;\n step.details = 'Identity match not supported by this agent (expected for some agents)';\n } else {\n step.passed = false;\n step.error = result.error || 'identity_match failed';\n }\n }\n steps.push(step);\n }\n\n return { steps, profile };\n}\n\n/**\n * Check if agent has any TMP tools\n */\nexport function hasTrustedMatchTools(tools: string[]): boolean {\n return TRUSTED_MATCH_TOOLS.some(t => tools.includes(t));\n}\n"],"mappings":"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","names":[]}
|
|
@@ -13,6 +13,7 @@ export declare const PROBE_TASKS: Set<string>;
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function probeProtectedResourceMetadata(agentUrl: string, options?: {
|
|
15
15
|
allowPrivateIp?: boolean;
|
|
16
|
+
fetchFn?: typeof fetch;
|
|
16
17
|
}): Promise<HttpProbeResult>;
|
|
17
18
|
/**
|
|
18
19
|
* GET `<issuer>/.well-known/oauth-authorization-server` for the first issuer
|
|
@@ -22,12 +23,15 @@ export declare function probeProtectedResourceMetadata(agentUrl: string, options
|
|
|
22
23
|
*/
|
|
23
24
|
export declare function probeOauthAuthServerMetadata(priorProbe: HttpProbeResult | undefined, options?: {
|
|
24
25
|
allowPrivateIp?: boolean;
|
|
26
|
+
fetchFn?: typeof fetch;
|
|
25
27
|
}): Promise<HttpProbeResult>;
|
|
26
28
|
export interface FetchProbeOptions {
|
|
27
29
|
/** Allow http:// and private-IP destinations. Default false. */
|
|
28
30
|
allowPrivateIp?: boolean;
|
|
29
31
|
/** Override timeout for specific call sites. */
|
|
30
32
|
timeoutMs?: number;
|
|
33
|
+
/** Trusted scoped fetch; must enforce DNS-rebinding protection. */
|
|
34
|
+
fetchFn?: typeof fetch;
|
|
31
35
|
}
|
|
32
36
|
/**
|
|
33
37
|
* Perform a GET against an attacker-influenceable URL with defensive limits.
|
|
@@ -83,6 +87,8 @@ export declare function rawMcpProbe(options: {
|
|
|
83
87
|
headers?: Record<string, string>;
|
|
84
88
|
/** Allow http:// and private-IP agent URLs (dev loops). Default false. */
|
|
85
89
|
allowPrivateIp?: boolean;
|
|
90
|
+
/** Scoped fetch implementation for every handshake and tool request. */
|
|
91
|
+
fetchFn?: typeof fetch;
|
|
86
92
|
}): Promise<{
|
|
87
93
|
httpResult: HttpProbeResult;
|
|
88
94
|
taskResult?: TaskResult;
|
|
@@ -13,6 +13,7 @@ export declare const PROBE_TASKS: Set<string>;
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function probeProtectedResourceMetadata(agentUrl: string, options?: {
|
|
15
15
|
allowPrivateIp?: boolean;
|
|
16
|
+
fetchFn?: typeof fetch;
|
|
16
17
|
}): Promise<HttpProbeResult>;
|
|
17
18
|
/**
|
|
18
19
|
* GET `<issuer>/.well-known/oauth-authorization-server` for the first issuer
|
|
@@ -22,12 +23,15 @@ export declare function probeProtectedResourceMetadata(agentUrl: string, options
|
|
|
22
23
|
*/
|
|
23
24
|
export declare function probeOauthAuthServerMetadata(priorProbe: HttpProbeResult | undefined, options?: {
|
|
24
25
|
allowPrivateIp?: boolean;
|
|
26
|
+
fetchFn?: typeof fetch;
|
|
25
27
|
}): Promise<HttpProbeResult>;
|
|
26
28
|
export interface FetchProbeOptions {
|
|
27
29
|
/** Allow http:// and private-IP destinations. Default false. */
|
|
28
30
|
allowPrivateIp?: boolean;
|
|
29
31
|
/** Override timeout for specific call sites. */
|
|
30
32
|
timeoutMs?: number;
|
|
33
|
+
/** Trusted scoped fetch; must enforce DNS-rebinding protection. */
|
|
34
|
+
fetchFn?: typeof fetch;
|
|
31
35
|
}
|
|
32
36
|
/**
|
|
33
37
|
* Perform a GET against an attacker-influenceable URL with defensive limits.
|
|
@@ -83,6 +87,8 @@ export declare function rawMcpProbe(options: {
|
|
|
83
87
|
headers?: Record<string, string>;
|
|
84
88
|
/** Allow http:// and private-IP agent URLs (dev loops). Default false. */
|
|
85
89
|
allowPrivateIp?: boolean;
|
|
90
|
+
/** Scoped fetch implementation for every handshake and tool request. */
|
|
91
|
+
fetchFn?: typeof fetch;
|
|
86
92
|
}): Promise<{
|
|
87
93
|
httpResult: HttpProbeResult;
|
|
88
94
|
taskResult?: TaskResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"probes.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/storyboard/probes.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,gBAAgB,EAChB,eAAe,IAAI,qBAAqB,EACxC,WAAW,IAAI,iBAAiB,EACjC,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAM3C,sEAAsE;AACtE,eAAO,MAAM,WAAW,aAQtB,CAAC;AAMH;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,
|
|
1
|
+
{"version":3,"file":"probes.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/storyboard/probes.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,gBAAgB,EAChB,eAAe,IAAI,qBAAqB,EACxC,WAAW,IAAI,iBAAiB,EACjC,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAM3C,sEAAsE;AACtE,eAAO,MAAM,WAAW,aAQtB,CAAC;AAMH;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;CAAO,GACjE,OAAO,CAAC,eAAe,CAAC,CAO1B;AAMD;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAChD,UAAU,EAAE,eAAe,GAAG,SAAS,EACvC,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;CAAO,GACjE,OAAO,CAAC,eAAe,CAAC,CA2B1B;AAMD,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC,CAwBvG;AAMD;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAOjD;AA2LD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,0EAA0E;IAC1E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB,GAAG,OAAO,CAAC;IAAE,UAAU,EAAE,eAAe,CAAC;IAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC,CAmGpE;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE;IACzC,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,0EAA0E;IAC1E,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,UAAU,EAAE,eAAe,CAAC;IAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC,CAkFpE;AAMD,eAAO,MAAM,eAAe,8BAAwB,CAAC;AACrD,eAAO,MAAM,WAAW,0BAAoB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -46,7 +46,10 @@ const PROBE_TASKS = /* @__PURE__ */ new Set([
|
|
|
46
46
|
async function probeProtectedResourceMetadata(agentUrl, options = {}) {
|
|
47
47
|
const u = new URL(agentUrl);
|
|
48
48
|
const metadataUrl = `${u.origin}/.well-known/oauth-protected-resource${u.pathname}`;
|
|
49
|
-
return fetchProbe(metadataUrl, {
|
|
49
|
+
return fetchProbe(metadataUrl, {
|
|
50
|
+
allowPrivateIp: options.allowPrivateIp ?? false,
|
|
51
|
+
fetchFn: options.fetchFn
|
|
52
|
+
});
|
|
50
53
|
}
|
|
51
54
|
async function probeOauthAuthServerMetadata(priorProbe, options = {}) {
|
|
52
55
|
if (!priorProbe || priorProbe.error) {
|
|
@@ -71,7 +74,10 @@ async function probeOauthAuthServerMetadata(priorProbe, options = {}) {
|
|
|
71
74
|
}
|
|
72
75
|
const issuer = servers[0].replace(/\/$/, "");
|
|
73
76
|
const metadataUrl = `${issuer}/.well-known/oauth-authorization-server`;
|
|
74
|
-
return fetchProbe(metadataUrl, {
|
|
77
|
+
return fetchProbe(metadataUrl, {
|
|
78
|
+
allowPrivateIp: options.allowPrivateIp ?? false,
|
|
79
|
+
fetchFn: options.fetchFn
|
|
80
|
+
});
|
|
75
81
|
}
|
|
76
82
|
async function fetchProbe(url, options = {}) {
|
|
77
83
|
try {
|
|
@@ -79,7 +85,8 @@ async function fetchProbe(url, options = {}) {
|
|
|
79
85
|
method: "GET",
|
|
80
86
|
headers: { accept: "application/json" },
|
|
81
87
|
allowPrivateIp: options.allowPrivateIp ?? false,
|
|
82
|
-
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
|
|
88
|
+
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
|
|
89
|
+
...options.fetchFn ? { trustedFetchFn: options.fetchFn } : {}
|
|
83
90
|
});
|
|
84
91
|
return {
|
|
85
92
|
url,
|
|
@@ -138,7 +145,8 @@ async function postRawMcpJsonRpc(options) {
|
|
|
138
145
|
...protocolVersion ? { [MCP_PROTOCOL_VERSION_HEADER]: protocolVersion } : {}
|
|
139
146
|
},
|
|
140
147
|
body: JSON.stringify(envelope),
|
|
141
|
-
allowPrivateIp
|
|
148
|
+
allowPrivateIp,
|
|
149
|
+
...options.fetchFn ? { trustedFetchFn: options.fetchFn } : {}
|
|
142
150
|
});
|
|
143
151
|
httpResult.status = res.status;
|
|
144
152
|
httpResult.headers = res.headers;
|
|
@@ -241,7 +249,7 @@ function taskResultFromPostFailure(posted) {
|
|
|
241
249
|
return failedTaskResult(posted.httpResult.error ?? `HTTP ${posted.httpResult.status}`);
|
|
242
250
|
}
|
|
243
251
|
async function rawMcpProbe(options) {
|
|
244
|
-
const { agentUrl, toolName, args, headers = {}, allowPrivateIp = false } = options;
|
|
252
|
+
const { agentUrl, toolName, args, headers = {}, allowPrivateIp = false, fetchFn } = options;
|
|
245
253
|
const initializeId = ++probeRequestId;
|
|
246
254
|
const initialize = await postRawMcpJsonRpc({
|
|
247
255
|
agentUrl,
|
|
@@ -257,6 +265,7 @@ async function rawMcpProbe(options) {
|
|
|
257
265
|
},
|
|
258
266
|
headers,
|
|
259
267
|
allowPrivateIp,
|
|
268
|
+
fetchFn,
|
|
260
269
|
responseId: initializeId
|
|
261
270
|
});
|
|
262
271
|
if (initialize.httpResult.error || initialize.httpResult.status >= 400 || !initialize.parsed || initialize.parsed.error) {
|
|
@@ -284,6 +293,7 @@ async function rawMcpProbe(options) {
|
|
|
284
293
|
},
|
|
285
294
|
headers,
|
|
286
295
|
allowPrivateIp,
|
|
296
|
+
fetchFn,
|
|
287
297
|
...sessionId && { sessionId },
|
|
288
298
|
protocolVersion: negotiatedProtocolVersion,
|
|
289
299
|
allowEmptyBody: true
|
|
@@ -306,6 +316,7 @@ async function rawMcpProbe(options) {
|
|
|
306
316
|
envelope: toolEnvelope,
|
|
307
317
|
headers,
|
|
308
318
|
allowPrivateIp,
|
|
319
|
+
fetchFn,
|
|
309
320
|
...sessionId && { sessionId },
|
|
310
321
|
protocolVersion: negotiatedProtocolVersion,
|
|
311
322
|
responseId: requestId
|