@adcp/sdk 8.1.0-beta.1 → 8.1.0-beta.11
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 +16 -1
- package/bin/adcp.js +75 -21
- package/dist/lib/conformance/oracle.d.ts.map +1 -1
- package/dist/lib/conformance/oracle.js +8 -1
- package/dist/lib/conformance/oracle.js.map +1 -1
- package/dist/lib/conformance/schemaArbitrary.js +135 -9
- package/dist/lib/conformance/schemaArbitrary.js.map +1 -1
- package/dist/lib/core/AgentClient.d.ts +1 -1
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/AgentClient.js.map +1 -1
- package/dist/lib/core/GovernanceMiddleware.d.ts +2 -1
- package/dist/lib/core/GovernanceMiddleware.d.ts.map +1 -1
- package/dist/lib/core/GovernanceMiddleware.js +9 -2
- package/dist/lib/core/GovernanceMiddleware.js.map +1 -1
- package/dist/lib/core/ResponseValidator.js +1 -1
- package/dist/lib/core/ResponseValidator.js.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.ts +6 -0
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +2 -3
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/core/TaskExecutor.d.ts +1 -0
- package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
- package/dist/lib/core/TaskExecutor.js +14 -3
- package/dist/lib/core/TaskExecutor.js.map +1 -1
- package/dist/lib/index.d.ts +3 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +26 -11
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/media-buy/index.d.ts +1 -1
- package/dist/lib/media-buy/index.d.ts.map +1 -1
- package/dist/lib/media-buy/index.js.map +1 -1
- package/dist/lib/media-buy/types.d.ts +12 -52
- package/dist/lib/media-buy/types.d.ts.map +1 -1
- package/dist/lib/media-buy/types.js +12 -15
- package/dist/lib/media-buy/types.js.map +1 -1
- package/dist/lib/net/index.d.ts +1 -1
- package/dist/lib/net/index.d.ts.map +1 -1
- package/dist/lib/net/index.js +2 -1
- package/dist/lib/net/index.js.map +1 -1
- package/dist/lib/protocols/index.d.ts +10 -2
- package/dist/lib/protocols/index.d.ts.map +1 -1
- package/dist/lib/protocols/index.js +7 -6
- package/dist/lib/protocols/index.js.map +1 -1
- package/dist/lib/schemas/index.d.ts +68 -10
- package/dist/lib/schemas/index.d.ts.map +1 -1
- package/dist/lib/schemas/index.js +57 -16
- package/dist/lib/schemas/index.js.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/create-adcp-server.d.ts +59 -53
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +62 -10
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/decisioning/account.d.ts +22 -6
- package/dist/lib/server/decisioning/account.d.ts.map +1 -1
- package/dist/lib/server/decisioning/account.js.map +1 -1
- package/dist/lib/server/decisioning/capabilities.d.ts +8 -0
- package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.d.ts +12 -11
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/list-helpers.d.ts +3 -2
- package/dist/lib/server/decisioning/list-helpers.d.ts.map +1 -1
- package/dist/lib/server/decisioning/list-helpers.js +0 -1
- package/dist/lib/server/decisioning/list-helpers.js.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.d.ts +8 -2
- package/dist/lib/server/decisioning/manifest-helpers.d.ts.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.js +8 -2
- package/dist/lib/server/decisioning/manifest-helpers.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/dispatch.d.ts +3 -2
- package/dist/lib/server/decisioning/proposal/dispatch.d.ts.map +1 -1
- package/dist/lib/server/decisioning/proposal/dispatch.js +1 -0
- package/dist/lib/server/decisioning/proposal/dispatch.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/mock-manager.d.ts +3 -2
- 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/types.d.ts +3 -2
- 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/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +14 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/specialisms/audiences.d.ts +4 -1
- package/dist/lib/server/decisioning/specialisms/audiences.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts +19 -7
- package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts +9 -4
- package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/content-standards.d.ts +17 -8
- package/dist/lib/server/decisioning/specialisms/content-standards.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +13 -5
- package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/creative.d.ts +14 -9
- package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/lists.d.ts +21 -10
- package/dist/lib/server/decisioning/specialisms/lists.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.ts +27 -12
- package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/signals.d.ts +5 -2
- package/dist/lib/server/decisioning/specialisms/signals.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.d.ts +9 -4
- package/dist/lib/server/decisioning/specialisms/sponsored-intelligence.d.ts.map +1 -1
- package/dist/lib/server/index.d.ts +2 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/operational-platform.d.ts +4 -3
- package/dist/lib/server/operational-platform.d.ts.map +1 -1
- package/dist/lib/server/operational-platform.js.map +1 -1
- package/dist/lib/server/responses.d.ts +28 -27
- package/dist/lib/server/responses.d.ts.map +1 -1
- package/dist/lib/server/responses.js +96 -35
- package/dist/lib/server/responses.js.map +1 -1
- package/dist/lib/signing/types.d.ts +6 -0
- package/dist/lib/signing/types.d.ts.map +1 -1
- package/dist/lib/signing/types.js.map +1 -1
- package/dist/lib/signing/verifier.d.ts.map +1 -1
- package/dist/lib/signing/verifier.js +33 -4
- package/dist/lib/signing/verifier.js.map +1 -1
- package/dist/lib/testing/client.d.ts +5 -0
- package/dist/lib/testing/client.d.ts.map +1 -1
- package/dist/lib/testing/client.js +34 -3
- package/dist/lib/testing/client.js.map +1 -1
- package/dist/lib/testing/compliance/comply.d.ts +8 -1
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +57 -25
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/types.d.ts +2 -0
- package/dist/lib/testing/compliance/types.d.ts.map +1 -1
- package/dist/lib/testing/index.d.ts +1 -1
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js +4 -1
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.d.ts.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.js +12 -9
- package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
- package/dist/lib/testing/storyboard/compliance.d.ts +11 -1
- package/dist/lib/testing/storyboard/compliance.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/compliance.js +37 -3
- package/dist/lib/testing/storyboard/compliance.js.map +1 -1
- package/dist/lib/testing/storyboard/context.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/context.js +26 -11
- package/dist/lib/testing/storyboard/context.js.map +1 -1
- package/dist/lib/testing/storyboard/index.d.ts +2 -2
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/index.js +6 -2
- package/dist/lib/testing/storyboard/index.js.map +1 -1
- package/dist/lib/testing/storyboard/probes.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/probes.js +3 -0
- package/dist/lib/testing/storyboard/probes.js.map +1 -1
- package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/request-builder.js +4 -1
- package/dist/lib/testing/storyboard/request-builder.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts +2 -0
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +357 -47
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/types.d.ts +65 -0
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/types.js.map +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +4 -3
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/validations.js +27 -3
- package/dist/lib/testing/storyboard/validations.js.map +1 -1
- package/dist/lib/testing/types.d.ts +19 -0
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/types/activate-signal.d.ts +647 -0
- package/dist/lib/types/build-creative.d.ts +2105 -0
- package/dist/lib/types/calibrate-content.d.ts +675 -0
- package/dist/lib/types/check-governance.d.ts +619 -0
- package/dist/lib/types/comply-test-controller.d.ts +8428 -0
- package/dist/lib/types/core.generated.d.ts +547 -537
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js +1 -1
- package/dist/lib/types/create-collection-list.d.ts +693 -0
- package/dist/lib/types/create-content-standards.d.ts +830 -0
- package/dist/lib/types/create-media-buy.d.ts +3374 -0
- package/dist/lib/types/create-property-list.d.ts +836 -0
- package/dist/lib/types/delete-collection-list.d.ts +497 -0
- package/dist/lib/types/delete-property-list.d.ts +497 -0
- package/dist/lib/types/get-account-financials.d.ts +624 -0
- package/dist/lib/types/get-adcp-capabilities.d.ts +2863 -0
- package/dist/lib/types/get-collection-list.d.ts +763 -0
- package/dist/lib/types/get-content-standards.d.ts +919 -0
- package/dist/lib/types/get-creative-delivery.d.ts +2219 -0
- package/dist/lib/types/get-creative-features.d.ts +1736 -0
- package/dist/lib/types/get-media-buy-artifacts.d.ts +864 -0
- package/dist/lib/types/get-media-buys.d.ts +1670 -0
- package/dist/lib/types/get-plan-audit-logs.d.ts +455 -0
- package/dist/lib/types/get-products.d.ts +4935 -0
- package/dist/lib/types/get-property-list.d.ts +874 -0
- package/dist/lib/types/get-signals.d.ts +986 -0
- package/dist/lib/types/index.d.ts +2 -0
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js +1 -0
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/types/inline-enums.generated.d.ts +163 -7
- package/dist/lib/types/inline-enums.generated.d.ts.map +1 -1
- package/dist/lib/types/inline-enums.generated.js +222 -9
- package/dist/lib/types/inline-enums.generated.js.map +1 -1
- package/dist/lib/types/list-accounts.d.ts +851 -0
- package/dist/lib/types/list-content-standards.d.ts +975 -0
- package/dist/lib/types/list-creative-formats.d.ts +3132 -0
- package/dist/lib/types/list-creatives.d.ts +2390 -0
- package/dist/lib/types/list-property-lists.d.ts +855 -0
- package/dist/lib/types/log-event.d.ts +373 -0
- package/dist/lib/types/per-tool-index.json +391 -0
- package/dist/lib/types/preview-creative.d.ts +1981 -0
- package/dist/lib/types/provide-performance-feedback.d.ts +218 -0
- package/dist/lib/types/report-plan-outcome.d.ts +433 -0
- package/dist/lib/types/report-usage.d.ts +579 -0
- package/dist/lib/types/schemas.generated.d.ts +146765 -128986
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +405 -437
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/server-payload-aliases.d.ts +78 -0
- package/dist/lib/types/server-payload-aliases.d.ts.map +1 -0
- package/dist/lib/types/server-payload-aliases.js +11 -0
- package/dist/lib/types/server-payload-aliases.js.map +1 -0
- package/dist/lib/types/server-payload.d.ts +39 -0
- package/dist/lib/types/server-payload.d.ts.map +1 -0
- package/dist/lib/types/server-payload.js +11 -0
- package/dist/lib/types/server-payload.js.map +1 -0
- package/dist/lib/types/si-get-offering.d.ts +259 -0
- package/dist/lib/types/si-initiate-session.d.ts +372 -0
- package/dist/lib/types/si-send-message.d.ts +300 -0
- package/dist/lib/types/si-terminate-session.d.ts +213 -0
- package/dist/lib/types/sync-accounts.d.ts +856 -0
- package/dist/lib/types/sync-audiences.d.ts +707 -0
- package/dist/lib/types/sync-catalogs.d.ts +766 -0
- package/dist/lib/types/sync-creatives.d.ts +2134 -0
- package/dist/lib/types/sync-event-sources.d.ts +665 -0
- package/dist/lib/types/sync-governance.d.ts +558 -0
- package/dist/lib/types/sync-plans.d.ts +979 -0
- package/dist/lib/types/tools.generated.d.ts +236 -188
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/types/update-collection-list.d.ts +697 -0
- package/dist/lib/types/update-content-standards.d.ts +847 -0
- package/dist/lib/types/update-media-buy.d.ts +3047 -0
- package/dist/lib/types/update-property-list.d.ts +840 -0
- package/dist/lib/types/validate-content-delivery.d.ts +722 -0
- package/dist/lib/types/validate-input.d.ts +1683 -0
- package/dist/lib/utils/adcp-version-config.d.ts +2 -0
- package/dist/lib/utils/adcp-version-config.d.ts.map +1 -1
- package/dist/lib/utils/adcp-version-config.js +42 -0
- package/dist/lib/utils/adcp-version-config.js.map +1 -1
- package/dist/lib/utils/envelope-status-compat.d.ts +24 -5
- package/dist/lib/utils/envelope-status-compat.d.ts.map +1 -1
- package/dist/lib/utils/envelope-status-compat.js +71 -5
- package/dist/lib/utils/envelope-status-compat.js.map +1 -1
- package/dist/lib/utils/index.d.ts +1 -0
- package/dist/lib/utils/index.d.ts.map +1 -1
- package/dist/lib/utils/index.js +5 -2
- package/dist/lib/utils/index.js.map +1 -1
- package/dist/lib/utils/media-buy-status.d.ts +22 -0
- package/dist/lib/utils/media-buy-status.d.ts.map +1 -0
- package/dist/lib/utils/media-buy-status.js +55 -0
- package/dist/lib/utils/media-buy-status.js.map +1 -0
- package/dist/lib/utils/response-schemas.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.js +3 -0
- package/dist/lib/utils/response-schemas.js.map +1 -1
- package/dist/lib/utils/response-unwrapper.d.ts.map +1 -1
- package/dist/lib/utils/response-unwrapper.js +48 -6
- package/dist/lib/utils/response-unwrapper.js.map +1 -1
- package/dist/lib/utils/tool-request-schemas.d.ts +8574 -1
- package/dist/lib/utils/tool-request-schemas.d.ts.map +1 -1
- package/dist/lib/utils/tool-request-schemas.js +4 -5
- package/dist/lib/utils/tool-request-schemas.js.map +1 -1
- package/dist/lib/utils/union-errors.d.ts +13 -6
- package/dist/lib/utils/union-errors.d.ts.map +1 -1
- package/dist/lib/utils/union-errors.js +34 -7
- package/dist/lib/utils/union-errors.js.map +1 -1
- package/dist/lib/validation/schema-loader.d.ts.map +1 -1
- package/dist/lib/validation/schema-loader.js +68 -15
- package/dist/lib/validation/schema-loader.js.map +1 -1
- package/dist/lib/validation/schema-validator.js +1 -1
- package/dist/lib/validation/schema-validator.js.map +1 -1
- package/dist/lib/version.d.ts +27 -3
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +42 -3
- package/dist/lib/version.js.map +1 -1
- package/examples/error-compliant-server.ts +1 -1
- package/examples/hello_seller_adapter_guaranteed.ts +14 -10
- package/examples/hello_seller_adapter_multi_tenant.ts +27 -23
- package/examples/hello_seller_adapter_non_guaranteed.ts +16 -14
- package/examples/hello_seller_adapter_proposal_mode.ts +22 -6
- package/examples/hello_signals_adapter_marketplace.ts +34 -3
- package/package.json +17 -2
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* - runStoryboardStep(): run a single step (stateless, LLM-friendly)
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.applyStoryboardVersionOptions = applyStoryboardVersionOptions;
|
|
11
|
+
exports.applyAdcpVersionRunOptions = applyAdcpVersionRunOptions;
|
|
10
12
|
exports.resolveCapabilityPath = resolveCapabilityPath;
|
|
11
13
|
exports.evaluateCapabilityPredicate = evaluateCapabilityPredicate;
|
|
12
14
|
exports.__redactSecretsForTest = __redactSecretsForTest;
|
|
@@ -34,12 +36,15 @@ const parallel_dispatch_1 = require("./parallel-dispatch");
|
|
|
34
36
|
const path_1 = require("./path");
|
|
35
37
|
const redact_secrets_1 = require("../../utils/redact-secrets");
|
|
36
38
|
const response_unwrapper_1 = require("../../utils/response-unwrapper");
|
|
39
|
+
const envelope_status_compat_1 = require("../../utils/envelope-status-compat");
|
|
37
40
|
const test_controller_1 = require("../test-controller");
|
|
38
41
|
const request_builder_1 = require("./request-builder");
|
|
39
42
|
const client_2 = require("../client");
|
|
40
43
|
const idempotency_1 = require("../../utils/idempotency");
|
|
41
44
|
const schema_loader_1 = require("../../validation/schema-loader");
|
|
45
|
+
const version_1 = require("../../version");
|
|
42
46
|
const probes_1 = require("./probes");
|
|
47
|
+
const capabilities_types_1 = require("../../signing/agent-resolver/capabilities-types");
|
|
43
48
|
const test_kit_1 = require("./test-kit");
|
|
44
49
|
const loader_1 = require("./loader");
|
|
45
50
|
const probe_dispatch_1 = require("./request-signing/probe-dispatch");
|
|
@@ -65,6 +70,26 @@ const SKIP_DETAILS = {
|
|
|
65
70
|
};
|
|
66
71
|
const CONTROLLER_SEEDING_FAILED_DETAIL = 'Skipped: pre-flight comply_test_controller seeding failed; the agent was not populated with the storyboard fixtures the remaining phases depend on.';
|
|
67
72
|
const OAUTH_NOT_ADVERTISED_DETAIL = 'Skipped: agent does not advertise OAuth — /.well-known/oauth-protected-resource returned 404 (RFC 9728 §3). API-key path must carry auth_mechanism_verified for this storyboard to pass.';
|
|
73
|
+
function applyStoryboardVersionOptions(storyboard, options) {
|
|
74
|
+
return applyAdcpVersionRunOptions(storyboard.adcp_version, options);
|
|
75
|
+
}
|
|
76
|
+
function applyAdcpVersionRunOptions(defaultAdcpVersion, options) {
|
|
77
|
+
const adcpVersion = options.adcpVersion ?? defaultAdcpVersion;
|
|
78
|
+
if (adcpVersion === undefined)
|
|
79
|
+
return options;
|
|
80
|
+
const versionEnvelope = options.versionEnvelope ?? storyboardVersionEnvelopeMode(adcpVersion);
|
|
81
|
+
if (options.adcpVersion === adcpVersion && options.versionEnvelope === versionEnvelope) {
|
|
82
|
+
return options;
|
|
83
|
+
}
|
|
84
|
+
return { ...options, adcpVersion, versionEnvelope };
|
|
85
|
+
}
|
|
86
|
+
function storyboardVersionEnvelopeMode(adcpVersion) {
|
|
87
|
+
const bundleKey = (0, schema_loader_1.resolveBundleKey)(adcpVersion);
|
|
88
|
+
const major = (0, version_1.parseAdcpMajorVersion)(bundleKey);
|
|
89
|
+
if (Number.isFinite(major) && major < 3)
|
|
90
|
+
return 'none';
|
|
91
|
+
return 'auto';
|
|
92
|
+
}
|
|
68
93
|
/**
|
|
69
94
|
* Suffix appended to the skip detail when the sole-stateful-step exemption
|
|
70
95
|
* fires (`not_applicable` / `missing_tool` / `missing_test_controller` on
|
|
@@ -179,6 +204,107 @@ function evaluateCapabilityPredicate(predicate, actual) {
|
|
|
179
204
|
function buildSkip(reason, detail) {
|
|
180
205
|
return { reason, detail: detail ?? SKIP_DETAILS[reason] };
|
|
181
206
|
}
|
|
207
|
+
function detectResponseDerivedNotApplicable(step, request, response, runState, allSteps) {
|
|
208
|
+
if (response === undefined || response === null)
|
|
209
|
+
return null;
|
|
210
|
+
const gates = [
|
|
211
|
+
...normalizeResponseNotApplicableGates(step.not_applicable_if),
|
|
212
|
+
...inferImplicitResponseNotApplicableGates(step, request, runState, allSteps),
|
|
213
|
+
];
|
|
214
|
+
for (const gate of gates) {
|
|
215
|
+
if (gate.kind !== 'terminal_page')
|
|
216
|
+
continue;
|
|
217
|
+
if (!terminalPageGateMatches(gate, request, response))
|
|
218
|
+
continue;
|
|
219
|
+
const detail = gate.detail ??
|
|
220
|
+
`${gate.reason ?? 'single_page_result'}: ${step.task} response is terminal; cursor-walk not applicable`;
|
|
221
|
+
return {
|
|
222
|
+
detail,
|
|
223
|
+
contextKeys: responseNotApplicableContextKeys(step, gate),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
function normalizeResponseNotApplicableGates(gates) {
|
|
229
|
+
if (!gates)
|
|
230
|
+
return [];
|
|
231
|
+
return Array.isArray(gates) ? gates : [gates];
|
|
232
|
+
}
|
|
233
|
+
function inferImplicitResponseNotApplicableGates(step, request, runState, allSteps) {
|
|
234
|
+
// Back-compat for the already-published pagination_integrity_list_accounts
|
|
235
|
+
// storyboard: it expresses the continuation requirement as validations
|
|
236
|
+
// rather than a dedicated response-derived gate. Keep this narrowly scoped
|
|
237
|
+
// to list_accounts so other seeded pagination storyboards do not silently
|
|
238
|
+
// waive fixture/setup mistakes.
|
|
239
|
+
if (step.task !== 'list_accounts')
|
|
240
|
+
return [];
|
|
241
|
+
const expectsContinuation = step.validations?.some(v => v.check === 'field_value' && v.path === 'pagination.has_more' && v.value === true);
|
|
242
|
+
const capturesCursor = step.context_outputs?.some(o => o.path === 'pagination.cursor');
|
|
243
|
+
const validatesCursor = step.validations?.some(v => v.check === 'field_present' && v.path === 'pagination.cursor');
|
|
244
|
+
if (!expectsContinuation || (!capturesCursor && !validatesCursor))
|
|
245
|
+
return [];
|
|
246
|
+
const maxResults = (0, path_1.resolvePath)(request, 'pagination.max_results');
|
|
247
|
+
if (typeof maxResults === 'number' &&
|
|
248
|
+
Number.isFinite(maxResults) &&
|
|
249
|
+
hasUnrunAccountSeedExceedingPageSize(allSteps, runState, maxResults)) {
|
|
250
|
+
return [];
|
|
251
|
+
}
|
|
252
|
+
const setupAccounts = (0, path_1.resolvePath)(runState?.priorStepResults.get('sync_three_accounts')?.response, 'accounts');
|
|
253
|
+
if (typeof maxResults === 'number' &&
|
|
254
|
+
Number.isFinite(maxResults) &&
|
|
255
|
+
Array.isArray(setupAccounts) &&
|
|
256
|
+
setupAccounts.length > maxResults) {
|
|
257
|
+
return [];
|
|
258
|
+
}
|
|
259
|
+
return [{ kind: 'terminal_page', items_path: 'accounts', reason: 'single_page_result' }];
|
|
260
|
+
}
|
|
261
|
+
function hasUnrunAccountSeedExceedingPageSize(allSteps, runState, maxResults) {
|
|
262
|
+
return (allSteps?.some(({ step }) => {
|
|
263
|
+
if (runState?.priorStepResults.has(step.id))
|
|
264
|
+
return false;
|
|
265
|
+
if (step.task !== 'sync_accounts')
|
|
266
|
+
return false;
|
|
267
|
+
const accounts = (0, path_1.resolvePath)(step.sample_request, 'accounts');
|
|
268
|
+
return Array.isArray(accounts) && accounts.length > maxResults;
|
|
269
|
+
}) ?? false);
|
|
270
|
+
}
|
|
271
|
+
function terminalPageGateMatches(gate, request, response) {
|
|
272
|
+
const maxResults = (0, path_1.resolvePath)(request, gate.request_max_results_path ?? 'pagination.max_results');
|
|
273
|
+
if (typeof maxResults !== 'number' || !Number.isFinite(maxResults) || maxResults <= 0)
|
|
274
|
+
return false;
|
|
275
|
+
const items = (0, path_1.resolvePath)(response, gate.items_path);
|
|
276
|
+
if (!Array.isArray(items))
|
|
277
|
+
return false;
|
|
278
|
+
const pagination = (0, path_1.resolvePath)(response, 'pagination');
|
|
279
|
+
if (pagination === undefined || pagination === null)
|
|
280
|
+
return items.length < maxResults;
|
|
281
|
+
if (typeof pagination !== 'object' || Array.isArray(pagination))
|
|
282
|
+
return false;
|
|
283
|
+
const p = pagination;
|
|
284
|
+
if (p.has_more === true)
|
|
285
|
+
return false;
|
|
286
|
+
if (p.has_more !== false)
|
|
287
|
+
return false;
|
|
288
|
+
if (typeof p.total_count === 'number' && p.total_count > items.length)
|
|
289
|
+
return false;
|
|
290
|
+
if (items.length < maxResults)
|
|
291
|
+
return true;
|
|
292
|
+
return typeof p.total_count === 'number' && p.total_count <= items.length;
|
|
293
|
+
}
|
|
294
|
+
function responseNotApplicableContextKeys(step, gate) {
|
|
295
|
+
if (gate.context_keys?.length)
|
|
296
|
+
return gate.context_keys;
|
|
297
|
+
return (step.context_outputs ?? [])
|
|
298
|
+
.filter(o => o.path === 'pagination.cursor')
|
|
299
|
+
.map(o => o.key)
|
|
300
|
+
.filter((key) => typeof key === 'string' && key.length > 0);
|
|
301
|
+
}
|
|
302
|
+
function responseDerivedContextResult(runState) {
|
|
303
|
+
const entries = runState.responseDerivedNotApplicableContextKeys;
|
|
304
|
+
return entries && entries.size > 0
|
|
305
|
+
? { response_derived_not_applicable_context_keys: Object.fromEntries(entries) }
|
|
306
|
+
: {};
|
|
307
|
+
}
|
|
182
308
|
/**
|
|
183
309
|
* True for skip reasons that imply state genuinely never materialized
|
|
184
310
|
* — no other code path could have established it. The runner trips
|
|
@@ -400,7 +526,7 @@ function remapTaskCompletionOutputs(outputs) {
|
|
|
400
526
|
return o;
|
|
401
527
|
});
|
|
402
528
|
}
|
|
403
|
-
async function resolveTaskCompletionOutputs(taskResult, outputs, client, webhookReceiver) {
|
|
529
|
+
async function resolveTaskCompletionOutputs(taskResult, outputs, client, webhookReceiver, originatingTaskName) {
|
|
404
530
|
const hasTaskCompletionPath = outputs.some(o => typeof o.path === 'string' && o.path.startsWith(TASK_COMPLETION_PATH_PREFIX));
|
|
405
531
|
if (!hasTaskCompletionPath)
|
|
406
532
|
return { attempted: false };
|
|
@@ -473,7 +599,7 @@ async function resolveTaskCompletionOutputs(taskResult, outputs, client, webhook
|
|
|
473
599
|
const polled = winner.result;
|
|
474
600
|
if (polled.success === false)
|
|
475
601
|
return { attempted: true, taskFailed: true };
|
|
476
|
-
return { attempted: true, data: polled.data };
|
|
602
|
+
return { attempted: true, data: normalizeTaskCompletionData(polled.data, originatingTaskName) };
|
|
477
603
|
}
|
|
478
604
|
// Webhook win.
|
|
479
605
|
const waitResult = winner.result;
|
|
@@ -488,7 +614,7 @@ async function resolveTaskCompletionOutputs(taskResult, outputs, client, webhook
|
|
|
488
614
|
// attribute to `capture_task_failed`, not silently fall through to a
|
|
489
615
|
// capture against an undefined `result`.
|
|
490
616
|
if (webhookBody?.status === 'completed') {
|
|
491
|
-
return { attempted: true, data: webhookBody.result };
|
|
617
|
+
return { attempted: true, data: normalizeTaskCompletionData(webhookBody.result, originatingTaskName) };
|
|
492
618
|
}
|
|
493
619
|
return { attempted: true, taskFailed: true };
|
|
494
620
|
}
|
|
@@ -500,6 +626,23 @@ async function resolveTaskCompletionOutputs(taskResult, outputs, client, webhook
|
|
|
500
626
|
clearTimeout(timer);
|
|
501
627
|
}
|
|
502
628
|
}
|
|
629
|
+
function normalizeTaskCompletionData(data, taskName) {
|
|
630
|
+
if (data == null || typeof data !== 'object' || Array.isArray(data))
|
|
631
|
+
return data;
|
|
632
|
+
const original = data;
|
|
633
|
+
const compat = (0, envelope_status_compat_1.injectLegacyEnvelopeStatus)(original, { toolName: taskName });
|
|
634
|
+
if (!('status' in original) && 'status' in compat) {
|
|
635
|
+
const { status: _status, ...rest } = compat;
|
|
636
|
+
return (0, envelope_status_compat_1.normalizeLegacyMediaBuyStatusForReturn)(rest, { toolName: taskName });
|
|
637
|
+
}
|
|
638
|
+
if ((taskName === 'create_media_buy' || taskName === 'update_media_buy') &&
|
|
639
|
+
typeof original.status === 'string' &&
|
|
640
|
+
compat.status === 'completed' &&
|
|
641
|
+
typeof compat.media_buy_status === 'string') {
|
|
642
|
+
return (0, envelope_status_compat_1.normalizeLegacyMediaBuyStatusForReturn)({ ...compat, status: original.status }, { toolName: taskName });
|
|
643
|
+
}
|
|
644
|
+
return (0, envelope_status_compat_1.normalizeLegacyMediaBuyStatusForReturn)(compat, { toolName: taskName });
|
|
645
|
+
}
|
|
503
646
|
function readEnvIntOrDefault(value, fallback) {
|
|
504
647
|
if (!value)
|
|
505
648
|
return fallback;
|
|
@@ -571,6 +714,7 @@ function filterResponseHeaders(headers) {
|
|
|
571
714
|
* empty on instance B.
|
|
572
715
|
*/
|
|
573
716
|
async function runStoryboard(agentUrlOrUrls, storyboard, options = {}) {
|
|
717
|
+
options = applyStoryboardVersionOptions(storyboard, options);
|
|
574
718
|
(0, test_kit_1.validateTestKit)(options.test_kit);
|
|
575
719
|
// Enforce authoring-time branch_set invariants regardless of how the
|
|
576
720
|
// storyboard reached us. YAML callers already ran these rules in
|
|
@@ -1211,6 +1355,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1211
1355
|
let clients;
|
|
1212
1356
|
let routingContext;
|
|
1213
1357
|
let profile;
|
|
1358
|
+
let callerOwnsClients = false;
|
|
1214
1359
|
if (useRouting) {
|
|
1215
1360
|
try {
|
|
1216
1361
|
routingContext = await (0, agent_routing_1.buildRoutingContext)(storyboard, options);
|
|
@@ -1225,8 +1370,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1225
1370
|
duration_ms: 0,
|
|
1226
1371
|
error: detail,
|
|
1227
1372
|
};
|
|
1228
|
-
|
|
1229
|
-
await (0, protocols_1.closeConnections)(options.protocol);
|
|
1373
|
+
await (0, protocols_1.closeConnections)(options.protocol);
|
|
1230
1374
|
return buildDiscoveryFailedResult(agentUrls, storyboard, failedStep);
|
|
1231
1375
|
}
|
|
1232
1376
|
clients = [...routingContext.clients.values()];
|
|
@@ -1258,7 +1402,9 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1258
1402
|
else {
|
|
1259
1403
|
// Build one client per URL. In single-URL mode `_client` (from comply()) is
|
|
1260
1404
|
// honored so the shared MCP transport is reused across storyboards.
|
|
1261
|
-
|
|
1405
|
+
const clientResolutions = agentUrls.map(url => (0, client_1.getOrCreateClientResolution)(url, options));
|
|
1406
|
+
clients = clientResolutions.map(r => r.client);
|
|
1407
|
+
callerOwnsClients = clientResolutions.some(r => r.reusedShared);
|
|
1262
1408
|
// Drop any retained A2A session ids before this storyboard's first call.
|
|
1263
1409
|
// `comply()` shares one client across N storyboards for transport reuse;
|
|
1264
1410
|
// AgentClient.retainSession holds onto `pendingTaskId` from non-terminal
|
|
@@ -1273,7 +1419,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1273
1419
|
// expected to run the same code behind a shared state store, so one probe
|
|
1274
1420
|
// is sufficient. For multi-instance runs, skipping N-1 redundant
|
|
1275
1421
|
// get_agent_info calls also keeps CI output clean.
|
|
1276
|
-
if (!
|
|
1422
|
+
if (!callerOwnsClients) {
|
|
1277
1423
|
const discovered = await (0, client_1.getOrDiscoverProfile)(clients[0], options);
|
|
1278
1424
|
// Discovery failure must surface as a HARD STORYBOARD FAILURE, not a
|
|
1279
1425
|
// silent empty `agentTools: []` that lets every step skip with
|
|
@@ -1282,8 +1428,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1282
1428
|
// (auth misconfig, MCP transport-fallback bugs, network policy, etc.).
|
|
1283
1429
|
// See: https://github.com/adcontextprotocol/adcp-client/issues/...
|
|
1284
1430
|
if (discovered.step.passed === false) {
|
|
1285
|
-
|
|
1286
|
-
await (0, protocols_1.closeConnections)(options.protocol);
|
|
1431
|
+
await (0, protocols_1.closeConnections)(options.protocol);
|
|
1287
1432
|
return buildDiscoveryFailedResult(agentUrls, storyboard, discovered.step);
|
|
1288
1433
|
}
|
|
1289
1434
|
profile = discovered.profile;
|
|
@@ -1329,7 +1474,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1329
1474
|
if (allRequires.length) {
|
|
1330
1475
|
const unmet = checkRequires(allRequires, options, profile);
|
|
1331
1476
|
if (unmet) {
|
|
1332
|
-
if (!
|
|
1477
|
+
if (!callerOwnsClients)
|
|
1333
1478
|
await (0, protocols_1.closeConnections)(options.protocol);
|
|
1334
1479
|
return {
|
|
1335
1480
|
...buildRequirementUnmetResult(agentUrls, storyboard, unmet.requirement, unmet.detail),
|
|
@@ -1348,7 +1493,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1348
1493
|
const actual = resolveCapabilityPath(rawCaps, cap.path);
|
|
1349
1494
|
const unmetDetail = evaluateCapabilityPredicate(cap, actual);
|
|
1350
1495
|
if (unmetDetail !== null) {
|
|
1351
|
-
if (!
|
|
1496
|
+
if (!callerOwnsClients)
|
|
1352
1497
|
await (0, protocols_1.closeConnections)(options.protocol);
|
|
1353
1498
|
return {
|
|
1354
1499
|
...buildCapabilityUnsupportedResult(agentUrls, storyboard, unmetDetail),
|
|
@@ -1371,7 +1516,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1371
1516
|
if (storyboard.required_tools?.length && options.agentTools) {
|
|
1372
1517
|
const hasAnyRequired = storyboard.required_tools.some(t => options.agentTools.includes(t));
|
|
1373
1518
|
if (!hasAnyRequired) {
|
|
1374
|
-
if (!
|
|
1519
|
+
if (!callerOwnsClients)
|
|
1375
1520
|
await (0, protocols_1.closeConnections)(options.protocol);
|
|
1376
1521
|
return {
|
|
1377
1522
|
...buildRequiredToolsMissingResult(agentUrls, storyboard, `agent does not advertise any of [${storyboard.required_tools.join(', ')}]`),
|
|
@@ -1394,6 +1539,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1394
1539
|
const contextProvenance = new Map();
|
|
1395
1540
|
const priorA2aEnvelopes = new Map();
|
|
1396
1541
|
const stepRequestStarts = new Map();
|
|
1542
|
+
const responseDerivedNotApplicableContextKeys = new Map();
|
|
1397
1543
|
const phaseResults = [];
|
|
1398
1544
|
let passedCount = 0;
|
|
1399
1545
|
let failedCount = 0;
|
|
@@ -1863,6 +2009,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1863
2009
|
contextProvenance,
|
|
1864
2010
|
priorA2aEnvelopes,
|
|
1865
2011
|
stepRequestStarts,
|
|
2012
|
+
responseDerivedNotApplicableContextKeys,
|
|
1866
2013
|
agentLibraryVersion: profile?.library_version,
|
|
1867
2014
|
});
|
|
1868
2015
|
const result = { ...rawResult, storyboard_id: storyboard.id };
|
|
@@ -2323,7 +2470,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2323
2470
|
// Close protocol connections when the runner created its own client. The
|
|
2324
2471
|
// connection pool is keyed by URL+auth, so a single closeConnections() call
|
|
2325
2472
|
// evicts every instance's transport regardless of how many URLs we used.
|
|
2326
|
-
if (!
|
|
2473
|
+
if (!callerOwnsClients) {
|
|
2327
2474
|
await (0, protocols_1.closeConnections)(options.protocol);
|
|
2328
2475
|
}
|
|
2329
2476
|
if (webhookReceiver)
|
|
@@ -2361,7 +2508,7 @@ async function runMultiPass(agentUrls, storyboard, options) {
|
|
|
2361
2508
|
// only the first pass attaches the synthetic `__controller_seeding__`
|
|
2362
2509
|
// phase to its `phaseResults`, so the aggregated top-level counts reflect
|
|
2363
2510
|
// a single seeding pass across the whole run.
|
|
2364
|
-
const preSeedClients = agentUrls.map(url => (0, client_1.
|
|
2511
|
+
const preSeedClients = agentUrls.map(url => (0, client_1.getOrCreateClientResolution)(url, options).client);
|
|
2365
2512
|
const preSeedContext = { ...options.context };
|
|
2366
2513
|
const preSeededResult = await (0, seeding_1.runControllerSeeding)(preSeedClients[0], storyboard, options, preSeedContext);
|
|
2367
2514
|
const passes = [];
|
|
@@ -2558,15 +2705,17 @@ function summarizeStrictValidation(phases) {
|
|
|
2558
2705
|
* Context is passed in and returned, enabling step-by-step orchestration.
|
|
2559
2706
|
*/
|
|
2560
2707
|
async function runStoryboardStep(agentUrl, storyboard, stepId, options = {}) {
|
|
2708
|
+
options = applyStoryboardVersionOptions(storyboard, options);
|
|
2561
2709
|
(0, test_kit_1.validateTestKit)(options.test_kit);
|
|
2562
|
-
const
|
|
2710
|
+
const clientResolution = (0, client_1.getOrCreateClientResolution)(agentUrl, options);
|
|
2711
|
+
const client = clientResolution.client;
|
|
2563
2712
|
// Discover agent profile for standalone step execution. Captured so the
|
|
2564
2713
|
// executeStep call below can thread `library_version` through to
|
|
2565
2714
|
// shape-drift hint detection (issue #850). Also threads _profile into
|
|
2566
2715
|
// options so capability-based skip gates in executeStep (e.g. account-mode
|
|
2567
2716
|
// branching) can read raw_capabilities, mirroring executeStoryboardPass.
|
|
2568
2717
|
let profile;
|
|
2569
|
-
if (!
|
|
2718
|
+
if (!clientResolution.reusedShared) {
|
|
2570
2719
|
const discovered = await (0, client_1.getOrDiscoverProfile)(client, options);
|
|
2571
2720
|
profile = discovered.profile;
|
|
2572
2721
|
if (profile && !options._profile) {
|
|
@@ -2612,6 +2761,7 @@ async function runStoryboardStep(agentUrl, storyboard, stepId, options = {}) {
|
|
|
2612
2761
|
// previous step's result). Storyboard-level runs build this internally;
|
|
2613
2762
|
// here the caller owns accumulation across stateless invocations.
|
|
2614
2763
|
const contextProvenance = new Map(Object.entries(options.context_provenance ?? {}));
|
|
2764
|
+
const responseDerivedNotApplicableContextKeys = new Map(Object.entries(options.response_derived_not_applicable_context_keys ?? {}));
|
|
2615
2765
|
const result = await executeStep(client, found.step, found.phaseId, context, allSteps, options, {
|
|
2616
2766
|
contributions: new Set(),
|
|
2617
2767
|
priorStepResults: new Map(),
|
|
@@ -2622,9 +2772,10 @@ async function runStoryboardStep(agentUrl, storyboard, stepId, options = {}) {
|
|
|
2622
2772
|
contextProvenance,
|
|
2623
2773
|
priorA2aEnvelopes: new Map(),
|
|
2624
2774
|
stepRequestStarts: new Map(),
|
|
2775
|
+
responseDerivedNotApplicableContextKeys,
|
|
2625
2776
|
agentLibraryVersion: profile?.library_version,
|
|
2626
2777
|
});
|
|
2627
|
-
if (!
|
|
2778
|
+
if (!clientResolution.reusedShared) {
|
|
2628
2779
|
await (0, protocols_1.closeConnections)(options.protocol);
|
|
2629
2780
|
}
|
|
2630
2781
|
if (ownsWebhookReceiver && webhookReceiver)
|
|
@@ -2642,6 +2793,7 @@ client, step, phaseId, context, allSteps, options, state) {
|
|
|
2642
2793
|
agentUrl: '',
|
|
2643
2794
|
contextProvenance: new Map(),
|
|
2644
2795
|
stepRequestStarts: new Map(),
|
|
2796
|
+
responseDerivedNotApplicableContextKeys: new Map(),
|
|
2645
2797
|
};
|
|
2646
2798
|
// HTTP probe tasks bypass the MCP client entirely.
|
|
2647
2799
|
if (probes_1.PROBE_TASKS.has(step.task)) {
|
|
@@ -2810,45 +2962,50 @@ client, step, phaseId, context, allSteps, options, state) {
|
|
|
2810
2962
|
const unresolvedVars = findUnresolvedContextVars(request);
|
|
2811
2963
|
if (unresolvedVars.length > 0 && !step.expect_error) {
|
|
2812
2964
|
const next = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
|
|
2813
|
-
const
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
//
|
|
2821
|
-
//
|
|
2822
|
-
|
|
2965
|
+
const responseDerivedDetails = unresolvedVars
|
|
2966
|
+
.map(v => runState.responseDerivedNotApplicableContextKeys?.get(v.key))
|
|
2967
|
+
.filter((d) => typeof d === 'string');
|
|
2968
|
+
const allResponseDerived = responseDerivedDetails.length === unresolvedVars.length && responseDerivedDetails.length > 0;
|
|
2969
|
+
const detail = allResponseDerived
|
|
2970
|
+
? [...new Set(responseDerivedDetails)].join('; ')
|
|
2971
|
+
: `Skipped: unresolved context variables from prior steps: ${unresolvedVars.map(v => v.key).join(', ')}.`;
|
|
2972
|
+
// Normal unresolved substitutions carry one validation result per missing
|
|
2973
|
+
// token. Response-derived terminal-page skips are already successful
|
|
2974
|
+
// not_applicable rows, so their downstream cursor consumers stay validation
|
|
2975
|
+
// empty to avoid inventing a failing-looking check for an expected skip.
|
|
2823
2976
|
const synthesized = [];
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2977
|
+
if (!allResponseDerived) {
|
|
2978
|
+
const seenTokens = new Set();
|
|
2979
|
+
for (const v of unresolvedVars) {
|
|
2980
|
+
if (seenTokens.has(v.token))
|
|
2981
|
+
continue;
|
|
2982
|
+
seenTokens.add(v.token);
|
|
2983
|
+
synthesized.push({
|
|
2984
|
+
check: 'unresolved_substitution',
|
|
2985
|
+
passed: false,
|
|
2986
|
+
description: `request token "${v.token}" did not resolve — prior step did not populate context.${v.key}`,
|
|
2987
|
+
json_pointer: null,
|
|
2988
|
+
expected: v.token,
|
|
2989
|
+
actual: null,
|
|
2990
|
+
schema_id: null,
|
|
2991
|
+
schema_url: null,
|
|
2992
|
+
});
|
|
2993
|
+
}
|
|
2838
2994
|
}
|
|
2839
2995
|
return {
|
|
2840
2996
|
step_id: step.id,
|
|
2841
2997
|
phase_id: phaseId,
|
|
2842
2998
|
title: step.title,
|
|
2843
2999
|
task: step.task,
|
|
2844
|
-
passed:
|
|
3000
|
+
passed: allResponseDerived,
|
|
2845
3001
|
skipped: true,
|
|
2846
|
-
skip_reason: 'prerequisite_failed',
|
|
2847
|
-
skip: buildSkip('prerequisite_failed', detail),
|
|
3002
|
+
skip_reason: allResponseDerived ? 'not_applicable' : 'prerequisite_failed',
|
|
3003
|
+
skip: buildSkip(allResponseDerived ? 'not_applicable' : 'prerequisite_failed', detail),
|
|
2848
3004
|
duration_ms: 0,
|
|
2849
3005
|
validations: synthesized,
|
|
2850
3006
|
context,
|
|
2851
|
-
|
|
3007
|
+
...responseDerivedContextResult(runState),
|
|
3008
|
+
...(!allResponseDerived && { error: detail }),
|
|
2852
3009
|
next,
|
|
2853
3010
|
extraction: { path: 'none' },
|
|
2854
3011
|
};
|
|
@@ -3203,6 +3360,32 @@ client, step, phaseId, context, allSteps, options, state) {
|
|
|
3203
3360
|
if (step.expect_error && !taskResult?.data && taskResult?.error) {
|
|
3204
3361
|
taskResult = { ...taskResult, data: { error: taskResult.error } };
|
|
3205
3362
|
}
|
|
3363
|
+
const responseDerivedSkip = detectResponseDerivedNotApplicable(effectiveStep, request, taskResult?.data, runState, allSteps);
|
|
3364
|
+
if (responseDerivedSkip && !step.expect_error) {
|
|
3365
|
+
for (const key of responseDerivedSkip.contextKeys) {
|
|
3366
|
+
runState.responseDerivedNotApplicableContextKeys?.set(key, responseDerivedSkip.detail);
|
|
3367
|
+
}
|
|
3368
|
+
const next = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
|
|
3369
|
+
return {
|
|
3370
|
+
step_id: step.id,
|
|
3371
|
+
phase_id: phaseId,
|
|
3372
|
+
title: step.title,
|
|
3373
|
+
task: step.task,
|
|
3374
|
+
passed: true,
|
|
3375
|
+
skipped: true,
|
|
3376
|
+
skip_reason: 'not_applicable',
|
|
3377
|
+
skip: buildSkip('not_applicable', responseDerivedSkip.detail),
|
|
3378
|
+
duration_ms: stepResult.duration_ms,
|
|
3379
|
+
validations: [],
|
|
3380
|
+
context,
|
|
3381
|
+
...responseDerivedContextResult(runState),
|
|
3382
|
+
response: (0, redact_secrets_1.redactSecrets)(taskResult?.data),
|
|
3383
|
+
next,
|
|
3384
|
+
request: requestRecord,
|
|
3385
|
+
...(responseRecord && { response_record: responseRecord }),
|
|
3386
|
+
extraction: extractionFromTaskResult(taskResult),
|
|
3387
|
+
};
|
|
3388
|
+
}
|
|
3206
3389
|
// Determine pass/fail — inverted when expect_error is set
|
|
3207
3390
|
let passed;
|
|
3208
3391
|
if (step.expect_error) {
|
|
@@ -3370,6 +3553,9 @@ client, step, phaseId, context, allSteps, options, state) {
|
|
|
3370
3553
|
if (passed && hasData && taskResult) {
|
|
3371
3554
|
const extracted = (0, context_1.extractContextWithProvenance)(effectiveStep.task, taskResult.data, step.id);
|
|
3372
3555
|
Object.assign(updatedContext, extracted.values);
|
|
3556
|
+
for (const key of Object.keys(extracted.values)) {
|
|
3557
|
+
runState.responseDerivedNotApplicableContextKeys?.delete(key);
|
|
3558
|
+
}
|
|
3373
3559
|
if (runState.contextProvenance) {
|
|
3374
3560
|
for (const [key, entry] of Object.entries(extracted.provenance)) {
|
|
3375
3561
|
runState.contextProvenance.set(key, entry);
|
|
@@ -3387,6 +3573,10 @@ client, step, phaseId, context, allSteps, options, state) {
|
|
|
3387
3573
|
// ensures the minted value from any same-step $generate:…#<key> inline
|
|
3388
3574
|
// substitution is visible here.
|
|
3389
3575
|
if (step.context_outputs?.length) {
|
|
3576
|
+
for (const output of step.context_outputs) {
|
|
3577
|
+
if (output.key)
|
|
3578
|
+
runState.responseDerivedNotApplicableContextKeys?.delete(output.key);
|
|
3579
|
+
}
|
|
3390
3580
|
// Resolve `task_completion.<path>` outputs against the eventual task
|
|
3391
3581
|
// artifact rather than the immediate response. When the immediate
|
|
3392
3582
|
// response is a submitted-arm envelope (HITL / async-signed-IO flows),
|
|
@@ -3401,7 +3591,7 @@ client, step, phaseId, context, allSteps, options, state) {
|
|
|
3401
3591
|
// `capture_poll_timeout` instead of recycling
|
|
3402
3592
|
// `capture_path_not_resolvable` so the failure-class is distinct from
|
|
3403
3593
|
// the original "field absent in immediate response" diagnostic.
|
|
3404
|
-
const taskCompletionResolution = await resolveTaskCompletionOutputs(taskResult, step.context_outputs, client, runState.webhookReceiver);
|
|
3594
|
+
const taskCompletionResolution = await resolveTaskCompletionOutputs(taskResult, step.context_outputs, client, runState.webhookReceiver, effectiveStep.task);
|
|
3405
3595
|
// `'data' in resolution` distinguishes "polled, artifact had no data"
|
|
3406
3596
|
// (use undefined → outputs fail with capture_path_not_resolvable) from
|
|
3407
3597
|
// "did not poll" (fall back to the immediate response data).
|
|
@@ -3413,6 +3603,9 @@ client, step, phaseId, context, allSteps, options, state) {
|
|
|
3413
3603
|
const remappedOutputs = remapTaskCompletionOutputs(step.context_outputs);
|
|
3414
3604
|
const explicit = (0, context_1.applyContextOutputsWithProvenance)(extractionData, remappedOutputs, step.id, effectiveStep.task, updatedContext);
|
|
3415
3605
|
Object.assign(updatedContext, explicit.values);
|
|
3606
|
+
for (const key of Object.keys(explicit.values)) {
|
|
3607
|
+
runState.responseDerivedNotApplicableContextKeys?.delete(key);
|
|
3608
|
+
}
|
|
3416
3609
|
if (runState.contextProvenance) {
|
|
3417
3610
|
for (const [key, entry] of Object.entries(explicit.provenance)) {
|
|
3418
3611
|
runState.contextProvenance.set(key, entry);
|
|
@@ -3543,6 +3736,7 @@ client, step, phaseId, context, allSteps, options, state) {
|
|
|
3543
3736
|
runState.contextProvenance.size > 0 && {
|
|
3544
3737
|
context_provenance: Object.fromEntries(runState.contextProvenance),
|
|
3545
3738
|
}),
|
|
3739
|
+
...responseDerivedContextResult(runState),
|
|
3546
3740
|
error: step.expect_error ? undefined : truncateError(stepResult.error || taskResult?.error),
|
|
3547
3741
|
...(!step.expect_error && taskResult?.adcp_error && { adcp_error: taskResult.adcp_error }),
|
|
3548
3742
|
next,
|
|
@@ -3559,7 +3753,24 @@ async function executeProbeStep(step, phaseId, context, allSteps, options, runSt
|
|
|
3559
3753
|
const start = Date.now();
|
|
3560
3754
|
let httpResult;
|
|
3561
3755
|
const probeOpts = { allowPrivateIp: options.allow_http === true };
|
|
3562
|
-
if (step.
|
|
3756
|
+
if (step.requires_contract) {
|
|
3757
|
+
const contracts = new Set(options.contracts ?? []);
|
|
3758
|
+
if (!contracts.has(step.requires_contract)) {
|
|
3759
|
+
httpResult = {
|
|
3760
|
+
url: runState.agentUrl,
|
|
3761
|
+
status: 0,
|
|
3762
|
+
headers: {},
|
|
3763
|
+
body: null,
|
|
3764
|
+
skipped: true,
|
|
3765
|
+
skip_reason: 'missing_test_kit_contract',
|
|
3766
|
+
error: `Test-kit contract "${step.requires_contract}" is not configured on this runner.`,
|
|
3767
|
+
};
|
|
3768
|
+
}
|
|
3769
|
+
}
|
|
3770
|
+
if (httpResult) {
|
|
3771
|
+
// Contract-gated synthetic probes self-skip before doing any network work.
|
|
3772
|
+
}
|
|
3773
|
+
else if (step.task === 'protected_resource_metadata') {
|
|
3563
3774
|
httpResult = await (0, probes_1.probeProtectedResourceMetadata)(runState.agentUrl, probeOpts);
|
|
3564
3775
|
// RFC 9728 presence semantics (adcp-client#677): a 404 means the agent is
|
|
3565
3776
|
// honestly not advertising OAuth. Convert to a clean step skip so the
|
|
@@ -3585,6 +3796,21 @@ async function executeProbeStep(step, phaseId, context, allSteps, options, runSt
|
|
|
3585
3796
|
else if (step.task === 'request_signing_probe') {
|
|
3586
3797
|
httpResult = await (0, probe_dispatch_1.probeRequestSigningVector)(step.id, runState.agentUrl, options);
|
|
3587
3798
|
}
|
|
3799
|
+
else if (step.task === 'fetch_brand_jwks') {
|
|
3800
|
+
httpResult = await probeBrandJwks(options._profile?.raw_capabilities, probeOpts);
|
|
3801
|
+
}
|
|
3802
|
+
else if (step.task === 'assert_jwks_purpose') {
|
|
3803
|
+
httpResult = assertJwksPurpose(runState.priorProbes.get('fetch_brand_jwks'), 'webhook-signing');
|
|
3804
|
+
}
|
|
3805
|
+
else if (step.task === 'expect_rate_limit_not_replayed') {
|
|
3806
|
+
httpResult = {
|
|
3807
|
+
url: runState.agentUrl,
|
|
3808
|
+
status: 0,
|
|
3809
|
+
headers: {},
|
|
3810
|
+
body: null,
|
|
3811
|
+
error: 'rate_limit_trip_runner contract is configured, but this SDK runner does not yet implement live rate-limit trip/replay probing.',
|
|
3812
|
+
};
|
|
3813
|
+
}
|
|
3588
3814
|
if (httpResult)
|
|
3589
3815
|
runState.priorProbes.set(step.task, httpResult);
|
|
3590
3816
|
const duration = Date.now() - start;
|
|
@@ -3670,6 +3896,90 @@ async function executeProbeStep(step, phaseId, context, allSteps, options, runSt
|
|
|
3670
3896
|
extraction,
|
|
3671
3897
|
};
|
|
3672
3898
|
}
|
|
3899
|
+
async function probeBrandJwks(rawCapabilities, options) {
|
|
3900
|
+
const brandJsonUrl = (0, capabilities_types_1.readBrandJsonUrl)(rawCapabilities);
|
|
3901
|
+
if (!brandJsonUrl) {
|
|
3902
|
+
return {
|
|
3903
|
+
url: '',
|
|
3904
|
+
status: 0,
|
|
3905
|
+
headers: {},
|
|
3906
|
+
body: null,
|
|
3907
|
+
error: 'identity.brand_json_url missing from get_adcp_capabilities; cannot fetch brand JWKS',
|
|
3908
|
+
};
|
|
3909
|
+
}
|
|
3910
|
+
const brand = await (0, probes_1.fetchProbe)(brandJsonUrl, options);
|
|
3911
|
+
if (brand.error || brand.status < 200 || brand.status >= 300) {
|
|
3912
|
+
return {
|
|
3913
|
+
...brand,
|
|
3914
|
+
error: brand.error ?? `brand.json fetch returned HTTP ${brand.status}`,
|
|
3915
|
+
};
|
|
3916
|
+
}
|
|
3917
|
+
const agents = brand.body && typeof brand.body === 'object' ? brand.body.agents : undefined;
|
|
3918
|
+
const jwksUri = Array.isArray(agents)
|
|
3919
|
+
? agents
|
|
3920
|
+
.map(agent => (agent && typeof agent === 'object' ? agent.jwks_uri : undefined))
|
|
3921
|
+
.find((uri) => typeof uri === 'string' && uri.length > 0)
|
|
3922
|
+
: undefined;
|
|
3923
|
+
if (!jwksUri) {
|
|
3924
|
+
return {
|
|
3925
|
+
url: brandJsonUrl,
|
|
3926
|
+
status: 0,
|
|
3927
|
+
headers: {},
|
|
3928
|
+
body: brand.body,
|
|
3929
|
+
error: 'brand.json agents[] did not contain a jwks_uri',
|
|
3930
|
+
};
|
|
3931
|
+
}
|
|
3932
|
+
const jwks = await (0, probes_1.fetchProbe)(jwksUri, options);
|
|
3933
|
+
if (jwks.error || jwks.status < 200 || jwks.status >= 300) {
|
|
3934
|
+
return {
|
|
3935
|
+
...jwks,
|
|
3936
|
+
error: jwks.error ?? `JWKS fetch returned HTTP ${jwks.status}`,
|
|
3937
|
+
};
|
|
3938
|
+
}
|
|
3939
|
+
return jwks;
|
|
3940
|
+
}
|
|
3941
|
+
function assertJwksPurpose(prior, purpose) {
|
|
3942
|
+
if (!prior || prior.error) {
|
|
3943
|
+
return {
|
|
3944
|
+
url: prior?.url ?? '',
|
|
3945
|
+
status: prior?.status ?? 0,
|
|
3946
|
+
headers: prior?.headers ?? {},
|
|
3947
|
+
body: prior?.body ?? null,
|
|
3948
|
+
error: prior?.error ?? 'fetch_brand_jwks step missing; cannot assert JWKS purpose',
|
|
3949
|
+
};
|
|
3950
|
+
}
|
|
3951
|
+
const keys = prior.body && typeof prior.body === 'object' ? prior.body.keys : undefined;
|
|
3952
|
+
if (!Array.isArray(keys)) {
|
|
3953
|
+
return {
|
|
3954
|
+
url: prior.url,
|
|
3955
|
+
status: 0,
|
|
3956
|
+
headers: {},
|
|
3957
|
+
body: prior.body,
|
|
3958
|
+
error: 'JWKS body does not contain keys[]',
|
|
3959
|
+
};
|
|
3960
|
+
}
|
|
3961
|
+
const matching = keys.filter(key => {
|
|
3962
|
+
if (!key || typeof key !== 'object')
|
|
3963
|
+
return false;
|
|
3964
|
+
const rec = key;
|
|
3965
|
+
return rec.adcp_use === purpose && rec.status !== 'revoked' && rec.revoked !== true;
|
|
3966
|
+
});
|
|
3967
|
+
if (matching.length === 0) {
|
|
3968
|
+
return {
|
|
3969
|
+
url: prior.url,
|
|
3970
|
+
status: 0,
|
|
3971
|
+
headers: {},
|
|
3972
|
+
body: prior.body,
|
|
3973
|
+
error: `JWKS contains no active key with adcp_use="${purpose}"`,
|
|
3974
|
+
};
|
|
3975
|
+
}
|
|
3976
|
+
return {
|
|
3977
|
+
url: prior.url,
|
|
3978
|
+
status: 200,
|
|
3979
|
+
headers: prior.headers,
|
|
3980
|
+
body: { purpose, matching_key_count: matching.length },
|
|
3981
|
+
};
|
|
3982
|
+
}
|
|
3673
3983
|
function findPriorProbe(priorStepResults) {
|
|
3674
3984
|
// Fallback for runStoryboardStep where priorProbes isn't populated — reach
|
|
3675
3985
|
// into the step result's response, which we set to the HttpProbeResult above.
|