deepline 0.2.13 → 0.2.15

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 (36) hide show
  1. package/dist/bundling-sources/sdk/src/index.ts +3 -0
  2. package/dist/bundling-sources/sdk/src/play.ts +150 -691
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +7 -1
  5. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +249 -51
  6. package/dist/bundling-sources/shared_libs/play-runtime/csv-rename.ts +10 -6
  7. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +32 -51
  8. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +11 -22
  9. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-policy.ts +34 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/play-call-execution.ts +2 -1
  11. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-projection-contract.ts +95 -0
  12. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +11 -6
  13. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +38 -9
  14. package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +23 -15
  15. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +3 -0
  16. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +2222 -0
  17. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +3 -2
  18. package/dist/bundling-sources/shared_libs/plays/compiler-manifest.ts +2 -0
  19. package/dist/bundling-sources/shared_libs/plays/contracts.ts +16 -0
  20. package/dist/bundling-sources/shared_libs/plays/input-contract-definition.ts +28 -0
  21. package/dist/bundling-sources/shared_libs/plays/input-contract.ts +3 -3
  22. package/dist/cli/index.js +5074 -829
  23. package/dist/cli/index.mjs +5019 -759
  24. package/dist/compiler-manifest-xFkbJX2B.d.mts +2517 -0
  25. package/dist/compiler-manifest-xFkbJX2B.d.ts +2517 -0
  26. package/dist/index.d.mts +36 -1011
  27. package/dist/index.d.ts +36 -1011
  28. package/dist/index.js +25 -7
  29. package/dist/index.mjs +25 -7
  30. package/dist/plays/bundle-play-file.d.mts +5 -8
  31. package/dist/plays/bundle-play-file.d.ts +5 -8
  32. package/dist/plays/bundle-play-file.mjs +3844 -3
  33. package/package.json +1 -1
  34. package/dist/bundling-sources/shared_libs/plays/source-metadata.ts +0 -240
  35. package/dist/tool-execution-error-4-rhemLQ.d.mts +0 -446
  36. package/dist/tool-execution-error-4-rhemLQ.d.ts +0 -446
@@ -160,7 +160,7 @@ export const SDK_RELEASE = {
160
160
  // 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
161
161
  // exposed storage-dependent synchronous access. This deliberate minor
162
162
  // release keeps lazy paging semantics independent of row residency.
163
- version: '0.2.13',
163
+ version: '0.2.15',
164
164
  contracts: {
165
165
  api: {
166
166
  name: 'sdk-http-api',
@@ -36,6 +36,12 @@ export function ctxRunPlayInlineOnlyMessage(
36
36
  childPlayName: string,
37
37
  reason: CtxRunPlayInlineOnlyReason,
38
38
  ): string {
39
+ const contractPath =
40
+ reason === 'explicit_timeout'
41
+ ? 'ctx.runPlay.options.timeoutMs'
42
+ : reason === 'explicit_child_workflow'
43
+ ? 'ctx.runPlay.options.execution'
44
+ : 'ctx.runPlay';
39
45
  const detail: Record<CtxRunPlayInlineOnlyReason, string> = {
40
46
  missing_static_contract: 'its static contract could not be resolved',
41
47
  dataset_child: 'it uses ctx.dataset(), ctx.csv(), or a Runtime Sheet',
@@ -59,7 +65,7 @@ export function ctxRunPlayInlineOnlyMessage(
59
65
  'Remove execution: "child-workflow" for a scalar lookup, or trigger the child as a top-level play when it needs its own lifecycle.',
60
66
  };
61
67
  return (
62
- `${CTX_RUN_PLAY_INLINE_ONLY}: ctx.runPlay("${childPlayName}") can only call a scalar, per-record play; ` +
68
+ `${CTX_RUN_PLAY_INLINE_ONLY}: [play_authoring_run_play_option_invalid path=${contractPath}] ctx.runPlay("${childPlayName}") can only call a scalar, per-record play; ` +
63
69
  `${detail[reason]}. ${nextStep[reason]}`
64
70
  );
65
71
  }
@@ -142,7 +142,17 @@ import {
142
142
  buildDurableToolCallCacheKey,
143
143
  buildDurableToolProviderIdempotencyKey,
144
144
  buildDurableToolReceiptPrefix,
145
+ resolveDurableCallCachePolicy,
145
146
  } from './durable-call-cache';
147
+ import {
148
+ PLAY_AUTHORING_CONTRACT_EDITION,
149
+ normalizePlayAuthoringCustomerDbStatement,
150
+ validateOptionalPlayAuthoringField,
151
+ validatePlayAuthoringField,
152
+ type PlayAuthoringContractEdition,
153
+ type PlaySqlQuery,
154
+ type PlayAuthoringRuntimeContext,
155
+ } from '../plays/authoring-contract';
146
156
  import {
147
157
  RuntimeReceiptLeaseLostError,
148
158
  RuntimeReceiptWaitTimeoutError,
@@ -236,7 +246,7 @@ import {
236
246
  import type {
237
247
  CsvOptions,
238
248
  RowState,
239
- DatasetOptions,
249
+ RuntimeDatasetOptions,
240
250
  ToolCallRequest,
241
251
  ToolBatchResult,
242
252
  ContextOptions,
@@ -248,7 +258,7 @@ import type {
248
258
  MapFieldDefinition,
249
259
  MapFieldResolver,
250
260
  ToolCallOptions,
251
- StepOptions,
261
+ RuntimeStepOptions,
252
262
  FetchOptions,
253
263
  ResolvedPlayExecution,
254
264
  PlayFetchResponse,
@@ -304,6 +314,8 @@ type InlineCompositionStore = {
304
314
  staticPipeline: ContextOptions['staticPipeline'];
305
315
  /** Immutable error contract pinned by the child play artifact. */
306
316
  toolErrorSchemaVersion: ToolExecutionErrorSchemaVersion;
317
+ /** Immutable authoring semantics pinned by the child play artifact. */
318
+ authoringContractEdition: PlayAuthoringContractEdition;
307
319
  };
308
320
  const inlineCompositionContext =
309
321
  new AsyncLocalStorage<InlineCompositionStore>();
@@ -575,13 +587,21 @@ export async function reconcileNodeRuntimeMapResultsWithPersistedSheet(input: {
575
587
  export function resolveToolRuntimeTimeoutMs(
576
588
  toolId: string,
577
589
  requestedTimeoutMs?: number,
590
+ authoringContractEdition: PlayAuthoringContractEdition = PLAY_AUTHORING_CONTRACT_EDITION,
578
591
  ): number | undefined {
579
- if (
580
- typeof requestedTimeoutMs === 'number' &&
581
- Number.isFinite(requestedTimeoutMs) &&
582
- requestedTimeoutMs > 0
583
- ) {
584
- return Math.max(1, Math.ceil(requestedTimeoutMs));
592
+ if (requestedTimeoutMs !== undefined) {
593
+ if (authoringContractEdition >= 2) {
594
+ validatePlayAuthoringField(
595
+ 'ctx.tools.execute.timeoutMs',
596
+ requestedTimeoutMs,
597
+ );
598
+ return requestedTimeoutMs;
599
+ }
600
+ // Edition 1 rounded positive finite values and treated every other value
601
+ // as omitted. Preserve that behavior for already-published artifacts.
602
+ if (Number.isFinite(requestedTimeoutMs) && requestedTimeoutMs > 0) {
603
+ return Math.max(1, Math.ceil(requestedTimeoutMs));
604
+ }
585
605
  }
586
606
  const normalized = toolId.trim().toLowerCase();
587
607
  // Long-inference tools keep their explicit 15-minute budget. Every other tool
@@ -1135,7 +1155,7 @@ class RuntimeDatasetBuilder<T extends Record<string, unknown>> {
1135
1155
  private readonly builder: StepProgramDatasetBuilder<
1136
1156
  RuntimeStepProgramStep,
1137
1157
  RuntimeStepProgramStep['resolver'],
1138
- DatasetOptions<T>,
1158
+ RuntimeDatasetOptions<T>,
1139
1159
  Promise<PlayDataset<Record<string, unknown>>>
1140
1160
  >;
1141
1161
 
@@ -1181,7 +1201,7 @@ class RuntimeDatasetBuilder<T extends Record<string, unknown>> {
1181
1201
  }
1182
1202
 
1183
1203
  run(
1184
- options?: DatasetOptions<T>,
1204
+ options?: RuntimeDatasetOptions<T>,
1185
1205
  ): Promise<PlayDataset<Record<string, unknown>>> {
1186
1206
  return this.builder.run(options);
1187
1207
  }
@@ -1288,7 +1308,20 @@ function createPacingResolver(
1288
1308
  };
1289
1309
  }
1290
1310
 
1291
- export class PlayContextImpl {
1311
+ type ScalarPlayAuthoringRuntimeContext = Pick<
1312
+ PlayAuthoringRuntimeContext,
1313
+ | 'tools'
1314
+ | 'customerDb'
1315
+ | 'tool'
1316
+ | 'step'
1317
+ | 'fetch'
1318
+ | 'secrets'
1319
+ | 'runPlay'
1320
+ | 'log'
1321
+ | 'sleep'
1322
+ >;
1323
+
1324
+ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
1292
1325
  private rowStates = new Map<number, RowState>();
1293
1326
  private toolCallQueue: ToolCallRequest[] = [];
1294
1327
  private pendingRuntimeToolOwnershipAssertions: Array<{
@@ -1423,7 +1456,7 @@ export class PlayContextImpl {
1423
1456
  input: Record<string, unknown>;
1424
1457
  description?: string;
1425
1458
  force?: boolean;
1426
- staleAfterSeconds?: number;
1459
+ staleAfterSeconds?: number | null;
1427
1460
  timeoutMs?: number;
1428
1461
  receiptWaitMs?: number;
1429
1462
  }): Promise<TOutput> => {
@@ -1432,20 +1465,37 @@ export class PlayContextImpl {
1432
1465
  'ctx.tools.execute requires a request object: ctx.tools.execute({ id, tool, input, description }).',
1433
1466
  );
1434
1467
  }
1468
+ validatePlayAuthoringField('ctx.tools.execute.id', request.id);
1469
+ validatePlayAuthoringField('ctx.tools.execute.tool', request.tool);
1470
+ validatePlayAuthoringField('ctx.tools.execute.input', request.input);
1471
+ if (request.description !== undefined) {
1472
+ validatePlayAuthoringField(
1473
+ 'ctx.tools.execute.description',
1474
+ request.description,
1475
+ );
1476
+ }
1477
+ if (request.force !== undefined) {
1478
+ validatePlayAuthoringField('ctx.tools.execute.force', request.force);
1479
+ }
1480
+ assertNoSecretTaint(request.input, 'ctx.tools.execute input');
1435
1481
  if (
1436
- typeof request.id !== 'string' ||
1437
- !request.id.trim() ||
1438
- typeof request.tool !== 'string' ||
1439
- !request.tool.trim() ||
1440
- !request.input ||
1441
- typeof request.input !== 'object' ||
1442
- Array.isArray(request.input)
1482
+ request.timeoutMs !== undefined &&
1483
+ this.currentAuthoringContractEdition >= 2
1443
1484
  ) {
1444
- throw new Error(
1445
- 'ctx.tools.execute({ id, tool, input }) requires a non-empty id, tool string, and input object.',
1485
+ validatePlayAuthoringField(
1486
+ 'ctx.tools.execute.timeoutMs',
1487
+ request.timeoutMs,
1488
+ );
1489
+ }
1490
+ if (
1491
+ request.receiptWaitMs !== undefined &&
1492
+ this.currentAuthoringContractEdition >= 2
1493
+ ) {
1494
+ validatePlayAuthoringField(
1495
+ 'ctx.tools.execute.receiptWaitMs',
1496
+ request.receiptWaitMs,
1446
1497
  );
1447
1498
  }
1448
- assertNoSecretTaint(request.input, 'ctx.tools.execute input');
1449
1499
  const force =
1450
1500
  request.force === true ||
1451
1501
  toolExecutionOverrides.getStore()?.force === true;
@@ -1478,19 +1528,55 @@ export class PlayContextImpl {
1478
1528
  },
1479
1529
  };
1480
1530
 
1531
+ async tool<TOutput = unknown>(
1532
+ key: string,
1533
+ toolId: string,
1534
+ input: Record<string, unknown>,
1535
+ options?: { description?: string },
1536
+ ): Promise<ToolExecuteResult<TOutput>> {
1537
+ validatePlayAuthoringField('ctx.tool.key', key);
1538
+ validatePlayAuthoringField('ctx.tool.tool', toolId);
1539
+ validatePlayAuthoringField('ctx.tool.input', input);
1540
+ if (options?.description !== undefined) {
1541
+ validatePlayAuthoringField(
1542
+ 'ctx.tool.options.description',
1543
+ options.description,
1544
+ );
1545
+ }
1546
+ return (await this.tools.execute<ToolExecuteResult<TOutput>>({
1547
+ id: key,
1548
+ tool: toolId,
1549
+ input,
1550
+ ...(options?.description ? { description: options.description } : {}),
1551
+ })) as ToolExecuteResult<TOutput>;
1552
+ }
1553
+
1481
1554
  async __deeplineRunWithForcedTools<T>(run: () => Promise<T>): Promise<T> {
1482
1555
  return await toolExecutionOverrides.run({ force: true }, run);
1483
1556
  }
1484
1557
  readonly customerDb = {
1485
1558
  query: async <TRow extends object = Record<string, unknown>>(
1486
- statement: string,
1559
+ statement: PlaySqlQuery | string,
1487
1560
  options?: { maxRows?: number; timeoutMs?: number },
1488
1561
  ): Promise<TRow[]> => {
1562
+ const sql = normalizePlayAuthoringCustomerDbStatement(statement);
1563
+ if (options?.maxRows !== undefined) {
1564
+ validatePlayAuthoringField(
1565
+ 'ctx.customerDb.query.options.maxRows',
1566
+ options.maxRows,
1567
+ );
1568
+ }
1569
+ if (options?.timeoutMs !== undefined) {
1570
+ validatePlayAuthoringField(
1571
+ 'ctx.customerDb.query.options.timeoutMs',
1572
+ options.timeoutMs,
1573
+ );
1574
+ }
1489
1575
  const result = (await this.tools.execute({
1490
1576
  id: `customer_db_query_${this.customerDbQueryIndex++}`,
1491
1577
  tool: 'query_customer_db',
1492
1578
  input: {
1493
- sql: statement,
1579
+ sql,
1494
1580
  ...(options?.maxRows !== undefined
1495
1581
  ? { max_rows: options.maxRows }
1496
1582
  : {}),
@@ -1681,6 +1767,14 @@ export class PlayContextImpl {
1681
1767
  );
1682
1768
  }
1683
1769
 
1770
+ private get currentAuthoringContractEdition(): PlayAuthoringContractEdition {
1771
+ return (
1772
+ this.activeInlineComposition?.authoringContractEdition ??
1773
+ this.#options.authoringContractEdition ??
1774
+ PLAY_AUTHORING_CONTRACT_EDITION
1775
+ );
1776
+ }
1777
+
1684
1778
  private recordPlayCallStep(input: {
1685
1779
  playId: string;
1686
1780
  execution?: 'inline';
@@ -3137,6 +3231,14 @@ export class PlayContextImpl {
3137
3231
  execute: (context: { leaseId: string | null }) => Promise<T>;
3138
3232
  },
3139
3233
  ): Promise<T> {
3234
+ const stalePolicy = resolveDurableCallCachePolicy(
3235
+ opts.staleAfterSeconds,
3236
+ operation === 'step'
3237
+ ? 'ctx.step.staleAfterSeconds'
3238
+ : operation === 'fetch'
3239
+ ? 'ctx.fetch.staleAfterSeconds'
3240
+ : 'ctx.tools.execute.staleAfterSeconds',
3241
+ );
3140
3242
  const receiptKey =
3141
3243
  opts.receiptKey?.trim() ||
3142
3244
  durableCtxKey({
@@ -3145,7 +3247,7 @@ export class PlayContextImpl {
3145
3247
  operation,
3146
3248
  id,
3147
3249
  semanticKey: opts.semanticKey,
3148
- staleAfterSeconds: opts.staleAfterSeconds,
3250
+ staleAfterSeconds: stalePolicy.staleAfterSeconds,
3149
3251
  });
3150
3252
  return await executeWithDurableRuntimeReceipt<T>({
3151
3253
  operation,
@@ -3153,7 +3255,7 @@ export class PlayContextImpl {
3153
3255
  runId: this.currentReceiptOwnerRunId,
3154
3256
  receiptKey,
3155
3257
  store: this.durableReceiptExecutionStore(),
3156
- force: opts.force,
3258
+ force: opts.force === true || stalePolicy.forceRefresh,
3157
3259
  repairRunningReceiptForSameRun: opts.repairRunningReceiptForSameRun,
3158
3260
  repairRunningReceiptForSameRunAfterWaitTimeout:
3159
3261
  opts.repairRunningReceiptForSameRunAfterWaitTimeout,
@@ -3483,15 +3585,20 @@ export class PlayContextImpl {
3483
3585
  forceFailedRefresh: boolean;
3484
3586
  staleAfterSeconds?: number | null;
3485
3587
  } {
3588
+ const stalePolicy = resolveDurableCallCachePolicy(
3589
+ options?.staleAfterSeconds,
3590
+ );
3486
3591
  return {
3487
3592
  force:
3488
3593
  options?.force === true ||
3594
+ stalePolicy.forceRefresh ||
3489
3595
  this.#options.cachePolicy?.forceToolRefresh === true,
3490
3596
  forceFailedRefresh:
3491
3597
  options?.force === true ||
3598
+ stalePolicy.forceRefresh ||
3492
3599
  this.#options.cachePolicy?.forceToolRefresh === true ||
3493
3600
  this.#options.cachePolicy?.forceFailedToolRefresh === true,
3494
- staleAfterSeconds: options?.staleAfterSeconds ?? null,
3601
+ staleAfterSeconds: stalePolicy.staleAfterSeconds,
3495
3602
  };
3496
3603
  }
3497
3604
 
@@ -4024,10 +4131,19 @@ export class PlayContextImpl {
4024
4131
 
4025
4132
  async csv(
4026
4133
  path: string,
4027
- _options?: CsvOptions,
4134
+ options?: CsvOptions,
4028
4135
  ): Promise<PlayDataset<Record<string, unknown>>> {
4029
4136
  this.assertInlineChildContract('dataset_child');
4030
- void _options;
4137
+ if (options) {
4138
+ for (const [field, value] of [
4139
+ ['ctx.csv.options.description', options.description],
4140
+ ['ctx.csv.options.columns', options.columns],
4141
+ ['ctx.csv.options.rename', options.rename],
4142
+ ['ctx.csv.options.required', options.required],
4143
+ ] as const) {
4144
+ validateOptionalPlayAuthoringField(field, value);
4145
+ }
4146
+ }
4031
4147
  // In cloud mode, CSV data is passed in — path is just a label
4032
4148
  // The activity loads the actual data before creating the ctx
4033
4149
  throw new Error(
@@ -4044,7 +4160,7 @@ export class PlayContextImpl {
4044
4160
  key: string,
4045
4161
  items: PlayDatasetInput<T>,
4046
4162
  input: RuntimeStepProgram,
4047
- options?: DatasetOptions<T>,
4163
+ options?: RuntimeDatasetOptions<T>,
4048
4164
  ): Promise<PlayDataset<Record<string, unknown>>>;
4049
4165
  dataset<
4050
4166
  T extends Record<string, unknown>,
@@ -4053,7 +4169,7 @@ export class PlayContextImpl {
4053
4169
  key: string,
4054
4170
  items: PlayDatasetInput<T>,
4055
4171
  input?: MapFieldDefinition<T, TColumns> | RuntimeStepProgram,
4056
- options?: DatasetOptions<T>,
4172
+ options?: RuntimeDatasetOptions<T>,
4057
4173
  ): RuntimeDatasetBuilder<T> | Promise<PlayDataset<Record<string, unknown>>> {
4058
4174
  this.assertInlineChildContract('dataset_child');
4059
4175
  if (rowContext.getStore()) {
@@ -4082,7 +4198,7 @@ export class PlayContextImpl {
4082
4198
  key: string,
4083
4199
  items: PlayDatasetInput<T>,
4084
4200
  input: RuntimeStepProgram,
4085
- options?: DatasetOptions<T>,
4201
+ options?: RuntimeDatasetOptions<T>,
4086
4202
  ): never;
4087
4203
  map<T extends Record<string, unknown>>(
4088
4204
  _key: string,
@@ -4090,7 +4206,7 @@ export class PlayContextImpl {
4090
4206
  _input?:
4091
4207
  | MapFieldDefinition<T, Record<string, unknown>>
4092
4208
  | RuntimeStepProgram,
4093
- _options?: DatasetOptions<T>,
4209
+ _options?: RuntimeDatasetOptions<T>,
4094
4210
  ): never {
4095
4211
  void _key;
4096
4212
  void _items;
@@ -4103,7 +4219,7 @@ export class PlayContextImpl {
4103
4219
  key: string,
4104
4220
  items: PlayDatasetInput<T>,
4105
4221
  program: RuntimeStepProgram,
4106
- options?: DatasetOptions<T>,
4222
+ options?: RuntimeDatasetOptions<T>,
4107
4223
  ): Promise<PlayDataset<Record<string, unknown>>> {
4108
4224
  const definition = this.stepProgramToMapDefinition(program);
4109
4225
  return this.runMapDefinition(key, items, definition, options);
@@ -4117,7 +4233,11 @@ export class PlayContextImpl {
4117
4233
  if (!isRuntimeStepProgram(program)) {
4118
4234
  throw new Error('ctx.runSteps(program, input) requires steps().');
4119
4235
  }
4120
- if (options?.description) {
4236
+ if (options?.description !== undefined) {
4237
+ validatePlayAuthoringField(
4238
+ 'ctx.runSteps.options.description',
4239
+ options.description,
4240
+ );
4121
4241
  this.log(options.description);
4122
4242
  }
4123
4243
  return (await this.executeStepProgram(program, input, 0, [], {
@@ -4132,13 +4252,28 @@ export class PlayContextImpl {
4132
4252
  key: string,
4133
4253
  items: PlayDatasetInput<T>,
4134
4254
  input: MapFieldDefinition<T, TColumns>,
4135
- options?: DatasetOptions<T>,
4255
+ options?: RuntimeDatasetOptions<T>,
4136
4256
  ): Promise<PlayDataset<Record<string, unknown>>> {
4137
4257
  if (rowContext.getStore()) {
4138
4258
  throw new Error(
4139
4259
  'Nested ctx.dataset() is not supported. Flatten your columns into one dataset, or keep custom per-row logic inside a single column.',
4140
4260
  );
4141
4261
  }
4262
+ validatePlayAuthoringField('ctx.dataset.key', key);
4263
+ if (options) {
4264
+ validateOptionalPlayAuthoringField(
4265
+ 'ctx.dataset.run.description',
4266
+ options.description,
4267
+ );
4268
+ validateOptionalPlayAuthoringField(
4269
+ 'ctx.dataset.run.onRowError',
4270
+ options.onRowError,
4271
+ );
4272
+ validateOptionalPlayAuthoringField('ctx.dataset.run.mode', options.mode);
4273
+ if (options.key !== undefined) {
4274
+ validatePlayAuthoringField('ctx.dataset.run.key', options.key);
4275
+ }
4276
+ }
4142
4277
  const normalizedMapKey = this.normalizeContextKey(key, 'map');
4143
4278
 
4144
4279
  const normalizedMapNamespace = normalizeTableNamespace(normalizedMapKey);
@@ -6946,6 +7081,33 @@ export class PlayContextImpl {
6946
7081
  input: Record<string, unknown>,
6947
7082
  options?: ToolCallOptions,
6948
7083
  ): Promise<unknown> {
7084
+ if (options?.description !== undefined) {
7085
+ validatePlayAuthoringField(
7086
+ 'ctx.tools.execute.description',
7087
+ options.description,
7088
+ );
7089
+ }
7090
+ if (options?.force !== undefined) {
7091
+ validatePlayAuthoringField('ctx.tools.execute.force', options.force);
7092
+ }
7093
+ if (
7094
+ options?.timeoutMs !== undefined &&
7095
+ this.currentAuthoringContractEdition >= 2
7096
+ ) {
7097
+ validatePlayAuthoringField(
7098
+ 'ctx.tools.execute.timeoutMs',
7099
+ options.timeoutMs,
7100
+ );
7101
+ }
7102
+ if (
7103
+ options?.receiptWaitMs !== undefined &&
7104
+ this.currentAuthoringContractEdition >= 2
7105
+ ) {
7106
+ validatePlayAuthoringField(
7107
+ 'ctx.tools.execute.receiptWaitMs',
7108
+ options.receiptWaitMs,
7109
+ );
7110
+ }
6949
7111
  const executionScope = this.currentExecutionScope;
6950
7112
  const normalizedKey = this.normalizeContextKey(key, 'tool');
6951
7113
  const toolCachePolicy = this.effectiveToolCallCachePolicy(options);
@@ -7052,7 +7214,11 @@ export class PlayContextImpl {
7052
7214
  logicalCallId,
7053
7215
  })
7054
7216
  : physicalDirectKey,
7055
- timeoutMs: resolveToolRuntimeTimeoutMs(toolId, options?.timeoutMs),
7217
+ timeoutMs: resolveToolRuntimeTimeoutMs(
7218
+ toolId,
7219
+ options?.timeoutMs,
7220
+ this.currentAuthoringContractEdition,
7221
+ ),
7056
7222
  ...(directReceiptLeaseId &&
7057
7223
  (this.#options.heartbeatRuntimeStepReceipts ||
7058
7224
  this.#options.getRuntimeStepReceipt ||
@@ -7154,6 +7320,7 @@ export class PlayContextImpl {
7154
7320
  const timeoutMs = resolveToolRuntimeTimeoutMs(
7155
7321
  toolId,
7156
7322
  options?.timeoutMs,
7323
+ this.currentAuthoringContractEdition,
7157
7324
  );
7158
7325
  this.enqueueToolCall({
7159
7326
  callId,
@@ -7168,7 +7335,7 @@ export class PlayContextImpl {
7168
7335
  toolId,
7169
7336
  input,
7170
7337
  ...(timeoutMs !== undefined ? { timeoutMs } : {}),
7171
- ...(typeof options?.receiptWaitMs === 'number'
7338
+ ...(options?.receiptWaitMs !== undefined
7172
7339
  ? { receiptWaitMs: options.receiptWaitMs }
7173
7340
  : {}),
7174
7341
  tableNamespace: store.tableNamespace,
@@ -7205,8 +7372,11 @@ export class PlayContextImpl {
7205
7372
  toolRetryPolicy?.requiresExecutionFence === true,
7206
7373
  executionLockTtlMs: Math.min(
7207
7374
  600_000,
7208
- resolveToolRuntimeTimeoutMs(toolId, options?.timeoutMs) ??
7209
- 300_000,
7375
+ resolveToolRuntimeTimeoutMs(
7376
+ toolId,
7377
+ options?.timeoutMs,
7378
+ this.currentAuthoringContractEdition,
7379
+ ) ?? 300_000,
7210
7380
  ),
7211
7381
  staleAfterSeconds: toolCachePolicy.staleAfterSeconds,
7212
7382
  onClaimedResult: (output, receiptKey) =>
@@ -7228,7 +7398,7 @@ export class PlayContextImpl {
7228
7398
  execute: ({ leaseId }) => executeTool({ leaseId }),
7229
7399
  runningReceiptWaitMaxAttempts:
7230
7400
  resolveRuntimeToolReceiptWaitMaxAttempts(
7231
- typeof options?.receiptWaitMs === 'number'
7401
+ options?.receiptWaitMs !== undefined
7232
7402
  ? { max_wait_ms: options.receiptWaitMs }
7233
7403
  : input,
7234
7404
  ),
@@ -7382,8 +7552,6 @@ export class PlayContextImpl {
7382
7552
  input: Record<string, unknown>,
7383
7553
  options?: PlayCallOptions,
7384
7554
  ): Promise<TOutput> {
7385
- assertNoSecretTaint(input, 'ctx.runPlay input');
7386
- const normalizedKey = this.normalizeContextKey(key, 'runPlay');
7387
7555
  if (
7388
7556
  arguments.length === 3 &&
7389
7557
  typeof playRef === 'object' &&
@@ -7396,13 +7564,26 @@ export class PlayContextImpl {
7396
7564
  const resolvedName =
7397
7565
  typeof playRef === 'string'
7398
7566
  ? playRef
7399
- : typeof playRef.playName === 'string'
7567
+ : playRef && typeof playRef.playName === 'string'
7400
7568
  ? playRef.playName
7401
- : (playRef.name ?? '');
7569
+ : playRef && typeof playRef.name === 'string'
7570
+ ? playRef.name
7571
+ : '';
7402
7572
 
7403
7573
  if (!resolvedName.trim()) {
7404
7574
  throw new Error('ctx.runPlay(...) requires a resolvable play name.');
7405
7575
  }
7576
+ validatePlayAuthoringField('ctx.runPlay.playRef', playRef);
7577
+ validatePlayAuthoringField('ctx.runPlay.input', input);
7578
+ assertNoSecretTaint(input, 'ctx.runPlay input');
7579
+ validatePlayAuthoringField('ctx.runPlay.key', key);
7580
+ if (options?.description !== undefined) {
7581
+ validatePlayAuthoringField(
7582
+ 'ctx.runPlay.options.description',
7583
+ options.description,
7584
+ );
7585
+ }
7586
+ const normalizedKey = this.normalizeContextKey(key, 'runPlay');
7406
7587
  if (!this.#options.resolvePlay) {
7407
7588
  throw new Error(
7408
7589
  'ctx.runPlay(...) is unavailable because no play resolver was configured.',
@@ -7414,11 +7595,13 @@ export class PlayContextImpl {
7414
7595
  `Unable to resolve play "${resolvedName}" for ctx.runPlay(...).`,
7415
7596
  );
7416
7597
  }
7417
- const childToolErrorSchemaVersion = normalizePlayContractCompatibility(
7598
+ const childCompatibility = normalizePlayContractCompatibility(
7418
7599
  resolvedPlay.contractSnapshot?.compatibility ??
7419
7600
  resolvedPlay.artifact?.compatibility ??
7420
7601
  buildPlayContractCompatibility(),
7421
- ).toolErrorSchemaVersion;
7602
+ );
7603
+ const childToolErrorSchemaVersion =
7604
+ childCompatibility.toolErrorSchemaVersion;
7422
7605
  const childExecutionDecision = resolveChildExecutionStrategy({
7423
7606
  pipeline: resolvedPlay.staticPipeline,
7424
7607
  timeoutMs: options?.timeoutMs,
@@ -7490,6 +7673,8 @@ export class PlayContextImpl {
7490
7673
  playName: resolvedName,
7491
7674
  staticPipeline: resolvedPlay.staticPipeline ?? null,
7492
7675
  toolErrorSchemaVersion: childToolErrorSchemaVersion,
7676
+ authoringContractEdition:
7677
+ childCompatibility.authoringContractEdition,
7493
7678
  },
7494
7679
  () => this.executeResolvedPlay(resolvedPlay, this, input),
7495
7680
  );
@@ -7671,8 +7856,11 @@ export class PlayContextImpl {
7671
7856
 
7672
7857
  async sleep(ms: number): Promise<void> {
7673
7858
  this.assertInlineChildContract('suspending_child');
7859
+ const delayMs =
7860
+ this.currentAuthoringContractEdition >= 2
7861
+ ? (validatePlayAuthoringField('ctx.sleep.ms', ms), ms)
7862
+ : Math.max(0, Math.round(ms));
7674
7863
  if (this.#options.durableBoundaries) {
7675
- const delayMs = Math.max(0, Math.round(ms));
7676
7864
  const boundaryId = this.durableBoundaryId(
7677
7865
  `sleep-${this.sleepBoundaryIndex}-${delayMs}`,
7678
7866
  );
@@ -7695,7 +7883,7 @@ export class PlayContextImpl {
7695
7883
  delayMs,
7696
7884
  });
7697
7885
  }
7698
- return new Promise((resolve) => setTimeout(resolve, ms));
7886
+ return new Promise((resolve) => setTimeout(resolve, delayMs));
7699
7887
  }
7700
7888
 
7701
7889
  async fetch(
@@ -7704,6 +7892,7 @@ export class PlayContextImpl {
7704
7892
  init: SecretAwareRequestInit = {},
7705
7893
  options?: FetchOptions,
7706
7894
  ): Promise<PlayFetchResponse> {
7895
+ validatePlayAuthoringField('ctx.fetch.key', key);
7707
7896
  const normalizedKey = this.normalizeContextKey(key, 'fetch');
7708
7897
  const rowStore = rowContext.getStore();
7709
7898
  const rowFetchScope = rowStore
@@ -7890,8 +8079,13 @@ export class PlayContextImpl {
7890
8079
  async step<T>(
7891
8080
  key: string,
7892
8081
  run: () => T | Promise<T>,
7893
- options?: StepOptions,
8082
+ options?: RuntimeStepOptions,
7894
8083
  ): Promise<T> {
8084
+ validatePlayAuthoringField('ctx.step.id', key);
8085
+ validateOptionalPlayAuthoringField(
8086
+ 'ctx.step.semanticKey',
8087
+ options?.semanticKey,
8088
+ );
7895
8089
  const normalizedKey = this.normalizeContextKey(key, 'step');
7896
8090
  if (!normalizedKey.trim()) {
7897
8091
  throw new Error('ctx.step(key, fn) requires a non-empty stable step id.');
@@ -9207,7 +9401,11 @@ export class PlayContextImpl {
9207
9401
  this.#options.executionGatewayBaseUrl?.trim() || this.#options.baseUrl;
9208
9402
  const url = `${executionBaseUrl.replace(/\/$/, '')}/api/v2/integrations/${encodeURIComponent(toolId)}/${executeSuffix}`;
9209
9403
  const toolErrorSchemaVersion = this.currentToolErrorSchemaVersion;
9210
- const timeoutMs = resolveToolRuntimeTimeoutMs(toolId, options?.timeoutMs);
9404
+ const timeoutMs = resolveToolRuntimeTimeoutMs(
9405
+ toolId,
9406
+ options?.timeoutMs,
9407
+ this.currentAuthoringContractEdition,
9408
+ );
9211
9409
  const provider = toolId.split(/[._]/)[0]?.trim() || 'provider';
9212
9410
  const activityId = `provider:${toolId}`;
9213
9411
  let retryActivityEmitted = false;
@@ -1,10 +1,14 @@
1
- export type CsvRenameMap = Record<string, string | readonly string[]>;
1
+ import type {
2
+ PlayAuthoringCsvOptions,
3
+ PlayAuthoringCsvRenameMap,
4
+ } from '../plays/authoring-contract';
2
5
 
3
- export type CsvRenameOptions = {
4
- columns?: CsvRenameMap;
5
- rename?: CsvRenameMap;
6
- required?: readonly string[];
7
- };
6
+ export type CsvRenameMap = PlayAuthoringCsvRenameMap;
7
+
8
+ export type CsvRenameOptions = Pick<
9
+ PlayAuthoringCsvOptions,
10
+ 'columns' | 'rename' | 'required'
11
+ >;
8
12
 
9
13
  const CSV_PROJECTED_FIELDS = Symbol.for('deepline.play.csv.projected_fields');
10
14
  const CSV_PROJECTED_FIELDS_KEY = '__deeplineCsvProjectedFields';