deepline 0.1.212 → 0.1.213
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/entry.ts +167 -329
- package/dist/bundling-sources/sdk/src/index.ts +2 -0
- package/dist/bundling-sources/sdk/src/play.ts +8 -1
- package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +11 -1
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +49 -0
- package/dist/bundling-sources/shared_libs/play-runtime/child-execution-placement.ts +14 -0
- package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +57 -23
- package/dist/bundling-sources/shared_libs/play-runtime/completed-receipt-cache.ts +166 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +142 -101
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-contract.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +30 -1
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +160 -2
- package/dist/bundling-sources/shared_libs/play-runtime/gateway-auth-session.ts +93 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-call-execution.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-completion-sink.ts +16 -1
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-state-sink.ts +10 -0
- package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +80 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +94 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +54 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +477 -85
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-postgres-admission.ts +162 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sheet-attempt-sql.ts +16 -17
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +1 -0
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +2 -4
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.mjs +2 -2
- package/dist/{compiler-manifest-j6z8qzpd.d.mts → compiler-manifest-BhgZ23A4.d.mts} +1 -0
- package/dist/{compiler-manifest-j6z8qzpd.d.ts → compiler-manifest-BhgZ23A4.d.ts} +1 -0
- package/dist/index.d.mts +8 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- 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
|
@@ -40,7 +40,6 @@ import {
|
|
|
40
40
|
mapRowOutcomeRuntimeFields,
|
|
41
41
|
resolveMapRowOutcomeKey,
|
|
42
42
|
} from './map-row-outcome';
|
|
43
|
-
import { RuntimeSheetRowsBlockedError } from './runtime-sheet-errors';
|
|
44
43
|
import { buildChildRunId } from './child-run-id';
|
|
45
44
|
import type { PlayCallGovernanceSnapshot } from './scheduler-backend';
|
|
46
45
|
import {
|
|
@@ -1521,12 +1520,14 @@ export class PlayContextImpl {
|
|
|
1521
1520
|
|
|
1522
1521
|
private recordPlayCallStep(input: {
|
|
1523
1522
|
playId: string;
|
|
1523
|
+
execution?: 'inline' | 'child-workflow';
|
|
1524
1524
|
description?: string | null;
|
|
1525
1525
|
nestedSteps?: PlayStep[];
|
|
1526
1526
|
}): void {
|
|
1527
1527
|
const step = {
|
|
1528
1528
|
type: 'play_call' as const,
|
|
1529
1529
|
playId: input.playId,
|
|
1530
|
+
...(input.execution ? { execution: input.execution } : {}),
|
|
1530
1531
|
nestedSteps: input.nestedSteps ?? [],
|
|
1531
1532
|
description: normalizeStepDescription(input.description ?? undefined),
|
|
1532
1533
|
};
|
|
@@ -1903,6 +1904,7 @@ export class PlayContextImpl {
|
|
|
1903
1904
|
}
|
|
1904
1905
|
const claimed = await this.#options.claimRuntimeStepReceipt({
|
|
1905
1906
|
key,
|
|
1907
|
+
leaseId: `receipt-lease:${crypto.randomUUID()}`,
|
|
1906
1908
|
runId: this.currentReceiptOwnerRunId,
|
|
1907
1909
|
runAttempt: this.currentRunAttempt,
|
|
1908
1910
|
leaseAware: true,
|
|
@@ -1979,30 +1981,6 @@ export class PlayContextImpl {
|
|
|
1979
1981
|
};
|
|
1980
1982
|
}
|
|
1981
1983
|
|
|
1982
|
-
private async skipRuntimeStepReceipt(
|
|
1983
|
-
key: string,
|
|
1984
|
-
runId: string,
|
|
1985
|
-
leaseId?: string | null,
|
|
1986
|
-
): Promise<RuntimeStepReceipt | null> {
|
|
1987
|
-
if (!this.#options.skipRuntimeStepReceipt) {
|
|
1988
|
-
return null;
|
|
1989
|
-
}
|
|
1990
|
-
const skipped = await this.#options.skipRuntimeStepReceipt({
|
|
1991
|
-
key,
|
|
1992
|
-
runId,
|
|
1993
|
-
runAttempt: this.currentRunAttempt,
|
|
1994
|
-
...(leaseId ? { leaseId } : {}),
|
|
1995
|
-
});
|
|
1996
|
-
if (!skipped || typeof skipped.key !== 'string' || !skipped.key.trim()) {
|
|
1997
|
-
return null;
|
|
1998
|
-
}
|
|
1999
|
-
return {
|
|
2000
|
-
...skipped,
|
|
2001
|
-
key: skipped.key.trim(),
|
|
2002
|
-
runId: skipped.runId ?? null,
|
|
2003
|
-
};
|
|
2004
|
-
}
|
|
2005
|
-
|
|
2006
1984
|
private async heartbeatRuntimeStepReceipt(
|
|
2007
1985
|
key: string,
|
|
2008
1986
|
_runId: string,
|
|
@@ -2310,6 +2288,11 @@ export class PlayContextImpl {
|
|
|
2310
2288
|
? await this.dispatchChunkedRuntimeReceiptRequest(uniqueKeys, (chunk) =>
|
|
2311
2289
|
claimReceipts({
|
|
2312
2290
|
keys: chunk,
|
|
2291
|
+
// A transport retry can replay this mutation after the store
|
|
2292
|
+
// committed but before the response body was consumed. Stable
|
|
2293
|
+
// caller-owned tokens distinguish that replay from a concurrent
|
|
2294
|
+
// claimant without weakening the provider-call execution fence.
|
|
2295
|
+
leaseIds: chunk.map(() => `receipt-lease:${crypto.randomUUID()}`),
|
|
2313
2296
|
runId: this.currentReceiptOwnerRunId,
|
|
2314
2297
|
runAttempt: this.currentRunAttempt,
|
|
2315
2298
|
leaseAware: true,
|
|
@@ -2777,6 +2760,24 @@ export class PlayContextImpl {
|
|
|
2777
2760
|
this.#options.completeRuntimeStepReceipt ||
|
|
2778
2761
|
this.#options.completeRuntimeStepReceipts,
|
|
2779
2762
|
),
|
|
2763
|
+
...(this.#options.acquireRuntimeReceiptExecutionLock &&
|
|
2764
|
+
this.#options.releaseRuntimeReceiptExecutionLock
|
|
2765
|
+
? {
|
|
2766
|
+
acquireExecutionLock: ({ receiptKey, ownerExecutionId, ttlMs }) =>
|
|
2767
|
+
this.#options.acquireRuntimeReceiptExecutionLock!({
|
|
2768
|
+
key: receiptKey,
|
|
2769
|
+
runId: this.currentReceiptOwnerRunId,
|
|
2770
|
+
ownerExecutionId,
|
|
2771
|
+
ttlMs,
|
|
2772
|
+
}),
|
|
2773
|
+
releaseExecutionLock: ({ receiptKey, ownerExecutionId }) =>
|
|
2774
|
+
this.#options.releaseRuntimeReceiptExecutionLock!({
|
|
2775
|
+
key: receiptKey,
|
|
2776
|
+
runId: this.currentReceiptOwnerRunId,
|
|
2777
|
+
ownerExecutionId,
|
|
2778
|
+
}),
|
|
2779
|
+
}
|
|
2780
|
+
: {}),
|
|
2780
2781
|
};
|
|
2781
2782
|
}
|
|
2782
2783
|
|
|
@@ -2834,6 +2835,8 @@ export class PlayContextImpl {
|
|
|
2834
2835
|
onClaimedResult?: (output: T, receiptKey: string) => T;
|
|
2835
2836
|
shouldPersistFailure?: (error: unknown) => boolean;
|
|
2836
2837
|
markRunningBeforeExecute?: boolean;
|
|
2838
|
+
requiresExecutionLock?: boolean;
|
|
2839
|
+
executionLockTtlMs?: number;
|
|
2837
2840
|
execute: (context: { leaseId: string | null }) => Promise<T>;
|
|
2838
2841
|
},
|
|
2839
2842
|
): Promise<T> {
|
|
@@ -2865,6 +2868,9 @@ export class PlayContextImpl {
|
|
|
2865
2868
|
onClaimedResult: opts.onClaimedResult,
|
|
2866
2869
|
shouldPersistFailure: opts.shouldPersistFailure,
|
|
2867
2870
|
markRunningBeforeExecute: opts.markRunningBeforeExecute,
|
|
2871
|
+
completedCacheOnly: operation === 'tool',
|
|
2872
|
+
requiresExecutionLock: opts.requiresExecutionLock,
|
|
2873
|
+
executionLockTtlMs: opts.executionLockTtlMs,
|
|
2868
2874
|
formatError: (error) => this.formatRuntimeError(error),
|
|
2869
2875
|
log: (message) => this.log(message),
|
|
2870
2876
|
execute: opts.execute,
|
|
@@ -4016,12 +4022,6 @@ export class PlayContextImpl {
|
|
|
4016
4022
|
resolvedTableNamespace = normalizeTableNamespace(
|
|
4017
4023
|
mapStartResult.tableNamespace,
|
|
4018
4024
|
);
|
|
4019
|
-
if ((mapStartResult.blockedRows?.length ?? 0) > 0) {
|
|
4020
|
-
throw new RuntimeSheetRowsBlockedError({
|
|
4021
|
-
tableNamespace: resolvedTableNamespace,
|
|
4022
|
-
blockedRows: mapStartResult.blockedRows ?? [],
|
|
4023
|
-
});
|
|
4024
|
-
}
|
|
4025
4025
|
|
|
4026
4026
|
const persistedRowIdentity = (
|
|
4027
4027
|
row: Record<string, unknown>,
|
|
@@ -4456,12 +4456,6 @@ export class PlayContextImpl {
|
|
|
4456
4456
|
resolvedTableNamespace = normalizeTableNamespace(
|
|
4457
4457
|
mapStartResult.tableNamespace,
|
|
4458
4458
|
);
|
|
4459
|
-
if ((mapStartResult.blockedRows?.length ?? 0) > 0) {
|
|
4460
|
-
throw new RuntimeSheetRowsBlockedError({
|
|
4461
|
-
tableNamespace: resolvedTableNamespace,
|
|
4462
|
-
blockedRows: mapStartResult.blockedRows ?? [],
|
|
4463
|
-
});
|
|
4464
|
-
}
|
|
4465
4459
|
const persistedRowIdentity = (row: Record<string, unknown>, index = 0) =>
|
|
4466
4460
|
resolveMapRowOutcomeKey(row) ?? rowIdentity(row, index);
|
|
4467
4461
|
const pendingRowsByKey = new Map<string, Record<string, unknown>>();
|
|
@@ -4574,6 +4568,7 @@ export class PlayContextImpl {
|
|
|
4574
4568
|
);
|
|
4575
4569
|
|
|
4576
4570
|
this.activeMapCellMeta = new Map();
|
|
4571
|
+
const staleCompletionKeys = new Set<string>();
|
|
4577
4572
|
const persistMapRows = async (rows: PersistableMapRow[]) => {
|
|
4578
4573
|
if (!this.#options.onMapRowsCompleted || rows.length === 0) {
|
|
4579
4574
|
return;
|
|
@@ -4597,7 +4592,7 @@ export class PlayContextImpl {
|
|
|
4597
4592
|
);
|
|
4598
4593
|
const flushStartedAt = Date.now();
|
|
4599
4594
|
try {
|
|
4600
|
-
await this.#options.onMapRowsCompleted!({
|
|
4595
|
+
const writeResult = await this.#options.onMapRowsCompleted!({
|
|
4601
4596
|
playName: this.#options.playName,
|
|
4602
4597
|
playId: this.#options.playId,
|
|
4603
4598
|
runId: this.#options.runId,
|
|
@@ -4609,6 +4604,11 @@ export class PlayContextImpl {
|
|
|
4609
4604
|
),
|
|
4610
4605
|
staticPipeline: this.#options.staticPipeline ?? null,
|
|
4611
4606
|
});
|
|
4607
|
+
if (writeResult) {
|
|
4608
|
+
for (const key of writeResult.staleDroppedKeys ?? []) {
|
|
4609
|
+
staleCompletionKeys.add(key);
|
|
4610
|
+
}
|
|
4611
|
+
}
|
|
4612
4612
|
this.resourceGovernor.observe({
|
|
4613
4613
|
sheetFlushBytes: chunkBytes,
|
|
4614
4614
|
sheetFlushLatencyMs: Date.now() - flushStartedAt,
|
|
@@ -4654,6 +4654,7 @@ export class PlayContextImpl {
|
|
|
4654
4654
|
completedRows: duplicateReuseCount,
|
|
4655
4655
|
},
|
|
4656
4656
|
{
|
|
4657
|
+
emitTerminalEvent: false,
|
|
4657
4658
|
onRowError: options?.onRowError,
|
|
4658
4659
|
executionRowKeys: rowsToExecuteEntries.map((entry) => entry.rowKey),
|
|
4659
4660
|
executionRowIndexes: rowsToExecuteEntries.map(
|
|
@@ -4751,7 +4752,49 @@ export class PlayContextImpl {
|
|
|
4751
4752
|
}
|
|
4752
4753
|
this.activeMapCellMeta = null;
|
|
4753
4754
|
|
|
4754
|
-
if (
|
|
4755
|
+
if (staleCompletionKeys.size > 0) {
|
|
4756
|
+
results = results.filter((row, index) => {
|
|
4757
|
+
const key = rowIdentity(row, itemOriginalIndexes[index] ?? index);
|
|
4758
|
+
return !staleCompletionKeys.has(key);
|
|
4759
|
+
});
|
|
4760
|
+
}
|
|
4761
|
+
|
|
4762
|
+
const durableCompletedRows = Math.max(
|
|
4763
|
+
0,
|
|
4764
|
+
reusedCount + mapResult.completedRows.length - staleCompletionKeys.size,
|
|
4765
|
+
);
|
|
4766
|
+
const durableFailedRows = mapResult.failedRows.length;
|
|
4767
|
+
const terminalFrame = this.checkpoint.mapFrames?.[mapScope.mapInvocationId];
|
|
4768
|
+
if (terminalFrame) {
|
|
4769
|
+
this.setMapFrame({
|
|
4770
|
+
...terminalFrame,
|
|
4771
|
+
status: 'completed',
|
|
4772
|
+
// Incremental rows add keys after their commit. Pure maps use the
|
|
4773
|
+
// durable aggregate count below instead of materializing up to millions
|
|
4774
|
+
// of keys only to mark the terminal frame.
|
|
4775
|
+
completedRowKeys: terminalFrame.completedRowKeys,
|
|
4776
|
+
pendingRowKeys: [],
|
|
4777
|
+
completedRowsCount: durableCompletedRows,
|
|
4778
|
+
pendingRowsCount: 0,
|
|
4779
|
+
failedRowsCount: durableFailedRows,
|
|
4780
|
+
activeBoundaryId: null,
|
|
4781
|
+
updatedAt: Date.now(),
|
|
4782
|
+
});
|
|
4783
|
+
}
|
|
4784
|
+
this.emitExecutionEvent({
|
|
4785
|
+
type: 'map.completed',
|
|
4786
|
+
mapInvocationId: mapScope.mapInvocationId,
|
|
4787
|
+
mapNodeId: mapScope.mapNodeId ?? null,
|
|
4788
|
+
logicalNamespace: mapScope.logicalNamespace,
|
|
4789
|
+
artifactTableNamespace: resolvedTableNamespace,
|
|
4790
|
+
completedRows: durableCompletedRows,
|
|
4791
|
+
failedRows: durableFailedRows,
|
|
4792
|
+
totalRows: totalInputCount,
|
|
4793
|
+
...this.inlineChildAggregateEventFields(),
|
|
4794
|
+
at: Date.now(),
|
|
4795
|
+
});
|
|
4796
|
+
|
|
4797
|
+
if (this.#options.onMapRowsCompleted && staleCompletionKeys.size === 0) {
|
|
4755
4798
|
results = await reconcileNodeRuntimeMapResultsWithPersistedSheet({
|
|
4756
4799
|
mapName: normalizedMapNamespace,
|
|
4757
4800
|
tableNamespace: resolvedTableNamespace,
|
|
@@ -4988,11 +5031,21 @@ export class PlayContextImpl {
|
|
|
4988
5031
|
mapName: normalizedTableNamespace,
|
|
4989
5032
|
budgetBytes: runtimeOptions?.retainedRowsMemoryBudgetBytes,
|
|
4990
5033
|
});
|
|
4991
|
-
const enqueueIncrementalPersist = (
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
5034
|
+
const enqueueIncrementalPersist = (
|
|
5035
|
+
row: PersistableMapRow,
|
|
5036
|
+
onCommitted: () => void,
|
|
5037
|
+
): void => {
|
|
5038
|
+
if (!incrementalPersistence) {
|
|
5039
|
+
onCommitted();
|
|
5040
|
+
return;
|
|
5041
|
+
}
|
|
5042
|
+
void incrementalPersistence
|
|
5043
|
+
.persistRows([row])
|
|
5044
|
+
.then(onCommitted)
|
|
5045
|
+
.catch(() => {
|
|
5046
|
+
// The final map-level flush awaits the same chain and surfaces the
|
|
5047
|
+
// persistence failure loudly without holding a completed row slot open.
|
|
5048
|
+
});
|
|
4996
5049
|
};
|
|
4997
5050
|
|
|
4998
5051
|
if (completedRows > 0 || pendingRows !== totalRows) {
|
|
@@ -5158,14 +5211,16 @@ export class PlayContextImpl {
|
|
|
5158
5211
|
// this replaces ran AFTER every row had already computed, emitting 150k
|
|
5159
5212
|
// post-hoc map.progress events and re-copying the completed-keys array
|
|
5160
5213
|
// per row — all theater, no live progress value.
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5214
|
+
if (!incrementalPersistence) {
|
|
5215
|
+
updateMapFrameProgress({
|
|
5216
|
+
completedRowKeys: results.map((_row, index) =>
|
|
5217
|
+
executionRowKey(
|
|
5218
|
+
this.toOutputRow(items[index] as Record<string, unknown>),
|
|
5219
|
+
index,
|
|
5220
|
+
),
|
|
5166
5221
|
),
|
|
5167
|
-
)
|
|
5168
|
-
}
|
|
5222
|
+
});
|
|
5223
|
+
}
|
|
5169
5224
|
if (emitTerminalEvent) {
|
|
5170
5225
|
updateMapFrameProgress({
|
|
5171
5226
|
status: 'completed',
|
|
@@ -5346,9 +5401,6 @@ export class PlayContextImpl {
|
|
|
5346
5401
|
});
|
|
5347
5402
|
retainedRowsMemoryTracker.track(failedRow);
|
|
5348
5403
|
failedRowsToPersist.push(failedRow);
|
|
5349
|
-
updateMapFrameProgress({
|
|
5350
|
-
failedRowKey: rowKey,
|
|
5351
|
-
});
|
|
5352
5404
|
this.emitScopedRowUpdate(rowKey, normalizedTableNamespace, {
|
|
5353
5405
|
rowId: idx,
|
|
5354
5406
|
status: 'failed',
|
|
@@ -5357,7 +5409,9 @@ export class PlayContextImpl {
|
|
|
5357
5409
|
error: formattedError,
|
|
5358
5410
|
dataPatch: {},
|
|
5359
5411
|
});
|
|
5360
|
-
enqueueIncrementalPersist(failedRow)
|
|
5412
|
+
enqueueIncrementalPersist(failedRow, () => {
|
|
5413
|
+
updateMapFrameProgress({ failedRowKey: rowKey });
|
|
5414
|
+
});
|
|
5361
5415
|
return FAILED_ROW;
|
|
5362
5416
|
}
|
|
5363
5417
|
const cellValue = this.serializeCellValue(value);
|
|
@@ -5404,9 +5458,6 @@ export class PlayContextImpl {
|
|
|
5404
5458
|
|
|
5405
5459
|
const merged = cloneCsvAliasedRow(baseRow, computedFields);
|
|
5406
5460
|
activeFieldName = null;
|
|
5407
|
-
updateMapFrameProgress({
|
|
5408
|
-
completedRowKey: rowKey,
|
|
5409
|
-
});
|
|
5410
5461
|
this.emitScopedRowUpdate(rowKey, normalizedTableNamespace, {
|
|
5411
5462
|
rowId: idx,
|
|
5412
5463
|
status: 'completed',
|
|
@@ -5426,7 +5477,9 @@ export class PlayContextImpl {
|
|
|
5426
5477
|
});
|
|
5427
5478
|
retainedRowsMemoryTracker.track(completedRow);
|
|
5428
5479
|
completedRowsToPersist.push(completedRow);
|
|
5429
|
-
enqueueIncrementalPersist(completedRow)
|
|
5480
|
+
enqueueIncrementalPersist(completedRow, () => {
|
|
5481
|
+
updateMapFrameProgress({ completedRowKey: rowKey });
|
|
5482
|
+
});
|
|
5430
5483
|
return publicRow;
|
|
5431
5484
|
} catch (error) {
|
|
5432
5485
|
if (isPlayRowExecutionSuspendedError(error)) {
|
|
@@ -5597,6 +5650,11 @@ export class PlayContextImpl {
|
|
|
5597
5650
|
(result): result is Record<string, unknown> =>
|
|
5598
5651
|
result !== WAITING_ROW && result !== FAILED_ROW,
|
|
5599
5652
|
);
|
|
5653
|
+
// A row is acknowledged only after its terminal sheet batch commits. The
|
|
5654
|
+
// incremental promises publish their frame updates from the commit
|
|
5655
|
+
// continuation, so this barrier also makes the terminal map event derive
|
|
5656
|
+
// from durable row truth instead of resolver completion.
|
|
5657
|
+
await incrementalPersistence?.flush();
|
|
5600
5658
|
if (emitTerminalEvent) {
|
|
5601
5659
|
updateMapFrameProgress({
|
|
5602
5660
|
status: 'completed',
|
|
@@ -6081,7 +6139,10 @@ export class PlayContextImpl {
|
|
|
6081
6139
|
});
|
|
6082
6140
|
let executionAuthScopeDigest =
|
|
6083
6141
|
(await this.resolveToolAuthScopeDigest(toolId))?.trim() ?? null;
|
|
6084
|
-
const
|
|
6142
|
+
const eventWaitHandler =
|
|
6143
|
+
(await this.#options.getIntegrationEventWaitHandler?.(toolId)) ?? null;
|
|
6144
|
+
const cacheableToolResult =
|
|
6145
|
+
!eventWaitHandler && !isQueryResultDatasetReadRequest(toolId, input);
|
|
6085
6146
|
let durableCacheKey = await this.durableToolCallCacheKey({
|
|
6086
6147
|
toolId,
|
|
6087
6148
|
requestInput: input,
|
|
@@ -6089,8 +6150,6 @@ export class PlayContextImpl {
|
|
|
6089
6150
|
staleAfterSeconds: toolCachePolicy.staleAfterSeconds,
|
|
6090
6151
|
});
|
|
6091
6152
|
const checkpointCacheKeys = [durableCacheKey];
|
|
6092
|
-
const eventWaitHandler =
|
|
6093
|
-
(await this.#options.getIntegrationEventWaitHandler?.(toolId)) ?? null;
|
|
6094
6153
|
const store = rowContext.getStore();
|
|
6095
6154
|
|
|
6096
6155
|
const executeTool = async (context?: {
|
|
@@ -6306,12 +6365,10 @@ export class PlayContextImpl {
|
|
|
6306
6365
|
authScopeAttempt < 2;
|
|
6307
6366
|
authScopeAttempt += 1
|
|
6308
6367
|
) {
|
|
6309
|
-
// Capture the lease the receipt store hands to `execute` for THIS
|
|
6310
|
-
// attempt's key. On an auth-scope re-claim we mark that old-scope receipt
|
|
6311
|
-
// `skipped` (below), and the skip is fenced on this run+attempt+lease so
|
|
6312
|
-
// it can only supersede the receipt this attempt owns.
|
|
6313
|
-
let claimedReceiptLeaseId: string | null = null;
|
|
6314
6368
|
try {
|
|
6369
|
+
const toolRetryPolicy = await this.#options
|
|
6370
|
+
.getToolRetryPolicy?.(toolId)
|
|
6371
|
+
.catch(() => null);
|
|
6315
6372
|
return await this.executeWithRuntimeReceipt(
|
|
6316
6373
|
'tool',
|
|
6317
6374
|
normalizedKey,
|
|
@@ -6320,6 +6377,15 @@ export class PlayContextImpl {
|
|
|
6320
6377
|
receiptKey: durableCacheKey,
|
|
6321
6378
|
semanticKey: toolRequestIdentity,
|
|
6322
6379
|
force: toolCachePolicy.force,
|
|
6380
|
+
// Missing metadata is intentionally lock-free. Only explicitly
|
|
6381
|
+
// dangerous non-idempotent side effects enter the fence path.
|
|
6382
|
+
requiresExecutionLock:
|
|
6383
|
+
toolRetryPolicy?.requiresExecutionFence === true,
|
|
6384
|
+
executionLockTtlMs: Math.min(
|
|
6385
|
+
600_000,
|
|
6386
|
+
resolveToolRuntimeTimeoutMs(toolId, options?.timeoutMs) ??
|
|
6387
|
+
300_000,
|
|
6388
|
+
),
|
|
6323
6389
|
staleAfterSeconds: toolCachePolicy.staleAfterSeconds,
|
|
6324
6390
|
onClaimedResult: (output, receiptKey) =>
|
|
6325
6391
|
markToolExecuteResultExecutionOutcome(output, {
|
|
@@ -6337,10 +6403,7 @@ export class PlayContextImpl {
|
|
|
6337
6403
|
shouldPersistFailure: (error) =>
|
|
6338
6404
|
!(error instanceof ToolExecuteAuthScopeChangedError),
|
|
6339
6405
|
markRunningBeforeExecute: false,
|
|
6340
|
-
execute: ({ leaseId }) => {
|
|
6341
|
-
claimedReceiptLeaseId = leaseId;
|
|
6342
|
-
return executeTool({ leaseId });
|
|
6343
|
-
},
|
|
6406
|
+
execute: ({ leaseId }) => executeTool({ leaseId }),
|
|
6344
6407
|
runningReceiptWaitMaxAttempts:
|
|
6345
6408
|
resolveRuntimeToolReceiptWaitMaxAttempts(
|
|
6346
6409
|
typeof options?.receiptWaitMs === 'number'
|
|
@@ -6356,36 +6419,9 @@ export class PlayContextImpl {
|
|
|
6356
6419
|
) {
|
|
6357
6420
|
throw error;
|
|
6358
6421
|
}
|
|
6359
|
-
//
|
|
6360
|
-
//
|
|
6361
|
-
//
|
|
6362
|
-
// the OLD cache key; without an explicit terminal it projects as a failed
|
|
6363
|
-
// node even though the work is about to be re-done under the new scope.
|
|
6364
|
-
// `skipped` is the terminal for superseded work; the skip is fenced on
|
|
6365
|
-
// this run+attempt+lease so it can only touch the receipt this attempt
|
|
6366
|
-
// owns. Best-effort: a skip that cannot fence (store returns null) must
|
|
6367
|
-
// not mask the reclaim itself.
|
|
6368
|
-
const supersededReceiptKey = durableCacheKey;
|
|
6369
|
-
try {
|
|
6370
|
-
const skipped = await this.skipRuntimeStepReceipt(
|
|
6371
|
-
supersededReceiptKey,
|
|
6372
|
-
this.currentRunId,
|
|
6373
|
-
claimedReceiptLeaseId,
|
|
6374
|
-
);
|
|
6375
|
-
if (skipped) {
|
|
6376
|
-
this.log(
|
|
6377
|
-
`ctx.tools.execute(${toolId}): auth_scope_changed_superseded ` +
|
|
6378
|
-
`old-scope receipt ${toolRequestIdentity} (label: ${normalizedKey}) ` +
|
|
6379
|
-
`marked skipped so the reclaim does not project as a failed node.`,
|
|
6380
|
-
);
|
|
6381
|
-
}
|
|
6382
|
-
} catch (skipError) {
|
|
6383
|
-
this.log(
|
|
6384
|
-
`ctx.tools.execute(${toolId}): auth_scope_changed_supersede_skip_failed ` +
|
|
6385
|
-
`(label: ${normalizedKey}); could not mark the old-scope receipt ` +
|
|
6386
|
-
`skipped: ${this.formatRuntimeError(skipError)}`,
|
|
6387
|
-
);
|
|
6388
|
-
}
|
|
6422
|
+
// Completed-receipt cache misses never publish a running receipt. The
|
|
6423
|
+
// old auth-scope attempt therefore has no ownership metadata to clean
|
|
6424
|
+
// up; re-key under the refreshed credential scope and retry once.
|
|
6389
6425
|
// Make the bounded auth-scope re-claim observable in run logs instead
|
|
6390
6426
|
// of a silent continuation: the credential identity changed after the
|
|
6391
6427
|
// receipt key was prepared, so we evict the cached digest, re-resolve,
|
|
@@ -6552,6 +6588,8 @@ export class PlayContextImpl {
|
|
|
6552
6588
|
}
|
|
6553
6589
|
const childExecutionDecision = resolveChildExecutionStrategy({
|
|
6554
6590
|
pipeline: resolvedPlay.staticPipeline,
|
|
6591
|
+
execution: options?.execution,
|
|
6592
|
+
childPlayName: resolvedName,
|
|
6555
6593
|
});
|
|
6556
6594
|
const launchThroughScheduler =
|
|
6557
6595
|
this.shouldLaunchChildPlaysThroughScheduler() &&
|
|
@@ -6696,6 +6734,7 @@ export class PlayContextImpl {
|
|
|
6696
6734
|
}
|
|
6697
6735
|
this.recordPlayCallStep({
|
|
6698
6736
|
playId: resolvedName,
|
|
6737
|
+
execution: options?.execution,
|
|
6699
6738
|
description: options?.description,
|
|
6700
6739
|
});
|
|
6701
6740
|
return checkpointResult.output;
|
|
@@ -6743,6 +6782,7 @@ export class PlayContextImpl {
|
|
|
6743
6782
|
}
|
|
6744
6783
|
this.recordPlayCallStep({
|
|
6745
6784
|
playId: resolvedName,
|
|
6785
|
+
execution: options?.execution,
|
|
6746
6786
|
description: options?.description,
|
|
6747
6787
|
});
|
|
6748
6788
|
return terminal.output;
|
|
@@ -6843,6 +6883,7 @@ export class PlayContextImpl {
|
|
|
6843
6883
|
}
|
|
6844
6884
|
this.recordPlayCallStep({
|
|
6845
6885
|
playId: resolvedName,
|
|
6886
|
+
execution: options?.execution,
|
|
6846
6887
|
description: options?.description,
|
|
6847
6888
|
nestedSteps: childContext.getSteps(),
|
|
6848
6889
|
});
|
|
@@ -214,6 +214,7 @@ export type PlayStep =
|
|
|
214
214
|
| {
|
|
215
215
|
type: 'play_call';
|
|
216
216
|
playId: string;
|
|
217
|
+
execution?: 'inline' | 'child-workflow';
|
|
217
218
|
results?: PlayStepRowResult[];
|
|
218
219
|
nestedSteps: PlayStep[];
|
|
219
220
|
description?: string;
|
|
@@ -252,6 +253,7 @@ export type PlayDatasetSubstep =
|
|
|
252
253
|
| {
|
|
253
254
|
type: 'play_call';
|
|
254
255
|
playId: string;
|
|
256
|
+
execution?: 'inline' | 'child-workflow';
|
|
255
257
|
results?: PlayStepRowResult[];
|
|
256
258
|
nestedSteps: PlayStep[];
|
|
257
259
|
description?: string;
|
|
@@ -24,6 +24,7 @@ import type { PreviousCell } from './cell-staleness';
|
|
|
24
24
|
import type { MapRowOutcome } from './durability-store';
|
|
25
25
|
import type { WorkReceiptFailureKind } from './work-receipts';
|
|
26
26
|
import type { RunExecutionScope } from './run-execution-scope';
|
|
27
|
+
import type { PlayCallExecution } from './play-call-execution';
|
|
27
28
|
|
|
28
29
|
export interface RowState {
|
|
29
30
|
results: Map<string, unknown>;
|
|
@@ -69,12 +70,26 @@ export interface RuntimeStepReceipt {
|
|
|
69
70
|
claimState?: 'claimed' | 'existing';
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
export type AcquireRuntimeReceiptExecutionLockInput = {
|
|
74
|
+
key: string;
|
|
75
|
+
runId: string;
|
|
76
|
+
ownerExecutionId: string;
|
|
77
|
+
ttlMs: number;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export type ReleaseRuntimeReceiptExecutionLockInput = {
|
|
81
|
+
key: string;
|
|
82
|
+
runId: string;
|
|
83
|
+
ownerExecutionId: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
72
86
|
export interface GetRuntimeStepReceiptInput {
|
|
73
87
|
key: string;
|
|
74
88
|
}
|
|
75
89
|
|
|
76
90
|
export interface ClaimRuntimeStepReceiptInput {
|
|
77
91
|
key: string;
|
|
92
|
+
leaseId?: string;
|
|
78
93
|
runId: string;
|
|
79
94
|
runAttempt?: number | null;
|
|
80
95
|
leaseAware?: boolean;
|
|
@@ -128,6 +143,7 @@ export interface GetRuntimeStepReceiptsInput {
|
|
|
128
143
|
|
|
129
144
|
export interface ClaimRuntimeStepReceiptsInput {
|
|
130
145
|
keys: string[];
|
|
146
|
+
leaseIds?: string[];
|
|
131
147
|
runId: string;
|
|
132
148
|
runAttempt?: number | null;
|
|
133
149
|
leaseAware?: boolean;
|
|
@@ -281,6 +297,7 @@ export type CustomerDbQueryHandler = (
|
|
|
281
297
|
|
|
282
298
|
export interface PlayCallOptions {
|
|
283
299
|
description?: string;
|
|
300
|
+
execution?: PlayCallExecution;
|
|
284
301
|
}
|
|
285
302
|
|
|
286
303
|
export interface StepOptions {
|
|
@@ -597,7 +614,10 @@ export interface ContextOptions {
|
|
|
597
614
|
rows: MapRowOutcome[];
|
|
598
615
|
outputFields: string[];
|
|
599
616
|
staticPipeline?: PlayStaticPipeline | null;
|
|
600
|
-
}) => Promise<void
|
|
617
|
+
}) => Promise<void | {
|
|
618
|
+
updated: number;
|
|
619
|
+
staleDroppedKeys?: string[];
|
|
620
|
+
}>;
|
|
601
621
|
playId?: string;
|
|
602
622
|
runId?: string;
|
|
603
623
|
/** Physical executor run that owns leases for an inline child context. */
|
|
@@ -634,6 +654,7 @@ export interface ContextOptions {
|
|
|
634
654
|
getToolQueueHints?: (toolId: string) => Promise<readonly PlayQueueHint[]>;
|
|
635
655
|
getToolRetryPolicy?: (toolId: string) => Promise<{
|
|
636
656
|
retrySafeTransientHttp?: boolean;
|
|
657
|
+
requiresExecutionFence?: boolean;
|
|
637
658
|
} | null>;
|
|
638
659
|
getToolActionCacheVersion?: (toolId: string) => Promise<string> | string;
|
|
639
660
|
getToolAuthScopeDigest?: (toolId: string) => Promise<string> | string;
|
|
@@ -672,6 +693,12 @@ export interface ContextOptions {
|
|
|
672
693
|
getRuntimeStepReceipt?: (
|
|
673
694
|
input: GetRuntimeStepReceiptInput,
|
|
674
695
|
) => Promise<RuntimeStepReceipt | null> | RuntimeStepReceipt | null;
|
|
696
|
+
acquireRuntimeReceiptExecutionLock?: (
|
|
697
|
+
input: AcquireRuntimeReceiptExecutionLockInput,
|
|
698
|
+
) => Promise<{ ownerExecutionId: string; expiresAt: string } | null>;
|
|
699
|
+
releaseRuntimeReceiptExecutionLock?: (
|
|
700
|
+
input: ReleaseRuntimeReceiptExecutionLockInput,
|
|
701
|
+
) => Promise<boolean>;
|
|
675
702
|
getRuntimeStepReceipts?: (
|
|
676
703
|
input: GetRuntimeStepReceiptsInput,
|
|
677
704
|
) =>
|
|
@@ -932,6 +959,7 @@ export type PlayStep =
|
|
|
932
959
|
| {
|
|
933
960
|
type: 'play_call';
|
|
934
961
|
playId: string;
|
|
962
|
+
execution?: PlayCallExecution;
|
|
935
963
|
results?: PlayStepRowResult[];
|
|
936
964
|
nestedSteps: PlayStep[];
|
|
937
965
|
description?: string;
|
|
@@ -971,6 +999,7 @@ export type PlayDatasetSubstep =
|
|
|
971
999
|
| {
|
|
972
1000
|
type: 'play_call';
|
|
973
1001
|
playId: string;
|
|
1002
|
+
execution?: PlayCallExecution;
|
|
974
1003
|
results?: PlayStepRowResult[];
|
|
975
1004
|
nestedSteps: PlayStep[];
|
|
976
1005
|
description?: string;
|