deepline 0.1.243 → 0.1.244

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 (71) hide show
  1. package/README.md +1 -1
  2. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +5 -25
  3. package/dist/bundling-sources/sdk/src/release.ts +23 -21
  4. package/dist/bundling-sources/sdk/src/types.ts +1 -1
  5. package/dist/bundling-sources/shared_libs/play-runtime/backend.ts +2 -21
  6. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +5 -6
  7. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +6 -13
  8. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +9 -26
  9. package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +1 -2
  10. package/dist/bundling-sources/shared_libs/play-runtime/map-row-identity.ts +1 -1
  11. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +191 -29
  12. package/dist/bundling-sources/shared_libs/play-runtime/play-latency-trace.ts +1 -1
  13. package/dist/bundling-sources/shared_libs/play-runtime/providers.ts +1 -36
  14. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +2 -3
  15. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/index.ts +0 -7
  16. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +1 -12
  17. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-pg.ts +2 -3
  18. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +5 -15
  19. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +6 -21
  20. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +3 -4
  21. package/dist/bundling-sources/shared_libs/plays/artifact-kind-guard.ts +16 -29
  22. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +4 -8
  23. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +21 -712
  24. package/dist/bundling-sources/shared_libs/plays/bundling/limits.ts +1 -18
  25. package/dist/cli/index.js +29 -71
  26. package/dist/cli/index.mjs +29 -71
  27. package/dist/{compiler-manifest-CYcwzSOJ.d.ts → compiler-manifest-DlE7dnRm.d.mts} +2 -8
  28. package/dist/{compiler-manifest-CYcwzSOJ.d.mts → compiler-manifest-DlE7dnRm.d.ts} +2 -8
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +24 -22
  32. package/dist/index.mjs +24 -22
  33. package/dist/plays/bundle-play-file.d.mts +7 -22
  34. package/dist/plays/bundle-play-file.d.ts +7 -22
  35. package/dist/plays/bundle-play-file.mjs +26 -614
  36. package/package.json +2 -2
  37. package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +0 -4504
  38. package/dist/bundling-sources/apps/play-runner-workers/src/dedup-do.ts +0 -1386
  39. package/dist/bundling-sources/apps/play-runner-workers/src/durable-object-deploy-handoff.ts +0 -30
  40. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +0 -8385
  41. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/README.md +0 -21
  42. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +0 -251
  43. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/coordinator-progress.ts +0 -289
  44. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/csv-rows.ts +0 -85
  45. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/customer-console.ts +0 -23
  46. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/dataset-handles.ts +0 -528
  47. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +0 -229
  48. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/ledger-event-batches.ts +0 -81
  49. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/live-progress.ts +0 -22
  50. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +0 -920
  51. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-latency-profile.ts +0 -90
  52. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/output-datasets.ts +0 -475
  53. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +0 -570
  54. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/result-dataset-persistence.ts +0 -50
  55. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/row-isolation.ts +0 -5
  56. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/run-work-dispatcher.ts +0 -519
  57. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -107
  58. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +0 -2541
  59. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-http-errors.ts +0 -7
  60. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +0 -227
  61. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/work-budget.ts +0 -130
  62. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/worker-platform-budget.ts +0 -39
  63. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/workflow-preview.ts +0 -26
  64. package/dist/bundling-sources/apps/play-runner-workers/src/runtime-api-retry.ts +0 -23
  65. package/dist/bundling-sources/apps/play-runner-workers/src/workflow-instance-create.ts +0 -47
  66. package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry-state.ts +0 -167
  67. package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry.ts +0 -91
  68. package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +0 -329
  69. package/dist/bundling-sources/sdk/src/worker-play-entry.ts +0 -240
  70. package/dist/bundling-sources/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +0 -252
  71. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -217
@@ -1,519 +0,0 @@
1
- import {
2
- shouldYieldWorkerWorkBudget,
3
- type WorkerWorkBudgetMeter,
4
- type WorkerWorkBudgetSnapshot,
5
- type WorkerWorkBudgetYieldLimits,
6
- type WorkerWorkBudgetYieldReason,
7
- } from './work-budget';
8
-
9
- export type WorkerMapWorkYield = {
10
- kind: 'map_chunk';
11
- mapName: string;
12
- nextChunkIndex: number;
13
- nextChunkStart: number;
14
- reason: WorkerWorkBudgetYieldReason;
15
- attempt: number;
16
- budget: WorkerWorkBudgetSnapshot;
17
- };
18
-
19
- export type WorkerMapWorkYieldResult = {
20
- // `freshBudget` means the yield crossed a real platform boundary that resets
21
- // the per-invocation resource budget (subrequests/CPU). Under Cloudflare
22
- // Workflows a completed `workflowStep.sleep` re-enters `run()` as a NEW
23
- // Worker invocation with a fresh per-invocation subrequest budget (completed
24
- // steps replay from the durable cache without re-issuing subrequests), so the
25
- // native workflow yield reports `true`. It is NOT keyed on isolate identity:
26
- // Cloudflare reuses warm isolates across invocations, so a fresh-budget
27
- // resume commonly shares the pre-sleep isolate. When no durable step boundary
28
- // is available (non-workflow execution), the yield cannot reset the platform
29
- // budget and reports `false`, which the dispatcher escalates and then fails
30
- // loudly instead of silently overflowing.
31
- freshBudget: boolean;
32
- };
33
-
34
- export type WorkerMapWorkBatch<TRawRow, TExecutableRow> = {
35
- rawRows: TRawRow[];
36
- rows: TExecutableRow[];
37
- chunkStart: number;
38
- chunkIndex: number;
39
- };
40
-
41
- export type WorkerRunWorkDispatcherTrace = {
42
- phase: string;
43
- ms?: number;
44
- extra?: Record<string, unknown>;
45
- };
46
-
47
- export type WorkerRunWorkDispatcherOptions = {
48
- budgetMeter: WorkerWorkBudgetMeter;
49
- nowMs: () => number;
50
- yieldLimits?: WorkerWorkBudgetYieldLimits;
51
- maxStaleYieldAttempts?: number;
52
- recordTrace?: (trace: WorkerRunWorkDispatcherTrace) => void;
53
- yieldBetweenChunks?: (
54
- yieldPoint: WorkerMapWorkYield,
55
- ) => Promise<WorkerMapWorkYieldResult>;
56
- };
57
-
58
- export type WorkerRunMapBatchesInput<TRawRow, TExecutableRow, TResult> = {
59
- mapName: string;
60
- chunks: AsyncIterable<TRawRow[]> | Iterable<TRawRow[]>;
61
- maxConcurrentChunks?: number;
62
- maxResidentBatchBytes?: number;
63
- prepareBatch: (
64
- rawRows: TRawRow[],
65
- chunkStart: number,
66
- chunkIndex: number,
67
- ) => TExecutableRow[];
68
- estimateRawBatchResidentBytes?: (
69
- rawRows: TRawRow[],
70
- chunkStart: number,
71
- chunkIndex: number,
72
- ) => number;
73
- executeBatch: (
74
- batch: WorkerMapWorkBatch<TRawRow, TExecutableRow>,
75
- ) => Promise<TResult>;
76
- estimateBatchSubrequests?: (
77
- batch: WorkerMapWorkBatch<TRawRow, TExecutableRow>,
78
- ) => number;
79
- estimateBatchResidentBytes?: (
80
- batch: WorkerMapWorkBatch<TRawRow, TExecutableRow>,
81
- ) => number;
82
- onBatchComplete: (
83
- result: TResult,
84
- batch: WorkerMapWorkBatch<TRawRow, TExecutableRow>,
85
- ) => Promise<boolean | void> | boolean | void;
86
- };
87
-
88
- export type WorkerRunMapBatchesResult = {
89
- chunksSeen: number;
90
- chunksExecuted: number;
91
- yieldPoints: WorkerMapWorkYield[];
92
- };
93
-
94
- export class WorkerBudgetExhaustedError extends Error {
95
- readonly mapName: string;
96
- readonly reason: WorkerWorkBudgetYieldReason;
97
- readonly attempts: number;
98
- readonly budget: WorkerWorkBudgetSnapshot;
99
-
100
- constructor(input: {
101
- mapName: string;
102
- reason: WorkerWorkBudgetYieldReason;
103
- attempts: number;
104
- budget: WorkerWorkBudgetSnapshot;
105
- }) {
106
- super(
107
- `Runtime dispatcher cannot continue ctx.dataset("${input.mapName}") after ${input.reason} budget pressure without a fresh platform budget.`,
108
- );
109
- this.name = 'WorkerBudgetExhaustedError';
110
- this.mapName = input.mapName;
111
- this.reason = input.reason;
112
- this.attempts = input.attempts;
113
- this.budget = input.budget;
114
- }
115
- }
116
-
117
- const DEFAULT_STALE_YIELD_ATTEMPTS = 3;
118
- export const WORKER_RUN_DISPATCHER_DEFAULT_MAX_RESIDENT_ROW_BYTES =
119
- 32 * 1024 * 1024;
120
-
121
- export class WorkerRunWorkDispatcher {
122
- constructor(private readonly options: WorkerRunWorkDispatcherOptions) {}
123
-
124
- private async yieldForBudgetPressure(input: {
125
- mapName: string;
126
- chunkIndex: number;
127
- chunkStart: number;
128
- reason: WorkerWorkBudgetYieldReason;
129
- snapshot: WorkerWorkBudgetSnapshot;
130
- startedAt: number;
131
- yieldPoints: WorkerMapWorkYield[];
132
- }): Promise<void> {
133
- const maxAttempts =
134
- this.options.maxStaleYieldAttempts ?? DEFAULT_STALE_YIELD_ATTEMPTS;
135
- for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
136
- const yieldPoint: WorkerMapWorkYield = {
137
- kind: 'map_chunk',
138
- mapName: input.mapName,
139
- nextChunkIndex: input.chunkIndex,
140
- nextChunkStart: input.chunkStart,
141
- reason: input.reason,
142
- attempt,
143
- budget: input.snapshot,
144
- };
145
- input.yieldPoints.push(yieldPoint);
146
- this.options.recordTrace?.({
147
- phase: 'runner.work_dispatcher.yield',
148
- ms: this.options.nowMs() - input.startedAt,
149
- extra: {
150
- mapName: input.mapName,
151
- nextChunkIndex: yieldPoint.nextChunkIndex,
152
- nextChunkStart: yieldPoint.nextChunkStart,
153
- reason: yieldPoint.reason,
154
- attempt: yieldPoint.attempt,
155
- budgetCounts: yieldPoint.budget.counts,
156
- elapsedMs: yieldPoint.budget.elapsedMs,
157
- },
158
- });
159
- const yieldResult = await this.options.yieldBetweenChunks?.(yieldPoint);
160
- if (yieldResult?.freshBudget) {
161
- this.options.budgetMeter.resetWindow();
162
- return;
163
- }
164
- this.options.recordTrace?.({
165
- phase: 'runner.work_dispatcher.stale_yield',
166
- ms: this.options.nowMs() - input.startedAt,
167
- extra: {
168
- mapName: input.mapName,
169
- nextChunkIndex: yieldPoint.nextChunkIndex,
170
- nextChunkStart: yieldPoint.nextChunkStart,
171
- reason: yieldPoint.reason,
172
- attempt: yieldPoint.attempt,
173
- },
174
- });
175
- if (attempt === maxAttempts - 1) {
176
- throw new WorkerBudgetExhaustedError({
177
- mapName: input.mapName,
178
- reason: yieldPoint.reason,
179
- attempts: maxAttempts,
180
- budget: yieldPoint.budget,
181
- });
182
- }
183
- }
184
- }
185
-
186
- async runMapBatches<TRawRow, TExecutableRow, TResult>(
187
- input: WorkerRunMapBatchesInput<TRawRow, TExecutableRow, TResult>,
188
- ): Promise<WorkerRunMapBatchesResult> {
189
- const startedAt = this.options.nowMs();
190
- const maxConcurrentChunks = Math.max(
191
- 1,
192
- Math.floor(input.maxConcurrentChunks ?? 1),
193
- );
194
- let chunkStart = 0;
195
- let chunkIndex = 0;
196
- let chunksSeen = 0;
197
- let chunksExecuted = 0;
198
- const yieldPoints: WorkerMapWorkYield[] = [];
199
- const iterator = toAsyncIterator(input.chunks);
200
- let next: IteratorResult<TRawRow[]> | null = null;
201
- const maxResidentBatchBytes =
202
- input.maxResidentBatchBytes ??
203
- WORKER_RUN_DISPATCHER_DEFAULT_MAX_RESIDENT_ROW_BYTES;
204
- const peekNext = async (): Promise<IteratorResult<TRawRow[]>> => {
205
- next ??= await iterator.next();
206
- return next;
207
- };
208
- const consumeNext = () => {
209
- next = null;
210
- };
211
- type InFlightChunk = {
212
- batch: WorkerMapWorkBatch<TRawRow, TExecutableRow>;
213
- projectedSubrequests: number;
214
- residentBytes: number;
215
- result: Promise<TResult>;
216
- };
217
- const inFlight: InFlightChunk[] = [];
218
- let shouldStop = false;
219
- const inFlightResidentBytes = () =>
220
- inFlight.reduce((total, chunk) => total + chunk.residentBytes, 0);
221
- const estimateResidentBytes = (
222
- batch: WorkerMapWorkBatch<TRawRow, TExecutableRow>,
223
- ): number =>
224
- Math.max(0, Math.floor(input.estimateBatchResidentBytes?.(batch) ?? 0));
225
- const estimateRawResidentBytes = (
226
- rawRows: TRawRow[],
227
- start: number,
228
- index: number,
229
- ): number =>
230
- Math.max(
231
- 0,
232
- Math.floor(
233
- input.estimateRawBatchResidentBytes?.(rawRows, start, index) ?? 0,
234
- ),
235
- );
236
-
237
- const launchAvailableChunks = async () => {
238
- while (
239
- maxConcurrentChunks > 1 &&
240
- !shouldStop &&
241
- inFlight.length < maxConcurrentChunks
242
- ) {
243
- const admissionYieldDecision = shouldYieldWorkerWorkBudget({
244
- meter: this.options.budgetMeter,
245
- limits: this.options.yieldLimits,
246
- });
247
- if (
248
- admissionYieldDecision.shouldYield &&
249
- admissionYieldDecision.reason
250
- ) {
251
- if (inFlight.length > 0) return;
252
- await this.yieldForBudgetPressure({
253
- mapName: input.mapName,
254
- chunkIndex,
255
- chunkStart,
256
- reason: admissionYieldDecision.reason,
257
- snapshot: admissionYieldDecision.snapshot,
258
- startedAt,
259
- yieldPoints,
260
- });
261
- continue;
262
- }
263
- const current = await peekNext();
264
- if (current.done) return;
265
- const rawRows = current.value;
266
- if (rawRows.length === 0) {
267
- chunksSeen += 1;
268
- consumeNext();
269
- continue;
270
- }
271
- const rawResidentBytes = estimateRawResidentBytes(
272
- rawRows,
273
- chunkStart,
274
- chunkIndex,
275
- );
276
- if (
277
- rawResidentBytes > 0 &&
278
- inFlightResidentBytes() + rawResidentBytes > maxResidentBatchBytes
279
- ) {
280
- if (inFlight.length > 0) return;
281
- throw new WorkerResidentRowBudgetExceededError({
282
- mapName: input.mapName,
283
- chunkIndex,
284
- residentBytes: rawResidentBytes,
285
- limitBytes: maxResidentBatchBytes,
286
- });
287
- }
288
- const rows = input.prepareBatch(rawRows, chunkStart, chunkIndex);
289
- if (rows.length === 0) {
290
- chunksSeen += 1;
291
- consumeNext();
292
- chunkStart += rawRows.length;
293
- continue;
294
- }
295
- const batch = {
296
- rawRows,
297
- rows,
298
- chunkStart,
299
- chunkIndex,
300
- };
301
- const residentBytes = estimateResidentBytes(batch);
302
- const projectedResidentBytes = inFlightResidentBytes() + residentBytes;
303
- if (projectedResidentBytes > maxResidentBatchBytes) {
304
- if (inFlight.length > 0) return;
305
- throw new WorkerResidentRowBudgetExceededError({
306
- mapName: input.mapName,
307
- chunkIndex,
308
- residentBytes,
309
- limitBytes: maxResidentBatchBytes,
310
- });
311
- }
312
- const projectedSubrequests = Math.max(
313
- 0,
314
- Math.floor(input.estimateBatchSubrequests?.(batch) ?? 0),
315
- );
316
- const alreadyProjected = inFlight.reduce(
317
- (total, chunk) => total + chunk.projectedSubrequests,
318
- 0,
319
- );
320
- const preChunkYieldDecision = shouldYieldWorkerWorkBudget({
321
- meter: this.options.budgetMeter,
322
- limits: this.options.yieldLimits,
323
- projectedSubrequests: alreadyProjected + projectedSubrequests,
324
- });
325
- if (preChunkYieldDecision.shouldYield && preChunkYieldDecision.reason) {
326
- if (inFlight.length > 0) return;
327
- await this.yieldForBudgetPressure({
328
- mapName: input.mapName,
329
- chunkIndex,
330
- chunkStart,
331
- reason: preChunkYieldDecision.reason,
332
- snapshot: preChunkYieldDecision.snapshot,
333
- startedAt,
334
- yieldPoints,
335
- });
336
- }
337
- const result = input.executeBatch(batch);
338
- result.catch(() => undefined);
339
- inFlight.push({
340
- batch,
341
- projectedSubrequests,
342
- residentBytes,
343
- result,
344
- });
345
- chunksSeen += 1;
346
- consumeNext();
347
- chunkStart += rawRows.length;
348
- chunkIndex += 1;
349
- }
350
- };
351
-
352
- if (maxConcurrentChunks <= 1) {
353
- while (true) {
354
- const current = await peekNext();
355
- if (current.done) break;
356
- const rawRows = current.value;
357
- chunksSeen += 1;
358
- consumeNext();
359
- if (rawRows.length === 0) {
360
- continue;
361
- }
362
- const rows = input.prepareBatch(rawRows, chunkStart, chunkIndex);
363
- if (rows.length === 0) {
364
- chunkStart += rawRows.length;
365
- continue;
366
- }
367
- const batch = {
368
- rawRows,
369
- rows,
370
- chunkStart,
371
- chunkIndex,
372
- };
373
- const preChunkYieldDecision = shouldYieldWorkerWorkBudget({
374
- meter: this.options.budgetMeter,
375
- limits: this.options.yieldLimits,
376
- projectedSubrequests: input.estimateBatchSubrequests?.(batch),
377
- });
378
- if (preChunkYieldDecision.shouldYield && preChunkYieldDecision.reason) {
379
- await this.yieldForBudgetPressure({
380
- mapName: input.mapName,
381
- chunkIndex,
382
- chunkStart,
383
- reason: preChunkYieldDecision.reason,
384
- snapshot: preChunkYieldDecision.snapshot,
385
- startedAt,
386
- yieldPoints,
387
- });
388
- }
389
- const result = await input.executeBatch(batch);
390
- chunksExecuted += 1;
391
- const shouldStop = await input.onBatchComplete(result, batch);
392
- chunkStart += rawRows.length;
393
- chunkIndex += 1;
394
- if (shouldStop === true) break;
395
- const upcoming = await peekNext();
396
-
397
- const yieldDecision = shouldYieldWorkerWorkBudget({
398
- meter: this.options.budgetMeter,
399
- limits: this.options.yieldLimits,
400
- });
401
- if (
402
- !upcoming.done &&
403
- yieldDecision.shouldYield &&
404
- yieldDecision.reason
405
- ) {
406
- await this.yieldForBudgetPressure({
407
- mapName: input.mapName,
408
- chunkIndex,
409
- chunkStart,
410
- reason: yieldDecision.reason,
411
- snapshot: yieldDecision.snapshot,
412
- startedAt,
413
- yieldPoints,
414
- });
415
- }
416
- }
417
- } else {
418
- // Bounded worker pool: keep up to K `executeBatch` calls in flight, but
419
- // funnel their results through a single serialized `onBatchComplete` chain
420
- // in submission (FIFO) order so counter aggregation, preview/cache
421
- // ordering, and progress ordering stay deterministic regardless of which
422
- // chunk's provider work settles first.
423
- let pendingError: unknown = null;
424
- const drainInFlight = async () => {
425
- if (inFlight.length > 0) {
426
- await Promise.allSettled(inFlight.map((chunk) => chunk.result));
427
- }
428
- };
429
- const launchOrAbort = async () => {
430
- try {
431
- await launchAvailableChunks();
432
- } catch (error) {
433
- pendingError = error;
434
- shouldStop = true;
435
- await drainInFlight();
436
- throw error;
437
- }
438
- };
439
- await launchOrAbort();
440
- while (inFlight.length > 0) {
441
- const nextChunk = inFlight.shift()!;
442
- try {
443
- const result = await nextChunk.result;
444
- chunksExecuted += 1;
445
- const batchShouldStop = await input.onBatchComplete(
446
- result,
447
- nextChunk.batch,
448
- );
449
- if (batchShouldStop === true) {
450
- shouldStop = true;
451
- }
452
- } catch (error) {
453
- // A chunk error aborts the map (matching the sequential path), but we
454
- // fail loud only after the chunks already in flight settle so no
455
- // detached executeBatch promise keeps writing behind our back.
456
- pendingError = error;
457
- shouldStop = true;
458
- break;
459
- }
460
- if (!shouldStop) {
461
- await launchOrAbort();
462
- }
463
- }
464
- await drainInFlight();
465
- if (pendingError) throw pendingError;
466
- }
467
-
468
- this.options.recordTrace?.({
469
- phase: 'runner.work_dispatcher.total',
470
- ms: this.options.nowMs() - startedAt,
471
- extra: {
472
- mapName: input.mapName,
473
- chunksSeen,
474
- chunksExecuted,
475
- maxConcurrentChunks,
476
- yieldPoints: yieldPoints.length,
477
- },
478
- });
479
-
480
- return { chunksSeen, chunksExecuted, yieldPoints };
481
- }
482
- }
483
-
484
- export class WorkerResidentRowBudgetExceededError extends Error {
485
- readonly mapName: string;
486
- readonly chunkIndex: number;
487
- readonly residentBytes: number;
488
- readonly limitBytes: number;
489
-
490
- constructor(input: {
491
- mapName: string;
492
- chunkIndex: number;
493
- residentBytes: number;
494
- limitBytes: number;
495
- }) {
496
- super(
497
- `Runtime dispatcher cannot admit ctx.dataset("${input.mapName}") chunk ${input.chunkIndex}: estimated resident row payload ${input.residentBytes} bytes exceeds the ${input.limitBytes} byte cap.`,
498
- );
499
- this.name = 'WorkerResidentRowBudgetExceededError';
500
- this.mapName = input.mapName;
501
- this.chunkIndex = input.chunkIndex;
502
- this.residentBytes = input.residentBytes;
503
- this.limitBytes = input.limitBytes;
504
- }
505
- }
506
-
507
- function toAsyncIterator<T>(
508
- input: AsyncIterable<T> | Iterable<T>,
509
- ): AsyncIterator<T> {
510
- if (Symbol.asyncIterator in input) {
511
- return input[Symbol.asyncIterator]();
512
- }
513
- const iterator = input[Symbol.iterator]();
514
- return {
515
- async next() {
516
- return iterator.next();
517
- },
518
- };
519
- }
@@ -1,107 +0,0 @@
1
- /**
2
- * Per-play Worker tool batch executor.
3
- *
4
- * This is intentionally local to the Worker bundle. Pulling the shared
5
- * executor module back in would widen the bundle graph for a tiny helper.
6
- */
7
-
8
- export type ToolBatchRequest = {
9
- runId: string;
10
- orgId: string;
11
- toolId: string;
12
- operation: string;
13
- provider: string;
14
- items: Array<{
15
- itemKey: string;
16
- payload: Record<string, unknown>;
17
- inputHash?: string | null;
18
- }>;
19
- waterfallId?: string | null;
20
- stageId?: string | null;
21
- fieldName?: string | null;
22
- mapName?: string | null;
23
- chunkIndex?: number | null;
24
- userProvidedRateLimitKey?: string | null;
25
- providerBatchSize: number;
26
- };
27
-
28
- type ToolBatchItemResult = {
29
- itemKey: string;
30
- result: unknown;
31
- cached?: boolean;
32
- };
33
-
34
- export function createToolBatchExecutor(input: {
35
- executeProviderBatch(batch: {
36
- request: ToolBatchRequest;
37
- batchIndex: number;
38
- idempotencyKeys: string[];
39
- rateLimitKey: string;
40
- items: ToolBatchRequest['items'];
41
- }): Promise<ToolBatchItemResult[]>;
42
- }) {
43
- return {
44
- async executeToolBatch(request: ToolBatchRequest) {
45
- const providerBatchSize = Math.max(
46
- 1,
47
- Math.floor(request.providerBatchSize),
48
- );
49
- const batches: Array<ToolBatchRequest['items']> = [];
50
- for (
51
- let index = 0;
52
- index < request.items.length;
53
- index += providerBatchSize
54
- ) {
55
- batches.push(request.items.slice(index, index + providerBatchSize));
56
- }
57
- const results: ToolBatchItemResult[] = [];
58
- for (let batchIndex = 0; batchIndex < batches.length; batchIndex += 1) {
59
- const items = batches[batchIndex]!;
60
- results.push(
61
- ...(await input.executeProviderBatch({
62
- request,
63
- batchIndex,
64
- items,
65
- rateLimitKey: [
66
- request.orgId,
67
- request.provider,
68
- request.operation,
69
- request.userProvidedRateLimitKey ?? '',
70
- ].join(':'),
71
- idempotencyKeys: items.map((item) =>
72
- [
73
- request.runId,
74
- request.mapName ?? '',
75
- request.chunkIndex ?? '',
76
- item.itemKey,
77
- request.fieldName ?? '',
78
- request.waterfallId ?? '',
79
- request.stageId ?? '',
80
- item.inputHash ?? stableStringify(item.payload),
81
- ].join(':'),
82
- ),
83
- })),
84
- );
85
- }
86
- return {
87
- runId: request.runId,
88
- toolId: request.toolId,
89
- operation: request.operation,
90
- provider: request.provider,
91
- batchCount: batches.length,
92
- itemCount: request.items.length,
93
- results,
94
- };
95
- },
96
- };
97
- }
98
-
99
- function stableStringify(value: unknown): string {
100
- if (value === null || typeof value !== 'object') return JSON.stringify(value);
101
- if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`;
102
- const record = value as Record<string, unknown>;
103
- return `{${Object.keys(record)
104
- .sort()
105
- .map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`)
106
- .join(',')}}`;
107
- }