@adcp/sdk 13.0.0-rc.8 → 13.0.0-rc.9
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/dist/lib/adapters/roster-account-store.d.mts +9 -8
- package/dist/lib/adapters/roster-account-store.d.ts +9 -8
- package/dist/lib/adapters/roster-account-store.d.ts.map +1 -1
- package/dist/lib/adapters/roster-account-store.js +2 -1
- package/dist/lib/adapters/roster-account-store.js.map +1 -1
- package/dist/lib/adapters/roster-account-store.mjs +2 -1
- package/dist/lib/adapters/roster-account-store.mjs.map +1 -1
- package/dist/lib/net/address-guards.d.ts.map +1 -1
- package/dist/lib/net/address-guards.js +6 -0
- package/dist/lib/net/address-guards.js.map +1 -1
- package/dist/lib/net/address-guards.mjs +6 -0
- package/dist/lib/net/address-guards.mjs.map +1 -1
- package/dist/lib/net/ssrf-fetch.d.ts.map +1 -1
- package/dist/lib/net/ssrf-fetch.js +66 -53
- package/dist/lib/net/ssrf-fetch.js.map +1 -1
- package/dist/lib/net/ssrf-fetch.mjs +66 -53
- package/dist/lib/net/ssrf-fetch.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/account-mode.d.mts +2 -1
- package/dist/lib/server/account-mode.d.ts +2 -1
- package/dist/lib/server/account-mode.d.ts.map +1 -1
- package/dist/lib/server/account-mode.js +1 -0
- package/dist/lib/server/account-mode.js.map +1 -1
- package/dist/lib/server/account-mode.mjs +1 -0
- package/dist/lib/server/account-mode.mjs.map +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +10 -6
- package/dist/lib/server/create-adcp-server.d.ts +10 -6
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +2 -1
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.mjs +2 -1
- package/dist/lib/server/create-adcp-server.mjs.map +1 -1
- package/dist/lib/server/decisioning/account.d.mts +16 -11
- package/dist/lib/server/decisioning/account.d.ts +16 -11
- 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/account.mjs.map +1 -1
- package/dist/lib/server/decisioning/pagination.d.mts +2 -0
- package/dist/lib/server/decisioning/pagination.d.ts +2 -0
- package/dist/lib/server/decisioning/pagination.d.ts.map +1 -1
- package/dist/lib/server/decisioning/pagination.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +20 -14
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +20 -14
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +32 -6
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +32 -6
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.mts +16 -4
- package/dist/lib/server/decisioning/specialisms/sales.d.ts +16 -4
- 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.ts.map +1 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/index.mjs.map +1 -1
- package/dist/lib/server/legacy/v5/index.d.mts +2 -1
- package/dist/lib/server/legacy/v5/index.d.ts +2 -1
- package/dist/lib/server/legacy/v5/index.d.ts.map +1 -1
- package/dist/lib/server/legacy/v5/index.js.map +1 -1
- package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
- package/dist/lib/testing/compliance/comply.d.mts +2 -0
- package/dist/lib/testing/compliance/comply.d.ts +2 -0
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +45 -14
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/comply.mjs +45 -14
- package/dist/lib/testing/compliance/comply.mjs.map +1 -1
- package/dist/lib/testing/compliance/index.d.mts +1 -1
- package/dist/lib/testing/compliance/index.d.ts +1 -1
- package/dist/lib/testing/compliance/index.d.ts.map +1 -1
- package/dist/lib/testing/compliance/index.js.map +1 -1
- package/dist/lib/testing/compliance/index.mjs.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.js +9 -1
- package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.mjs +9 -1
- package/dist/lib/testing/compliance/storyboard-tracks.mjs.map +1 -1
- package/dist/lib/testing/compliance/types.d.mts +26 -25
- package/dist/lib/testing/compliance/types.d.ts +26 -25
- package/dist/lib/testing/compliance/types.d.ts.map +1 -1
- package/dist/lib/testing/compliance/types.js.map +1 -1
- package/dist/lib/testing/index.d.mts +2 -2
- package/dist/lib/testing/index.d.ts +2 -2
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js +16 -0
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/index.mjs +16 -0
- package/dist/lib/testing/index.mjs.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.d.ts.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.js +20 -12
- package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.mjs +20 -12
- package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
- package/dist/lib/testing/storyboard/creative-assets.d.mts +23 -0
- package/dist/lib/testing/storyboard/creative-assets.d.ts +23 -0
- package/dist/lib/testing/storyboard/creative-assets.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/creative-assets.js +322 -45
- package/dist/lib/testing/storyboard/creative-assets.js.map +1 -1
- package/dist/lib/testing/storyboard/creative-assets.mjs +321 -45
- package/dist/lib/testing/storyboard/creative-assets.mjs.map +1 -1
- package/dist/lib/testing/storyboard/index.d.mts +4 -1
- package/dist/lib/testing/storyboard/index.d.ts +4 -1
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/index.js +20 -0
- package/dist/lib/testing/storyboard/index.js.map +1 -1
- package/dist/lib/testing/storyboard/index.mjs +19 -0
- package/dist/lib/testing/storyboard/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.mts +21 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.ts +22 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.js +668 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.js.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.mjs +638 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.mjs.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.d.mts +5 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.d.ts +6 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.js +44 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.js.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.mjs +20 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.mjs.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.d.mts +38 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.d.ts +39 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.js +17 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.js.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.mjs +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.mjs.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.d.mts +32 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.d.ts +33 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.js +105 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.js.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.mjs +80 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.mjs.map +1 -0
- package/dist/lib/testing/storyboard/probes.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/probes.js +2 -1
- package/dist/lib/testing/storyboard/probes.js.map +1 -1
- package/dist/lib/testing/storyboard/probes.mjs +2 -1
- 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 +382 -69
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.mjs +387 -70
- package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
- package/dist/lib/testing/storyboard/seeding.js +3 -1
- package/dist/lib/testing/storyboard/seeding.js.map +1 -1
- package/dist/lib/testing/storyboard/seeding.mjs +3 -1
- package/dist/lib/testing/storyboard/seeding.mjs.map +1 -1
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/task-map.js +16 -2
- package/dist/lib/testing/storyboard/task-map.js.map +1 -1
- package/dist/lib/testing/storyboard/task-map.mjs +16 -2
- package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
- package/dist/lib/testing/storyboard/trusted-match-context-replay.d.mts +11 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.d.ts +12 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.js +340 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.js.map +1 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.mjs +316 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.mjs.map +1 -0
- package/dist/lib/testing/storyboard/types.d.mts +84 -15
- package/dist/lib/testing/storyboard/types.d.ts +84 -15
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/types.js +2 -0
- package/dist/lib/testing/storyboard/types.js.map +1 -1
- package/dist/lib/testing/storyboard/types.mjs +2 -0
- package/dist/lib/testing/storyboard/types.mjs.map +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +3 -0
- package/dist/lib/testing/storyboard/validations.d.ts +3 -0
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/validations.js +64 -24
- package/dist/lib/testing/storyboard/validations.js.map +1 -1
- package/dist/lib/testing/storyboard/validations.mjs +64 -24
- package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
- package/dist/lib/types/server-payload-aliases.d.mts +8 -2
- package/dist/lib/types/server-payload-aliases.d.ts +8 -2
- package/dist/lib/types/server-payload-aliases.d.ts.map +1 -1
- package/dist/lib/types/server-payload-aliases.js.map +1 -1
- package/dist/lib/upstream-recorder/recorder.d.mts +7 -18
- package/dist/lib/upstream-recorder/recorder.d.ts +7 -18
- package/dist/lib/upstream-recorder/recorder.d.ts.map +1 -1
- package/dist/lib/upstream-recorder/recorder.js +17 -10
- package/dist/lib/upstream-recorder/recorder.js.map +1 -1
- package/dist/lib/upstream-recorder/recorder.mjs +12 -5
- package/dist/lib/upstream-recorder/recorder.mjs.map +1 -1
- package/dist/lib/utils/redact-secrets.d.ts.map +1 -1
- package/dist/lib/utils/redact-secrets.js +7 -1
- package/dist/lib/utils/redact-secrets.js.map +1 -1
- package/dist/lib/utils/redact-secrets.mjs +7 -1
- package/dist/lib/utils/redact-secrets.mjs.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- 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 +4 -2
- package/docs/llms.txt +1 -1
- package/package.json +2 -2
|
@@ -30,7 +30,7 @@ import { IDENTIFIER_DIGEST_LIMIT } from "../../upstream-recorder/constants.mjs";
|
|
|
30
30
|
import { enrichRequest, hasRequestEnricher } from "./request-builder.mjs";
|
|
31
31
|
import {
|
|
32
32
|
BUILD_ASSETS_FROM_FORMAT_DIRECTIVE,
|
|
33
|
-
|
|
33
|
+
expandCreativeAssetDirectivesWithDiagnostics,
|
|
34
34
|
findUnresolvedCreativeAssetDirectives
|
|
35
35
|
} from "./creative-assets.mjs";
|
|
36
36
|
import { resolveAccount, resolveBrand } from "../client.mjs";
|
|
@@ -62,6 +62,12 @@ import { runControllerSeeding } from "./seeding.mjs";
|
|
|
62
62
|
import { applyFixtureBindingsToRequest } from "./fixture-resolution.mjs";
|
|
63
63
|
import { getComplianceCacheDir } from "./compliance.mjs";
|
|
64
64
|
import { signWebhook } from "../../signing/client.mjs";
|
|
65
|
+
import { replayTrustedMatchContextVector } from "./trusted-match-context-replay.mjs";
|
|
66
|
+
import {
|
|
67
|
+
gradeOAuthMetadataGraph,
|
|
68
|
+
redactOAuthUrlForOutput,
|
|
69
|
+
redactOAuthUrlsInText
|
|
70
|
+
} from "./oauth-metadata-graph/index.mjs";
|
|
65
71
|
import {
|
|
66
72
|
buildRoutingContext,
|
|
67
73
|
DiscoveryFailure,
|
|
@@ -80,6 +86,7 @@ const SKIP_DETAILS = {
|
|
|
80
86
|
prerequisite_failed: "Skipped: a prerequisite step or contract did not pass.",
|
|
81
87
|
missing_tool: "Skipped: agent did not advertise the required tool.",
|
|
82
88
|
missing_test_controller: "Skipped: deterministic_testing phase requires comply_test_controller, which the agent did not advertise.",
|
|
89
|
+
fixture_unavailable: "Skipped: the runner test kit cannot synthesize a valid input for the seller-declared contract.",
|
|
83
90
|
unsatisfied_contract: "Skipped: test-kit contract is out of scope for this grading run.",
|
|
84
91
|
requirement_unmet: "Skipped: a requires: tag named a runtime requirement that is not available on this run (see RunnerSkipResult.requirement).",
|
|
85
92
|
peer_branch_taken: "Skipped: a peer branch in the same any_of branch set already contributed the aggregation flag.",
|
|
@@ -129,6 +136,7 @@ const DETAILED_SKIP_DETAILS = {
|
|
|
129
136
|
rate_limit_not_triggered: "No RATE_LIMITED response was observed within the configured max_attempts."
|
|
130
137
|
};
|
|
131
138
|
const REPLAY_WEBHOOK_VECTOR_TASK = "replay_webhook_vector";
|
|
139
|
+
const REPLAY_TRUSTED_MATCH_CONTEXT_VECTOR_TASK = "replay_trusted_match_context_vector";
|
|
132
140
|
const WEBHOOK_REPLAY_DEFAULT_TIMEOUT_MS = 1e4;
|
|
133
141
|
function selectionForProbeSkip(reason, detail) {
|
|
134
142
|
switch (reason) {
|
|
@@ -209,6 +217,9 @@ function evaluateRequiresCapabilityGate(predicate, profile, agentTools, adcpVers
|
|
|
209
217
|
const actual = resolveCapabilityPathForGate(rawCaps, predicate, adcpVersion);
|
|
210
218
|
return evaluateCapabilityPredicate(predicate, actual);
|
|
211
219
|
}
|
|
220
|
+
if ("equals" in predicate && predicate.path === "oauth.supported" && predicate.equals === true) {
|
|
221
|
+
return evaluateCapabilityPredicate(predicate, void 0);
|
|
222
|
+
}
|
|
212
223
|
const tools = agentTools ?? profile?.tools;
|
|
213
224
|
if ("equals" in predicate && tools !== void 0 && !tools.includes("get_adcp_capabilities")) {
|
|
214
225
|
return evaluateCapabilityPredicate(predicate, void 0);
|
|
@@ -233,6 +244,24 @@ function allExecutablePhasesCapabilitySkipped(storyboard, phaseCapabilitySkipDet
|
|
|
233
244
|
function buildSkip(reason, detail) {
|
|
234
245
|
return { reason, detail: detail ?? SKIP_DETAILS[reason] };
|
|
235
246
|
}
|
|
247
|
+
function buildCreativeAssetFixtureUnavailableStep(step, phaseId, context, allSteps, runState, failure, task = step.task) {
|
|
248
|
+
const detail = `creative_asset_fixture_unavailable: slot "${failure.slotId}", asset type "${failure.assetType}", constraint: ${failure.constraint} (${failure.path})`;
|
|
249
|
+
return {
|
|
250
|
+
step_id: step.id,
|
|
251
|
+
phase_id: phaseId,
|
|
252
|
+
title: step.title,
|
|
253
|
+
task,
|
|
254
|
+
passed: true,
|
|
255
|
+
skipped: true,
|
|
256
|
+
skip_reason: "fixture_unavailable",
|
|
257
|
+
skip: buildSkip("fixture_unavailable", detail),
|
|
258
|
+
duration_ms: 0,
|
|
259
|
+
validations: [],
|
|
260
|
+
context,
|
|
261
|
+
next: getNextStepPreview(step.id, allSteps, context, runState.runnerVars),
|
|
262
|
+
extraction: { path: "none" }
|
|
263
|
+
};
|
|
264
|
+
}
|
|
236
265
|
function detectResponseDerivedNotApplicable(step, request, response, runState, allSteps) {
|
|
237
266
|
if (response === void 0 || response === null) return null;
|
|
238
267
|
const gates = [
|
|
@@ -516,7 +545,10 @@ function filterResponseHeaders(headers) {
|
|
|
516
545
|
if (!headers) return void 0;
|
|
517
546
|
const out = {};
|
|
518
547
|
for (const [k, v] of Object.entries(headers)) {
|
|
519
|
-
|
|
548
|
+
const lower = k.toLowerCase();
|
|
549
|
+
if (RESPONSE_HEADER_ALLOWLIST.has(lower)) {
|
|
550
|
+
out[lower] = lower === "location" ? redactOAuthUrlForOutput(v) : v;
|
|
551
|
+
}
|
|
520
552
|
}
|
|
521
553
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
522
554
|
}
|
|
@@ -548,15 +580,6 @@ async function runStoryboardBody(agentUrlOrUrls, storyboard, options) {
|
|
|
548
580
|
"runStoryboard: _client override is incompatible with multi-instance mode. Remove _client (or pass a single agent URL) to use round-robin dispatch."
|
|
549
581
|
);
|
|
550
582
|
}
|
|
551
|
-
const requestedStrategy = options.multi_instance_strategy ?? "round-robin";
|
|
552
|
-
if (requestedStrategy === "multi-pass" && isMultiInstance) {
|
|
553
|
-
if (options.webhook_receiver) {
|
|
554
|
-
throw new Error(
|
|
555
|
-
'runStoryboard: webhook_receiver is incompatible with multi_instance_strategy: "multi-pass". Each pass would bind a fresh receiver URL, so agents caching the pass-1 URL would deliver to a dead port in pass 2. Use round-robin when the storyboard needs a webhook receiver, or run multi-pass on a storyboard without webhook observation.'
|
|
556
|
-
);
|
|
557
|
-
}
|
|
558
|
-
return runMultiPass(agentUrls, storyboard, options);
|
|
559
|
-
}
|
|
560
583
|
const allRequires = resolveStoryboardRequires(storyboard, options);
|
|
561
584
|
if (allRequires.length) {
|
|
562
585
|
const unmet = checkRequires(allRequires, storyboard, options, options._profile);
|
|
@@ -568,6 +591,15 @@ async function runStoryboardBody(agentUrlOrUrls, storyboard, options) {
|
|
|
568
591
|
};
|
|
569
592
|
}
|
|
570
593
|
}
|
|
594
|
+
const requestedStrategy = options.multi_instance_strategy ?? "round-robin";
|
|
595
|
+
if (requestedStrategy === "multi-pass" && isMultiInstance) {
|
|
596
|
+
if (options.webhook_receiver) {
|
|
597
|
+
throw new Error(
|
|
598
|
+
'runStoryboard: webhook_receiver is incompatible with multi_instance_strategy: "multi-pass". Each pass would bind a fresh receiver URL, so agents caching the pass-1 URL would deliver to a dead port in pass 2. Use round-robin when the storyboard needs a webhook receiver, or run multi-pass on a storyboard without webhook observation.'
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
return runMultiPass(agentUrls, storyboard, options);
|
|
602
|
+
}
|
|
571
603
|
if (options.agents) {
|
|
572
604
|
const projected = Object.values(options.agents).map((e) => e.url);
|
|
573
605
|
return executeStoryboardPass(projected, storyboard, options, 0);
|
|
@@ -646,7 +678,7 @@ function buildCapabilityUnsupportedResult(agentUrls, storyboard, detail) {
|
|
|
646
678
|
return {
|
|
647
679
|
storyboard_id: storyboard.id,
|
|
648
680
|
storyboard_title: storyboard.title,
|
|
649
|
-
agent_url: agentUrls[0],
|
|
681
|
+
agent_url: redactOAuthUrlForOutput(agentUrls[0]),
|
|
650
682
|
overall_passed: true,
|
|
651
683
|
phases: [
|
|
652
684
|
{
|
|
@@ -701,6 +733,8 @@ const REQUIREMENT_TO_SKIP_REASON = {
|
|
|
701
733
|
seeded_state: "requirement_unmet",
|
|
702
734
|
real_wire: "requirement_unmet",
|
|
703
735
|
webhook_receiver: "requirement_unmet",
|
|
736
|
+
webhook_replay_receiver: "not_applicable",
|
|
737
|
+
trusted_match_context_router_runner: "not_applicable",
|
|
704
738
|
request_signer: "not_applicable",
|
|
705
739
|
multi_agent: "requirement_unmet"
|
|
706
740
|
};
|
|
@@ -727,7 +761,7 @@ function buildRequirementUnmetResult(agentUrls, storyboard, requirement, detail)
|
|
|
727
761
|
return {
|
|
728
762
|
storyboard_id: storyboard.id,
|
|
729
763
|
storyboard_title: storyboard.title,
|
|
730
|
-
agent_url: agentUrls[0],
|
|
764
|
+
agent_url: redactOAuthUrlForOutput(agentUrls[0]),
|
|
731
765
|
overall_passed: true,
|
|
732
766
|
phases: [
|
|
733
767
|
{
|
|
@@ -777,7 +811,7 @@ function buildRequiredAnyOfToolsMissingResult(agentUrls, storyboard, detail) {
|
|
|
777
811
|
return {
|
|
778
812
|
storyboard_id: storyboard.id,
|
|
779
813
|
storyboard_title: storyboard.title,
|
|
780
|
-
agent_url: agentUrls[0],
|
|
814
|
+
agent_url: redactOAuthUrlForOutput(agentUrls[0]),
|
|
781
815
|
overall_passed: true,
|
|
782
816
|
phases: [
|
|
783
817
|
{
|
|
@@ -857,6 +891,25 @@ function checkRequires(requires, storyboard, options, profile) {
|
|
|
857
891
|
}
|
|
858
892
|
break;
|
|
859
893
|
}
|
|
894
|
+
case "webhook_replay_receiver": {
|
|
895
|
+
if (!options.webhook_replay_receiver?.url) {
|
|
896
|
+
return {
|
|
897
|
+
requirement,
|
|
898
|
+
detail: "Storyboard contains a `replay_webhook_vector` step but no webhook replay receiver URL is configured. Pass `webhook_replay_receiver.url` in StoryboardRunOptions to run inbound buyer/orchestrator receiver conformance. Seller agents without an inbound receiver grade not_applicable for this storyboard."
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
break;
|
|
902
|
+
}
|
|
903
|
+
case "trusted_match_context_router_runner": {
|
|
904
|
+
const runner = options.trusted_match_context_router_runner;
|
|
905
|
+
if (!runner?.router_url || typeof runner.registerProviders !== "function") {
|
|
906
|
+
return {
|
|
907
|
+
requirement,
|
|
908
|
+
detail: "Storyboard contains a `replay_trusted_match_context_vector` step but no Trusted Match Context router harness is configured. Pass `trusted_match_context_router_runner` with `router_url` and `registerProviders` to run raw POST /context conformance."
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
860
913
|
case "request_signer": {
|
|
861
914
|
if (!profile?.raw_capabilities) break;
|
|
862
915
|
const supported = resolveCapabilityPath(profile.raw_capabilities, "request_signing.supported");
|
|
@@ -918,22 +971,32 @@ function valueContainsWebhookToken(value) {
|
|
|
918
971
|
function detectImplicitRequires(storyboard, options = {}) {
|
|
919
972
|
const requires = [];
|
|
920
973
|
let needsWebhook = false;
|
|
974
|
+
let needsWebhookReplayReceiver = false;
|
|
975
|
+
let needsTrustedMatchContextRouterRunner = false;
|
|
921
976
|
let needsSigner = storyboard.id === "signed_requests";
|
|
922
977
|
const contractsInScope = new Set(options.contracts ?? []);
|
|
923
978
|
for (const phase of storyboard.phases) {
|
|
924
979
|
for (const step of phase.steps) {
|
|
925
|
-
const
|
|
926
|
-
if (!needsWebhook && (step.sample_request && valueContainsWebhookToken(step.sample_request) || step.rate_limit_trip?.trip_target_sample_request &&
|
|
980
|
+
const stepContractInScope = !step.requires_contract || contractsInScope.has(step.requires_contract);
|
|
981
|
+
if (!needsWebhook && (step.sample_request && valueContainsWebhookToken(step.sample_request) || step.rate_limit_trip?.trip_target_sample_request && stepContractInScope && valueContainsWebhookToken(step.rate_limit_trip.trip_target_sample_request))) {
|
|
927
982
|
needsWebhook = true;
|
|
928
983
|
}
|
|
929
984
|
if (!needsSigner && step.task === "request_signing_probe") {
|
|
930
985
|
needsSigner = true;
|
|
931
986
|
}
|
|
932
|
-
if (
|
|
987
|
+
if (!needsWebhookReplayReceiver && stepContractInScope && step.task === REPLAY_WEBHOOK_VECTOR_TASK) {
|
|
988
|
+
needsWebhookReplayReceiver = true;
|
|
989
|
+
}
|
|
990
|
+
if (!needsTrustedMatchContextRouterRunner && stepContractInScope && step.task === REPLAY_TRUSTED_MATCH_CONTEXT_VECTOR_TASK) {
|
|
991
|
+
needsTrustedMatchContextRouterRunner = true;
|
|
992
|
+
}
|
|
993
|
+
if (needsWebhook && needsWebhookReplayReceiver && needsTrustedMatchContextRouterRunner && needsSigner) break;
|
|
933
994
|
}
|
|
934
|
-
if (needsWebhook && needsSigner) break;
|
|
995
|
+
if (needsWebhook && needsWebhookReplayReceiver && needsTrustedMatchContextRouterRunner && needsSigner) break;
|
|
935
996
|
}
|
|
936
997
|
if (needsWebhook) requires.push("webhook_receiver");
|
|
998
|
+
if (needsWebhookReplayReceiver) requires.push("webhook_replay_receiver");
|
|
999
|
+
if (needsTrustedMatchContextRouterRunner) requires.push("trusted_match_context_router_runner");
|
|
937
1000
|
if (needsSigner) requires.push("request_signer");
|
|
938
1001
|
return requires;
|
|
939
1002
|
}
|
|
@@ -956,7 +1019,7 @@ function buildDiscoveryFailedResult(agentUrls, storyboard, discoveryStep) {
|
|
|
956
1019
|
return {
|
|
957
1020
|
storyboard_id: storyboard.id,
|
|
958
1021
|
storyboard_title: storyboard.title,
|
|
959
|
-
agent_url: agentUrls[0],
|
|
1022
|
+
agent_url: redactOAuthUrlForOutput(agentUrls[0]),
|
|
960
1023
|
overall_passed: false,
|
|
961
1024
|
phases: [
|
|
962
1025
|
{
|
|
@@ -988,7 +1051,7 @@ function buildRequiredToolsMissingResult(agentUrls, storyboard, detail) {
|
|
|
988
1051
|
return {
|
|
989
1052
|
storyboard_id: storyboard.id,
|
|
990
1053
|
storyboard_title: storyboard.title,
|
|
991
|
-
agent_url: agentUrls[0],
|
|
1054
|
+
agent_url: redactOAuthUrlForOutput(agentUrls[0]),
|
|
992
1055
|
overall_passed: true,
|
|
993
1056
|
phases: [
|
|
994
1057
|
{
|
|
@@ -1330,6 +1393,33 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1330
1393
|
storyboard,
|
|
1331
1394
|
phaseCapabilitySkipDetails
|
|
1332
1395
|
);
|
|
1396
|
+
const capabilitySkippedPhaseIds = /* @__PURE__ */ new Set([
|
|
1397
|
+
...phaseCapabilitySkipDetails.keys(),
|
|
1398
|
+
...storyboard.phases.filter((phase) => shouldSkipPhase(phase, options)).map((phase) => phase.id)
|
|
1399
|
+
]);
|
|
1400
|
+
let creativeAssetFixtureGap = preflightRemainingCreativeAssetDirectives(
|
|
1401
|
+
allSteps,
|
|
1402
|
+
-1,
|
|
1403
|
+
context,
|
|
1404
|
+
options,
|
|
1405
|
+
{
|
|
1406
|
+
contributions,
|
|
1407
|
+
priorStepResults,
|
|
1408
|
+
priorProbes,
|
|
1409
|
+
agentUrl: agentUrls[0],
|
|
1410
|
+
webhookReceiver,
|
|
1411
|
+
runnerVars,
|
|
1412
|
+
contextProvenance,
|
|
1413
|
+
priorA2aEnvelopes,
|
|
1414
|
+
stepRequestStarts,
|
|
1415
|
+
responseDerivedNotApplicableContextKeys,
|
|
1416
|
+
agentProfile: profile,
|
|
1417
|
+
agentLibraryVersion: profile?.library_version,
|
|
1418
|
+
storyboardRequiresRequestSigner: allRequires.includes("request_signer")
|
|
1419
|
+
},
|
|
1420
|
+
capabilitySkippedPhaseIds
|
|
1421
|
+
);
|
|
1422
|
+
let creativeAssetFixtureGapRecorded = false;
|
|
1333
1423
|
if (!hasExecutableSteps) {
|
|
1334
1424
|
const isScenarioComposed = (storyboard.requires_scenarios?.length ?? 0) > 0;
|
|
1335
1425
|
const detail = isScenarioComposed ? `Storyboard "${storyboard.id}" has no local phases \u2014 its test surface is fully composed from the scenarios listed in \`requires_scenarios\`.` : `Storyboard "${storyboard.id}" has no executable phases \u2014 populate \`phases[].steps\` or remove the storyboard.`;
|
|
@@ -1387,7 +1477,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1387
1477
|
fixtureDiscoveryClient = dispatch.nextFor(fixtureStep("get_products")).client;
|
|
1388
1478
|
}
|
|
1389
1479
|
}
|
|
1390
|
-
const seeding = skipControllerSeedingForPhaseGates ? null : preSeeded !== void 0 ? preSeeded.result : await runControllerSeeding(fixtureSeedClient, storyboard, options, context, fixtureDiscoveryClient);
|
|
1480
|
+
const seeding = creativeAssetFixtureGap ? null : skipControllerSeedingForPhaseGates ? null : preSeeded !== void 0 ? preSeeded.result : await runControllerSeeding(fixtureSeedClient, storyboard, options, context, fixtureDiscoveryClient);
|
|
1391
1481
|
if (seeding) {
|
|
1392
1482
|
const attach = preSeeded === void 0 || preSeeded.attach;
|
|
1393
1483
|
if (attach) {
|
|
@@ -1435,6 +1525,32 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1435
1525
|
}
|
|
1436
1526
|
}
|
|
1437
1527
|
}
|
|
1528
|
+
const buildExecutionState = (agentUrl = agentUrls[0], agentProfile = profile) => ({
|
|
1529
|
+
contributions,
|
|
1530
|
+
priorStepResults,
|
|
1531
|
+
priorProbes,
|
|
1532
|
+
agentUrl,
|
|
1533
|
+
webhookReceiver,
|
|
1534
|
+
runnerVars,
|
|
1535
|
+
contextProvenance,
|
|
1536
|
+
priorA2aEnvelopes,
|
|
1537
|
+
stepRequestStarts,
|
|
1538
|
+
responseDerivedNotApplicableContextKeys,
|
|
1539
|
+
agentProfile,
|
|
1540
|
+
agentLibraryVersion: agentProfile?.library_version,
|
|
1541
|
+
storyboardRequiresRequestSigner: allRequires.includes("request_signer"),
|
|
1542
|
+
fixtureBindings
|
|
1543
|
+
});
|
|
1544
|
+
if (!creativeAssetFixtureGap && !seedingMissingController && !seedingUnsupported && !seedingFailed && !fixtureUnsatisfied) {
|
|
1545
|
+
creativeAssetFixtureGap = preflightRemainingCreativeAssetDirectives(
|
|
1546
|
+
allSteps,
|
|
1547
|
+
-1,
|
|
1548
|
+
context,
|
|
1549
|
+
options,
|
|
1550
|
+
buildExecutionState(),
|
|
1551
|
+
capabilitySkippedPhaseIds
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1438
1554
|
for (const phase of storyboard.phases) {
|
|
1439
1555
|
options.signal?.throwIfAborted();
|
|
1440
1556
|
const phaseStart = Date.now();
|
|
@@ -1448,6 +1564,33 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1448
1564
|
});
|
|
1449
1565
|
continue;
|
|
1450
1566
|
}
|
|
1567
|
+
if (creativeAssetFixtureGap) {
|
|
1568
|
+
const gapSteps = [];
|
|
1569
|
+
if (!creativeAssetFixtureGapRecorded && creativeAssetFixtureGap.target.phaseId === phase.id) {
|
|
1570
|
+
const gapStep = buildCreativeAssetFixtureUnavailableStep(
|
|
1571
|
+
creativeAssetFixtureGap.target.step,
|
|
1572
|
+
phase.id,
|
|
1573
|
+
context,
|
|
1574
|
+
allSteps,
|
|
1575
|
+
buildExecutionState(),
|
|
1576
|
+
creativeAssetFixtureGap.failure
|
|
1577
|
+
);
|
|
1578
|
+
gapStep.storyboard_id = storyboard.id;
|
|
1579
|
+
gapSteps.push(gapStep);
|
|
1580
|
+
priorStepResults.set(gapStep.step_id, gapStep);
|
|
1581
|
+
skippedCount++;
|
|
1582
|
+
creativeAssetFixtureGapRecorded = true;
|
|
1583
|
+
}
|
|
1584
|
+
phaseResults.push({
|
|
1585
|
+
phase_id: phase.id,
|
|
1586
|
+
phase_title: phase.title,
|
|
1587
|
+
passed: true,
|
|
1588
|
+
steps: gapSteps,
|
|
1589
|
+
duration_ms: 0
|
|
1590
|
+
});
|
|
1591
|
+
priorPhaseIds.push(phase.id);
|
|
1592
|
+
continue;
|
|
1593
|
+
}
|
|
1451
1594
|
const phaseCapabilitySkipDetail = phaseCapabilitySkipDetails.get(phase.id);
|
|
1452
1595
|
if (phaseCapabilitySkipDetail !== void 0) {
|
|
1453
1596
|
const skippedSteps = buildPhaseCapabilitySkippedSteps(storyboard, phase, phaseCapabilitySkipDetail, context);
|
|
@@ -1631,6 +1774,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1631
1774
|
phasePassed = false;
|
|
1632
1775
|
continue;
|
|
1633
1776
|
}
|
|
1777
|
+
const stepExecutionState = buildExecutionState(assignment.agentUrl, assignment.profile);
|
|
1634
1778
|
const rawResult = await executeStep(
|
|
1635
1779
|
assignment.client,
|
|
1636
1780
|
step,
|
|
@@ -1639,26 +1783,11 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1639
1783
|
context,
|
|
1640
1784
|
allSteps,
|
|
1641
1785
|
options,
|
|
1642
|
-
|
|
1643
|
-
contributions,
|
|
1644
|
-
priorStepResults,
|
|
1645
|
-
priorProbes,
|
|
1646
|
-
agentUrl: assignment.agentUrl,
|
|
1647
|
-
webhookReceiver,
|
|
1648
|
-
runnerVars,
|
|
1649
|
-
contextProvenance,
|
|
1650
|
-
priorA2aEnvelopes,
|
|
1651
|
-
stepRequestStarts,
|
|
1652
|
-
responseDerivedNotApplicableContextKeys,
|
|
1653
|
-
agentProfile: assignment.profile,
|
|
1654
|
-
agentLibraryVersion: assignment.profile?.library_version,
|
|
1655
|
-
storyboardRequiresRequestSigner: allRequires.includes("request_signer"),
|
|
1656
|
-
fixtureBindings
|
|
1657
|
-
}
|
|
1786
|
+
stepExecutionState
|
|
1658
1787
|
);
|
|
1659
1788
|
const result2 = { ...rawResult, storyboard_id: storyboard.id };
|
|
1660
1789
|
if (isMultiInstance || useRouting) {
|
|
1661
|
-
result2.agent_url = assignment.agentUrl;
|
|
1790
|
+
result2.agent_url = redactOAuthUrlForOutput(assignment.agentUrl);
|
|
1662
1791
|
result2.agent_index = assignment.instanceIndex + 1;
|
|
1663
1792
|
}
|
|
1664
1793
|
stepResults.push(result2);
|
|
@@ -1777,6 +1906,39 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1777
1906
|
annotateMultiInstanceFailure(result2, storyboard, stepResults);
|
|
1778
1907
|
}
|
|
1779
1908
|
}
|
|
1909
|
+
if (!result2.skipped && result2.passed) {
|
|
1910
|
+
const currentGlobalIndex = allSteps.find(
|
|
1911
|
+
(flat) => flat.phaseId === phase.id && flat.step.id === step.id
|
|
1912
|
+
)?.globalIndex;
|
|
1913
|
+
if (currentGlobalIndex !== void 0) {
|
|
1914
|
+
creativeAssetFixtureGap = preflightRemainingCreativeAssetDirectives(
|
|
1915
|
+
allSteps,
|
|
1916
|
+
currentGlobalIndex,
|
|
1917
|
+
context,
|
|
1918
|
+
options,
|
|
1919
|
+
stepExecutionState,
|
|
1920
|
+
capabilitySkippedPhaseIds
|
|
1921
|
+
);
|
|
1922
|
+
}
|
|
1923
|
+
if (creativeAssetFixtureGap) {
|
|
1924
|
+
if (creativeAssetFixtureGap.target.phaseId === phase.id) {
|
|
1925
|
+
const gapStep = buildCreativeAssetFixtureUnavailableStep(
|
|
1926
|
+
creativeAssetFixtureGap.target.step,
|
|
1927
|
+
phase.id,
|
|
1928
|
+
context,
|
|
1929
|
+
allSteps,
|
|
1930
|
+
stepExecutionState,
|
|
1931
|
+
creativeAssetFixtureGap.failure
|
|
1932
|
+
);
|
|
1933
|
+
gapStep.storyboard_id = storyboard.id;
|
|
1934
|
+
stepResults.push(gapStep);
|
|
1935
|
+
priorStepResults.set(gapStep.step_id, gapStep);
|
|
1936
|
+
skippedCount++;
|
|
1937
|
+
creativeAssetFixtureGapRecorded = true;
|
|
1938
|
+
}
|
|
1939
|
+
break;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1780
1942
|
}
|
|
1781
1943
|
if (phasePendingNotApplicable && !phaseEstablishedStatefulState && !phaseStatefulCascades.has(phase.id)) {
|
|
1782
1944
|
const hadStatefulPeers = phaseStatefulStepIds.some((id) => id !== phasePendingNotApplicable.stepId);
|
|
@@ -1820,7 +1982,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1820
1982
|
});
|
|
1821
1983
|
priorPhaseIds.push(phase.id);
|
|
1822
1984
|
}
|
|
1823
|
-
const branchSetDelta = applyBranchSetGrading(
|
|
1985
|
+
const branchSetDelta = creativeAssetFixtureGap ? { skippedDelta: 0 } : applyBranchSetGrading(
|
|
1824
1986
|
storyboard.phases,
|
|
1825
1987
|
phaseResults,
|
|
1826
1988
|
branchSetsByPhaseId,
|
|
@@ -1829,12 +1991,14 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1829
1991
|
countedAsFailed
|
|
1830
1992
|
);
|
|
1831
1993
|
skippedCount += branchSetDelta.skippedDelta;
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1994
|
+
if (!creativeAssetFixtureGap) {
|
|
1995
|
+
for (const spec of assertions) {
|
|
1996
|
+
if (!spec.onEnd) continue;
|
|
1997
|
+
const raw = await spec.onEnd(assertionContexts.get(spec.id));
|
|
1998
|
+
for (const r of raw) {
|
|
1999
|
+
assertionResults.push({ ...r, assertion_id: spec.id, scope: "storyboard" });
|
|
2000
|
+
if (!r.passed) assertionsFailed = true;
|
|
2001
|
+
}
|
|
1838
2002
|
}
|
|
1839
2003
|
}
|
|
1840
2004
|
const requiredPhaseHasExecutedPass = phaseResults.some((p, idx) => {
|
|
@@ -1843,13 +2007,17 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1843
2007
|
return p.steps.some((s) => !s.skipped && s.passed);
|
|
1844
2008
|
});
|
|
1845
2009
|
const requiredPhaseDefs = storyboard.phases.filter((phaseDef) => !phaseDef.optional);
|
|
2010
|
+
const requiredPhasesNotApplicable = requiredPhaseDefs.length > 0 && requiredPhaseDefs.every((phaseDef) => {
|
|
2011
|
+
const phaseResult = phaseResults.find((p) => p.phase_id === phaseDef.id);
|
|
2012
|
+
return !!phaseResult && phaseResult.passed && phaseResult.steps.length > 0 && phaseResult.steps.every((step) => step.skipped && step.skip?.reason === "not_applicable");
|
|
2013
|
+
});
|
|
1846
2014
|
const requiredPhasesCoveredByCapabilityGates = phaseCapabilitySkippedIds.size > 0 && requiredPhaseDefs.length > 0 && requiredPhaseDefs.every((phaseDef) => {
|
|
1847
2015
|
if (phaseCapabilitySkippedIds.has(phaseDef.id)) return true;
|
|
1848
2016
|
const phaseResult = phaseResults.find((p) => p.phase_id === phaseDef.id);
|
|
1849
2017
|
return !!phaseResult && phaseResult.passed && phaseResult.steps.some((s) => !s.skipped && s.passed);
|
|
1850
2018
|
});
|
|
1851
|
-
const requiredPhasesPassed = !hasExecutableSteps || requiredPhaseHasExecutedPass || failedCount === 0 && requiredPhasesCoveredByCapabilityGates;
|
|
1852
|
-
const storyboardWideFixtureUnavailable = (seedingUnsupported || fixtureUnsatisfied) && failedCount === 0;
|
|
2019
|
+
const requiredPhasesPassed = !hasExecutableSteps || requiredPhaseHasExecutedPass || requiredPhasesNotApplicable || failedCount === 0 && requiredPhasesCoveredByCapabilityGates;
|
|
2020
|
+
const storyboardWideFixtureUnavailable = (seedingUnsupported || fixtureUnsatisfied || creativeAssetFixtureGap !== void 0) && failedCount === 0;
|
|
1853
2021
|
if (seedingPhaseResult) phaseResults.unshift(seedingPhaseResult);
|
|
1854
2022
|
const schemasUsed = collectSchemasUsed(phaseResults);
|
|
1855
2023
|
const strictSummary = summarizeStrictValidation(phaseResults);
|
|
@@ -1861,13 +2029,17 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1861
2029
|
const result = {
|
|
1862
2030
|
storyboard_id: storyboard.id,
|
|
1863
2031
|
storyboard_title: storyboard.title,
|
|
1864
|
-
agent_url: agentUrls[0],
|
|
1865
|
-
...isMultiInstance && { agent_urls:
|
|
2032
|
+
agent_url: redactOAuthUrlForOutput(agentUrls[0]),
|
|
2033
|
+
...isMultiInstance && { agent_urls: agentUrls.map(redactOAuthUrlForOutput) },
|
|
1866
2034
|
// Inner multi-pass passes surface as `round-robin` (that's what they are
|
|
1867
2035
|
// individually); the aggregating wrapper relabels the top-level result
|
|
1868
2036
|
// `multi-pass`.
|
|
1869
2037
|
...isMultiInstance && { multi_instance_strategy: "round-robin" },
|
|
1870
|
-
...routingContext && {
|
|
2038
|
+
...routingContext && {
|
|
2039
|
+
agent_map: Object.fromEntries(
|
|
2040
|
+
Object.entries(routingContext.agentMap).map(([specialism, url]) => [specialism, redactOAuthUrlForOutput(url)])
|
|
2041
|
+
)
|
|
2042
|
+
},
|
|
1871
2043
|
overall_passed: failedCount === 0 && (requiredPhasesPassed || storyboardWideFixtureUnavailable) && !assertionsFailed,
|
|
1872
2044
|
phases: phaseResults,
|
|
1873
2045
|
context,
|
|
@@ -1886,12 +2058,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1886
2058
|
...routingContext && routingContext.discoveryFailures.length > 0 ? {
|
|
1887
2059
|
discovery_failures: routingContext.discoveryFailures.map((f) => ({
|
|
1888
2060
|
agent_key: f.agentKey,
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
// encode credentials in the URL, and the leaderboard /
|
|
1892
|
-
// dashboard surface mustn't carry them.
|
|
1893
|
-
url: f.url.replace(/\/\/[^/@\s]+@/, "//[REDACTED]@"),
|
|
1894
|
-
error: f.underlying
|
|
2061
|
+
url: redactOAuthUrlForOutput(f.url),
|
|
2062
|
+
error: redactOAuthUrlsInText(f.underlying)
|
|
1895
2063
|
}))
|
|
1896
2064
|
} : {}
|
|
1897
2065
|
};
|
|
@@ -1929,7 +2097,24 @@ async function runMultiPass(agentUrls, storyboard, options) {
|
|
|
1929
2097
|
options.agentTools,
|
|
1930
2098
|
options.adcpVersion
|
|
1931
2099
|
);
|
|
1932
|
-
const
|
|
2100
|
+
const preSeedExcludedPhaseIds = /* @__PURE__ */ new Set([
|
|
2101
|
+
...phaseCapabilitySkipDetails.keys(),
|
|
2102
|
+
...storyboard.phases.filter((phase) => shouldSkipPhase(phase, options)).map((phase) => phase.id)
|
|
2103
|
+
]);
|
|
2104
|
+
const preSeedFixtureGap = preflightRemainingCreativeAssetDirectives(
|
|
2105
|
+
flattenSteps(storyboard),
|
|
2106
|
+
-1,
|
|
2107
|
+
preSeedContext,
|
|
2108
|
+
options,
|
|
2109
|
+
{
|
|
2110
|
+
contributions: /* @__PURE__ */ new Set(),
|
|
2111
|
+
priorStepResults: /* @__PURE__ */ new Map(),
|
|
2112
|
+
priorProbes: /* @__PURE__ */ new Map(),
|
|
2113
|
+
agentUrl: agentUrls[0]
|
|
2114
|
+
},
|
|
2115
|
+
preSeedExcludedPhaseIds
|
|
2116
|
+
);
|
|
2117
|
+
const preSeededResult = preSeedFixtureGap || allExecutablePhasesCapabilitySkipped(storyboard, phaseCapabilitySkipDetails) ? null : await runControllerSeeding(preSeedClients[0], storyboard, options, preSeedContext);
|
|
1933
2118
|
const passes = [];
|
|
1934
2119
|
const passResults = [];
|
|
1935
2120
|
for (let passIdx = 0; passIdx < agentUrls.length; passIdx++) {
|
|
@@ -1961,8 +2146,8 @@ async function runMultiPass(agentUrls, storyboard, options) {
|
|
|
1961
2146
|
return {
|
|
1962
2147
|
storyboard_id: storyboard.id,
|
|
1963
2148
|
storyboard_title: storyboard.title,
|
|
1964
|
-
agent_url: agentUrls[0],
|
|
1965
|
-
agent_urls:
|
|
2149
|
+
agent_url: redactOAuthUrlForOutput(agentUrls[0]),
|
|
2150
|
+
agent_urls: agentUrls.map(redactOAuthUrlForOutput),
|
|
1966
2151
|
multi_instance_strategy: "multi-pass",
|
|
1967
2152
|
overall_passed: overallPassed,
|
|
1968
2153
|
phases: first.phases,
|
|
@@ -2287,7 +2472,19 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
2287
2472
|
};
|
|
2288
2473
|
}
|
|
2289
2474
|
request = fixtureBinding.request;
|
|
2290
|
-
|
|
2475
|
+
const creativeAssetExpansion = expandCreativeAssetDirectivesWithDiagnostics(request, context, options.test_kit);
|
|
2476
|
+
request = creativeAssetExpansion.value;
|
|
2477
|
+
if (!creativeAssetExpansion.ok && creativeAssetExpansion.failure.reason === "fixture_unavailable") {
|
|
2478
|
+
return buildCreativeAssetFixtureUnavailableStep(
|
|
2479
|
+
step,
|
|
2480
|
+
phaseId,
|
|
2481
|
+
context,
|
|
2482
|
+
allSteps,
|
|
2483
|
+
runState,
|
|
2484
|
+
creativeAssetExpansion.failure,
|
|
2485
|
+
effectiveStep.task
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2291
2488
|
const unresolvedContextVars = findUnresolvedContextVars(request);
|
|
2292
2489
|
const unresolvedAssetDirectives = findUnresolvedCreativeAssetDirectives(request).map((path) => ({
|
|
2293
2490
|
key: path,
|
|
@@ -2359,7 +2556,7 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
2359
2556
|
transport: options.protocol === "a2a" ? "a2a" : "mcp",
|
|
2360
2557
|
operation: effectiveStep.task,
|
|
2361
2558
|
payload: redactSecrets(request),
|
|
2362
|
-
...runState.agentUrl ? { url: runState.agentUrl } : {}
|
|
2559
|
+
...runState.agentUrl ? { url: redactOAuthUrlForOutput(runState.agentUrl) } : {}
|
|
2363
2560
|
},
|
|
2364
2561
|
extraction: { path: "none" }
|
|
2365
2562
|
};
|
|
@@ -2554,7 +2751,7 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
2554
2751
|
transport: useRawProbe ? "mcp" : options.protocol === "a2a" ? "a2a" : "mcp",
|
|
2555
2752
|
operation: effectiveStep.task,
|
|
2556
2753
|
payload: redactSecrets(request),
|
|
2557
|
-
...runState.agentUrl ? { url: runState.agentUrl } : {}
|
|
2754
|
+
...runState.agentUrl ? { url: redactOAuthUrlForOutput(runState.agentUrl) } : {}
|
|
2558
2755
|
};
|
|
2559
2756
|
const inputSchemaStripNotices = collectInputSchemaFieldStripNotices(
|
|
2560
2757
|
taskResult?.debug_logs,
|
|
@@ -2910,6 +3107,7 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
2910
3107
|
async function executeProbeStep(client, step, phaseId, context, allSteps, options, runState) {
|
|
2911
3108
|
const start = Date.now();
|
|
2912
3109
|
let httpResult;
|
|
3110
|
+
let oauthMetadataGraph;
|
|
2913
3111
|
const probeOpts = {
|
|
2914
3112
|
allowPrivateIp: options.allow_http === true,
|
|
2915
3113
|
fetchFn: options.transport?.fetchFn
|
|
@@ -2931,8 +3129,17 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
2931
3129
|
}
|
|
2932
3130
|
if (httpResult) {
|
|
2933
3131
|
} else if (step.task === "protected_resource_metadata") {
|
|
2934
|
-
|
|
2935
|
-
|
|
3132
|
+
if (step.validations?.some((validation) => validation.check === "oauth_metadata_graph")) {
|
|
3133
|
+
oauthMetadataGraph = await gradeOAuthMetadataGraph(runState.agentUrl, {
|
|
3134
|
+
allowHttp: options.allow_http === true,
|
|
3135
|
+
signal: options.signal,
|
|
3136
|
+
trustedFetchFn: options.transport?.fetchFn
|
|
3137
|
+
});
|
|
3138
|
+
httpResult = oauthMetadataGraph.protected_resource_result;
|
|
3139
|
+
} else {
|
|
3140
|
+
httpResult = await probeProtectedResourceMetadata(runState.agentUrl, probeOpts);
|
|
3141
|
+
}
|
|
3142
|
+
if (!oauthMetadataGraph && !httpResult.error && httpResult.status === 404) {
|
|
2936
3143
|
httpResult.skipped = true;
|
|
2937
3144
|
httpResult.skip_reason = "oauth_not_advertised";
|
|
2938
3145
|
}
|
|
@@ -2970,6 +3177,16 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
2970
3177
|
};
|
|
2971
3178
|
const targetRequestResult = buildEffectiveStepRequest(targetStep, context, options, runState);
|
|
2972
3179
|
if (!targetRequestResult.ok) {
|
|
3180
|
+
if ("creativeAssetFailure" in targetRequestResult) {
|
|
3181
|
+
return buildCreativeAssetFixtureUnavailableStep(
|
|
3182
|
+
step,
|
|
3183
|
+
phaseId,
|
|
3184
|
+
context,
|
|
3185
|
+
allSteps,
|
|
3186
|
+
runState,
|
|
3187
|
+
targetRequestResult.creativeAssetFailure
|
|
3188
|
+
);
|
|
3189
|
+
}
|
|
2973
3190
|
const next = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
|
|
2974
3191
|
return {
|
|
2975
3192
|
step_id: step.id,
|
|
@@ -3083,7 +3300,34 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
3083
3300
|
transport: targetTransport,
|
|
3084
3301
|
operation: rateLimitTrip.trip_target_task,
|
|
3085
3302
|
payload: redactSecrets(observedRequest),
|
|
3086
|
-
...runState.agentUrl ? { url: runState.agentUrl } : {}
|
|
3303
|
+
...runState.agentUrl ? { url: redactOAuthUrlForOutput(runState.agentUrl) } : {}
|
|
3304
|
+
};
|
|
3305
|
+
}
|
|
3306
|
+
} else if (step.task === REPLAY_TRUSTED_MATCH_CONTEXT_VECTOR_TASK) {
|
|
3307
|
+
const routerRunner = options.trusted_match_context_router_runner;
|
|
3308
|
+
if (!routerRunner?.router_url || typeof routerRunner.registerProviders !== "function") {
|
|
3309
|
+
httpResult = {
|
|
3310
|
+
url: routerRunner?.router_url ?? runState.agentUrl,
|
|
3311
|
+
status: 0,
|
|
3312
|
+
headers: {},
|
|
3313
|
+
body: null,
|
|
3314
|
+
skipped: true,
|
|
3315
|
+
skip_reason: "grader_skipped",
|
|
3316
|
+
error: "No Trusted Match Context router harness configured. Pass trusted_match_context_router_runner with router_url and registerProviders; the runner will not dispatch this pseudo-task over MCP/A2A."
|
|
3317
|
+
};
|
|
3318
|
+
} else {
|
|
3319
|
+
const requestOverride = options.request ? injectContext({ ...options.request }, context, runState.runnerVars) : step.sample_request ? injectContext({ ...step.sample_request }, context, runState.runnerVars) : void 0;
|
|
3320
|
+
const replay = await replayTrustedMatchContextVector(step, routerRunner, {
|
|
3321
|
+
...requestOverride && { requestOverride },
|
|
3322
|
+
...options.adcpVersion && { adcpVersion: options.adcpVersion },
|
|
3323
|
+
...options.signal && { signal: options.signal }
|
|
3324
|
+
});
|
|
3325
|
+
httpResult = replay.httpResult;
|
|
3326
|
+
requestRecordOverride = {
|
|
3327
|
+
transport: "http",
|
|
3328
|
+
operation: step.task,
|
|
3329
|
+
payload: redactSecrets(replay.request),
|
|
3330
|
+
url: redactOAuthUrlForOutput(replay.httpResult.url)
|
|
3087
3331
|
};
|
|
3088
3332
|
}
|
|
3089
3333
|
}
|
|
@@ -3093,7 +3337,7 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
3093
3337
|
transport: "http",
|
|
3094
3338
|
operation: step.task,
|
|
3095
3339
|
payload: null,
|
|
3096
|
-
...httpResult?.url ? { url: httpResult.url } : runState.agentUrl ? { url: runState.agentUrl } : {}
|
|
3340
|
+
...httpResult?.url ? { url: redactOAuthUrlForOutput(httpResult.url) } : runState.agentUrl ? { url: redactOAuthUrlForOutput(runState.agentUrl) } : {}
|
|
3097
3341
|
};
|
|
3098
3342
|
const filteredProbeHeaders = filterResponseHeaders(httpResult?.headers);
|
|
3099
3343
|
const responseTransport = requestRecordOverride?.transport ?? "http";
|
|
@@ -3106,6 +3350,7 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
3106
3350
|
} : void 0;
|
|
3107
3351
|
const redactedHttpResult = httpResult ? {
|
|
3108
3352
|
...httpResult,
|
|
3353
|
+
headers: filteredProbeHeaders ?? {},
|
|
3109
3354
|
body: redactSecrets(httpResult.body),
|
|
3110
3355
|
...responseTransport !== "http" && { status: void 0 }
|
|
3111
3356
|
} : void 0;
|
|
@@ -3135,15 +3380,24 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
3135
3380
|
};
|
|
3136
3381
|
}
|
|
3137
3382
|
const vctx = {
|
|
3138
|
-
taskName: step.task,
|
|
3383
|
+
taskName: step.task === REPLAY_TRUSTED_MATCH_CONTEXT_VECTOR_TASK ? "context_match" : step.task,
|
|
3139
3384
|
...options.adcpVersion && { adcpVersion: options.adcpVersion },
|
|
3140
3385
|
...options._serverAdcpVersion && { responseAdcpVersion: options._serverAdcpVersion },
|
|
3141
3386
|
httpResult: redactedHttpResult,
|
|
3387
|
+
...step.task === REPLAY_TRUSTED_MATCH_CONTEXT_VECTOR_TASK && redactedHttpResult && {
|
|
3388
|
+
taskResult: {
|
|
3389
|
+
success: !redactedHttpResult.error && redactedHttpResult.status >= 200 && redactedHttpResult.status < 300,
|
|
3390
|
+
data: redactedHttpResult.body,
|
|
3391
|
+
...redactedHttpResult.error && { error: redactedHttpResult.error }
|
|
3392
|
+
}
|
|
3393
|
+
},
|
|
3142
3394
|
agentUrl: runState.agentUrl,
|
|
3143
3395
|
contributions: runState.contributions,
|
|
3396
|
+
...step.response_schema_ref && { responseSchemaRef: step.response_schema_ref },
|
|
3144
3397
|
request: requestRecord,
|
|
3145
3398
|
...responseRecord && { response: responseRecord },
|
|
3146
|
-
storyboardContext: context
|
|
3399
|
+
storyboardContext: context,
|
|
3400
|
+
...oauthMetadataGraph && { oauthMetadataGraph }
|
|
3147
3401
|
};
|
|
3148
3402
|
const validations = step.validations?.length ? runValidations(step.validations, vctx) : [];
|
|
3149
3403
|
const allValidationsPassed = validations.every((v) => v.passed);
|
|
@@ -3205,13 +3459,73 @@ function buildEffectiveStepRequest(step, context, options, runState) {
|
|
|
3205
3459
|
request = applyIdempotencyInvariant(request, step.task, step);
|
|
3206
3460
|
const fixtureBinding = applyFixtureBindingsSafely(request, step.task, options, runState);
|
|
3207
3461
|
if (!fixtureBinding.ok) return fixtureBinding;
|
|
3462
|
+
const creativeAssetExpansion = expandCreativeAssetDirectivesWithDiagnostics(
|
|
3463
|
+
fixtureBinding.request,
|
|
3464
|
+
context,
|
|
3465
|
+
options.test_kit
|
|
3466
|
+
);
|
|
3467
|
+
if (!creativeAssetExpansion.ok && creativeAssetExpansion.failure.reason === "fixture_unavailable") {
|
|
3468
|
+
return { ok: false, creativeAssetFailure: creativeAssetExpansion.failure };
|
|
3469
|
+
}
|
|
3208
3470
|
return {
|
|
3209
3471
|
ok: true,
|
|
3210
|
-
request:
|
|
3472
|
+
request: creativeAssetExpansion.value
|
|
3211
3473
|
};
|
|
3212
3474
|
}
|
|
3475
|
+
function preflightRemainingCreativeAssetDirectives(allSteps, afterGlobalIndex, context, options, runState, excludedPhaseIds = /* @__PURE__ */ new Set()) {
|
|
3476
|
+
for (const target of allSteps) {
|
|
3477
|
+
if (target.globalIndex <= afterGlobalIndex) continue;
|
|
3478
|
+
if (excludedPhaseIds.has(target.phaseId)) continue;
|
|
3479
|
+
const resolvedTask = resolveTaskName(target.step, options);
|
|
3480
|
+
if (!resolvedTask) continue;
|
|
3481
|
+
if (target.step.requires_tool && options.agentTools && !options.agentTools.includes(target.step.requires_tool)) {
|
|
3482
|
+
continue;
|
|
3483
|
+
}
|
|
3484
|
+
if (target.step.requires_contract && !new Set(options.contracts ?? []).has(target.step.requires_contract)) {
|
|
3485
|
+
continue;
|
|
3486
|
+
}
|
|
3487
|
+
if (!PROBE_TASKS.has(target.step.task) && options.agentTools && !options.agentTools.includes(resolvedTask)) {
|
|
3488
|
+
continue;
|
|
3489
|
+
}
|
|
3490
|
+
let requestStep = resolvedTask === target.step.task ? target.step : { ...target.step, task: resolvedTask };
|
|
3491
|
+
if (target.step.task === "expect_rate_limit_not_replayed") {
|
|
3492
|
+
const rateLimitTrip = target.step.rate_limit_trip;
|
|
3493
|
+
if (validateRateLimitTripSpec(rateLimitTrip) || !rateLimitTrip) continue;
|
|
3494
|
+
requestStep = {
|
|
3495
|
+
...target.step,
|
|
3496
|
+
task: rateLimitTrip.trip_target_task,
|
|
3497
|
+
sample_request: rateLimitTrip.trip_target_sample_request,
|
|
3498
|
+
omit_idempotency_key: true
|
|
3499
|
+
};
|
|
3500
|
+
}
|
|
3501
|
+
const request = buildEffectiveStepRequest(requestStep, context, options, runState);
|
|
3502
|
+
if (!request.ok && "creativeAssetFailure" in request) {
|
|
3503
|
+
return { target, failure: request.creativeAssetFailure };
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
return void 0;
|
|
3507
|
+
}
|
|
3213
3508
|
async function executeReplayWebhookVectorStep(step, phaseId, context, allSteps, options, runState) {
|
|
3214
3509
|
const start = Date.now();
|
|
3510
|
+
if (step.requires_contract && !new Set(options.contracts ?? []).has(step.requires_contract)) {
|
|
3511
|
+
const detail = `Test-kit contract "${step.requires_contract}" is not configured on this runner.`;
|
|
3512
|
+
const reason = "missing_test_kit_contract";
|
|
3513
|
+
return {
|
|
3514
|
+
step_id: step.id,
|
|
3515
|
+
phase_id: phaseId,
|
|
3516
|
+
title: step.title,
|
|
3517
|
+
task: step.task,
|
|
3518
|
+
passed: true,
|
|
3519
|
+
skipped: true,
|
|
3520
|
+
skip_reason: reason,
|
|
3521
|
+
skip: buildSkip(DETAILED_SKIP_TO_CANONICAL[reason], detail),
|
|
3522
|
+
duration_ms: Date.now() - start,
|
|
3523
|
+
validations: [],
|
|
3524
|
+
context,
|
|
3525
|
+
next: getNextStepPreview(step.id, allSteps, context, runState.runnerVars),
|
|
3526
|
+
extraction: { path: "none", note: "test-kit contract not configured" }
|
|
3527
|
+
};
|
|
3528
|
+
}
|
|
3215
3529
|
const receiver = options.webhook_replay_receiver;
|
|
3216
3530
|
if (!receiver?.url) {
|
|
3217
3531
|
const detail = "No webhook replay receiver URL configured. Pass `webhook_replay_receiver.url` in StoryboardRunOptions to run inbound receiver conformance.";
|
|
@@ -3789,6 +4103,9 @@ function phaseContainsOauthMetadataProbe(phase) {
|
|
|
3789
4103
|
function agentAdvertisesOauth(profile) {
|
|
3790
4104
|
const rawCaps = profile?.raw_capabilities;
|
|
3791
4105
|
if (rawCaps === void 0) return true;
|
|
4106
|
+
const oauthSupported = resolveCapabilityPath(rawCaps, "oauth.supported");
|
|
4107
|
+
if (oauthSupported === true) return true;
|
|
4108
|
+
if (oauthSupported === false) return false;
|
|
3792
4109
|
const endpoint = resolveCapabilityPath(rawCaps, "account.authorization_endpoint");
|
|
3793
4110
|
return typeof endpoint === "string" && endpoint.length > 0;
|
|
3794
4111
|
}
|
|
@@ -4044,7 +4361,7 @@ async function prefetchUpstreamTraffic(stepId, resolvedValidations, client, opti
|
|
|
4044
4361
|
transport: options.protocol === "a2a" ? "a2a" : "mcp",
|
|
4045
4362
|
operation: "comply_test_controller",
|
|
4046
4363
|
payload: redactSecrets({ scenario: "query_upstream_traffic", params }),
|
|
4047
|
-
...runState.agentUrl ? { url: runState.agentUrl } : {}
|
|
4364
|
+
...runState.agentUrl ? { url: redactOAuthUrlForOutput(runState.agentUrl) } : {}
|
|
4048
4365
|
};
|
|
4049
4366
|
const startMs = Date.now();
|
|
4050
4367
|
let payload;
|