@adcp/sdk 17.0.0-beta.0 → 17.0.0-beta.1
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/version/3.1/bidding.js +1 -1
- package/dist/lib/adapters/version/3.1/bidding.mjs +1 -1
- package/dist/lib/core/ResponseValidator.js +1 -1
- package/dist/lib/core/ResponseValidator.mjs +1 -1
- package/dist/lib/core/SingleAgentClient.d.mts +7 -5
- package/dist/lib/core/SingleAgentClient.d.ts +7 -5
- package/dist/lib/core/SingleAgentClient.js +57 -32
- package/dist/lib/core/SingleAgentClient.mjs +59 -33
- package/dist/lib/core/TaskExecutor.js +5 -3
- package/dist/lib/core/TaskExecutor.mjs +5 -3
- package/dist/lib/errors/index.d.mts +22 -0
- package/dist/lib/errors/index.d.ts +22 -0
- package/dist/lib/errors/index.js +43 -0
- package/dist/lib/errors/index.mjs +42 -0
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.mjs +2 -0
- package/dist/lib/protocols/mcp-modern.d.mts +2 -0
- package/dist/lib/protocols/mcp-modern.d.ts +2 -0
- package/dist/lib/protocols/mcp-modern.js +31 -5
- package/dist/lib/protocols/mcp-modern.mjs +31 -5
- package/dist/lib/protocols/mcp-scope.d.mts +3 -1
- package/dist/lib/protocols/mcp-scope.d.ts +3 -1
- package/dist/lib/protocols/mcp-scope.js +19 -2
- package/dist/lib/protocols/mcp-scope.mjs +18 -2
- package/dist/lib/protocols/mcp.js +12 -6
- package/dist/lib/protocols/mcp.mjs +13 -6
- package/dist/lib/testing/client.d.mts +1 -0
- package/dist/lib/testing/client.d.ts +1 -0
- package/dist/lib/testing/client.js +6 -5
- package/dist/lib/testing/client.mjs +6 -5
- package/dist/lib/testing/storyboard/agent-routing.d.mts +5 -2
- package/dist/lib/testing/storyboard/agent-routing.d.ts +5 -2
- package/dist/lib/testing/storyboard/agent-routing.js +11 -4
- package/dist/lib/testing/storyboard/agent-routing.mjs +11 -4
- package/dist/lib/testing/storyboard/context.d.mts +13 -3
- package/dist/lib/testing/storyboard/context.d.ts +13 -3
- package/dist/lib/testing/storyboard/context.js +15 -10
- package/dist/lib/testing/storyboard/context.mjs +15 -10
- package/dist/lib/testing/storyboard/runner.js +141 -13
- package/dist/lib/testing/storyboard/runner.mjs +141 -13
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/validations.js +4 -1
- package/dist/lib/testing/storyboard/validations.mjs +4 -1
- package/dist/lib/testing/test-controller.js +3 -0
- package/dist/lib/testing/test-controller.mjs +3 -0
- package/dist/lib/utils/envelope-status-compat.d.mts +18 -1
- package/dist/lib/utils/envelope-status-compat.d.ts +18 -1
- package/dist/lib/utils/envelope-status-compat.js +11 -5
- package/dist/lib/utils/envelope-status-compat.mjs +11 -5
- package/dist/lib/utils/response-unwrapper.js +12 -9
- package/dist/lib/utils/response-unwrapper.mjs +12 -9
- package/dist/lib/v2/projection/creative-delivery.js +56 -11
- package/dist/lib/v2/projection/creative-delivery.mjs +56 -11
- package/dist/lib/validation/schema-validator.js +1 -1
- package/dist/lib/validation/schema-validator.mjs +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.mjs +3 -3
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/COLLECTION-FIXTURE-FOUNDATION.md +11 -0
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +12 -1
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-16-to-17.md +24 -1
- package/docs/migration-reporting-storage-package.md +1 -1
- package/package.json +1 -1
|
@@ -641,23 +641,24 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
|
|
|
641
641
|
}
|
|
642
642
|
const failure = describeProfileDiscoveryFailure(profile);
|
|
643
643
|
if (!step.passed || failure) {
|
|
644
|
-
const
|
|
645
|
-
|
|
644
|
+
const evidence2 = { ...step, ...failure ?? {}, passed: false, duration_ms: step.duration_ms };
|
|
645
|
+
evidence2.error = (0, import_redact_credential_patterns.redactCredentialPatterns)(evidence2.error ?? "Agent discovery failed", false).slice(
|
|
646
646
|
0,
|
|
647
647
|
4096
|
|
648
648
|
);
|
|
649
|
-
profile.capabilities_failure =
|
|
649
|
+
profile.capabilities_failure = evidence2;
|
|
650
650
|
}
|
|
651
651
|
if (!step.passed) step.error = (0, import_redact_credential_patterns.redactCredentialPatterns)(step.error ?? "Agent discovery failed", false);
|
|
652
652
|
if (!failure && step.passed && (scopeKey === void 0 || scopeKey === client.getCapabilityEvidenceScope().scopeKey)) {
|
|
653
653
|
seedTestClientSigningCapability(client, profile, schemaAdcpVersion);
|
|
654
654
|
}
|
|
655
|
+
const evidence = step.passed && !failure ? { ...step } : void 0;
|
|
655
656
|
if (step.passed && !failure) {
|
|
656
657
|
delete step.request;
|
|
657
658
|
delete step.response_record;
|
|
658
659
|
delete step.adcp_error;
|
|
659
660
|
}
|
|
660
|
-
return { profile, step, ...caughtError !== void 0 && { caughtError } };
|
|
661
|
+
return { profile, step, ...caughtError !== void 0 && { caughtError }, ...evidence && { evidence } };
|
|
661
662
|
}
|
|
662
663
|
async function discoverAgentCapabilities(client, profile, options) {
|
|
663
664
|
const steps = [];
|
|
@@ -876,7 +877,7 @@ function validateResponseSchema(toolName, data, responseAdcpVersion) {
|
|
|
876
877
|
warnings: [`No Zod schema registered for "${toolName}" \u2014 validation skipped`]
|
|
877
878
|
};
|
|
878
879
|
}
|
|
879
|
-
const compatData = data && typeof data === "object" && !Array.isArray(data) ? (0, import_envelope_status_compat.injectLegacyEnvelopeStatus)(data, { toolName }) : data;
|
|
880
|
+
const compatData = data && typeof data === "object" && !Array.isArray(data) ? (0, import_envelope_status_compat.injectLegacyEnvelopeStatus)(data, { toolName, adcpVersion: responseAdcpVersion }) : data;
|
|
880
881
|
const result = schema.safeParse((0, import_response_schemas.prepareResponseForSchemaValidation)(toolName, compatData, responseAdcpVersion));
|
|
881
882
|
if (result.success) {
|
|
882
883
|
return {
|
|
@@ -599,23 +599,24 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
|
|
|
599
599
|
}
|
|
600
600
|
const failure = describeProfileDiscoveryFailure(profile);
|
|
601
601
|
if (!step.passed || failure) {
|
|
602
|
-
const
|
|
603
|
-
|
|
602
|
+
const evidence2 = { ...step, ...failure ?? {}, passed: false, duration_ms: step.duration_ms };
|
|
603
|
+
evidence2.error = redactCredentialPatterns(evidence2.error ?? "Agent discovery failed", false).slice(
|
|
604
604
|
0,
|
|
605
605
|
4096
|
|
606
606
|
);
|
|
607
|
-
profile.capabilities_failure =
|
|
607
|
+
profile.capabilities_failure = evidence2;
|
|
608
608
|
}
|
|
609
609
|
if (!step.passed) step.error = redactCredentialPatterns(step.error ?? "Agent discovery failed", false);
|
|
610
610
|
if (!failure && step.passed && (scopeKey === void 0 || scopeKey === client.getCapabilityEvidenceScope().scopeKey)) {
|
|
611
611
|
seedTestClientSigningCapability(client, profile, schemaAdcpVersion);
|
|
612
612
|
}
|
|
613
|
+
const evidence = step.passed && !failure ? { ...step } : void 0;
|
|
613
614
|
if (step.passed && !failure) {
|
|
614
615
|
delete step.request;
|
|
615
616
|
delete step.response_record;
|
|
616
617
|
delete step.adcp_error;
|
|
617
618
|
}
|
|
618
|
-
return { profile, step, ...caughtError !== void 0 && { caughtError } };
|
|
619
|
+
return { profile, step, ...caughtError !== void 0 && { caughtError }, ...evidence && { evidence } };
|
|
619
620
|
}
|
|
620
621
|
async function discoverAgentCapabilities(client, profile, options) {
|
|
621
622
|
const steps = [];
|
|
@@ -834,7 +835,7 @@ function validateResponseSchema(toolName, data, responseAdcpVersion) {
|
|
|
834
835
|
warnings: [`No Zod schema registered for "${toolName}" \u2014 validation skipped`]
|
|
835
836
|
};
|
|
836
837
|
}
|
|
837
|
-
const compatData = data && typeof data === "object" && !Array.isArray(data) ? injectLegacyEnvelopeStatus(data, { toolName }) : data;
|
|
838
|
+
const compatData = data && typeof data === "object" && !Array.isArray(data) ? injectLegacyEnvelopeStatus(data, { toolName, adcpVersion: responseAdcpVersion }) : data;
|
|
838
839
|
const result = schema.safeParse(prepareResponseForSchemaValidation(toolName, compatData, responseAdcpVersion));
|
|
839
840
|
if (result.success) {
|
|
840
841
|
return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TestClient } from '../client.mjs';
|
|
2
|
-
import type { AgentProfile } from '../types.mjs';
|
|
2
|
+
import type { AgentProfile, TestStepResult } from '../types.mjs';
|
|
3
3
|
import { type AdcpProtocol } from '../../utils/capabilities.mjs';
|
|
4
4
|
import type { AgentEntry, Storyboard, StoryboardRunOptions, StoryboardStep } from './types.mjs';
|
|
5
5
|
/** Storyboard applicability is any-of; it does not authorize individual steps. */
|
|
@@ -18,6 +18,8 @@ export interface AgentRoutingContext {
|
|
|
18
18
|
clients: Map<string, TestClient>;
|
|
19
19
|
/** Per-agent discovered profile (`get_adcp_capabilities` result). */
|
|
20
20
|
profiles: Map<string, AgentProfile>;
|
|
21
|
+
/** Actual discovery exchanges, retained separately from compact rollup steps. */
|
|
22
|
+
discoverySteps?: ReadonlyMap<string, TestStepResult>;
|
|
21
23
|
/** Protocol → keys of agents that claim it. */
|
|
22
24
|
protocolIndex: Map<AdcpProtocol, string[]>;
|
|
23
25
|
/** Resolved (key → URL) for echo on the storyboard result. */
|
|
@@ -41,7 +43,8 @@ export declare class DiscoveryFailure extends Error {
|
|
|
41
43
|
readonly agentKey: string;
|
|
42
44
|
readonly url: string;
|
|
43
45
|
readonly underlying: string;
|
|
44
|
-
|
|
46
|
+
readonly step?: TestStepResult | undefined;
|
|
47
|
+
constructor(message: string, agentKey: string, url: string, underlying: string, step?: TestStepResult | undefined);
|
|
45
48
|
}
|
|
46
49
|
/**
|
|
47
50
|
* Discover every agent in the map in parallel and build the routing index.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TestClient } from '../client';
|
|
2
|
-
import type { AgentProfile } from '../types';
|
|
2
|
+
import type { AgentProfile, TestStepResult } from '../types';
|
|
3
3
|
import { type AdcpProtocol } from '../../utils/capabilities';
|
|
4
4
|
import type { AgentEntry, Storyboard, StoryboardRunOptions, StoryboardStep } from './types';
|
|
5
5
|
/** Storyboard applicability is any-of; it does not authorize individual steps. */
|
|
@@ -18,6 +18,8 @@ export interface AgentRoutingContext {
|
|
|
18
18
|
clients: Map<string, TestClient>;
|
|
19
19
|
/** Per-agent discovered profile (`get_adcp_capabilities` result). */
|
|
20
20
|
profiles: Map<string, AgentProfile>;
|
|
21
|
+
/** Actual discovery exchanges, retained separately from compact rollup steps. */
|
|
22
|
+
discoverySteps?: ReadonlyMap<string, TestStepResult>;
|
|
21
23
|
/** Protocol → keys of agents that claim it. */
|
|
22
24
|
protocolIndex: Map<AdcpProtocol, string[]>;
|
|
23
25
|
/** Resolved (key → URL) for echo on the storyboard result. */
|
|
@@ -41,7 +43,8 @@ export declare class DiscoveryFailure extends Error {
|
|
|
41
43
|
readonly agentKey: string;
|
|
42
44
|
readonly url: string;
|
|
43
45
|
readonly underlying: string;
|
|
44
|
-
|
|
46
|
+
readonly step?: TestStepResult | undefined;
|
|
47
|
+
constructor(message: string, agentKey: string, url: string, underlying: string, step?: TestStepResult | undefined);
|
|
45
48
|
}
|
|
46
49
|
/**
|
|
47
50
|
* Discover every agent in the map in parallel and build the routing index.
|
|
@@ -127,16 +127,18 @@ class RoutingError extends Error {
|
|
|
127
127
|
hint;
|
|
128
128
|
}
|
|
129
129
|
class DiscoveryFailure extends Error {
|
|
130
|
-
constructor(message, agentKey, url, underlying) {
|
|
130
|
+
constructor(message, agentKey, url, underlying, step) {
|
|
131
131
|
super(message);
|
|
132
132
|
this.agentKey = agentKey;
|
|
133
133
|
this.url = url;
|
|
134
134
|
this.underlying = underlying;
|
|
135
|
+
this.step = step;
|
|
135
136
|
this.name = "DiscoveryFailure";
|
|
136
137
|
}
|
|
137
138
|
agentKey;
|
|
138
139
|
url;
|
|
139
140
|
underlying;
|
|
141
|
+
step;
|
|
140
142
|
}
|
|
141
143
|
async function discoverAgentRouting(options) {
|
|
142
144
|
const agents = options.agents;
|
|
@@ -150,6 +152,7 @@ async function discoverAgentRouting(options) {
|
|
|
150
152
|
agentMap[key] = entry.url;
|
|
151
153
|
}
|
|
152
154
|
const profiles = /* @__PURE__ */ new Map();
|
|
155
|
+
const discoverySteps = /* @__PURE__ */ new Map();
|
|
153
156
|
const discoveryFailures = [];
|
|
154
157
|
if (options._routingProfiles) {
|
|
155
158
|
for (const [key] of entries) {
|
|
@@ -162,6 +165,7 @@ async function discoverAgentRouting(options) {
|
|
|
162
165
|
return {
|
|
163
166
|
clients,
|
|
164
167
|
profiles,
|
|
168
|
+
discoverySteps,
|
|
165
169
|
protocolIndex: buildProtocolIndex(profiles),
|
|
166
170
|
agentMap,
|
|
167
171
|
discoveryFailures
|
|
@@ -171,8 +175,8 @@ async function discoverAgentRouting(options) {
|
|
|
171
175
|
entries.map(async ([key, entry]) => {
|
|
172
176
|
const perAgentOptions = buildAgentOptions(entry, options);
|
|
173
177
|
try {
|
|
174
|
-
const { profile, step } = await (0, import_client.getOrDiscoverStoryboardProfile)(clients.get(key), perAgentOptions);
|
|
175
|
-
return { key, profile, step };
|
|
178
|
+
const { profile, step, evidence } = await (0, import_client.getOrDiscoverStoryboardProfile)(clients.get(key), perAgentOptions);
|
|
179
|
+
return { key, profile, step, evidence };
|
|
176
180
|
} catch (err) {
|
|
177
181
|
return {
|
|
178
182
|
key,
|
|
@@ -180,6 +184,7 @@ async function discoverAgentRouting(options) {
|
|
|
180
184
|
step: {
|
|
181
185
|
step: "Discover agent capabilities",
|
|
182
186
|
passed: false,
|
|
187
|
+
duration_ms: 0,
|
|
183
188
|
error: scrubAuthSecrets(err?.message || String(err))
|
|
184
189
|
}
|
|
185
190
|
};
|
|
@@ -187,6 +192,7 @@ async function discoverAgentRouting(options) {
|
|
|
187
192
|
})
|
|
188
193
|
);
|
|
189
194
|
for (const r of discoveryResults) {
|
|
195
|
+
discoverySteps.set(r.key, "evidence" in r && r.evidence ? r.evidence : r.step);
|
|
190
196
|
if (!r.profile || r.step.passed === false) {
|
|
191
197
|
const rawDetail = scrubAuthSecrets(r.step.error ?? "Discovery returned no profile.");
|
|
192
198
|
const detail = rawDetail.length > 512 ? `${rawDetail.slice(0, 512)} \u2026(truncated)` : rawDetail;
|
|
@@ -194,7 +200,7 @@ async function discoverAgentRouting(options) {
|
|
|
194
200
|
const message = resilient ? baseMessage : `${baseMessage}
|
|
195
201
|
|
|
196
202
|
If this is hello-cluster / exploratory CI and you want unrelated storyboards to complete despite this failure, set \`StoryboardRunOptions.discovery_resilient: true\`. Do NOT set it in production \u2014 a topology with a broken tenant is a hard misconfiguration there.`;
|
|
197
|
-
const failure = new DiscoveryFailure(message, r.key, agents[r.key].url, detail);
|
|
203
|
+
const failure = new DiscoveryFailure(message, r.key, agents[r.key].url, detail, { ...r.step, error: detail });
|
|
198
204
|
if (!resilient) throw failure;
|
|
199
205
|
discoveryFailures.push(failure);
|
|
200
206
|
continue;
|
|
@@ -204,6 +210,7 @@ If this is hello-cluster / exploratory CI and you want unrelated storyboards to
|
|
|
204
210
|
return {
|
|
205
211
|
clients,
|
|
206
212
|
profiles,
|
|
213
|
+
discoverySteps,
|
|
207
214
|
protocolIndex: buildProtocolIndex(profiles),
|
|
208
215
|
agentMap,
|
|
209
216
|
discoveryFailures
|
|
@@ -95,16 +95,18 @@ class RoutingError extends Error {
|
|
|
95
95
|
hint;
|
|
96
96
|
}
|
|
97
97
|
class DiscoveryFailure extends Error {
|
|
98
|
-
constructor(message, agentKey, url, underlying) {
|
|
98
|
+
constructor(message, agentKey, url, underlying, step) {
|
|
99
99
|
super(message);
|
|
100
100
|
this.agentKey = agentKey;
|
|
101
101
|
this.url = url;
|
|
102
102
|
this.underlying = underlying;
|
|
103
|
+
this.step = step;
|
|
103
104
|
this.name = "DiscoveryFailure";
|
|
104
105
|
}
|
|
105
106
|
agentKey;
|
|
106
107
|
url;
|
|
107
108
|
underlying;
|
|
109
|
+
step;
|
|
108
110
|
}
|
|
109
111
|
async function discoverAgentRouting(options) {
|
|
110
112
|
const agents = options.agents;
|
|
@@ -118,6 +120,7 @@ async function discoverAgentRouting(options) {
|
|
|
118
120
|
agentMap[key] = entry.url;
|
|
119
121
|
}
|
|
120
122
|
const profiles = /* @__PURE__ */ new Map();
|
|
123
|
+
const discoverySteps = /* @__PURE__ */ new Map();
|
|
121
124
|
const discoveryFailures = [];
|
|
122
125
|
if (options._routingProfiles) {
|
|
123
126
|
for (const [key] of entries) {
|
|
@@ -130,6 +133,7 @@ async function discoverAgentRouting(options) {
|
|
|
130
133
|
return {
|
|
131
134
|
clients,
|
|
132
135
|
profiles,
|
|
136
|
+
discoverySteps,
|
|
133
137
|
protocolIndex: buildProtocolIndex(profiles),
|
|
134
138
|
agentMap,
|
|
135
139
|
discoveryFailures
|
|
@@ -139,8 +143,8 @@ async function discoverAgentRouting(options) {
|
|
|
139
143
|
entries.map(async ([key, entry]) => {
|
|
140
144
|
const perAgentOptions = buildAgentOptions(entry, options);
|
|
141
145
|
try {
|
|
142
|
-
const { profile, step } = await getOrDiscoverStoryboardProfile(clients.get(key), perAgentOptions);
|
|
143
|
-
return { key, profile, step };
|
|
146
|
+
const { profile, step, evidence } = await getOrDiscoverStoryboardProfile(clients.get(key), perAgentOptions);
|
|
147
|
+
return { key, profile, step, evidence };
|
|
144
148
|
} catch (err) {
|
|
145
149
|
return {
|
|
146
150
|
key,
|
|
@@ -148,6 +152,7 @@ async function discoverAgentRouting(options) {
|
|
|
148
152
|
step: {
|
|
149
153
|
step: "Discover agent capabilities",
|
|
150
154
|
passed: false,
|
|
155
|
+
duration_ms: 0,
|
|
151
156
|
error: scrubAuthSecrets(err?.message || String(err))
|
|
152
157
|
}
|
|
153
158
|
};
|
|
@@ -155,6 +160,7 @@ async function discoverAgentRouting(options) {
|
|
|
155
160
|
})
|
|
156
161
|
);
|
|
157
162
|
for (const r of discoveryResults) {
|
|
163
|
+
discoverySteps.set(r.key, "evidence" in r && r.evidence ? r.evidence : r.step);
|
|
158
164
|
if (!r.profile || r.step.passed === false) {
|
|
159
165
|
const rawDetail = scrubAuthSecrets(r.step.error ?? "Discovery returned no profile.");
|
|
160
166
|
const detail = rawDetail.length > 512 ? `${rawDetail.slice(0, 512)} \u2026(truncated)` : rawDetail;
|
|
@@ -162,7 +168,7 @@ async function discoverAgentRouting(options) {
|
|
|
162
168
|
const message = resilient ? baseMessage : `${baseMessage}
|
|
163
169
|
|
|
164
170
|
If this is hello-cluster / exploratory CI and you want unrelated storyboards to complete despite this failure, set \`StoryboardRunOptions.discovery_resilient: true\`. Do NOT set it in production \u2014 a topology with a broken tenant is a hard misconfiguration there.`;
|
|
165
|
-
const failure = new DiscoveryFailure(message, r.key, agents[r.key].url, detail);
|
|
171
|
+
const failure = new DiscoveryFailure(message, r.key, agents[r.key].url, detail, { ...r.step, error: detail });
|
|
166
172
|
if (!resilient) throw failure;
|
|
167
173
|
discoveryFailures.push(failure);
|
|
168
174
|
continue;
|
|
@@ -172,6 +178,7 @@ If this is hello-cluster / exploratory CI and you want unrelated storyboards to
|
|
|
172
178
|
return {
|
|
173
179
|
clients,
|
|
174
180
|
profiles,
|
|
181
|
+
discoverySteps,
|
|
175
182
|
protocolIndex: buildProtocolIndex(profiles),
|
|
176
183
|
agentMap,
|
|
177
184
|
discoveryFailures
|
|
@@ -10,12 +10,22 @@
|
|
|
10
10
|
* (context_outputs/context_inputs) while still enabling stateful flows.
|
|
11
11
|
*/
|
|
12
12
|
import type { StoryboardContext, ContextOutput, ContextInput, ContextProvenanceEntry } from './types.mjs';
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* `adcpVersion` is the release the step was requested at. Media-buy mutation
|
|
15
|
+
* extractors use it to tell a 3.1+ task-envelope `status` from a 3.0
|
|
16
|
+
* lifecycle `status` when the response does not echo its version.
|
|
17
|
+
*/
|
|
18
|
+
type ContextExtractor = (data: unknown, adcpVersion?: string) => Record<string, unknown>;
|
|
14
19
|
export declare const CONTEXT_EXTRACTORS: Record<string, ContextExtractor>;
|
|
15
20
|
/**
|
|
16
21
|
* Extract context values from a task response.
|
|
22
|
+
*
|
|
23
|
+
* @param adcpVersion - Optional AdCP release the request was sent at. Used
|
|
24
|
+
* only when the response does not echo `adcp_version`, to read a
|
|
25
|
+
* create/update top-level `status` as the 3.1+ task status rather than a
|
|
26
|
+
* 3.0 media-buy lifecycle.
|
|
17
27
|
*/
|
|
18
|
-
export declare function extractContext(taskName: string, data: unknown): Record<string, unknown>;
|
|
28
|
+
export declare function extractContext(taskName: string, data: unknown, adcpVersion?: string): Record<string, unknown>;
|
|
19
29
|
/**
|
|
20
30
|
* Propagate the alias cache from one context to another — call after
|
|
21
31
|
* shallow-cloning context between storyboard steps so replay tests
|
|
@@ -132,7 +142,7 @@ export interface ContextWriteResult {
|
|
|
132
142
|
* tagging it as a convention-based extraction. `response_path` is absent
|
|
133
143
|
* for convention extractors — they're hardcoded functions, not YAML paths.
|
|
134
144
|
*/
|
|
135
|
-
export declare function extractContextWithProvenance(taskName: string, data: unknown, stepId: string): ContextWriteResult;
|
|
145
|
+
export declare function extractContextWithProvenance(taskName: string, data: unknown, stepId: string, adcpVersion?: string): ContextWriteResult;
|
|
136
146
|
/**
|
|
137
147
|
* Like `applyContextOutputs`, but also returns provenance for each written
|
|
138
148
|
* key carrying the YAML `response_path` so diagnostics can cite it verbatim.
|
|
@@ -10,12 +10,22 @@
|
|
|
10
10
|
* (context_outputs/context_inputs) while still enabling stateful flows.
|
|
11
11
|
*/
|
|
12
12
|
import type { StoryboardContext, ContextOutput, ContextInput, ContextProvenanceEntry } from './types';
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* `adcpVersion` is the release the step was requested at. Media-buy mutation
|
|
15
|
+
* extractors use it to tell a 3.1+ task-envelope `status` from a 3.0
|
|
16
|
+
* lifecycle `status` when the response does not echo its version.
|
|
17
|
+
*/
|
|
18
|
+
type ContextExtractor = (data: unknown, adcpVersion?: string) => Record<string, unknown>;
|
|
14
19
|
export declare const CONTEXT_EXTRACTORS: Record<string, ContextExtractor>;
|
|
15
20
|
/**
|
|
16
21
|
* Extract context values from a task response.
|
|
22
|
+
*
|
|
23
|
+
* @param adcpVersion - Optional AdCP release the request was sent at. Used
|
|
24
|
+
* only when the response does not echo `adcp_version`, to read a
|
|
25
|
+
* create/update top-level `status` as the 3.1+ task status rather than a
|
|
26
|
+
* 3.0 media-buy lifecycle.
|
|
17
27
|
*/
|
|
18
|
-
export declare function extractContext(taskName: string, data: unknown): Record<string, unknown>;
|
|
28
|
+
export declare function extractContext(taskName: string, data: unknown, adcpVersion?: string): Record<string, unknown>;
|
|
19
29
|
/**
|
|
20
30
|
* Propagate the alias cache from one context to another — call after
|
|
21
31
|
* shallow-cloning context between storyboard steps so replay tests
|
|
@@ -132,7 +142,7 @@ export interface ContextWriteResult {
|
|
|
132
142
|
* tagging it as a convention-based extraction. `response_path` is absent
|
|
133
143
|
* for convention extractors — they're hardcoded functions, not YAML paths.
|
|
134
144
|
*/
|
|
135
|
-
export declare function extractContextWithProvenance(taskName: string, data: unknown, stepId: string): ContextWriteResult;
|
|
145
|
+
export declare function extractContextWithProvenance(taskName: string, data: unknown, stepId: string, adcpVersion?: string): ContextWriteResult;
|
|
136
146
|
/**
|
|
137
147
|
* Like `applyContextOutputs`, but also returns provenance for each written
|
|
138
148
|
* key carrying the YAML `response_path` so diagnostics can cite it verbatim.
|
|
@@ -59,14 +59,19 @@ function asRecord(value) {
|
|
|
59
59
|
function readMediaBuyStatus(record) {
|
|
60
60
|
return (0, import_media_buy_status.getAuthoritativeMediaBuyStatus)(record);
|
|
61
61
|
}
|
|
62
|
-
function readMediaBuyFields(data) {
|
|
62
|
+
function readMediaBuyFields(data, adcpVersion) {
|
|
63
63
|
const outer = asRecord(data);
|
|
64
64
|
const nested = asRecord(outer?.media_buy);
|
|
65
65
|
return {
|
|
66
66
|
mediaBuyId: nested?.media_buy_id ?? outer?.media_buy_id,
|
|
67
|
-
status: readMediaBuyStatus(nested) ?? readMediaBuyStatus(outer)
|
|
67
|
+
status: readMediaBuyStatus(nested) ?? readMediaBuyStatus(withRequestedVersion(outer, adcpVersion))
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
+
function withRequestedVersion(record, adcpVersion) {
|
|
71
|
+
if (!record || !adcpVersion) return record;
|
|
72
|
+
if (typeof record.adcp_version === "string" || typeof record.adcp_major_version === "number") return record;
|
|
73
|
+
return { ...record, adcp_version: adcpVersion };
|
|
74
|
+
}
|
|
70
75
|
function readProposalFields(proposal) {
|
|
71
76
|
if (!proposal) return {};
|
|
72
77
|
const extracted = {};
|
|
@@ -181,15 +186,15 @@ const CONTEXT_EXTRACTORS = {
|
|
|
181
186
|
control_media_buy(data) {
|
|
182
187
|
return readCompactMediaBuyFields(data);
|
|
183
188
|
},
|
|
184
|
-
create_media_buy(data) {
|
|
185
|
-
const { mediaBuyId, status } = readMediaBuyFields(data);
|
|
189
|
+
create_media_buy(data, adcpVersion) {
|
|
190
|
+
const { mediaBuyId, status } = readMediaBuyFields(data, adcpVersion);
|
|
186
191
|
const extracted = {};
|
|
187
192
|
if (mediaBuyId) extracted.media_buy_id = mediaBuyId;
|
|
188
193
|
if (status) extracted.media_buy_status = status;
|
|
189
194
|
return extracted;
|
|
190
195
|
},
|
|
191
|
-
update_media_buy(data) {
|
|
192
|
-
const { mediaBuyId, status } = readMediaBuyFields(data);
|
|
196
|
+
update_media_buy(data, adcpVersion) {
|
|
197
|
+
const { mediaBuyId, status } = readMediaBuyFields(data, adcpVersion);
|
|
193
198
|
const extracted = {};
|
|
194
199
|
if (mediaBuyId) extracted.media_buy_id = mediaBuyId;
|
|
195
200
|
if (status) extracted.media_buy_status = status;
|
|
@@ -381,11 +386,11 @@ const CONTEXT_EXTRACTORS = {
|
|
|
381
386
|
return extracted;
|
|
382
387
|
}
|
|
383
388
|
};
|
|
384
|
-
function extractContext(taskName, data) {
|
|
389
|
+
function extractContext(taskName, data, adcpVersion) {
|
|
385
390
|
const extractor = CONTEXT_EXTRACTORS[taskName];
|
|
386
391
|
if (!extractor) return {};
|
|
387
392
|
try {
|
|
388
|
-
return extractor(data);
|
|
393
|
+
return extractor(data, adcpVersion);
|
|
389
394
|
} catch {
|
|
390
395
|
return {};
|
|
391
396
|
}
|
|
@@ -482,8 +487,8 @@ function applyContextOutputs(data, outputs) {
|
|
|
482
487
|
}
|
|
483
488
|
return result;
|
|
484
489
|
}
|
|
485
|
-
function extractContextWithProvenance(taskName, data, stepId) {
|
|
486
|
-
const values = extractContext(taskName, data);
|
|
490
|
+
function extractContextWithProvenance(taskName, data, stepId, adcpVersion) {
|
|
491
|
+
const values = extractContext(taskName, data, adcpVersion);
|
|
487
492
|
const clearGroups = (() => {
|
|
488
493
|
const response = asRecord(data);
|
|
489
494
|
switch (taskName) {
|
|
@@ -26,14 +26,19 @@ function asRecord(value) {
|
|
|
26
26
|
function readMediaBuyStatus(record) {
|
|
27
27
|
return getAuthoritativeMediaBuyStatus(record);
|
|
28
28
|
}
|
|
29
|
-
function readMediaBuyFields(data) {
|
|
29
|
+
function readMediaBuyFields(data, adcpVersion) {
|
|
30
30
|
const outer = asRecord(data);
|
|
31
31
|
const nested = asRecord(outer?.media_buy);
|
|
32
32
|
return {
|
|
33
33
|
mediaBuyId: nested?.media_buy_id ?? outer?.media_buy_id,
|
|
34
|
-
status: readMediaBuyStatus(nested) ?? readMediaBuyStatus(outer)
|
|
34
|
+
status: readMediaBuyStatus(nested) ?? readMediaBuyStatus(withRequestedVersion(outer, adcpVersion))
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
+
function withRequestedVersion(record, adcpVersion) {
|
|
38
|
+
if (!record || !adcpVersion) return record;
|
|
39
|
+
if (typeof record.adcp_version === "string" || typeof record.adcp_major_version === "number") return record;
|
|
40
|
+
return { ...record, adcp_version: adcpVersion };
|
|
41
|
+
}
|
|
37
42
|
function readProposalFields(proposal) {
|
|
38
43
|
if (!proposal) return {};
|
|
39
44
|
const extracted = {};
|
|
@@ -148,15 +153,15 @@ const CONTEXT_EXTRACTORS = {
|
|
|
148
153
|
control_media_buy(data) {
|
|
149
154
|
return readCompactMediaBuyFields(data);
|
|
150
155
|
},
|
|
151
|
-
create_media_buy(data) {
|
|
152
|
-
const { mediaBuyId, status } = readMediaBuyFields(data);
|
|
156
|
+
create_media_buy(data, adcpVersion) {
|
|
157
|
+
const { mediaBuyId, status } = readMediaBuyFields(data, adcpVersion);
|
|
153
158
|
const extracted = {};
|
|
154
159
|
if (mediaBuyId) extracted.media_buy_id = mediaBuyId;
|
|
155
160
|
if (status) extracted.media_buy_status = status;
|
|
156
161
|
return extracted;
|
|
157
162
|
},
|
|
158
|
-
update_media_buy(data) {
|
|
159
|
-
const { mediaBuyId, status } = readMediaBuyFields(data);
|
|
163
|
+
update_media_buy(data, adcpVersion) {
|
|
164
|
+
const { mediaBuyId, status } = readMediaBuyFields(data, adcpVersion);
|
|
160
165
|
const extracted = {};
|
|
161
166
|
if (mediaBuyId) extracted.media_buy_id = mediaBuyId;
|
|
162
167
|
if (status) extracted.media_buy_status = status;
|
|
@@ -348,11 +353,11 @@ const CONTEXT_EXTRACTORS = {
|
|
|
348
353
|
return extracted;
|
|
349
354
|
}
|
|
350
355
|
};
|
|
351
|
-
function extractContext(taskName, data) {
|
|
356
|
+
function extractContext(taskName, data, adcpVersion) {
|
|
352
357
|
const extractor = CONTEXT_EXTRACTORS[taskName];
|
|
353
358
|
if (!extractor) return {};
|
|
354
359
|
try {
|
|
355
|
-
return extractor(data);
|
|
360
|
+
return extractor(data, adcpVersion);
|
|
356
361
|
} catch {
|
|
357
362
|
return {};
|
|
358
363
|
}
|
|
@@ -449,8 +454,8 @@ function applyContextOutputs(data, outputs) {
|
|
|
449
454
|
}
|
|
450
455
|
return result;
|
|
451
456
|
}
|
|
452
|
-
function extractContextWithProvenance(taskName, data, stepId) {
|
|
453
|
-
const values = extractContext(taskName, data);
|
|
457
|
+
function extractContextWithProvenance(taskName, data, stepId, adcpVersion) {
|
|
458
|
+
const values = extractContext(taskName, data, adcpVersion);
|
|
454
459
|
const clearGroups = (() => {
|
|
455
460
|
const response = asRecord(data);
|
|
456
461
|
switch (taskName) {
|