deepline 0.3.463 → 0.3.465

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 (158) hide show
  1. package/dist/bundling-sources/sdk/src/play.ts +3 -0
  2. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  3. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +130 -55
  4. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +16 -2
  5. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +98 -0
  6. package/dist/bundling-sources/shared_libs/plays/field-catalog.ts +353 -52
  7. package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +63 -3
  8. package/dist/cli/auth-W62UTNJZ.js +41 -0
  9. package/dist/cli/{auth-LZLBR4C3.mjs → auth-WZCX4MTH.mjs} +5 -5
  10. package/dist/cli/{billing-OTOP5RE4.mjs → billing-ATR3CLIW.mjs} +6 -6
  11. package/dist/cli/{billing-6TJPNJQD.js → billing-DQUD3DBY.js} +77 -77
  12. package/dist/cli/{chunk-IKWRUNAP.mjs → chunk-3K3EHT6E.mjs} +1 -1
  13. package/dist/cli/{chunk-ALZBANZI.js → chunk-3XFNF6RR.js} +8 -8
  14. package/dist/cli/{chunk-3BOIOCNX.js → chunk-4URRABMM.js} +1 -1
  15. package/dist/cli/{chunk-BGNWI3KH.js → chunk-5VGMRONE.js} +3 -3
  16. package/dist/cli/{chunk-5LEAXRHV.js → chunk-6P4OYABU.js} +54 -226
  17. package/dist/cli/{chunk-UROQDCVW.js → chunk-6WKYRHGT.js} +3 -3
  18. package/dist/cli/{chunk-VDGTTH7K.mjs → chunk-6Y34LU6P.mjs} +2 -2
  19. package/dist/cli/{chunk-5DRNNC72.js → chunk-7R76B3WE.js} +5 -5
  20. package/dist/cli/{chunk-C25QE4CH.mjs → chunk-7Y2MLWTM.mjs} +1 -1
  21. package/dist/cli/chunk-7YDN6AEK.mjs +649 -0
  22. package/dist/cli/{chunk-VY2GBNTX.js → chunk-A3GML7WW.js} +9 -9
  23. package/dist/cli/{chunk-UIURR26V.mjs → chunk-B6GAIXVD.mjs} +4 -4
  24. package/dist/cli/{chunk-7XYDDCQ2.js → chunk-BQNUJK53.js} +26 -26
  25. package/dist/cli/{chunk-FK2HNDCN.js → chunk-DDF74332.js} +2 -2
  26. package/dist/cli/{chunk-JVDKZJUH.js → chunk-DJD4KLIX.js} +258 -258
  27. package/dist/cli/{chunk-7D6X7IXW.mjs → chunk-E3EYQ2FQ.mjs} +4 -4
  28. package/dist/cli/{chunk-WUZS2HK6.js → chunk-E3PLLFE2.js} +53 -53
  29. package/dist/cli/{chunk-BAPTQDLF.mjs → chunk-EA2F4YVX.mjs} +2 -2
  30. package/dist/cli/{chunk-XDWS2JJT.mjs → chunk-EISIAWBD.mjs} +1 -1
  31. package/dist/cli/{chunk-GUT7CLOL.mjs → chunk-EVQBOVOJ.mjs} +3 -3
  32. package/dist/cli/{chunk-S4XQCFES.mjs → chunk-FFTLJGZQ.mjs} +5 -5
  33. package/dist/cli/{chunk-5LHXOIPT.js → chunk-GBQSEOXE.js} +7 -7
  34. package/dist/cli/{chunk-NTLI6P6Y.mjs → chunk-GNLCGR7R.mjs} +2 -2
  35. package/dist/cli/{chunk-RD6IQ2JY.mjs → chunk-GW7RUNLW.mjs} +1 -1
  36. package/dist/cli/{chunk-6PMCRYDA.js → chunk-HIMV32ZX.js} +6 -4
  37. package/dist/cli/{chunk-CVQ7N5CV.mjs → chunk-HS6CM7TF.mjs} +11 -11
  38. package/dist/cli/{chunk-DHXCBITQ.mjs → chunk-HXWZ52CW.mjs} +3 -3
  39. package/dist/cli/{chunk-MSY22NQW.mjs → chunk-I2TCWIW2.mjs} +44 -216
  40. package/dist/cli/chunk-JLZKF7EY.js +649 -0
  41. package/dist/cli/{chunk-TIRBDQ3W.js → chunk-JN7AOVD4.js} +16 -16
  42. package/dist/cli/{chunk-4YZKBBLZ.mjs → chunk-JQSPKPHT.mjs} +5 -5
  43. package/dist/cli/{chunk-XQCTG5OO.js → chunk-L3U44YVO.js} +5 -5
  44. package/dist/cli/{chunk-7FCYPAPP.js → chunk-LFTLH5BK.js} +2 -2
  45. package/dist/cli/{chunk-TKAQR3IB.mjs → chunk-MUQAKLBP.mjs} +1 -1
  46. package/dist/cli/{chunk-3U5EAP6E.mjs → chunk-N27BUJU3.mjs} +5 -5
  47. package/dist/cli/{chunk-NDHJR2WZ.js → chunk-N57JYG7J.js} +36 -36
  48. package/dist/cli/{chunk-O3BJYD6D.mjs → chunk-NIJYJI67.mjs} +2 -2
  49. package/dist/cli/{chunk-CTQ56DXP.mjs → chunk-OEU3ZNBZ.mjs} +1 -1
  50. package/dist/cli/{chunk-VPHN2HAL.mjs → chunk-OGCAGZXO.mjs} +6 -4
  51. package/dist/cli/{chunk-NAPTMYTY.js → chunk-OKI3HWFF.js} +8 -8
  52. package/dist/cli/{chunk-PVY4DPPF.js → chunk-OQDN6JK6.js} +13 -13
  53. package/dist/cli/{chunk-CBZP6J3V.js → chunk-PIGMBDBZ.js} +21 -21
  54. package/dist/cli/{chunk-SKU6ECIY.js → chunk-QPJ2BDFD.js} +5 -5
  55. package/dist/cli/{chunk-UC4SFYNU.js → chunk-RREWUPC3.js} +6 -6
  56. package/dist/cli/{chunk-LYFKBLJI.mjs → chunk-SBM5JVTK.mjs} +1 -1
  57. package/dist/cli/{chunk-2NISBXMN.js → chunk-SOIXDMZK.js} +51 -51
  58. package/dist/cli/{chunk-WUMIYOXQ.mjs → chunk-SSQXSMAT.mjs} +2 -2
  59. package/dist/cli/{chunk-2ZIRCBYG.js → chunk-TJXGEK7P.js} +6 -6
  60. package/dist/cli/{chunk-XW2JIYG7.mjs → chunk-UMQT7QMB.mjs} +2 -2
  61. package/dist/cli/{chunk-RGOUCIIZ.js → chunk-W4J2EK5K.js} +3 -3
  62. package/dist/cli/{chunk-3BVLLJ3H.mjs → chunk-X6BQ4JAD.mjs} +2 -2
  63. package/dist/cli/{chunk-F2RHUPVH.mjs → chunk-XFAO5A5R.mjs} +1 -1
  64. package/dist/cli/{chunk-YGGIZ3VT.js → chunk-XJ5W64AC.js} +4 -4
  65. package/dist/cli/{chunk-I624J4H5.mjs → chunk-YZZGFUQ4.mjs} +1 -1
  66. package/dist/cli/command-docs.js +2 -2
  67. package/dist/cli/command-docs.mjs +1 -1
  68. package/dist/cli/{csv-OK45Z5XQ.mjs → csv-AE7OLXCV.mjs} +4 -4
  69. package/dist/cli/{csv-EH5QWR4O.js → csv-ZVFGYRB7.js} +13 -13
  70. package/dist/cli/{db-3ESJKETS.js → db-JOD2MQ2T.js} +27 -27
  71. package/dist/cli/{db-6Z5E4HKN.mjs → db-KTXMCLB5.mjs} +6 -6
  72. package/dist/cli/describe-2IKB4KIX.js +48 -0
  73. package/dist/cli/{describe-PNDQB7YS.mjs → describe-FENTKQFK.mjs} +20 -20
  74. package/dist/cli/describe-core.d.mts +3 -3
  75. package/dist/cli/describe-core.d.ts +3 -3
  76. package/dist/cli/describe-core.js +4 -4
  77. package/dist/cli/describe-core.mjs +3 -3
  78. package/dist/cli/{executions-2NTWQFEG.mjs → executions-FJCV5L37.mjs} +6 -6
  79. package/dist/cli/{executions-KUOBRX5V.js → executions-IT6TQ65Q.js} +8 -8
  80. package/dist/cli/{feedback-7RPRMSGY.mjs → feedback-LTTO73YD.mjs} +4 -4
  81. package/dist/cli/{feedback-UPHAZJ4C.js → feedback-WGURC3BG.js} +8 -8
  82. package/dist/cli/git-UOIC2DJL.js +25 -0
  83. package/dist/cli/{git-SCYP6WSZ.mjs → git-ZYEDB2UG.mjs} +5 -5
  84. package/dist/cli/index.js +139 -139
  85. package/dist/cli/index.mjs +41 -41
  86. package/dist/cli/{legacy-noops-A4KYAGI6.mjs → legacy-noops-EGQ4G4BT.mjs} +5 -5
  87. package/dist/cli/{legacy-noops-7XMFCVRG.js → legacy-noops-JFXWEOZF.js} +8 -8
  88. package/dist/cli/{monitors-FLC5J7RI.mjs → monitors-IK6GWLCA.mjs} +7 -7
  89. package/dist/cli/{monitors-NZV6IX5H.js → monitors-WKN2K6ZH.js} +91 -91
  90. package/dist/cli/{org-IZ7UP3XF.js → org-FE5VMAKF.js} +68 -68
  91. package/dist/cli/{org-LUETJ7Z5.mjs → org-PD5YBUHR.mjs} +6 -6
  92. package/dist/cli/{pages-22ML3O7O.js → pages-H3DKEVVI.js} +17 -17
  93. package/dist/cli/{pages-EUX5EAGF.mjs → pages-ZVKSOSZJ.mjs} +6 -6
  94. package/dist/cli/{play-USJBQADG.js → play-2UL5OPGH.js} +305 -305
  95. package/dist/cli/{play-CDHPAKKM.mjs → play-RLIQY22H.mjs} +18 -18
  96. package/dist/cli/{providers-WFEUNPGC.js → providers-2IMHQDBC.js} +9 -9
  97. package/dist/cli/{providers-CCXZ3SQF.mjs → providers-M4AFFJF2.mjs} +6 -6
  98. package/dist/cli/{quickstart-O4JSUORZ.js → quickstart-OE64DBKK.js} +6 -6
  99. package/dist/cli/{quickstart-ZUULI635.mjs → quickstart-PS4QKNG2.mjs} +4 -4
  100. package/dist/cli/{run-QJ4NX5F5.mjs → run-3TKR5CZU.mjs} +25 -25
  101. package/dist/cli/{run-ISDJYJMU.js → run-SWLGV2VS.js} +40 -40
  102. package/dist/cli/{search-IX3XKZJ3.mjs → search-AMZ67RKO.mjs} +7 -7
  103. package/dist/cli/search-LXG7T6YZ.js +32 -0
  104. package/dist/cli/{secrets-7VUDXTUZ.mjs → secrets-INBXKNFM.mjs} +6 -6
  105. package/dist/cli/{secrets-ELQSNCTR.js → secrets-ZTLJY7L2.js} +15 -15
  106. package/dist/cli/{sessions-A3FG3AZX.js → sessions-3GKS45NP.js} +6 -6
  107. package/dist/cli/{sessions-VOIQ62GB.mjs → sessions-ZVBTKQ7J.mjs} +5 -5
  108. package/dist/cli/{settings-ZTXQEMZI.js → settings-7YG3UWJH.js} +78 -78
  109. package/dist/cli/{settings-S6N6EFBG.mjs → settings-AUPDZZ2U.mjs} +11 -11
  110. package/dist/cli/{setup-AYPIK4JE.mjs → setup-44QB72NU.mjs} +9 -9
  111. package/dist/cli/{setup-Y3WOIFLS.js → setup-YGESCFTH.js} +44 -44
  112. package/dist/cli/{skills-5SF5QWNI.mjs → skills-N3AWWCWO.mjs} +7 -7
  113. package/dist/cli/skills-QALGBUFY.js +31 -0
  114. package/dist/cli/{tools-3XNZ4J64.mjs → tools-3SHNTJPU.mjs} +18 -18
  115. package/dist/cli/tools-PUQ3JBZ7.js +55 -0
  116. package/dist/cli/{update-3U4OVX5R.mjs → update-3TWB5EEV.mjs} +9 -9
  117. package/dist/cli/update-O7XSJMLX.js +33 -0
  118. package/dist/cli/{workflow-2M5JP7SA.mjs → workflow-SYP62XNN.mjs} +7 -7
  119. package/dist/cli/{workflow-RM7H7555.js → workflow-ULIZU7KI.js} +17 -17
  120. package/dist/{client-DTwnz_AW.d.mts → client-ADFHNtFM.d.mts} +1 -1
  121. package/dist/{client-DS2IWYZF.d.ts → client-BClp2yrq.d.ts} +1 -1
  122. package/dist/{client-core-B_6HAIBy.d.ts → client-core-BFU73Ttw.d.ts} +1 -1
  123. package/dist/{client-core-DzBSlY1U.d.mts → client-core-DWLmmJWo.d.mts} +1 -1
  124. package/dist/{compiler-manifest-Dcyd3-Zd.d.ts → compiler-manifest-Cs17yO-H.d.mts} +321 -3
  125. package/dist/{compiler-manifest-Dcyd3-Zd.d.mts → compiler-manifest-Cs17yO-H.d.ts} +321 -3
  126. package/dist/{errors-yQwfgrcX.d.ts → errors-Dee-QpVS.d.ts} +1 -1
  127. package/dist/{errors-d-sTrZhe.d.mts → errors-qNfvQuRB.d.mts} +1 -1
  128. package/dist/{index-C6oXchjN.d.mts → index-BTqNNXmC.d.mts} +1 -1
  129. package/dist/{index-P56zy_z5.d.ts → index-DXTh1Lxe.d.ts} +1 -1
  130. package/dist/index.d.mts +7 -7
  131. package/dist/index.d.ts +7 -7
  132. package/dist/index.js +80 -13
  133. package/dist/index.mjs +76 -9
  134. package/dist/install-integrity.json +114 -114
  135. package/dist/plays/bundle-play-file.d.mts +3 -3
  136. package/dist/plays/bundle-play-file.d.ts +3 -3
  137. package/dist/plays/play-description.d.mts +2 -2
  138. package/dist/plays/play-description.d.ts +2 -2
  139. package/dist/plays/run-request.d.mts +2 -2
  140. package/dist/plays/run-request.d.ts +2 -2
  141. package/dist/release.d.mts +1 -1
  142. package/dist/release.d.ts +1 -1
  143. package/dist/release.js +2 -2
  144. package/dist/release.mjs +1 -1
  145. package/dist/server.d.mts +4 -4
  146. package/dist/server.d.ts +4 -4
  147. package/dist/server.js +5 -5
  148. package/dist/server.mjs +3 -3
  149. package/package.json +1 -1
  150. package/dist/cli/auth-XPGKBJKB.js +0 -41
  151. package/dist/cli/chunk-NA4T3B62.js +0 -286
  152. package/dist/cli/chunk-TXZVVBQZ.mjs +0 -286
  153. package/dist/cli/describe-QUF7VTTR.js +0 -48
  154. package/dist/cli/git-UH653WHV.js +0 -25
  155. package/dist/cli/search-TIFNLRPM.js +0 -32
  156. package/dist/cli/skills-MWFRMG3H.js +0 -31
  157. package/dist/cli/tools-XEC4OD3R.js +0 -55
  158. package/dist/cli/update-DWYEYTZE.js +0 -33
@@ -1498,6 +1498,8 @@ function extractorDescriptorRecord(
1498
1498
  .map((entry) => entry.trim())
1499
1499
  .filter(Boolean);
1500
1500
  const emailStatus = emailStatusExtractorConfig(descriptor.emailStatus);
1501
+ const means =
1502
+ typeof descriptor.means === 'string' ? descriptor.means : undefined;
1501
1503
  return [
1502
1504
  [
1503
1505
  key,
@@ -1506,6 +1508,7 @@ function extractorDescriptorRecord(
1506
1508
  ...(transforms.length > 0 ? { transforms } : {}),
1507
1509
  ...(enumValues.length > 0 ? { enum: enumValues } : {}),
1508
1510
  ...(emailStatus ? { emailStatus } : {}),
1511
+ ...(means !== undefined ? { means } : {}),
1509
1512
  },
1510
1513
  ],
1511
1514
  ];
@@ -205,7 +205,7 @@ export const SDK_RELEASE = {
205
205
  // getters keep their established compatibility behavior.
206
206
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
207
207
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
208
- version: '0.3.463',
208
+ version: '0.3.465',
209
209
  updateSummary: {
210
210
  introducedIn: '0.3.90',
211
211
  summary:
@@ -705,11 +705,12 @@ const TOOL_RETRY_AFTER_FALLBACK_MS = 1_000;
705
705
  // broken gateway-to-runner connection, not slow provider work.
706
706
  export const TOOL_EXECUTE_RESPONSE_BODY_TIMEOUT_MS = 30_000;
707
707
  const TOOL_RETRY_HEARTBEAT_INTERVAL_MS = 30_000;
708
- const TOOL_PROVIDER_RESIDENT_WAIT_BUDGET_MS = 5_000;
708
+ // Provider pacing and authored sleeps share one live-sandbox wait policy.
709
+ // Bound provider retry residency; longer waits and execution drains still park.
710
+ const SANDBOX_RESIDENT_WAIT_BUDGET_MS = 10 * 60_000;
709
711
  // The call already waited its whole admission budget in this sandbox, so it
710
712
  // rejoins the shared lane promptly instead of adding a fixed delay of its own.
711
713
  const PROVIDER_ADMISSION_REQUEUE_DELAY_MS = 1_000;
712
- const AUTHORED_SLEEP_RESIDENT_LIMIT_MS = 10_000;
713
714
  const DEEPLINEAGENT_TOOL_RUNTIME_TIMEOUT_MS = 15 * 60 * 1000;
714
715
  // Every runtime-API tool fetch needs a client-side deadline. Without one, a
715
716
  // stalled execute request (e.g. a credential-less call whose gateway connection
@@ -2908,6 +2909,11 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
2908
2909
  * broad catch cannot turn the invocation into a normal completed result.
2909
2910
  */
2910
2911
  private pendingDurableSuspension: PlayExecutionSuspension | null = null;
2912
+ private readonly durableSuspensionController = new AbortController();
2913
+ private readonly activeAuthoredSleepIntents = new Map<
2914
+ string,
2915
+ Promise<Extract<PlayExecutionSuspension, { kind: 'sleep' }>>
2916
+ >();
2911
2917
  private readonly durableCallCacheEpochMs: number;
2912
2918
  /**
2913
2919
  * Durable tool receipts are the replay/cache authority for the execution
@@ -3274,7 +3280,11 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
3274
3280
  private suspendDurably(suspension: PlayExecutionSuspension): never {
3275
3281
  this.pendingDurableSuspension ??= suspension;
3276
3282
  this.#options.onBatchComplete?.(this.checkpoint);
3277
- throw new PlayExecutionSuspendedError(this.pendingDurableSuspension);
3283
+ const error = new PlayExecutionSuspendedError(
3284
+ this.pendingDurableSuspension,
3285
+ );
3286
+ this.durableSuspensionController.abort(error);
3287
+ throw error;
3278
3288
  }
3279
3289
 
3280
3290
  async tool<TOutput = unknown>(
@@ -11947,13 +11957,15 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
11947
11957
  // rather than resetting it for each successive provider response.
11948
11958
  let providerIdleWaitStartedAt: number | null = null;
11949
11959
  const canWaitForProviderRetry = (retry: ProviderRowRetry) => {
11960
+ if (retry.readyAtMs >= (this.#options.executionDrainAtMs ?? Infinity))
11961
+ return false;
11950
11962
  const elapsedMs =
11951
11963
  providerIdleWaitStartedAt === null
11952
11964
  ? 0
11953
11965
  : performance.now() - providerIdleWaitStartedAt;
11954
11966
  return (
11955
11967
  Math.max(1, retry.readyAtMs - Date.now()) <=
11956
- Math.max(0, TOOL_PROVIDER_RESIDENT_WAIT_BUDGET_MS - elapsedMs)
11968
+ Math.max(0, SANDBOX_RESIDENT_WAIT_BUDGET_MS - elapsedMs)
11957
11969
  );
11958
11970
  };
11959
11971
  const activeRowHistories = new Map<number, Record<string, unknown>>();
@@ -15935,21 +15947,66 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
15935
15947
  existing?.kind === 'sleep'
15936
15948
  ? existing.delayMs
15937
15949
  : Math.max(1_000, Math.ceil(retryAtMs - Date.now()));
15950
+ // Provider holds end at an absolute deadline. Checkpoint persistence,
15951
+ // runner shutdown and scheduler handoff must not restart the whole delay.
15952
+ const wakeAtMs =
15953
+ existing?.kind === 'sleep' && existing.wakeAtMs !== undefined
15954
+ ? existing.wakeAtMs
15955
+ : Date.now() + delayMs;
15938
15956
  this.checkpoint.resolvedBoundaries = {
15939
15957
  ...(this.checkpoint.resolvedBoundaries ?? {}),
15940
- [boundaryId]: { kind: 'sleep', delayMs },
15958
+ [boundaryId]: { ...existing, kind: 'sleep', delayMs, wakeAtMs },
15941
15959
  };
15942
15960
  this.runtimeLog(
15943
15961
  `[runtime.provider.wait] ${JSON.stringify({
15944
15962
  provider,
15945
- retry_at: new Date(Date.now() + delayMs).toISOString(),
15946
- wait_ms: delayMs,
15963
+ retry_at: new Date(wakeAtMs).toISOString(),
15964
+ wait_ms: Math.max(0, wakeAtMs - Date.now()),
15947
15965
  boundary_id: boundaryId,
15948
15966
  })}`,
15949
15967
  { level: 'warn' },
15950
15968
  );
15951
- this.observeProviderCapacityWait(provider, Date.now() + delayMs);
15952
- this.suspendDurably({ kind: 'sleep', boundaryId, delayMs });
15969
+ this.observeProviderCapacityWait(provider, wakeAtMs);
15970
+ await this.suspendForEarliestSleep({
15971
+ kind: 'sleep',
15972
+ boundaryId,
15973
+ delayMs,
15974
+ wakeAtMs,
15975
+ });
15976
+ }
15977
+
15978
+ private async suspendForEarliestSleep(
15979
+ intent: Extract<PlayExecutionSuspension, { kind: 'sleep' }>,
15980
+ ): Promise<never> {
15981
+ const publications = new Set(this.activeAuthoredSleepIntents.values());
15982
+ let published = await Promise.all(publications);
15983
+ for (;;) {
15984
+ this.assertNoPendingDurableSuspension();
15985
+ const added = [...this.activeAuthoredSleepIntents.values()].filter(
15986
+ (publication) => !publications.has(publication),
15987
+ );
15988
+ if (added.length === 0) break;
15989
+ for (const publication of added) publications.add(publication);
15990
+ published = published.concat(await Promise.all(added));
15991
+ }
15992
+ const earliest = published.reduce((selected, candidate) => {
15993
+ const boundary =
15994
+ this.checkpoint.resolvedBoundaries?.[candidate.boundaryId];
15995
+ if (
15996
+ candidate.wakeAtMs === undefined ||
15997
+ (boundary?.kind === 'sleep' && boundary.completedAt !== undefined)
15998
+ )
15999
+ return selected;
16000
+ return selected.wakeAtMs === undefined ||
16001
+ candidate.wakeAtMs < selected.wakeAtMs
16002
+ ? candidate
16003
+ : selected;
16004
+ }, intent);
16005
+ // Legacy sleeps keep relative timing. Absolute sleeps yield at the first
16006
+ // unfinished wake, including authored siblings of a provider hold.
16007
+ return this.suspendDurably(
16008
+ intent.wakeAtMs === undefined ? intent : earliest,
16009
+ );
15953
16010
  }
15954
16011
 
15955
16012
  private sleepMetadataReceiptKey(
@@ -16130,50 +16187,62 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
16130
16187
  if (existing?.kind === 'sleep' && existing.completedAt !== undefined) {
16131
16188
  return;
16132
16189
  }
16133
- const wakeAtMs =
16134
- existing?.kind === 'sleep' && existing.wakeAtMs !== undefined
16135
- ? existing.wakeAtMs
16136
- : this.durableDirectToolResultsBackedByReceipts
16137
- ? await this.resolveCanonicalSleepWakeAtMs(boundaryId, delayMs)
16138
- : undefined;
16139
- this.assertNoPendingDurableSuspension();
16140
- this.checkpoint.resolvedBoundaries = {
16141
- ...(this.checkpoint.resolvedBoundaries ?? {}),
16142
- [boundaryId]: {
16143
- ...existing,
16144
- kind: 'sleep',
16145
- delayMs,
16146
- ...(wakeAtMs !== undefined ? { wakeAtMs } : {}),
16147
- },
16148
- };
16149
- if (
16150
- wakeAtMs !== undefined &&
16151
- !rowStore &&
16152
- this.durableDirectToolResultsBackedByReceipts &&
16153
- (wakeAtMs <= Date.now() ||
16154
- (delayMs <= AUTHORED_SLEEP_RESIDENT_LIMIT_MS &&
16155
- wakeAtMs < (this.#options.executionDrainAtMs ?? Infinity)))
16156
- ) {
16157
- const remainingMs = Math.max(0, wakeAtMs - Date.now());
16158
- if (remainingMs > 0)
16159
- await this.sleepWithCheckpointHeartbeat(remainingMs);
16190
+ // Register publication before awaiting storage so concurrent sleeps all
16191
+ // participate in handoff. A slow publication cannot hide an earlier timer.
16192
+ const publication = (async () => {
16193
+ const wakeAtMs =
16194
+ existing?.kind === 'sleep' && existing.wakeAtMs !== undefined
16195
+ ? existing.wakeAtMs
16196
+ : this.durableDirectToolResultsBackedByReceipts
16197
+ ? await this.resolveCanonicalSleepWakeAtMs(boundaryId, delayMs)
16198
+ : undefined;
16160
16199
  this.assertNoPendingDurableSuspension();
16161
- this.checkpoint.resolvedBoundaries[boundaryId] = {
16162
- ...this.checkpoint.resolvedBoundaries[boundaryId],
16163
- kind: 'sleep',
16200
+ this.checkpoint.resolvedBoundaries = {
16201
+ ...(this.checkpoint.resolvedBoundaries ?? {}),
16202
+ [boundaryId]: {
16203
+ ...existing,
16204
+ kind: 'sleep',
16205
+ delayMs,
16206
+ ...(wakeAtMs !== undefined ? { wakeAtMs } : {}),
16207
+ },
16208
+ };
16209
+ return {
16210
+ kind: 'sleep' as const,
16211
+ boundaryId,
16164
16212
  delayMs,
16165
- wakeAtMs,
16166
- completedAt: Date.now(),
16213
+ ...(wakeAtMs !== undefined ? { wakeAtMs } : {}),
16167
16214
  };
16168
- this.#options.onBatchComplete?.(this.checkpoint);
16169
- return;
16215
+ })();
16216
+ this.activeAuthoredSleepIntents.set(boundaryId, publication);
16217
+ try {
16218
+ const intent = await publication;
16219
+ const wakeAtMs = intent.wakeAtMs;
16220
+ const remainingMs =
16221
+ wakeAtMs === undefined ? null : Math.max(0, wakeAtMs - Date.now());
16222
+ if (
16223
+ remainingMs !== null &&
16224
+ this.durableDirectToolResultsBackedByReceipts &&
16225
+ (remainingMs === 0 ||
16226
+ (remainingMs <= SANDBOX_RESIDENT_WAIT_BUDGET_MS &&
16227
+ wakeAtMs! < (this.#options.executionDrainAtMs ?? Infinity)))
16228
+ ) {
16229
+ if (remainingMs > 0)
16230
+ await this.sleepWithCheckpointHeartbeat(remainingMs);
16231
+ this.assertNoPendingDurableSuspension();
16232
+ this.checkpoint.resolvedBoundaries![boundaryId] = {
16233
+ ...this.checkpoint.resolvedBoundaries![boundaryId],
16234
+ kind: 'sleep',
16235
+ delayMs,
16236
+ wakeAtMs,
16237
+ completedAt: Date.now(),
16238
+ };
16239
+ this.#options.onBatchComplete?.(this.checkpoint);
16240
+ return;
16241
+ }
16242
+ await this.suspendForEarliestSleep(intent);
16243
+ } finally {
16244
+ this.activeAuthoredSleepIntents.delete(boundaryId);
16170
16245
  }
16171
- this.suspendDurably({
16172
- kind: 'sleep',
16173
- boundaryId,
16174
- delayMs,
16175
- ...(wakeAtMs !== undefined ? { wakeAtMs } : {}),
16176
- });
16177
16246
  }
16178
16247
  return new Promise((resolve) => setTimeout(resolve, delayMs));
16179
16248
  }
@@ -19783,6 +19852,11 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
19783
19852
  // work. Repeated zero or expired holds must also yield durably.
19784
19853
  let residentProviderWaitStartedAt: number | null = null;
19785
19854
  const canWaitForProviderInSandbox = (waitMs: number) => {
19855
+ if (
19856
+ Date.now() + Math.max(1, waitMs) >=
19857
+ (this.#options.executionDrainAtMs ?? Infinity)
19858
+ )
19859
+ return false;
19786
19860
  if (
19787
19861
  providerResidentWaitKey &&
19788
19862
  this.exhaustedProviderResidentWaitCalls.has(
@@ -19796,7 +19870,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
19796
19870
  : performance.now() - residentProviderWaitStartedAt;
19797
19871
  return (
19798
19872
  Math.max(1, waitMs) <=
19799
- Math.max(0, TOOL_PROVIDER_RESIDENT_WAIT_BUDGET_MS - elapsedMs)
19873
+ Math.max(0, SANDBOX_RESIDENT_WAIT_BUDGET_MS - elapsedMs)
19800
19874
  );
19801
19875
  };
19802
19876
  const markProviderResidentWaitBudgetExhausted = () => {
@@ -21589,12 +21663,13 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
21589
21663
  const waitMs = Math.max(1, Math.ceil(ms));
21590
21664
  const startedAt = performance.now();
21591
21665
  const executionSignal = this.#options.executionSignal;
21592
- const signal =
21593
- executionSignal && callerSignal
21594
- ? AbortSignal.any([executionSignal, callerSignal])
21595
- : (executionSignal ?? callerSignal);
21666
+ const signal = AbortSignal.any([
21667
+ this.durableSuspensionController.signal,
21668
+ ...(executionSignal ? [executionSignal] : []),
21669
+ ...(callerSignal ? [callerSignal] : []),
21670
+ ]);
21596
21671
 
21597
- signal?.throwIfAborted();
21672
+ signal.throwIfAborted();
21598
21673
  while (performance.now() - startedAt < waitMs) {
21599
21674
  this.#options.onBatchComplete?.(this.checkpoint);
21600
21675
  signal?.throwIfAborted();
@@ -4932,6 +4932,20 @@ async function buildRuntimeSheetDatasetStartResult(
4932
4932
  );
4933
4933
  return Object.keys(cells).length ? [{ key, cells }] : [];
4934
4934
  });
4935
+ // History readers (`datasetRowInput: current_run`) seed rows from authored
4936
+ // input plus `__deepline*` runtime fields only and read stored output through
4937
+ // `previousCells`. Merging that output into the rows too would send every
4938
+ // completed cell twice and can push a resume admission past its byte budget.
4939
+ const rowFieldsForReader = (
4940
+ data: Record<string, unknown>,
4941
+ ): Record<string, unknown> =>
4942
+ input.includePreviousCells
4943
+ ? Object.fromEntries(
4944
+ Object.entries(data).filter(([field]) =>
4945
+ field.startsWith('__deepline'),
4946
+ ),
4947
+ )
4948
+ : data;
4935
4949
  const buildFreshRow = (entry: RuntimeDatasetRowEntry) => {
4936
4950
  const row: Record<string, unknown> = {
4937
4951
  ...sanitizePostgresJsonValue(entry.row),
@@ -5024,7 +5038,7 @@ async function buildRuntimeSheetDatasetStartResult(
5024
5038
  }
5025
5039
  completedRows.push({
5026
5040
  ...entry.row,
5027
- ...stored,
5041
+ ...rowFieldsForReader(stored),
5028
5042
  __deeplineRowKey: entry.key,
5029
5043
  });
5030
5044
  } else if (disposition === 'blocked') {
@@ -5056,7 +5070,7 @@ async function buildRuntimeSheetDatasetStartResult(
5056
5070
  const buildMergedRow = (entry: RuntimeDatasetRowEntry) => {
5057
5071
  const merged = { ...entry.row };
5058
5072
  for (const [field, value] of Object.entries(
5059
- persistedRowsByKey.get(entry.key) ?? {},
5073
+ rowFieldsForReader(persistedRowsByKey.get(entry.key) ?? {}),
5060
5074
  )) {
5061
5075
  if (
5062
5076
  value !== null ||
@@ -32,6 +32,12 @@ import {
32
32
  type JobChangeGetterValue,
33
33
  type JobChangeStatus,
34
34
  } from '../plays/extractor-targets';
35
+ import {
36
+ fieldOfName,
37
+ fieldPaths,
38
+ resolveFieldName,
39
+ type FieldBinding,
40
+ } from '../plays/field-catalog';
35
41
  import type {
36
42
  BasicToolExecuteResult,
37
43
  BasicToolResultListAccessor,
@@ -520,6 +526,10 @@ function parseExecuteToolMetadata(
520
526
  !Array.isArray(recordEntry.emailStatus)
521
527
  ? (recordEntry.emailStatus as EmailStatusExtractorConfig)
522
528
  : undefined;
529
+ const means =
530
+ typeof recordEntry.means === 'string'
531
+ ? recordEntry.means
532
+ : undefined;
523
533
  return [
524
534
  [
525
535
  key,
@@ -544,6 +554,7 @@ function parseExecuteToolMetadata(
544
554
  : {}),
545
555
  ...(overrides.length > 0 ? { overrides } : {}),
546
556
  ...(emailStatus ? { emailStatus } : {}),
557
+ ...(means !== undefined ? { means } : {}),
547
558
  },
548
559
  ],
549
560
  ];
@@ -1540,6 +1551,71 @@ function listTableNamespace(
1540
1551
  }
1541
1552
  }
1542
1553
 
1554
+ /**
1555
+ * The outputs of a result that are catalog fields: declared extractors whose
1556
+ * meaning is known, from the tool's own `means` or the name's one meaning.
1557
+ * Values found by guessing at keys are never bindings.
1558
+ */
1559
+ function resultFieldBindings(
1560
+ result: ToolExecuteResult | BasicToolExecuteResult,
1561
+ ): FieldBinding[] {
1562
+ const extractors = result._metadata.extractors ?? {};
1563
+ return Object.entries(extractors).flatMap(([name, descriptor]) => {
1564
+ if (!result.extractedValues[name]) return [];
1565
+ const id = fieldOfName(name, descriptor.means);
1566
+ return id ? [{ name, id }] : [];
1567
+ });
1568
+ }
1569
+
1570
+ function resultOutputNames(
1571
+ result: ToolExecuteResult | BasicToolExecuteResult,
1572
+ ): string[] {
1573
+ return [
1574
+ ...Object.keys(result._metadata.extractors ?? {}),
1575
+ ...Object.keys(result.extractedLists),
1576
+ ];
1577
+ }
1578
+
1579
+ function readResultField(
1580
+ result: ToolExecuteResult | BasicToolExecuteResult,
1581
+ name: string,
1582
+ ): unknown {
1583
+ const bindings = resultFieldBindings(result);
1584
+ const binding = resolveFieldName(name, bindings, resultOutputNames(result));
1585
+ if (!binding) {
1586
+ const ids = [...new Set(bindings.map((known) => known.id))];
1587
+ throw new Error(
1588
+ `${result._metadata.toolId} has no field "${name}". ${ids.length > 0 ? `Its fields: ${ids.join(', ')}.` : 'It declares no catalog fields.'} Other values are in result.response.`,
1589
+ );
1590
+ }
1591
+ return result.extractedValues[binding.name]!.get();
1592
+ }
1593
+
1594
+ /** `result.fields`, laid out by `fieldPaths`; each value reads on access. */
1595
+ function buildResultFields(
1596
+ result: ToolExecuteResult | BasicToolExecuteResult,
1597
+ ): Record<string, unknown> {
1598
+ const tree: Record<string, unknown> = {};
1599
+ const lists = Object.keys(result.extractedLists);
1600
+ for (const entry of fieldPaths(
1601
+ resultFieldBindings(result),
1602
+ resultOutputNames(result),
1603
+ lists,
1604
+ )) {
1605
+ let node = tree;
1606
+ for (const key of entry.path.slice(0, -1)) {
1607
+ node = (node[key] ??= {}) as Record<string, unknown>;
1608
+ }
1609
+ Object.defineProperty(node, entry.path[entry.path.length - 1]!, {
1610
+ get: entry.list
1611
+ ? () => result.extractedLists[entry.name]!.get()
1612
+ : () => readResultField(result, entry.name),
1613
+ enumerable: true,
1614
+ });
1615
+ }
1616
+ return tree;
1617
+ }
1618
+
1543
1619
  export function createToolExecuteResult<TResult = unknown>(input: {
1544
1620
  status: string;
1545
1621
  jobId?: string;
@@ -1614,11 +1690,33 @@ export function createToolExecuteResult<TResult = unknown>(input: {
1614
1690
  extractedValues,
1615
1691
  extractedLists,
1616
1692
  } as ToolExecuteResult<TResult>;
1693
+ // Read through `this`, so copies made from these descriptors (the edition
1694
+ // projection, native batch views) read their own values.
1617
1695
  Object.defineProperties(wrapper, {
1618
1696
  toolOutput: {
1619
1697
  value: toolResponse,
1620
1698
  enumerable: false,
1621
1699
  },
1700
+ response: {
1701
+ get(this: ToolExecuteResult) {
1702
+ return Object.hasOwn(this.toolResponse, 'rawV2')
1703
+ ? this.toolResponse.rawV2
1704
+ : this.toolResponse.raw;
1705
+ },
1706
+ enumerable: false,
1707
+ },
1708
+ fields: {
1709
+ get(this: ToolExecuteResult) {
1710
+ return buildResultFields(this);
1711
+ },
1712
+ enumerable: false,
1713
+ },
1714
+ field: {
1715
+ value(this: ToolExecuteResult, name: string) {
1716
+ return readResultField(this, name);
1717
+ },
1718
+ enumerable: false,
1719
+ },
1622
1720
  });
1623
1721
  Object.defineProperty(wrapper, '_metadata', {
1624
1722
  value: metadata,