deepline 0.3.333 → 0.3.334

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 (116) hide show
  1. package/dist/bundling-sources/sdk/src/play.ts +1 -1
  2. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  3. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +174 -20
  4. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +4 -0
  5. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +8 -2
  6. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +11 -7
  7. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-deadline.ts +14 -14
  8. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +12 -5
  9. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +6 -1
  10. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +7 -2
  11. package/dist/bundling-sources/shared_libs/play-runtime/suspension.ts +1 -0
  12. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +7 -0
  13. package/dist/cli/{auth-OQ356CEE.mjs → auth-PAEBUPRS.mjs} +4 -4
  14. package/dist/cli/auth-WR3XFOHN.js +31 -0
  15. package/dist/cli/{billing-7YVHLDMO.mjs → billing-QGQJUM5G.mjs} +4 -4
  16. package/dist/cli/{billing-3APFTHNY.js → billing-V746QMQC.js} +71 -71
  17. package/dist/cli/{chunk-KBXHB5P3.js → chunk-6466HVYR.js} +26 -26
  18. package/dist/cli/{chunk-V77J5ISS.js → chunk-6MVMTDL7.js} +4 -4
  19. package/dist/cli/{chunk-UHHTRBJF.js → chunk-7XXNMV6G.js} +45 -45
  20. package/dist/cli/{chunk-HNX3RC6V.mjs → chunk-A7S4PRK2.mjs} +1 -1
  21. package/dist/cli/{chunk-F2XAQHQC.mjs → chunk-EJLUQARV.mjs} +4 -4
  22. package/dist/cli/{chunk-KREEYWVL.mjs → chunk-EJVAWHQ7.mjs} +6 -6
  23. package/dist/cli/{chunk-3WQJWQ5T.js → chunk-FLMBKUHB.js} +60 -60
  24. package/dist/cli/{chunk-AFVETOG3.js → chunk-GNHI4WZC.js} +15 -15
  25. package/dist/cli/{chunk-NI4FJRFJ.mjs → chunk-GUMAWNWZ.mjs} +5 -5
  26. package/dist/cli/{chunk-DROPDYOD.js → chunk-GX2YGFQV.js} +1 -1
  27. package/dist/cli/{chunk-IYFKFNEB.js → chunk-HIPRSI5H.js} +225 -225
  28. package/dist/cli/{chunk-IDEK4DND.js → chunk-NLHRXDIT.js} +2 -2
  29. package/dist/cli/{chunk-AGGDEQDF.mjs → chunk-O564PHDU.mjs} +1 -1
  30. package/dist/cli/{chunk-4DUEB2WO.mjs → chunk-O64RSXDZ.mjs} +2 -2
  31. package/dist/cli/{chunk-2CLENWOQ.mjs → chunk-P3ZX3NSE.mjs} +1 -1
  32. package/dist/cli/{chunk-64CZWDWT.js → chunk-R6O3YVIG.js} +8 -8
  33. package/dist/cli/{chunk-5A44CWQE.js → chunk-SABEM6FL.js} +48 -48
  34. package/dist/cli/{chunk-ABVOFJAE.mjs → chunk-SBEWKGUA.mjs} +1 -1
  35. package/dist/cli/{chunk-SXX4ST3D.mjs → chunk-TT2CLWMK.mjs} +1 -1
  36. package/dist/cli/{chunk-N5KGBQPG.mjs → chunk-TVIWEQ4V.mjs} +3 -3
  37. package/dist/cli/{chunk-H5SORD7Q.mjs → chunk-U724V33M.mjs} +2 -2
  38. package/dist/cli/{chunk-PRZ4S4NU.js → chunk-UUB3FTKZ.js} +6 -6
  39. package/dist/cli/{chunk-5UN6KLD2.mjs → chunk-VB7TNIUB.mjs} +1 -1
  40. package/dist/cli/{chunk-STVJ7ZPD.js → chunk-XXZSLV7B.js} +6 -6
  41. package/dist/cli/{chunk-6JPZJ5W7.mjs → chunk-Y2VN54ME.mjs} +2 -2
  42. package/dist/cli/{chunk-F2QKAGST.js → chunk-Z6VHC643.js} +9 -9
  43. package/dist/cli/client-6OBIO6GC.js +20 -0
  44. package/dist/cli/{client-WKS7HQRP.mjs → client-JIZWAGVW.mjs} +3 -3
  45. package/dist/cli/{csv-ZFY2LD2K.mjs → csv-7DCY7Z6R.mjs} +3 -3
  46. package/dist/cli/{csv-MMW6EKKD.js → csv-KAFKXAFU.js} +12 -12
  47. package/dist/cli/{db-FMOQU6QW.js → db-5LJPO2VA.js} +29 -29
  48. package/dist/cli/{db-Q2NJVILC.mjs → db-KJBWUFPL.mjs} +4 -4
  49. package/dist/cli/{describe-EWP7DMNU.mjs → describe-CPF4KDKZ.mjs} +8 -8
  50. package/dist/cli/{describe-4KG2JAQV.js → describe-VJEEVOH6.js} +15 -15
  51. package/dist/cli/{executions-UOD7FWEE.mjs → executions-LJN5QOK7.mjs} +4 -4
  52. package/dist/cli/{executions-Y4XSGKN6.js → executions-LPVCV5SC.js} +6 -6
  53. package/dist/cli/{feedback-3F3EURZC.mjs → feedback-3HYS6ECC.mjs} +3 -3
  54. package/dist/cli/{feedback-TEJJUXDI.js → feedback-K26WP7HJ.js} +6 -6
  55. package/dist/cli/{git-5YM22RGA.mjs → git-U4VBLXSS.mjs} +4 -4
  56. package/dist/cli/git-VMQTXKJQ.js +23 -0
  57. package/dist/cli/index.js +79 -79
  58. package/dist/cli/index.mjs +31 -31
  59. package/dist/cli/{legacy-noops-T5OUSXMR.js → legacy-noops-32YL3VF4.js} +7 -7
  60. package/dist/cli/{legacy-noops-D5XBVUHS.mjs → legacy-noops-ORHX2FMA.mjs} +4 -4
  61. package/dist/cli/{monitors-LPZNYNQW.mjs → monitors-5JJBEJS7.mjs} +4 -4
  62. package/dist/cli/{monitors-VI7VBQRP.js → monitors-NFE4ICED.js} +85 -85
  63. package/dist/cli/{org-OBGIV5QE.js → org-7CJS35TF.js} +60 -60
  64. package/dist/cli/{org-BYIDOMJB.mjs → org-RJYSDJ3W.mjs} +4 -4
  65. package/dist/cli/play-FUZYMPHF.js +153 -0
  66. package/dist/cli/{play-Y5PQQRBO.mjs → play-H2QUTJR2.mjs} +7 -7
  67. package/dist/cli/{providers-GEGIGKOL.mjs → providers-TEVRE4Q6.mjs} +4 -4
  68. package/dist/cli/{providers-VH6J7FFY.js → providers-VUKRZWZY.js} +7 -7
  69. package/dist/cli/{quickstart-GHITFT27.mjs → quickstart-2MIHVSZO.mjs} +3 -3
  70. package/dist/cli/{quickstart-ZQX5XNHG.js → quickstart-36OGYQ2P.js} +5 -5
  71. package/dist/cli/search-DFSHYVZ5.js +26 -0
  72. package/dist/cli/{search-AFX3DYAC.mjs → search-IRRQSN6R.mjs} +5 -5
  73. package/dist/cli/{secrets-4EOVXQJM.mjs → secrets-3W6OVDVE.mjs} +4 -4
  74. package/dist/cli/{secrets-F37M7D7R.js → secrets-K67ZKZZM.js} +13 -13
  75. package/dist/cli/{sessions-RX5SFHDI.mjs → sessions-AOMOV4HG.mjs} +4 -4
  76. package/dist/cli/{sessions-T57Q72GD.js → sessions-SLQ2QFLK.js} +5 -5
  77. package/dist/cli/{settings-3FVWW7GL.js → settings-2X7H6O4I.js} +74 -74
  78. package/dist/cli/{settings-764O5ZEH.mjs → settings-L4IFYF5D.mjs} +7 -7
  79. package/dist/cli/{setup-FQVRVTR6.js → setup-2RY5APQS.js} +41 -41
  80. package/dist/cli/{setup-X7OAHFTO.mjs → setup-CZYQTZ2K.mjs} +6 -6
  81. package/dist/cli/{skills-O6ILHPV5.mjs → skills-D2QQH5S7.mjs} +4 -4
  82. package/dist/cli/skills-RIFYRYWL.js +28 -0
  83. package/dist/cli/tools-M7LTH6ZT.js +40 -0
  84. package/dist/cli/{tools-HL4SQG35.mjs → tools-TYIEROJJ.mjs} +6 -6
  85. package/dist/cli/{update-A3P2RSIB.mjs → update-7YCSUWFP.mjs} +6 -6
  86. package/dist/cli/update-HC62SVSQ.js +28 -0
  87. package/dist/cli/{workflow-62AGKI6T.js → workflow-42IFLYPN.js} +15 -15
  88. package/dist/cli/{workflow-44424AVE.mjs → workflow-GGRUCLCI.mjs} +5 -5
  89. package/dist/{client-l-IoLh8Z.d.ts → client-DkoxT4wF.d.ts} +1 -1
  90. package/dist/{client-D5XOQKsA.d.mts → client-PDAfbylh.d.mts} +1 -1
  91. package/dist/{compiler-manifest-82q4jtfQ.d.ts → compiler-manifest-CButyeZ8.d.mts} +7 -0
  92. package/dist/{compiler-manifest-82q4jtfQ.d.mts → compiler-manifest-CButyeZ8.d.ts} +7 -0
  93. package/dist/{index-BPbW2XHF.d.mts → index-BMsNUoL5.d.mts} +1 -1
  94. package/dist/{index-k0rquHIm.d.ts → index-LDRzwo09.d.ts} +1 -1
  95. package/dist/index.d.mts +6 -6
  96. package/dist/index.d.ts +6 -6
  97. package/dist/index.js +6 -6
  98. package/dist/index.mjs +3 -3
  99. package/dist/install-integrity.json +80 -80
  100. package/dist/plays/bundle-play-file.d.mts +3 -3
  101. package/dist/plays/bundle-play-file.d.ts +3 -3
  102. package/dist/plays/run-request.d.mts +2 -2
  103. package/dist/plays/run-request.d.ts +2 -2
  104. package/dist/release.d.mts +1 -1
  105. package/dist/release.d.ts +1 -1
  106. package/dist/release.js +2 -2
  107. package/dist/release.mjs +1 -1
  108. package/package.json +1 -1
  109. package/dist/cli/auth-26GA3RM6.js +0 -31
  110. package/dist/cli/client-IZRTEBU4.js +0 -20
  111. package/dist/cli/git-GNEZSTVF.js +0 -23
  112. package/dist/cli/play-5JYRSXAL.js +0 -153
  113. package/dist/cli/search-YIXGQFXA.js +0 -26
  114. package/dist/cli/skills-DPGB67XX.js +0 -28
  115. package/dist/cli/tools-WZCXSXER.js +0 -40
  116. package/dist/cli/update-63MANY7U.js +0 -28
@@ -477,7 +477,7 @@ export type CsvOptions = PlayAuthoringCsvOptions;
477
477
  * // Emit a log line (visible in `play tail`)
478
478
  * ctx.log(`Loaded ${await leads.count()} leads`);
479
479
  *
480
- * // Pause execution
480
+ * // Wait at least one second before continuing.
481
481
  * await ctx.sleep(1000);
482
482
  *
483
483
  * // Access submitted input through the handler's second argument.
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
200
200
  // getters keep their established compatibility behavior.
201
201
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
202
202
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
203
- version: '0.3.333',
203
+ version: '0.3.334',
204
204
  updateSummary:
205
205
  'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
206
206
  packageCapabilities: {
@@ -654,6 +654,7 @@ const TOOL_RETRY_AFTER_FALLBACK_MS = 1_000;
654
654
  export const TOOL_EXECUTE_RESPONSE_BODY_TIMEOUT_MS = 30_000;
655
655
  const TOOL_RETRY_HEARTBEAT_INTERVAL_MS = 30_000;
656
656
  const TOOL_PROVIDER_RESIDENT_WAIT_BUDGET_MS = 5_000;
657
+ const AUTHORED_SLEEP_RESIDENT_LIMIT_MS = 10_000;
657
658
  const DEEPLINEAGENT_TOOL_RUNTIME_TIMEOUT_MS = 15 * 60 * 1000;
658
659
  // Every runtime-API tool fetch needs a client-side deadline. Without one, a
659
660
  // stalled execute request (e.g. a credential-less call whose gateway connection
@@ -2929,6 +2930,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
2929
2930
  */
2930
2931
  private readonly persistenceLatch: RuntimePersistenceLatch =
2931
2932
  createRuntimePersistenceLatch();
2933
+ private sleepMetadataPersistenceFailed = false;
2932
2934
  /**
2933
2935
  * The single source of every concurrency, budget, and pacing decision for this
2934
2936
  * run-attempt. Tool/play/row slots are blocking semaphores; budgets are charged
@@ -3154,6 +3156,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
3154
3156
  */
3155
3157
  assertNoPendingDurableSuspension(): void {
3156
3158
  this.#options.executionSignal?.throwIfAborted();
3159
+ if (this.sleepMetadataPersistenceFailed) {
3160
+ throw new RuntimePersistenceCircuitOpenError(this.persistenceLatch);
3161
+ }
3157
3162
  this.assertNoSlackHitlTimeoutFailure();
3158
3163
  this.assertNoRowProviderBackpressure();
3159
3164
  if (this.pendingDurableSuspension) {
@@ -6235,7 +6240,10 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
6235
6240
  runningReceiptWaitMaxAttempts?: number;
6236
6241
  runningReceiptWaitDelayMs?: number;
6237
6242
  reclaimRunning?: boolean;
6238
- markSkipped?: (output: T) => Promise<void> | void;
6243
+ markSkipped?: (
6244
+ output: T,
6245
+ receipt: RuntimeStepReceipt,
6246
+ ) => Promise<void> | void;
6239
6247
  onRecovered?: (
6240
6248
  output: T,
6241
6249
  receipt: RuntimeStepReceipt,
@@ -14581,6 +14589,111 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
14581
14589
  this.suspendDurably({ kind: 'sleep', boundaryId, delayMs });
14582
14590
  }
14583
14591
 
14592
+ private sleepMetadataReceiptKey(
14593
+ boundaryId: string,
14594
+ intent: 'wake' | 'count',
14595
+ ): string {
14596
+ return durableCtxKey({
14597
+ orgId: this.#options.orgId,
14598
+ playId: this.currentExecutionScope.receipt.namespace,
14599
+ operation: 'step',
14600
+ id: `__deepline_sleep_${intent}__`,
14601
+ semanticKey: stableStringify({
14602
+ runId: this.currentReceiptOwnerRunId,
14603
+ boundaryId,
14604
+ }),
14605
+ });
14606
+ }
14607
+
14608
+ private async readStepSleepCount(boundaryId: string): Promise<number | null> {
14609
+ try {
14610
+ const receipt = await this.getRuntimeStepReceipt(
14611
+ this.sleepMetadataReceiptKey(boundaryId, 'count'),
14612
+ );
14613
+ if (receipt?.status !== 'completed') return null;
14614
+ const output = receipt.output;
14615
+ const sleepCount =
14616
+ output && typeof output === 'object' && 'sleepCount' in output
14617
+ ? output.sleepCount
14618
+ : undefined;
14619
+ if (
14620
+ typeof sleepCount !== 'number' ||
14621
+ !Number.isSafeInteger(sleepCount) ||
14622
+ sleepCount < 0
14623
+ ) {
14624
+ throw new Error(`Durable step ${boundaryId} has no valid sleep count.`);
14625
+ }
14626
+ return sleepCount;
14627
+ } catch (error) {
14628
+ this.sleepMetadataPersistenceFailed = true;
14629
+ tripRuntimePersistenceLatch(this.persistenceLatch, error);
14630
+ throw error;
14631
+ }
14632
+ }
14633
+
14634
+ private async persistStepSleepCount(
14635
+ boundaryId: string,
14636
+ sleepCount: number,
14637
+ ): Promise<void> {
14638
+ try {
14639
+ await this.completeRuntimeStepReceipt(
14640
+ this.sleepMetadataReceiptKey(boundaryId, 'count'),
14641
+ this.currentReceiptOwnerRunId,
14642
+ { sleepCount },
14643
+ COMPLETED_RECEIPT_CACHE_INSERT_LEASE_ID,
14644
+ );
14645
+ if ((await this.readStepSleepCount(boundaryId)) === null) {
14646
+ throw new Error(
14647
+ `Durable step ${boundaryId} did not persist its sleep count.`,
14648
+ );
14649
+ }
14650
+ } catch (error) {
14651
+ this.sleepMetadataPersistenceFailed = true;
14652
+ tripRuntimePersistenceLatch(this.persistenceLatch, error);
14653
+ throw error;
14654
+ }
14655
+ }
14656
+
14657
+ private async resolveCanonicalSleepWakeAtMs(
14658
+ boundaryId: string,
14659
+ delayMs: number,
14660
+ ): Promise<number> {
14661
+ const key = this.sleepMetadataReceiptKey(boundaryId, 'wake');
14662
+ const proposedWakeAtMs = Date.now() + delayMs;
14663
+ try {
14664
+ let receipt = await this.getRuntimeStepReceipt(key);
14665
+ if (receipt?.status !== 'completed') {
14666
+ await this.completeRuntimeStepReceipt(
14667
+ key,
14668
+ this.currentReceiptOwnerRunId,
14669
+ { wakeAtMs: proposedWakeAtMs },
14670
+ COMPLETED_RECEIPT_CACHE_INSERT_LEASE_ID,
14671
+ );
14672
+ receipt = await this.getRuntimeStepReceipt(key);
14673
+ }
14674
+ const output = receipt?.output;
14675
+ const wakeAtMs =
14676
+ output && typeof output === 'object' && 'wakeAtMs' in output
14677
+ ? output.wakeAtMs
14678
+ : undefined;
14679
+ if (
14680
+ receipt?.status !== 'completed' ||
14681
+ typeof wakeAtMs !== 'number' ||
14682
+ !Number.isSafeInteger(wakeAtMs) ||
14683
+ wakeAtMs < 0
14684
+ ) {
14685
+ throw new Error(
14686
+ `Durable sleep intent ${boundaryId} has no valid wake timestamp.`,
14687
+ );
14688
+ }
14689
+ return wakeAtMs;
14690
+ } catch (error) {
14691
+ this.sleepMetadataPersistenceFailed = true;
14692
+ tripRuntimePersistenceLatch(this.persistenceLatch, error);
14693
+ throw error;
14694
+ }
14695
+ }
14696
+
14584
14697
  async sleep(ms: number): Promise<void> {
14585
14698
  if (!rowContext.getStore()) this.assertRowAdmissionOpen();
14586
14699
  this.assertNoPendingDurableSuspension();
@@ -14654,17 +14767,49 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
14654
14767
  if (existing?.kind === 'sleep' && existing.completedAt !== undefined) {
14655
14768
  return;
14656
14769
  }
14770
+ const wakeAtMs =
14771
+ existing?.kind === 'sleep' && existing.wakeAtMs !== undefined
14772
+ ? existing.wakeAtMs
14773
+ : this.durableDirectToolResultsBackedByReceipts
14774
+ ? await this.resolveCanonicalSleepWakeAtMs(boundaryId, delayMs)
14775
+ : undefined;
14776
+ this.assertNoPendingDurableSuspension();
14657
14777
  this.checkpoint.resolvedBoundaries = {
14658
14778
  ...(this.checkpoint.resolvedBoundaries ?? {}),
14659
14779
  [boundaryId]: {
14780
+ ...existing,
14660
14781
  kind: 'sleep',
14661
14782
  delayMs,
14783
+ ...(wakeAtMs !== undefined ? { wakeAtMs } : {}),
14662
14784
  },
14663
14785
  };
14786
+ if (
14787
+ wakeAtMs !== undefined &&
14788
+ !rowStore &&
14789
+ this.durableDirectToolResultsBackedByReceipts &&
14790
+ (wakeAtMs <= Date.now() ||
14791
+ (delayMs <= AUTHORED_SLEEP_RESIDENT_LIMIT_MS &&
14792
+ wakeAtMs < (this.#options.executionDrainAtMs ?? Infinity)))
14793
+ ) {
14794
+ const remainingMs = Math.max(0, wakeAtMs - Date.now());
14795
+ if (remainingMs > 0)
14796
+ await this.sleepWithCheckpointHeartbeat(remainingMs);
14797
+ this.assertNoPendingDurableSuspension();
14798
+ this.checkpoint.resolvedBoundaries[boundaryId] = {
14799
+ ...this.checkpoint.resolvedBoundaries[boundaryId],
14800
+ kind: 'sleep',
14801
+ delayMs,
14802
+ wakeAtMs,
14803
+ completedAt: Date.now(),
14804
+ };
14805
+ this.#options.onBatchComplete?.(this.checkpoint);
14806
+ return;
14807
+ }
14664
14808
  this.suspendDurably({
14665
14809
  kind: 'sleep',
14666
14810
  boundaryId,
14667
14811
  delayMs,
14812
+ ...(wakeAtMs !== undefined ? { wakeAtMs } : {}),
14668
14813
  });
14669
14814
  }
14670
14815
  return new Promise((resolve) => setTimeout(resolve, delayMs));
@@ -15001,30 +15146,33 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
15001
15146
  const boundaryId = this.durableBoundaryId(
15002
15147
  `step-${scope}:${normalizedKey}${boundarySuffix}`,
15003
15148
  );
15149
+ const advanceRecoveredSleepCursor = async (
15150
+ receipt?: RuntimeStepReceipt,
15151
+ ) => {
15152
+ if (rowStore?.replayCallIndexes?.recoverStep(boundaryId)) return;
15153
+ const existing = assertKnownResolvedBoundary(
15154
+ boundaryId,
15155
+ this.checkpoint.resolvedBoundaries?.[boundaryId],
15156
+ );
15157
+ const sleepCount =
15158
+ existing?.kind === 'step' && existing.sleepCount !== undefined
15159
+ ? existing.sleepCount
15160
+ : receipt?.runId === this.currentReceiptOwnerRunId
15161
+ ? ((await this.readStepSleepCount(boundaryId)) ?? 0)
15162
+ : 0;
15163
+ if (Number.isSafeInteger(sleepCount) && sleepCount > 0)
15164
+ this.sleepBoundaryIndex += sleepCount;
15165
+ };
15004
15166
  const executeStep = async (): Promise<T> => {
15005
15167
  const existing = assertKnownResolvedBoundary(
15006
15168
  boundaryId,
15007
15169
  this.checkpoint.resolvedBoundaries?.[boundaryId],
15008
15170
  );
15009
15171
  if (existing?.kind === 'step' && 'output' in existing) {
15010
- const replayedCalls =
15011
- rowStore?.replayCallIndexes?.recoverStep(boundaryId) ?? false;
15012
15172
  this.runtimeLog(
15013
15173
  `ctx.step(${normalizedKey}): recovered result from checkpoint`,
15014
15174
  );
15015
- // The step callback is not evaluated on replay, so any sleeps that it
15016
- // contained would otherwise disappear from the positional sleep
15017
- // cursor. Preserve the authored boundary sequence before evaluating
15018
- // the next sibling operation. This is deliberately run-local state;
15019
- // it is not a cross-run sleep cache or an input-derived identity.
15020
- if (
15021
- !replayedCalls &&
15022
- Number.isSafeInteger(existing.sleepCount) &&
15023
- existing.sleepCount !== undefined &&
15024
- existing.sleepCount > 0
15025
- ) {
15026
- this.sleepBoundaryIndex += existing.sleepCount;
15027
- }
15175
+ await advanceRecoveredSleepCursor();
15028
15176
  return existing.output as T;
15029
15177
  }
15030
15178
 
@@ -15047,15 +15195,20 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
15047
15195
  // publish an enclosing step fallback that would make a later resume skip
15048
15196
  // the suspended work.
15049
15197
  this.assertNoPendingDurableSuspension();
15198
+ const sleepCount = rowStore?.replayCallIndexes
15199
+ ? (callAdvances.get('sleep:legacy') ?? 0)
15200
+ : this.sleepBoundaryIndex - sleepBoundaryIndexBefore;
15201
+ if (sleepCount > 0 && this.durableDirectToolResultsBackedByReceipts) {
15202
+ await this.persistStepSleepCount(boundaryId, sleepCount);
15203
+ }
15204
+ this.assertNoPendingDurableSuspension();
15050
15205
  this.checkpoint.resolvedBoundaries = {
15051
15206
  ...(this.checkpoint.resolvedBoundaries ?? {}),
15052
15207
  [boundaryId]: {
15053
15208
  kind: 'step',
15054
15209
  stepId: normalizedKey,
15055
15210
  output,
15056
- sleepCount: rowStore?.replayCallIndexes
15057
- ? (callAdvances.get('sleep:legacy') ?? 0)
15058
- : this.sleepBoundaryIndex - sleepBoundaryIndexBefore,
15211
+ sleepCount,
15059
15212
  completedAt: Date.now(),
15060
15213
  },
15061
15214
  };
@@ -15100,8 +15253,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
15100
15253
  : options?.semanticKey,
15101
15254
  staleAfterSeconds: options?.staleAfterSeconds,
15102
15255
  force: this.#options.cachePolicy?.forceStepRefresh === true,
15103
- markSkipped: (output) => {
15256
+ markSkipped: async (output, receipt) => {
15104
15257
  assertJsonSerializableStepOutput(normalizedKey, output);
15258
+ await advanceRecoveredSleepCursor(receipt);
15105
15259
  },
15106
15260
  execute: executeStep,
15107
15261
  },
@@ -815,6 +815,8 @@ export interface ContextOptions {
815
815
  rowAdmissionSignal?: AbortSignal;
816
816
  /** Local runner cancellation; never serialized into a Play artifact. */
817
817
  executionSignal?: AbortSignal;
818
+ /** Runner-local deadline for stopping new work, captured when its timer arms. */
819
+ executionDrainAtMs?: number;
818
820
  /**
819
821
  * Runtime-sheet transport selected by the runner. Daytona sandboxes use the
820
822
  * execution gateway and must never fall back to minting direct DB sessions.
@@ -1244,6 +1246,8 @@ export interface PlayCheckpoint {
1244
1246
  | {
1245
1247
  kind: 'sleep';
1246
1248
  delayMs: number;
1249
+ /** Original wake deadline. Historical boundaries retain relative waits. */
1250
+ wakeAtMs?: number;
1247
1251
  completedAt?: number;
1248
1252
  scope?: {
1249
1253
  type: 'workflow' | 'map_row';
@@ -777,7 +777,10 @@ export async function executeWithDurableRuntimeReceipt<T>(input: {
777
777
  runningReceiptWaitMaxAttempts?: number;
778
778
  runningReceiptWaitDelayMs?: number;
779
779
  reclaimRunning?: boolean;
780
- markSkipped?: (output: T) => Promise<void> | void;
780
+ markSkipped?: (
781
+ output: T,
782
+ receipt: RuntimeStepReceipt,
783
+ ) => Promise<void> | void;
781
784
  onRecovered?: (
782
785
  output: T,
783
786
  receipt: RuntimeStepReceipt,
@@ -812,6 +815,9 @@ export async function executeWithDurableRuntimeReceipt<T>(input: {
812
815
  ): Promise<T> => {
813
816
  input.log(`ctx.${input.operation}(${input.id}): reused completed work`);
814
817
  if (receipt.output === undefined) {
818
+ if (input.operation === 'step' && input.markSkipped) {
819
+ await input.markSkipped(receipt.output as T, receipt);
820
+ }
815
821
  return receipt.output as T;
816
822
  }
817
823
  const output = runtimeReceiptOutput<T>(receipt);
@@ -819,7 +825,7 @@ export async function executeWithDurableRuntimeReceipt<T>(input: {
819
825
  ? input.onRecovered(output, receipt, 'cache')
820
826
  : output;
821
827
  if (input.markSkipped) {
822
- await input.markSkipped(recovered);
828
+ await input.markSkipped(recovered, receipt);
823
829
  }
824
830
  return recovered;
825
831
  };
@@ -1159,6 +1159,7 @@ export interface ExecutePlayRunnerOptions {
1159
1159
  signal?: AbortSignal;
1160
1160
  /** Stops future row admission while already admitted rows can persist. */
1161
1161
  rowAdmissionSignal?: AbortSignal;
1162
+ executionDrainAtMs?: number;
1162
1163
  /** Runner-local terminal state made available to the deadline drain. */
1163
1164
  onRuntimeReady?: (runtime: {
1164
1165
  log: (line: string) => void;
@@ -2036,14 +2037,15 @@ async function run(
2036
2037
  runnerRunAttempt,
2037
2038
  );
2038
2039
  const workCounterSegmentId = randomUUID();
2040
+ const runtimeLimitMs =
2041
+ validatePlaySandboxRuntimeLimits(
2042
+ config.context.sandboxRuntimeLimits ??
2043
+ STANDARD_PLAY_SANDBOX_RUNTIME_LIMITS,
2044
+ ).timeoutSeconds * 1_000;
2039
2045
  const persistenceSignal =
2040
- options?.signal ??
2041
- AbortSignal.timeout(
2042
- validatePlaySandboxRuntimeLimits(
2043
- config.context.sandboxRuntimeLimits ??
2044
- STANDARD_PLAY_SANDBOX_RUNTIME_LIMITS,
2045
- ).timeoutSeconds * 1_000,
2046
- );
2046
+ options?.signal ?? AbortSignal.timeout(runtimeLimitMs);
2047
+ const executionDrainAtMs =
2048
+ options?.executionDrainAtMs ?? runStartedAt + runtimeLimitMs;
2047
2049
  const contextSetupStartedAt = Date.now();
2048
2050
  const getRuntimeToolMetadata = createRuntimeToolMetadataResolver(config);
2049
2051
  const getRuntimeToolAuthScopeDigest =
@@ -2225,6 +2227,7 @@ async function run(
2225
2227
  artifactRuntimeContract,
2226
2228
  rowAdmissionSignal: options?.rowAdmissionSignal,
2227
2229
  executionSignal: persistenceSignal,
2230
+ executionDrainAtMs,
2228
2231
  executorToken: config.context.executorToken,
2229
2232
  baseUrl: config.context.baseUrl,
2230
2233
  // Runtime control stays on baseUrl (the receipt gateway); provider calls
@@ -3894,6 +3897,7 @@ async function main() {
3894
3897
  result = await executePlayRunner(config, {
3895
3898
  signal: executionController.signal,
3896
3899
  rowAdmissionSignal: rowAdmissionController.signal,
3900
+ executionDrainAtMs: runtimeDeadline.drainAtMs,
3897
3901
  onRuntimeReady: (runtime) => {
3898
3902
  runtimeState = runtime;
3899
3903
  },
@@ -16,6 +16,7 @@ export interface PlayRunnerRuntimeDeadlineOptions {
16
16
  }
17
17
 
18
18
  export interface PlayRunnerRuntimeDeadlineHandle {
19
+ drainAtMs: number;
19
20
  /** Claim normal settlement. False means the deadline already won. */
20
21
  claimCompletion: () => boolean;
21
22
  /** Settles only if the deadline callback unexpectedly returns or rejects. */
@@ -60,6 +61,10 @@ export function startPlayRunnerRuntimeDeadline(
60
61
  options: PlayRunnerRuntimeDeadlineOptions,
61
62
  ): PlayRunnerRuntimeDeadlineHandle {
62
63
  const limitMs = Math.max(1, Math.floor(options.limitMs));
64
+ const drainDelayMs = options.onDrain
65
+ ? Math.max(1, limitMs - Math.min(options.drainLeadMs ?? 4_000, limitMs / 2))
66
+ : limitMs;
67
+ const drainAtMs = Date.now() + drainDelayMs;
63
68
  const setTimeoutImpl =
64
69
  options.setTimeoutImpl ??
65
70
  ((callback, delayMs) => setTimeout(callback, delayMs));
@@ -73,20 +78,14 @@ export function startPlayRunnerRuntimeDeadline(
73
78
  settleDeadline = resolve;
74
79
  });
75
80
  const drainHandle = options.onDrain
76
- ? setTimeoutImpl(
77
- () => {
78
- if (fired || completionClaimed) return;
79
- try {
80
- options.onDrain?.();
81
- } catch (error) {
82
- options.onError?.(error);
83
- }
84
- },
85
- Math.max(
86
- 1,
87
- limitMs - Math.min(options.drainLeadMs ?? 4_000, limitMs / 2),
88
- ),
89
- )
81
+ ? setTimeoutImpl(() => {
82
+ if (fired || completionClaimed) return;
83
+ try {
84
+ options.onDrain?.();
85
+ } catch (error) {
86
+ options.onError?.(error);
87
+ }
88
+ }, drainDelayMs)
90
89
  : null;
91
90
  const handle = setTimeoutImpl(() => {
92
91
  if (fired || completionClaimed) return;
@@ -99,6 +98,7 @@ export function startPlayRunnerRuntimeDeadline(
99
98
  }, limitMs);
100
99
 
101
100
  return {
101
+ drainAtMs,
102
102
  claimCompletion: () => {
103
103
  if (fired || completionClaimed) return false;
104
104
  completionClaimed = true;
@@ -736,7 +736,7 @@ export class AbsurdExecutionOperationTimeoutError extends Error {
736
736
  * park/resume seam without a real engine. */
737
737
  export type AbsurdSuspensionContext = Pick<
738
738
  TaskContext,
739
- 'sleepFor' | 'awaitEvent' | 'heartbeat'
739
+ 'sleepFor' | 'sleepUntil' | 'awaitEvent' | 'heartbeat'
740
740
  >;
741
741
 
742
742
  /** Injected DB + app-runtime seams so the handler is testable against real SQL
@@ -1393,10 +1393,17 @@ export async function parkAndResolveSuspension(input: {
1393
1393
 
1394
1394
  if (suspension.kind === 'sleep') {
1395
1395
  // Throws SuspendTask on the first leg; returns once the deadline elapsed.
1396
- await ctx.sleepFor(
1397
- suspension.boundaryId,
1398
- Math.max(0, suspension.delayMs) / 1000,
1399
- );
1396
+ if (suspension.wakeAtMs !== undefined) {
1397
+ await ctx.sleepUntil(
1398
+ suspension.boundaryId,
1399
+ new Date(suspension.wakeAtMs),
1400
+ );
1401
+ } else {
1402
+ await ctx.sleepFor(
1403
+ suspension.boundaryId,
1404
+ Math.max(0, suspension.delayMs) / 1000,
1405
+ );
1406
+ }
1400
1407
  return absurdCheckpointWithSleep(
1401
1408
  checkpoint,
1402
1409
  suspension.boundaryId,
@@ -818,7 +818,12 @@ export function absurdCheckpointWithSleep(
818
818
  ...base,
819
819
  resolvedBoundaries: {
820
820
  ...resolvedBoundaries(base),
821
- [boundaryId]: { kind: 'sleep', delayMs, completedAt: Date.now() },
821
+ [boundaryId]: {
822
+ ...resolvedBoundaries(base)[boundaryId],
823
+ kind: 'sleep',
824
+ delayMs,
825
+ completedAt: Date.now(),
826
+ },
822
827
  },
823
828
  };
824
829
  }
@@ -17448,7 +17448,10 @@ async function loadPostgresSchedulerStagedFile(
17448
17448
  export async function readPostgresSchedulerResult(
17449
17449
  client: PostgresSchedulerQueryClient,
17450
17450
  runId: string,
17451
- options?: Pick<PostgresSchedulerOptions, 'schema'>,
17451
+ options?: Pick<PostgresSchedulerOptions, 'schema'> & {
17452
+ /** Read-only customer-result hydration; ordinary scheduler reads retain their behavior. */
17453
+ includeCancelledOutput?: boolean;
17454
+ },
17452
17455
  ): Promise<PlaySchedulerResultEnvelope | null> {
17453
17456
  const result = await client.query<RunRow>(
17454
17457
  `
@@ -17477,7 +17480,9 @@ export async function readPostgresSchedulerResult(
17477
17480
  runId: row.run_id,
17478
17481
  status: row.status,
17479
17482
  ...(row.status === 'completed' ||
17480
- (row.status === 'failed' && row.terminal_result_json !== null)
17483
+ ((row.status === 'failed' ||
17484
+ (row.status === 'cancelled' && options?.includeCancelledOutput)) &&
17485
+ row.terminal_result_json !== null)
17481
17486
  ? { output: row.terminal_result_json }
17482
17487
  : {}),
17483
17488
  ...(row.status === 'failed' || row.status === 'cancelled'
@@ -8,6 +8,7 @@ export type PlayExecutionSuspension =
8
8
  kind: 'sleep';
9
9
  boundaryId: string;
10
10
  delayMs: number;
11
+ wakeAtMs?: number;
11
12
  }
12
13
  | {
13
14
  kind: 'integration_event';
@@ -1659,6 +1659,13 @@ export interface PlayAuthoringRuntimeContext<
1659
1659
  context?: Readonly<Record<string, string | number | boolean>>;
1660
1660
  },
1661
1661
  ): void;
1662
+ /**
1663
+ * Wait at least the requested duration before continuing the Play.
1664
+ * Waits of at most 10 seconds stay in the current execution when its remaining time permits.
1665
+ * Longer waits park the Run. On wake, replay reuses completed steps and sleeps.
1666
+ * Scheduling and replay can delay continuation beyond the requested duration.
1667
+ * Use sequential waits for backoff or coordination outside Dataset resolvers.
1668
+ */
1662
1669
  sleep(ms: number): Promise<void>;
1663
1670
  }
1664
1671
 
@@ -9,11 +9,11 @@ import {
9
9
  registerAuthCommands,
10
10
  reportSetupCompleted,
11
11
  resolvePendingAuthClaimForResume
12
- } from "./chunk-H5SORD7Q.mjs";
13
- import "./chunk-HNX3RC6V.mjs";
14
- import "./chunk-5UN6KLD2.mjs";
12
+ } from "./chunk-U724V33M.mjs";
13
+ import "./chunk-A7S4PRK2.mjs";
14
+ import "./chunk-VB7TNIUB.mjs";
15
15
  import "./chunk-DLIRSHV6.mjs";
16
- import "./chunk-2CLENWOQ.mjs";
16
+ import "./chunk-P3ZX3NSE.mjs";
17
17
  import "./chunk-NXGCO4JB.mjs";
18
18
  import "./chunk-WZYKRD7T.mjs";
19
19
  import "./chunk-KRD6H754.mjs";
@@ -0,0 +1,31 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+ var _chunkSABEM6FLjs = require('./chunk-SABEM6FL.js');
13
+ require('./chunk-UUB3FTKZ.js');
14
+ require('./chunk-6MVMTDL7.js');
15
+ require('./chunk-XNYIZMNQ.js');
16
+ require('./chunk-GX2YGFQV.js');
17
+ require('./chunk-7P5AA3SN.js');
18
+ require('./chunk-OG64RBAC.js');
19
+ require('./chunk-COGTRVWW.js');
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+ exports.EXIT_WORKSPACE_MISMATCH = _chunkSABEM6FLjs.EXIT_WORKSPACE_MISMATCH; exports.clearPendingClaim = _chunkSABEM6FLjs.clearPendingClaim; exports.clearSatisfiedPendingClaim = _chunkSABEM6FLjs.clearSatisfiedPendingClaim; exports.handleRegister = _chunkSABEM6FLjs.handleRegister; exports.handleStatus = _chunkSABEM6FLjs.handleStatus; exports.handleWait = _chunkSABEM6FLjs.handleWait; exports.readPendingAuthClaim = _chunkSABEM6FLjs.readPendingAuthClaim; exports.registerAuthCommands = _chunkSABEM6FLjs.registerAuthCommands; exports.reportSetupCompleted = _chunkSABEM6FLjs.reportSetupCompleted; exports.resolvePendingAuthClaimForResume = _chunkSABEM6FLjs.resolvePendingAuthClaimForResume;
@@ -2,7 +2,7 @@ import {
2
2
  DeeplineClient,
3
3
  iterateCursorPages,
4
4
  requireBillingIdempotencyKey
5
- } from "./chunk-SXX4ST3D.mjs";
5
+ } from "./chunk-TT2CLWMK.mjs";
6
6
  import "./chunk-CBVIJSHF.mjs";
7
7
  import {
8
8
  createTimestampedName,
@@ -10,13 +10,13 @@ import {
10
10
  openInBrowser,
11
11
  printCommandEnvelope,
12
12
  shouldEmitJson
13
- } from "./chunk-HNX3RC6V.mjs";
13
+ } from "./chunk-A7S4PRK2.mjs";
14
14
  import {
15
15
  AuthError,
16
16
  ConfigError
17
- } from "./chunk-5UN6KLD2.mjs";
17
+ } from "./chunk-VB7TNIUB.mjs";
18
18
  import "./chunk-DLIRSHV6.mjs";
19
- import "./chunk-2CLENWOQ.mjs";
19
+ import "./chunk-P3ZX3NSE.mjs";
20
20
  import "./chunk-6IKARAYD.mjs";
21
21
  import {
22
22
  DeeplineError