eve 0.81.0 → 0.82.0

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 (327) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/src/channel/channel-address.d.ts +21 -2
  3. package/dist/src/channel/channel-address.js +1 -1
  4. package/dist/src/channel/channel-operations.d.ts +32 -1
  5. package/dist/src/channel/channel-operations.js +1 -1
  6. package/dist/src/channel/delivery-idempotency.d.ts +4 -0
  7. package/dist/src/channel/delivery-idempotency.js +1 -0
  8. package/dist/src/channel/routes.d.ts +6 -0
  9. package/dist/src/channel/session.d.ts +5 -0
  10. package/dist/src/channel/session.js +1 -1
  11. package/dist/src/channel/types.d.ts +14 -11
  12. package/dist/src/chunks/{use-eve-agent-Bp6nbhfV.js → use-eve-agent-DTu78IAF.js} +36 -0
  13. package/dist/src/chunks/{use-eve-agent-DLkjJIm3.js → use-eve-agent-DlznYwQk.js} +36 -0
  14. package/dist/src/cli/dev/command-options.d.ts +1 -0
  15. package/dist/src/cli/dev/diagnostic-dump.js +1 -1
  16. package/dist/src/cli/run.d.ts +1 -0
  17. package/dist/src/cli/run.js +1 -1
  18. package/dist/src/client/index.d.ts +1 -1
  19. package/dist/src/client/message-reducer-types.d.ts +7 -3
  20. package/dist/src/client/message-reducer.js +1 -1
  21. package/dist/src/client/transcript-reducer.d.ts +6 -3
  22. package/dist/src/client/transcript-reducer.js +1 -1
  23. package/dist/src/compiled/.vendor-stamp.json +2 -2
  24. package/dist/src/compiled/@eve/catalog/index.js +1 -1
  25. package/dist/src/compiler/extension-compatibility.d.ts +19 -18
  26. package/dist/src/compiler/extension-compatibility.js +1 -1
  27. package/dist/src/compiler/load-binding-namespace.d.ts +2 -0
  28. package/dist/src/compiler/load-binding-namespace.js +1 -1
  29. package/dist/src/compiler/manifest.js +1 -1
  30. package/dist/src/compiler/module-lifecycle.d.ts +1 -1
  31. package/dist/src/compiler/module-lifecycle.js +1 -1
  32. package/dist/src/compiler/module-map.js +1 -1
  33. package/dist/src/compiler/normalize-agent-config.js +1 -1
  34. package/dist/src/compiler/normalize-manifest.js +1 -1
  35. package/dist/src/compiler/project-sources.d.ts +6 -0
  36. package/dist/src/compiler/project-sources.js +1 -1
  37. package/dist/src/context/keys.d.ts +2 -0
  38. package/dist/src/context/keys.js +1 -1
  39. package/dist/src/evals/cli/eval-state-directory.d.ts +7 -0
  40. package/dist/src/evals/cli/eval-state-directory.js +1 -0
  41. package/dist/src/evals/cli/eval.js +2 -2
  42. package/dist/src/eve-channel/create-request.d.ts +2 -1
  43. package/dist/src/eve-channel/index.js +1 -1
  44. package/dist/src/eve-channel/request.d.ts +2 -1
  45. package/dist/src/eve-channel/request.js +1 -2
  46. package/dist/src/eve-channel/support.d.ts +11 -1
  47. package/dist/src/eve-channel/support.js +2 -1
  48. package/dist/src/eve-channel/types.d.ts +25 -0
  49. package/dist/src/execution/agent-sessions/context.d.ts +2 -13
  50. package/dist/src/execution/agent-sessions/context.js +1 -1
  51. package/dist/src/execution/agent-sessions/runtime-overrides.d.ts +5 -0
  52. package/dist/src/execution/agent-sessions/runtime-overrides.js +1 -0
  53. package/dist/src/execution/agent-sessions/session.d.ts +2 -2
  54. package/dist/src/execution/agent-sessions/session.js +1 -1
  55. package/dist/src/execution/agent-sessions/steps.d.ts +2 -0
  56. package/dist/src/execution/agent-sessions/steps.js +1 -1
  57. package/dist/src/execution/coordination-dispatch-shared.d.ts +5 -5
  58. package/dist/src/execution/coordination-dispatch-step.d.ts +17 -2
  59. package/dist/src/execution/coordination-dispatch-step.js +1 -1
  60. package/dist/src/execution/create-session-step.d.ts +5 -2
  61. package/dist/src/execution/create-session-step.js +1 -1
  62. package/dist/src/execution/deliver-payloads.js +1 -1
  63. package/dist/src/execution/durable-session-store.d.ts +0 -1
  64. package/dist/src/execution/dynamic-connection-recovery.js +1 -1
  65. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  66. package/dist/src/execution/effective-agent-config.d.ts +8 -2
  67. package/dist/src/execution/effective-agent-config.js +1 -1
  68. package/dist/src/execution/hook-ownership.d.ts +8 -0
  69. package/dist/src/execution/hook-ownership.js +1 -1
  70. package/dist/src/execution/install-workflow-deployment-id.d.ts +3 -0
  71. package/dist/src/execution/install-workflow-deployment-id.js +1 -0
  72. package/dist/src/execution/legacy-session/turn-workflow.js +1 -1
  73. package/dist/src/execution/node-step.d.ts +1 -0
  74. package/dist/src/execution/node-step.js +1 -1
  75. package/dist/src/execution/runtime-context.d.ts +2 -0
  76. package/dist/src/execution/runtime-context.js +1 -1
  77. package/dist/src/execution/session/active-turn.js +1 -1
  78. package/dist/src/execution/session/admission.js +1 -1
  79. package/dist/src/execution/session/checkpoint-migrations.js +1 -1
  80. package/dist/src/execution/session/entry-input.d.ts +20 -8
  81. package/dist/src/execution/session/entry-input.js +1 -1
  82. package/dist/src/execution/session/entry.js +1 -1
  83. package/dist/src/execution/session/finalization.js +1 -1
  84. package/dist/src/execution/session/handoff-steps.d.ts +75 -13
  85. package/dist/src/execution/session/handoff-steps.js +1 -1
  86. package/dist/src/execution/session/handoff.d.ts +73 -34
  87. package/dist/src/execution/session/handoff.js +1 -1
  88. package/dist/src/execution/session/input-queue.d.ts +5 -1
  89. package/dist/src/execution/session/input-queue.js +1 -1
  90. package/dist/src/execution/session/pending-history.d.ts +5 -0
  91. package/dist/src/execution/session/pending-history.js +1 -0
  92. package/dist/src/execution/session/pending-turn-state.js +1 -1
  93. package/dist/src/execution/session/program.d.ts +1 -1
  94. package/dist/src/execution/session/program.js +1 -1
  95. package/dist/src/execution/session/run-watch.d.ts +22 -0
  96. package/dist/src/execution/session/run-watch.js +1 -0
  97. package/dist/src/execution/session/timeout-control.d.ts +18 -4
  98. package/dist/src/execution/session/timeout-control.js +1 -1
  99. package/dist/src/execution/session/timeout.d.ts +1 -2
  100. package/dist/src/execution/session/timeout.js +1 -1
  101. package/dist/src/execution/session/turn-event-handler.js +1 -1
  102. package/dist/src/execution/session/turn-step-result.js +1 -1
  103. package/dist/src/execution/session/turn-step.js +1 -1
  104. package/dist/src/execution/session/turn-waiting-step.js +1 -1
  105. package/dist/src/execution/session/turn.js +1 -1
  106. package/dist/src/execution/session-inbox/address.d.ts +4 -1
  107. package/dist/src/execution/session-inbox/end-stranded-session.js +1 -1
  108. package/dist/src/execution/session-inbox/hook-release.d.ts +9 -2
  109. package/dist/src/execution/session-inbox/hook-release.js +1 -1
  110. package/dist/src/execution/session-inbox/inbox.d.ts +66 -6
  111. package/dist/src/execution/session-inbox/inbox.js +1 -1
  112. package/dist/src/execution/session-inbox/protocol.js +1 -1
  113. package/dist/src/execution/session-inbox/resume.d.ts +4 -3
  114. package/dist/src/execution/session.d.ts +0 -12
  115. package/dist/src/execution/session.js +2 -2
  116. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  117. package/dist/src/execution/tasks/model-step.js +1 -1
  118. package/dist/src/execution/tasks/start.d.ts +4 -4
  119. package/dist/src/execution/tasks/start.js +1 -1
  120. package/dist/src/execution/tasks/steps.js +1 -1
  121. package/dist/src/execution/terminate-child-sessions-step.js +1 -1
  122. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  123. package/dist/src/execution/tools/workflow/body.d.ts +2 -2
  124. package/dist/src/execution/workflow-runtime.d.ts +11 -12
  125. package/dist/src/execution/workflow-runtime.js +1 -1
  126. package/dist/src/harness/hitl/approvals.js +1 -1
  127. package/dist/src/harness/hitl/budget-request.d.ts +12 -6
  128. package/dist/src/harness/hitl/budget-request.js +1 -1
  129. package/dist/src/harness/hitl/budget.d.ts +7 -1
  130. package/dist/src/harness/hitl/budget.js +1 -1
  131. package/dist/src/harness/hitl/coordinator.js +1 -1
  132. package/dist/src/harness/hitl/delivery.d.ts +1 -1
  133. package/dist/src/harness/hitl/delivery.js +1 -1
  134. package/dist/src/harness/hitl/index.js +1 -1
  135. package/dist/src/harness/hitl/intake.d.ts +2 -2
  136. package/dist/src/harness/hitl/intake.js +1 -1
  137. package/dist/src/harness/messages.d.ts +5 -0
  138. package/dist/src/harness/messages.js +1 -1
  139. package/dist/src/harness/model-call/call.d.ts +2 -2
  140. package/dist/src/harness/model-call/call.js +1 -1
  141. package/dist/src/harness/model-call/request.d.ts +2 -2
  142. package/dist/src/harness/session-machine/transitions.d.ts +3 -1
  143. package/dist/src/harness/session-machine/transitions.js +1 -1
  144. package/dist/src/harness/step/context.d.ts +3 -0
  145. package/dist/src/harness/step/context.js +1 -1
  146. package/dist/src/harness/step/intake.d.ts +5 -2
  147. package/dist/src/harness/step/intake.js +1 -1
  148. package/dist/src/harness/tool-loop.js +1 -1
  149. package/dist/src/harness/turn-tag-state.d.ts +7 -26
  150. package/dist/src/harness/turn-tag-state.js +1 -1
  151. package/dist/src/harness/types.d.ts +10 -25
  152. package/dist/src/instrumentation/content.d.ts +1 -1
  153. package/dist/src/instrumentation/content.js +1 -1
  154. package/dist/src/instrumentation/lifecycle.d.ts +4 -2
  155. package/dist/src/internal/application/build-profile.d.ts +3 -0
  156. package/dist/src/internal/application/build-profile.js +1 -1
  157. package/dist/src/internal/application/compiled-artifacts.js +2 -2
  158. package/dist/src/internal/application/dev-environment.d.ts +13 -0
  159. package/dist/src/internal/application/dev-environment.js +1 -1
  160. package/dist/src/internal/application/stamped-package-version.js +1 -1
  161. package/dist/src/internal/authored-definition/connection.js +1 -1
  162. package/dist/src/internal/authored-definition/core.js +1 -1
  163. package/dist/src/internal/authored-module-build-options.d.ts +7 -0
  164. package/dist/src/internal/authored-module-build-options.js +1 -0
  165. package/dist/src/internal/authored-module-graph.d.ts +13 -0
  166. package/dist/src/internal/authored-module-graph.js +1 -0
  167. package/dist/src/internal/authored-module-loader.d.ts +22 -1
  168. package/dist/src/internal/authored-module-loader.js +1 -3
  169. package/dist/src/internal/authored-module.d.ts +7 -0
  170. package/dist/src/internal/authored-module.js +1 -1
  171. package/dist/src/internal/authored-package-boundary.js +1 -1
  172. package/dist/src/internal/bundler/nitro-rolldown.d.ts +5 -1
  173. package/dist/src/internal/bundler/nitro-rolldown.js +1 -1
  174. package/dist/src/internal/development-programmatic-source-loader.d.ts +1 -0
  175. package/dist/src/internal/development-programmatic-source-loader.js +1 -1
  176. package/dist/src/internal/mcp/skills.js +1 -1
  177. package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
  178. package/dist/src/internal/nitro/dev-runtime-generation-metadata.js +1 -1
  179. package/dist/src/internal/nitro/host/build-application.js +1 -1
  180. package/dist/src/internal/nitro/host/build-deployment-id.d.ts +8 -0
  181. package/dist/src/internal/nitro/host/build-deployment-id.js +1 -0
  182. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  183. package/dist/src/internal/nitro/host/dev-server-state.js +1 -1
  184. package/dist/src/internal/nitro/host/skill-server-assets.js +1 -1
  185. package/dist/src/internal/nitro/host/stage-build-deployment-id.d.ts +2 -0
  186. package/dist/src/internal/nitro/host/stage-build-deployment-id.js +1 -0
  187. package/dist/src/internal/nitro/host/start-production-server.d.ts +1 -0
  188. package/dist/src/internal/nitro/host/start-production-server.js +3 -3
  189. package/dist/src/internal/nitro/routes/schedule-task.d.ts +3 -0
  190. package/dist/src/internal/nitro/routes/schedule-task.js +1 -1
  191. package/dist/src/internal/programmatic-source-loader.d.ts +1 -0
  192. package/dist/src/internal/programmatic-source-loader.js +1 -1
  193. package/dist/src/internal/schedules/disabled.d.ts +2 -0
  194. package/dist/src/internal/schedules/disabled.js +1 -0
  195. package/dist/src/internal/workflow/development-world-client.js +1 -1
  196. package/dist/src/internal/workflow/development-world-server.js +1 -1
  197. package/dist/src/internal/workflow/local-world-data-directory.d.ts +2 -1
  198. package/dist/src/internal/workflow/local-world-data-directory.js +1 -1
  199. package/dist/src/internal/workflow-bundle/builder.js +1 -1
  200. package/dist/src/protocol/message.d.ts +27 -1
  201. package/dist/src/protocol/message.js +2 -2
  202. package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +13 -0
  203. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
  204. package/dist/src/public/channels/chat-sdk/fetch-message.d.ts +10 -0
  205. package/dist/src/public/channels/chat-sdk/fetch-message.js +1 -0
  206. package/dist/src/public/channels/chat-sdk/index.d.ts +1 -1
  207. package/dist/src/public/channels/chat-sdk/messageToUserContent.d.ts +2 -1
  208. package/dist/src/public/channels/chat-sdk/messageToUserContent.js +1 -1
  209. package/dist/src/public/channels/chat-sdk/reply-context.d.ts +15 -0
  210. package/dist/src/public/channels/chat-sdk/reply-context.js +2 -0
  211. package/dist/src/public/channels/discord/discordChannel.d.ts +3 -0
  212. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  213. package/dist/src/public/channels/github/dispatch.js +1 -1
  214. package/dist/src/public/channels/github/githubChannel.d.ts +3 -0
  215. package/dist/src/public/channels/imessage-tapbacks.d.ts +74 -0
  216. package/dist/src/public/channels/imessage-tapbacks.js +1 -0
  217. package/dist/src/public/channels/index.d.ts +2 -1
  218. package/dist/src/public/channels/index.js +1 -1
  219. package/dist/src/public/channels/linear/linearChannel.d.ts +3 -0
  220. package/dist/src/public/channels/linear/linearChannel.js +1 -1
  221. package/dist/src/public/channels/linq/inboundContent.d.ts +7 -0
  222. package/dist/src/public/channels/linq/inboundContent.js +1 -1
  223. package/dist/src/public/channels/linq/index.d.ts +1 -0
  224. package/dist/src/public/channels/linq/index.js +1 -1
  225. package/dist/src/public/channels/linq/linqChannel.d.ts +17 -1
  226. package/dist/src/public/channels/linq/linqChannel.js +1 -1
  227. package/dist/src/public/channels/photon/attachments.d.ts +5 -2
  228. package/dist/src/public/channels/photon/attachments.js +1 -1
  229. package/dist/src/public/channels/photon/inboundContent.d.ts +7 -0
  230. package/dist/src/public/channels/photon/inboundContent.js +2 -1
  231. package/dist/src/public/channels/photon/index.d.ts +1 -0
  232. package/dist/src/public/channels/photon/index.js +1 -1
  233. package/dist/src/public/channels/photon/photonIMessageChannel.d.ts +17 -1
  234. package/dist/src/public/channels/photon/photonIMessageChannel.js +1 -1
  235. package/dist/src/public/channels/slack/api.d.ts +14 -1
  236. package/dist/src/public/channels/slack/api.js +1 -1
  237. package/dist/src/public/channels/slack/model-context.d.ts +7 -0
  238. package/dist/src/public/channels/slack/model-context.js +1 -1
  239. package/dist/src/public/channels/slack/reply-delivery.d.ts +5 -0
  240. package/dist/src/public/channels/slack/reply-delivery.js +1 -1
  241. package/dist/src/public/channels/slack/slackChannel.d.ts +17 -3
  242. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  243. package/dist/src/public/channels/teams/teamsChannel.d.ts +3 -0
  244. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  245. package/dist/src/public/channels/telegram/telegramChannel.d.ts +3 -0
  246. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  247. package/dist/src/public/definitions/agent.d.ts +1 -1
  248. package/dist/src/public/definitions/channel.d.ts +2 -2
  249. package/dist/src/public/definitions/channel.js +1 -1
  250. package/dist/src/public/definitions/hook.d.ts +1 -0
  251. package/dist/src/public/index.d.ts +1 -1
  252. package/dist/src/public/tools/index.d.ts +1 -1
  253. package/dist/src/runtime/agent/resolve-model.d.ts +4 -0
  254. package/dist/src/runtime/agent/resolve-model.js +1 -1
  255. package/dist/src/runtime/resolve-agent.js +1 -1
  256. package/dist/src/runtime/sessions/compiled-agent-cache.js +1 -1
  257. package/dist/src/runtime/subagents/dynamic-agent-config.d.ts +2 -1
  258. package/dist/src/runtime/subagents/dynamic-agent-config.js +1 -1
  259. package/dist/src/runtime/types.d.ts +3 -2
  260. package/dist/src/setup/scaffold/create/project.js +1 -1
  261. package/dist/src/shared/agent-definition.d.ts +31 -42
  262. package/dist/src/shared/gateway-routing.d.ts +20 -0
  263. package/dist/src/shared/gateway-routing.js +1 -0
  264. package/dist/src/shared/session-history.d.ts +22 -0
  265. package/dist/src/shared/session-history.js +1 -0
  266. package/dist/src/shared/skill-package.js +1 -1
  267. package/dist/src/subagents/tool.d.ts +1 -3
  268. package/dist/src/subagents/tool.js +1 -1
  269. package/dist/src/svelte/index.js +1 -1
  270. package/dist/src/svelte/use-eve-agent.js +1 -1
  271. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  272. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  273. package/dist/src/tools/workflow-definition.d.ts +14 -1
  274. package/dist/src/tracing/eve/agent-otel-provider.js +1 -1
  275. package/dist/src/tracing/eve/conversation-context.d.ts +4 -1
  276. package/dist/src/tracing/eve/conversation-context.js +1 -1
  277. package/dist/src/tracing/eve/gateway.d.ts +5 -0
  278. package/dist/src/tracing/eve/gateway.js +1 -1
  279. package/dist/src/tracing/eve/invoke-tool-span.js +1 -1
  280. package/dist/src/tracing/eve/operation-input.d.ts +0 -12
  281. package/dist/src/tracing/eve/operation-input.js +1 -1
  282. package/dist/src/tracing/eve/otel-registration.js +1 -1
  283. package/dist/src/tracing/eve/policy.d.ts +1 -1
  284. package/dist/src/tracing/eve/policy.js +1 -1
  285. package/dist/src/tracing/eve/session.d.ts +5 -2
  286. package/dist/src/tracing/eve/session.js +1 -1
  287. package/dist/src/vue/index.js +1 -1
  288. package/dist/src/vue/use-eve-agent.js +1 -1
  289. package/docs/README.md +1 -0
  290. package/docs/agent-config.md +108 -65
  291. package/docs/channels/chat-sdk.mdx +10 -3
  292. package/docs/channels/custom.mdx +38 -6
  293. package/docs/channels/eve.mdx +73 -0
  294. package/docs/channels/linq.mdx +51 -0
  295. package/docs/channels/photon.mdx +68 -2
  296. package/docs/channels/slack.mdx +6 -2
  297. package/docs/concepts/built-in-tools.md +1 -1
  298. package/docs/concepts/execution-model-and-durability.mdx +27 -11
  299. package/docs/concepts/sessions-runs-and-streaming.md +9 -8
  300. package/docs/connections/overview.mdx +1 -1
  301. package/docs/experimental/dynamic-schedules.mdx +186 -0
  302. package/docs/experimental/meta.json +4 -0
  303. package/docs/guides/client/streaming.mdx +1 -0
  304. package/docs/guides/deployment/self-hosting.md +3 -0
  305. package/docs/guides/hooks.md +21 -1
  306. package/docs/guides/instrumentation/otel.mdx +20 -0
  307. package/docs/memory/overview.mdx +2 -1
  308. package/docs/patterns/dynamic-scheduling.md +3 -1
  309. package/docs/patterns/meta.json +1 -0
  310. package/docs/patterns/voice-notes.md +67 -0
  311. package/docs/reference/cli.md +14 -7
  312. package/docs/sandbox/index.mdx +2 -0
  313. package/docs/schedules.mdx +2 -0
  314. package/docs/subagents/index.mdx +2 -0
  315. package/docs/tools/overview.mdx +2 -1
  316. package/docs/tools/tasks-upgrade.md +12 -7
  317. package/docs/tools/tasks.md +10 -6
  318. package/docs/tools/workflows.mdx +36 -5
  319. package/docs/tutorial/connect-a-warehouse.mdx +1 -1
  320. package/docs/tutorial/run-analysis.mdx +1 -1
  321. package/package.json +1 -1
  322. package/dist/src/execution/run-session-limits.d.ts +0 -12
  323. package/dist/src/execution/run-session-limits.js +0 -1
  324. package/dist/src/harness/session-usage-limits.d.ts +0 -49
  325. package/dist/src/harness/session-usage-limits.js +0 -1
  326. package/dist/src/subagents/token-budget.d.ts +0 -15
  327. package/dist/src/subagents/token-budget.js +0 -1
@@ -1 +1 @@
1
- import{attachClientContext,readClientContext}from"#internal/client-context.js";import{SESSION_INBOX_CONTEXT_KEY,sessionCommandHookToken}from"#execution/session-inbox/address.js";import{readSerializedSessionSchedule}from"#context/session-schedule.js";import{getWorkflowMetadata,getWritable}from"#compiled/@workflow/core/index.js";import{isHookConflictError}from"#execution/hook-ownership.js";import{DEFAULT_SESSION_TIMEOUT_MS,sessionTimeoutDeadline}from"#execution/session/timeout.js";import{sessionHookTokens}from"#execution/session/hook-tokens.js";import{createSessionInbox}from"#execution/session-inbox/inbox.js";import{failSession,runPreparedSession}from"#execution/session/program.js";import{createSessionTimeoutControl}from"#execution/session/timeout-control.js";import{recordSessionOwnerStep,signalSessionOwnerActivationStep,stopUntrackedChildSessionsStep,validateSessionCheckpointStep}from"#execution/session/handoff-steps.js";import{hasDelegatedSessionContext}from"#execution/delegated-session-context.js";import{readChannelRequestId,readRootSessionId}from"#execution/eve-workflow-attributes.js";import{createTurnControl}from"#execution/session/turn-control.js";import{resolveInitialTurnCallerStep}from"#subagents/parent-notification.js";import{normalizeSerializableError}from"#execution/workflow-errors.js";import{createSessionStep}from"#execution/create-session-step.js";import{settleContinuationConflictStep}from"#execution/continuation-conflict-step.js";import{migrateSessionCheckpoint}from"#execution/session/checkpoint-migrations.js";async function workflowEntry(e){"use workflow";let t=e.kind===`initial`?await bootInitialOwner(e,getWorkflowMetadata().workflowRunId):await bootHandoffOwner(e);return t===void 0?{output:``}:{output:(await runPreparedSession(t.session,t.inbox)).output}}function stampSessionIdentity(e,t){return{...e,"eve.sessionId":t,[SESSION_INBOX_CONTEXT_KEY]:{sessionId:t}}}async function prepareInitialOwner(e,t){let[n,r]=await Promise.allSettled([e.claimSessionHook(sessionCommandHookToken(t.sessionId)),t.continuationToken===``?Promise.resolve():e.claimSessionHook(t.continuationToken)]);if(n.status===`rejected`)throw n.reason;if(r.status===`rejected`){if(isHookConflictError(r.reason))return{kind:`alias-conflict`};throw r.reason}let i=createTurnControl(),a=t.deadline===void 0?void 0:createSessionTimeoutControl({deadline:t.deadline,sessionId:t.sessionId}),o={kind:`owned`,timeoutControl:a,turnControl:i,async dispose(){i.dispose(),await a?.dispose()}};return a?.start().catch(()=>{}),o}function unwrapSettled(e){if(e.status===`rejected`)throw e.reason;return e.value}async function disposeInitialBoot(e,t){let[n,r]=await Promise.allSettled([t?.dispose(),e.dispose()]);if(n.status===`rejected`)throw n.reason;if(r.status===`rejected`)throw r.reason}async function bootInitialOwner(e,t){let n=stampSessionIdentity(e.serializedContext,t),r=getWritable(),i=createSessionInbox(t),a=e.sessionTimeoutMs??DEFAULT_SESSION_TIMEOUT_MS,o=sessionTimeoutDeadline(a,Date.now()),s=n[`eve.continuationToken`]||``,c=n[`eve.bundle`],l;try{let u=createSessionStep({compiledArtifactsSource:c.source,continuationToken:s,dynamicSubagentAgentConfig:n[`eve.dynamicSubagentAgentConfig`],inheritedLimits:e.limits,nodeId:c.nodeId,outputSchema:e.input.outputSchema,rootSessionId:readRootSessionId(n),sessionId:t}),d=prepareInitialOwner(i,{continuationToken:s,deadline:o,sessionId:t}),f=hasDelegatedSessionContext(n)?resolveInitialTurnCallerStep({serializedContext:n}):Promise.resolve(void 0),[p,m,h]=await Promise.allSettled([u,d,f]);m.status===`fulfilled`&&m.value.kind===`owned`&&(l=m.value);let g=unwrapSettled(p),_=unwrapSettled(m);if(_.kind===`alias-conflict`){e.continuationConflictCommand!==void 0&&await settleContinuationConflictStep({command:e.continuationConflictCommand,continuationToken:s}),await disposeInitialBoot(i,l);return}return{inbox:i,session:{anchor:{kind:`self`},caller:unwrapSettled(h),capabilities:n[`eve.capabilities`],deploymentId:e.ownerDeploymentId,history:g.history,start:e.input.message===void 0?{kind:`first-message`}:{input:createInitialDelivery(e,n),kind:`turn`},initialTurnControl:_.turnControl,retention:e.retention,serializedContext:n,sessionId:t,sessionState:g.state,sessionTimeoutControl:_.timeoutControl,sessionTimeoutMs:a,sessionTimeoutDeadline:o,sessionWritable:r}}}catch(e){return await disposeInitialBoot(i,l),await failSession({error:e,serializedContext:n,sessionId:t,sessionState:void 0,sessionWritable:r})}}async function bootHandoffOwner(e){let{sessionId:t}=e,n=createSessionInbox(t),r,i,a;try{let o=migrateSessionCheckpoint(e.checkpoint),s=await validateSessionCheckpointStep({migration:o,sessionId:t});if(o.kind===`incompatible`||s.kind===`incompatible`){let t=await n.release();await signalSessionOwnerActivationStep({activation:{kind:`incompatible`,payloads:t,reason:`checkpoint-version`},token:e.activationToken});return}({checkpoint:r,childRunIdsToStop:i}=o),a=stampSessionIdentity(r.serializedContext,t),await recordSessionOwnerStep({sessionId:t}),await n.claimSessionHooks(sessionHookTokens({serializedContext:a,sessionState:r.sessionState})),await signalSessionOwnerActivationStep({activation:{kind:`active`},token:e.activationToken})}catch(t){let r=await n.release();await signalSessionOwnerActivationStep({activation:{error:normalizeSerializableError(t),kind:`failed`,payloads:r},token:e.activationToken});return}i.length>0&&await stopUntrackedChildSessionsStep({runIds:i,sessionId:t});let o=e.reason===`compaction`?e.sessionTimeoutDeadline:sessionTimeoutDeadline(r.sessionTimeoutMs,Date.now()),s=o===void 0?void 0:createSessionTimeoutControl({deadline:o,sessionId:t});return{inbox:n,session:{anchor:{kind:`successor`},caller:e.delivery?.caller,capabilities:r.capabilities,deploymentId:e.ownerDeploymentId,history:r.history,start:e.delivery===void 0?{kind:`parked`}:{input:e.delivery,kind:`turn`},retention:r.retention,serializedContext:a,sessionId:t,sessionState:r.sessionState,sessionTimeoutControl:s,sessionTimeoutMs:r.sessionTimeoutMs,sessionTimeoutDeadline:o,sessionWritable:e.sessionWritable}}}function createInitialDelivery(e,t){if(e.input.message!==void 0)return{schedule:readSerializedSessionSchedule(t),deliveryMetadata:t[`eve.channelDelivery`]===void 0?void 0:[{...t[`eve.channelDelivery`],payloadIndex:0}],kind:`deliver`,payloads:[attachClientContext({message:e.input.message,context:e.input.context,outputSchema:e.input.outputSchema,state:e.input.state},readClientContext(e.input))],requestId:readChannelRequestId(t)}}workflowEntry.workflowId=`workflow//eve//workflowEntry`;export{bootInitialOwner,workflowEntry};
1
+ import{attachClientContext,readClientContext}from"#internal/client-context.js";import{SESSION_INBOX_CONTEXT_KEY,sessionCommandHookToken}from"#execution/session-inbox/address.js";import{readSerializedSessionSchedule}from"#context/session-schedule.js";import{createHook,getWorkflowMetadata,getWritable}from"#compiled/@workflow/core/index.js";import{claimHookOwnership,isHookConflictError}from"#execution/hook-ownership.js";import{DEFAULT_SESSION_TIMEOUT_MS}from"#execution/session/timeout.js";import{sessionHookTokens}from"#execution/session/hook-tokens.js";import{createSessionInbox}from"#execution/session-inbox/inbox.js";import{failSession,runPreparedSession}from"#execution/session/program.js";import{createSessionTimeoutControl}from"#execution/session/timeout-control.js";import{prepareSuccessorStep,signalSessionOwnerActivationStep,stopUntrackedChildSessionsStep}from"#execution/session/handoff-steps.js";import{hasDelegatedSessionContext}from"#execution/delegated-session-context.js";import{readChannelRequestId,readRootSessionId}from"#execution/eve-workflow-attributes.js";import{createTurnControl}from"#execution/session/turn-control.js";import{HANDOFF_LEASE_RETENTION,handoffLeaseToken,sendSessionHandover}from"#execution/session/handoff.js";import{resolveInitialTurnCallerStep}from"#subagents/parent-notification.js";import{normalizeSerializableError}from"#execution/workflow-errors.js";import{createSessionStep}from"#execution/create-session-step.js";import{settleContinuationConflictStep}from"#execution/continuation-conflict-step.js";import{migrateSessionCheckpoint}from"#execution/session/checkpoint-migrations.js";import{abandonHandoverIfRunEnds,watchRunEnd}from"#execution/session/run-watch.js";async function workflowEntry(e){"use workflow";let t=e.kind===`initial`?await bootInitialOwner(e,getWorkflowMetadata().workflowRunId):(e.handoffVersion??0)>=3?await bootForcedHandoffOwner(e):await bootReleasedHandoffOwner(e);return t===void 0?{output:``}:{output:(await runPreparedSession(t.session,t.inbox)).output}}function stampSessionIdentity(e,t){return{...e,"eve.sessionId":t,[SESSION_INBOX_CONTEXT_KEY]:{sessionId:t}}}async function prepareInitialOwner(e,t){let[n,r]=await Promise.allSettled([e.claimSessionHook(sessionCommandHookToken(t.sessionId)),t.continuationToken===``?Promise.resolve():e.claimSessionHook(t.continuationToken)]);if(n.status===`rejected`)throw n.reason;if(r.status===`rejected`){if(isHookConflictError(r.reason))return{kind:`alias-conflict`};throw r.reason}let i=createTurnControl(),a=createSessionTimeoutControl({sessionId:t.sessionId,timeoutMs:t.sessionTimeoutMs}),o={kind:`owned`,timeoutControl:a,turnControl:i,async dispose(){i.dispose(),await a?.dispose()}};return a?.start().catch(()=>{}),o}function unwrapSettled(e){if(e.status===`rejected`)throw e.reason;return e.value}async function disposeInitialBoot(e,t){let[n,r]=await Promise.allSettled([t?.dispose(),e.dispose()]);if(n.status===`rejected`)throw n.reason;if(r.status===`rejected`)throw r.reason}async function bootInitialOwner(e,t){let n=stampSessionIdentity(e.serializedContext,t),r=getWritable(),i=createSessionInbox(t),a=e.sessionTimeoutMs??DEFAULT_SESSION_TIMEOUT_MS,o=n[`eve.continuationToken`]||``,s=n[`eve.bundle`],c;try{let l=createSessionStep({agentSessionRuntimeOverrides:n[`eve.agentSessionRuntimeOverrides`],compiledArtifactsSource:s.source,continuationToken:o,dynamicSubagentAgentConfig:n[`eve.dynamicSubagentAgentConfig`],history:e.input.message===void 0?e.input.history:void 0,nodeId:s.nodeId,outputSchema:e.input.outputSchema,rootSessionId:readRootSessionId(n),sessionId:t}),u=prepareInitialOwner(i,{continuationToken:o,sessionId:t,sessionTimeoutMs:a}),d=hasDelegatedSessionContext(n)?resolveInitialTurnCallerStep({serializedContext:n}):Promise.resolve(void 0),[f,p,m]=await Promise.allSettled([l,u,d]);p.status===`fulfilled`&&p.value.kind===`owned`&&(c=p.value);let h=unwrapSettled(f),g=unwrapSettled(p);if(g.kind===`alias-conflict`){e.continuationConflictCommand!==void 0&&await settleContinuationConflictStep({command:e.continuationConflictCommand,continuationToken:o}),await disposeInitialBoot(i,c);return}let _=unwrapSettled(m);return{inbox:i,session:{admittedDeliveryKeys:e.idempotencyKey===void 0?[]:[e.idempotencyKey],anchor:{kind:`self`},caller:_,capabilities:n[`eve.capabilities`],deploymentId:e.ownerDeploymentId,history:h.history,start:e.input.message===void 0?{kind:`first-message`}:{input:createInitialDelivery(e,n),kind:`turn`},initialTurnControl:g.turnControl,retention:e.retention,serializedContext:n,sessionId:t,sessionState:h.state,sessionTimeoutControl:g.timeoutControl,sessionTimeoutMs:a,sessionWritable:r}}}catch(e){return await disposeInitialBoot(i,c),await failSession({error:e,serializedContext:n,sessionId:t,sessionState:void 0,sessionWritable:r})}}async function prepareSuccessor(e,t){let{sessionId:n}=e,r=migrateSessionCheckpoint(e.checkpoint),i=await prepareSuccessorStep({handoffVersion:e.handoffVersion,migration:r,sessionId:n,...t!==void 0&&{source:t}});if(r.kind===`incompatible`||i.kind===`incompatible`){await signalSessionOwnerActivationStep({activation:{kind:`incompatible`,payloads:[],reason:`checkpoint-version`,runId:getWorkflowMetadata().workflowRunId},token:e.activationToken});return}if(i.kind===`source-gone`){await signalFailedActivation(e,Error(`The session's previous owner no longer holds all of its addresses.`),{payloads:[]});return}let{checkpoint:a,childRunIdsToStop:o}=r;return{checkpoint:a,childRunIdsToStop:o,serializedContext:stampSessionIdentity(a.serializedContext,n)}}async function signalFailedActivation(e,t,n){await signalSessionOwnerActivationStep({activation:{error:normalizeSerializableError(t),kind:`failed`,runId:getWorkflowMetadata().workflowRunId,...n},token:e.activationToken})}async function bootForcedHandoffOwner(e){let{attemptKey:t,hookTokens:n,sessionId:r,sourceRunId:i}=e;if(t===void 0||n===void 0||i===void 0){await signalFailedActivation(e,Error(`Session handoff version 3 input is missing attemptKey, hookTokens, or sourceRunId.`),{payloads:[]});return}try{let e=createHook({experimental_minRetention:HANDOFF_LEASE_RETENTION,token:handoffLeaseToken(t)});await claimHookOwnership(e)}catch(t){if(isHookConflictError(t))return;await signalFailedActivation(e,t,{payloads:[]});return}let a;try{a=await prepareSuccessor(e,{hookTokens:n,runId:i})}catch(t){await signalFailedActivation(e,t,{payloads:[]});return}if(a===void 0)return;let o=createSessionInbox(r);try{await o.claimSessionHooks(n,{force:!0,handover:t})}catch(n){let a=o.claimedTokens.length>0;await signalFailedActivation(e,n,{claimedHooks:a,payloads:[]}),a&&await handBack(o,{attemptKey:t,sessionId:r,sourceRunId:i}),await o.dispose();return}return abandonHandoverIfRunEnds(o,{attemptKey:t,sourceRunId:i}),await startSuccessor(e,o,a)}async function handBack(e,t){let n=watchRunEnd(t.sourceRunId),r=new AbortController;try{if(await Promise.race([e.whenTakenOver(r.signal).then(()=>`taken-back`),n.ended.then(()=>`source-ended`)])===`source-ended`)return}finally{n.stop(),r.abort()}await sendSessionHandover({attemptKey:t.attemptKey,payloads:e.drain(),sessionId:t.sessionId})}async function bootReleasedHandoffOwner(e){let t=createSessionInbox(e.sessionId),n;try{if(n=await prepareSuccessor(e),n===void 0)return;await t.claimSessionHooks(sessionHookTokens({serializedContext:n.serializedContext,sessionState:n.checkpoint.sessionState})),await signalSessionOwnerActivationStep({activation:{kind:`active`},token:e.activationToken})}catch(n){await signalFailedActivation(e,n,{payloads:await t.release()});return}return await startSuccessor(e,t,n)}async function startSuccessor(e,t,n){let{sessionId:r}=e,{checkpoint:i,childRunIdsToStop:a,serializedContext:o}=n;return a.length>0&&await stopUntrackedChildSessionsStep({runIds:a,sessionId:r}),{inbox:t,session:{anchor:{kind:`successor`},admittedDeliveryKeys:i.admittedDeliveryKeys,caller:e.delivery?.caller,capabilities:i.capabilities,deploymentId:e.ownerDeploymentId,history:i.history,start:e.delivery===void 0?{kind:`parked`}:{input:e.delivery,kind:`turn`},retention:i.retention,serializedContext:o,sessionId:r,sessionState:i.sessionState,sessionTimeoutControl:createSessionTimeoutControl({sessionId:r,timeoutMs:i.sessionTimeoutMs}),sessionTimeoutMs:i.sessionTimeoutMs,sessionWritable:e.sessionWritable}}}function createInitialDelivery(e,t){if(e.input.message!==void 0)return{idempotencyKey:e.idempotencyKey,schedule:readSerializedSessionSchedule(t),deliveryMetadata:t[`eve.channelDelivery`]===void 0?void 0:[{...t[`eve.channelDelivery`],payloadIndex:0}],kind:`deliver`,payloads:[attachClientContext({message:e.input.message,context:e.input.context,history:e.input.history,outputSchema:e.input.outputSchema,state:e.input.state},readClientContext(e.input))],requestId:readChannelRequestId(t)}}workflowEntry.workflowId=`workflow//eve//workflowEntry`;export{bootInitialOwner,workflowEntry};
@@ -1 +1 @@
1
- import{storedProjection}from"#harness/session-machine/view.js";import{liveTaskRuns,readTaskTable}from"#execution/tasks/table.js";import{getSessionUsage,takeSessionUsageDelta}from"#harness/turn-tag-state.js";import{terminateChildSessionsStep}from"#execution/terminate-child-sessions-step.js";import{notifyTurnCallerStep}from"#subagents/parent-notification.js";import{normalizeSerializableError}from"#execution/workflow-errors.js";import{emitTerminalSessionCompletionStep}from"#execution/terminal-session-completion-step.js";import{endSessionSandboxStep,reportSessionSandboxCleanupFailureStep}from"#execution/session/end-sandbox-step.js";import{emitTerminalSessionFailureStep}from"#execution/terminal-session-failure-step.js";async function finalizeSession(e,t){let{serializedContext:n,sessionState:r}=t.cursor;if(r!==void 0&&liveTaskRuns(readTaskTable(r.snapshot?.session?.state)).length>0&&await terminateChildSessionsStep({sessionState:r}),r!==void 0)try{await endSessionSandboxStep({reason:e.kind===`done`?`completed`:e.kind,serializedContext:n,sessionState:r})}catch(t){await reportSessionSandboxCleanupFailureStep({error:normalizeSerializableError(t),outcome:e.kind,sessionId:r.sessionId}).catch(()=>void 0)}let i=r?.snapshot.session,a=i===void 0?void 0:getSessionUsage(i);e.kind===`expired`?await emitTerminalSessionCompletionStep({sessionWritable:t.sessionWritable,serializedContext:n,turn:lastPublishedTurn(i?.state),usage:a}):e.kind===`failed`&&await emitTerminalSessionFailureStep({error:normalizeSerializableError(e.error),sessionWritable:t.sessionWritable,serializedContext:n,turnId:e.turnId,usage:a});let o=settledResult(e,t);if(t.caller!==void 0){let e={output:o.output,usage:o.turnUsage};o.isError&&(e.isError=!0),await notifyTurnCallerStep({caller:t.caller,lifecycle:`terminal`,sessionId:r?.sessionId??n[`eve.sessionId`],settled:e})}return e.kind===`done`?{isError:e.action.isError,output:e.action.output,usage:e.action.usage,usageDelta:e.action.usageDelta}:{isError:o.isError,output:o.output,usage:o.sessionUsage,usageDelta:o.turnUsage}}function settledResult(e,t){let n=t.cursor.sessionState?.snapshot.session,r=n===void 0||t.caller===void 0?{}:{sessionUsage:getSessionUsage(n),turnUsage:takeSessionUsageDelta(n).delta};switch(e.kind){case`done`:return{isError:e.action.isError===!0,output:e.action.output,sessionUsage:e.action.usage,turnUsage:e.action.usageDelta};case`expired`:return t.caller===void 0?{isError:!1,output:``}:{isError:!0,output:`The session ended before the delegated task completed.`,...r};case`failed`:return{isError:!0,output:normalizeSerializableError(e.error),...r}}}function lastPublishedTurn(e){let t=Object.values(storedProjection(e).turns).reduce((e,t)=>e===void 0||t.sequence>e.sequence?t:e,void 0);return t===void 0?void 0:{id:t.turnId,sequence:t.sequence}}export{finalizeSession};
1
+ import{storedProjection}from"#harness/session-machine/view.js";import{getSessionUsage,takeSessionUsageDelta}from"#harness/turn-tag-state.js";import{liveTaskRuns,readTaskTable}from"#execution/tasks/table.js";import{terminateChildSessionsStep}from"#execution/terminate-child-sessions-step.js";import{notifyTurnCallerStep}from"#subagents/parent-notification.js";import{normalizeSerializableError}from"#execution/workflow-errors.js";import{emitTerminalSessionCompletionStep}from"#execution/terminal-session-completion-step.js";import{endSessionSandboxStep,reportSessionSandboxCleanupFailureStep}from"#execution/session/end-sandbox-step.js";import{emitTerminalSessionFailureStep}from"#execution/terminal-session-failure-step.js";async function finalizeSession(e,t){let{serializedContext:n,sessionState:r}=t.cursor;if(r!==void 0&&liveTaskRuns(readTaskTable(r.snapshot?.session?.state)).length>0&&await terminateChildSessionsStep({sessionState:r}),r!==void 0)try{await endSessionSandboxStep({reason:e.kind===`done`?`completed`:e.kind,serializedContext:n,sessionState:r})}catch(t){await reportSessionSandboxCleanupFailureStep({error:normalizeSerializableError(t),outcome:e.kind,sessionId:r.sessionId}).catch(()=>void 0)}let i=r?.snapshot.session,a=i===void 0?void 0:getSessionUsage(i);e.kind===`expired`?await emitTerminalSessionCompletionStep({sessionWritable:t.sessionWritable,serializedContext:n,turn:lastPublishedTurn(i?.state),usage:a}):e.kind===`failed`&&await emitTerminalSessionFailureStep({error:normalizeSerializableError(e.error),sessionWritable:t.sessionWritable,serializedContext:n,turnId:e.turnId,usage:a});let o=settledResult(e,t);if(t.caller!==void 0){let e={output:o.output,usage:o.turnUsage};o.isError&&(e.isError=!0),await notifyTurnCallerStep({caller:t.caller,lifecycle:`terminal`,sessionId:r?.sessionId??n[`eve.sessionId`],settled:e})}return e.kind===`done`?{isError:e.action.isError,output:e.action.output,usage:e.action.usage,usageDelta:e.action.usageDelta}:{isError:o.isError,output:o.output,usage:o.sessionUsage,usageDelta:o.turnUsage}}function settledResult(e,t){let n=t.cursor.sessionState?.snapshot.session,r=n===void 0||t.caller===void 0?{}:{sessionUsage:getSessionUsage(n),turnUsage:takeSessionUsageDelta(n).delta};switch(e.kind){case`done`:return{isError:e.action.isError===!0,output:e.action.output,sessionUsage:e.action.usage,turnUsage:e.action.usageDelta};case`expired`:return t.caller===void 0?{isError:!1,output:``}:{isError:!0,output:`The session ended before the delegated task completed.`,...r};case`failed`:return{isError:!0,output:normalizeSerializableError(e.error),...r}}}function lastPublishedTurn(e){let t=Object.values(storedProjection(e).turns).reduce((e,t)=>e===void 0||t.sequence>e.sequence?t:e,void 0);return t===void 0?void 0:{id:t.turnId,sequence:t.sequence}}export{finalizeSession};
@@ -1,30 +1,68 @@
1
+ import type { SessionHandoverPayload } from "#execution/session-inbox/inbox.js";
1
2
  import type { SessionCheckpointMigration } from "#execution/session/checkpoint-migrations.js";
2
3
  import { type DurableSessionState } from "#execution/durable-session-store.js";
3
- import { type SessionOwnerActivation } from "#execution/session/handoff.js";
4
+ import { type SessionCheckpoint, type SessionOwnerActivation } from "#execution/session/handoff.js";
5
+ import { type SessionHandoffStart } from "#execution/session/entry-input.js";
4
6
  /** Parses retained work with this deployment's code before deciding whether it can move. */
5
7
  export declare function isSessionStateIdleForHandoff(input: {
6
8
  readonly sessionState: DurableSessionState;
7
9
  }): boolean;
8
- /** Reads durable work using the source deployment's handoff contract. */
9
- export declare function isSessionIdleForHandoffStep(input: {
10
- readonly sessionState: DurableSessionState;
10
+ export type SuccessorStartInput = SessionHandoffStart & {
11
+ readonly activationToken: string;
12
+ /** Original run whose stream stays the public session stream. */
13
+ readonly anchorRunId: string;
14
+ readonly attemptKey: string;
15
+ readonly checkpoint: SessionCheckpoint;
16
+ readonly hookTokens: readonly string[];
17
+ /** The owner starting the successor, which hands over what it accepts meanwhile. */
18
+ readonly sourceRunId: string;
19
+ readonly targetDeploymentId: string;
20
+ };
21
+ export type SuccessorStart = {
22
+ readonly kind: "not-idle";
23
+ } | {
24
+ readonly kind: "unsupported";
25
+ } | {
26
+ readonly kind: "started";
27
+ readonly runId: string;
28
+ };
29
+ /**
30
+ * Starts a successor owner bound to the original session stream, unless this
31
+ * deployment's code finds work in the checkpoint that cannot move yet, or the
32
+ * World cannot move session addresses between runs without releasing them.
33
+ */
34
+ export declare function startSuccessorStep(input: SuccessorStartInput): Promise<SuccessorStart>;
35
+ /** Whether `runId` has ended; a run not readable yet has not. */
36
+ export declare function hasRunEndedStep(input: {
37
+ readonly runId: string;
11
38
  }): Promise<boolean>;
12
39
  export type SessionCheckpointValidation = {
13
40
  readonly kind: "valid";
14
41
  } | {
15
42
  readonly kind: "incompatible";
16
43
  readonly reason: "checkpoint-version";
44
+ }
45
+ /** The source no longer holds every address it handed over, so none may be taken. */
46
+ | {
47
+ readonly kind: "source-gone";
17
48
  };
18
49
  /**
19
- * Validates an upgraded checkpoint and resolves the target deployment's
20
- * compiled bundle.
50
+ * Validates an upgraded checkpoint, resolves the target deployment's compiled
51
+ * bundle, and records this owner's identity before it claims any hook.
21
52
  *
22
53
  * A checkpoint this deployment cannot read is a settled answer, not a fault,
23
54
  * so it returns rather than throws: retrying the step can never change it.
24
55
  */
25
- export declare function validateSessionCheckpointStep(input: {
56
+ export declare function prepareSuccessorStep(input: {
57
+ /** Absent for version 1 sources, which predate the field. */
58
+ readonly handoffVersion: number | undefined;
26
59
  readonly migration: SessionCheckpointMigration;
27
60
  readonly sessionId: string;
61
+ /** Version 3: the run that still holds the session and the addresses it hands over. */
62
+ readonly source?: {
63
+ readonly runId: string;
64
+ readonly hookTokens: readonly string[];
65
+ };
28
66
  }): Promise<SessionCheckpointValidation>;
29
67
  /**
30
68
  * Stops idle subagent sessions an older owner kept resumable, after this owner
@@ -43,12 +81,12 @@ export declare function reportSessionHandoffRetainedStep(input: {
43
81
  readonly targetDeploymentId: string;
44
82
  }): Promise<void>;
45
83
  /**
46
- * Records the identity of an owner that this deployment's code did not start
47
- * (a handoff successor or a legacy importer) before it claims any hook:
48
- * ingress reads `$eve.version` to decide whether the owner can run, so a
49
- * missing value would strand a healthy session. The value comes from this
50
- * step's code, not the previous owner's. Unlike observability attributes, a
51
- * failed write fails the boot.
84
+ * Records the identity of a legacy importer before it claims any hook;
85
+ * handoff successors do the same inside `prepareSuccessorStep`. Ingress reads
86
+ * `$eve.version` to decide whether the owner can run, so a missing value would
87
+ * strand a healthy session. The value comes from this step's code, not the
88
+ * previous owner's. Unlike observability attributes, a failed write fails the
89
+ * boot.
52
90
  */
53
91
  export declare function recordSessionOwnerStep(input: {
54
92
  readonly sessionId: string;
@@ -57,6 +95,30 @@ export declare function signalSessionOwnerActivationStep(input: {
57
95
  readonly activation: SessionOwnerActivation;
58
96
  readonly token: string;
59
97
  }): Promise<void>;
98
+ /** Makes a takeover with no attempt open visible: every forced claim belongs to one. */
99
+ export declare function reportSessionTakenOverOutsideAttemptStep(input: {
100
+ readonly sessionId: string;
101
+ }): Promise<void>;
102
+ /**
103
+ * Makes a move whose handover part keeps failing visible; the owner keeps
104
+ * retrying, because dropping the part would lose an accepted message.
105
+ */
106
+ export declare function reportHandoverPartStuckStep(input: {
107
+ readonly attemptKey: string;
108
+ readonly error: string | undefined;
109
+ readonly failures: number;
110
+ readonly index: number;
111
+ readonly sessionId: string;
112
+ }): Promise<void>;
113
+ /**
114
+ * Sends one handover part through the stable session address, which reaches
115
+ * whichever run owns the session. A part that keeps failing fails the step,
116
+ * for the caller to retry until it is delivered.
117
+ */
118
+ export declare function sendSessionHandoverPartStep(input: {
119
+ readonly part: Omit<SessionHandoverPayload, "kind">;
120
+ readonly sessionId: string;
121
+ }): Promise<"delivered" | "session-ended">;
60
122
  export declare function signalSessionAnchorStep(input: {
61
123
  readonly result: {
62
124
  readonly output: unknown;
@@ -1 +1 @@
1
- import{openInputs,openSignIns}from"#protocol/session-projection.js";import{createLogger,logError}from"#internal/logging.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{walkCauseChain}from"#shared/errors.js";import{getSandboxEnvironmentRuntime}from"#shared/sandbox-environment.js";import{BundleKey}from"#runtime/sessions/runtime-context-keys.js";import{queuedInput,storedProjection}from"#harness/session-machine/view.js";import{cancelRun,getWorld,resumeHook}from"#internal/workflow/runtime.js";import{getResolvedRuntimeAgentNode}from"#runtime/graph.js";import{readDurableSession}from"#execution/durable-session-store.js";import{getBlockingWorkflowToolRuns}from"#harness/workflow-tool-runs.js";import{IncompatibleStateLayoutError,deserializeContext}from"#context/serialize.js";import{holdsHitlRequests}from"#harness/hitl/index.js";import{EntityConflictError,RunExpiredError,WorkflowRunNotFoundError}from"#compiled/@workflow/errors/index.js";import{EVE_SESSION_ATTRIBUTE,EVE_VERSION_ATTRIBUTE}from"#execution/eve-workflow-attributes.js";import{SESSION_CHECKPOINT_VERSION}from"#execution/session/handoff.js";const log=createLogger(`execution.handoff`);function isSessionStateIdleForHandoff(e){let{state:t}=readDurableSession(e.sessionState),n=getBlockingWorkflowToolRuns(t);if(holdsHitlRequests(t)||[`eve.runtime.pendingInputBatch`,`eve.runtime.pendingCoordinationBatch`,`eve.runtime.deferredStepInput`,`eve.harness.pendingWorkflowInterrupt`].some(e=>t?.[e]!==void 0))return!1;let r=t?.[`eve.runtime.pendingInputBatches`];if(r!==void 0&&(!Array.isArray(r)||r.length>0))return!1;let i=storedProjection(t);return n.length===0&&i.activeTurnId===void 0&&openInputs(i).length===0&&openSignIns(i).length===0&&queuedInput(t)===void 0}async function isSessionIdleForHandoffStep(e){"use step";return isSessionStateIdleForHandoff(e)}async function validateSessionCheckpointStep(e){"use step";let{migration:t}=e,unreadable=t=>(log.warn(`session handoff refused: this deployment cannot read the checkpoint`,{detail:t,readableCheckpointVersion:SESSION_CHECKPOINT_VERSION,sessionId:e.sessionId}),{kind:`incompatible`,reason:`checkpoint-version`});if(t.kind===`incompatible`)return unreadable(t.detail);let{checkpoint:n}=t,r=n.sessionTimeoutMs;if(r!==!1&&(typeof r!=`number`||!Number.isFinite(r)||r<0))throw Error(`Session checkpoint contains an invalid timeout duration.`);let i;try{i=await deserializeContext(n.serializedContext)}catch(e){if(e instanceof IncompatibleStateLayoutError)return unreadable(e.message);throw e}let a=i.require(BundleKey),o=readDurableSession(n.sessionState).sandboxState?.session;if(o!=null&&o.providerName!==void 0){let e=getResolvedRuntimeAgentNode(a.graph,a.nodeId).sandboxRegistry.sandbox.inheritance?.definition??getResolvedRuntimeAgentNode(a.graph,a.nodeId).sandboxRegistry.sandbox.definition;if(e.kind!==`independent`)throw Error(`Session checkpoint sandbox has no resolved provider.`);let t=getSandboxEnvironmentRuntime(e.environment);if(o.providerName!==t.providerName||o.stateProtocolVersion!==t.stateProtocolVersion)throw Error(`Session checkpoint sandbox provider state is incompatible.`)}if(!isSessionStateIdleForHandoff(n))throw Error(`Session checkpoint contains pending work and cannot be handed off.`);return{kind:`valid`}}async function stopUntrackedChildSessionsStep(e){"use step";let t=await getWorld();for(let n of e.runIds)if(n!==e.sessionId)try{await cancelRun(t,n,{cancelReason:`Session upgraded`})}catch(t){[...walkCauseChain(t)].some(e=>EntityConflictError.is(e)||RunExpiredError.is(e)||WorkflowRunNotFoundError.is(e))||logError(log,`could not stop a subagent session after handoff`,t,{childRunId:n,sessionId:e.sessionId})}}async function reportSessionHandoffRetainedStep(e){"use step";log.warn(`session handoff failed; the current owner keeps the session`,{...e,checkpointVersion:SESSION_CHECKPOINT_VERSION})}async function recordSessionOwnerStep(e){"use step";let{setAttributes:t}=await import(`#compiled/@workflow/core/index.js`);await t({[EVE_SESSION_ATTRIBUTE]:e.sessionId,[EVE_VERSION_ATTRIBUTE]:resolveInstalledPackageInfo().version},{allowReservedAttributes:!0})}async function signalSessionOwnerActivationStep(e){"use step";await resumeHook(e.token,e.activation)}async function signalSessionAnchorStep(e){"use step";await resumeHook(e.token,e.result)}export{isSessionIdleForHandoffStep,isSessionStateIdleForHandoff,recordSessionOwnerStep,reportSessionHandoffRetainedStep,signalSessionAnchorStep,signalSessionOwnerActivationStep,stopUntrackedChildSessionsStep,validateSessionCheckpointStep};
1
+ import{openInputs,openSignIns}from"#protocol/session-projection.js";import{createLogger,logError}from"#internal/logging.js";import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{walkCauseChain}from"#shared/errors.js";import{getSandboxEnvironmentRuntime}from"#shared/sandbox-environment.js";import{BundleKey}from"#runtime/sessions/runtime-context-keys.js";import{queuedInput,storedProjection}from"#harness/session-machine/view.js";import{cancelRun,getRun,getWorld,resumeHook}from"#internal/workflow/runtime.js";import{hasRunEnded,startWorkflowOnDeployment,workflowEntryReference}from"#execution/workflow-runtime.js";import{getResolvedRuntimeAgentNode}from"#runtime/graph.js";import{readDurableSession}from"#execution/durable-session-store.js";import{getBlockingWorkflowToolRuns}from"#harness/workflow-tool-runs.js";import{IncompatibleStateLayoutError,deserializeContext}from"#context/serialize.js";import{holdsHitlRequests}from"#harness/hitl/index.js";import{EntityConflictError,HookNotFoundError,RunExpiredError,WorkflowRunNotFoundError}from"#compiled/@workflow/errors/index.js";import{findSessionHookHolder}from"#execution/session-inbox/owner.js";import{EVE_SESSION_ATTRIBUTE,EVE_VERSION_ATTRIBUTE}from"#execution/eve-workflow-attributes.js";import{SESSION_CHECKPOINT_VERSION}from"#execution/session/handoff.js";import{mapWithConcurrency}from"#shared/map-with-concurrency.js";import{SESSION_HANDOFF_VERSION}from"#execution/session/entry-input.js";const log=createLogger(`execution.handoff`);function isSessionStateIdleForHandoff(e){let{state:t}=readDurableSession(e.sessionState),n=getBlockingWorkflowToolRuns(t);if(holdsHitlRequests(t)||[`eve.runtime.pendingInputBatch`,`eve.runtime.pendingCoordinationBatch`,`eve.runtime.deferredStepInput`,`eve.harness.pendingWorkflowInterrupt`].some(e=>t?.[e]!==void 0))return!1;let r=t?.[`eve.runtime.pendingInputBatches`];if(r!==void 0&&(!Array.isArray(r)||r.length>0))return!1;let i=storedProjection(t);return n.length===0&&i.activeTurnId===void 0&&openInputs(i).length===0&&openSignIns(i).length===0&&queuedInput(t)===void 0}async function startSuccessorStep(e){"use step";let{activationToken:t,anchorRunId:n,checkpoint:r,targetDeploymentId:i,...a}=e,{capabilities:o}=await getWorld();if(o?.hookForceClaim!==!0||o.hookRetention?.active!==!0)return log.warn(`session handoff unavailable: the Workflow world cannot force-claim hooks`,{sessionId:n}),{kind:`unsupported`};if(!isSessionStateIdleForHandoff(r))return{kind:`not-idle`};let s={...a,activationToken:t,checkpoint:r,handoffVersion:SESSION_HANDOFF_VERSION,kind:`handoff`,ownerDeploymentId:i,sessionWritable:getRun(n).getWritable(),sessionId:n};return{kind:`started`,runId:(await startWorkflowOnDeployment(workflowEntryReference,[s],i,r.retention===void 0?void 0:{experimental_retention:r.retention})).runId}}async function hasRunEndedStep(e){"use step";return await hasRunEnded(e.runId)}async function prepareSuccessorStep(e){"use step";let{migration:t}=e,unreadable=t=>(log.warn(`session handoff refused: this deployment cannot read the checkpoint`,{detail:t,readableCheckpointVersion:SESSION_CHECKPOINT_VERSION,sessionId:e.sessionId}),{kind:`incompatible`,reason:`checkpoint-version`});if(t.kind===`incompatible`)return unreadable(t.detail);let{checkpoint:n}=t,r=n.sessionTimeoutMs;if(r!==!1&&(typeof r!=`number`||!Number.isFinite(r)||r<0))throw Error(`Session checkpoint contains an invalid timeout duration.`);let i;try{i=await deserializeContext(n.serializedContext)}catch(e){if(e instanceof IncompatibleStateLayoutError)return unreadable(e.message);throw e}let a=i.require(BundleKey),o=readDurableSession(n.sessionState).sandboxState?.session;if(o!=null&&o.providerName!==void 0){let e=getResolvedRuntimeAgentNode(a.graph,a.nodeId).sandboxRegistry.sandbox.inheritance?.definition??getResolvedRuntimeAgentNode(a.graph,a.nodeId).sandboxRegistry.sandbox.definition;if(e.kind!==`independent`)throw Error(`Session checkpoint sandbox has no resolved provider.`);let t=getSandboxEnvironmentRuntime(e.environment);if(o.providerName!==t.providerName||o.stateProtocolVersion!==t.stateProtocolVersion)throw Error(`Session checkpoint sandbox provider state is incompatible.`)}if(!isSessionStateIdleForHandoff(n))throw Error(`Session checkpoint contains pending work and cannot be handed off.`);return e.source!==void 0&&!await holdsEveryAddress(e.source)?{kind:`source-gone`}:(await recordSessionOwner(e.sessionId),(e.handoffVersion??1)<SESSION_HANDOFF_VERSION&&log.info(`session moved from an owner that releases its addresses first`,{handoffVersion:e.handoffVersion??1,sessionId:e.sessionId}),{kind:`valid`})}async function holdsEveryAddress(e){return(await mapWithConcurrency(e.hookTokens,16,e=>findSessionHookHolder(sessionInboxHookToken(e)))).every(t=>t?.runId===e.runId)}async function stopUntrackedChildSessionsStep(e){"use step";let t=await getWorld();for(let n of e.runIds)if(n!==e.sessionId)try{await cancelRun(t,n,{cancelReason:`Session upgraded`})}catch(t){[...walkCauseChain(t)].some(e=>EntityConflictError.is(e)||RunExpiredError.is(e)||WorkflowRunNotFoundError.is(e))||logError(log,`could not stop a subagent session after handoff`,t,{childRunId:n,sessionId:e.sessionId})}}async function reportSessionHandoffRetainedStep(e){"use step";log.warn(`session handoff failed; the current owner keeps the session`,{...e,checkpointVersion:SESSION_CHECKPOINT_VERSION})}async function recordSessionOwnerStep(e){"use step";await recordSessionOwner(e.sessionId)}async function recordSessionOwner(e){let{setAttributes:t}=await import(`#compiled/@workflow/core/index.js`);await t({[EVE_SESSION_ATTRIBUTE]:e,[EVE_VERSION_ATTRIBUTE]:resolveInstalledPackageInfo().version},{allowReservedAttributes:!0})}async function signalSessionOwnerActivationStep(e){"use step";try{await resumeHook(e.token,e.activation)}catch(e){if(!HookNotFoundError.is(e))throw e}}async function reportSessionTakenOverOutsideAttemptStep(e){"use step";log.error(`session taken over with no handoff attempt open; this run leaves without finalizing`,{sessionId:e.sessionId})}async function reportHandoverPartStuckStep(e){"use step";log.warn(`session handover part keeps failing; the previous owner keeps retrying`,e)}async function sendSessionHandoverPartStep(e){"use step";try{return await resumeHook(sessionInboxHookToken(sessionCommandHookToken(e.sessionId)),{...e.part,kind:`handover`}),`delivered`}catch(e){if(HookNotFoundError.is(e))return`session-ended`;throw e}}async function signalSessionAnchorStep(e){"use step";await resumeHook(e.token,e.result)}export{hasRunEndedStep,isSessionStateIdleForHandoff,prepareSuccessorStep,recordSessionOwnerStep,reportHandoverPartStuckStep,reportSessionHandoffRetainedStep,reportSessionTakenOverOutsideAttemptStep,sendSessionHandoverPartStep,signalSessionAnchorStep,signalSessionOwnerActivationStep,startSuccessorStep,stopUntrackedChildSessionsStep};
@@ -1,4 +1,4 @@
1
- import type { DeliverHookPayload, SessionCapabilities } from "#channel/types.js";
1
+ import type { SessionCapabilities } from "#channel/types.js";
2
2
  import type { DurableSessionState } from "#execution/durable-session-store.js";
3
3
  import type { HarnessModelMessage } from "#harness/messages.js";
4
4
  import type { SessionInboxHandle, SessionInboxPayload } from "#execution/session-inbox/inbox.js";
@@ -13,9 +13,10 @@ import type { AgentWorkflowRetentionDefinition } from "#shared/agent-definition.
13
13
  * A newer successor must always accept older checkpoints: every bump adds the
14
14
  * upgrade from the previous version in `checkpoint-migrations.ts`.
15
15
  */
16
- export declare const SESSION_CHECKPOINT_VERSION = 15;
16
+ export declare const SESSION_CHECKPOINT_VERSION = 16;
17
17
  /** Everything a successor needs to continue an idle session. Hooks are derived from the state. */
18
18
  export interface SessionCheckpoint {
19
+ readonly admittedDeliveryKeys: readonly string[];
19
20
  readonly version: typeof SESSION_CHECKPOINT_VERSION;
20
21
  readonly capabilities?: SessionCapabilities;
21
22
  readonly history: HarnessModelMessage[];
@@ -29,81 +30,119 @@ export type SessionOwnerActivation = {
29
30
  } | {
30
31
  readonly kind: "incompatible";
31
32
  readonly reason: "checkpoint-version";
33
+ /** Version 3: the successor run that gave this verdict. */
34
+ readonly runId?: string;
32
35
  /** Commands accepted by partial successor claims before it rejected the checkpoint. */
33
36
  readonly payloads: readonly SessionInboxPayload[];
34
37
  } | {
35
38
  readonly kind: "failed";
39
+ /**
40
+ * Version 3: the successor took some of the session's hooks before it
41
+ * failed. The owner takes them back and waits for their handover.
42
+ */
43
+ readonly claimedHooks?: boolean;
36
44
  readonly error: unknown;
45
+ /** Version 3: the successor run that gave this verdict. */
46
+ readonly runId?: string;
37
47
  /** Commands accepted by partial successor claims before startup failed. */
38
48
  readonly payloads: readonly SessionInboxPayload[];
39
49
  };
40
50
  interface SessionHandoffInput {
41
- readonly checkpoint: Omit<SessionCheckpoint, "history" | "serializedContext" | "sessionState" | "version">;
51
+ readonly checkpoint: Omit<SessionCheckpoint, "admittedDeliveryKeys" | "history" | "serializedContext" | "sessionState" | "version">;
42
52
  readonly deploymentId: string;
43
53
  readonly inbox: SessionInboxHandle;
44
54
  readonly isInitialOwner: boolean;
45
55
  readonly sessionId: string;
46
56
  }
47
57
  export declare function sessionAnchorToken(sessionId: string): string;
58
+ /** Only one run per attempt can hold this; a successor that loses it exits untouched. */
59
+ export declare function handoffLeaseToken(attemptKey: string): string;
60
+ /**
61
+ * Measured from the lease's creation and far beyond any queue delay, so a
62
+ * duplicate candidate that boots late still finds the token taken.
63
+ */
64
+ export declare const HANDOFF_LEASE_RETENTION = "7d";
48
65
  type SessionTransferOutcome = {
49
66
  readonly kind: "transferred";
50
67
  } | {
51
68
  readonly kind: "retained";
52
69
  readonly reason: SessionRetainedReason;
53
70
  };
54
- type SessionRetainedReason = "same-deployment" | "missing-deployment" | "not-idle" | "busy" | "accepted-during-release" | "activation-failed" | "checkpoint-incompatible" | "known-incompatible";
55
- /** A compaction handoff the owner owes; the successor keeps this deadline. */
56
- export interface CompactionHandoff {
57
- readonly sessionTimeoutDeadline: Date | undefined;
58
- }
59
- type SessionTransferState = Pick<SessionCheckpoint, "history" | "serializedContext" | "sessionState">;
71
+ type SessionRetainedReason = "same-deployment" | "missing-deployment" | "not-idle" | "busy" | "activation-failed" | "checkpoint-incompatible" | "known-incompatible" | "unsupported-world";
72
+ type SessionTransferState = Pick<SessionCheckpoint, "admittedDeliveryKeys" | "history" | "serializedContext" | "sessionState">;
73
+ /**
74
+ * Sends `payloads` as handover parts, one payload per part: each was accepted
75
+ * on its own, so no part exceeds what the World already took. Every part is
76
+ * retried with backoff until it is delivered or the session has ended: the
77
+ * receiver reads nothing until the final part lands, and dropping a part
78
+ * would lose a message the session accepted.
79
+ */
80
+ export declare function sendSessionHandover(input: {
81
+ readonly attemptKey: string;
82
+ readonly payloads: readonly SessionInboxPayload[];
83
+ readonly sessionId: string;
84
+ }): Promise<void>;
60
85
  /**
61
86
  * The sole boundary for moving an idle session to a successor run: on another
62
87
  * exact deployment when newer code accepts a delivery, or on this deployment
63
88
  * after compaction so no single run's event log grows with the session.
64
89
  * Constructed once per owner; each `try*` method attempts one transfer.
65
- * When the upstream atomic hook-handoff primitive lands, only this class changes.
66
90
  *
67
- * Skipping known-incompatible targets requires this owner run to execute the
68
- * `incompatible` activation branch below. Owners still on an older eve build
69
- * treat that signal as a generic failure and attempt handoff on every turn;
70
- * they still benefit from successors returning incompatibility without step
71
- * retries.
91
+ * The owner never releases its hooks. The successor force-claims every one of
92
+ * them, and the takeover itself is the success signal: the owner then hands
93
+ * over whatever it accepted meanwhile and exits. Until the attempt settles
94
+ * the owner runs no turn.
72
95
  */
73
96
  export declare class SessionHandoff {
74
97
  private readonly input;
75
98
  private anchor;
76
99
  /** Deployments that rejected this session's checkpoint during this owner run. */
77
100
  private readonly incompatibleTargetDeploymentIds;
101
+ /** Counts this run's attempts; replay repeats the same sequence. */
102
+ private attempts;
103
+ /** The World cannot force-claim hooks, so no attempt can ever succeed. */
104
+ private worldUnsupported;
78
105
  constructor(input: SessionHandoffInput);
79
106
  /**
80
- * Attempts to move the session to the selected delivery's deployment. When a
81
- * compaction handoff is due and that deployment is this one or unknown, the
82
- * session moves to a fresh run here instead. The outcome states whether the
83
- * successor activated or this owner retained the session. Candidate failures
84
- * recover locally rather than escaping.
107
+ * Attempts to move the session to the selected delivery's deployment. The
108
+ * outcome states whether the successor took over or this owner retained the
109
+ * session. Candidate failures recover locally rather than escaping.
85
110
  */
86
- tryTransfer(selection: TurnSelection, state: SessionTransferState, options?: {
87
- readonly compaction?: CompactionHandoff;
88
- }): Promise<SessionTransferOutcome>;
111
+ tryTransfer(selection: TurnSelection, state: SessionTransferState): Promise<SessionTransferOutcome>;
89
112
  /**
90
113
  * Attempts to move a session that compacted to a fresh run on this
91
- * deployment. Without a delivery the caller guarantees no input is waiting,
92
- * and the successor parks until the next one arrives. The successor keeps
93
- * the session's deadline.
114
+ * deployment. The caller guarantees no input is waiting; the successor
115
+ * parks until the next one arrives.
94
116
  */
95
- tryCompactionTransfer(state: SessionTransferState, compaction: CompactionHandoff & {
96
- readonly delivery?: DeliverHookPayload;
97
- }): Promise<SessionTransferOutcome>;
117
+ tryCompactionTransfer(state: SessionTransferState): Promise<SessionTransferOutcome>;
98
118
  private transfer;
119
+ /**
120
+ * The session was taken over while no attempt was open. This run leaves as
121
+ * after a transfer, without finalizing the stream the new owner now writes.
122
+ */
123
+ adoptTakeover(): Promise<{
124
+ readonly kind: "transferred";
125
+ }>;
126
+ /**
127
+ * Claims the attempt's lease. `gaveUpRunId` is the candidate whose outcome
128
+ * the owner is acting on: holding the lease, it can no longer take over.
129
+ */
130
+ private fenceAttempt;
131
+ /** Forwards what this run accepted but never read to the run that took the session over. */
132
+ private handOver;
133
+ /**
134
+ * Takes back every address a candidate that gave up may hold. Forced claims
135
+ * replace this run's own hooks, so this holds whether or not a pump has
136
+ * observed the candidate's claim yet.
137
+ */
138
+ private holdEveryToken;
139
+ private recoverFromSilentCandidate;
140
+ /** Keeps the session after a candidate's verdict, taking back any hook it claimed. */
141
+ private recover;
142
+ private ensureAnchor;
99
143
  /** After a transfer, the original run parks until the final owner reports the session result. */
100
144
  awaitAnchoredResult(): Promise<WorkflowEntryResult>;
101
145
  disposeAnchor(): Promise<void>;
102
- /** Starts the candidate and waits for it to activate or fail. */
103
- private startAndActivate;
104
- /** Reclaims the exact hook set and replays payloads accepted while it was released. */
105
- private recover;
106
146
  private reportRetained;
107
- private ensureAnchor;
108
147
  }
109
148
  export {};
@@ -1 +1 @@
1
- import{isObject}from"#shared/guards.js";import{sessionHandoffMarkerToken}from"#execution/session-inbox/address.js";import{startSessionOwnerStep}from"#execution/workflow-runtime.js";import{createHook,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{claimHookOwnership,disposeHook}from"#execution/hook-ownership.js";import{sessionHookTokens}from"#execution/session/hook-tokens.js";import{isSessionIdleForHandoffStep,reportSessionHandoffRetainedStep}from"#execution/session/handoff-steps.js";import{readAcceptedDeploymentId}from"#execution/session/accepted-deployment.js";const SESSION_CHECKPOINT_VERSION=15;function sessionAnchorToken(e){return`${e}:anchor`}var SessionHandoff=class{input;anchor;incompatibleTargetDeploymentIds=new Set;constructor(e){this.input=e}async tryTransfer(e,t,n={}){let{delivery:r}=e,i=readAcceptedDeploymentId(r);return(i===void 0||i===this.input.deploymentId)&&n.compaction!==void 0?e.handoffEligible?await this.tryCompactionTransfer(t,{...n.compaction,delivery:r}):{kind:`retained`,reason:`busy`}:i===void 0?{kind:`retained`,reason:`missing-deployment`}:i===this.input.deploymentId?{kind:`retained`,reason:`same-deployment`}:this.incompatibleTargetDeploymentIds.has(i)?{kind:`retained`,reason:`known-incompatible`}:e.handoffEligible?await this.transfer(t,i,{delivery:r}):{kind:`retained`,reason:`busy`}}async tryCompactionTransfer(e,t){let{deploymentId:n}=this.input;return this.incompatibleTargetDeploymentIds.has(n)?{kind:`retained`,reason:`known-incompatible`}:await this.transfer(e,n,{...t,reason:`compaction`})}async transfer(e,t,n){let{inbox:r}=this.input;if(!await isSessionIdleForHandoffStep({sessionState:e.sessionState}))return{kind:`retained`,reason:`not-idle`};let i={...this.input.checkpoint,...e,version:15},a=sessionHookTokens(e);await this.ensureAnchor();let o=a.map(e=>createHook({token:sessionHandoffMarkerToken(e)}));await Promise.all(o.map(e=>claimHookOwnership(e)));let s;try{let e=await r.release();if(e.length>0)return await this.recover(a,e),{kind:`retained`,reason:`accepted-during-release`};let o=[];try{let e=await this.startAndActivate(i,n,t);if(e.kind===`active`)return{kind:`transferred`};o=e.payloads,e.kind===`incompatible`?(this.incompatibleTargetDeploymentIds.add(t),s={reason:`checkpoint-incompatible`}):s={error:e.error,reason:`activation-failed`}}catch(e){s={error:e,reason:`activation-failed`}}await this.recover(a,o)}finally{await Promise.all(o.map(e=>disposeHook(e)))}return await this.reportRetained(s.reason,t,s.error),{kind:`retained`,reason:s.reason}}async awaitAnchoredResult(){if(this.anchor===void 0)throw Error(`Session anchor was never claimed.`);try{return await this.anchor}finally{await this.disposeAnchor()}}async disposeAnchor(){if(this.anchor===void 0)return;let e=this.anchor;this.anchor=void 0,await disposeHook(e)}async startAndActivate(e,t,n){let r=createHook({token:`${getWorkflowMetadata().workflowRunId}:handoff`});await claimHookOwnership(r);try{return await startSessionOwnerStep({...t,activationToken:r.token,anchorRunId:this.input.sessionId,checkpoint:e,targetDeploymentId:n}),await r}finally{await disposeHook(r)}}async recover(e,t){await this.input.inbox.claimSessionHooks(e),this.input.inbox.restore(t)}async reportRetained(e,t,n){let r=isObject(n)&&typeof n.message==`string`?n.message:void 0;await reportSessionHandoffRetainedStep({error:r,reason:e,sessionId:this.input.sessionId,sourceDeploymentId:this.input.deploymentId,targetDeploymentId:t})}async ensureAnchor(){this.input.isInitialOwner&&this.anchor===void 0&&(this.anchor=createHook({token:sessionAnchorToken(this.input.sessionId)}),await claimHookOwnership(this.anchor))}};export{SESSION_CHECKPOINT_VERSION,SessionHandoff,sessionAnchorToken};
1
+ import{isObject}from"#shared/guards.js";import{createHook,getWorkflowMetadata,sleep}from"#compiled/@workflow/core/index.js";import{claimHookOwnership,disposeHook,isHookConflictError}from"#execution/hook-ownership.js";import{hasRunEndedStep,reportHandoverPartStuckStep,reportSessionHandoffRetainedStep,reportSessionTakenOverOutsideAttemptStep,sendSessionHandoverPartStep,startSuccessorStep}from"#execution/session/handoff-steps.js";import{abandonHandoverIfRunEnds,watchRunEnd}from"#execution/session/run-watch.js";import{readAcceptedDeploymentId}from"#execution/session/accepted-deployment.js";const SESSION_CHECKPOINT_VERSION=16;function sessionAnchorToken(e){return`${e}:anchor`}function handoffLeaseToken(e){return`eve:handoff:lease:${e}`}const HANDOFF_LEASE_RETENTION=`7d`;function verdictRunId(e){return e.kind===`verdict`&&e.verdict.kind!==`active`?e.verdict.runId:void 0}async function sendSessionHandover(e){let{attemptKey:t,sessionId:n}=e,r=e.payloads.filter(e=>e.kind!==`handover`);for(let[e,i]of r.entries())if(await sendHandoverPart({attemptKey:t,index:e,payloads:[i]},n)===`session-ended`)return;await sendHandoverPart({attemptKey:t,final:!0,index:r.length,payloads:[]},n)}async function sendHandoverPart(e,t){for(let n=1,r=1;;n++)try{return await sendSessionHandoverPartStep({part:e,sessionId:t})}catch(i){n===HANDOVER_PART_FAILURES_BEFORE_REPORT&&await reportHandoverPartStuckStep({attemptKey:e.attemptKey,error:isObject(i)&&typeof i.message==`string`?i.message:void 0,failures:n,index:e.index,sessionId:t}).catch(()=>{}),await sleep(r*1e3),r=Math.min(r*2,60)}}const HANDOVER_PART_FAILURES_BEFORE_REPORT=5;var SessionHandoff=class{input;anchor;incompatibleTargetDeploymentIds=new Set;attempts=0;worldUnsupported=!1;constructor(e){this.input=e}async tryTransfer(e,t){let{delivery:n}=e,r=readAcceptedDeploymentId(n);return r===void 0?{kind:`retained`,reason:`missing-deployment`}:r===this.input.deploymentId?{kind:`retained`,reason:`same-deployment`}:this.incompatibleTargetDeploymentIds.has(r)?{kind:`retained`,reason:`known-incompatible`}:e.handoffEligible?await this.transfer(t,r,{delivery:n}):{kind:`retained`,reason:`busy`}}async tryCompactionTransfer(e){let{deploymentId:t}=this.input;return this.incompatibleTargetDeploymentIds.has(t)?{kind:`retained`,reason:`known-incompatible`}:await this.transfer(e,t,{reason:`compaction`})}async transfer(e,t,n){let{inbox:r}=this.input;if(this.worldUnsupported)return{kind:`retained`,reason:`unsupported-world`};if(r.awaitingHandover)return{kind:`retained`,reason:`busy`};let i=getWorkflowMetadata().workflowRunId,a=this.attempts++,o=`${i}:${String(a)}`,s=r.claimedTokens,c=createHook({token:`${i}:handoff:${String(a)}`});this.ensureAnchor();let l=new AbortController,u=Date.now();try{let a;try{let r=await startSuccessorStep({...n,activationToken:c.token,anchorRunId:this.input.sessionId,attemptKey:o,checkpoint:{...this.input.checkpoint,...e,version:16},hookTokens:s,sourceRunId:i,targetDeploymentId:t});if(r.kind===`not-idle`)return{kind:`retained`,reason:`not-idle`};if(r.kind===`unsupported`)return this.worldUnsupported=!0,{kind:`retained`,reason:`unsupported-world`};a=r.runId}catch(e){let n=await this.fenceAttempt(o);if(n.kind!==`live`)return n.kind===`done`&&await this.holdEveryToken(s),await this.reportRetained(`activation-failed`,t,e),{kind:`retained`,reason:`activation-failed`};a=n.runId}let d=r.whenTakenOver(l.signal).then(()=>({kind:`taken-over`})),f,p;for(;;){if(f===void 0&&p===void 0&&r.hasPending()){let e=u+3e5-Date.now();p=sleep(Math.max(0,e)).then(()=>({kind:`deadline`}))}let e;try{e=await Promise.race([d,c.then(e=>({kind:`verdict`,verdict:e})),f===void 0?p??r.whenArrival().then(()=>({kind:`arrival`})):f.ended.then(()=>({kind:`candidate-ended`}))])}finally{f?.stop()}if(e.kind===`taken-over`)return await this.handOver(o);if(e.kind===`arrival`)continue;let n=e.kind===`candidate-ended`?a:verdictRunId(e),i=await this.fenceAttempt(o,n);if(i.kind===`live`){a=i.runId,f=watchRunEnd(a);continue}i.kind===`done`&&i.runId!==verdictRunId(e)&&await this.holdEveryToken(s);let l=e.kind===`verdict`?await this.recover(e.verdict,{attemptKey:o,candidateRunId:a,hookTokens:s,targetDeploymentId:t}):this.recoverFromSilentCandidate(e.kind);return await this.reportRetained(l.reason,t,l.error),{kind:`retained`,reason:l.reason}}}finally{l.abort(),await disposeHook(c)}}async adoptTakeover(){return await reportSessionTakenOverOutsideAttemptStep({sessionId:this.input.sessionId}),this.ensureAnchor(),{kind:`transferred`}}async fenceAttempt(e,t){let n=createHook({experimental_minRetention:`7d`,token:handoffLeaseToken(e)});try{await claimHookOwnership(n)}catch(e){if(!isHookConflictError(e)||typeof e.conflictingRunId!=`string`)throw e;let n=e.conflictingRunId;return n===t||await hasRunEndedStep({runId:n})?{kind:`done`,runId:n}:{kind:`live`,runId:n}}return{kind:`won`}}async handOver(e){return await sendSessionHandover({attemptKey:e,payloads:this.input.inbox.drain(),sessionId:this.input.sessionId}),{kind:`transferred`}}async holdEveryToken(e){await this.input.inbox.claimSessionHooks(e,{force:!0})}recoverFromSilentCandidate(e){return{error:Error(e===`deadline`?`The successor run did not report within 5 minutes.`:`The successor run ended before the handoff settled.`),reason:`activation-failed`}}async recover(e,t){let{inbox:n}=this.input;switch(e.kind){case`active`:return{error:Error(`Successor reported active without a takeover.`),reason:`activation-failed`};case`incompatible`:return this.incompatibleTargetDeploymentIds.add(t.targetDeploymentId),e.payloads.length>0&&n.restore(e.payloads),{reason:`checkpoint-incompatible`};case`failed`:return e.claimedHooks===!0?(await n.claimSessionHooks(t.hookTokens,{force:!0,handover:t.attemptKey}),abandonHandoverIfRunEnds(n,{attemptKey:t.attemptKey,sourceRunId:e.runId??t.candidateRunId})):isHookConflictError(e.error)&&this.incompatibleTargetDeploymentIds.add(t.targetDeploymentId),e.payloads.length>0&&n.restore(e.payloads),{error:e.error,reason:`activation-failed`}}}ensureAnchor(){this.input.isInitialOwner&&this.anchor===void 0&&(this.anchor=createHook({token:sessionAnchorToken(this.input.sessionId)}))}async awaitAnchoredResult(){if(this.anchor===void 0)throw Error(`Session anchor was never claimed.`);try{return await this.anchor}finally{await this.disposeAnchor()}}async disposeAnchor(){if(this.anchor===void 0)return;let e=this.anchor;this.anchor=void 0,await disposeHook(e)}async reportRetained(e,t,n){let r=isObject(n)&&typeof n.message==`string`?n.message:void 0;await reportSessionHandoffRetainedStep({error:r,reason:e,sessionId:this.input.sessionId,sourceDeploymentId:this.input.deploymentId,targetDeploymentId:t})}};export{HANDOFF_LEASE_RETENTION,SESSION_CHECKPOINT_VERSION,SessionHandoff,handoffLeaseToken,sendSessionHandover,sessionAnchorToken};
@@ -27,11 +27,15 @@ export type SessionInputSelection = TurnSelection | {
27
27
  */
28
28
  export declare class SessionInputQueue {
29
29
  private readonly entries;
30
+ private readonly admittedKeys;
30
31
  private nextSequence;
32
+ constructor(admittedDeliveryKeys: readonly string[]);
33
+ get admittedDeliveryKeys(): readonly string[];
34
+ isDuplicate(delivery: DeliverHookPayload): boolean;
31
35
  get pendingCount(): number;
32
36
  /** The sequence the next admission receives; every earlier admission is below it. */
33
37
  get nextAdmission(): number;
34
- enqueueDelivery(delivery: DeliverHookPayload): DeliveryAdmission;
38
+ enqueueDelivery(delivery: DeliverHookPayload): DeliveryAdmission | undefined;
35
39
  enqueueControl(control: SessionControl): void;
36
40
  /** Keeps one payload per authorization attempt; a repeated callback for the same attempt is dropped. */
37
41
  enqueueAuthorization(payloads: readonly DeliverPayload[]): void;
@@ -1 +1 @@
1
- import{coalesceDeliveries}from"#harness/messages.js";import{ANONYMOUS_PRINCIPAL,principalOf}from"#execution/session/principal.js";var SessionInputQueue=class{entries=[];nextSequence=0;get pendingCount(){return this.entries.length}get nextAdmission(){return this.nextSequence}enqueueDelivery(e){let t={delivery:e,sequence:this.nextSequence++};return this.entries.push({...t,kind:`delivery`}),t}enqueueControl(e){this.entries.push({control:e,kind:`control`,sequence:this.nextSequence++})}enqueueAuthorization(e){for(let t of e){let e=authorizationAttemptId(t);e!==void 0&&(this.entries.some(t=>t.kind===`authorization`&&t.attemptId===e)||this.entries.push({attemptId:e,kind:`authorization`,payload:t,sequence:this.nextSequence++}))}}takeAuthorizations(e){let t=this.entries.filter(t=>t.kind===`authorization`&&e.has(t.attemptId));if(!(t.length===0||new Set(t.map(e=>e.attemptId)).size<e.size))return this.retain(e=>!t.includes(e)),t.map(e=>e.payload)}delivery(e){return this.entries.find(t=>t.kind===`delivery`&&t.sequence===e)?.delivery}replaceDelivery(e,t){let n=this.entries.findIndex(t=>t.kind===`delivery`&&t.sequence===e);if(!(n<0)){if(t===void 0){this.entries.splice(n,1);return}this.entries[n]={delivery:t,kind:`delivery`,sequence:e}}}takeSteering(e,t,n){let r=this.entries.filter(r=>r.kind===`delivery`&&e.has(r.sequence)&&isSteeringDelivery(r.delivery,t,{heldOnPerson:n?.heldSince!==void 0&&r.sequence>=n.heldSince}));if(r.length!==0)return this.retain(e=>e.kind!==`delivery`||!r.includes(e)),{delivery:combine(r),handoffEligible:!1,kind:`turn`,sequences:r.map(({sequence:e})=>e)}}takeNext(e){this.retain(e=>e.kind!==`authorization`);let t=this.entries.shift();if(t===void 0)return;if(t.kind===`control`)return{control:t.control,kind:`control`};let n=[t,...this.takeFollowingDeliveriesFrom(t)],r=n.map(({sequence:e})=>e),i=combine(n);return{delivery:i,handoffEligible:r.length===1&&r[0]===e?.freshSequence&&i.caller===void 0&&this.entries.length===0,kind:`turn`,sequences:r}}takeFollowingDeliveriesFrom(e){let t=principalOf(e.delivery.auth),n=[],r=e.delivery.caller?.callId;for(;;){let e=this.entries[0];if(e?.kind!==`delivery`||t===ANONYMOUS_PRINCIPAL||principalOf(e.delivery.auth)!==t||r!==void 0&&e.delivery.caller!==void 0&&e.delivery.caller.callId!==r)break;n.push(e),this.entries.shift(),r??=e.delivery.caller?.callId}return n}retain(e){let t=this.entries.filter(e);this.entries.splice(0,this.entries.length,...t)}};function isSteeringDelivery(e,t,n){return(n?.heldOnPerson===!0||(e.turnPolicy??`steer`)===`steer`)&&(e.caller===void 0||e.caller.callId===t.callerCallId)&&(e.auth===void 0||principalOf(e.auth)===t.principal)}function isSteeringMessage(e,t){return isSteeringDelivery(e,t)&&e.payloads.some(e=>e.message!==void 0&&e.inputResponses===void 0)}function combine(e){return e.length===1?e[0].delivery:coalesceDeliveries(e.map(({delivery:e})=>e))}function authorizationAttemptId(e){let t=e.authorizationCallback;return typeof t?.attemptId==`string`?t.attemptId:void 0}export{SessionInputQueue,isSteeringDelivery,isSteeringMessage};
1
+ import{DELIVERY_IDEMPOTENCY_WINDOW}from"#channel/delivery-idempotency.js";import{coalesceDeliveries}from"#harness/messages.js";import{ANONYMOUS_PRINCIPAL,principalOf}from"#execution/session/principal.js";var SessionInputQueue=class{entries=[];admittedKeys;nextSequence=0;constructor(e){this.admittedKeys=new Set(e)}get admittedDeliveryKeys(){return[...this.admittedKeys]}isDuplicate(e){return e.idempotencyKey!==void 0&&this.admittedKeys.has(e.idempotencyKey)}get pendingCount(){return this.entries.length}get nextAdmission(){return this.nextSequence}enqueueDelivery(e){if(this.isDuplicate(e))return;e.idempotencyKey!==void 0&&(this.admittedKeys.add(e.idempotencyKey),this.admittedKeys.size>DELIVERY_IDEMPOTENCY_WINDOW&&this.admittedKeys.delete(this.admittedKeys.values().next().value));let t={delivery:e,sequence:this.nextSequence++};return this.entries.push({...t,kind:`delivery`}),t}enqueueControl(e){this.entries.push({control:e,kind:`control`,sequence:this.nextSequence++})}enqueueAuthorization(e){for(let t of e){let e=authorizationAttemptId(t);e!==void 0&&(this.entries.some(t=>t.kind===`authorization`&&t.attemptId===e)||this.entries.push({attemptId:e,kind:`authorization`,payload:t,sequence:this.nextSequence++}))}}takeAuthorizations(e){let t=this.entries.filter(t=>t.kind===`authorization`&&e.has(t.attemptId));if(!(t.length===0||new Set(t.map(e=>e.attemptId)).size<e.size))return this.retain(e=>!t.includes(e)),t.map(e=>e.payload)}delivery(e){return this.entries.find(t=>t.kind===`delivery`&&t.sequence===e)?.delivery}replaceDelivery(e,t){let n=this.entries.findIndex(t=>t.kind===`delivery`&&t.sequence===e);if(!(n<0)){if(t===void 0){this.entries.splice(n,1);return}this.entries[n]={delivery:t,kind:`delivery`,sequence:e}}}takeSteering(e,t,n){let r=this.entries.filter(r=>r.kind===`delivery`&&e.has(r.sequence)&&isSteeringDelivery(r.delivery,t,{heldOnPerson:n?.heldSince!==void 0&&r.sequence>=n.heldSince}));if(r.length!==0)return this.retain(e=>e.kind!==`delivery`||!r.includes(e)),{delivery:combine(r),handoffEligible:!1,kind:`turn`,sequences:r.map(({sequence:e})=>e)}}takeNext(e){this.retain(e=>e.kind!==`authorization`);let t=this.entries.shift();if(t===void 0)return;if(t.kind===`control`)return{control:t.control,kind:`control`};let n=[t,...this.takeFollowingDeliveriesFrom(t)],r=n.map(({sequence:e})=>e),i=combine(n);return{delivery:i,handoffEligible:r.length===1&&r[0]===e?.freshSequence&&i.caller===void 0&&this.entries.length===0,kind:`turn`,sequences:r}}takeFollowingDeliveriesFrom(e){let t=principalOf(e.delivery.auth),n=[],r=e.delivery.caller?.callId;for(;;){let e=this.entries[0];if(e?.kind!==`delivery`||t===ANONYMOUS_PRINCIPAL||principalOf(e.delivery.auth)!==t||r!==void 0&&e.delivery.caller!==void 0&&e.delivery.caller.callId!==r)break;n.push(e),this.entries.shift(),r??=e.delivery.caller?.callId}return n}retain(e){let t=this.entries.filter(e);this.entries.splice(0,this.entries.length,...t)}};function isSteeringDelivery(e,t,n){return(n?.heldOnPerson===!0||(e.turnPolicy??`steer`)===`steer`)&&(e.caller===void 0||e.caller.callId===t.callerCallId)&&(e.auth===void 0||principalOf(e.auth)===t.principal)}function isSteeringMessage(e,t){return isSteeringDelivery(e,t)&&e.payloads.some(e=>e.message!==void 0&&e.inputResponses===void 0)}function combine(e){return e.length===1?e[0].delivery:coalesceDeliveries(e.map(({delivery:e})=>e))}function authorizationAttemptId(e){let t=e.authorizationCallback;return typeof t?.attemptId==`string`?t.attemptId:void 0}export{SessionInputQueue,isSteeringDelivery,isSteeringMessage};
@@ -0,0 +1,5 @@
1
+ import type { SessionStateMap } from "#harness/types.js";
2
+ import type { SessionHistoryMessage } from "#shared/session-history.js";
3
+ export declare function withPendingHistory(state: SessionStateMap | undefined, history: readonly SessionHistoryMessage[] | undefined): SessionStateMap | undefined;
4
+ export declare function readPendingHistory(state: SessionStateMap | undefined): readonly SessionHistoryMessage[];
5
+ export declare function withoutPendingHistory(state: SessionStateMap | undefined): SessionStateMap | undefined;
@@ -0,0 +1 @@
1
+ const PENDING_HISTORY_STATE_KEY=`eve.session.pendingHistory`;function withPendingHistory(e,t){return t===void 0||t.length===0?e:{...e,[PENDING_HISTORY_STATE_KEY]:t}}function readPendingHistory(e){return e?.[PENDING_HISTORY_STATE_KEY]??[]}function withoutPendingHistory(e){if(e===void 0||!(PENDING_HISTORY_STATE_KEY in e))return e;let{[PENDING_HISTORY_STATE_KEY]:t,...n}=e;return n}export{readPendingHistory,withPendingHistory,withoutPendingHistory};
@@ -1 +1 @@
1
- import{openSignIns}from"#protocol/session-projection.js";import{runtimeWait}from"#harness/session-machine/view.js";import{readHitlState}from"#harness/hitl/index.js";import{sessionView}from"#harness/session-machine/commit.js";import{ownOpenRequestIds}from"#harness/session-machine/transitions.js";function derivePendingState(e,t){let{signIns:n}=readHitlState(e.state),r={authorizationAttemptIds:n.length===0?void 0:n.flatMap(e=>e.attemptId===void 0?[]:[e.attemptId]),hasPendingAuthorization:openSignIns(t).length>0,hasPendingInputBatch:ownOpenRequestIds(sessionView(t,e.state)).size>0},i=runtimeWait(e.state);return i===void 0?r:{...r,hasRunsToDispatch:i.tasks.length>0,pendingCoordinationCallIds:i.callIds,pendingTaskToolCalls:i.taskToolCalls}}export{derivePendingState};
1
+ import{openSignIns}from"#protocol/session-projection.js";import{runtimeWait}from"#harness/session-machine/view.js";import{readHitlState}from"#harness/hitl/index.js";import{ownOpenRequestIds}from"#harness/session-machine/transitions.js";import{sessionView}from"#harness/session-machine/commit.js";function derivePendingState(e,t){let{signIns:n}=readHitlState(e.state),r={authorizationAttemptIds:n.length===0?void 0:n.flatMap(e=>e.attemptId===void 0?[]:[e.attemptId]),hasPendingAuthorization:openSignIns(t).length>0,hasPendingInputBatch:ownOpenRequestIds(sessionView(t,e.state)).size>0},i=runtimeWait(e.state);return i===void 0?r:{...r,hasRunsToDispatch:i.tasks.length>0,pendingCoordinationCallIds:i.callIds,pendingTaskToolCalls:i.taskToolCalls}}export{derivePendingState};
@@ -34,6 +34,7 @@ export type SessionStart =
34
34
  readonly kind: "parked";
35
35
  };
36
36
  export interface SessionBoot {
37
+ readonly admittedDeliveryKeys: readonly string[];
37
38
  readonly anchor: SessionAnchor;
38
39
  readonly caller: TurnCaller | undefined;
39
40
  readonly capabilities?: SessionCapabilities;
@@ -46,7 +47,6 @@ export interface SessionBoot {
46
47
  readonly sessionId: string;
47
48
  readonly sessionState: DurableSessionState;
48
49
  readonly sessionTimeoutControl?: SessionTimeoutControl;
49
- readonly sessionTimeoutDeadline?: Date;
50
50
  readonly sessionTimeoutMs: number | false;
51
51
  readonly sessionWritable: WritableStream<Uint8Array>;
52
52
  }
@@ -1 +1 @@
1
- import{STUB_CONTEXT_KEY}from"#tool-stubs/types.js";import{workingTasks}from"#execution/tasks/table.js";import{settleCancelledTurnStep}from"#execution/settle-cancelled-turn-step.js";import"#execution/session-inbox/inbox.js";import{signalSessionAnchorStep}from"#execution/session/handoff-steps.js";import{SessionInputQueue}from"#execution/session/input-queue.js";import{createTurnControl}from"#execution/session/turn-control.js";import{SessionHandoff,sessionAnchorToken}from"#execution/session/handoff.js";import{notifyCancelledTaskCallerStep,notifyTurnCallerStep,resolveInitialTurnCallerStep}from"#subagents/parent-notification.js";import{withStubPlayback}from"#execution/tool-stubs/playback.js";import{nextTurnDelivery}from"#execution/session/next-input.js";import{SessionExecution}from"#execution/session/turn.js";import{SessionStateCursor}from"#execution/session/state-cursor.js";import{cancelWorkingTasks,sessionTaskTable}from"#execution/tasks/session.js";import{finalizeSession}from"#execution/session/finalization.js";function createSafeOuterWorkflowError(){let e=Error(`Agent workflow failed. Inspect the private session trace for details.`);return e.name=`EveWorkflowFailure`,e}async function runPreparedSession(e,t){let n=e.serializedContext[STUB_CONTEXT_KEY];n!==void 0&&n.rootSessionId===void 0&&(e.serializedContext[STUB_CONTEXT_KEY]={...n,rootSessionId:e.sessionId});let r=new SessionStateCursor({history:e.history,inbox:t,sessionWritable:e.sessionWritable,serializedContext:e.serializedContext,sessionState:e.sessionState}),i={caller:e.caller,terminalEmitted:!1},a=new SessionHandoff({checkpoint:{capabilities:e.capabilities,retention:e.retention,sessionTimeoutMs:e.sessionTimeoutMs},deploymentId:e.deploymentId,inbox:t,isInitialOwner:e.anchor.kind===`self`,sessionId:e.sessionId}),o={output:``,isError:!0},s;try{return o=await withStubPlayback(n,e.sessionId,async()=>{try{s=await runSessionLoop(e,{cursor:r,handoff:a,inbox:t,progress:i})}finally{await t.dispose()}return s.kind===`transferred`?e.anchor.kind===`self`?(o=await a.awaitAnchoredResult(),o):{output:``}:(o=await finalizeSession(s.outcome,{caller:i.caller,cursor:r,sessionWritable:e.sessionWritable}),i.terminalEmitted=!0,o)}),o}catch(t){throw i.terminalEmitted||await finalizeSession({error:t,kind:`failed`,turnId:i.turnId},{caller:i.caller,cursor:r,sessionWritable:e.sessionWritable}),createSafeOuterWorkflowError()}finally{await t.dispose(),await reportResultToAnchor(e,o,a,s)}}async function failSession(e){let t;try{t=await resolveInitialTurnCallerStep({serializedContext:e.serializedContext})}catch{}throw await finalizeSession({error:e.error,kind:`failed`},{caller:t,cursor:{serializedContext:e.serializedContext,sessionState:e.sessionState},sessionWritable:e.sessionWritable}),createSafeOuterWorkflowError()}async function reportResultToAnchor(e,t,n,r){switch(e.anchor.kind){case`self`:await n.disposeAnchor(),await e.anchor.notify?.(t);return;case`successor`:if(r?.kind===`transferred`)return;await signalSessionAnchorStep({result:t,token:sessionAnchorToken(e.sessionId)});return}}async function runSessionLoop(e,t){let{cursor:n,handoff:r,inbox:i,progress:a}=t,o=new SessionInputQueue,s=new SessionExecution({capabilities:e.capabilities,cursor:n,inbox:i,queue:o,sessionId:e.sessionId}),c=e.sessionTimeoutControl,nextParkedActivity=async()=>{for(;;){let e=await nextTurnDelivery({cursor:n,hasWorkingTasks:()=>workingTasks(sessionTaskTable(n)).length>0,inbox:i,queue:o});if(e.kind===`workflow`){await s.handleWorkflowMessage(e.message);continue}if(e.kind===`cancel-working-tasks`){await cancelWorkingTasks(n,`turn_cancelled`);continue}return e}},l=e.initialTurnControl??(e.anchor.kind===`self`?createTurnControl():void 0),u=0,d=!1,runTurn=async e=>{let t=a.caller,n=l;l=void 0,a.turnId=`turn_${String(u++)}`;let r=await s.runTurn(e,{caller:t,control:n});return r.caller!==void 0&&(a.caller=r.caller),r.compacted===!0&&(d=!0),r},transferState=()=>({history:n.history,serializedContext:n.serializedContext,sessionState:n.sessionState}),dueCompactionHandoff=()=>d&&a.caller===void 0&&workingTasks(sessionTaskTable(n)).length===0?{sessionTimeoutDeadline:e.sessionTimeoutDeadline}:void 0,tryCompactionHandoff=async()=>{let e=dueCompactionHandoff();if(e===void 0||o.pendingCount>0||i.hasPending())return;let t=await r.tryCompactionTransfer(transferState(),e);return t.kind===`transferred`?t:void 0},runDeliveredTurn=async e=>{let t=await r.tryTransfer(e,transferState(),{compaction:dueCompactionHandoff()});return t.kind===`transferred`?t:(e.delivery.caller!==void 0&&(a.caller=e.delivery.caller),{action:await runTurn({delivery:e.delivery}),kind:`action`})},settleCancelledTurn=async e=>{let t=await n.advanceWithHistory(t=>settleCancelledTurnStep({...t,reportUsage:e}));return a.caller=void 0,t},awaitPrewarmedAction=async()=>{for(;;){let e=await nextParkedActivity();switch(e.kind){case`expired`:case`reset`:case`closed`:return{kind:`terminal`,outcome:{kind:`expired`}};case`clear`:case`compact`:continue;case`turn`:return await runDeliveredTurn(e);case`cancel-turn`:continue}}},runInitialAction=async()=>{switch(e.start.kind){case`first-message`:return await awaitPrewarmedAction();case`parked`:return{action:{kind:`park`},kind:`action`};case`turn`:{let{input:t}=e.start;return{action:await runTurn(t===void 0?void 0:{delivery:t}),kind:`action`}}}};try{let[t,n]=await Promise.allSettled([runInitialAction(),c?.start()]);if(n.status===`rejected`)throw n.reason;if(t.status===`rejected`)throw t.reason;let r=t.value;if(r.kind!==`action`)return r;let i=r.action;for(;;){if(i.kind===`done`)return{kind:`terminal`,outcome:{action:i,kind:`done`}};if(i.cancelled===!0){let{caller:t}=a,n=await settleCancelledTurn(t!==void 0);if(t!==void 0){let r={caller:t,sessionId:e.sessionId};await notifyCancelledTaskCallerStep(n.usage===void 0?r:{...r,usage:n.usage})}}else i.settled!==void 0&&(a.caller!==void 0&&await notifyTurnCallerStep({caller:a.caller,lifecycle:`parked`,sessionId:e.sessionId,settled:i.settled}),a.caller=void 0);let t=await tryCompactionHandoff();if(t!==void 0)return t;let n=await nextParkedActivity();switch(n.kind){case`expired`:case`reset`:case`closed`:return{kind:`terminal`,outcome:{kind:`expired`}};case`clear`:case`compact`:i=await runTurn({control:n.kind});continue;case`cancel-turn`:await s.cancelTurnWork(),await settleCancelledTurn(!1),i={...i,settled:void 0};continue;case`turn`:{let e=await runDeliveredTurn(n);if(e.kind!==`action`)return e;i=e.action;continue}}}}finally{l?.dispose(),await c?.dispose()}}export{failSession,runPreparedSession};
1
+ import{STUB_CONTEXT_KEY}from"#tool-stubs/types.js";import{workingTasks}from"#execution/tasks/table.js";import{settleCancelledTurnStep}from"#execution/settle-cancelled-turn-step.js";import"#execution/session-inbox/inbox.js";import{signalSessionAnchorStep}from"#execution/session/handoff-steps.js";import{SessionInputQueue}from"#execution/session/input-queue.js";import{createTurnControl}from"#execution/session/turn-control.js";import{SessionHandoff,sessionAnchorToken}from"#execution/session/handoff.js";import{notifyCancelledTaskCallerStep,notifyTurnCallerStep,resolveInitialTurnCallerStep}from"#subagents/parent-notification.js";import{withStubPlayback}from"#execution/tool-stubs/playback.js";import{nextTurnDelivery}from"#execution/session/next-input.js";import{SessionExecution}from"#execution/session/turn.js";import{SessionStateCursor}from"#execution/session/state-cursor.js";import{cancelWorkingTasks,sessionTaskTable}from"#execution/tasks/session.js";import{finalizeSession}from"#execution/session/finalization.js";function createSafeOuterWorkflowError(){let e=Error(`Agent workflow failed. Inspect the private session trace for details.`);return e.name=`EveWorkflowFailure`,e}async function runPreparedSession(e,t){let n=e.serializedContext[STUB_CONTEXT_KEY];n!==void 0&&n.rootSessionId===void 0&&(e.serializedContext[STUB_CONTEXT_KEY]={...n,rootSessionId:e.sessionId});let r=new SessionStateCursor({history:e.history,inbox:t,sessionWritable:e.sessionWritable,serializedContext:e.serializedContext,sessionState:e.sessionState}),i={caller:e.caller,terminalEmitted:!1},a=new SessionHandoff({checkpoint:{capabilities:e.capabilities,retention:e.retention,sessionTimeoutMs:e.sessionTimeoutMs},deploymentId:e.deploymentId,inbox:t,isInitialOwner:e.anchor.kind===`self`,sessionId:e.sessionId}),o={output:``,isError:!0},s;try{return o=await withStubPlayback(n,e.sessionId,async()=>{try{s=await runSessionLoop(e,{cursor:r,handoff:a,inbox:t,progress:i})}finally{await t.dispose()}return s.kind===`transferred`?e.anchor.kind===`self`?(o=await a.awaitAnchoredResult(),o):{output:``}:(o=await finalizeSession(s.outcome,{caller:i.caller,cursor:r,sessionWritable:e.sessionWritable}),i.terminalEmitted=!0,o)}),o}catch(t){throw i.terminalEmitted||await finalizeSession({error:t,kind:`failed`,turnId:i.turnId},{caller:i.caller,cursor:r,sessionWritable:e.sessionWritable}),createSafeOuterWorkflowError()}finally{await t.dispose(),await reportResultToAnchor(e,o,a,s)}}async function failSession(e){let t;try{t=await resolveInitialTurnCallerStep({serializedContext:e.serializedContext})}catch{}throw await finalizeSession({error:e.error,kind:`failed`},{caller:t,cursor:{serializedContext:e.serializedContext,sessionState:e.sessionState},sessionWritable:e.sessionWritable}),createSafeOuterWorkflowError()}async function reportResultToAnchor(e,t,n,r){switch(e.anchor.kind){case`self`:await n.disposeAnchor(),await e.anchor.notify?.(t);return;case`successor`:if(r?.kind===`transferred`)return;await signalSessionAnchorStep({result:t,token:sessionAnchorToken(e.sessionId)});return}}async function runSessionLoop(e,t){let{cursor:n,handoff:r,inbox:i,progress:a}=t,o=new SessionInputQueue(e.admittedDeliveryKeys),s=new SessionExecution({capabilities:e.capabilities,cursor:n,inbox:i,queue:o,sessionId:e.sessionId}),c=e.sessionTimeoutControl,nextParkedActivity=async()=>{for(;;){let e=await nextTurnDelivery({cursor:n,hasWorkingTasks:()=>workingTasks(sessionTaskTable(n)).length>0,inbox:i,queue:o});if(e.kind===`workflow`){await s.handleWorkflowMessage(e.message);continue}if(e.kind===`cancel-working-tasks`){await cancelWorkingTasks(n,`turn_cancelled`);continue}if(!(e.kind===`expired`&&c!==void 0&&((o.pendingCount>0||i.hasPending())&&c.recordActivity(),await c.handleTimerElapsed()===`extended`)))return e}},l=e.initialTurnControl??(e.anchor.kind===`self`?createTurnControl():void 0),u=0,d=!1,runTurn=async e=>{let t=a.caller,n=l;l=void 0,a.turnId=`turn_${String(u++)}`;let r=await s.runTurn(e,{caller:t,control:n});return c?.recordActivity(),r.caller!==void 0&&(a.caller=r.caller),r.compacted===!0&&(d=!0),r},transferState=()=>({admittedDeliveryKeys:o.admittedDeliveryKeys,history:n.history,serializedContext:n.serializedContext,sessionState:n.sessionState}),compactionHandoffReady=()=>d&&a.caller===void 0&&workingTasks(sessionTaskTable(n)).length===0,tryCompactionHandoff=async()=>{if(!compactionHandoffReady()||o.pendingCount>0||i.hasPending())return;let e=await r.tryCompactionTransfer(transferState());return e.kind===`transferred`?e:void 0},runDeliveredTurn=async e=>{let t=await r.tryTransfer(e,transferState());return t.kind===`transferred`?t:(e.delivery.caller!==void 0&&(a.caller=e.delivery.caller),{action:await runTurn({delivery:e.delivery}),kind:`action`})},settleCancelledTurn=async e=>{let t=await n.advanceWithHistory(t=>settleCancelledTurnStep({...t,reportUsage:e}));return a.caller=void 0,t},awaitPrewarmedAction=async()=>{for(;;){let e=await nextParkedActivity();switch(e.kind){case`closed`:return i.takenOver?await r.adoptTakeover():{kind:`terminal`,outcome:{kind:`expired`}};case`expired`:case`reset`:return{kind:`terminal`,outcome:{kind:`expired`}};case`clear`:case`compact`:continue;case`turn`:return await runDeliveredTurn(e);case`cancel-turn`:continue}}},runInitialAction=async()=>{switch(e.start.kind){case`first-message`:return await awaitPrewarmedAction();case`parked`:return{action:{kind:`park`},kind:`action`};case`turn`:{let{input:t}=e.start;return{action:await runTurn(t===void 0?void 0:{delivery:t}),kind:`action`}}}};try{let[t,n]=await Promise.allSettled([runInitialAction(),c?.start()]);if(n.status===`rejected`)throw n.reason;if(t.status===`rejected`)throw t.reason;let o=t.value;if(o.kind!==`action`)return o;let l=o.action;for(;;){if(l.kind===`done`)return{kind:`terminal`,outcome:{action:l,kind:`done`}};if(l.cancelled===!0){let{caller:t}=a,n=await settleCancelledTurn(t!==void 0);if(t!==void 0){let r={caller:t,sessionId:e.sessionId};await notifyCancelledTaskCallerStep(n.usage===void 0?r:{...r,usage:n.usage})}}else l.settled!==void 0&&(a.caller!==void 0&&await notifyTurnCallerStep({caller:a.caller,lifecycle:`parked`,sessionId:e.sessionId,settled:l.settled}),a.caller=void 0);let t=await tryCompactionHandoff();if(t!==void 0)return t;let n=await nextParkedActivity();switch(n.kind){case`closed`:return i.takenOver?await r.adoptTakeover():{kind:`terminal`,outcome:{kind:`expired`}};case`expired`:case`reset`:return{kind:`terminal`,outcome:{kind:`expired`}};case`clear`:case`compact`:l=await runTurn({control:n.kind});continue;case`cancel-turn`:await s.cancelTurnWork(),await settleCancelledTurn(!1),c?.recordActivity(),l={...l,settled:void 0};continue;case`turn`:{let e=await runDeliveredTurn(n);if(e.kind!==`action`)return e;l=e.action;continue}}}}finally{l?.dispose(),await c?.dispose()}}export{failSession,runPreparedSession};
@@ -0,0 +1,22 @@
1
+ import type { SessionInboxHandle } from "#execution/session-inbox/inbox.js";
2
+ export interface RunWatch {
3
+ /** Resolves once the run has ended; never settles once stopped. */
4
+ readonly ended: Promise<void>;
5
+ stop(): void;
6
+ }
7
+ /**
8
+ * Watches a counterpart run so a wait on it has a way out when that run is
9
+ * gone. Durable sleeps between checks keep it deterministic under replay;
10
+ * `stop()` ends it before its next check.
11
+ */
12
+ export declare function watchRunEnd(runId: string): RunWatch;
13
+ /**
14
+ * Opens the inbox's handover gate with nothing restored if `sourceRunId` ends
15
+ * before its handover arrives: an ended run can never send it. The watch
16
+ * starts only once a read waits on the gate, so a handover that arrives
17
+ * before it is needed costs nothing.
18
+ */
19
+ export declare function abandonHandoverIfRunEnds(inbox: SessionInboxHandle, handover: {
20
+ readonly attemptKey: string;
21
+ readonly sourceRunId: string;
22
+ }): void;
@@ -0,0 +1 @@
1
+ import{sleep}from"#compiled/@workflow/core/index.js";import{hasRunEndedStep}from"#execution/session/handoff-steps.js";function watchRunEnd(e){let t=!1;return{ended:(async()=>{for(;!t&&(await sleep(`10s`),!t);)if(await hasRunEndedStep({runId:e}).catch(()=>!1)&&!t)return;return await new Promise(()=>{})})(),stop(){t=!0}}}function abandonHandoverIfRunEnds(e,t){e.whenBlockedOnHandover().then(()=>{if(!e.awaitingHandover)return;let n=watchRunEnd(t.sourceRunId);e.whenHandoverSettled().then(()=>n.stop()),n.ended.then(()=>e.abandonHandover(t.attemptKey))})}export{abandonHandoverIfRunEnds,watchRunEnd};
@@ -1,10 +1,24 @@
1
- /** Workflow-body handle that targets a durable deadline at the stable command inbox. */
1
+ /**
2
+ * Workflow-body handle for one owner's idle timeout. Activity moves the
3
+ * deadline only in memory; when the durable timer fires before the session
4
+ * has been idle for the whole window, the owner re-arms it for the new
5
+ * deadline. An active session therefore costs one timer per window, not one
6
+ * per turn.
7
+ */
2
8
  export interface SessionTimeoutControl {
3
9
  dispose(): Promise<void>;
10
+ /**
11
+ * Answers this owner's elapsed timer: `expired` once the session has been
12
+ * idle for the whole window, otherwise `extended` after arming a timer for
13
+ * the deadline that the latest activity set.
14
+ */
15
+ handleTimerElapsed(): Promise<"expired" | "extended">;
16
+ /** Restarts the idle window from now. */
17
+ recordActivity(): void;
4
18
  start(): Promise<void>;
5
19
  }
6
- /** Creates a timer controller for one stable session command inbox. */
20
+ /** Creates the idle timeout for one owner run, or `undefined` when timeouts are disabled. */
7
21
  export declare function createSessionTimeoutControl(input: {
8
- readonly deadline: Date;
9
22
  readonly sessionId: string;
10
- }): SessionTimeoutControl;
23
+ readonly timeoutMs: number | false;
24
+ }): SessionTimeoutControl | undefined;
@@ -1 +1 @@
1
- import{sessionCommandHookToken}from"#execution/session-inbox/address.js";import{getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{cancelSessionTimeoutStep,startSessionTimeoutStep}from"#execution/session/timeout-steps.js";function createSessionTimeoutControl(e){let t,n;return{async dispose(){try{await n}catch{}if(t===void 0)return;let e=t;t=void 0,await cancelSessionTimeoutStep({runId:e.runId})},async start(){n??=(async()=>{t=await startSessionTimeoutStep({deadline:e.deadline,ownerRunId:getWorkflowMetadata().workflowRunId,token:sessionCommandHookToken(e.sessionId)})})(),await n}}}export{createSessionTimeoutControl};
1
+ import{sessionCommandHookToken}from"#execution/session-inbox/address.js";import{getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{cancelSessionTimeoutStep,startSessionTimeoutStep}from"#execution/session/timeout-steps.js";function createSessionTimeoutControl(e){let{sessionId:t,timeoutMs:n}=e;if(n===!1)return;let r=Date.now(),i,a,arm=async()=>{a??=(async()=>{i=await startSessionTimeoutStep({deadline:new Date(r+n),ownerRunId:getWorkflowMetadata().workflowRunId,token:sessionCommandHookToken(t)})})(),await a};return{async dispose(){try{await a}catch{}if(i===void 0)return;let e=i;i=void 0,await cancelSessionTimeoutStep({runId:e.runId})},async handleTimerElapsed(){return Date.now()>=r+n?`expired`:(i=void 0,a=void 0,await arm(),`extended`)},recordActivity(){r=Date.now()},start:arm}}export{createSessionTimeoutControl};
@@ -1,3 +1,2 @@
1
- /** Default lifetime from creation or the latest successful ownership handoff. */
1
+ /** Default time a session may sit idle before it completes. */
2
2
  export declare const DEFAULT_SESSION_TIMEOUT_MS: number;
3
- export declare function sessionTimeoutDeadline(timeoutMs: number | false, startedAtMs: number): Date | undefined;
@@ -1 +1 @@
1
- const DEFAULT_SESSION_TIMEOUT_MS=2592e6;function sessionTimeoutDeadline(e,t){return e===!1?void 0:new Date(t+e)}export{DEFAULT_SESSION_TIMEOUT_MS,sessionTimeoutDeadline};
1
+ const DEFAULT_SESSION_TIMEOUT_MS=2592e6;export{DEFAULT_SESSION_TIMEOUT_MS};