deepline 0.1.153 → 0.1.154

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 (48) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +15 -0
  2. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +1180 -825
  3. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +34 -18
  4. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +41 -0
  5. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +143 -8
  6. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +104 -0
  7. package/dist/bundling-sources/sdk/src/index.ts +0 -1
  8. package/dist/bundling-sources/sdk/src/play.ts +3 -48
  9. package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +27 -2
  10. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  11. package/dist/bundling-sources/sdk/src/worker-play-entry.ts +0 -10
  12. package/dist/bundling-sources/shared_libs/play-data-plane/index.ts +0 -1
  13. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +87 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/batch-runtime.ts +0 -59
  15. package/dist/bundling-sources/shared_libs/play-runtime/cell-staleness.ts +0 -253
  16. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +805 -1570
  17. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +47 -74
  18. package/dist/bundling-sources/shared_libs/play-runtime/default-batch-strategies.ts +36 -14
  19. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +145 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +284 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/postgres-json.ts +12 -5
  22. package/dist/bundling-sources/shared_libs/play-runtime/run-lifecycle-policy.ts +78 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +10 -45
  24. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +1 -0
  25. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +923 -535
  26. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +45 -76
  27. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +12 -1
  28. package/dist/bundling-sources/shared_libs/play-runtime/step-program-dataset-builder.ts +1 -14
  29. package/dist/bundling-sources/shared_libs/play-runtime/tool-execution-outcome.ts +159 -0
  30. package/dist/bundling-sources/shared_libs/play-runtime/tool-result-types.ts +4 -1
  31. package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +32 -0
  32. package/dist/bundling-sources/shared_libs/plays/definition.ts +4 -2
  33. package/dist/bundling-sources/shared_libs/plays/runtime-validation.ts +3 -14
  34. package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +1 -43
  35. package/dist/cli/index.js +1301 -399
  36. package/dist/cli/index.mjs +1269 -361
  37. package/dist/{compiler-manifest-BjoRENv9.d.ts → compiler-manifest-DW1flrHk.d.mts} +0 -9
  38. package/dist/{compiler-manifest-BjoRENv9.d.mts → compiler-manifest-DW1flrHk.d.ts} +0 -9
  39. package/dist/index.d.mts +9 -38
  40. package/dist/index.d.ts +9 -38
  41. package/dist/index.js +22 -11
  42. package/dist/index.mjs +22 -11
  43. package/dist/plays/bundle-play-file.d.mts +2 -2
  44. package/dist/plays/bundle-play-file.d.ts +2 -2
  45. package/package.json +1 -1
  46. package/dist/bundling-sources/shared_libs/play-data-plane/cell-policy.ts +0 -76
  47. package/dist/bundling-sources/shared_libs/play-runtime/progress-emitter.ts +0 -197
  48. package/dist/bundling-sources/shared_libs/play-runtime/waterfall-replay.ts +0 -79
@@ -118,6 +118,38 @@ export function compileRequestsWithStrategy<TRequest>(input: {
118
118
  return compiledBatches;
119
119
  }
120
120
 
121
+ function testRateLimitBatchItems(
122
+ value: unknown,
123
+ ): Array<{ itemKey?: string; result?: unknown }> {
124
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
125
+ return [];
126
+ }
127
+ const record = value as Record<string, unknown>;
128
+ if (Array.isArray(record.items)) {
129
+ return record.items as Array<{ itemKey?: string; result?: unknown }>;
130
+ }
131
+ const candidates = [
132
+ record.data,
133
+ record.result,
134
+ record.output,
135
+ record.toolResponse &&
136
+ typeof record.toolResponse === 'object' &&
137
+ !Array.isArray(record.toolResponse)
138
+ ? (record.toolResponse as Record<string, unknown>).raw
139
+ : undefined,
140
+ record.toolOutput &&
141
+ typeof record.toolOutput === 'object' &&
142
+ !Array.isArray(record.toolOutput)
143
+ ? (record.toolOutput as Record<string, unknown>).raw
144
+ : undefined,
145
+ ];
146
+ for (const candidate of candidates) {
147
+ const items = testRateLimitBatchItems(candidate);
148
+ if (items.length > 0) return items;
149
+ }
150
+ return [];
151
+ }
152
+
121
153
  export function getDefaultPlayRuntimeBatchStrategy(
122
154
  operation: string | null | undefined,
123
155
  ): AnyBatchOperationStrategy | null {
@@ -144,7 +176,7 @@ export function getDefaultPlayRuntimeBatchStrategy(
144
176
  : undefined;
145
177
  const items = payloads.map((payload, index) => ({
146
178
  itemKey: String(
147
- payload.lead_id || payload.row_number || `row_${index}`,
179
+ payload.lead_id || payload.row_number || payload.key || `row_${index}`,
148
180
  ),
149
181
  payload,
150
182
  }));
@@ -162,23 +194,7 @@ export function getDefaultPlayRuntimeBatchStrategy(
162
194
  };
163
195
  },
164
196
  splitResult(fullResult, compiled) {
165
- const container =
166
- fullResult != null &&
167
- typeof fullResult === 'object' &&
168
- !Array.isArray(fullResult)
169
- ? (fullResult as Record<string, unknown>)
170
- : {};
171
- const nestedData =
172
- container.data != null &&
173
- typeof container.data === 'object' &&
174
- !Array.isArray(container.data)
175
- ? (container.data as Record<string, unknown>)
176
- : {};
177
- const resultItems = Array.isArray(container.items)
178
- ? (container.items as Array<{ itemKey?: string; result?: unknown }>)
179
- : Array.isArray(nestedData.items)
180
- ? (nestedData.items as Array<{ itemKey?: string; result?: unknown }>)
181
- : [];
197
+ const resultItems = testRateLimitBatchItems(fullResult);
182
198
  return compiled.items.map((item, index) => ({
183
199
  itemKey: item.itemKey,
184
200
  result:
@@ -1,7 +1,11 @@
1
1
  import {
2
2
  harnessClaimRuntimeReceipt,
3
+ harnessClaimRuntimeReceipts,
3
4
  harnessCompleteRuntimeReceipt,
5
+ harnessCompleteRuntimeReceipts,
4
6
  harnessFailRuntimeReceipt,
7
+ harnessFailRuntimeReceipts,
8
+ harnessGetRuntimeReceipt,
5
9
  } from '../../../../sdk/src/plays/harness-stub';
6
10
  import type { PreloadedRuntimeDbSessionInput } from '../../../play-harness-worker/src/rpc-types';
7
11
  import type { WorkerRuntimeReceiptStore } from './receipts';
@@ -13,6 +17,16 @@ export function createHarnessWorkerReceiptStore(input: {
13
17
  userEmail?: string | null;
14
18
  }): WorkerRuntimeReceiptStore {
15
19
  return {
20
+ getReceipt(command) {
21
+ return harnessGetRuntimeReceipt({
22
+ executorToken: input.executorToken,
23
+ orgId: input.orgId,
24
+ preloadedDbSessions: input.preloadedDbSessions ?? null,
25
+ userEmail: input.userEmail ?? null,
26
+ runId: '',
27
+ ...command,
28
+ });
29
+ },
16
30
  claimReceipt(command) {
17
31
  return harnessClaimRuntimeReceipt({
18
32
  executorToken: input.executorToken,
@@ -22,6 +36,15 @@ export function createHarnessWorkerReceiptStore(input: {
22
36
  ...command,
23
37
  });
24
38
  },
39
+ claimReceipts(command) {
40
+ return harnessClaimRuntimeReceipts({
41
+ executorToken: input.executorToken,
42
+ orgId: input.orgId,
43
+ preloadedDbSessions: input.preloadedDbSessions ?? null,
44
+ userEmail: input.userEmail ?? null,
45
+ ...command,
46
+ });
47
+ },
25
48
  completeReceipt(command) {
26
49
  return harnessCompleteRuntimeReceipt({
27
50
  executorToken: input.executorToken,
@@ -31,6 +54,15 @@ export function createHarnessWorkerReceiptStore(input: {
31
54
  ...command,
32
55
  });
33
56
  },
57
+ completeReceipts(command) {
58
+ return harnessCompleteRuntimeReceipts({
59
+ executorToken: input.executorToken,
60
+ orgId: input.orgId,
61
+ preloadedDbSessions: input.preloadedDbSessions ?? null,
62
+ userEmail: input.userEmail ?? null,
63
+ ...command,
64
+ });
65
+ },
34
66
  failReceipt(command) {
35
67
  return harnessFailRuntimeReceipt({
36
68
  executorToken: input.executorToken,
@@ -40,5 +72,14 @@ export function createHarnessWorkerReceiptStore(input: {
40
72
  ...command,
41
73
  });
42
74
  },
75
+ failReceipts(command) {
76
+ return harnessFailRuntimeReceipts({
77
+ executorToken: input.executorToken,
78
+ orgId: input.orgId,
79
+ preloadedDbSessions: input.preloadedDbSessions ?? null,
80
+ userEmail: input.userEmail ?? null,
81
+ ...command,
82
+ });
83
+ },
43
84
  };
44
85
  }
@@ -3,6 +3,7 @@ import {
3
3
  type WorkReceipt,
4
4
  type WorkReceiptClaim,
5
5
  type WorkReceiptCommand,
6
+ type WorkReceiptGetCommand,
6
7
  type WorkReceiptStatus,
7
8
  type WorkReceiptStore,
8
9
  } from '../../../../shared_libs/play-runtime/work-receipts';
@@ -12,6 +13,7 @@ export type RuntimeReceiptStatus = WorkReceiptStatus;
12
13
  export type WorkerRuntimeReceipt = WorkReceipt;
13
14
 
14
15
  export type WorkerRuntimeReceiptCommand = WorkReceiptCommand;
16
+ export type WorkerRuntimeReceiptGetCommand = WorkReceiptGetCommand;
15
17
 
16
18
  export type WorkerRuntimeReceiptClaim = WorkReceiptClaim;
17
19
 
@@ -25,11 +27,25 @@ type RuntimeReceiptContext = {
25
27
  receiptStore: WorkerRuntimeReceiptStore;
26
28
  };
27
29
 
30
+ const WORKER_RECEIPT_WAIT_MAX_ATTEMPTS = 240;
31
+ const WORKER_RECEIPT_WAIT_DELAY_MS = 250;
32
+
33
+ class RuntimeReceiptWaitTimeoutError extends Error {
34
+ constructor(key: string) {
35
+ super(`Timed out waiting for runtime receipt ${key}.`);
36
+ this.name = 'RuntimeReceiptWaitTimeoutError';
37
+ }
38
+ }
39
+
28
40
  function scopedReceiptKey(input: {
29
41
  orgId?: string | null;
30
42
  playName: string;
31
43
  key: string;
32
44
  }): string {
45
+ const orgId = input.orgId?.trim() || 'org';
46
+ if (input.key.startsWith(`ctx:${orgId}:`)) {
47
+ return input.key;
48
+ }
33
49
  return buildScopedWorkReceiptKey(input);
34
50
  }
35
51
 
@@ -41,6 +57,53 @@ function errorMessage(error: unknown): string {
41
57
  return error instanceof Error ? error.message : String(error);
42
58
  }
43
59
 
60
+ async function waitForReusableReceipt<T>(input: {
61
+ key: string;
62
+ playName: string;
63
+ receiptStore: WorkerRuntimeReceiptStore;
64
+ maxAttempts?: number;
65
+ delayMs?: number;
66
+ }): Promise<T> {
67
+ if (!input.receiptStore.getReceipt) {
68
+ throw new Error(
69
+ `Runtime receipt ${input.key} wait requires read-only receipt lookup.`,
70
+ );
71
+ }
72
+ const maxAttempts = input.maxAttempts ?? WORKER_RECEIPT_WAIT_MAX_ATTEMPTS;
73
+ const delayMs = input.delayMs ?? WORKER_RECEIPT_WAIT_DELAY_MS;
74
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
75
+ if (attempt > 0) {
76
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
77
+ }
78
+ const receipt = await input.receiptStore.getReceipt({
79
+ playName: input.playName,
80
+ key: input.key,
81
+ });
82
+ if (receipt?.status === 'completed' || receipt?.status === 'skipped') {
83
+ return receiptOutput<T>(receipt);
84
+ }
85
+ if (receipt?.status === 'failed') {
86
+ throw new Error(
87
+ `Runtime receipt ${input.key} failed while waiting: ${receipt.error ?? 'unknown error'}`,
88
+ );
89
+ }
90
+ }
91
+ throw new RuntimeReceiptWaitTimeoutError(input.key);
92
+ }
93
+
94
+ function shouldRepairSameRunRunningReceipt(input: {
95
+ repairRunningReceiptForSameRun?: boolean;
96
+ currentRunId: string;
97
+ receipt: WorkerRuntimeReceipt;
98
+ }): boolean {
99
+ return (
100
+ input.repairRunningReceiptForSameRun === true &&
101
+ input.receipt.status === 'running' &&
102
+ typeof input.receipt.runId === 'string' &&
103
+ input.receipt.runId.trim() === input.currentRunId
104
+ );
105
+ }
106
+
44
107
  async function executeAndPersistReceipt<T>(input: {
45
108
  key: string;
46
109
  playName: string;
@@ -89,6 +152,9 @@ export async function runWorkerRuntimeReceiptBoundary<T>(
89
152
  input: RuntimeReceiptContext & {
90
153
  execute: () => Promise<T> | T;
91
154
  repairRunningReceiptForSameRun?: boolean;
155
+ repairRunningReceiptForSameRunAfterWaitTimeout?: boolean;
156
+ runningReceiptWaitMaxAttempts?: number;
157
+ runningReceiptWaitDelayMs?: number;
92
158
  reclaimRunning?: boolean;
93
159
  },
94
160
  ): Promise<T> {
@@ -104,14 +170,83 @@ export async function runWorkerRuntimeReceiptBoundary<T>(
104
170
  return receiptOutput<T>(claimed.receipt);
105
171
  }
106
172
  if (claimed.disposition === 'running') {
107
- return executeAndPersistReceipt({
108
- key,
109
- playName: input.playName,
110
- runId: input.runId,
111
- execute: input.execute,
112
- receiptStore,
113
- ownership: 'reconciled',
114
- });
173
+ if (
174
+ shouldRepairSameRunRunningReceipt({
175
+ repairRunningReceiptForSameRun: input.repairRunningReceiptForSameRun,
176
+ currentRunId: input.runId,
177
+ receipt: claimed.receipt,
178
+ })
179
+ ) {
180
+ const repaired = await receiptStore.claimReceipt({
181
+ playName: input.playName,
182
+ runId: input.runId,
183
+ key,
184
+ reclaimRunning: true,
185
+ });
186
+ if (repaired.disposition === 'reused') {
187
+ return receiptOutput<T>(repaired.receipt);
188
+ }
189
+ if (repaired.disposition === 'failed') {
190
+ throw new Error(
191
+ `Runtime receipt ${key} is failed and could not be repaired: ${repaired.receipt.error ?? 'unknown error'}`,
192
+ );
193
+ }
194
+ if (repaired.disposition === 'claimed') {
195
+ return executeAndPersistReceipt({
196
+ key,
197
+ playName: input.playName,
198
+ runId: input.runId,
199
+ execute: input.execute,
200
+ receiptStore,
201
+ ownership: 'claimed',
202
+ });
203
+ }
204
+ }
205
+ try {
206
+ return await waitForReusableReceipt<T>({
207
+ key,
208
+ playName: input.playName,
209
+ receiptStore,
210
+ maxAttempts: input.runningReceiptWaitMaxAttempts,
211
+ delayMs: input.runningReceiptWaitDelayMs,
212
+ });
213
+ } catch (error) {
214
+ if (
215
+ input.repairRunningReceiptForSameRunAfterWaitTimeout === true &&
216
+ error instanceof RuntimeReceiptWaitTimeoutError &&
217
+ shouldRepairSameRunRunningReceipt({
218
+ repairRunningReceiptForSameRun: true,
219
+ currentRunId: input.runId,
220
+ receipt: claimed.receipt,
221
+ })
222
+ ) {
223
+ const repaired = await receiptStore.claimReceipt({
224
+ playName: input.playName,
225
+ runId: input.runId,
226
+ key,
227
+ reclaimRunning: true,
228
+ });
229
+ if (repaired.disposition === 'reused') {
230
+ return receiptOutput<T>(repaired.receipt);
231
+ }
232
+ if (repaired.disposition === 'failed') {
233
+ throw new Error(
234
+ `Runtime receipt ${key} is failed and could not be repaired after wait timeout: ${repaired.receipt.error ?? 'unknown error'}`,
235
+ );
236
+ }
237
+ if (repaired.disposition === 'claimed') {
238
+ return executeAndPersistReceipt({
239
+ key,
240
+ playName: input.playName,
241
+ runId: input.runId,
242
+ execute: input.execute,
243
+ receiptStore,
244
+ ownership: 'claimed',
245
+ });
246
+ }
247
+ }
248
+ throw error;
249
+ }
115
250
  }
116
251
  if (claimed.disposition === 'failed') {
117
252
  throw new Error(
@@ -0,0 +1,104 @@
1
+ import {
2
+ markToolExecuteResultExecutionOutcome,
3
+ type ToolExecutionOutcome,
4
+ } from '../../../../shared_libs/play-runtime/tool-execution-outcome';
5
+
6
+ export type WorkerToolReceiptSelection = {
7
+ claimableReceiptKey: string | null;
8
+ forceDurableRefresh: boolean;
9
+ };
10
+
11
+ export type WorkerToolReceiptGroup<TRequest> = {
12
+ claimableReceiptKey: string;
13
+ forceDurableRefresh: boolean;
14
+ requests: TRequest[];
15
+ };
16
+
17
+ export type WorkerToolReceiptGroupPlan<TRequest> = {
18
+ localRequests: TRequest[];
19
+ durableGroups: WorkerToolReceiptGroup<TRequest>[];
20
+ };
21
+
22
+ export function canReclaimTimedOutWorkerToolReceipt(input: {
23
+ ownerRunId?: string | null;
24
+ currentRunId: string;
25
+ }): boolean {
26
+ const ownerRunId = input.ownerRunId?.trim();
27
+ const currentRunId = input.currentRunId.trim();
28
+ return Boolean(ownerRunId && currentRunId && ownerRunId === currentRunId);
29
+ }
30
+
31
+ export function selectWorkerToolReceipt(input: {
32
+ durableReceiptKey?: string | null;
33
+ localRetryCacheKey: string;
34
+ force: boolean;
35
+ allowLocalRetryReceipts: boolean;
36
+ }): WorkerToolReceiptSelection {
37
+ const durableReceiptKey = input.durableReceiptKey?.trim() || null;
38
+ const localRetryReceiptKey =
39
+ durableReceiptKey || !input.allowLocalRetryReceipts
40
+ ? null
41
+ : input.localRetryCacheKey.trim() || null;
42
+ return {
43
+ claimableReceiptKey: durableReceiptKey ?? localRetryReceiptKey,
44
+ forceDurableRefresh: input.force === true && durableReceiptKey !== null,
45
+ };
46
+ }
47
+
48
+ export function planWorkerToolReceiptGroups<TRequest>(
49
+ requests: TRequest[],
50
+ input: {
51
+ allowLocalRetryReceipts: boolean;
52
+ getReceiptInput: (request: TRequest) => {
53
+ durableReceiptKey?: string | null;
54
+ localRetryCacheKey: string;
55
+ force: boolean;
56
+ };
57
+ },
58
+ ): WorkerToolReceiptGroupPlan<TRequest> {
59
+ const localRequests: TRequest[] = [];
60
+ const groupsByKey = new Map<string, WorkerToolReceiptGroup<TRequest>>();
61
+ for (const request of requests) {
62
+ const { claimableReceiptKey, forceDurableRefresh } =
63
+ selectWorkerToolReceipt({
64
+ ...input.getReceiptInput(request),
65
+ allowLocalRetryReceipts: input.allowLocalRetryReceipts,
66
+ });
67
+ if (!claimableReceiptKey) {
68
+ localRequests.push(request);
69
+ continue;
70
+ }
71
+ const group = groupsByKey.get(claimableReceiptKey) ?? {
72
+ claimableReceiptKey,
73
+ forceDurableRefresh: false,
74
+ requests: [],
75
+ };
76
+ group.requests.push(request);
77
+ group.forceDurableRefresh ||= forceDurableRefresh;
78
+ groupsByKey.set(claimableReceiptKey, group);
79
+ }
80
+ return {
81
+ localRequests,
82
+ durableGroups: [...groupsByKey.values()],
83
+ };
84
+ }
85
+
86
+ export function markWorkerToolReceiptResultCached(
87
+ value: unknown,
88
+ cacheKey: string,
89
+ receiptKey = cacheKey,
90
+ ): unknown {
91
+ return markWorkerToolReceiptResultExecution(value, {
92
+ kind: 'cache',
93
+ cacheKey,
94
+ receiptKey,
95
+ attachedToReceiptKey: receiptKey,
96
+ });
97
+ }
98
+
99
+ export function markWorkerToolReceiptResultExecution(
100
+ value: unknown,
101
+ outcome: ToolExecutionOutcome,
102
+ ): unknown {
103
+ return markToolExecuteResultExecutionOutcome(value, outcome);
104
+ }
@@ -184,7 +184,6 @@ export type {
184
184
  PlayDatasetInput,
185
185
  PlayStepProgramStep,
186
186
  PrebuiltPlayRef,
187
- StaleAfterSeconds,
188
187
  StepOptions,
189
188
  StepProgram,
190
189
  StepProgramResolver,
@@ -300,24 +300,6 @@ export type ToolExecutionRequest = {
300
300
  staleAfterSeconds?: number;
301
301
  };
302
302
 
303
- /**
304
- * Freshness policy for dataset cells and step-program columns.
305
- *
306
- * Use a positive whole number of seconds for a fixed TTL. Use a function when
307
- * the next expiry depends on the value that was just produced. The function
308
- * receives the completed cell value; return a positive whole number of seconds
309
- * to set the next expiry, or `null` to keep that value indefinitely.
310
- *
311
- * Result-based policies are evaluated only for dataset/step-program cells. The
312
- * scalar `ctx.step`, `ctx.fetch`, `ctx.runPlay`, and `ctx.tools.execute` APIs
313
- * accept numeric TTLs.
314
- *
315
- * @sdkReference runtime 080
316
- */
317
- export type StaleAfterSeconds<Value = unknown> =
318
- | number
319
- | ((value: Value) => number | null);
320
-
321
303
  export type StepResolver<Row, Value> = (
322
304
  row: Row,
323
305
  ctx: DeeplinePlayRuntimeContext,
@@ -349,8 +331,7 @@ export type DatasetColumnRunInput<Row, Value> = {
349
331
  /**
350
332
  * Object-column form for `.withColumn(...)`.
351
333
  *
352
- * Use this when a column needs `runIf`, typed `previousCell`, or a
353
- * result-based `staleAfterSeconds(value)` policy.
334
+ * Use this when a column needs `runIf` or typed `previousCell`.
354
335
  *
355
336
  * @sdkReference runtime 100
356
337
  */
@@ -359,12 +340,6 @@ export type DatasetColumnDefinition<Row, Value> = {
359
340
  run: (input: DatasetColumnRunInput<Row, Value>) => Value | Promise<Value>;
360
341
  /** Optional row-level gate. Skipped rows produce `null` for this column. */
361
342
  readonly runIf?: (row: Row, index: number) => boolean | Promise<boolean>;
362
- /** Recompute this cell on each run instead of reusing its durable value. */
363
- readonly recompute?: boolean;
364
- /** Recompute this cell when its durable value is an error-shaped object. */
365
- readonly recomputeOnError?: boolean;
366
- /** Fixed or value-dependent freshness policy for this cell. */
367
- readonly staleAfterSeconds?: StaleAfterSeconds<Value>;
368
343
  };
369
344
 
370
345
  export type ConditionalStepResolver<Row, Value, Else = null> = {
@@ -385,12 +360,6 @@ export type ConditionalStepResolver<Row, Value, Else = null> = {
385
360
  export type StepOptions<Row, Value = unknown> = {
386
361
  /** Optional row-level gate. Skipped rows produce `null` for this column. */
387
362
  readonly runIf?: (row: Row, index: number) => boolean | Promise<boolean>;
388
- /** Recompute this cell on each run instead of reusing its durable value. */
389
- readonly recompute?: boolean;
390
- /** Recompute this cell when its durable value is an error-shaped object. */
391
- readonly recomputeOnError?: boolean;
392
- /** Fixed or value-dependent freshness policy for this cell. */
393
- readonly staleAfterSeconds?: StaleAfterSeconds<Value>;
394
363
  };
395
364
 
396
365
  export type StepProgram<Input, Output, Return = Output> = {
@@ -424,9 +393,6 @@ export type StepProgramResolver<Input, Return> = {
424
393
 
425
394
  export type PlayStepProgramStep = {
426
395
  readonly name: string;
427
- readonly recompute?: boolean;
428
- readonly recomputeOnError?: boolean;
429
- readonly staleAfterSeconds?: StaleAfterSeconds;
430
396
  readonly resolver:
431
397
  | StepResolver<Record<string, unknown>, unknown>
432
398
  | ConditionalStepResolver<Record<string, unknown>, unknown>
@@ -491,8 +457,7 @@ export type DatasetBuilder<
491
457
  /**
492
458
  * Define one output column with object-column authoring.
493
459
  *
494
- * Use this form for typed `previousCell` access or result-based
495
- * `staleAfterSeconds(value)` policies.
460
+ * Use this form for typed `previousCell` access.
496
461
  *
497
462
  * @param name - Output column name.
498
463
  * @param definition - Object-column definition.
@@ -507,7 +472,7 @@ export type DatasetBuilder<
507
472
  *
508
473
  * @param name - Output column name.
509
474
  * @param resolver - Computes the value for one row.
510
- * @param options - Row gate and freshness options.
475
+ * @param options - Row gate options.
511
476
  * @returns The same dataset builder with a nullable column type for skipped rows.
512
477
  */
513
478
  withColumn<Name extends string, Value>(
@@ -1218,16 +1183,6 @@ class DeeplineStepProgram<Input, Output, ReturnValue> implements StepProgram<
1218
1183
  {
1219
1184
  name,
1220
1185
  resolver: stepResolver as PlayStepProgramStep['resolver'],
1221
- ...(options?.staleAfterSeconds !== undefined
1222
- ? {
1223
- staleAfterSeconds:
1224
- options.staleAfterSeconds as PlayStepProgramStep['staleAfterSeconds'],
1225
- }
1226
- : {}),
1227
- ...(options?.recompute === true ? { recompute: true } : {}),
1228
- ...(options?.recomputeOnError === true
1229
- ? { recomputeOnError: true }
1230
- : {}),
1231
1186
  },
1232
1187
  ],
1233
1188
  this.returnResolver as StepResolver<
@@ -33,10 +33,13 @@ import type {
33
33
  PlayHarnessRpc,
34
34
  PreloadedRuntimeDbSessionInput,
35
35
  CompleteRuntimeReceiptInput,
36
+ CompleteRuntimeReceiptsInput,
36
37
  FailRuntimeReceiptInput,
38
+ FailRuntimeReceiptsInput,
37
39
  RuntimeApiCallInput,
38
40
  RuntimeApiCallResult,
39
41
  RuntimeReceiptInput,
42
+ RuntimeReceiptsInput,
40
43
  SheetDatasetRowsInput,
41
44
  SheetDatasetRowsResult,
42
45
  StagedFileChunkInput,
@@ -46,7 +49,6 @@ import type {
46
49
  WorkReceipt,
47
50
  WorkReceiptClaim,
48
51
  } from '../../../shared_libs/play-runtime/work-receipts';
49
- import type { CellStalenessPolicy } from '../../../shared_libs/play-runtime/cell-staleness';
50
52
 
51
53
  /**
52
54
  * Service-binding RPC stub shape — what `env.HARNESS` looks like inside
@@ -133,18 +135,42 @@ export async function harnessClaimRuntimeReceipt(
133
135
  return requireBinding().claimRuntimeReceipt(input);
134
136
  }
135
137
 
138
+ export async function harnessClaimRuntimeReceipts(
139
+ input: RuntimeReceiptsInput,
140
+ ): Promise<WorkReceiptClaim[]> {
141
+ return requireBinding().claimRuntimeReceipts(input);
142
+ }
143
+
144
+ export async function harnessGetRuntimeReceipt(
145
+ input: RuntimeReceiptInput,
146
+ ): Promise<WorkReceipt | null> {
147
+ return requireBinding().getRuntimeReceipt(input);
148
+ }
149
+
136
150
  export async function harnessCompleteRuntimeReceipt(
137
151
  input: CompleteRuntimeReceiptInput,
138
152
  ): Promise<WorkReceipt | null> {
139
153
  return requireBinding().completeRuntimeReceipt(input);
140
154
  }
141
155
 
156
+ export async function harnessCompleteRuntimeReceipts(
157
+ input: CompleteRuntimeReceiptsInput,
158
+ ): Promise<WorkReceipt[]> {
159
+ return requireBinding().completeRuntimeReceipts(input);
160
+ }
161
+
142
162
  export async function harnessFailRuntimeReceipt(
143
163
  input: FailRuntimeReceiptInput,
144
164
  ): Promise<WorkReceipt | null> {
145
165
  return requireBinding().failRuntimeReceipt(input);
146
166
  }
147
167
 
168
+ export async function harnessFailRuntimeReceipts(
169
+ input: FailRuntimeReceiptsInput,
170
+ ): Promise<WorkReceipt[]> {
171
+ return requireBinding().failRuntimeReceipts(input);
172
+ }
173
+
148
174
  /**
149
175
  * Read a bounded staged-file byte range through typed harness RPC. This is the
150
176
  * only staged-file data path for per-play Workers; there is intentionally no
@@ -192,7 +218,6 @@ export async function harnessStartSheetDataset(input: {
192
218
  runId: string;
193
219
  inputOffset?: number;
194
220
  userEmail?: string | null;
195
- cellPolicies?: Record<string, CellStalenessPolicy>;
196
221
  }): Promise<{
197
222
  inserted: number;
198
223
  skipped: number;
@@ -102,10 +102,10 @@ export const SDK_RELEASE = {
102
102
  // the SDK enrich generator's one-second stale policy.
103
103
  // 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
104
104
  // 0.1.111 ships dataset-native tool list getters and result row datasets.
105
- version: '0.1.153',
105
+ version: '0.1.154',
106
106
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
107
107
  supportPolicy: {
108
- latest: '0.1.153',
108
+ latest: '0.1.154',
109
109
  minimumSupported: '0.1.53',
110
110
  deprecatedBelow: '0.1.53',
111
111
  commandMinimumSupported: [
@@ -129,16 +129,6 @@ class WorkerStepProgram<Input, Output, ReturnValue> implements StepProgram<
129
129
  {
130
130
  name,
131
131
  resolver: stepResolver as PlayStepProgramStep['resolver'],
132
- ...(options?.staleAfterSeconds !== undefined
133
- ? {
134
- staleAfterSeconds:
135
- options.staleAfterSeconds as PlayStepProgramStep['staleAfterSeconds'],
136
- }
137
- : {}),
138
- ...(options?.recompute === true ? { recompute: true } : {}),
139
- ...(options?.recomputeOnError === true
140
- ? { recomputeOnError: true }
141
- : {}),
142
132
  },
143
133
  ],
144
134
  this.returnResolver as StepResolver<
@@ -1,3 +1,2 @@
1
- export * from './cell-policy';
2
1
  export * from './column-names';
3
2
  export * from './sheet-contract';