deepline 0.2.74 → 0.3.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.
Files changed (35) 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 +7 -0
  4. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +15 -1
  5. package/dist/bundling-sources/sdk/src/release.ts +12 -1
  6. package/dist/bundling-sources/sdk/src/types.ts +7 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +146 -29
  8. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +3 -0
  9. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +57 -1
  11. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +20 -19
  12. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +100 -25
  13. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +25 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +0 -9
  15. package/dist/bundling-sources/shared_libs/play-runtime/tool-response-contract.ts +89 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/tool-result-types.ts +29 -3
  17. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +203 -16
  18. package/dist/bundling-sources/shared_libs/play-runtime/transient-service-error.ts +6 -5
  19. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +3 -0
  20. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +1 -0
  21. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +5 -2
  22. package/dist/bundling-sources/shared_libs/plays/contracts.ts +14 -0
  23. package/dist/cli/index.js +123 -47
  24. package/dist/cli/index.mjs +86 -10
  25. package/dist/{compiler-manifest-DFuz9-0_.d.mts → compiler-manifest-BX85pKXW.d.mts} +7 -2
  26. package/dist/{compiler-manifest-DFuz9-0_.d.ts → compiler-manifest-BX85pKXW.d.ts} +7 -2
  27. package/dist/index.d.mts +14 -3
  28. package/dist/index.d.ts +14 -3
  29. package/dist/index.js +85 -4
  30. package/dist/index.mjs +85 -4
  31. package/dist/install-integrity.json +3 -2
  32. package/dist/plays/bundle-play-file.d.mts +12 -2
  33. package/dist/plays/bundle-play-file.d.ts +12 -2
  34. package/dist/plays/bundle-play-file.mjs +20 -4
  35. package/package.json +1 -1
@@ -99,12 +99,17 @@ import {
99
99
  TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
100
100
  } from '../../shared_libs/tool-execution-error.js';
101
101
  import { decodePlayRunPublicStatus } from '../../shared_libs/play-runtime/run-lifecycle-policy.js';
102
+ import {
103
+ legacyRawFromToolResponseRawV2,
104
+ providerMetaFromToolResponseRawV2,
105
+ RAW_V2_TOOL_RESPONSE_CONTRACT,
106
+ } from '../../shared_libs/play-runtime/tool-response-contract.js';
102
107
 
103
108
  const TERMINAL_PLAY_STATUSES = new Set(['completed', 'failed', 'cancelled']);
104
109
  const INCLUDE_TOOL_METADATA_HEADER = 'x-deepline-include-tool-metadata';
105
110
  const EXECUTE_RESPONSE_CONTRACT_HEADER = 'x-deepline-execute-response-contract';
106
111
  const EXECUTE_RESPONSE_INTENT_HEADER = 'x-deepline-execute-response-intent';
107
- const V2_EXECUTE_RESPONSE_CONTRACT = 'v2-tool-response';
112
+ const RAW_V2_EXECUTE_RESPONSE_CONTRACT = RAW_V2_TOOL_RESPONSE_CONTRACT;
108
113
  const COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1_000];
109
114
  const REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY = 3;
110
115
  const REGISTER_PLAY_ARTIFACTS_MAX_BATCH_COUNT = 3;
@@ -452,7 +457,8 @@ function resolveToolExecuteTimeoutMs(
452
457
  /**
453
458
  * Standard provider/tool execution envelope returned by low-level SDK calls.
454
459
  *
455
- * `toolResponse.raw` contains the provider result. `extractedValues` and
460
+ * `toolResponse.rawV2` contains the complete scrubbed provider response;
461
+ * `toolResponse.raw` is derived locally as the legacy provider-result projection. `extractedValues` and
456
462
  * `extractedLists` contain Deepline-normalized getters when the tool exposes
457
463
  * them. Billing fields are Deepline-facing and must not expose provider spend.
458
464
  */
@@ -462,7 +468,10 @@ export type ToolExecution<TData = unknown, TMeta = Record<string, unknown>> = {
462
468
  meta?: Record<string, unknown>;
463
469
  toolResponse: {
464
470
  raw: TData;
471
+ rawV2?: unknown;
472
+ view?: 'data' | 'rawV2';
465
473
  meta?: TMeta;
474
+ responseMeta?: TMeta;
466
475
  };
467
476
  extractedLists?: Record<string, unknown>;
468
477
  extractedValues?: Record<string, unknown>;
@@ -1147,6 +1156,67 @@ function isRecord(value: unknown): value is Record<string, unknown> {
1147
1156
  return Boolean(value && typeof value === 'object' && !Array.isArray(value));
1148
1157
  }
1149
1158
 
1159
+ /** Materialize raw-v2's rawV2-only wire response into the stable SDK result view. */
1160
+ function materializeToolExecutionResponse<
1161
+ TData = unknown,
1162
+ TMeta = Record<string, unknown>,
1163
+ >(response: ToolExecution<TData, TMeta>): ToolExecution<TData, TMeta> {
1164
+ const toolResponse = response.toolResponse;
1165
+ // An older V2 backend does not understand raw-v2 yet and therefore falls
1166
+ // through to the historical `{ result: { data, meta? } }` response. New SDK
1167
+ // clients must keep working during that server rollout window.
1168
+ if (!toolResponse && isRecord(response.result)) {
1169
+ const legacyResult = response.result;
1170
+ if (Object.prototype.hasOwnProperty.call(legacyResult, 'data')) {
1171
+ const legacyMeta = isRecord(legacyResult.meta)
1172
+ ? (legacyResult.meta as TMeta)
1173
+ : undefined;
1174
+ return {
1175
+ ...response,
1176
+ toolResponse: {
1177
+ raw: legacyResult.data as TData,
1178
+ ...(legacyMeta ? { meta: legacyMeta } : {}),
1179
+ },
1180
+ };
1181
+ }
1182
+ }
1183
+ if (
1184
+ !toolResponse ||
1185
+ Object.prototype.hasOwnProperty.call(toolResponse, 'raw')
1186
+ ) {
1187
+ return response;
1188
+ }
1189
+ const rawV2 = toolResponse.rawV2;
1190
+ const view = toolResponse.view;
1191
+ const providerMeta = providerMetaFromToolResponseRawV2(
1192
+ rawV2,
1193
+ view ?? 'rawV2',
1194
+ ) as TMeta | undefined;
1195
+ const responseMeta = isRecord(toolResponse.responseMeta)
1196
+ ? (toolResponse.responseMeta as TMeta)
1197
+ : undefined;
1198
+ return {
1199
+ ...response,
1200
+ toolResponse: {
1201
+ ...toolResponse,
1202
+ raw: legacyRawFromToolResponseRawV2(
1203
+ rawV2,
1204
+ view ?? 'rawV2',
1205
+ responseMeta as Record<string, unknown> | undefined,
1206
+ ) as TData,
1207
+ ...(toolResponse.meta || providerMeta || responseMeta
1208
+ ? {
1209
+ meta: {
1210
+ ...(toolResponse.meta ?? {}),
1211
+ ...(providerMeta ?? {}),
1212
+ ...(responseMeta ?? {}),
1213
+ } as TMeta,
1214
+ }
1215
+ : {}),
1216
+ },
1217
+ };
1218
+ }
1219
+
1150
1220
  function isPrebuiltPlayDescription(
1151
1221
  play: Pick<PlayDescription, 'origin' | 'ownerType'>,
1152
1222
  ): boolean {
@@ -2019,7 +2089,7 @@ export class DeeplineClient {
2019
2089
  options?: ExecuteToolRawOptions,
2020
2090
  ): Promise<ToolExecution<TData, TMeta>> {
2021
2091
  const headers = {
2022
- [EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
2092
+ [EXECUTE_RESPONSE_CONTRACT_HEADER]: RAW_V2_EXECUTE_RESPONSE_CONTRACT,
2023
2093
  [TOOL_EXECUTION_ERROR_SCHEMA_HEADER]: String(
2024
2094
  TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
2025
2095
  ),
@@ -2028,7 +2098,7 @@ export class DeeplineClient {
2028
2098
  : {}),
2029
2099
  [EXECUTE_RESPONSE_INTENT_HEADER]: options?.responseIntent ?? 'raw',
2030
2100
  };
2031
- return this.http.post<ToolExecution<TData, TMeta>>(
2101
+ const response = await this.http.post<ToolExecution<TData, TMeta>>(
2032
2102
  `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
2033
2103
  {
2034
2104
  payload: input,
@@ -2042,6 +2112,7 @@ export class DeeplineClient {
2042
2112
  toolId,
2043
2113
  },
2044
2114
  );
2115
+ return materializeToolExecutionResponse(response);
2045
2116
  }
2046
2117
 
2047
2118
  /**
@@ -22,6 +22,10 @@ export type SdkCompatibilityResponse = {
22
22
  update_required: boolean;
23
23
  message: string;
24
24
  update_command: string;
25
+ update_summary?: {
26
+ version: string;
27
+ summary: string;
28
+ };
25
29
  command?: string | null;
26
30
  /**
27
31
  * Present only when the queried command postdates this CLI. Advisory: the
@@ -1471,6 +1471,8 @@ function toolExecutionEnvelopeToResult(
1471
1471
  },
1472
1472
  ): ToolExecuteResult {
1473
1473
  const raw = response.toolResponse?.raw ?? null;
1474
+ const rawV2 = response.toolResponse?.rawV2;
1475
+ const view = response.toolResponse?.view;
1474
1476
  const meta = response.toolResponse?.meta;
1475
1477
  const metadata = isRecord(response._metadata)
1476
1478
  ? response._metadata.tool
@@ -1487,6 +1489,11 @@ function toolExecutionEnvelopeToResult(
1487
1489
  data: raw,
1488
1490
  ...(isRecord(meta) ? { meta } : {}),
1489
1491
  },
1492
+ response: {
1493
+ ...(rawV2 !== undefined ? { rawV2 } : {}),
1494
+ ...(view === 'data' || view === 'rawV2' ? { view } : {}),
1495
+ ...(isRecord(meta) ? { meta } : {}),
1496
+ },
1490
1497
  metadata: {
1491
1498
  toolId:
1492
1499
  typeof toolMetadata.toolId === 'string'
@@ -2,6 +2,7 @@ import { tmpdir } from 'node:os';
2
2
  import { dirname, join, resolve } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { existsSync } from 'node:fs';
5
+ import { realpath } from 'node:fs/promises';
5
6
  import {
6
7
  bundlePlayFile as bundlePlayFileCore,
7
8
  type BundlePlayFileOptions,
@@ -145,10 +146,23 @@ export async function bundlePlayFile(
145
146
  filePath: string,
146
147
  options: BundlePlayFileOptions = {},
147
148
  ): Promise<BundledPlayFileResult> {
149
+ // The SDK sends this graph to a remote checker/runtime. Its file identities
150
+ // therefore must describe the authoring workspace, rather than the local
151
+ // machine paths used while building it. This is especially important on
152
+ // Windows: a raw `C:\\...` key cannot be reconciled beneath `/var/task`.
153
+ // Match the bundler's physical-path normalization. On macOS, for example,
154
+ // os.tmpdir() can report /var while the source graph resolves /private/var.
155
+ const localWorkspaceRoot = dirname(resolve(filePath));
156
+ const sourceIdentityRoot = await realpath(localWorkspaceRoot).catch(
157
+ () => localWorkspaceRoot,
158
+ );
148
159
  const result = await bundlePlayFileCore(filePath, {
149
160
  target: options.target ?? defaultPlayBundleTarget(),
150
161
  exportName: options.exportName,
151
- adapter: createSdkPlayBundlingAdapter(),
162
+ adapter: {
163
+ ...createSdkPlayBundlingAdapter(),
164
+ sourceIdentityRoot,
165
+ },
152
166
  });
153
167
  if (result.success)
154
168
  validatePlaySourceFilesHaveNoInlineSecrets(result.sourceFiles);
@@ -136,6 +136,12 @@ export type SdkRelease = {
136
136
  * publish time (auto-bump); edit by hand only for minor/major releases.
137
137
  */
138
138
  version: string;
139
+ /**
140
+ * One concise, agent-readable explanation shown while this release is an
141
+ * available update. Keep it actionable; the compatibility route includes it
142
+ * in its existing update message so older installed CLIs can print it too.
143
+ */
144
+ updateSummary?: string;
139
145
  /** Named compatibility policies. This is the only authored contract policy. */
140
146
  contracts: DeeplineContractPolicy;
141
147
  /** Public support policy reported by `/api/v2/sdk/compat`. */
@@ -183,7 +189,12 @@ export const SDK_RELEASE = {
183
189
  // 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
184
190
  // exposed storage-dependent synchronous access. This deliberate minor
185
191
  // release keeps lazy paging semantics independent of row residency.
186
- version: '0.2.74',
192
+ // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
193
+ // available at toolResponse.rawV2 while toolResponse.raw and all declared
194
+ // getters keep their established compatibility behavior.
195
+ version: '0.3.1',
196
+ updateSummary:
197
+ 'New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.',
187
198
  contracts: {
188
199
  api: {
189
200
  name: 'sdk-http-api',
@@ -212,12 +212,19 @@ export interface ToolDefinition {
212
212
  expression?: string;
213
213
  meaning?: string;
214
214
  };
215
+ canonicalToolResponse?: {
216
+ expression?: string;
217
+ meaning?: string;
218
+ };
215
219
  invalidGetterHint?: string;
216
220
  };
217
221
  toolExecutionResult?: {
218
222
  type?: 'ToolExecutionResult';
219
223
  toolResponse?: {
220
224
  raw?: string;
225
+ rawV2?: string;
226
+ view?: string;
227
+ responseMeta?: string;
221
228
  meta?: string;
222
229
  };
223
230
  meta?: string;
@@ -94,6 +94,14 @@ import {
94
94
  type RuntimeResourceGovernor,
95
95
  } from './resource-governor';
96
96
  import { CTX_FETCH_EGRESS_TOOL_ID } from './builtin-pacing';
97
+ import {
98
+ legacyRawFromToolResponseRawV2,
99
+ normalizeToolResponseContract,
100
+ providerMetaFromToolResponseRawV2,
101
+ RAW_V2_TOOL_RESPONSE_CONTRACT,
102
+ type ToolResponseContract,
103
+ type ToolResponseView,
104
+ } from './tool-response-contract';
97
105
  import { ProviderExhaustedError } from './run-failure';
98
106
  import {
99
107
  buildPlayContractCompatibility,
@@ -357,6 +365,8 @@ type InlineCompositionStore = {
357
365
  toolErrorSchemaVersion: ToolExecutionErrorSchemaVersion;
358
366
  /** Immutable authoring semantics pinned by the child play artifact. */
359
367
  authoringContractEdition: PlayAuthoringContractEdition;
368
+ /** Immutable execute response contract pinned by the child artifact. */
369
+ toolResponseContract: ToolResponseContract;
360
370
  };
361
371
  const inlineCompositionContext =
362
372
  new AsyncLocalStorage<InlineCompositionStore>();
@@ -1116,6 +1126,8 @@ function isUnsafeOutboundUrlError(error: unknown): boolean {
1116
1126
  function publicToolResponseEnvelope(value: unknown): {
1117
1127
  status: string;
1118
1128
  raw: unknown;
1129
+ rawV2?: unknown;
1130
+ view?: ToolResponseView;
1119
1131
  meta?: Record<string, unknown>;
1120
1132
  } | null {
1121
1133
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
@@ -1127,27 +1139,100 @@ function publicToolResponseEnvelope(value: unknown): {
1127
1139
  if (
1128
1140
  !toolResponse ||
1129
1141
  typeof toolResponse !== 'object' ||
1130
- Array.isArray(toolResponse) ||
1131
- !Object.prototype.hasOwnProperty.call(toolResponse, 'raw')
1142
+ Array.isArray(toolResponse)
1132
1143
  ) {
1133
1144
  return null;
1134
1145
  }
1135
1146
  const response = toolResponse as Record<string, unknown>;
1136
- return {
1137
- status: record.status,
1138
- raw: response.raw,
1139
- ...(response.meta &&
1147
+ const rawV2 = Object.prototype.hasOwnProperty.call(response, 'rawV2')
1148
+ ? response.rawV2
1149
+ : undefined;
1150
+ const view =
1151
+ response.view === 'data' || response.view === 'rawV2'
1152
+ ? response.view
1153
+ : undefined;
1154
+ if (
1155
+ !Object.prototype.hasOwnProperty.call(response, 'raw') &&
1156
+ rawV2 === undefined
1157
+ ) {
1158
+ return null;
1159
+ }
1160
+ const providerMeta = providerMetaFromToolResponseRawV2(
1161
+ rawV2,
1162
+ view ?? 'rawV2',
1163
+ );
1164
+ const toolResponseMeta =
1165
+ response.meta &&
1140
1166
  typeof response.meta === 'object' &&
1141
1167
  !Array.isArray(response.meta)
1142
- ? { meta: response.meta as Record<string, unknown> }
1168
+ ? (response.meta as Record<string, unknown>)
1169
+ : {};
1170
+ const responseMeta =
1171
+ response.responseMeta &&
1172
+ typeof response.responseMeta === 'object' &&
1173
+ !Array.isArray(response.responseMeta)
1174
+ ? (response.responseMeta as Record<string, unknown>)
1175
+ : {};
1176
+ return {
1177
+ status: record.status,
1178
+ raw: Object.prototype.hasOwnProperty.call(response, 'raw')
1179
+ ? response.raw
1180
+ : legacyRawFromToolResponseRawV2(rawV2, view ?? 'rawV2', responseMeta),
1181
+ ...(rawV2 !== undefined ? { rawV2 } : {}),
1182
+ ...(view ? { view } : {}),
1183
+ ...(Object.keys({ ...toolResponseMeta, ...providerMeta, ...responseMeta })
1184
+ .length > 0
1185
+ ? { meta: { ...toolResponseMeta, ...providerMeta, ...responseMeta } }
1143
1186
  : {}),
1144
1187
  };
1145
1188
  }
1146
1189
 
1190
+ /**
1191
+ * A batched provider request returns one envelope for several logical source
1192
+ * tool calls. Each source call persists only its own item-shaped canonical
1193
+ * response: retaining the aggregate envelope would make its legacy `raw`
1194
+ * projection change on receipt replay and duplicate every batch for every row.
1195
+ */
1196
+ function publicToolResponseForBatchedItem(
1197
+ execution: ParsedToolExecuteResponse,
1198
+ result: unknown,
1199
+ forceRawV2: boolean,
1200
+ ): ParsedToolExecuteResponse['toolResponse'] | undefined {
1201
+ const providerMeta = execution.toolResponse?.meta;
1202
+ if (
1203
+ !forceRawV2 &&
1204
+ (!execution.toolResponse ||
1205
+ !Object.prototype.hasOwnProperty.call(execution.toolResponse, 'rawV2'))
1206
+ ) {
1207
+ return undefined;
1208
+ }
1209
+ return {
1210
+ rawV2: { data: result },
1211
+ view: 'data',
1212
+ ...(providerMeta ? { meta: providerMeta } : {}),
1213
+ };
1214
+ }
1215
+
1216
+ /**
1217
+ * Batch splitters predate raw-v2 and receive the same legacy value they got
1218
+ * from callToolAPI. Keep that input contract stable; raw-v2 is attached to the
1219
+ * completed logical call separately by publicToolResponseForBatchedItem.
1220
+ */
1221
+ function legacyResultForBatchSplitter(execution: ParsedToolExecuteResponse): unknown {
1222
+ if (execution.toolResponse && 'raw' in execution.toolResponse) {
1223
+ return execution.toolResponse.raw;
1224
+ }
1225
+ return execution.result != null &&
1226
+ typeof execution.result === 'object' &&
1227
+ !Array.isArray(execution.result) &&
1228
+ 'data' in execution.result
1229
+ ? execution.result.data
1230
+ : execution.result;
1231
+ }
1232
+
1147
1233
  const EXECUTE_TOOL_METADATA_HEADER = 'x-deepline-include-tool-metadata';
1148
1234
  const EXECUTE_RESPONSE_CONTRACT_HEADER = 'x-deepline-execute-response-contract';
1149
1235
  const EXECUTE_RESPONSE_INTENT_HEADER = 'x-deepline-execute-response-intent';
1150
- const V2_EXECUTE_RESPONSE_CONTRACT = 'v2-tool-response';
1151
1236
  function recordOrNull(value: unknown): Record<string, unknown> | null {
1152
1237
  return value && typeof value === 'object' && !Array.isArray(value)
1153
1238
  ? (value as Record<string, unknown>)
@@ -2518,6 +2603,13 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
2518
2603
  return TOOL_EXECUTION_ERROR_SCHEMA_VERSION;
2519
2604
  }
2520
2605
 
2606
+ private get currentToolResponseContract(): ToolResponseContract {
2607
+ return normalizeToolResponseContract(
2608
+ this.activeInlineComposition?.toolResponseContract ??
2609
+ this.#options.toolResponseContract,
2610
+ );
2611
+ }
2612
+
2521
2613
  private get currentAuthoringContractEdition(): PlayAuthoringContractEdition {
2522
2614
  return (
2523
2615
  this.activeInlineComposition?.authoringContractEdition ??
@@ -4975,6 +5067,12 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
4975
5067
  result: unknown;
4976
5068
  metadata?: ToolResultMetadataInput | null;
4977
5069
  meta?: Record<string, unknown>;
5070
+ toolResponse?: {
5071
+ raw?: unknown;
5072
+ rawV2?: unknown;
5073
+ view?: 'data' | 'rawV2';
5074
+ meta?: Record<string, unknown>;
5075
+ };
4978
5076
  execution: ToolResultExecutionMetadata;
4979
5077
  requestInput?: Record<string, unknown>;
4980
5078
  }): Promise<ToolExecuteResult> {
@@ -4998,6 +5096,18 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
4998
5096
  ...(publicToolResult.meta ? { meta: publicToolResult.meta } : {}),
4999
5097
  }
5000
5098
  : input.result,
5099
+ response: publicToolResult
5100
+ ? {
5101
+ ...(Object.prototype.hasOwnProperty.call(
5102
+ publicToolResult,
5103
+ 'rawV2',
5104
+ )
5105
+ ? { rawV2: publicToolResult.rawV2 }
5106
+ : {}),
5107
+ ...(publicToolResult.view ? { view: publicToolResult.view } : {}),
5108
+ ...(publicToolResult.meta ? { meta: publicToolResult.meta } : {}),
5109
+ }
5110
+ : input.toolResponse,
5001
5111
  metadata:
5002
5112
  input.metadata ??
5003
5113
  (await this.resolveToolResultMetadata(input.toolId)),
@@ -5136,6 +5246,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
5136
5246
  metadata?: ToolResultMetadataInput | null,
5137
5247
  jobId?: string,
5138
5248
  meta?: Record<string, unknown>,
5249
+ toolResponse?: ParsedToolExecuteResponse['toolResponse'],
5139
5250
  ): Promise<unknown> {
5140
5251
  const cacheKey = request.cacheKey;
5141
5252
  const receiptKey = request.receiptKey?.trim() || null;
@@ -5146,6 +5257,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
5146
5257
  result,
5147
5258
  metadata,
5148
5259
  meta,
5260
+ toolResponse,
5149
5261
  execution: toolExecutionMetadataForOutcome({
5150
5262
  kind: 'live',
5151
5263
  cacheKey,
@@ -5196,6 +5308,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
5196
5308
  metadata?: ToolResultMetadataInput | null;
5197
5309
  jobId?: string;
5198
5310
  meta?: Record<string, unknown>;
5311
+ toolResponse?: ParsedToolExecuteResponse['toolResponse'];
5199
5312
  }>,
5200
5313
  ): Promise<unknown[]> {
5201
5314
  const wrappedEntries = await Promise.all(
@@ -5208,6 +5321,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
5208
5321
  result: entry.result,
5209
5322
  metadata: entry.metadata,
5210
5323
  meta: entry.meta,
5324
+ toolResponse: entry.toolResponse,
5211
5325
  execution: toolExecutionMetadataForOutcome({
5212
5326
  kind: 'live',
5213
5327
  cacheKey: entry.request.cacheKey,
@@ -8941,6 +9055,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
8941
9055
  status: execution.status,
8942
9056
  jobId: execution.jobId,
8943
9057
  result: execution.result,
9058
+ toolResponse: execution.toolResponse,
8944
9059
  metadata: execution.metadata,
8945
9060
  meta: execution.meta,
8946
9061
  requestInput: input,
@@ -9338,6 +9453,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
9338
9453
  );
9339
9454
  const childToolErrorSchemaVersion =
9340
9455
  childCompatibility.toolErrorSchemaVersion;
9456
+ const childToolResponseContract = childCompatibility.toolResponseContract;
9341
9457
  const childExecutionDecision = resolveChildExecutionStrategy({
9342
9458
  pipeline: resolvedPlay.staticPipeline,
9343
9459
  timeoutMs: options?.timeoutMs,
@@ -9410,6 +9526,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
9410
9526
  playName: resolvedName,
9411
9527
  staticPipeline: resolvedPlay.staticPipeline ?? null,
9412
9528
  toolErrorSchemaVersion: childToolErrorSchemaVersion,
9529
+ toolResponseContract: childToolResponseContract,
9413
9530
  authoringContractEdition:
9414
9531
  childCompatibility.authoringContractEdition,
9415
9532
  },
@@ -10658,6 +10775,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
10658
10775
  execution?.metadata ?? null,
10659
10776
  execution?.jobId,
10660
10777
  execution?.meta,
10778
+ execution?.toolResponse,
10661
10779
  );
10662
10780
  if (result != null) {
10663
10781
  successfulLiveStepCallIds.add(owner.callId);
@@ -10984,7 +11102,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
10984
11102
  });
10985
11103
  let releaseToolSlot: () => void = () => undefined;
10986
11104
  try {
10987
- const value = await this.callToolAPI(
11105
+ const execution = await this.callToolExecutionAPI(
10988
11106
  batch.batchOperation,
10989
11107
  batch.batchPayload,
10990
11108
  {
@@ -11043,7 +11161,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11043
11161
  },
11044
11162
  },
11045
11163
  );
11046
- return { value, releaseToolSlot };
11164
+ return { execution, releaseToolSlot };
11047
11165
  } catch (error) {
11048
11166
  releaseToolSlot();
11049
11167
  throw error;
@@ -11060,7 +11178,11 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11060
11178
  try {
11061
11179
  const splitResults =
11062
11180
  entry.result != null
11063
- ? entry.request.splitResults(entry.result.value)
11181
+ ? entry.request.splitResults(
11182
+ legacyResultForBatchSplitter(
11183
+ entry.result.execution,
11184
+ ),
11185
+ )
11064
11186
  : entry.request.memberRequests.map(() => null);
11065
11187
  const resolvedResults =
11066
11188
  await this.resolveToolCallBatchResults(
@@ -11069,6 +11191,15 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11069
11191
  (request, index) => ({
11070
11192
  request,
11071
11193
  result: splitResults[index] ?? null,
11194
+ toolResponse:
11195
+ entry.result == null
11196
+ ? undefined
11197
+ : publicToolResponseForBatchedItem(
11198
+ entry.result.execution,
11199
+ splitResults[index] ?? null,
11200
+ this.currentToolResponseContract ===
11201
+ RAW_V2_TOOL_RESPONSE_CONTRACT,
11202
+ ),
11072
11203
  }),
11073
11204
  ),
11074
11205
  );
@@ -11105,6 +11236,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11105
11236
  metadata?: ToolResultMetadataInput | null;
11106
11237
  jobId?: string;
11107
11238
  meta?: Record<string, unknown>;
11239
+ toolResponse?: ParsedToolExecuteResponse['toolResponse'];
11108
11240
  resolve: (value: unknown) => void;
11109
11241
  reject: (error: unknown) => void;
11110
11242
  }> = [];
@@ -11123,6 +11255,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11123
11255
  metadata: entry.metadata,
11124
11256
  jobId: entry.jobId,
11125
11257
  meta: entry.meta,
11258
+ toolResponse: entry.toolResponse,
11126
11259
  })),
11127
11260
  );
11128
11261
  for (let index = 0; index < entries.length; index += 1) {
@@ -11155,6 +11288,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11155
11288
  metadata: execution.metadata ?? null,
11156
11289
  jobId: execution.jobId,
11157
11290
  meta: execution.meta,
11291
+ toolResponse: execution.toolResponse,
11158
11292
  resolve,
11159
11293
  reject,
11160
11294
  });
@@ -11369,23 +11503,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11369
11503
  )(ctx, input);
11370
11504
  }
11371
11505
 
11372
- private async callToolAPI(
11373
- toolId: string,
11374
- input: Record<string, unknown>,
11375
- options?: ToolExecutionApiOptions,
11376
- ): Promise<unknown> {
11377
- const execution = await this.callToolExecutionAPI(toolId, input, options);
11378
- if (execution.toolResponse && 'raw' in execution.toolResponse) {
11379
- return execution.toolResponse.raw;
11380
- }
11381
- return execution.result != null &&
11382
- typeof execution.result === 'object' &&
11383
- !Array.isArray(execution.result) &&
11384
- 'data' in execution.result
11385
- ? execution.result.data
11386
- : execution.result;
11387
- }
11388
-
11389
11506
  private providerIdempotencyKeyForToolCall(input: {
11390
11507
  cacheKey: string;
11391
11508
  force?: boolean;
@@ -11873,7 +11990,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11873
11990
  'Content-Type': 'application/json',
11874
11991
  Authorization: `Bearer ${this.#options.executorToken}`,
11875
11992
  [EXECUTE_RESPONSE_CONTRACT_HEADER]:
11876
- V2_EXECUTE_RESPONSE_CONTRACT,
11993
+ this.currentToolResponseContract,
11877
11994
  [EXECUTE_RESPONSE_INTENT_HEADER]: 'dataset',
11878
11995
  [EXECUTE_TOOL_METADATA_HEADER]: 'true',
11879
11996
  [TOOL_EXECUTION_ERROR_SCHEMA_HEADER]: String(
@@ -51,6 +51,7 @@ import type {
51
51
  ToolExecutionFailureV1,
52
52
  } from '../tool-execution-error';
53
53
  import type { FixtureBehavior } from './fixture-behavior';
54
+ import type { ToolResponseContract } from './tool-response-contract';
54
55
 
55
56
  export interface RowState {
56
57
  results: Map<string, unknown>;
@@ -572,6 +573,8 @@ export interface ContextOptions {
572
573
  authoringContractEdition?: PlayAuthoringContractEdition;
573
574
  /** Error shape pinned by the immutable play artifact; missing preserves legacy schema 0. */
574
575
  toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
576
+ /** Execute-result contract pinned by the immutable Play artifact. */
577
+ toolResponseContract?: ToolResponseContract;
575
578
  /** Short-lived HMAC-signed internal token for tool callbacks. Required for cloud execution. */
576
579
  executorToken?: string;
577
580
  baseUrl?: string;
@@ -15,6 +15,7 @@ import type { PlaySandboxRuntimeLimits } from './sandbox-runtime-limits';
15
15
  import type { PlayRunInputPayload } from './play-input';
16
16
  import type { PlayRunFailureDetails } from './run-failure';
17
17
  import type { ToolExecutionErrorSchemaVersion } from '../tool-execution-error';
18
+ import type { ToolResponseContract } from './tool-response-contract';
18
19
  import type { FixtureBehavior } from './fixture-behavior';
19
20
 
20
21
  export type PlayRunnerRateStateBackendConfig =
@@ -138,6 +139,8 @@ export interface PlayRunnerContextConfig {
138
139
  maxConcurrentRows?: number | null;
139
140
  /** Immutable tool-error payload schema copied from the run contract. */
140
141
  toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
142
+ /** Immutable execute response contract copied from the Play artifact. */
143
+ toolResponseContract?: ToolResponseContract;
141
144
  orgId?: string;
142
145
  workflowId?: string;
143
146
  playId?: string;