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.
- package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +15 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +1180 -825
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +34 -18
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +41 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +143 -8
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +104 -0
- package/dist/bundling-sources/sdk/src/index.ts +0 -1
- package/dist/bundling-sources/sdk/src/play.ts +3 -48
- package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +27 -2
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/sdk/src/worker-play-entry.ts +0 -10
- package/dist/bundling-sources/shared_libs/play-data-plane/index.ts +0 -1
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +87 -0
- package/dist/bundling-sources/shared_libs/play-runtime/batch-runtime.ts +0 -59
- package/dist/bundling-sources/shared_libs/play-runtime/cell-staleness.ts +0 -253
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +805 -1570
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +47 -74
- package/dist/bundling-sources/shared_libs/play-runtime/default-batch-strategies.ts +36 -14
- package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +145 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +284 -0
- package/dist/bundling-sources/shared_libs/play-runtime/postgres-json.ts +12 -5
- package/dist/bundling-sources/shared_libs/play-runtime/run-lifecycle-policy.ts +78 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +10 -45
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +923 -535
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +45 -76
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +12 -1
- package/dist/bundling-sources/shared_libs/play-runtime/step-program-dataset-builder.ts +1 -14
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execution-outcome.ts +159 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result-types.ts +4 -1
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +32 -0
- package/dist/bundling-sources/shared_libs/plays/definition.ts +4 -2
- package/dist/bundling-sources/shared_libs/plays/runtime-validation.ts +3 -14
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +1 -43
- package/dist/cli/index.js +1301 -399
- package/dist/cli/index.mjs +1269 -361
- package/dist/{compiler-manifest-BjoRENv9.d.ts → compiler-manifest-DW1flrHk.d.mts} +0 -9
- package/dist/{compiler-manifest-BjoRENv9.d.mts → compiler-manifest-DW1flrHk.d.ts} +0 -9
- package/dist/index.d.mts +9 -38
- package/dist/index.d.ts +9 -38
- package/dist/index.js +22 -11
- package/dist/index.mjs +22 -11
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/package.json +1 -1
- package/dist/bundling-sources/shared_libs/play-data-plane/cell-policy.ts +0 -76
- package/dist/bundling-sources/shared_libs/play-runtime/progress-emitter.ts +0 -197
- 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
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
+
}
|
|
@@ -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
|
|
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
|
|
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
|
|
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.
|
|
105
|
+
version: '0.1.154',
|
|
106
106
|
apiContract: '2026-06-dataset-handle-results-hard-cutover',
|
|
107
107
|
supportPolicy: {
|
|
108
|
-
latest: '0.1.
|
|
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<
|