deepline 0.2.73 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +75 -4
  2. package/dist/bundling-sources/sdk/src/compat.ts +4 -0
  3. package/dist/bundling-sources/sdk/src/play.ts +9 -0
  4. package/dist/bundling-sources/sdk/src/release.ts +12 -1
  5. package/dist/bundling-sources/sdk/src/types.ts +7 -0
  6. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +159 -32
  7. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +3 -0
  8. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -0
  9. package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +32 -7
  10. package/dist/bundling-sources/shared_libs/play-runtime/tool-response-contract.ts +89 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/tool-result-types.ts +29 -3
  12. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +203 -16
  13. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +3 -0
  14. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +6 -3
  15. package/dist/bundling-sources/shared_libs/plays/contracts.ts +14 -0
  16. package/dist/cli/index.js +83 -9
  17. package/dist/cli/index.mjs +83 -9
  18. package/dist/{compiler-manifest-DFBtSjB2.d.mts → compiler-manifest-BX85pKXW.d.mts} +11 -4
  19. package/dist/{compiler-manifest-DFBtSjB2.d.ts → compiler-manifest-BX85pKXW.d.ts} +11 -4
  20. package/dist/index.d.mts +14 -3
  21. package/dist/index.d.ts +14 -3
  22. package/dist/index.js +85 -4
  23. package/dist/index.mjs +85 -4
  24. package/dist/install-integrity.json +3 -2
  25. package/dist/plays/bundle-play-file.d.mts +12 -2
  26. package/dist/plays/bundle-play-file.d.ts +12 -2
  27. package/dist/plays/bundle-play-file.mjs +7 -2
  28. package/package.json +1 -1
@@ -30,8 +30,10 @@ export type SecretAuth = PlaySecretAuth &
30
30
  }
31
31
  );
32
32
 
33
+ export type SecretAuthInput = SecretAuth | readonly SecretAuth[];
34
+
33
35
  export type SecretAwareRequestInit = PlaySecretAwareRequestInit & {
34
- auth?: SecretAuth;
36
+ auth?: SecretAuthInput;
35
37
  };
36
38
 
37
39
  function isRecord(value: unknown): value is Record<string | symbol, unknown> {
@@ -46,6 +48,22 @@ export function isSecretAuth(value: unknown): value is SecretAuth {
46
48
  return isRecord(value) && value[SECRET_AUTH_BRAND] === true;
47
49
  }
48
50
 
51
+ export function isSecretAuthInput(value: unknown): value is SecretAuthInput {
52
+ return (
53
+ isSecretAuth(value) ||
54
+ (Array.isArray(value) &&
55
+ value.length > 0 &&
56
+ value.every((entry) => isSecretAuth(entry)))
57
+ );
58
+ }
59
+
60
+ export function secretAuthEntries(
61
+ auth: SecretAuthInput | undefined,
62
+ ): readonly SecretAuth[] {
63
+ if (!auth) return [];
64
+ return isSecretAuth(auth) ? [auth] : auth;
65
+ }
66
+
49
67
  export function valueContainsSecret(value: unknown): boolean {
50
68
  const pending: unknown[] = [value];
51
69
  const seen = new WeakSet<object>();
@@ -107,17 +125,24 @@ export function createHeaderSecretAuth(
107
125
  }
108
126
 
109
127
  export function secretAuthHeaderMarkers(
110
- auth: SecretAuth | undefined,
128
+ auth: SecretAuthInput | undefined,
111
129
  ): Record<string, string> {
112
- if (!auth) return {};
113
- if (auth.kind === 'bearer') {
114
- return { authorization: `[secret:${auth.secret.name}]` };
130
+ const markers: Record<string, string> = {};
131
+ for (const entry of secretAuthEntries(auth)) {
132
+ const header =
133
+ entry.kind === 'bearer' ? 'authorization' : entry.header.toLowerCase();
134
+ if (markers[header] !== undefined) {
135
+ throw new Error(
136
+ `ctx.fetch cannot attach more than one secret to the ${header} header.`,
137
+ );
138
+ }
139
+ markers[header] = `[secret:${entry.secret.name}]`;
115
140
  }
116
- return { [auth.header.toLowerCase()]: `[secret:${auth.secret.name}]` };
141
+ return markers;
117
142
  }
118
143
 
119
144
  export function assertSecretAuthUsesTls(
120
- auth: SecretAuth | undefined,
145
+ auth: SecretAuthInput | undefined,
121
146
  input: string | URL,
122
147
  sink: string,
123
148
  ): void {
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Public tool-response contracts shared by the API, SDK, Play bundler, and
3
+ * runtime. A response contract is transport behavior, never Play authoring.
4
+ */
5
+ export const V2_TOOL_RESPONSE_CONTRACT = 'v2-tool-response' as const;
6
+ export const RAW_V2_TOOL_RESPONSE_CONTRACT = 'raw-v2' as const;
7
+
8
+ export type ToolResponseContract =
9
+ | typeof V2_TOOL_RESPONSE_CONTRACT
10
+ | typeof RAW_V2_TOOL_RESPONSE_CONTRACT;
11
+
12
+ export type ToolResponseView = 'data' | 'rawV2';
13
+
14
+ export function isToolResponseContract(
15
+ value: unknown,
16
+ ): value is ToolResponseContract {
17
+ return (
18
+ value === V2_TOOL_RESPONSE_CONTRACT ||
19
+ value === RAW_V2_TOOL_RESPONSE_CONTRACT
20
+ );
21
+ }
22
+
23
+ export class UnsupportedToolResponseContractError extends Error {
24
+ constructor(value: unknown) {
25
+ super(
26
+ `Unsupported tool response contract ${String(value)}. Supported contracts: ${V2_TOOL_RESPONSE_CONTRACT}, ${RAW_V2_TOOL_RESPONSE_CONTRACT}.`,
27
+ );
28
+ this.name = 'UnsupportedToolResponseContractError';
29
+ }
30
+ }
31
+
32
+ /** Missing artifact compatibility predates canonical bodies and stays V2. */
33
+ export function normalizeToolResponseContract(
34
+ value: unknown,
35
+ ): ToolResponseContract {
36
+ if (value == null) return V2_TOOL_RESPONSE_CONTRACT;
37
+ if (isToolResponseContract(value)) return value;
38
+ throw new UnsupportedToolResponseContractError(value);
39
+ }
40
+
41
+ export function legacyRawFromToolResponseRawV2(
42
+ rawV2: unknown,
43
+ view: ToolResponseView,
44
+ responseMeta?: Record<string, unknown>,
45
+ ): unknown {
46
+ const legacyRaw =
47
+ view === 'data' &&
48
+ rawV2 &&
49
+ typeof rawV2 === 'object' &&
50
+ !Array.isArray(rawV2)
51
+ ? (rawV2 as Record<string, unknown>).data
52
+ : rawV2;
53
+ // Before raw-v2, an async launch without a data envelope exposed
54
+ // Deepline's billing summary at `toolResponse.raw.deepline_billing`.
55
+ // The canonical response keeps it separate from provider data, so reattach
56
+ // it only to this derived legacy view.
57
+ const deeplineBilling = responseMeta?.deepline_billing;
58
+ if (
59
+ view === 'rawV2' &&
60
+ deeplineBilling !== undefined &&
61
+ legacyRaw &&
62
+ typeof legacyRaw === 'object' &&
63
+ !Array.isArray(legacyRaw)
64
+ ) {
65
+ return {
66
+ ...(legacyRaw as Record<string, unknown>),
67
+ deepline_billing: deeplineBilling,
68
+ };
69
+ }
70
+ return legacyRaw;
71
+ }
72
+
73
+ export function providerMetaFromToolResponseRawV2(
74
+ rawV2: unknown,
75
+ view: ToolResponseView,
76
+ ): Record<string, unknown> | undefined {
77
+ if (
78
+ view !== 'data' ||
79
+ !rawV2 ||
80
+ typeof rawV2 !== 'object' ||
81
+ Array.isArray(rawV2)
82
+ ) {
83
+ return undefined;
84
+ }
85
+ const meta = (rawV2 as Record<string, unknown>).meta;
86
+ return meta && typeof meta === 'object' && !Array.isArray(meta)
87
+ ? (meta as Record<string, unknown>)
88
+ : undefined;
89
+ }
@@ -75,7 +75,7 @@ export type ToolResultEnvelope<
75
75
  meta?: TMeta;
76
76
  };
77
77
 
78
- export type SerializedToolExecuteResult = {
78
+ export type SerializedToolExecuteResultV1 = {
79
79
  __kind: 'deepline.tool_execute_result.v1';
80
80
  status: string;
81
81
  job_id?: string;
@@ -98,11 +98,36 @@ export type SerializedToolExecuteResult = {
98
98
  execution: ToolResultExecutionMetadata;
99
99
  };
100
100
 
101
+ /**
102
+ * Canonical receipt form. Provider data is stored once as `rawV2`; the legacy
103
+ * raw/meta view is recreated from the payload-free projection descriptor.
104
+ */
105
+ export type SerializedToolExecuteResultV2 = Omit<
106
+ SerializedToolExecuteResultV1,
107
+ '__kind' | 'toolResponse'
108
+ > & {
109
+ __kind: 'deepline.tool_execute_result.v2';
110
+ toolResponse: {
111
+ rawV2: unknown;
112
+ view: 'data' | 'rawV2';
113
+ /** Deepline-owned additions not already represented in `rawV2.meta`. */
114
+ responseMeta?: Record<string, unknown>;
115
+ };
116
+ };
117
+
118
+ export type SerializedToolExecuteResult =
119
+ | SerializedToolExecuteResultV1
120
+ | SerializedToolExecuteResultV2;
121
+
101
122
  export type ToolResponseEnvelope<
102
123
  TData = unknown,
103
124
  TMeta = Record<string, unknown>,
104
125
  > = {
105
126
  raw: TData;
127
+ /** Complete parsed and scrubbed provider response, materialized from raw-v2. */
128
+ rawV2?: unknown;
129
+ /** Durable descriptor for deriving the legacy raw view from `rawV2`. */
130
+ view?: 'data' | 'rawV2';
106
131
  meta?: TMeta;
107
132
  };
108
133
 
@@ -156,8 +181,9 @@ export type ToolExecuteResultAccessors<
156
181
  * Canonical result returned by Deepline tool execution.
157
182
  *
158
183
  * The top-level object is Deepline-owned execution metadata and semantic
159
- * extraction state. Raw tool/provider data lives under `toolResponse.raw`;
160
- * response metadata lives under `toolResponse.meta`. Semantic single-value
184
+ * extraction state. The canonical provider response lives under
185
+ * `toolResponse.rawV2`; `toolResponse.raw` remains the legacy compatibility
186
+ * projection. Response metadata lives under `toolResponse.meta`. Semantic single-value
161
187
  * getters live under `extractedValues.<name>.get()`, and list getters live
162
188
  * under `extractedLists.<name>.get()`.
163
189
  *
@@ -49,10 +49,18 @@ import {
49
49
  } from '../plays/dataset';
50
50
  import { normalizeTableNamespace, sha256Hex } from '../plays/row-identity';
51
51
  import { listNameFromDeclaredPath } from './tool-result-paths';
52
+ import {
53
+ legacyRawFromToolResponseRawV2,
54
+ providerMetaFromToolResponseRawV2,
55
+ type ToolResponseView,
56
+ } from './tool-response-contract';
52
57
 
53
58
  type PathSegment = string | number | '*';
54
59
 
55
- const SERIALIZED_TOOL_EXECUTE_RESULT_KIND = 'deepline.tool_execute_result.v1';
60
+ const SERIALIZED_TOOL_EXECUTE_RESULT_V1_KIND =
61
+ 'deepline.tool_execute_result.v1';
62
+ const SERIALIZED_TOOL_EXECUTE_RESULT_V2_KIND =
63
+ 'deepline.tool_execute_result.v2';
56
64
  const SERIALIZED_TOOL_RESULT_LIST_PREVIEW_LIMIT = 5;
57
65
  const LIVE_TOOL_RESULT_LIST_DATASET_REGISTRY_LIMIT = 256;
58
66
  const SERIALIZED_TOOL_LIST_ROWS = Symbol('deepline.serialized_tool_list_rows');
@@ -123,6 +131,8 @@ function isRecord(value: unknown): value is Record<string, unknown> {
123
131
 
124
132
  type V2ToolExecuteOutput = {
125
133
  raw: unknown;
134
+ rawV2?: unknown;
135
+ view?: ToolResponseView;
126
136
  meta?: Record<string, unknown>;
127
137
  };
128
138
 
@@ -131,12 +141,35 @@ function parseV2ToolExecuteOutput(
131
141
  ): V2ToolExecuteOutput | null {
132
142
  const toolResponse = data.toolResponse;
133
143
  if (isRecord(toolResponse)) {
134
- const meta = isRecord(toolResponse.meta) ? toolResponse.meta : undefined;
144
+ const rawV2 = Object.prototype.hasOwnProperty.call(toolResponse, 'rawV2')
145
+ ? toolResponse.rawV2
146
+ : undefined;
147
+ const view =
148
+ toolResponse.view === 'data' || toolResponse.view === 'rawV2'
149
+ ? toolResponse.view
150
+ : undefined;
151
+ const providerMeta = providerMetaFromToolResponseRawV2(
152
+ rawV2,
153
+ view ?? 'rawV2',
154
+ );
155
+ const responseMeta = isRecord(toolResponse.responseMeta)
156
+ ? toolResponse.responseMeta
157
+ : undefined;
158
+ const meta = {
159
+ ...(isRecord(toolResponse.meta) ? toolResponse.meta : {}),
160
+ ...(providerMeta ?? {}),
161
+ ...(responseMeta ?? {}),
162
+ };
163
+ const raw = Object.prototype.hasOwnProperty.call(toolResponse, 'raw')
164
+ ? toolResponse.raw
165
+ : rawV2 === undefined
166
+ ? null
167
+ : legacyRawFromToolResponseRawV2(rawV2, view ?? 'rawV2', responseMeta);
135
168
  return {
136
- raw: Object.prototype.hasOwnProperty.call(toolResponse, 'raw')
137
- ? toolResponse.raw
138
- : null,
139
- ...(meta ? { meta } : {}),
169
+ raw,
170
+ ...(rawV2 !== undefined ? { rawV2 } : {}),
171
+ ...(view ? { view } : {}),
172
+ ...(Object.keys(meta).length > 0 ? { meta } : {}),
140
173
  };
141
174
  }
142
175
  return null;
@@ -181,7 +214,10 @@ export type ParsedToolExecuteResponse = {
181
214
  meta?: Record<string, unknown>;
182
215
  toolResponse?: {
183
216
  raw?: unknown;
217
+ rawV2?: unknown;
218
+ view?: 'data' | 'rawV2';
184
219
  meta?: Record<string, unknown>;
220
+ responseMeta?: Record<string, unknown>;
185
221
  };
186
222
  /** Legacy `{ data, meta }` envelope consumed by createToolExecuteResult. */
187
223
  result: unknown;
@@ -204,9 +240,17 @@ export function parseToolExecuteResponse(
204
240
  status,
205
241
  jobId: typeof body.job_id === 'string' ? body.job_id : undefined,
206
242
  meta: isRecord(body.meta) ? body.meta : undefined,
207
- toolResponse: isRecord(body.toolResponse)
208
- ? (body.toolResponse as ParsedToolExecuteResponse['toolResponse'])
209
- : undefined,
243
+ toolResponse: (() => {
244
+ const output = parseV2ToolExecuteOutput(body);
245
+ return output
246
+ ? {
247
+ raw: output.raw,
248
+ ...(output.rawV2 !== undefined ? { rawV2: output.rawV2 } : {}),
249
+ ...(output.view ? { view: output.view } : {}),
250
+ ...(output.meta ? { meta: output.meta } : {}),
251
+ }
252
+ : undefined;
253
+ })(),
210
254
  result,
211
255
  metadata: parseExecuteToolMetadata(toolId, body),
212
256
  };
@@ -1135,11 +1179,20 @@ export function createToolExecuteResult<TResult = unknown>(input: {
1135
1179
  metadata: ToolResultMetadataInput;
1136
1180
  execution: ToolResultExecutionMetadata;
1137
1181
  meta?: Record<string, unknown>;
1182
+ response?: {
1183
+ rawV2?: unknown;
1184
+ view?: 'data' | 'rawV2';
1185
+ meta?: Record<string, unknown>;
1186
+ };
1138
1187
  }): ToolExecuteResult<TResult> {
1139
1188
  const result = toResultEnvelope(input.result);
1140
1189
  const resultRoot = {
1141
1190
  toolResponse: {
1142
1191
  raw: result.data,
1192
+ ...(input.response && 'rawV2' in input.response
1193
+ ? { rawV2: input.response.rawV2 }
1194
+ : {}),
1195
+ ...(input.response?.view ? { view: input.response.view } : {}),
1143
1196
  ...(result.meta ? { meta: result.meta } : {}),
1144
1197
  },
1145
1198
  };
@@ -1165,6 +1218,10 @@ export function createToolExecuteResult<TResult = unknown>(input: {
1165
1218
  };
1166
1219
  const toolResponse = {
1167
1220
  raw: result.data,
1221
+ ...(input.response && 'rawV2' in input.response
1222
+ ? { rawV2: input.response.rawV2 }
1223
+ : {}),
1224
+ ...(input.response?.view ? { view: input.response.view } : {}),
1168
1225
  ...(result.meta ? { meta: result.meta } : {}),
1169
1226
  };
1170
1227
  const extractedValues = buildExtractedAccessors(targets);
@@ -1634,6 +1691,17 @@ function applySerializedListDatasets(
1634
1691
  listDatasets,
1635
1692
  listRows,
1636
1693
  });
1694
+ if (Object.prototype.hasOwnProperty.call(result.toolResponse, 'rawV2')) {
1695
+ const view = result.toolResponse.view ?? 'rawV2';
1696
+ if (view === 'data' && isRecord(result.toolResponse.rawV2)) {
1697
+ result.toolResponse.rawV2 = {
1698
+ ...result.toolResponse.rawV2,
1699
+ data: result.toolResponse.raw,
1700
+ };
1701
+ } else {
1702
+ result.toolResponse.rawV2 = result.toolResponse.raw;
1703
+ }
1704
+ }
1637
1705
  Object.defineProperty(result, SERIALIZED_TOOL_LIST_ROWS, {
1638
1706
  value: listRows,
1639
1707
  enumerable: false,
@@ -1695,6 +1763,47 @@ function metadataInputFromToolExecuteResult(
1695
1763
  };
1696
1764
  }
1697
1765
 
1766
+ function sameJsonValue(left: unknown, right: unknown): boolean {
1767
+ if (left === right) return true;
1768
+ try {
1769
+ return JSON.stringify(left) === JSON.stringify(right);
1770
+ } catch {
1771
+ return false;
1772
+ }
1773
+ }
1774
+
1775
+ function responseMetaOutsideRawV2(input: {
1776
+ rawV2: unknown;
1777
+ view: 'data' | 'rawV2';
1778
+ meta: Record<string, unknown> | undefined;
1779
+ }): Record<string, unknown> | undefined {
1780
+ if (!input.meta) return undefined;
1781
+ const providerMeta =
1782
+ input.view === 'data' && isRecord(input.rawV2) && isRecord(input.rawV2.meta)
1783
+ ? input.rawV2.meta
1784
+ : undefined;
1785
+ if (!providerMeta) return input.meta;
1786
+ const responseMeta = Object.fromEntries(
1787
+ Object.entries(input.meta).filter(
1788
+ ([key, value]) =>
1789
+ !Object.prototype.hasOwnProperty.call(providerMeta, key) ||
1790
+ !sameJsonValue(providerMeta[key], value),
1791
+ ),
1792
+ );
1793
+ return Object.keys(responseMeta).length > 0 ? responseMeta : undefined;
1794
+ }
1795
+
1796
+ function rawV2WithSerializedRawPreview(input: {
1797
+ rawV2: unknown;
1798
+ view: 'data' | 'rawV2';
1799
+ raw: unknown;
1800
+ }): unknown {
1801
+ if (input.view === 'data' && isRecord(input.rawV2)) {
1802
+ return { ...input.rawV2, data: input.raw };
1803
+ }
1804
+ return input.raw;
1805
+ }
1806
+
1698
1807
  export function serializeToolExecuteResult(
1699
1808
  value: ToolExecuteResult,
1700
1809
  ): SerializedToolExecuteResult {
@@ -1706,17 +1815,54 @@ export function serializeToolExecuteResult(
1706
1815
  metadata,
1707
1816
  });
1708
1817
  const targetValues = serializedTargetValuesFromResult(value);
1818
+ const serializedRaw = serializedRawWithListPreviews({
1819
+ raw: value.toolResponse.raw,
1820
+ metadata,
1821
+ listDatasets,
1822
+ });
1823
+ if (Object.prototype.hasOwnProperty.call(value.toolResponse, 'rawV2')) {
1824
+ const view = value.toolResponse.view ?? 'rawV2';
1825
+ const rawV2 = rawV2WithSerializedRawPreview({
1826
+ rawV2: value.toolResponse.rawV2,
1827
+ view,
1828
+ raw:
1829
+ view === 'data'
1830
+ ? serializedRaw
1831
+ : serializedRawWithListPreviews({
1832
+ raw: value.toolResponse.rawV2,
1833
+ metadata,
1834
+ listDatasets,
1835
+ }),
1836
+ });
1837
+ const responseMeta = responseMetaOutsideRawV2({
1838
+ rawV2: value.toolResponse.rawV2,
1839
+ view,
1840
+ meta: value.toolResponse.meta,
1841
+ });
1842
+ return {
1843
+ __kind: SERIALIZED_TOOL_EXECUTE_RESULT_V2_KIND,
1844
+ status: value.status,
1845
+ ...(typeof value.job_id === 'string' ? { job_id: value.job_id } : {}),
1846
+ ...(isRecord(value.meta) ? { meta: value.meta } : {}),
1847
+ toolResponse: {
1848
+ rawV2,
1849
+ view,
1850
+ ...(responseMeta ? { responseMeta } : {}),
1851
+ },
1852
+ ...(listDatasets ? { listDatasets } : {}),
1853
+ ...(listRows ? { listRows } : {}),
1854
+ ...(targetValues ? { targetValues } : {}),
1855
+ metadata,
1856
+ execution: value._metadata.execution,
1857
+ };
1858
+ }
1709
1859
  return {
1710
- __kind: SERIALIZED_TOOL_EXECUTE_RESULT_KIND,
1860
+ __kind: SERIALIZED_TOOL_EXECUTE_RESULT_V1_KIND,
1711
1861
  status: value.status,
1712
1862
  ...(typeof value.job_id === 'string' ? { job_id: value.job_id } : {}),
1713
1863
  ...(isRecord(value.meta) ? { meta: value.meta } : {}),
1714
1864
  toolResponse: {
1715
- raw: serializedRawWithListPreviews({
1716
- raw: value.toolResponse.raw,
1717
- metadata,
1718
- listDatasets,
1719
- }),
1865
+ raw: serializedRaw,
1720
1866
  ...(value.toolResponse.meta ? { meta: value.toolResponse.meta } : {}),
1721
1867
  },
1722
1868
  ...(listDatasets ? { listDatasets } : {}),
@@ -1732,7 +1878,8 @@ export function isSerializedToolExecuteResult(
1732
1878
  ): value is SerializedToolExecuteResult {
1733
1879
  return (
1734
1880
  isRecord(value) &&
1735
- value.__kind === SERIALIZED_TOOL_EXECUTE_RESULT_KIND &&
1881
+ (value.__kind === SERIALIZED_TOOL_EXECUTE_RESULT_V1_KIND ||
1882
+ value.__kind === SERIALIZED_TOOL_EXECUTE_RESULT_V2_KIND) &&
1736
1883
  typeof value.status === 'string' &&
1737
1884
  isRecord(value.toolResponse) &&
1738
1885
  isRecord(value.metadata) &&
@@ -1743,6 +1890,46 @@ export function isSerializedToolExecuteResult(
1743
1890
  export function deserializeToolExecuteResult(
1744
1891
  value: SerializedToolExecuteResult,
1745
1892
  ): ToolExecuteResult {
1893
+ if (value.__kind === SERIALIZED_TOOL_EXECUTE_RESULT_V2_KIND) {
1894
+ const view = value.toolResponse.view;
1895
+ const rawV2 = value.toolResponse.rawV2;
1896
+ const providerMeta =
1897
+ view === 'data' && isRecord(rawV2) && isRecord(rawV2.meta)
1898
+ ? rawV2.meta
1899
+ : undefined;
1900
+ const meta = {
1901
+ ...(providerMeta ?? {}),
1902
+ ...(value.toolResponse.responseMeta ?? {}),
1903
+ };
1904
+ const raw = legacyRawFromToolResponseRawV2(
1905
+ rawV2,
1906
+ view,
1907
+ value.toolResponse.responseMeta,
1908
+ );
1909
+ return applySerializedListDatasets(
1910
+ applySerializedTargetValues(
1911
+ createToolExecuteResult({
1912
+ status: value.status,
1913
+ jobId: value.job_id,
1914
+ result: {
1915
+ data: raw,
1916
+ ...(Object.keys(meta).length > 0 ? { meta } : {}),
1917
+ },
1918
+ response: {
1919
+ rawV2,
1920
+ view,
1921
+ ...(Object.keys(meta).length > 0 ? { meta } : {}),
1922
+ },
1923
+ metadata: value.metadata,
1924
+ execution: value.execution,
1925
+ meta: value.meta,
1926
+ }),
1927
+ value.targetValues,
1928
+ ),
1929
+ value.listDatasets,
1930
+ value.listRows,
1931
+ );
1932
+ }
1746
1933
  return applySerializedListDatasets(
1747
1934
  applySerializedTargetValues(
1748
1935
  createToolExecuteResult({
@@ -1,4 +1,5 @@
1
1
  import type { ToolExecutionErrorSchemaVersion } from '../tool-execution-error';
2
+ import type { ToolResponseContract } from '../play-runtime/tool-response-contract';
2
3
  import type { PlayAuthoringContractEdition } from './authoring-contract';
3
4
 
4
5
  export type PlayPackageImport = {
@@ -28,6 +29,8 @@ export type PlayArtifactCompatibility = {
28
29
  toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
29
30
  /** Missing preserves edition 1 for artifacts created before authoring contracts were pinned. */
30
31
  authoringContractEdition?: PlayAuthoringContractEdition;
32
+ /** Missing preserves the raw-only V2 execute response contract. */
33
+ toolResponseContract?: ToolResponseContract;
31
34
  };
32
35
 
33
36
  /** The only executable Play artifact contract. */
@@ -410,6 +410,8 @@ export type PlaySecretAuth = {
410
410
  /** Header name, set only when `kind` is `header`. */
411
411
  readonly header?: string;
412
412
  };
413
+ /** One or more resolved authentication schemes for an outbound request. */
414
+ export type PlaySecretAuthInput = PlaySecretAuth | readonly PlaySecretAuth[];
413
415
  /**
414
416
  * The `init` accepted by `ctx.fetch`. Same shape as `RequestInit` plus `auth`.
415
417
  *
@@ -419,9 +421,9 @@ export type PlaySecretAwareRequestInit = Omit<RequestInit, 'headers'> & {
419
421
  /** Ordinary request headers, recorded in the durable receipt. Never interpolate a secret value here — use `auth`. */
420
422
  headers?: HeadersInit;
421
423
  /**
422
- * The single authenticated header for this request. One value, not a list: exactly one `ctx.secrets` auth attaches per `ctx.fetch`. An API wanting two credentialed headers at once Supabase with both `apikey` and `Authorization` cannot express both. Put the must-stay-secret credential in `auth`; pass a genuinely non-secret second value in `headers`. If both are secret, the request needs a server-side proxy holding one of them.
424
+ * One or more secret-backed authentication headers for this request. Pass a single `ctx.secrets` auth for the common case, or an array when an API requires multiple credentialed headers for example, Supabase with both `apikey` and `Authorization`. Every secret is resolved only while the request is attached, never stored in the durable receipt. Each auth entry must target a distinct header.
423
425
  */
424
- auth?: PlaySecretAuth;
426
+ auth?: PlaySecretAuthInput;
425
427
  };
426
428
  export type PlayLooseObject = { [key: string]: PlayLooseObject };
427
429
 
@@ -2464,6 +2466,7 @@ export const PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
2464
2466
  'declare const SECRET_HANDLE_BRAND: unique symbol;',
2465
2467
  'export type SecretHandle = { readonly [SECRET_HANDLE_BRAND]: never; readonly name: string; toString(): string; toJSON(): never };',
2466
2468
  "export type SecretAuth = { readonly kind: 'bearer' | 'header'; readonly secret: SecretHandle; readonly header?: string };",
2469
+ 'export type SecretAuthInput = SecretAuth | readonly SecretAuth[];',
2467
2470
  'export type PlayInputContract<TInput> = { readonly schema: Record<string, unknown>; readonly __inputType?: TInput };',
2468
2471
  'export type PlayReturnObject = Record<string, unknown> & { readonly _metadata?: never };',
2469
2472
  'export type CsvRenameMap = Record<string, string | readonly string[]>;',
@@ -2512,7 +2515,7 @@ export const PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
2512
2515
  ` customerDb: { query<TRow extends Record<string, unknown> = Record<string, unknown>>(statement: SqlQuery, options?: { maxRows?: ${cloudReferenceType('ctx.customerDb.query.options.maxRows')}; timeoutMs?: ${cloudReferenceType('ctx.customerDb.query.options.timeoutMs')} }): Promise<TRow[]> };`,
2513
2516
  ` tool<K extends string>(key: ${cloudReferenceType('ctx.tool.key')}, toolId: K, input: ${cloudReferenceType('ctx.tool.input')}, options?: { description?: ${cloudReferenceType('ctx.tool.options.description')} }): Promise<ToolExecutionOutput<K>>;`,
2514
2517
  ' step<T>(id: string, run: () => T | Promise<T>, options?: RuntimeStepOptions): Promise<T>;',
2515
- " fetch(key: string, url: string | URL, init?: RequestInit & { headers?: HeadersInit & { 'Idempotency-Key'?: string; 'X-Idempotency-Key'?: string }; auth?: SecretAuth }, options?: FetchOptions): Promise<PlayFetchResponse>;",
2518
+ " fetch(key: string, url: string | URL, init?: RequestInit & { headers?: HeadersInit & { 'Idempotency-Key'?: string; 'X-Idempotency-Key'?: string }; auth?: SecretAuthInput }, options?: FetchOptions): Promise<PlayFetchResponse>;",
2516
2519
  ' secrets: { get(name: string): SecretHandle; bearer(secret: SecretHandle): SecretAuth; header(header: string, secret: SecretHandle): SecretAuth };',
2517
2520
  ` runPlay<TOutput = unknown>(key: string, playRef: ${cloudReferenceType('ctx.runPlay.playRef')}, input: ${cloudReferenceType('ctx.runPlay.input')}, options: PlayCallOptions): Promise<TOutput>;`,
2518
2521
  ' log(message: string): void;',
@@ -10,6 +10,11 @@ import {
10
10
  type PlayAuthoringContractEdition,
11
11
  type AdmittedPlayAuthoringContract,
12
12
  } from './authoring-contract';
13
+ import {
14
+ normalizeToolResponseContract,
15
+ RAW_V2_TOOL_RESPONSE_CONTRACT,
16
+ type ToolResponseContract,
17
+ } from '../play-runtime/tool-response-contract';
13
18
 
14
19
  export type PlayContractSource = 'ad_hoc' | 'draft' | 'published';
15
20
 
@@ -39,12 +44,15 @@ export type PlayContractCompatibilitySnapshot = {
39
44
  toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
40
45
  /** Missing preserves edition 1 for artifacts stored before authoring contracts were pinned. */
41
46
  authoringContractEdition?: PlayAuthoringContractEdition;
47
+ /** Immutable execute-result transport selected when the artifact is built. */
48
+ toolResponseContract?: ToolResponseContract;
42
49
  };
43
50
 
44
51
  export type NormalizedPlayContractCompatibilitySnapshot =
45
52
  PlayContractCompatibilitySnapshot & {
46
53
  toolErrorSchemaVersion: ToolExecutionErrorSchemaVersion;
47
54
  authoringContractEdition: PlayAuthoringContractEdition;
55
+ toolResponseContract: ToolResponseContract;
48
56
  };
49
57
 
50
58
  export class UnsupportedPlayToolErrorSchemaVersionError extends Error {
@@ -94,6 +102,9 @@ export function normalizePlayContractCompatibility(
94
102
  return {
95
103
  ...compatibility,
96
104
  toolErrorSchemaVersion: TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
105
+ toolResponseContract: normalizeToolResponseContract(
106
+ compatibility.toolResponseContract,
107
+ ),
97
108
  authoringContractEdition: normalizePlayAuthoringContractEdition(
98
109
  compatibility.authoringContractEdition,
99
110
  ),
@@ -104,6 +115,7 @@ export function buildPlayContractCompatibility(input?: {
104
115
  runtimeBackend?: string | null;
105
116
  toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
106
117
  authoringContractEdition?: PlayAuthoringContractEdition;
118
+ toolResponseContract?: ToolResponseContract;
107
119
  }): PlayContractCompatibilitySnapshot {
108
120
  return {
109
121
  apiVersion: PLAY_PUBLIC_API_VERSION,
@@ -115,6 +127,8 @@ export function buildPlayContractCompatibility(input?: {
115
127
  input?.toolErrorSchemaVersion ?? TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
116
128
  authoringContractEdition:
117
129
  input?.authoringContractEdition ?? PLAY_AUTHORING_CONTRACT_EDITION,
130
+ toolResponseContract:
131
+ input?.toolResponseContract ?? RAW_V2_TOOL_RESPONSE_CONTRACT,
118
132
  };
119
133
  }
120
134