deepline 0.1.12 → 0.1.19
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/README.md +14 -6
- package/dist/cli/index.js +1298 -711
- package/dist/cli/index.mjs +1294 -707
- package/dist/index.d.mts +199 -23
- package/dist/index.d.ts +199 -23
- package/dist/index.js +219 -13
- package/dist/index.mjs +219 -13
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +68 -12
- package/dist/repo/apps/play-runner-workers/src/entry.ts +241 -51
- package/dist/repo/sdk/src/client.ts +237 -0
- package/dist/repo/sdk/src/config.ts +125 -8
- package/dist/repo/sdk/src/http.ts +10 -2
- package/dist/repo/sdk/src/play.ts +19 -36
- package/dist/repo/sdk/src/plays/bundle-play-file.ts +22 -8
- package/dist/repo/sdk/src/plays/local-file-discovery.ts +207 -160
- package/dist/repo/sdk/src/types.ts +25 -0
- package/dist/repo/sdk/src/version.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +237 -145
- package/dist/repo/shared_libs/plays/bundling/index.ts +206 -229
- package/dist/repo/shared_libs/plays/dataset.ts +28 -0
- package/package.json +5 -4
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/index.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/repo/apps/play-runner-workers/src/runtime/README.md +0 -21
- package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +0 -177
- package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +0 -52
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -100
- package/dist/repo/sdk/src/cli/commands/auth.ts +0 -500
- package/dist/repo/sdk/src/cli/commands/billing.ts +0 -188
- package/dist/repo/sdk/src/cli/commands/csv.ts +0 -123
- package/dist/repo/sdk/src/cli/commands/db.ts +0 -119
- package/dist/repo/sdk/src/cli/commands/feedback.ts +0 -40
- package/dist/repo/sdk/src/cli/commands/org.ts +0 -117
- package/dist/repo/sdk/src/cli/commands/play.ts +0 -3441
- package/dist/repo/sdk/src/cli/commands/tools.ts +0 -687
- package/dist/repo/sdk/src/cli/dataset-stats.ts +0 -415
- package/dist/repo/sdk/src/cli/index.ts +0 -148
- package/dist/repo/sdk/src/cli/progress.ts +0 -149
- package/dist/repo/sdk/src/cli/skills-sync.ts +0 -141
- package/dist/repo/sdk/src/cli/trace.ts +0 -61
- package/dist/repo/sdk/src/cli/utils.ts +0 -145
- package/dist/repo/sdk/src/compat.ts +0 -77
- package/dist/repo/shared_libs/observability/node-tracing.ts +0 -129
- package/dist/repo/shared_libs/observability/tracing.ts +0 -98
- package/dist/repo/shared_libs/play-runtime/context.ts +0 -4242
- package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +0 -250
- package/dist/repo/shared_libs/play-runtime/ctx-types.ts +0 -725
- package/dist/repo/shared_libs/play-runtime/dataset-id.ts +0 -10
- package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +0 -304
- package/dist/repo/shared_libs/play-runtime/db-session.ts +0 -462
- package/dist/repo/shared_libs/play-runtime/live-events.ts +0 -214
- package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +0 -50
- package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +0 -114
- package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +0 -158
- package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +0 -172
- package/dist/repo/shared_libs/play-runtime/protocol.ts +0 -121
- package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +0 -42
- package/dist/repo/shared_libs/play-runtime/result-normalization.ts +0 -33
- package/dist/repo/shared_libs/play-runtime/runtime-api.ts +0 -1873
- package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +0 -2
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -201
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +0 -48
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +0 -84
- package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +0 -147
- package/dist/repo/shared_libs/play-runtime/suspension.ts +0 -68
- package/dist/repo/shared_libs/play-runtime/tracing.ts +0 -31
- package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +0 -75
- package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +0 -140
- package/dist/repo/shared_libs/plays/artifact-transport.ts +0 -14
- package/dist/repo/shared_libs/plays/artifact-types.ts +0 -49
- package/dist/repo/shared_libs/plays/compiler-manifest.ts +0 -186
- package/dist/repo/shared_libs/plays/definition.ts +0 -264
- package/dist/repo/shared_libs/plays/file-refs.ts +0 -11
- package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +0 -206
- package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +0 -164
- package/dist/repo/shared_libs/plays/runtime-validation.ts +0 -395
- package/dist/repo/shared_libs/temporal/constants.ts +0 -39
- package/dist/repo/shared_libs/temporal/preview-config.ts +0 -153
|
@@ -204,11 +204,18 @@ type WorkerEnv = {
|
|
|
204
204
|
* loud error. Loud failures > silent fallbacks.
|
|
205
205
|
*/
|
|
206
206
|
HARNESS?: import('../../play-harness-worker/src/rpc-types').PlayHarnessRpc;
|
|
207
|
+
VERCEL_PROTECTION_BYPASS_TOKEN?: string;
|
|
207
208
|
};
|
|
208
209
|
|
|
209
210
|
let cachedRuntimeApiBinding: WorkerEnv['RUNTIME_API'] | null = null;
|
|
211
|
+
let cachedRuntimeApiVercelBypassToken: string | null = null;
|
|
210
212
|
function captureRuntimeApiBinding(env: WorkerEnv): void {
|
|
211
213
|
cachedRuntimeApiBinding = env.RUNTIME_API ?? null;
|
|
214
|
+
cachedRuntimeApiVercelBypassToken =
|
|
215
|
+
typeof env.VERCEL_PROTECTION_BYPASS_TOKEN === 'string' &&
|
|
216
|
+
env.VERCEL_PROTECTION_BYPASS_TOKEN.trim()
|
|
217
|
+
? env.VERCEL_PROTECTION_BYPASS_TOKEN.trim()
|
|
218
|
+
: null;
|
|
212
219
|
}
|
|
213
220
|
|
|
214
221
|
let cachedCoordinatorBinding: WorkerEnv['COORDINATOR'] | null = null;
|
|
@@ -288,22 +295,20 @@ async function probeHarnessOnce(
|
|
|
288
295
|
}
|
|
289
296
|
}
|
|
290
297
|
/**
|
|
291
|
-
* Routes runtime API requests through the in-process RUNTIME_API binding
|
|
292
|
-
*
|
|
298
|
+
* Routes runtime API requests through the in-process RUNTIME_API binding when
|
|
299
|
+
* Cloudflare exposes the coordinator WorkerEntrypoint export. Some workflow
|
|
300
|
+
* execution paths do not expose those exports; there we keep the older public
|
|
301
|
+
* fetch transport so the play still reaches the same authenticated handler.
|
|
293
302
|
*/
|
|
294
303
|
const RUNTIME_API_TIMEOUT_MS = 30_000;
|
|
295
304
|
const RUNTIME_API_PLAY_RUN_TIMEOUT_MS = 75_000;
|
|
305
|
+
let loggedMissingRuntimeApiBinding = false;
|
|
296
306
|
|
|
297
307
|
async function fetchRuntimeApi(
|
|
298
308
|
baseUrl: string,
|
|
299
309
|
path: string,
|
|
300
310
|
init: RequestInit,
|
|
301
311
|
): Promise<Response> {
|
|
302
|
-
if (!cachedRuntimeApiBinding) {
|
|
303
|
-
throw new Error(
|
|
304
|
-
`[play-harness] RUNTIME_API binding missing — coordinator did not wire it before invoking the play. path=${path}`,
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
312
|
const timeoutMs =
|
|
308
313
|
path === '/api/v2/plays/run'
|
|
309
314
|
? RUNTIME_API_PLAY_RUN_TIMEOUT_MS
|
|
@@ -313,16 +318,25 @@ async function fetchRuntimeApi(
|
|
|
313
318
|
try {
|
|
314
319
|
const mergedInit: RequestInit = {
|
|
315
320
|
...init,
|
|
321
|
+
headers: runtimeApiHeaders(init.headers, cachedRuntimeApiBinding == null),
|
|
316
322
|
signal: controller.signal,
|
|
317
323
|
};
|
|
318
|
-
|
|
319
|
-
|
|
324
|
+
if (!cachedRuntimeApiBinding) {
|
|
325
|
+
if (!loggedMissingRuntimeApiBinding) {
|
|
326
|
+
loggedMissingRuntimeApiBinding = true;
|
|
327
|
+
console.warn(
|
|
328
|
+
`[play-harness] RUNTIME_API binding missing; using public runtime API transport. path=${path}`,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
return await fetch(`${baseUrl.replace(/\/$/, '')}${path}`, mergedInit);
|
|
332
|
+
}
|
|
333
|
+
return await cachedRuntimeApiBinding.fetch(
|
|
334
|
+
new Request(`${baseUrl.replace(/\/$/, '')}${path}`, mergedInit),
|
|
320
335
|
);
|
|
321
|
-
return res;
|
|
322
336
|
} catch (err) {
|
|
323
337
|
if (err instanceof Error && err.name === 'AbortError') {
|
|
324
338
|
throw new Error(
|
|
325
|
-
`[play-harness]
|
|
339
|
+
`[play-harness] runtime API call timed out after ${timeoutMs}ms. path=${path} baseUrl=${baseUrl}`,
|
|
326
340
|
);
|
|
327
341
|
}
|
|
328
342
|
throw err;
|
|
@@ -331,6 +345,24 @@ async function fetchRuntimeApi(
|
|
|
331
345
|
}
|
|
332
346
|
}
|
|
333
347
|
|
|
348
|
+
function runtimeApiHeaders(
|
|
349
|
+
headers: HeadersInit | undefined,
|
|
350
|
+
includeVercelBypass: boolean,
|
|
351
|
+
): Headers {
|
|
352
|
+
const next = new Headers(headers);
|
|
353
|
+
if (includeVercelBypass) {
|
|
354
|
+
const bypassToken = cachedVercelProtectionBypassToken();
|
|
355
|
+
if (bypassToken) {
|
|
356
|
+
next.set('x-vercel-protection-bypass', bypassToken);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return next;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function cachedVercelProtectionBypassToken(): string | null {
|
|
363
|
+
return cachedRuntimeApiVercelBypassToken;
|
|
364
|
+
}
|
|
365
|
+
|
|
334
366
|
const WORKER_PLAY_CALL_LIMITS = {
|
|
335
367
|
maxPlayCallDepth: 6,
|
|
336
368
|
maxPlayCallCount: 32,
|
|
@@ -350,6 +382,20 @@ function makeWorkerDataset<T extends Record<string, unknown>>(
|
|
|
350
382
|
count?: number;
|
|
351
383
|
datasetKind?: 'csv' | 'map';
|
|
352
384
|
cacheSummary?: string | null;
|
|
385
|
+
workProgress?: {
|
|
386
|
+
total: number;
|
|
387
|
+
executed: number;
|
|
388
|
+
reused: number;
|
|
389
|
+
skipped: number;
|
|
390
|
+
pending: number;
|
|
391
|
+
failed: number;
|
|
392
|
+
degraded?: boolean;
|
|
393
|
+
duplicates?: {
|
|
394
|
+
exact?: number;
|
|
395
|
+
semantic?: number;
|
|
396
|
+
rejected?: number;
|
|
397
|
+
};
|
|
398
|
+
};
|
|
353
399
|
},
|
|
354
400
|
): T[] & {
|
|
355
401
|
count(): Promise<number>;
|
|
@@ -363,6 +409,7 @@ function makeWorkerDataset<T extends Record<string, unknown>>(
|
|
|
363
409
|
const count = Math.max(0, Math.floor(options?.count ?? rows.length));
|
|
364
410
|
const datasetKind = options?.datasetKind ?? 'map';
|
|
365
411
|
const cacheSummary = options?.cacheSummary ?? null;
|
|
412
|
+
const workProgress = options?.workProgress;
|
|
366
413
|
// Build the array result. JSON.stringify on arrays calls toJSON only if
|
|
367
414
|
// present on the array itself — we attach below. The dataset metadata is
|
|
368
415
|
// also exposed via own properties so plays can `enriched.count()` etc.
|
|
@@ -415,6 +462,10 @@ function makeWorkerDataset<T extends Record<string, unknown>>(
|
|
|
415
462
|
value: cacheSummary,
|
|
416
463
|
enumerable: false,
|
|
417
464
|
});
|
|
465
|
+
Object.defineProperty(arr, '__deeplineWorkProgress', {
|
|
466
|
+
value: workProgress,
|
|
467
|
+
enumerable: false,
|
|
468
|
+
});
|
|
418
469
|
// Plays often `return { rows: dataset, count: N }`. JSON.stringify on the
|
|
419
470
|
// array would normally produce `[row, row, ...]` — we want the dataset
|
|
420
471
|
// envelope shape instead so assertions seeing `result.rows.columns` pass.
|
|
@@ -435,6 +486,9 @@ function makeWorkerDataset<T extends Record<string, unknown>>(
|
|
|
435
486
|
preview: plainRows,
|
|
436
487
|
tableNamespace: name,
|
|
437
488
|
...(cacheSummary ? { cacheSummary } : {}),
|
|
489
|
+
...(workProgress
|
|
490
|
+
? { _metadata: { workProgress } }
|
|
491
|
+
: {}),
|
|
438
492
|
};
|
|
439
493
|
},
|
|
440
494
|
enumerable: false,
|
|
@@ -454,6 +508,7 @@ type RunnerEvent =
|
|
|
454
508
|
| { type: 'error'; message: string; stack?: string; ts: number };
|
|
455
509
|
|
|
456
510
|
type WorkflowRunOutput = {
|
|
511
|
+
playName: string;
|
|
457
512
|
result: unknown;
|
|
458
513
|
outputRows: number;
|
|
459
514
|
durationMs: number;
|
|
@@ -469,7 +524,12 @@ function makeRequestId(): string {
|
|
|
469
524
|
}
|
|
470
525
|
|
|
471
526
|
function publicCsvInputRow<T extends Record<string, unknown>>(row: T): T {
|
|
472
|
-
|
|
527
|
+
const stripped = stripCsvProjectedFields(row) as Record<string, unknown>;
|
|
528
|
+
return Object.fromEntries(
|
|
529
|
+
Object.entries(stripped).filter(
|
|
530
|
+
([fieldName]) => !fieldName.startsWith('__deepline'),
|
|
531
|
+
),
|
|
532
|
+
) as T;
|
|
473
533
|
}
|
|
474
534
|
|
|
475
535
|
/**
|
|
@@ -714,6 +774,11 @@ function childPlayEventKey(input: { key: string; workflowId: string }): string {
|
|
|
714
774
|
return `child_play_${hashChildPlayEventKey(`${input.key}:${input.workflowId}`)}_${readableKey}`;
|
|
715
775
|
}
|
|
716
776
|
|
|
777
|
+
function workflowTimeoutFromMs(timeoutMs: number): string {
|
|
778
|
+
const seconds = Math.max(1, Math.ceil(timeoutMs / 1000));
|
|
779
|
+
return `${seconds} second${seconds === 1 ? '' : 's'}`;
|
|
780
|
+
}
|
|
781
|
+
|
|
717
782
|
async function waitForChildPlayTerminalEvent(input: {
|
|
718
783
|
req: RunRequest;
|
|
719
784
|
workflowStep?: WorkflowStep;
|
|
@@ -734,11 +799,11 @@ async function waitForChildPlayTerminalEvent(input: {
|
|
|
734
799
|
const event = (await (
|
|
735
800
|
input.workflowStep.waitForEvent as unknown as (
|
|
736
801
|
name: string,
|
|
737
|
-
options: { type: string; timeout:
|
|
802
|
+
options: { type: string; timeout: string },
|
|
738
803
|
) => Promise<{ payload: unknown }>
|
|
739
804
|
)(`child_play_terminal:${eventKey}`, {
|
|
740
805
|
type: integrationEventType(eventKey),
|
|
741
|
-
timeout: input.timeoutMs,
|
|
806
|
+
timeout: workflowTimeoutFromMs(input.timeoutMs),
|
|
742
807
|
})) as { payload: unknown };
|
|
743
808
|
const rawPayload = isRecord(event.payload) ? event.payload : {};
|
|
744
809
|
const payload = isRecord(rawPayload.data) ? rawPayload.data : rawPayload;
|
|
@@ -909,15 +974,25 @@ async function waitForSyntheticIntegrationEvent(
|
|
|
909
974
|
typeof input.timeout_ms === 'number' && Number.isFinite(input.timeout_ms)
|
|
910
975
|
? Math.max(1, Math.round(input.timeout_ms))
|
|
911
976
|
: 30_000;
|
|
977
|
+
await postRuntimeApiBestEffort(req.baseUrl, req.executorToken, {
|
|
978
|
+
action: 'update_run_status',
|
|
979
|
+
playId: req.runId,
|
|
980
|
+
status: 'running',
|
|
981
|
+
runtimeBackend: 'cf_workflows_dynamic_worker',
|
|
982
|
+
waitKind: 'integration_event_batch',
|
|
983
|
+
waitUntil: nowMs() + timeoutMs,
|
|
984
|
+
activeBoundaryId: `integration_event:${eventKey}`,
|
|
985
|
+
lastCheckpointAt: nowMs(),
|
|
986
|
+
});
|
|
912
987
|
try {
|
|
913
988
|
const event = (await (
|
|
914
989
|
workflowStep.waitForEvent as unknown as (
|
|
915
990
|
name: string,
|
|
916
|
-
options: { type: string; timeout:
|
|
991
|
+
options: { type: string; timeout: string },
|
|
917
992
|
) => Promise<{ payload: unknown }>
|
|
918
993
|
)(`integration_event:${eventKey}`, {
|
|
919
994
|
type: integrationEventType(eventKey),
|
|
920
|
-
timeout: timeoutMs,
|
|
995
|
+
timeout: workflowTimeoutFromMs(timeoutMs),
|
|
921
996
|
})) as { payload: unknown };
|
|
922
997
|
const payload =
|
|
923
998
|
event.payload &&
|
|
@@ -983,7 +1058,7 @@ async function callToolDirect(
|
|
|
983
1058
|
headers: {
|
|
984
1059
|
'content-type': 'application/json',
|
|
985
1060
|
authorization: `Bearer ${req.executorToken}`,
|
|
986
|
-
'x-deepline-request-id': `${req.runId}:${toolId}:${id}`,
|
|
1061
|
+
'x-deepline-request-id': `${req.runId}:${toolId}:${id}:attempt:${attempt}`,
|
|
987
1062
|
[EXECUTE_TOOL_METADATA_HEADER]: 'true',
|
|
988
1063
|
},
|
|
989
1064
|
body: JSON.stringify({ payload: input }),
|
|
@@ -1455,7 +1530,9 @@ async function executeBatchedWorkerToolGroup(input: {
|
|
|
1455
1530
|
) => {
|
|
1456
1531
|
for (const entry of chunkResults) {
|
|
1457
1532
|
const batchResult = isToolExecuteResult(entry.result)
|
|
1458
|
-
? entry.result.result
|
|
1533
|
+
? isRecordLike(entry.result.result)
|
|
1534
|
+
? entry.result.result.data
|
|
1535
|
+
: undefined
|
|
1459
1536
|
: entry.result;
|
|
1460
1537
|
const splitResults =
|
|
1461
1538
|
batchResult != null
|
|
@@ -1516,6 +1593,7 @@ type WorkerMapChunkSummary<T extends Record<string, unknown>> = {
|
|
|
1516
1593
|
rowsWritten: number;
|
|
1517
1594
|
rowsExecuted: number;
|
|
1518
1595
|
rowsCached: number;
|
|
1596
|
+
rowsDuplicateReused: number;
|
|
1519
1597
|
rowsInserted: number;
|
|
1520
1598
|
rowsSkipped: number;
|
|
1521
1599
|
outputDatasetId: string;
|
|
@@ -1641,22 +1719,32 @@ async function executeWorkerStepProgram(
|
|
|
1641
1719
|
path: string[];
|
|
1642
1720
|
outputs: RecordedStepProgramOutput[];
|
|
1643
1721
|
},
|
|
1722
|
+
workflowStep?: WorkflowStep,
|
|
1644
1723
|
): Promise<unknown> {
|
|
1645
1724
|
let currentRow: Record<string, unknown> = cloneCsvAliasedRow(inputRow);
|
|
1646
1725
|
for (const step of program.steps) {
|
|
1647
1726
|
const stepPath = [...(recorder?.path ?? []), step.name];
|
|
1648
|
-
const
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1727
|
+
const runStep = async () =>
|
|
1728
|
+
await executeWorkerStepResolver(
|
|
1729
|
+
step.resolver,
|
|
1730
|
+
currentRow,
|
|
1731
|
+
ctx,
|
|
1732
|
+
index,
|
|
1733
|
+
recorder
|
|
1734
|
+
? {
|
|
1735
|
+
...recorder,
|
|
1736
|
+
path: stepPath,
|
|
1737
|
+
}
|
|
1738
|
+
: undefined,
|
|
1739
|
+
);
|
|
1740
|
+
const resolution = workflowStep
|
|
1741
|
+
? await (
|
|
1742
|
+
workflowStep.do as unknown as (
|
|
1743
|
+
name: string,
|
|
1744
|
+
callback: () => Promise<WorkerStepResolution>,
|
|
1745
|
+
) => Promise<WorkerStepResolution>
|
|
1746
|
+
)(stepPath.join('.'), runStep)
|
|
1747
|
+
: await runStep();
|
|
1660
1748
|
const value = resolution.value;
|
|
1661
1749
|
currentRow = cloneCsvAliasedRow(currentRow, { [step.name]: value });
|
|
1662
1750
|
if (recorder) {
|
|
@@ -2569,7 +2657,17 @@ function createMinimalWorkerCtx(
|
|
|
2569
2657
|
const rowsToExecuteEntries = chunkEntries.filter(
|
|
2570
2658
|
({ rowKey }) => pendingKeys.has(rowKey) || !completedKeys.has(rowKey),
|
|
2571
2659
|
);
|
|
2572
|
-
const
|
|
2660
|
+
const uniqueRowsToExecuteEntries = [
|
|
2661
|
+
...new Map(
|
|
2662
|
+
rowsToExecuteEntries.map((entry) => [entry.rowKey, entry]),
|
|
2663
|
+
).values(),
|
|
2664
|
+
];
|
|
2665
|
+
const duplicateInputReuseCount = Math.max(
|
|
2666
|
+
0,
|
|
2667
|
+
chunkEntries.length -
|
|
2668
|
+
new Set(chunkEntries.map((entry) => entry.rowKey)).size,
|
|
2669
|
+
);
|
|
2670
|
+
const rowsToExecute = uniqueRowsToExecuteEntries.map(({ row }) => row);
|
|
2573
2671
|
const rowsInserted = prepared.inserted + missingPreparedRows.length;
|
|
2574
2672
|
const rowsSkipped = Math.max(
|
|
2575
2673
|
0,
|
|
@@ -2593,7 +2691,7 @@ function createMinimalWorkerCtx(
|
|
|
2593
2691
|
if (abortSignal?.aborted) return;
|
|
2594
2692
|
const myIndex = idx++;
|
|
2595
2693
|
if (myIndex >= rowsToExecute.length) return;
|
|
2596
|
-
const entry =
|
|
2694
|
+
const entry = uniqueRowsToExecuteEntries[myIndex]!;
|
|
2597
2695
|
const row = entry.row;
|
|
2598
2696
|
const absoluteIndex = entry.absoluteIndex;
|
|
2599
2697
|
const enriched: Record<string, unknown> = cloneCsvAliasedRow(row);
|
|
@@ -2701,14 +2799,33 @@ function createMinimalWorkerCtx(
|
|
|
2701
2799
|
})(),
|
|
2702
2800
|
);
|
|
2703
2801
|
}
|
|
2704
|
-
|
|
2705
|
-
|
|
2802
|
+
const persistExecutedRows = async () => {
|
|
2803
|
+
const rowsToPersist = executedRows
|
|
2804
|
+
.map((row, executedIndex) =>
|
|
2805
|
+
row
|
|
2806
|
+
? {
|
|
2807
|
+
row,
|
|
2808
|
+
executedIndex,
|
|
2809
|
+
}
|
|
2810
|
+
: null,
|
|
2811
|
+
)
|
|
2812
|
+
.filter(
|
|
2813
|
+
(
|
|
2814
|
+
entry,
|
|
2815
|
+
): entry is {
|
|
2816
|
+
row: T & Record<string, unknown>;
|
|
2817
|
+
executedIndex: number;
|
|
2818
|
+
} => entry !== null,
|
|
2819
|
+
);
|
|
2820
|
+
if (rowsToPersist.length === 0) {
|
|
2821
|
+
return;
|
|
2822
|
+
}
|
|
2706
2823
|
await persistCompletedMapRows({
|
|
2707
2824
|
req,
|
|
2708
2825
|
tableNamespace: name,
|
|
2709
2826
|
outputFields,
|
|
2710
2827
|
extraOutputFields: Array.from(generatedOutputFields),
|
|
2711
|
-
rows:
|
|
2828
|
+
rows: rowsToPersist.map(({ row, executedIndex }) => ({
|
|
2712
2829
|
...row,
|
|
2713
2830
|
...(executedCellMetaPatches[executedIndex]
|
|
2714
2831
|
? {
|
|
@@ -2716,9 +2833,19 @@ function createMinimalWorkerCtx(
|
|
|
2716
2833
|
executedCellMetaPatches[executedIndex],
|
|
2717
2834
|
}
|
|
2718
2835
|
: {}),
|
|
2719
|
-
__deeplineRowKey:
|
|
2836
|
+
__deeplineRowKey:
|
|
2837
|
+
uniqueRowsToExecuteEntries[executedIndex]!.rowKey,
|
|
2720
2838
|
})),
|
|
2721
2839
|
});
|
|
2840
|
+
};
|
|
2841
|
+
const workerResults = await Promise.allSettled(workers);
|
|
2842
|
+
await persistExecutedRows();
|
|
2843
|
+
const rejectedWorker = workerResults.find(
|
|
2844
|
+
(result): result is PromiseRejectedResult =>
|
|
2845
|
+
result.status === 'rejected',
|
|
2846
|
+
);
|
|
2847
|
+
if (rejectedWorker) {
|
|
2848
|
+
throw rejectedWorker.reason;
|
|
2722
2849
|
}
|
|
2723
2850
|
const resultByKey = new Map<string, T & Record<string, unknown>>();
|
|
2724
2851
|
for (const completedRow of prepared.completedRows) {
|
|
@@ -2739,7 +2866,7 @@ function createMinimalWorkerCtx(
|
|
|
2739
2866
|
executedIndex += 1
|
|
2740
2867
|
) {
|
|
2741
2868
|
const executedRow = executedRows[executedIndex]!;
|
|
2742
|
-
const key =
|
|
2869
|
+
const key = uniqueRowsToExecuteEntries[executedIndex]!.rowKey;
|
|
2743
2870
|
if (key) resultByKey.set(key, executedRow);
|
|
2744
2871
|
}
|
|
2745
2872
|
const out = chunkRows
|
|
@@ -2755,7 +2882,8 @@ function createMinimalWorkerCtx(
|
|
|
2755
2882
|
rowsRead: chunkRows.length,
|
|
2756
2883
|
rowsWritten: out.length,
|
|
2757
2884
|
rowsExecuted: executedRows.length,
|
|
2758
|
-
rowsCached:
|
|
2885
|
+
rowsCached: Math.max(0, out.length - executedRows.length),
|
|
2886
|
+
rowsDuplicateReused: duplicateInputReuseCount,
|
|
2759
2887
|
rowsInserted,
|
|
2760
2888
|
rowsSkipped,
|
|
2761
2889
|
outputDatasetId: `map:${name}`,
|
|
@@ -2767,6 +2895,7 @@ function createMinimalWorkerCtx(
|
|
|
2767
2895
|
const out: Array<T & Record<string, unknown>> = [];
|
|
2768
2896
|
let totalRowsExecuted = 0;
|
|
2769
2897
|
let totalRowsCached = 0;
|
|
2898
|
+
let totalRowsDuplicateReused = 0;
|
|
2770
2899
|
let totalRowsInserted = 0;
|
|
2771
2900
|
let totalRowsSkipped = 0;
|
|
2772
2901
|
|
|
@@ -2809,6 +2938,17 @@ function createMinimalWorkerCtx(
|
|
|
2809
2938
|
return makeWorkerDataset(name, out, {
|
|
2810
2939
|
count: totalRowsWritten,
|
|
2811
2940
|
cacheSummary,
|
|
2941
|
+
workProgress: {
|
|
2942
|
+
total: totalRowsWritten,
|
|
2943
|
+
executed: totalRowsExecuted,
|
|
2944
|
+
reused: totalRowsCached,
|
|
2945
|
+
skipped: totalRowsCached,
|
|
2946
|
+
pending: 0,
|
|
2947
|
+
failed: 0,
|
|
2948
|
+
...(totalRowsDuplicateReused > 0
|
|
2949
|
+
? { duplicates: { exact: totalRowsDuplicateReused } }
|
|
2950
|
+
: {}),
|
|
2951
|
+
},
|
|
2812
2952
|
});
|
|
2813
2953
|
};
|
|
2814
2954
|
|
|
@@ -2829,6 +2969,7 @@ function createMinimalWorkerCtx(
|
|
|
2829
2969
|
totalRowsWritten += chunkResult.rowsWritten;
|
|
2830
2970
|
totalRowsExecuted += chunkResult.rowsExecuted;
|
|
2831
2971
|
totalRowsCached += chunkResult.rowsCached;
|
|
2972
|
+
totalRowsDuplicateReused += chunkResult.rowsDuplicateReused;
|
|
2832
2973
|
totalRowsInserted += chunkResult.rowsInserted;
|
|
2833
2974
|
totalRowsSkipped += chunkResult.rowsSkipped;
|
|
2834
2975
|
if (out.length < 10) {
|
|
@@ -2852,6 +2993,7 @@ function createMinimalWorkerCtx(
|
|
|
2852
2993
|
totalRowsWritten += chunkResult.rowsWritten;
|
|
2853
2994
|
totalRowsExecuted += chunkResult.rowsExecuted;
|
|
2854
2995
|
totalRowsCached += chunkResult.rowsCached;
|
|
2996
|
+
totalRowsDuplicateReused += chunkResult.rowsDuplicateReused;
|
|
2855
2997
|
totalRowsInserted += chunkResult.rowsInserted;
|
|
2856
2998
|
totalRowsSkipped += chunkResult.rowsSkipped;
|
|
2857
2999
|
if (out.length < 10) {
|
|
@@ -2865,6 +3007,7 @@ function createMinimalWorkerCtx(
|
|
|
2865
3007
|
const chunkResult = await runChunkStep(sliced, 0, 0);
|
|
2866
3008
|
totalRowsExecuted = chunkResult.rowsExecuted;
|
|
2867
3009
|
totalRowsCached = chunkResult.rowsCached;
|
|
3010
|
+
totalRowsDuplicateReused = chunkResult.rowsDuplicateReused;
|
|
2868
3011
|
totalRowsInserted = chunkResult.rowsInserted;
|
|
2869
3012
|
totalRowsSkipped = chunkResult.rowsSkipped;
|
|
2870
3013
|
out.push(...chunkResult.preview);
|
|
@@ -2917,18 +3060,39 @@ function createMinimalWorkerCtx(
|
|
|
2917
3060
|
},
|
|
2918
3061
|
async step<T>(name: string, callback: () => Promise<T> | T): Promise<T> {
|
|
2919
3062
|
assertNotAborted(abortSignal);
|
|
2920
|
-
if (!
|
|
2921
|
-
|
|
3063
|
+
if (!name.trim()) {
|
|
3064
|
+
throw new Error('ctx.step(name, callback) requires a name.');
|
|
2922
3065
|
}
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
}
|
|
3066
|
+
// Static pipeline JS blocks are already Workflow steps in the Workers
|
|
3067
|
+
// backend. Nesting another `step.do` here can leave preview runs parked
|
|
3068
|
+
// inside the JS stage before they reach subsequent event waits.
|
|
3069
|
+
return await callback();
|
|
3070
|
+
},
|
|
3071
|
+
async runSteps<T>(
|
|
3072
|
+
program: WorkerStepProgram,
|
|
3073
|
+
input: Record<string, unknown>,
|
|
3074
|
+
opts?: { description?: string },
|
|
3075
|
+
): Promise<T> {
|
|
3076
|
+
assertNotAborted(abortSignal);
|
|
3077
|
+
if (!isWorkerStepProgram(program)) {
|
|
3078
|
+
throw new Error('ctx.runSteps(program, input) requires steps().');
|
|
3079
|
+
}
|
|
3080
|
+
if (opts?.description) {
|
|
3081
|
+
emitEvent({
|
|
3082
|
+
type: 'log',
|
|
3083
|
+
level: 'info',
|
|
3084
|
+
message: String(opts.description),
|
|
3085
|
+
ts: nowMs(),
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
3088
|
+
return (await executeWorkerStepProgram(
|
|
3089
|
+
program,
|
|
3090
|
+
input,
|
|
3091
|
+
ctx,
|
|
3092
|
+
0,
|
|
3093
|
+
undefined,
|
|
3094
|
+
workflowStep,
|
|
3095
|
+
)) as T;
|
|
2932
3096
|
},
|
|
2933
3097
|
async csv<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
2934
3098
|
arg: unknown,
|
|
@@ -3263,6 +3427,14 @@ function createMinimalWorkerCtx(
|
|
|
3263
3427
|
return makeWorkerDataset(name, out, {
|
|
3264
3428
|
count: totalRowsWritten,
|
|
3265
3429
|
cacheSummary,
|
|
3430
|
+
workProgress: {
|
|
3431
|
+
total: totalRowsWritten,
|
|
3432
|
+
executed: totalRowsExecuted,
|
|
3433
|
+
reused: totalRowsCached,
|
|
3434
|
+
skipped: totalRowsCached,
|
|
3435
|
+
pending: 0,
|
|
3436
|
+
failed: 0,
|
|
3437
|
+
},
|
|
3266
3438
|
});
|
|
3267
3439
|
};
|
|
3268
3440
|
|
|
@@ -3619,11 +3791,11 @@ function createMinimalWorkerCtx(
|
|
|
3619
3791
|
const event = (await (
|
|
3620
3792
|
workflowStep.waitForEvent as unknown as (
|
|
3621
3793
|
name: string,
|
|
3622
|
-
options: { type: string; timeout:
|
|
3794
|
+
options: { type: string; timeout: string },
|
|
3623
3795
|
) => Promise<{ payload: unknown }>
|
|
3624
3796
|
)(`wait_for_event:${workflowEventType(eventType)}`, {
|
|
3625
3797
|
type: workflowEventType(eventType),
|
|
3626
|
-
timeout: timeoutMs,
|
|
3798
|
+
timeout: workflowTimeoutFromMs(timeoutMs),
|
|
3627
3799
|
})) as { payload: unknown };
|
|
3628
3800
|
return event.payload ?? null;
|
|
3629
3801
|
},
|
|
@@ -3804,6 +3976,9 @@ async function executeRunRequest(
|
|
|
3804
3976
|
status: 'completed',
|
|
3805
3977
|
result: terminalResult,
|
|
3806
3978
|
runtimeBackend: 'cf_workflows_dynamic_worker',
|
|
3979
|
+
waitKind: null,
|
|
3980
|
+
waitUntil: null,
|
|
3981
|
+
activeBoundaryId: null,
|
|
3807
3982
|
liveLogs,
|
|
3808
3983
|
lastCheckpointAt: nowMs(),
|
|
3809
3984
|
});
|
|
@@ -3825,6 +4000,7 @@ async function executeRunRequest(
|
|
|
3825
4000
|
);
|
|
3826
4001
|
});
|
|
3827
4002
|
return {
|
|
4003
|
+
playName: req.playName,
|
|
3828
4004
|
result: serializedResult,
|
|
3829
4005
|
outputRows: inferOutputRows(serializedResult),
|
|
3830
4006
|
durationMs: nowMs() - startedAt,
|
|
@@ -3847,6 +4023,9 @@ async function executeRunRequest(
|
|
|
3847
4023
|
status: aborted ? 'cancelled' : 'failed',
|
|
3848
4024
|
error: message,
|
|
3849
4025
|
runtimeBackend: 'cf_workflows_dynamic_worker',
|
|
4026
|
+
waitKind: null,
|
|
4027
|
+
waitUntil: null,
|
|
4028
|
+
activeBoundaryId: null,
|
|
3850
4029
|
liveLogs,
|
|
3851
4030
|
lastCheckpointAt: nowMs(),
|
|
3852
4031
|
});
|
|
@@ -4121,6 +4300,14 @@ function serializeValue(value: unknown, depth: number): unknown {
|
|
|
4121
4300
|
? (value as unknown as { __deeplineCacheSummary: string })
|
|
4122
4301
|
.__deeplineCacheSummary
|
|
4123
4302
|
: null;
|
|
4303
|
+
const workProgress =
|
|
4304
|
+
isRecord(
|
|
4305
|
+
(value as unknown as { __deeplineWorkProgress?: unknown })
|
|
4306
|
+
.__deeplineWorkProgress,
|
|
4307
|
+
)
|
|
4308
|
+
? (value as unknown as { __deeplineWorkProgress: Record<string, unknown> })
|
|
4309
|
+
.__deeplineWorkProgress
|
|
4310
|
+
: null;
|
|
4124
4311
|
const previewRows = value
|
|
4125
4312
|
.slice(0, 5)
|
|
4126
4313
|
.map((row) => serializeValue(row, depth + 1))
|
|
@@ -4138,6 +4325,9 @@ function serializeValue(value: unknown, depth: number): unknown {
|
|
|
4138
4325
|
preview: previewRows,
|
|
4139
4326
|
tableNamespace,
|
|
4140
4327
|
...(cacheSummary ? { cacheSummary } : {}),
|
|
4328
|
+
...(workProgress
|
|
4329
|
+
? { _metadata: { workProgress } }
|
|
4330
|
+
: {}),
|
|
4141
4331
|
};
|
|
4142
4332
|
}
|
|
4143
4333
|
return value.map((entry) => serializeValue(entry, depth + 1));
|