deepline 0.1.206 → 0.1.207

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 (29) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +25 -16
  2. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  3. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +96 -12
  4. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +51 -0
  5. package/dist/bundling-sources/shared_libs/play-runtime/child-run-id.ts +16 -0
  6. package/dist/bundling-sources/shared_libs/play-runtime/child-run-lifecycle.ts +70 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +321 -175
  8. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +13 -1
  9. package/dist/bundling-sources/shared_libs/play-runtime/governor/adaptive-admission.ts +16 -4
  10. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +161 -81
  11. package/dist/bundling-sources/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +26 -9
  12. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +109 -1
  13. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +1 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/receipt-completion-sink.ts +7 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/run-execution-scope.ts +256 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +17 -5
  17. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +103 -18
  18. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +8 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +1 -1
  20. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-pg.ts +5 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-compute-usage.ts +74 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +5 -12
  23. package/dist/bundling-sources/shared_libs/play-runtime/worker-api-types.ts +2 -1
  24. package/dist/bundling-sources/shared_libs/runtime-env.ts +55 -0
  25. package/dist/cli/index.js +27 -6
  26. package/dist/cli/index.mjs +27 -6
  27. package/dist/index.js +2 -2
  28. package/dist/index.mjs +2 -2
  29. package/package.json +1 -1
@@ -51,7 +51,17 @@ import {
51
51
  PLAY_RUNTIME_API_COMPAT_PATH,
52
52
  PLAY_RUNTIME_CHILD_EXECUTOR_TOKEN_COMPAT_PATH,
53
53
  } from './runtime-api-paths';
54
- import { startRunViaAppRuntime } from './app-runtime-api';
54
+ import {
55
+ settleInlineChildRunViaAppRuntime,
56
+ startRunViaAppRuntime,
57
+ } from './app-runtime-api';
58
+ import { executeChildRunLifecycle } from './child-run-lifecycle';
59
+ import {
60
+ createRootRunExecutionScope,
61
+ deriveChildRunExecutionScope,
62
+ type RunExecutionScope,
63
+ } from './run-execution-scope';
64
+ import { DEFAULT_RUNTIME_EXECUTION_CAPABILITIES } from './execution-capabilities';
55
65
  import { vercelProtectionBypassHeader } from './vercel-protection';
56
66
  export {
57
67
  RuntimeSheetRowsBlockedError,
@@ -126,7 +136,7 @@ import {
126
136
  isQueryResultDatasetReadRequest,
127
137
  isQueryResultDatasetTool,
128
138
  } from './query-result-dataset';
129
- import { isRowIsolationExemptError } from './row-isolation';
139
+ import { isAbortLikeError, isRowIsolationExemptError } from './row-isolation';
130
140
  import {
131
141
  createRuntimePersistenceLatch,
132
142
  RuntimePersistenceCircuitOpenError,
@@ -231,6 +241,12 @@ import {
231
241
  type StepProgramDatasetOptions,
232
242
  } from './step-program-dataset-builder';
233
243
  import { readRuntimeSheetDatasetRows } from './runtime-api';
244
+ import { resolveChildExecutionStrategy } from './child-execution-strategy';
245
+
246
+ type ResolvedPlayExecutor = (
247
+ ctx: PlayContextImpl,
248
+ input: Record<string, unknown>,
249
+ ) => Promise<unknown>;
234
250
 
235
251
  /**
236
252
  * SECURITY: AsyncLocalStorage is per async execution, not a cross-run cache.
@@ -1035,6 +1051,7 @@ export class PlayContextImpl {
1035
1051
  { resolve: (value: unknown) => void; reject: (reason: unknown) => void }
1036
1052
  >();
1037
1053
  #options: ContextOptions;
1054
+ private readonly executionScope: RunExecutionScope;
1038
1055
  private logBuffer: string[] = [];
1039
1056
  private checkpoint: PlayCheckpoint;
1040
1057
  private steps: PlayStep[] = [];
@@ -1094,6 +1111,10 @@ export class PlayContextImpl {
1094
1111
  * child run-id derivation. All policy lives in {@link governor}.
1095
1112
  */
1096
1113
  private readonly governance: GovernanceSnapshot;
1114
+ private readonly resolvedPlayExecutorCache = new Map<
1115
+ string,
1116
+ Promise<ResolvedPlayExecutor>
1117
+ >();
1097
1118
  readonly tools = {
1098
1119
  execute: <TOutput = unknown>(request: {
1099
1120
  id: string;
@@ -1200,33 +1221,53 @@ export class PlayContextImpl {
1200
1221
  options.workflowId ||
1201
1222
  'anonymous-play';
1202
1223
  const rootRunId = options.runId ?? options.workflowId ?? 'anonymous-run';
1224
+ this.executionScope =
1225
+ options.executionScope ??
1226
+ createRootRunExecutionScope({
1227
+ runId: rootRunId,
1228
+ playId: rootPlayId,
1229
+ attempt:
1230
+ typeof options.runAttempt === 'number' &&
1231
+ Number.isFinite(options.runAttempt)
1232
+ ? Math.max(0, Math.floor(options.runAttempt))
1233
+ : 0,
1234
+ receiptNamespace: options.runtimeReceiptScope ?? rootPlayId,
1235
+ authority: {
1236
+ orgId: options.orgId ?? 'org',
1237
+ workflowId: options.workflowId ?? rootRunId,
1238
+ integrationMode: options.integrationMode ?? null,
1239
+ capabilities: DEFAULT_RUNTIME_EXECUTION_CAPABILITIES,
1240
+ },
1241
+ });
1203
1242
  if (options.requireSharedRateState && !options.rateState) {
1204
1243
  throw new Error(
1205
1244
  'Shared rate-state backend is required for this Node runtime substrate.',
1206
1245
  );
1207
1246
  }
1208
- this.governor = createPlayExecutionGovernor({
1209
- adapter: 'cjs_node20',
1210
- scope: {
1211
- orgId: options.orgId ?? 'org',
1212
- rootRunId: options.runId ?? options.workflowId ?? 'run',
1213
- },
1214
- rateState: options.rateState ?? new InMemoryRateStateBackend(),
1215
- budgetState: options.budgetState,
1216
- resolvePacing: createPacingResolver(options.getToolQueueHints),
1217
- // A root run keeps depth 0 (its first child play is depth 1) but still
1218
- // seeds its own play id into the ancestry/currentPlayId so the cycle guard
1219
- // catches a child re-invoking the root. createDefaultGovernanceSnapshot
1220
- // couples depth to rootPlayId, so the root snapshot is built explicitly.
1221
- resume: options.governance ?? {
1222
- ...createDefaultGovernanceSnapshot({
1247
+ this.governor =
1248
+ options.executionGovernor ??
1249
+ createPlayExecutionGovernor({
1250
+ adapter: 'cjs_node20',
1251
+ scope: {
1223
1252
  orgId: options.orgId ?? 'org',
1224
- rootRunId,
1225
- }),
1226
- currentPlayId: rootPlayId,
1227
- ancestryPlayIds: [rootPlayId],
1228
- },
1229
- });
1253
+ rootRunId: options.runId ?? options.workflowId ?? 'run',
1254
+ },
1255
+ rateState: options.rateState ?? new InMemoryRateStateBackend(),
1256
+ budgetState: options.budgetState,
1257
+ resolvePacing: createPacingResolver(options.getToolQueueHints),
1258
+ // A root run keeps depth 0 (its first child play is depth 1) but still
1259
+ // seeds its own play id into the ancestry/currentPlayId so the cycle guard
1260
+ // catches a child re-invoking the root. createDefaultGovernanceSnapshot
1261
+ // couples depth to rootPlayId, so the root snapshot is built explicitly.
1262
+ resume: options.governance ?? {
1263
+ ...createDefaultGovernanceSnapshot({
1264
+ orgId: options.orgId ?? 'org',
1265
+ rootRunId,
1266
+ }),
1267
+ currentPlayId: rootPlayId,
1268
+ ancestryPlayIds: [rootPlayId],
1269
+ },
1270
+ });
1230
1271
  this.resourceGovernor = createRuntimeResourceGovernor({
1231
1272
  executionGovernor: this.governor,
1232
1273
  });
@@ -1716,7 +1757,7 @@ export class PlayContextImpl {
1716
1757
  }
1717
1758
  const claimed = await this.#options.claimRuntimeStepReceipt({
1718
1759
  key,
1719
- runId,
1760
+ runId: this.currentReceiptOwnerRunId,
1720
1761
  runAttempt: this.currentRunAttempt,
1721
1762
  leaseAware: true,
1722
1763
  ...(reclaimRunning ? { reclaimRunning: true } : {}),
@@ -1735,7 +1776,7 @@ export class PlayContextImpl {
1735
1776
 
1736
1777
  private async completeRuntimeStepReceipt(
1737
1778
  key: string,
1738
- runId: string,
1779
+ _runId: string,
1739
1780
  output: unknown | null,
1740
1781
  leaseId?: string | null,
1741
1782
  ): Promise<RuntimeStepReceipt | null> {
@@ -1749,7 +1790,7 @@ export class PlayContextImpl {
1749
1790
  }
1750
1791
  const completed = await this.#options.completeRuntimeStepReceipt({
1751
1792
  key,
1752
- runId,
1793
+ runId: this.currentReceiptOwnerRunId,
1753
1794
  runAttempt: this.currentRunAttempt,
1754
1795
  ...(leaseId ? { leaseId } : {}),
1755
1796
  output,
@@ -1770,7 +1811,7 @@ export class PlayContextImpl {
1770
1811
 
1771
1812
  private async releaseRuntimeStepReceipt(
1772
1813
  key: string,
1773
- runId: string,
1814
+ _runId: string,
1774
1815
  leaseId?: string | null,
1775
1816
  ): Promise<RuntimeStepReceipt | null> {
1776
1817
  if (!this.#options.releaseRuntimeStepReceipt) {
@@ -1778,7 +1819,7 @@ export class PlayContextImpl {
1778
1819
  }
1779
1820
  const released = await this.#options.releaseRuntimeStepReceipt({
1780
1821
  key,
1781
- runId,
1822
+ runId: this.currentReceiptOwnerRunId,
1782
1823
  runAttempt: this.currentRunAttempt,
1783
1824
  ...(leaseId ? { leaseId } : {}),
1784
1825
  });
@@ -1818,14 +1859,14 @@ export class PlayContextImpl {
1818
1859
 
1819
1860
  private async heartbeatRuntimeStepReceipt(
1820
1861
  key: string,
1821
- runId: string,
1862
+ _runId: string,
1822
1863
  leaseId: string,
1823
1864
  ): Promise<RuntimeStepReceipt | null> {
1824
1865
  if (!this.#options.heartbeatRuntimeStepReceipts) {
1825
1866
  return null;
1826
1867
  }
1827
1868
  const [receipt] = await this.#options.heartbeatRuntimeStepReceipts({
1828
- runId,
1869
+ runId: this.currentReceiptOwnerRunId,
1829
1870
  runAttempt: this.currentRunAttempt,
1830
1871
  leaseId,
1831
1872
  keys: [key],
@@ -1866,7 +1907,7 @@ export class PlayContextImpl {
1866
1907
  const receipts = await this.markRuntimeStepReceiptsRunning(
1867
1908
  targets.map((target) => ({
1868
1909
  key: target.receiptKey,
1869
- runId: this.currentRunId,
1910
+ runId: this.currentReceiptOwnerRunId,
1870
1911
  leaseId: target.leaseId,
1871
1912
  })),
1872
1913
  );
@@ -1875,7 +1916,7 @@ export class PlayContextImpl {
1875
1916
  if (!this.runtimeToolReceiptStillOwned(receipt, target.leaseId)) {
1876
1917
  throw new RuntimeReceiptLeaseLostError({
1877
1918
  receiptKey: target.receiptKey,
1878
- runId: this.currentRunId,
1919
+ runId: this.currentReceiptOwnerRunId,
1879
1920
  leaseId: target.leaseId,
1880
1921
  });
1881
1922
  }
@@ -1886,7 +1927,7 @@ export class PlayContextImpl {
1886
1927
  if (this.#options.heartbeatRuntimeStepReceipts) {
1887
1928
  for (const [leaseId, keys] of byLeaseId) {
1888
1929
  const receipts = await this.#options.heartbeatRuntimeStepReceipts({
1889
- runId: this.currentRunId,
1930
+ runId: this.currentReceiptOwnerRunId,
1890
1931
  runAttempt: this.currentRunAttempt,
1891
1932
  leaseId,
1892
1933
  keys,
@@ -1902,7 +1943,7 @@ export class PlayContextImpl {
1902
1943
  ) {
1903
1944
  throw new RuntimeReceiptLeaseLostError({
1904
1945
  receiptKey: targets[0]?.receiptKey ?? 'unknown',
1905
- runId: this.currentRunId,
1946
+ runId: this.currentReceiptOwnerRunId,
1906
1947
  leaseId: targets[0]?.leaseId ?? 'unknown',
1907
1948
  });
1908
1949
  }
@@ -1915,7 +1956,7 @@ export class PlayContextImpl {
1915
1956
  if (!this.runtimeToolReceiptStillOwned(receipt, target.leaseId)) {
1916
1957
  throw new RuntimeReceiptLeaseLostError({
1917
1958
  receiptKey: target.receiptKey,
1918
- runId: this.currentRunId,
1959
+ runId: this.currentReceiptOwnerRunId,
1919
1960
  leaseId: target.leaseId,
1920
1961
  });
1921
1962
  }
@@ -1935,7 +1976,7 @@ export class PlayContextImpl {
1935
1976
  if (!this.runtimeToolReceiptStillOwned(receipt, leaseId)) {
1936
1977
  throw new RuntimeReceiptLeaseLostError({
1937
1978
  receiptKey: keys[index] ?? 'unknown',
1938
- runId: this.currentRunId,
1979
+ runId: this.currentReceiptOwnerRunId,
1939
1980
  leaseId,
1940
1981
  });
1941
1982
  }
@@ -1953,7 +1994,7 @@ export class PlayContextImpl {
1953
1994
  if (receipt.status !== 'running') return false;
1954
1995
  if (receipt.leaseId !== leaseId) return false;
1955
1996
  const ownerRunId = receipt.leaseOwnerRunId ?? receipt.runId ?? null;
1956
- return !ownerRunId || ownerRunId === this.currentRunId;
1997
+ return !ownerRunId || ownerRunId === this.currentReceiptOwnerRunId;
1957
1998
  }
1958
1999
 
1959
2000
  private runtimeToolReceiptStillOwnedByCurrentAttempt(
@@ -1967,7 +2008,7 @@ export class PlayContextImpl {
1967
2008
  return false;
1968
2009
  }
1969
2010
  const ownerRunId = receipt.leaseOwnerRunId ?? receipt.runId ?? null;
1970
- if (ownerRunId !== this.currentRunId) return false;
2011
+ if (ownerRunId !== this.currentReceiptOwnerRunId) return false;
1971
2012
  const ownerAttempt =
1972
2013
  typeof receipt.leaseOwnerAttempt === 'number'
1973
2014
  ? receipt.leaseOwnerAttempt
@@ -1989,7 +2030,7 @@ export class PlayContextImpl {
1989
2030
 
1990
2031
  private async failRuntimeStepReceipt(
1991
2032
  key: string,
1992
- runId: string,
2033
+ _runId: string,
1993
2034
  error: string,
1994
2035
  leaseId?: string | null,
1995
2036
  failureKind?: WorkReceiptFailureKind | null,
@@ -1999,7 +2040,7 @@ export class PlayContextImpl {
1999
2040
  }
2000
2041
  const failed = await this.#options.failRuntimeStepReceipt({
2001
2042
  key,
2002
- runId,
2043
+ runId: this.currentReceiptOwnerRunId,
2003
2044
  runAttempt: this.currentRunAttempt,
2004
2045
  ...(leaseId ? { leaseId } : {}),
2005
2046
  ...(failureKind ? { failureKind } : {}),
@@ -2094,7 +2135,7 @@ export class PlayContextImpl {
2094
2135
 
2095
2136
  private async claimRuntimeStepReceipts(
2096
2137
  keys: string[],
2097
- runId: string,
2138
+ _runId: string,
2098
2139
  reclaimRunning = false,
2099
2140
  forceRefresh = false,
2100
2141
  forceFailedRefresh = false,
@@ -2108,7 +2149,7 @@ export class PlayContextImpl {
2108
2149
  ? await this.dispatchChunkedRuntimeReceiptRequest(uniqueKeys, (chunk) =>
2109
2150
  claimReceipts({
2110
2151
  keys: chunk,
2111
- runId,
2152
+ runId: this.currentReceiptOwnerRunId,
2112
2153
  runAttempt: this.currentRunAttempt,
2113
2154
  leaseAware: true,
2114
2155
  ...(reclaimRunning ? { reclaimRunning: true } : {}),
@@ -2120,7 +2161,7 @@ export class PlayContextImpl {
2120
2161
  uniqueKeys.map((key) =>
2121
2162
  this.claimRuntimeStepReceipt(
2122
2163
  key,
2123
- runId,
2164
+ this.currentReceiptOwnerRunId,
2124
2165
  reclaimRunning,
2125
2166
  forceRefresh,
2126
2167
  forceFailedRefresh,
@@ -2155,7 +2196,7 @@ export class PlayContextImpl {
2155
2196
  }
2156
2197
  const receipt = await this.#options.markRuntimeStepReceiptRunning({
2157
2198
  key: input.key,
2158
- runId: input.runId,
2199
+ runId: this.currentReceiptOwnerRunId,
2159
2200
  runAttempt: this.currentRunAttempt,
2160
2201
  ...(input.leaseId ? { leaseId: input.leaseId } : {}),
2161
2202
  });
@@ -2177,6 +2218,7 @@ export class PlayContextImpl {
2177
2218
  marked = await this.dispatchChunkedRuntimeReceiptRequest(
2178
2219
  normalizedInputs.map((receipt) => ({
2179
2220
  ...receipt,
2221
+ runId: this.currentReceiptOwnerRunId,
2180
2222
  runAttempt: this.currentRunAttempt,
2181
2223
  })),
2182
2224
  (chunk) => markReceipts({ receipts: chunk }),
@@ -2214,6 +2256,7 @@ export class PlayContextImpl {
2214
2256
  const queued = await this.dispatchChunkedRuntimeReceiptRequest(
2215
2257
  normalizedInputs.map((receipt) => ({
2216
2258
  ...receipt,
2259
+ runId: this.currentReceiptOwnerRunId,
2217
2260
  runAttempt: this.currentRunAttempt,
2218
2261
  })),
2219
2262
  (chunk) =>
@@ -2237,7 +2280,9 @@ export class PlayContextImpl {
2237
2280
  const receiptKey = request.receiptKey?.trim() || null;
2238
2281
  const leaseId = request.receiptLeaseId?.trim() || null;
2239
2282
  if (!receiptKey || !leaseId) return [];
2240
- return [{ key: receiptKey, runId: this.currentRunId, leaseId }];
2283
+ return [
2284
+ { key: receiptKey, runId: this.currentReceiptOwnerRunId, leaseId },
2285
+ ];
2241
2286
  });
2242
2287
  if (targets.length === 0) return;
2243
2288
  await this.markRuntimeStepReceiptsQueued(targets);
@@ -2268,6 +2313,7 @@ export class PlayContextImpl {
2268
2313
  ? await this.dispatchChunkedRuntimeReceiptRequest(
2269
2314
  normalizedInputs.map((receipt) => ({
2270
2315
  ...receipt,
2316
+ runId: this.currentReceiptOwnerRunId,
2271
2317
  runAttempt: receipt.runAttempt ?? this.currentRunAttempt,
2272
2318
  })),
2273
2319
  (chunk) => completeReceipts({ receipts: chunk }),
@@ -2412,6 +2458,7 @@ export class PlayContextImpl {
2412
2458
  ? await this.dispatchChunkedRuntimeReceiptRequest(
2413
2459
  normalizedInputs.map((receipt) => ({
2414
2460
  ...receipt,
2461
+ runId: this.currentReceiptOwnerRunId,
2415
2462
  runAttempt: receipt.runAttempt ?? this.currentRunAttempt,
2416
2463
  })),
2417
2464
  (chunk) => failReceipts({ receipts: chunk }),
@@ -2445,7 +2492,7 @@ export class PlayContextImpl {
2445
2492
  if (receiptKeys.length === 0) return;
2446
2493
  await this.claimRuntimeStepReceipts(
2447
2494
  receiptKeys,
2448
- this.currentRunId,
2495
+ this.currentReceiptOwnerRunId,
2449
2496
  true,
2450
2497
  true,
2451
2498
  );
@@ -2595,7 +2642,7 @@ export class PlayContextImpl {
2595
2642
  private async executeWithRuntimeReceipt<T>(
2596
2643
  operation: DurableCtxOperation,
2597
2644
  id: string,
2598
- runId: string,
2645
+ _runId: string,
2599
2646
  opts: {
2600
2647
  force?: boolean;
2601
2648
  receiptKey?: string | null;
@@ -2622,7 +2669,7 @@ export class PlayContextImpl {
2622
2669
  opts.receiptKey?.trim() ||
2623
2670
  durableCtxKey({
2624
2671
  orgId: this.#options.orgId,
2625
- playId: this.governance.currentPlayId,
2672
+ playId: this.executionScope.receipt.namespace,
2626
2673
  operation,
2627
2674
  id,
2628
2675
  semanticKey: opts.semanticKey,
@@ -2631,7 +2678,7 @@ export class PlayContextImpl {
2631
2678
  return await executeWithDurableRuntimeReceipt<T>({
2632
2679
  operation,
2633
2680
  id,
2634
- runId,
2681
+ runId: this.currentReceiptOwnerRunId,
2635
2682
  receiptKey,
2636
2683
  store: this.durableReceiptExecutionStore(),
2637
2684
  force: opts.force,
@@ -2653,14 +2700,15 @@ export class PlayContextImpl {
2653
2700
  }
2654
2701
 
2655
2702
  private get currentRunId(): string {
2656
- return this.#options.runId ?? this.governance.currentRunId ?? 'unknown';
2703
+ return this.executionScope.logical.runId;
2704
+ }
2705
+
2706
+ private get currentReceiptOwnerRunId(): string {
2707
+ return this.executionScope.receipt.ownerRunId;
2657
2708
  }
2658
2709
 
2659
2710
  private get currentRunAttempt(): number {
2660
- const attempt = this.#options.runAttempt;
2661
- return typeof attempt === 'number' && Number.isFinite(attempt)
2662
- ? Math.max(0, Math.floor(attempt))
2663
- : 0;
2711
+ return this.executionScope.receipt.ownerAttempt;
2664
2712
  }
2665
2713
 
2666
2714
  private emitScopedFieldMetaUpdate(input: {
@@ -3148,7 +3196,7 @@ export class PlayContextImpl {
3148
3196
  await this.completeRuntimeStepReceipts([
3149
3197
  {
3150
3198
  key: receiptKey,
3151
- runId: this.currentRunId,
3199
+ runId: this.currentReceiptOwnerRunId,
3152
3200
  leaseId: request.receiptLeaseId ?? null,
3153
3201
  output: serializeToolExecuteResult(wrapped),
3154
3202
  },
@@ -3204,7 +3252,7 @@ export class PlayContextImpl {
3204
3252
  ? [
3205
3253
  {
3206
3254
  key: receiptKey,
3207
- runId: this.currentRunId,
3255
+ runId: this.currentReceiptOwnerRunId,
3208
3256
  leaseId: entry.request.receiptLeaseId ?? null,
3209
3257
  output: serializeToolExecuteResult(entry.wrapped),
3210
3258
  },
@@ -3277,7 +3325,7 @@ export class PlayContextImpl {
3277
3325
  result: this.runtimeReceiptOutput(completed),
3278
3326
  requestInput: request.input,
3279
3327
  execution: toolExecutionMetadataForOutcome(
3280
- completed.runId === this.currentRunId
3328
+ completed.runId === this.currentReceiptOwnerRunId
3281
3329
  ? {
3282
3330
  kind: 'live',
3283
3331
  cacheKey,
@@ -3332,7 +3380,7 @@ export class PlayContextImpl {
3332
3380
  await this.failRuntimeStepReceipts([
3333
3381
  {
3334
3382
  key: receiptKey,
3335
- runId: this.currentRunId,
3383
+ runId: this.currentReceiptOwnerRunId,
3336
3384
  leaseId: request.receiptLeaseId ?? null,
3337
3385
  error: message,
3338
3386
  failureKind: runtimeReceiptFailureKindForError(error),
@@ -5879,7 +5927,7 @@ export class PlayContextImpl {
5879
5927
  await this.markRuntimeStepReceiptsQueued([
5880
5928
  {
5881
5929
  key: directCacheKey,
5882
- runId: this.currentRunId,
5930
+ runId: this.currentReceiptOwnerRunId,
5883
5931
  leaseId: directReceiptLeaseId,
5884
5932
  },
5885
5933
  ]);
@@ -6241,9 +6289,7 @@ export class PlayContextImpl {
6241
6289
  if (!resolvedName.trim()) {
6242
6290
  throw new Error('ctx.runPlay(...) requires a resolvable play name.');
6243
6291
  }
6244
- const scheduledChildPlayCall = this.shouldLaunchChildPlaysThroughScheduler()
6245
- ? this.beginScheduledChildPlayCall()
6246
- : null;
6292
+ let scheduledChildPlayCall: { release(): void } | null = null;
6247
6293
 
6248
6294
  try {
6249
6295
  if (!this.#options.resolvePlay) {
@@ -6260,6 +6306,18 @@ export class PlayContextImpl {
6260
6306
  }
6261
6307
  const childRevisionFingerprint =
6262
6308
  resolvedPlayRevisionFingerprint(resolvedPlay);
6309
+ const childExecutionDecision = resolveChildExecutionStrategy({
6310
+ pipeline: resolvedPlay.staticPipeline,
6311
+ });
6312
+ const launchThroughScheduler =
6313
+ this.shouldLaunchChildPlaysThroughScheduler() &&
6314
+ childExecutionDecision.strategy === 'scheduled';
6315
+ scheduledChildPlayCall = launchThroughScheduler
6316
+ ? this.beginScheduledChildPlayCall()
6317
+ : null;
6318
+ this.log(
6319
+ `ctx.runPlay(${normalizedKey}): ${childExecutionDecision.strategy} (${childExecutionDecision.reason})`,
6320
+ );
6263
6321
  const runPlayRowScope = rowContext.getStore();
6264
6322
  const runPlaySemanticKey = buildDurableRunPlaySemanticKey({
6265
6323
  childPlayName: resolvedName,
@@ -6298,11 +6356,21 @@ export class PlayContextImpl {
6298
6356
  input,
6299
6357
  graphHash: null,
6300
6358
  });
6301
- const childGovernance = await this.governor.forkChild({
6302
- childPlayName: resolvedName,
6303
- childRunId,
6304
- });
6305
- const childPlaySlot = await this.governor.acquireChildSubmitSlot();
6359
+ const inlineChildGovernor = launchThroughScheduler
6360
+ ? null
6361
+ : await this.governor.forkInlineChild({
6362
+ childPlayName: resolvedName,
6363
+ childRunId,
6364
+ });
6365
+ const childGovernance = launchThroughScheduler
6366
+ ? await this.governor.forkChild({
6367
+ childPlayName: resolvedName,
6368
+ childRunId,
6369
+ })
6370
+ : inlineChildGovernor!.snapshot();
6371
+ const childPlaySlot = launchThroughScheduler
6372
+ ? await this.governor.acquireChildSubmitSlot()
6373
+ : null;
6306
6374
  const rowStore = rowContext.getStore();
6307
6375
  const producer = {
6308
6376
  kind: 'play' as const,
@@ -6311,7 +6379,6 @@ export class PlayContextImpl {
6311
6379
  displayName: displayNameFromProducerId(resolvedName),
6312
6380
  runId: childRunId,
6313
6381
  };
6314
-
6315
6382
  try {
6316
6383
  if (rowStore) {
6317
6384
  this.emitScopedFieldMetaUpdate({
@@ -6328,7 +6395,7 @@ export class PlayContextImpl {
6328
6395
  dataPatch: {},
6329
6396
  });
6330
6397
  }
6331
- if (this.shouldLaunchChildPlaysThroughScheduler()) {
6398
+ if (launchThroughScheduler) {
6332
6399
  const boundaryId = this.childPlayBoundaryId(
6333
6400
  childGovernance.currentRunId,
6334
6401
  );
@@ -6368,7 +6435,7 @@ export class PlayContextImpl {
6368
6435
  childInput: input,
6369
6436
  description: options?.description ?? null,
6370
6437
  });
6371
- childPlaySlot.release();
6438
+ childPlaySlot?.release();
6372
6439
  const terminal = await this.readScheduledChildTerminal<TOutput>({
6373
6440
  childRunId: childGovernance.currentRunId,
6374
6441
  childPlayName: resolvedName,
@@ -6423,71 +6490,112 @@ export class PlayContextImpl {
6423
6490
  this.consumePendingChildPlaySuspension() ?? suspension,
6424
6491
  );
6425
6492
  }
6426
- await this.registerInlineChildRun({
6427
- parentRunId: this.currentRunId,
6428
- childRunId: childGovernance.currentRunId,
6429
- childPlayName: resolvedName,
6430
- staticPipeline: resolvedPlay.staticPipeline ?? null,
6431
- });
6432
- const childContext = createPlayContext({
6433
- ...this.#options,
6434
- playId: resolvedName,
6435
- playName: resolvedName,
6436
- runId: childGovernance.currentRunId,
6437
- executorToken: await this.mintChildExecutorToken({
6438
- parentRunId: this.currentRunId,
6439
- parentPlayName: this.#options.playName,
6440
- childRunId: childGovernance.currentRunId,
6493
+ const childExecutionScope = deriveChildRunExecutionScope(
6494
+ this.executionScope,
6495
+ {
6496
+ placement: 'inline',
6497
+ runId: childGovernance.currentRunId,
6498
+ playId: resolvedName,
6499
+ receiptNamespace: `${resolvedName}:${childGovernance.currentRunId}`,
6500
+ },
6501
+ );
6502
+ return await executeChildRunLifecycle({
6503
+ scope: childExecutionScope,
6504
+ metadata: {
6505
+ placement: 'inline',
6441
6506
  childPlayName: resolvedName,
6442
- }),
6443
- staticPipeline: resolvedPlay.staticPipeline ?? null,
6444
- checkpoint: this.checkpoint,
6445
- governance: childGovernance,
6446
- getRuntimeStepReceipt: undefined,
6447
- getRuntimeStepReceipts: undefined,
6448
- claimRuntimeStepReceipt: undefined,
6449
- claimRuntimeStepReceipts: undefined,
6450
- completeRuntimeStepReceipt: undefined,
6451
- completeRuntimeStepReceipts: undefined,
6452
- failRuntimeStepReceipt: undefined,
6453
- failRuntimeStepReceipts: undefined,
6454
- heartbeatRuntimeStepReceipts: undefined,
6455
- skipRuntimeStepReceipt: undefined,
6507
+ staticPipeline: resolvedPlay.staticPipeline ?? null,
6508
+ },
6509
+ adapter: {
6510
+ open: async () => {
6511
+ await this.registerInlineChildRun({
6512
+ scope: childExecutionScope,
6513
+ staticPipeline: resolvedPlay.staticPipeline ?? null,
6514
+ });
6515
+ },
6516
+ // start_inline_child_run records run.started with the durable row.
6517
+ started: () => undefined,
6518
+ complete: async (_scope, _metadata, result) => {
6519
+ await this.settleInlineChildRun({
6520
+ scope: childExecutionScope,
6521
+ status: 'completed',
6522
+ result,
6523
+ });
6524
+ },
6525
+ fail: async (_scope, _metadata, error) => {
6526
+ await this.settleInlineChildRun({
6527
+ scope: childExecutionScope,
6528
+ status: isAbortLikeError(error) ? 'cancelled' : 'failed',
6529
+ error: this.formatRuntimeError(error),
6530
+ });
6531
+ },
6532
+ },
6533
+ execute: async () => {
6534
+ const inlineScalarChild =
6535
+ childExecutionDecision.reason === 'scalar_child';
6536
+ const childContext = createPlayContext({
6537
+ ...this.#options,
6538
+ executionScope: childExecutionScope,
6539
+ playId: resolvedName,
6540
+ playName: resolvedName,
6541
+ runId: childGovernance.currentRunId,
6542
+ executorToken: inlineScalarChild
6543
+ ? this.#options.executorToken
6544
+ : await this.mintChildExecutorToken({
6545
+ parentRunId: this.currentRunId,
6546
+ parentPlayName: this.#options.playName,
6547
+ childRunId: childGovernance.currentRunId,
6548
+ childPlayName: resolvedName,
6549
+ }),
6550
+ staticPipeline: resolvedPlay.staticPipeline ?? null,
6551
+ checkpoint: this.checkpoint,
6552
+ governance: undefined,
6553
+ executionGovernor: inlineChildGovernor!,
6554
+ ...(inlineScalarChild
6555
+ ? {}
6556
+ : {
6557
+ getRuntimeStepReceipt: undefined,
6558
+ getRuntimeStepReceipts: undefined,
6559
+ claimRuntimeStepReceipt: undefined,
6560
+ claimRuntimeStepReceipts: undefined,
6561
+ completeRuntimeStepReceipt: undefined,
6562
+ completeRuntimeStepReceipts: undefined,
6563
+ failRuntimeStepReceipt: undefined,
6564
+ failRuntimeStepReceipts: undefined,
6565
+ heartbeatRuntimeStepReceipts: undefined,
6566
+ skipRuntimeStepReceipt: undefined,
6567
+ }),
6568
+ });
6569
+ const childExecution = this.executeResolvedPlay(
6570
+ resolvedPlay,
6571
+ childContext,
6572
+ input,
6573
+ );
6574
+ await childContext.drainQueuedWork([childExecution]);
6575
+ const result = await childExecution;
6576
+ if (rowStore) {
6577
+ this.emitScopedFieldMetaUpdate({
6578
+ rowId: rowStore.rowId,
6579
+ key: rowStore.rowKey ?? null,
6580
+ tableNamespace: rowStore.tableNamespace ?? null,
6581
+ fieldName: rowStore.fieldName,
6582
+ status: 'completed',
6583
+ rowStatus: 'running',
6584
+ stage: resolvedName,
6585
+ provider: 'deepline_native',
6586
+ error: null,
6587
+ producer,
6588
+ dataPatch: {},
6589
+ });
6590
+ }
6591
+ this.recordPlayCallStep({
6592
+ playId: resolvedName,
6593
+ description: options?.description,
6594
+ nestedSteps: childContext.getSteps(),
6595
+ });
6596
+ return result as TOutput;
6597
+ },
6456
6598
  });
6457
- const childExecution = this.executeResolvedPlay(
6458
- resolvedPlay,
6459
- childContext,
6460
- input,
6461
- );
6462
- await childContext.drainQueuedWork([childExecution]);
6463
- const result = await childExecution;
6464
- if (rowStore) {
6465
- this.emitScopedFieldMetaUpdate({
6466
- rowId: rowStore.rowId,
6467
- key: rowStore.rowKey ?? null,
6468
- tableNamespace: rowStore.tableNamespace ?? null,
6469
- fieldName: rowStore.fieldName,
6470
- status: 'completed',
6471
- rowStatus: 'running',
6472
- stage: resolvedName,
6473
- provider: 'deepline_native',
6474
- error: null,
6475
- producer,
6476
- dataPatch: {},
6477
- });
6478
- }
6479
- const step = {
6480
- type: 'play_call' as const,
6481
- playId: resolvedName,
6482
- nestedSteps: childContext.getSteps(),
6483
- description: normalizeStepDescription(options?.description),
6484
- };
6485
- if (this.activeDatasetStep) {
6486
- this.activeDatasetStep.substeps.push(step);
6487
- } else {
6488
- this.steps.push(step);
6489
- }
6490
- return result as TOutput;
6491
6599
  } catch (error) {
6492
6600
  if (isPlayExecutionSuspendedError(error)) {
6493
6601
  throw error;
@@ -6509,7 +6617,7 @@ export class PlayContextImpl {
6509
6617
  }
6510
6618
  throw error;
6511
6619
  } finally {
6512
- childPlaySlot.release();
6620
+ childPlaySlot?.release();
6513
6621
  }
6514
6622
  };
6515
6623
 
@@ -6588,9 +6696,7 @@ export class PlayContextImpl {
6588
6696
  }
6589
6697
 
6590
6698
  private async registerInlineChildRun(input: {
6591
- parentRunId: string;
6592
- childRunId: string;
6593
- childPlayName: string;
6699
+ scope: RunExecutionScope;
6594
6700
  staticPipeline: unknown;
6595
6701
  }): Promise<void> {
6596
6702
  const baseUrl = this.#options.baseUrl?.trim();
@@ -6606,11 +6712,11 @@ export class PlayContextImpl {
6606
6712
  this.#options.vercelProtectionBypassToken ?? null,
6607
6713
  },
6608
6714
  {
6609
- playName: input.childPlayName,
6610
- runId: input.childRunId,
6611
- parentRunId: input.parentRunId,
6612
- rootRunId: this.governance.rootRunId,
6613
- workflowFamilyKey: this.governance.rootRunId,
6715
+ playName: input.scope.logical.playId,
6716
+ runId: input.scope.logical.runId,
6717
+ parentRunId: input.scope.logical.parentRunId,
6718
+ rootRunId: input.scope.logical.rootRunId,
6719
+ workflowFamilyKey: input.scope.logical.rootRunId,
6614
6720
  artifactHash: this.#options.artifactHash ?? null,
6615
6721
  graphHash: this.#options.graphHash ?? null,
6616
6722
  schedulerSchema: this.#options.runtimeSchedulerSchema ?? null,
@@ -6621,6 +6727,35 @@ export class PlayContextImpl {
6621
6727
  );
6622
6728
  }
6623
6729
 
6730
+ private async settleInlineChildRun(input: {
6731
+ scope: RunExecutionScope;
6732
+ status: 'completed' | 'failed' | 'cancelled';
6733
+ result?: unknown;
6734
+ error?: string | null;
6735
+ }): Promise<void> {
6736
+ const baseUrl = this.#options.baseUrl?.trim();
6737
+ const executorToken = this.#options.executorToken?.trim();
6738
+ if (!baseUrl || !executorToken) return;
6739
+
6740
+ await settleInlineChildRunViaAppRuntime(
6741
+ {
6742
+ baseUrl,
6743
+ executorToken,
6744
+ integrationMode: this.#options.integrationMode ?? null,
6745
+ vercelProtectionBypassToken:
6746
+ this.#options.vercelProtectionBypassToken ?? null,
6747
+ },
6748
+ {
6749
+ parentRunId: input.scope.logical.parentRunId ?? this.currentRunId,
6750
+ childRunId: input.scope.logical.runId,
6751
+ childPlayName: input.scope.logical.playId,
6752
+ status: input.status,
6753
+ ...(input.result !== undefined ? { result: input.result } : {}),
6754
+ ...(input.error !== undefined ? { error: input.error } : {}),
6755
+ },
6756
+ );
6757
+ }
6758
+
6624
6759
  /**
6625
6760
  * Extract a list from a tool result.
6626
6761
  * e.g. ctx.extractList(result, 'people', ['first_name', 'last_name', 'email'])
@@ -7229,14 +7364,14 @@ export class PlayContextImpl {
7229
7364
  normalReceiptKeys.length > 0
7230
7365
  ? await this.claimRuntimeStepReceipts(
7231
7366
  normalReceiptKeys,
7232
- this.currentRunId,
7367
+ this.currentReceiptOwnerRunId,
7233
7368
  )
7234
7369
  : new Map<string, RuntimeStepReceipt>();
7235
7370
  const forcedClaims =
7236
7371
  claimableForcedReceiptKeys.length > 0
7237
7372
  ? await this.claimRuntimeStepReceipts(
7238
7373
  claimableForcedReceiptKeys,
7239
- this.currentRunId,
7374
+ this.currentReceiptOwnerRunId,
7240
7375
  false,
7241
7376
  true,
7242
7377
  )
@@ -7245,7 +7380,7 @@ export class PlayContextImpl {
7245
7380
  failedRefreshReceiptKeys.length > 0
7246
7381
  ? await this.claimRuntimeStepReceipts(
7247
7382
  failedRefreshReceiptKeys,
7248
- this.currentRunId,
7383
+ this.currentReceiptOwnerRunId,
7249
7384
  false,
7250
7385
  false,
7251
7386
  true,
@@ -7393,7 +7528,7 @@ export class PlayContextImpl {
7393
7528
  const reclaimed = (
7394
7529
  await this.claimRuntimeStepReceipts(
7395
7530
  [receiptKey],
7396
- this.currentRunId,
7531
+ this.currentReceiptOwnerRunId,
7397
7532
  true,
7398
7533
  forceAfterWait,
7399
7534
  )
@@ -7426,7 +7561,7 @@ export class PlayContextImpl {
7426
7561
  if (!reclaimed.leaseId) {
7427
7562
  throw new RuntimeReceiptLeaseLostError({
7428
7563
  receiptKey,
7429
- runId: this.currentRunId,
7564
+ runId: this.currentReceiptOwnerRunId,
7430
7565
  leaseId: 'missing',
7431
7566
  });
7432
7567
  }
@@ -7564,7 +7699,7 @@ export class PlayContextImpl {
7564
7699
  if (!claim.leaseId) {
7565
7700
  throw new RuntimeReceiptLeaseLostError({
7566
7701
  receiptKey,
7567
- runId: this.currentRunId,
7702
+ runId: this.currentReceiptOwnerRunId,
7568
7703
  leaseId: 'missing',
7569
7704
  });
7570
7705
  }
@@ -7895,34 +8030,45 @@ export class PlayContextImpl {
7895
8030
  `Play "${resolvedPlay.playId}" is missing a bundled artifact.`,
7896
8031
  );
7897
8032
  }
7898
- const runtimeModule =
7899
- (await import('node:module')) as unknown as typeof import('node:module') & {
7900
- Module: typeof import('node:module').Module & {
7901
- _nodeModulePaths: (from: string) => string[];
7902
- };
7903
- };
7904
- const compiled = new runtimeModule.Module(artifact.virtualFilename);
7905
- compiled.filename = artifact.virtualFilename;
7906
- compiled.paths = runtimeModule.Module._nodeModulePaths(process.cwd());
7907
- (
7908
- compiled as import('node:module').Module & {
7909
- _compile: (code: string, filename: string) => void;
7910
- }
7911
- )._compile(artifact.bundledCode, artifact.virtualFilename);
7912
- const candidate =
7913
- typeof compiled.exports === 'function'
7914
- ? compiled.exports
7915
- : (compiled.exports as { default?: unknown }).default;
7916
- if (typeof candidate !== 'function') {
7917
- throw new Error(
7918
- `Play "${resolvedPlay.playId}" does not export a callable default.`,
7919
- );
8033
+ const cacheKey = resolvedPlayRevisionFingerprint(resolvedPlay);
8034
+ let executor = this.resolvedPlayExecutorCache.get(cacheKey);
8035
+ if (!executor) {
8036
+ executor = (async (): Promise<ResolvedPlayExecutor> => {
8037
+ const runtimeModule =
8038
+ (await import('node:module')) as unknown as typeof import('node:module') & {
8039
+ Module: typeof import('node:module').Module & {
8040
+ _nodeModulePaths: (from: string) => string[];
8041
+ };
8042
+ };
8043
+ const compiled = new runtimeModule.Module(artifact.virtualFilename);
8044
+ compiled.filename = artifact.virtualFilename;
8045
+ compiled.paths = runtimeModule.Module._nodeModulePaths(process.cwd());
8046
+ (
8047
+ compiled as import('node:module').Module & {
8048
+ _compile: (code: string, filename: string) => void;
8049
+ }
8050
+ )._compile(artifact.bundledCode, artifact.virtualFilename);
8051
+ const candidate =
8052
+ typeof compiled.exports === 'function'
8053
+ ? compiled.exports
8054
+ : (compiled.exports as { default?: unknown }).default;
8055
+ if (typeof candidate !== 'function') {
8056
+ throw new Error(
8057
+ `Play "${resolvedPlay.playId}" does not export a callable default.`,
8058
+ );
8059
+ }
8060
+ return async (childCtx, runtimeInput) =>
8061
+ await (
8062
+ candidate as (
8063
+ runtimeCtx: unknown,
8064
+ value: Record<string, unknown>,
8065
+ ) => Promise<unknown>
8066
+ )(childCtx, runtimeInput);
8067
+ })();
8068
+ this.resolvedPlayExecutorCache.set(cacheKey, executor);
7920
8069
  }
7921
8070
  return await (
7922
- candidate as (
7923
- ctx: unknown,
7924
- runtimeInput: Record<string, unknown>,
7925
- ) => Promise<unknown>
8071
+ await executor
7926
8072
  )(ctx, input);
7927
8073
  }
7928
8074
 
@@ -7966,7 +8112,7 @@ export class PlayContextImpl {
7966
8112
  }): string {
7967
8113
  const fallbackAttemptId =
7968
8114
  input.force === true && !input.leaseId
7969
- ? `${this.currentRunId}:${crypto.randomUUID()}`
8115
+ ? `${this.currentReceiptOwnerRunId}:${crypto.randomUUID()}`
7970
8116
  : null;
7971
8117
  return buildDurableToolProviderIdempotencyKey({
7972
8118
  receiptKey: input.cacheKey,