eve 0.76.3 → 0.78.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 (209) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/src/channel/adapter.d.ts +13 -4
  3. package/dist/src/channel/channel-address.js +1 -1
  4. package/dist/src/channel/send-input.d.ts +6 -2
  5. package/dist/src/channel/send-input.js +1 -1
  6. package/dist/src/channel/session.js +1 -1
  7. package/dist/src/chunks/{use-eve-agent-BtKWTEpm.js → use-eve-agent-B8brxCk-.js} +46 -28
  8. package/dist/src/chunks/{use-eve-agent-jI6EsYAu.js → use-eve-agent-BSYe_Re7.js} +46 -28
  9. package/dist/src/cli/commands/vercel-non-interactive.d.ts +5 -3
  10. package/dist/src/cli/commands/vercel-non-interactive.js +1 -1
  11. package/dist/src/client/eve-agent-store.d.ts +2 -2
  12. package/dist/src/client/message-response.d.ts +2 -0
  13. package/dist/src/client/message-response.js +1 -1
  14. package/dist/src/client/session.js +1 -1
  15. package/dist/src/compiled/.vendor-stamp.json +9 -9
  16. package/dist/src/compiled/@ai-sdk/anthropic/index.d.ts +6 -1
  17. package/dist/src/compiled/@ai-sdk/anthropic/index.js +1 -1
  18. package/dist/src/compiled/@ai-sdk/google/index.d.ts +16 -3
  19. package/dist/src/compiled/@ai-sdk/google/index.js +6 -6
  20. package/dist/src/compiled/@ai-sdk/mcp/index.d.ts +681 -348
  21. package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
  22. package/dist/src/compiled/@ai-sdk/openai/index.d.ts +56 -42
  23. package/dist/src/compiled/@ai-sdk/openai/index.js +5 -3
  24. package/dist/src/compiled/@ai-sdk/otel/index.js +3 -3
  25. package/dist/src/compiled/@ai-sdk/provider/index.d.ts +49 -15
  26. package/dist/src/compiled/@ai-sdk/provider/index.js +1 -1
  27. package/dist/src/compiled/@ai-sdk/provider-utils/index.d.ts +4 -1
  28. package/dist/src/compiled/_chunks/workflow/{dist-DXLdlucM.js → dist-C8k3N3BQ.js} +2 -4
  29. package/dist/src/compiled/_chunks/workflow/dist-DsNhwdzf.js +1 -0
  30. package/dist/src/compiled/_chunks/workflow/experimental-decision-DlvnsBD-.js +3 -0
  31. package/dist/src/compiler/extension-compatibility.d.ts +18 -18
  32. package/dist/src/compiler/extension-compatibility.js +1 -1
  33. package/dist/src/compiler/normalize-agent-config.js +1 -1
  34. package/dist/src/context/dynamic-model-lifecycle.js +1 -1
  35. package/dist/src/context/keys.d.ts +16 -0
  36. package/dist/src/context/keys.js +1 -1
  37. package/dist/src/evals/judge.js +1 -1
  38. package/dist/src/eve-channel/index.js +1 -1
  39. package/dist/src/eve-channel/types.d.ts +14 -1
  40. package/dist/src/execution/agent-sessions/steps.d.ts +2 -0
  41. package/dist/src/execution/agent-sessions/steps.js +1 -1
  42. package/dist/src/execution/cancelled-model-call-batch.js +1 -1
  43. package/dist/src/execution/catalog/connection-entry.js +1 -1
  44. package/dist/src/execution/catalog/search.js +1 -1
  45. package/dist/src/execution/catalog/step-catalog.d.ts +12 -3
  46. package/dist/src/execution/catalog/step-catalog.js +1 -1
  47. package/dist/src/execution/coordination-dispatch-shared.d.ts +1 -2
  48. package/dist/src/execution/coordination-dispatch-shared.js +1 -1
  49. package/dist/src/execution/coordination-dispatch-step.js +1 -1
  50. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  51. package/dist/src/execution/publish-session-events.js +1 -1
  52. package/dist/src/execution/sandbox/bindings/docker-container.js +1 -1
  53. package/dist/src/execution/sandbox/bindings/docker.js +1 -1
  54. package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
  55. package/dist/src/execution/sandbox/bindings/just-bash.d.ts +1 -1
  56. package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
  57. package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
  58. package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
  59. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  60. package/dist/src/execution/sandbox/read-file.d.ts +5 -5
  61. package/dist/src/execution/sandbox/read-file.js +2 -2
  62. package/dist/src/execution/sandbox/session.d.ts +6 -0
  63. package/dist/src/execution/sandbox/session.js +2 -2
  64. package/dist/src/execution/session/active-turn.d.ts +9 -1
  65. package/dist/src/execution/session/active-turn.js +1 -1
  66. package/dist/src/execution/session/checkpoint-migrations.js +1 -1
  67. package/dist/src/execution/session/end-sandbox-step.js +1 -1
  68. package/dist/src/execution/session/handoff.d.ts +1 -1
  69. package/dist/src/execution/session/handoff.js +1 -1
  70. package/dist/src/execution/session/next-input.js +1 -1
  71. package/dist/src/execution/session/turn-step.js +1 -1
  72. package/dist/src/execution/session/turn.d.ts +11 -4
  73. package/dist/src/execution/session/turn.js +1 -1
  74. package/dist/src/execution/session-inbox/inbox.d.ts +3 -0
  75. package/dist/src/execution/session-inbox/inbox.js +1 -1
  76. package/dist/src/execution/session-workflow-tool-run.d.ts +14 -12
  77. package/dist/src/execution/session-workflow-tool-run.js +1 -1
  78. package/dist/src/execution/tasks/start.d.ts +14 -1
  79. package/dist/src/execution/tasks/start.js +1 -1
  80. package/dist/src/execution/tasks/steps.d.ts +7 -4
  81. package/dist/src/execution/tasks/steps.js +1 -1
  82. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  83. package/dist/src/execution/tools/workflow/apply-run-messages-step.d.ts +20 -0
  84. package/dist/src/execution/tools/workflow/apply-run-messages-step.js +1 -0
  85. package/dist/src/execution/tools/workflow/ask.d.ts +0 -1
  86. package/dist/src/execution/tools/workflow/ask.js +1 -1
  87. package/dist/src/execution/tools/workflow/interrupt.d.ts +5 -2
  88. package/dist/src/execution/tools/workflow/interrupt.js +1 -1
  89. package/dist/src/execution/tools/workflow/messages.d.ts +14 -0
  90. package/dist/src/execution/tools/workflow/messages.js +1 -1
  91. package/dist/src/execution/tools/workflow/owner.d.ts +18 -6
  92. package/dist/src/execution/tools/workflow/owner.js +1 -1
  93. package/dist/src/execution/tools/workflow/start.d.ts +10 -0
  94. package/dist/src/execution/tools/workflow/start.js +1 -1
  95. package/dist/src/execution/tools/workflow/step.js +1 -1
  96. package/dist/src/execution/tools/workflow/workflow-owner-blocking.d.ts +12 -0
  97. package/dist/src/execution/tools/workflow/workflow-owner-blocking.js +1 -1
  98. package/dist/src/execution/tools/workflow/workflow.js +1 -1
  99. package/dist/src/execution/web-fetch/request.js +1 -1
  100. package/dist/src/execution/workflow-runtime.d.ts +18 -3
  101. package/dist/src/execution/workflow-runtime.js +1 -1
  102. package/dist/src/harness/attachment-staging.d.ts +13 -12
  103. package/dist/src/harness/attachment-staging.js +1 -1
  104. package/dist/src/harness/compaction/step.js +1 -1
  105. package/dist/src/harness/emission.js +1 -1
  106. package/dist/src/harness/hitl/approvals.d.ts +4 -7
  107. package/dist/src/harness/hitl/approvals.js +1 -1
  108. package/dist/src/harness/hitl/approved-calls.d.ts +11 -0
  109. package/dist/src/harness/hitl/approved-calls.js +1 -1
  110. package/dist/src/harness/hitl/candidates.d.ts +0 -4
  111. package/dist/src/harness/hitl/candidates.js +1 -1
  112. package/dist/src/harness/hitl/delivery.d.ts +0 -1
  113. package/dist/src/harness/hitl/delivery.js +1 -1
  114. package/dist/src/harness/hitl/index.d.ts +2 -2
  115. package/dist/src/harness/hitl/index.js +1 -1
  116. package/dist/src/harness/hitl/intake.d.ts +2 -2
  117. package/dist/src/harness/hitl/intake.js +1 -1
  118. package/dist/src/harness/model-call/call.js +1 -1
  119. package/dist/src/harness/model-call/errors.d.ts +10 -0
  120. package/dist/src/harness/model-call/errors.js +1 -1
  121. package/dist/src/harness/model-call/run.js +1 -1
  122. package/dist/src/harness/session-machine/state.d.ts +0 -2
  123. package/dist/src/harness/session-machine/transitions.js +1 -1
  124. package/dist/src/harness/session-machine/view.d.ts +0 -3
  125. package/dist/src/harness/session-machine/view.js +1 -1
  126. package/dist/src/harness/step/after-model.js +1 -1
  127. package/dist/src/harness/token-estimate.js +1 -1
  128. package/dist/src/harness/tool-loop.js +1 -1
  129. package/dist/src/harness/tools.js +1 -1
  130. package/dist/src/internal/application/package.js +1 -1
  131. package/dist/src/internal/application/stamped-package-version.js +1 -1
  132. package/dist/src/internal/attachments/data.d.ts +29 -10
  133. package/dist/src/internal/attachments/data.js +1 -1
  134. package/dist/src/internal/attachments/errors.d.ts +2 -2
  135. package/dist/src/internal/attachments/media-metadata.d.ts +15 -0
  136. package/dist/src/internal/attachments/media-metadata.js +1 -1
  137. package/dist/src/internal/attachments/public-link.d.ts +5 -0
  138. package/dist/src/internal/attachments/public-link.js +1 -0
  139. package/dist/src/internal/attachments/sandbox-refs.d.ts +7 -6
  140. package/dist/src/internal/attachments/sandbox-refs.js +1 -1
  141. package/dist/src/internal/attachments/url-refs.js +1 -1
  142. package/dist/src/protocol/message.d.ts +7 -0
  143. package/dist/src/protocol/message.js +2 -2
  144. package/dist/src/public/channels/attachment-error.d.ts +14 -0
  145. package/dist/src/public/channels/attachment-error.js +1 -0
  146. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +1 -1
  147. package/dist/src/public/channels/discord/defaults.js +1 -1
  148. package/dist/src/public/channels/github/defaults.js +1 -1
  149. package/dist/src/public/channels/index.d.ts +2 -0
  150. package/dist/src/public/channels/index.js +1 -1
  151. package/dist/src/public/channels/linear/defaults.js +1 -1
  152. package/dist/src/public/channels/slack/api.d.ts +10 -0
  153. package/dist/src/public/channels/slack/api.js +1 -1
  154. package/dist/src/public/channels/slack/approval-cards.js +1 -1
  155. package/dist/src/public/channels/slack/attachments.d.ts +29 -19
  156. package/dist/src/public/channels/slack/attachments.js +1 -1
  157. package/dist/src/public/channels/slack/defaults.js +1 -1
  158. package/dist/src/public/channels/slack/inbound.d.ts +6 -0
  159. package/dist/src/public/channels/slack/inbound.js +1 -1
  160. package/dist/src/public/channels/slack/interaction-cards.d.ts +6 -0
  161. package/dist/src/public/channels/slack/interaction-cards.js +1 -1
  162. package/dist/src/public/channels/slack/interactions.js +1 -1
  163. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  164. package/dist/src/public/channels/teams/defaults.js +1 -1
  165. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  166. package/dist/src/public/channels/telegram/defaults.js +1 -1
  167. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  168. package/dist/src/public/channels/twilio/defaults.js +1 -1
  169. package/dist/src/public/definitions/channel.js +1 -1
  170. package/dist/src/runtime/channels/registry.js +1 -1
  171. package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
  172. package/dist/src/setup/scaffold/create/project.js +2 -2
  173. package/dist/src/setup/scaffold/update/web-options.js +1 -1
  174. package/dist/src/shared/agent-definition.d.ts +2 -1
  175. package/dist/src/shared/channel-definition.d.ts +16 -4
  176. package/dist/src/svelte/index.d.ts +0 -1
  177. package/dist/src/svelte/index.js +1 -1
  178. package/dist/src/svelte/use-eve-agent.js +1 -1
  179. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  180. package/dist/src/tools/provided/read-file.d.ts +3 -2
  181. package/dist/src/tools/provided/read-file.js +2 -2
  182. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  183. package/dist/src/vue/index.d.ts +0 -1
  184. package/dist/src/vue/index.js +1 -1
  185. package/dist/src/vue/use-eve-agent.js +1 -1
  186. package/docs/agent-config.md +12 -4
  187. package/docs/channels/chat-sdk.mdx +1 -1
  188. package/docs/channels/custom.mdx +30 -3
  189. package/docs/channels/eve.mdx +34 -0
  190. package/docs/channels/slack.mdx +5 -1
  191. package/docs/concepts/built-in-tools.md +10 -10
  192. package/docs/concepts/sessions-runs-and-streaming.md +2 -2
  193. package/docs/evals/overview.mdx +1 -1
  194. package/docs/guides/client/streaming.mdx +1 -1
  195. package/docs/guides/dynamic-capabilities.md +6 -2
  196. package/docs/memory/custom-provider.md +3 -1
  197. package/docs/sandbox/index.mdx +10 -4
  198. package/docs/tools/human-in-the-loop.md +1 -1
  199. package/docs/tools/overview.mdx +1 -1
  200. package/package.json +11 -11
  201. package/dist/src/compiled/_chunks/workflow/experimental-decision-BrfWf6-n.js +0 -3
  202. package/dist/src/context/caller-scope.d.ts +0 -7
  203. package/dist/src/context/caller-scope.js +0 -1
  204. package/dist/src/execution/tools/workflow/emit-workflow-tool-run-report-step.d.ts +0 -13
  205. package/dist/src/execution/tools/workflow/emit-workflow-tool-run-report-step.js +0 -1
  206. package/dist/src/harness/hitl/approved-call-callers.d.ts +0 -14
  207. package/dist/src/harness/hitl/approved-call-callers.js +0 -1
  208. package/dist/src/internal/attachments/refs.d.ts +0 -55
  209. package/dist/src/internal/attachments/refs.js +0 -1
@@ -21,6 +21,8 @@ export interface SessionInboxReader {
21
21
  next(): Promise<SessionInboxPayload | undefined>;
22
22
  /** Removes every payload accepted so far, in arrival order. */
23
23
  drain(): SessionInboxPayload[];
24
+ /** Removes the payloads at the front of the queue that `accepts` takes, stopping at the first it doesn't. */
25
+ takeLeading<T extends SessionInboxPayload>(accepts: (payload: SessionInboxPayload) => payload is T): T[];
24
26
  hasPending(): boolean;
25
27
  /** Resolves once a payload is ready or the inbox closes, without consuming anything. */
26
28
  whenPending(): Promise<void>;
@@ -33,6 +35,7 @@ export interface SessionInboxReader {
33
35
  onInterrupt(handler: (payload: SessionInboxPayload) => void): () => void;
34
36
  /** Observes deliveries without consuming them; replays unread deliveries on subscription. */
35
37
  onDelivery(handler: (payload: SessionInboxPayload) => void): () => void;
38
+ /** Requeues payloads a successor handed back, ahead of everything pumped since. */
36
39
  restore(payloads: readonly SessionInboxPayload[]): void;
37
40
  }
38
41
  export interface SessionInboxOwnership {
@@ -1 +1 @@
1
- import{sessionInboxHookToken}from"#execution/session-inbox/address.js";import{createHook,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{claimHookOwnership,disposeHook}from"#execution/hook-ownership.js";import{releaseSessionHooksStep}from"#execution/session-inbox/release-step.js";function isInterrupt(e){return e.kind===`cancel`||e.kind===`reset`||e.kind===`session-timeout`||e.kind===`session-failure`}function createSessionInbox(e){let t=[],n=[],r=new Set,i=new Set,a=new Set,o,notify=()=>{for(let e of r)e();r.clear()},wait=()=>new Promise(e=>r.add(e)),closed=()=>t.every(e=>e.closed||e.stopping),pump=async e=>{let t=e.hook[Symbol.asyncIterator]();try{for(;!e.stopping;){let e=await t.next();if(e.done)break;if(n.push(e.value),e.value.kind===`send`||e.value.kind===`deliver`)for(let t of a)t(e.value);if(isInterrupt(e.value))for(let t of i)t(e.value);notify()}}catch(t){e.stopping||(o={error:t})}finally{e.closed=!0,notify()}},stop=async()=>{let e=t.splice(0);for(let t of e)t.stopping=!0;notify(),await Promise.all(e.map(({hook:e})=>disposeHook(e)));let r=n.splice(0);return notify(),r},claimSessionHook=async n=>{if(!n)throw Error(`A session alias requires a nonempty continuation token.`);let r=t.find(e=>e.token===n);if(r!==void 0)return await r.registered;if(t.length>=256)throw Error(`A session may claim at most 256 addresses.`);let i={token:n,hook:createHook({token:sessionInboxHookToken(n),metadata:{sessionId:e}}),stopping:!1,closed:!1};t.push(i);try{i.registered=claimHookOwnership(i.hook),await i.registered,pump(i)}catch(e){throw t.splice(t.indexOf(i),1),e}};return{get claimedTokens(){return t.map(({token:e})=>e)},claimSessionHook,async claimSessionHooks(e){let t=await Promise.allSettled([...new Set(e)].map(claimSessionHook));for(let e of t)if(e.status===`rejected`)throw e.reason},async next(){for(;;){if(o!==void 0)throw o.error;if(n.length>0)return n.shift();if(closed())return;await wait()}},drain(){if(o!==void 0)throw o.error;return n.splice(0)},hasPending(){if(o!==void 0)throw o.error;return n.length>0},async whenPending(){for(;o===void 0&&n.length===0&&!closed();)await wait()},onInterrupt(e){return i.add(e),()=>i.delete(e)},onDelivery(e){a.add(e);for(let t of n)(t.kind===`send`||t.kind===`deliver`)&&e(t);return()=>a.delete(e)},restore(e){if(t.length===0)throw Error(`Cannot restore session commands before reclaiming the session hooks.`);n.unshift(...e),notify()},async dispose(){await stop()},async release(){return t.length>0&&await releaseSessionHooksStep({ownerRunId:getWorkflowMetadata().workflowRunId,tokens:t.map(({hook:e})=>e.token)}),await stop()}}}function isWorkflowMessage(e){return e.kind===`agent-started`||e.kind===`started`||e.kind===`report`||e.kind===`reply`||e.kind===`request`||e.kind===`withdraw`||e.kind===`usage`||e.kind===`outcome`}export{createSessionInbox,isInterrupt,isWorkflowMessage};
1
+ import{sessionInboxHookToken}from"#execution/session-inbox/address.js";import{createHook,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{claimHookOwnership,disposeHook}from"#execution/hook-ownership.js";import{releaseSessionHooksStep}from"#execution/session-inbox/release-step.js";function isInterrupt(e){return e.kind===`cancel`||e.kind===`reset`||e.kind===`session-timeout`||e.kind===`session-failure`}function createSessionInbox(e){let t=[],n=[],r=new Set,i=new Set,a=new Set,o,notify=()=>{for(let e of r)e();r.clear()},wait=()=>new Promise(e=>r.add(e)),closed=()=>t.every(e=>e.closed||e.stopping),pump=async e=>{let t=e.hook[Symbol.asyncIterator]();try{for(;!e.stopping;){let e=await t.next();if(e.done)break;let r=e.value;if(r.kind===`workflow-batch`){n.push(...r.messages),notify();continue}if(n.push(r),r.kind===`send`||r.kind===`deliver`)for(let e of a)e(r);if(isInterrupt(r))for(let e of i)e(r);notify()}}catch(t){e.stopping||(o={error:t})}finally{e.closed=!0,notify()}},stop=async()=>{let e=t.splice(0);for(let t of e)t.stopping=!0;notify(),await Promise.all(e.map(({hook:e})=>disposeHook(e)));let r=n.splice(0);return notify(),r},claimSessionHook=async n=>{if(!n)throw Error(`A session alias requires a nonempty continuation token.`);let r=t.find(e=>e.token===n);if(r!==void 0)return await r.registered;if(t.length>=256)throw Error(`A session may claim at most 256 addresses.`);let i={token:n,hook:createHook({token:sessionInboxHookToken(n),metadata:{sessionId:e}}),stopping:!1,closed:!1};t.push(i);try{i.registered=claimHookOwnership(i.hook),await i.registered,pump(i)}catch(e){throw t.splice(t.indexOf(i),1),e}};return{get claimedTokens(){return t.map(({token:e})=>e)},claimSessionHook,async claimSessionHooks(e){let t=await Promise.allSettled([...new Set(e)].map(claimSessionHook));for(let e of t)if(e.status===`rejected`)throw e.reason},async next(){for(;;){if(o!==void 0)throw o.error;if(n.length>0)return n.shift();if(closed())return;await wait()}},drain(){if(o!==void 0)throw o.error;return n.splice(0)},takeLeading(e){if(o!==void 0)throw o.error;let t=[];for(let r=n[0];r!==void 0&&e(r);r=n[0])t.push(r),n.shift();return t},hasPending(){if(o!==void 0)throw o.error;return n.length>0},async whenPending(){for(;o===void 0&&n.length===0&&!closed();)await wait()},onInterrupt(e){return i.add(e),()=>i.delete(e)},onDelivery(e){a.add(e);for(let t of n)(t.kind===`send`||t.kind===`deliver`)&&e(t);return()=>a.delete(e)},restore(e){if(t.length===0)throw Error(`Cannot restore session commands before reclaiming the session hooks.`);n.unshift(...e),notify()},async dispose(){await stop()},async release(){return t.length>0&&await releaseSessionHooksStep({ownerRunId:getWorkflowMetadata().workflowRunId,tokens:t.map(({hook:e})=>e.token)}),await stop()}}}function isWorkflowMessage(e){return e.kind===`agent-started`||e.kind===`started`||e.kind===`report`||e.kind===`reply`||e.kind===`request`||e.kind===`withdraw`||e.kind===`usage`||e.kind===`outcome`}export{createSessionInbox,isInterrupt,isWorkflowMessage};
@@ -1,19 +1,21 @@
1
- import type { WorkflowToolRunAgentStartedMessage, WorkflowToolRunMessage } from "#execution/tools/workflow/messages.js";
1
+ import type { AppliedRunMessage } from "#execution/tools/workflow/apply-run-messages-step.js";
2
+ import { type WorkflowToolRunMessage } from "#execution/tools/workflow/messages.js";
2
3
  import type { SessionStateCursor } from "#execution/session/state-cursor.js";
4
+ import { type SessionInboxReader } from "#execution/session-inbox/inbox.js";
3
5
  import type { RuntimeActionResult } from "#shared/action-types.js";
4
6
  interface HandlerInput<T> {
5
7
  readonly cursor: SessionStateCursor;
6
8
  readonly message: T;
7
9
  }
8
- export declare function handleWorkflowToolRunMessage(input: HandlerInput<WorkflowToolRunMessage>): Promise<RuntimeActionResult | undefined>;
9
- /** Boundary messages in admission order, with consecutive `agent-started` messages grouped. */
10
- type BoundaryBatch = {
11
- readonly kind: "agent-started";
12
- readonly messages: WorkflowToolRunAgentStartedMessage[];
13
- } | {
14
- readonly kind: "message";
15
- readonly message: WorkflowToolRunMessage;
16
- };
17
- /** Groups consecutive `agent-started` messages so one `emitAgentStartedStep` publishes each group. */
18
- export declare function batchAgentStarts(messages: readonly WorkflowToolRunMessage[]): BoundaryBatch[];
10
+ export declare function isAppliedRunMessage(message: WorkflowToolRunMessage): message is AppliedRunMessage;
11
+ /**
12
+ * Removes the applied run messages at the front of the inbox, in arrival
13
+ * order, while `admits` takes them. One batch's caller passes its budget on.
14
+ */
15
+ export declare function takeLeadingAppliedRunMessages(inbox: SessionInboxReader, admits?: (message: WorkflowToolRunMessage) => boolean): AppliedRunMessage[];
16
+ /**
17
+ * Handles a run message the session does not apply as it reads it: a
18
+ * question, its withdrawal, or an `execute` run's outcome.
19
+ */
20
+ export declare function handleWorkflowToolRunMessage(input: HandlerInput<Exclude<WorkflowToolRunMessage, AppliedRunMessage>>): Promise<RuntimeActionResult | undefined>;
19
21
  export {};
@@ -1 +1 @@
1
- import{findBlockingWorkflowToolRun,isInboxToolResultFromRecordedWorkflowToolRun}from"#harness/workflow-tool-runs.js";import{emitAgentStartedStep,emitWorkflowToolRunReportStep}from"#execution/tools/workflow/emit-workflow-tool-run-report-step.js";import{deliverWorkflowAuthorization}from"#execution/tools/workflow/owner.js";import{withdrawFinishedRunQuestionsStep,withdrawWorkflowToolRunQuestionStep}from"#execution/tools/workflow/withdraw-step.js";import{workflowToolRunOutcomeToToolResult,workflowToolRunRequestToInputRequestPayload}from"#execution/tools/workflow/owner-inbox.js";import{runProxySubagentEventStep}from"#subagents/event-proxy-step.js";async function handleWorkflowToolRunMessage(e){let{message:t}=e;switch(t.kind){case`started`:case`reply`:case`usage`:return;case`outcome`:return await handleWorkflowToolRunOutcome({...e,message:t});case`request`:await handleWorkflowToolRunRequest({...e,message:t});return;case`withdraw`:await handleWorkflowToolRunWithdraw({...e,message:t});return;case`report`:await e.cursor.advance(e=>emitWorkflowToolRunReportStep({...e,from:t.from,update:t.update}));return;case`agent-started`:await e.cursor.advance(e=>emitAgentStartedStep({...e,messages:[t]}));return}}function batchAgentStarts(e){let t=[];for(let n of e){let e=t.at(-1);n.kind===`agent-started`?e?.kind===`agent-started`?e.messages.push(n):t.push({kind:`agent-started`,messages:[n]}):t.push({kind:`message`,message:n})}return t}async function handleWorkflowToolRunOutcome(e){let{cursor:t,message:n}=e,r=t.sessionState.snapshot.session.state;if(findBlockingWorkflowToolRun(r,n.from.callId,n.from.turnId)?.address.runId!==n.from.runId)return;let i=workflowToolRunOutcomeToToolResult(n);if(isInboxToolResultFromRecordedWorkflowToolRun(r,i)){if(t.sessionState.hasProxyInputRequests){let{runId:e}=n.from;await t.advance(t=>withdrawFinishedRunQuestionsStep({...t,runId:e}))}return i}}async function handleWorkflowToolRunRequest(e){let{cursor:t,message:n}=e;if(n.request.kind===`authorization-request`){let e=n.request;await deliverWorkflowAuthorization({...n,request:e},async()=>{await t.advance(t=>runProxySubagentEventStep({hookPayload:e.event,...t}))});return}await t.advance(e=>runProxySubagentEventStep({...n.request.kind===`ask`&&{workflowAsk:createWorkflowAskRoute(n.request)},hookPayload:workflowToolRunRequestToInputRequestPayload(n),runId:n.from.runId,...e}))}async function handleWorkflowToolRunWithdraw(e){let{cursor:t,message:n}=e;await t.advance(e=>withdrawWorkflowToolRunQuestionStep({...e,control:n.control,requestId:n.replyTo,runId:n.from.runId}))}function createWorkflowAskRoute(e){return{control:e.control}}export{batchAgentStarts,handleWorkflowToolRunMessage};
1
+ import{findBlockingWorkflowToolRun,isInboxToolResultFromRecordedWorkflowToolRun}from"#harness/workflow-tool-runs.js";import{isWorkflowMessage}from"#execution/session-inbox/inbox.js";import{runMessageBatchBudget}from"#execution/tools/workflow/messages.js";import{isTaskRunMessage}from"#execution/tasks/session.js";import{deliverWorkflowAuthorization}from"#execution/tools/workflow/owner.js";import{withdrawFinishedRunQuestionsStep,withdrawWorkflowToolRunQuestionStep}from"#execution/tools/workflow/withdraw-step.js";import{workflowToolRunOutcomeToToolResult,workflowToolRunRequestToInputRequestPayload}from"#execution/tools/workflow/owner-inbox.js";import{runProxySubagentEventStep}from"#subagents/event-proxy-step.js";function isAppliedRunMessage(e){return e.kind===`agent-started`||e.kind===`report`||isTaskRunMessage(e)}function takeLeadingAppliedRunMessages(e,t=runMessageBatchBudget()){return e.takeLeading(e=>isWorkflowMessage(e)&&isAppliedRunMessage(e)&&t(e))}async function handleWorkflowToolRunMessage(e){let{message:t}=e;switch(t.kind){case`started`:case`reply`:case`usage`:return;case`outcome`:return await handleWorkflowToolRunOutcome({...e,message:t});case`request`:await handleWorkflowToolRunRequest({...e,message:t});return;case`withdraw`:await handleWorkflowToolRunWithdraw({...e,message:t});return}}async function handleWorkflowToolRunOutcome(e){let{cursor:t,message:n}=e,r=t.sessionState.snapshot.session.state;if(findBlockingWorkflowToolRun(r,n.from.callId,n.from.turnId)?.address.runId!==n.from.runId)return;let i=workflowToolRunOutcomeToToolResult(n);if(isInboxToolResultFromRecordedWorkflowToolRun(r,i)){if(t.sessionState.hasProxyInputRequests){let{runId:e}=n.from;await t.advance(t=>withdrawFinishedRunQuestionsStep({...t,runId:e}))}return i}}async function handleWorkflowToolRunRequest(e){let{cursor:t,message:n}=e;if(n.request.kind===`authorization-request`){let e=n.request;await deliverWorkflowAuthorization({...n,request:e},async()=>{await t.advance(t=>runProxySubagentEventStep({hookPayload:e.event,...t}))});return}await t.advance(e=>runProxySubagentEventStep({...n.request.kind===`ask`&&{workflowAsk:createWorkflowAskRoute(n.request)},hookPayload:workflowToolRunRequestToInputRequestPayload(n),runId:n.from.runId,...e}))}async function handleWorkflowToolRunWithdraw(e){let{cursor:t,message:n}=e;await t.advance(e=>withdrawWorkflowToolRunQuestionStep({...e,control:n.control,requestId:n.replyTo,runId:n.from.runId}))}function createWorkflowAskRoute(e){return{control:e.control}}export{handleWorkflowToolRunMessage,isAppliedRunMessage,takeLeadingAppliedRunMessages};
@@ -1,7 +1,8 @@
1
+ import { type TaskTable } from "#execution/tasks/table.js";
1
2
  import { type StartWorkflowTaskInput } from "#execution/tools/workflow/start.js";
2
3
  import type { HarnessSessionBase } from "#harness/types.js";
3
4
  import type { TaskStartedStreamEvent } from "#protocol/message.js";
4
- import type { RuntimeToolResultActionResult, WorkflowToolRunEntry } from "#shared/action-types.js";
5
+ import type { RuntimeToolResultActionResult, RuntimeWorkflowTaskRequest, WorkflowToolRunEntry } from "#shared/action-types.js";
5
6
  type TaskDispatchInput = StartWorkflowTaskInput & {
6
7
  readonly taskId: string;
7
8
  };
@@ -31,4 +32,16 @@ export declare function startTaskRun(input: StartWorkflowTaskInput & {
31
32
  * to the task's run, whose body receives it from `receive()`.
32
33
  */
33
34
  export declare function sendToTask(input: TaskDispatchInput): Promise<TaskDispatchResult>;
35
+ /**
36
+ * The entry of the run that dispatching `task` starts, or `undefined` when it
37
+ * starts none: a call to a running task, or a task cancelled before the
38
+ * session could start it. The task cap can still refuse a task's run.
39
+ */
40
+ export declare function runEntryToStart(table: TaskTable, task: RuntimeWorkflowTaskRequest): WorkflowToolRunEntry | undefined;
41
+ /**
42
+ * Whether dispatching `tasks` in order starts every run {@link runEntryToStart}
43
+ * names. A call to a running task can take a slot under the task cap, and
44
+ * sending to it can fail the batch, so such a batch never qualifies.
45
+ */
46
+ export declare function startsEveryRun(table: TaskTable, tasks: readonly RuntimeWorkflowTaskRequest[]): boolean;
34
47
  export {};
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{TOO_MANY_TASKS_CODE,UNKNOWN_TASK_CODE}from"#protocol/task-tools.js";import{renderTaskReceipt,renderTaskSentReceipt,renderTooManyTasksError,renderUnknownTaskError}from"#execution/tasks/render.js";import{MAX_WORKING_TASKS,findTask,isTaskAvailable,isTaskWorking,readTaskTable,recordTaskCall,recordTaskRun,removeTask,workingTasks,writeTaskTable}from"#execution/tasks/table.js";import{startFailureResult,startWorkflowToolCallRun}from"#execution/tools/workflow/start.js";import{sendTaskRunCommands}from"#execution/tasks/steps.js";import{createRuntimeToolResultFromValue}from"#harness/action-result-helpers.js";const log=createLogger(`execution.tasks`);async function startTaskRun(e){let{entry:t,session:n,task:r}=e,{taskId:i}=t,a={...e,taskId:i},o=startReceipt(a,t.entryPoint===`serve`),s=readTaskTable(n.state),c=findTask(s,i);if(c===void 0||!isTaskWorking(c))return{result:o,session:n};let l=tooManyTasks(a,s);if(l!==void 0)return{result:l,session:writeTaskTable(n,removeTask(s,i))};let u;try{u=await startWorkflowToolCallRun(e,t)}catch(e){return logError(log,`task run failed to start`,e,{taskId:i,toolName:r.toolName}),{result:startFailureResult(r,e),session:writeTaskTable(n,removeTask(s,i))}}return{result:o,session:writeTaskTable(n,recordTaskRun(s,i,u)),started:taskStartedEvent(a,c)}}async function sendToTask(e){let{session:t,task:n,taskId:r}=e,i=readTaskTable(t.state),a=findTask(i,r);if(!isTaskAvailable(a,n.toolName))return{result:unknownTaskResult(e),session:t};if(!isTaskWorking(a)){let n=tooManyTasks(e,i);if(n!==void 0)return{result:n,session:t}}let o=recordTaskCall(i,r,{agentContext:e.agentContext,auth:e.auth,callId:n.callId,executeInput:n.executeInput,input:n.input,sequence:e.batchEvent.sequence,stepIndex:e.batchEvent.stepIndex,turnId:e.batchEvent.turnId});return o.send!==void 0&&await sendTaskRunCommands(o.send),{result:toolResult(e,renderTaskSentReceipt(r)),session:writeTaskTable(t,o.table),started:taskStartedEvent(e,a)}}function tooManyTasks(e,t){let n=workingTasks(t).filter(e=>e.run!==void 0);if(n.length<MAX_WORKING_TASKS)return;let r=n.map(e=>e.id);return createRuntimeToolResultFromValue({callId:e.task.callId,isError:!0,output:{code:TOO_MANY_TASKS_CODE,message:renderTooManyTasksError(MAX_WORKING_TASKS,r)},toolName:e.task.toolName})}function unknownTaskResult(e){return createRuntimeToolResultFromValue({callId:e.task.callId,isError:!0,output:{code:UNKNOWN_TASK_CODE,message:renderUnknownTaskError(e.taskId,e.task.toolName)},toolName:e.task.toolName})}function taskStartedEvent(e,t){return{callId:e.task.callId,kind:t.kind,name:e.task.toolName,taskId:e.taskId,turnId:e.batchEvent.turnId}}function startReceipt(e,t){return toolResult(e,renderTaskReceipt({id:e.taskId,resumable:t,tool:e.task.toolName}))}function toolResult(e,t){return createRuntimeToolResultFromValue({callId:e.task.callId,output:t,toolName:e.task.toolName})}export{sendToTask,startTaskRun};
1
+ import{createLogger,logError}from"#internal/logging.js";import{TOO_MANY_TASKS_CODE,UNKNOWN_TASK_CODE}from"#protocol/task-tools.js";import{renderTaskReceipt,renderTaskSentReceipt,renderTooManyTasksError,renderUnknownTaskError}from"#execution/tasks/render.js";import{MAX_WORKING_TASKS,findTask,isTaskAvailable,isTaskWorking,readTaskTable,recordTaskCall,recordTaskRun,removeTask,workingTasks,writeTaskTable}from"#execution/tasks/table.js";import{startFailureResult,startWorkflowToolCallRun}from"#execution/tools/workflow/start.js";import{sendTaskRunCommands}from"#execution/tasks/steps.js";import{createRuntimeToolResultFromValue}from"#harness/action-result-helpers.js";const log=createLogger(`execution.tasks`);async function startTaskRun(e){let{entry:t,session:n,task:r}=e,{taskId:i}=t,a={...e,taskId:i},o=startReceipt(a,t.entryPoint===`serve`),s=readTaskTable(n.state),c=startableTask(s,i);if(c===void 0)return{result:o,session:n};let l=tooManyTasks(a,s);if(l!==void 0)return{result:l,session:writeTaskTable(n,removeTask(s,i))};let u;try{u=await startWorkflowToolCallRun(e,t)}catch(e){return logError(log,`task run failed to start`,e,{taskId:i,toolName:r.toolName}),{result:startFailureResult(r,e),session:writeTaskTable(n,removeTask(s,i))}}return{result:o,session:writeTaskTable(n,recordTaskRun(s,i,u)),started:taskStartedEvent(a,c)}}async function sendToTask(e){let{session:t,task:n,taskId:r}=e,i=readTaskTable(t.state),a=findTask(i,r);if(!isTaskAvailable(a,n.toolName))return{result:unknownTaskResult(e),session:t};if(!isTaskWorking(a)){let n=tooManyTasks(e,i);if(n!==void 0)return{result:n,session:t}}let o=recordTaskCall(i,r,{agentContext:e.agentContext,auth:e.auth,callId:n.callId,executeInput:n.executeInput,input:n.input,sequence:e.batchEvent.sequence,stepIndex:e.batchEvent.stepIndex,turnId:e.batchEvent.turnId});return o.send!==void 0&&await sendTaskRunCommands(o.send),{result:toolResult(e,renderTaskSentReceipt(r)),session:writeTaskTable(t,o.table),started:taskStartedEvent(e,a)}}function runEntryToStart(e,t){let{entry:n}=t;switch(n.entryPoint){case`execute`:return{entryPoint:`execute`};case`task`:case`serve`:return startableTask(e,n.taskId)===void 0?void 0:n;case`receive`:return}}function startableTask(e,t){let n=findTask(e,t);return n!==void 0&&isTaskWorking(n)?n:void 0}function startsEveryRun(e,t){return!t.some(e=>e.entry.entryPoint===`receive`)&&hasTaskSlots(e,t.filter(t=>t.entry.entryPoint!==`execute`&&runEntryToStart(e,t)!==void 0).length)}function runningTasks(e){return workingTasks(e).filter(e=>e.run!==void 0)}function hasTaskSlots(e,t){return runningTasks(e).length+t<=MAX_WORKING_TASKS}function tooManyTasks(e,t){if(hasTaskSlots(t,1))return;let n=runningTasks(t).map(e=>e.id);return createRuntimeToolResultFromValue({callId:e.task.callId,isError:!0,output:{code:TOO_MANY_TASKS_CODE,message:renderTooManyTasksError(MAX_WORKING_TASKS,n)},toolName:e.task.toolName})}function unknownTaskResult(e){return createRuntimeToolResultFromValue({callId:e.task.callId,isError:!0,output:{code:UNKNOWN_TASK_CODE,message:renderUnknownTaskError(e.taskId,e.task.toolName)},toolName:e.task.toolName})}function taskStartedEvent(e,t){return{callId:e.task.callId,kind:t.kind,name:e.task.toolName,taskId:e.taskId,turnId:e.batchEvent.turnId}}function startReceipt(e,t){return toolResult(e,renderTaskReceipt({id:e.taskId,resumable:t,tool:e.task.toolName}))}function toolResult(e,t){return createRuntimeToolResultFromValue({callId:e.task.callId,output:t,toolName:e.task.toolName})}export{runEntryToStart,sendToTask,startTaskRun,startsEveryRun};
@@ -1,5 +1,5 @@
1
1
  import { type TaskRunCommands } from "#execution/tasks/table.js";
2
- import { type SessionStepState } from "#execution/publish-session-events.js";
2
+ import { type PublishedSessionEvents, type SessionStepState } from "#execution/publish-session-events.js";
3
3
  import { type SessionStateTransition } from "#execution/session/state-delta.js";
4
4
  import type { WorkflowToolRunMessage } from "#execution/tools/workflow/messages.js";
5
5
  import type { TaskCancelReason } from "#protocol/message.js";
@@ -7,10 +7,13 @@ import type { TaskCancelReason } from "#protocol/message.js";
7
7
  export type TaskRunMessage = Extract<WorkflowToolRunMessage, {
8
8
  readonly kind: "outcome" | "reply" | "started" | "usage";
9
9
  }>;
10
- /** Applies one message from a task's run: started, a reply, usage no reply carried, or the run's outcome. */
11
- export declare function applyTaskRunMessageStep(input: SessionStepState & {
10
+ /**
11
+ * Applies one message from a task's run: started, a reply, usage no reply
12
+ * carried, or the run's outcome. Call from a step and adopt the result.
13
+ */
14
+ export declare function applyTaskRunMessage(input: SessionStepState & {
12
15
  readonly message: TaskRunMessage;
13
- }): Promise<SessionStateTransition>;
16
+ }): Promise<PublishedSessionEvents>;
14
17
  /**
15
18
  * Cancels tasks: their calls settle as cancelled and their runs are told to
16
19
  * stop. A run ends itself within its cleanup deadline and reports cancelled.
@@ -1 +1 @@
1
- import{storedProjection}from"#harness/session-machine/view.js";import{resumeHook}from"#internal/workflow/runtime.js";import{cancelTask,findTask,finishTaskRun,markTaskRunStarted,readTaskTable,recordTaskRunUsage,settleRemainingTaskCalls,settleTaskCalls,writeTaskTable}from"#execution/tasks/table.js";import{readDurableSession,replaceDurableSessionSnapshot}from"#execution/durable-session-store.js";import{publishSessionEvents,relaySessionEvents}from"#execution/publish-session-events.js";import{withSessionStateDelta}from"#execution/session/state-delta.js";import{sessionView}from"#harness/session-machine/commit.js";import{finishRun,settleTask}from"#harness/session-machine/transitions.js";import{getProxyInputRequests}from"#harness/proxy-input-requests.js";import{countRunUsage}from"#execution/agent-sessions/usage.js";import{workflowToolRunFailureOutput}from"#execution/tools/workflow/owner-inbox.js";import{ignoreGoneTarget}from"#execution/tasks/workflow-target.js";async function applyTaskRunMessageStep(e){"use step";return await withSessionStateDelta(e,applyTaskRunMessage)}async function applyTaskRunMessage(e){let{message:t}=e,n=t.from.taskId,r=readDurableSession(e.sessionState);if(n===void 0)return{serializedContext:e.serializedContext,sessionState:e.sessionState};let i=readTaskTable(r.state),a=[],o=[];switch(t.kind){case`started`:{let e=markTaskRunStarted(i,n,t.from.runId);i=e.table,e.held!==void 0&&await sendTaskRunCommands(e.held);break}case`reply`:{({session:r,table:i}=countTaskRunUsage(r,i,n,t));let e={output:t.output,status:`completed`},o=findTask(i,n),s=settleTaskCalls(i,{callIds:t.callIds,outcome:e,taskId:n});i=s.table,a.push(...taskSettledEvents(r,o,s.settled,e));break}case`usage`:({session:r,table:i}=countTaskRunUsage(r,i,n,t));break;case`outcome`:{({session:r,table:i}=countTaskRunUsage(r,i,n,t));let e=toOutcome(t),s=findTask(i,n),c=settleRemainingTaskCalls(i,n,e);a.push(...taskSettledEvents(r,s,c.settled,e)),i=finishTaskRun(c.table,n,t.from.runId),o=finishRun(viewOf(r),{requestIds:runRequestIds(r,t.from.runId),taskId:n}).events;break}}let s=await relaySessionEvents({...e,sessionState:saveTable(e.sessionState,r,i)},o);return await publishSessionEvents({...e,...s},a)}async function cancelTasksStep(e){"use step";return await withSessionStateDelta(e,cancelTasks)}async function cancelTasks(e){let t=readDurableSession(e.sessionState),n=readTaskTable(t.state),r=[],i=viewOf(t),a=[],o={reason:e.reason,status:`cancelled`};for(let s of e.taskIds){let e=findTask(n,s),c=cancelTask(n,s);if(n=c.table,r.push(...taskSettledEvents(t,e,c.settled,o)),c.send!==void 0){if(e?.resumable===!1){let e=runRequestIds(t,c.send.run.runId);a.push(...finishRun(i,{requestIds:e,taskId:s}).events)}await sendTaskRunCommands(c.send)}}let s=await relaySessionEvents({...e,sessionState:saveTable(e.sessionState,t,n)},a);return await publishSessionEvents({...e,...s},r)}function taskSettledEvents(e,t,n,r){return t===void 0?[]:settleTask(viewOf(e),{calls:n,outcome:r,task:t}).events}async function sendTaskRunCommands(e){for(let t of e.commands)await ignoreGoneTarget(resumeHook(e.run.hookToken,toControlMessage(t)))}function toControlMessage(e){switch(e.kind){case`cancel`:return{kind:`cancel`,reason:`The task was cancelled.`};case`call`:return{call:e.call,kind:`call`}}}function toOutcome(e){switch(e.result.status){case`completed`:return{output:e.result.output,status:`completed`};case`failed`:return{error:failureMessage(e),status:`failed`};case`cancelled`:return{status:`cancelled`}}}function failureMessage(e){let t=workflowToolRunFailureOutput(e);if(typeof t==`string`)return t;let n=typeof t==`object`&&t?Reflect.get(t,`message`):void 0;return typeof n==`string`?n:JSON.stringify(t)}function countTaskRunUsage(e,t,n,r){let i=findTask(t,n)?.run;return r.usage===void 0||i?.runId!==r.from.runId?{session:e,table:t}:{session:countRunUsage(e,r.usage,i.usage),table:recordTaskRunUsage(t,n,r.usage)}}function runRequestIds(e,t){return[...getProxyInputRequests(e.state)].filter(([,e])=>e.runId===t).map(([e])=>e)}function viewOf(e){return sessionView(storedProjection(e.state),e.state)}function saveTable(e,t,n){return replaceDurableSessionSnapshot({session:writeTaskTable(t,n),state:e})}export{applyTaskRunMessageStep,cancelTasksStep,sendTaskRunCommands};
1
+ import{storedProjection}from"#harness/session-machine/view.js";import{resumeHook}from"#internal/workflow/runtime.js";import{cancelTask,findTask,finishTaskRun,markTaskRunStarted,readTaskTable,recordTaskRunUsage,settleRemainingTaskCalls,settleTaskCalls,writeTaskTable}from"#execution/tasks/table.js";import{readDurableSession,replaceDurableSessionSnapshot}from"#execution/durable-session-store.js";import{publishSessionEvents,relaySessionEvents}from"#execution/publish-session-events.js";import{withSessionStateDelta}from"#execution/session/state-delta.js";import{sessionView}from"#harness/session-machine/commit.js";import{finishRun,settleTask}from"#harness/session-machine/transitions.js";import{getProxyInputRequests}from"#harness/proxy-input-requests.js";import{countRunUsage}from"#execution/agent-sessions/usage.js";import{workflowToolRunFailureOutput}from"#execution/tools/workflow/owner-inbox.js";import{ignoreGoneTarget}from"#execution/tasks/workflow-target.js";async function applyTaskRunMessage(e){let{message:t}=e,n=t.from.taskId,r=readDurableSession(e.sessionState);if(n===void 0)return{serializedContext:e.serializedContext,sessionState:e.sessionState};let i=readTaskTable(r.state),a=[],o=[];switch(t.kind){case`started`:{let e=markTaskRunStarted(i,n,t.from.runId);i=e.table,e.held!==void 0&&await sendTaskRunCommands(e.held);break}case`reply`:{({session:r,table:i}=countTaskRunUsage(r,i,n,t));let e={output:t.output,status:`completed`},o=findTask(i,n),s=settleTaskCalls(i,{callIds:t.callIds,outcome:e,taskId:n});i=s.table,a.push(...taskSettledEvents(r,o,s.settled,e));break}case`usage`:({session:r,table:i}=countTaskRunUsage(r,i,n,t));break;case`outcome`:{({session:r,table:i}=countTaskRunUsage(r,i,n,t));let e=toOutcome(t),s=findTask(i,n),c=settleRemainingTaskCalls(i,n,e);a.push(...taskSettledEvents(r,s,c.settled,e)),i=finishTaskRun(c.table,n,t.from.runId),o=finishRun(viewOf(r),{requestIds:runRequestIds(r,t.from.runId),taskId:n}).events;break}}let s=await relaySessionEvents({...e,sessionState:saveTable(e.sessionState,r,i)},o);return await publishSessionEvents({...e,...s},a)}async function cancelTasksStep(e){"use step";return await withSessionStateDelta(e,cancelTasks)}async function cancelTasks(e){let t=readDurableSession(e.sessionState),n=readTaskTable(t.state),r=[],i=viewOf(t),a=[],o={reason:e.reason,status:`cancelled`};for(let s of e.taskIds){let e=findTask(n,s),c=cancelTask(n,s);if(n=c.table,r.push(...taskSettledEvents(t,e,c.settled,o)),c.send!==void 0){if(e?.resumable===!1){let e=runRequestIds(t,c.send.run.runId);a.push(...finishRun(i,{requestIds:e,taskId:s}).events)}await sendTaskRunCommands(c.send)}}let s=await relaySessionEvents({...e,sessionState:saveTable(e.sessionState,t,n)},a);return await publishSessionEvents({...e,...s},r)}function taskSettledEvents(e,t,n,r){return t===void 0?[]:settleTask(viewOf(e),{calls:n,outcome:r,task:t}).events}async function sendTaskRunCommands(e){for(let t of e.commands)await ignoreGoneTarget(resumeHook(e.run.hookToken,toControlMessage(t)))}function toControlMessage(e){switch(e.kind){case`cancel`:return{kind:`cancel`,reason:`The task was cancelled.`};case`call`:return{call:e.call,kind:`call`}}}function toOutcome(e){switch(e.result.status){case`completed`:return{output:e.result.output,status:`completed`};case`failed`:return{error:failureMessage(e),status:`failed`};case`cancelled`:return{status:`cancelled`}}}function failureMessage(e){let t=workflowToolRunFailureOutput(e);if(typeof t==`string`)return t;let n=typeof t==`object`&&t?Reflect.get(t,`message`):void 0;return typeof n==`string`?n:JSON.stringify(t)}function countTaskRunUsage(e,t,n,r){let i=findTask(t,n)?.run;return r.usage===void 0||i?.runId!==r.from.runId?{session:e,table:t}:{session:countRunUsage(e,r.usage,i.usage),table:recordTaskRunUsage(t,n,r.usage)}}function runRequestIds(e,t){return[...getProxyInputRequests(e.state)].filter(([,e])=>e.runId===t).map(([e])=>e)}function viewOf(e){return sessionView(storedProjection(e.state),e.state)}function saveTable(e,t,n){return replaceDurableSessionSnapshot({session:writeTaskTable(t,n),state:e})}export{applyTaskRunMessage,cancelTasksStep,sendTaskRunCommands};
@@ -1 +1 @@
1
- import{decide}from"#ai/decide.js";async function runAgentRouterTask(e,t){"use workflow";let n=await chooseTarget(e.message,descriptions(t),t.abortSignal),{message:r,status:i}=await(await t.agent(n).send(e.message,{signal:t.abortSignal})).result();if(i===`failed`)throw Error(`Agent "${n}" failed to handle the task.`);return r??null}async function chooseTarget(e,t,n){"use step";let r=Object.keys(t);if(r.length===0)throw Error(`agentRouter requires at least one available agent with a description.`);return r.length===1?r[0]:(await decide({abortSignal:n,state:{message:e},questions:{route:{type:`choice`,instructions:`Which subagent should handle this task?`,criteria:t}}})).answers.route.choice}function descriptions(e){return Object.fromEntries(Object.entries(e.agents).flatMap(([e,t])=>{let n=t.description.trim();return n.length===0?[]:[[e,n]]}))}runAgentRouterTask.workflowId=`workflow//eve@0.76.3//runAgentRouterTask`;export{runAgentRouterTask};
1
+ import{decide}from"#ai/decide.js";async function runAgentRouterTask(e,t){"use workflow";let n=await chooseTarget(e.message,descriptions(t),t.abortSignal),{message:r,status:i}=await(await t.agent(n).send(e.message,{signal:t.abortSignal})).result();if(i===`failed`)throw Error(`Agent "${n}" failed to handle the task.`);return r??null}async function chooseTarget(e,t,n){"use step";let r=Object.keys(t);if(r.length===0)throw Error(`agentRouter requires at least one available agent with a description.`);return r.length===1?r[0]:(await decide({abortSignal:n,state:{message:e},questions:{route:{type:`choice`,instructions:`Which subagent should handle this task?`,criteria:t}}})).answers.route.choice}function descriptions(e){return Object.fromEntries(Object.entries(e.agents).flatMap(([e,t])=>{let n=t.description.trim();return n.length===0?[]:[[e,n]]}))}runAgentRouterTask.workflowId=`workflow//eve@0.78.0//runAgentRouterTask`;export{runAgentRouterTask};
@@ -0,0 +1,20 @@
1
+ import { type SessionStepState } from "#execution/publish-session-events.js";
2
+ import { type SessionStateTransition } from "#execution/session/state-delta.js";
3
+ import { type TaskRunMessage } from "#execution/tasks/steps.js";
4
+ import type { WorkflowToolRunMessage } from "#execution/tools/workflow/messages.js";
5
+ /** A run's message the session applies as it reads it, which answers no call a turn waits on. */
6
+ export type AppliedRunMessage = Extract<WorkflowToolRunMessage, {
7
+ readonly kind: "agent-started" | "report";
8
+ }> | (TaskRunMessage & {
9
+ readonly from: {
10
+ readonly taskId: string;
11
+ };
12
+ });
13
+ /**
14
+ * Applies run messages in the order they arrived, in one step however many
15
+ * there are: a fan-out's starts, reports, and replies would otherwise cost a
16
+ * step each.
17
+ */
18
+ export declare function applyRunMessagesStep(input: SessionStepState & {
19
+ readonly messages: readonly AppliedRunMessage[];
20
+ }): Promise<SessionStateTransition>;
@@ -0,0 +1 @@
1
+ import{createActionPartialEvent,createAgentStartedEvent}from"#protocol/message.js";import{publishSessionEvents}from"#execution/publish-session-events.js";import{withSessionStateDelta}from"#execution/session/state-delta.js";import{applyTaskRunMessage}from"#execution/tasks/steps.js";import{createRuntimeToolResultFromValue}from"#harness/action-result-helpers.js";function workflowToolRunReportEvent(e,t){return createActionPartialEvent({result:createRuntimeToolResultFromValue({callId:e.callId,output:t,toolName:e.toolName}),sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId})}function agentStartedEvent(e,{from:t,session:n}){return createAgentStartedEvent({callId:t.callId,name:n.name,parentSessionId:e,remote:n.kind===`remote`?{url:n.url,...n.resolverId!==void 0&&{resolverId:n.resolverId}}:void 0,sessionId:n.sessionId,...t.taskId!==void 0&&{taskId:t.taskId},turnId:t.turnId})}async function applyRunMessagesStep(e){"use step";return await withSessionStateDelta(e,async({messages:e,...t})=>{let n=t,r=[],publish=async()=>{r.length!==0&&(n={...n,...await publishSessionEvents(n,r)},r=[])};for(let t of e)t.kind===`agent-started`?r.push(agentStartedEvent(n.sessionState.sessionId,t)):t.kind===`report`?r.push(workflowToolRunReportEvent(t.from,t.update)):(await publish(),n={...n,...await applyTaskRunMessage({...n,message:t})});return await publish(),{serializedContext:n.serializedContext,sessionState:n.sessionState}})}export{applyRunMessagesStep};
@@ -63,7 +63,6 @@ export declare class WorkflowToolRunAsks {
63
63
  flush(): Promise<void>;
64
64
  /** Applies the session's decision. The first one wins; a repeated one is dropped. */
65
65
  settle(decision: WorkflowToolRunAskDecision): void;
66
- fail(requestId: string, error: unknown): void;
67
66
  /** The session stopped the work, so it answers none of its questions anymore. */
68
67
  cancelAll(): void;
69
68
  private take;
@@ -1 +1 @@
1
- import{workflowToolContextErrorMessage}from"#shared/workflow-tool-context.js";const WORKFLOW_TOOL_RUN_CONTEXT=Symbol.for(`eve.workflow-tool-run.context`);function attachWorkflowToolRunContext(e,t){Object.defineProperty(e,WORKFLOW_TOOL_RUN_CONTEXT,{enumerable:!1,value:t})}function readWorkflowToolRunContext(e,t){let n=e?.[WORKFLOW_TOOL_RUN_CONTEXT];if(n===void 0)throw Error(workflowToolContextErrorMessage(t));return n}function findWorkflowToolRunContext(e){return typeof e==`object`&&e?e[WORKFLOW_TOOL_RUN_CONTEXT]:void 0}const CANCELLED={status:`cancelled`},UNAVAILABLE={status:`unavailable`};var WorkflowToolRunAsks=class{opened=0;pending=new Map;withdrawing=new Set;runId;constructor(e){this.runId=e}open(e){this.opened+=1;let t=`${this.runId}-ask-${String(this.opened)}`,n,r=new Promise((e,t)=>{n={reject:t,resolve:e,withdraw:void 0}});return this.pending.set(t,n),n.withdraw=e(t),{answer:r,requestId:t}}withdraw(e){let t=this.pending.get(e),n=t?.withdraw;if(t===void 0||n===void 0)return;t.withdraw=void 0;let r=n().catch(t=>this.fail(e,t));this.withdrawing.add(r),r.then(()=>this.withdrawing.delete(r))}withdrawAll(){for(let e of this.pending.keys())this.withdraw(e)}async flush(){for(;this.withdrawing.size>0;)await Promise.all(this.withdrawing)}settle(e){let t=e.kind===`answer`?e.response:CANCELLED;this.take(e.requestId)?.resolve(t)}fail(e,t){this.take(e)?.reject(t)}cancelAll(){for(let e of this.pending.keys())this.take(e)?.resolve(CANCELLED)}take(e){let t=this.pending.get(e);return this.pending.delete(e),t}};function ask(e,t,n={}){let r=readWorkflowToolRunContext(e,`ask`);if(r.agentContext.capabilities?.requestInput!==!0)return Promise.resolve(UNAVAILABLE);let i=[e.abortSignal];if(n.signal!==void 0&&i.push(n.signal),i.some(e=>e.aborted))return Promise.resolve(CANCELLED);let{asks:a,control:o,owner:s}=r,c=r.from,{answer:l,requestId:u}=a.open(e=>{let n=s.send({kind:`request`,from:c,replyTo:e,request:{control:o,kind:`ask`,request:t}});return n.catch(t=>a.fail(e,t)),()=>n.then(()=>s.send({control:o,from:c,kind:`withdraw`,replyTo:e}))}),requestWithdrawal=()=>a.withdraw(u);for(let e of i)e.addEventListener(`abort`,requestWithdrawal,{once:!0});return l.finally(()=>{for(let e of i)e.removeEventListener(`abort`,requestWithdrawal)})}export{WorkflowToolRunAsks,ask,attachWorkflowToolRunContext,findWorkflowToolRunContext};
1
+ import{workflowToolContextErrorMessage}from"#shared/workflow-tool-context.js";const WORKFLOW_TOOL_RUN_CONTEXT=Symbol.for(`eve.workflow-tool-run.context`);function attachWorkflowToolRunContext(e,t){Object.defineProperty(e,WORKFLOW_TOOL_RUN_CONTEXT,{enumerable:!1,value:t})}function readWorkflowToolRunContext(e,t){let n=e?.[WORKFLOW_TOOL_RUN_CONTEXT];if(n===void 0)throw Error(workflowToolContextErrorMessage(t));return n}function findWorkflowToolRunContext(e){return typeof e==`object`&&e?e[WORKFLOW_TOOL_RUN_CONTEXT]:void 0}const CANCELLED={status:`cancelled`},UNAVAILABLE={status:`unavailable`};var WorkflowToolRunAsks=class{opened=0;pending=new Map;withdrawing=new Set;runId;constructor(e){this.runId=e}open(e){this.opened+=1;let t=`${this.runId}-ask-${String(this.opened)}`,n,r=new Promise(e=>{n={resolve:e,withdraw:void 0}});return this.pending.set(t,n),n.withdraw=e(t),{answer:r,requestId:t}}withdraw(e){let t=this.pending.get(e),n=t?.withdraw;if(t===void 0||n===void 0)return;t.withdraw=void 0;let r=n();this.withdrawing.add(r),r.then(()=>this.withdrawing.delete(r))}withdrawAll(){for(let e of this.pending.keys())this.withdraw(e)}async flush(){for(;this.withdrawing.size>0;)await Promise.all(this.withdrawing)}settle(e){let t=e.kind===`answer`?e.response:CANCELLED;this.take(e.requestId)?.resolve(t)}cancelAll(){for(let e of this.pending.keys())this.take(e)?.resolve(CANCELLED)}take(e){let t=this.pending.get(e);return this.pending.delete(e),t}};function ask(e,t,n={}){let r=readWorkflowToolRunContext(e,`ask`);if(r.agentContext.capabilities?.requestInput!==!0)return Promise.resolve(UNAVAILABLE);let i=[e.abortSignal];if(n.signal!==void 0&&i.push(n.signal),i.some(e=>e.aborted))return Promise.resolve(CANCELLED);let{asks:a,control:o,owner:s}=r,c=r.from,{answer:l,requestId:u}=a.open(e=>{let n=s.send({kind:`request`,from:c,replyTo:e,request:{control:o,kind:`ask`,request:t}});return()=>n.then(()=>s.send({control:o,from:c,kind:`withdraw`,replyTo:e}))}),requestWithdrawal=()=>a.withdraw(u);for(let e of i)e.addEventListener(`abort`,requestWithdrawal,{once:!0});return l.finally(()=>{for(let e of i)e.removeEventListener(`abort`,requestWithdrawal)})}export{WorkflowToolRunAsks,ask,attachWorkflowToolRunContext,findWorkflowToolRunContext};
@@ -1,6 +1,9 @@
1
1
  import type { WorkflowToolRunAddress } from "#execution/tools/workflow/types.js";
2
2
  /**
3
- * Aborts the `execute` call's `abortSignal`. A run that already finished has nothing
4
- * left to interrupt, so a missing hook is not an error.
3
+ * Aborts the `execute` call's `abortSignal`. A turn steered right after it
4
+ * started the run can get here before the run registers its control hook, so
5
+ * a live run's missing hook is waited for. A run that ended has nothing left
6
+ * to interrupt. A run still without its hook at the deadline fails the step,
7
+ * which the runtime retries, since the interrupt was not delivered.
5
8
  */
6
9
  export declare function interruptWorkflowToolRun(run: WorkflowToolRunAddress): Promise<void>;
@@ -1 +1 @@
1
- import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";const INTERRUPT={kind:`interrupt`};async function interruptWorkflowToolRun(e){await resumeHookStep(e.hookToken,INTERRUPT,{ifPresent:!0})}export{interruptWorkflowToolRun};
1
+ import{resumeHook}from"#internal/workflow/runtime.js";import{hasRunEnded,pollUntil}from"#execution/workflow-runtime.js";import{isTaskWorkflowTargetGone}from"#execution/tasks/workflow-target.js";const INTERRUPT={kind:`interrupt`},RUN_START_TIMEOUT_MS=3e4;async function interruptWorkflowToolRun(e){"use step";if(await pollUntil(async()=>{try{return await resumeHook(e.hookToken,INTERRUPT),!0}catch(e){if(!isTaskWorkflowTargetGone(e))throw e}return await hasRunEnded(e.runId)?!0:void 0},RUN_START_TIMEOUT_MS)===void 0)throw Error(`Workflow tool run "${e.runId}" did not start taking commands within ${RUN_START_TIMEOUT_MS/1e3} seconds, so it has not received the interrupt yet.`)}export{interruptWorkflowToolRun};
@@ -146,6 +146,20 @@ export type WorkflowToolRunMessage = ({
146
146
  } & WorkflowToolRunUsageMessage) | ({
147
147
  readonly kind: "outcome";
148
148
  } & WorkflowToolRunOutcomeMessage);
149
+ /**
150
+ * Messages a run relays to its session in one delivery, in the order its body
151
+ * sent them. The session's inbox reads them as separate messages.
152
+ */
153
+ export interface WorkflowToolRunMessageBatch {
154
+ readonly kind: "workflow-batch";
155
+ readonly messages: readonly WorkflowToolRunMessage[];
156
+ }
157
+ /**
158
+ * Returns a predicate that admits messages, in order, while their batch stays
159
+ * under the size cap. The first message always fits, so one larger than the
160
+ * cap still goes, alone.
161
+ */
162
+ export declare function runMessageBatchBudget(): (message: WorkflowToolRunMessage) => boolean;
149
163
  /**
150
164
  * A later call to a `serve` task, which its run hands to `receive()`. It
151
165
  * carries everything the session knew of the call when it admitted it, as a
@@ -1 +1 @@
1
- function isWorkflowToolRunControlMessage(e){if(typeof e!=`object`||!e)return!1;let{call:t,kind:n,reason:r,requestId:i,response:a}=e;switch(n){case`interrupt`:return!0;case`cancel`:case`end`:return typeof r==`string`;case`call`:return isWorkflowToolRunCall(t);case`answer`:return typeof i==`string`&&isWorkflowToolRunAnswer(a);case`withdrawn`:return typeof i==`string`;default:return!1}}function isWorkflowToolRunAskDecision(e){return e.kind===`answer`||e.kind===`withdrawn`}function isWorkflowToolRunAnswer(e){if(typeof e!=`object`||!e)return!1;let{optionId:t,responder:n,status:r,text:i}=e;return r===`answered`&&(t===void 0||typeof t==`string`)&&(n===void 0||isToolInputResponseResponder(n))&&(i===void 0||typeof i==`string`)}function isToolInputResponseResponder(e){if(typeof e!=`object`||!e)return!1;let{authenticator:t,principalId:n,principalType:r}=e;return typeof t==`string`&&typeof n==`string`&&typeof r==`string`}function isWorkflowToolRunCall(e){if(typeof e!=`object`||!e)return!1;let{agentContext:t,auth:n,callId:r,input:i,sequence:a,stepIndex:o,turnId:s}=e;return typeof t==`object`&&!!t&&typeof n==`object`&&!!n&&typeof r==`string`&&typeof i==`object`&&!!i&&typeof a==`number`&&typeof o==`number`&&typeof s==`string`}export{isWorkflowToolRunAskDecision,isWorkflowToolRunControlMessage};
1
+ function runMessageBatchBudget(){let e=0,t=!1;return n=>{let r=serializedLength(n);return t&&e+r>64e3?!1:(e+=r,t=!0,!0)}}function serializedLength(e){try{return JSON.stringify(e)?.length??0}catch{return 1/0}}function isWorkflowToolRunControlMessage(e){if(typeof e!=`object`||!e)return!1;let{call:t,kind:n,reason:r,requestId:i,response:a}=e;switch(n){case`interrupt`:return!0;case`cancel`:case`end`:return typeof r==`string`;case`call`:return isWorkflowToolRunCall(t);case`answer`:return typeof i==`string`&&isWorkflowToolRunAnswer(a);case`withdrawn`:return typeof i==`string`;default:return!1}}function isWorkflowToolRunAskDecision(e){return e.kind===`answer`||e.kind===`withdrawn`}function isWorkflowToolRunAnswer(e){if(typeof e!=`object`||!e)return!1;let{optionId:t,responder:n,status:r,text:i}=e;return r===`answered`&&(t===void 0||typeof t==`string`)&&(n===void 0||isToolInputResponseResponder(n))&&(i===void 0||typeof i==`string`)}function isToolInputResponseResponder(e){if(typeof e!=`object`||!e)return!1;let{authenticator:t,principalId:n,principalType:r}=e;return typeof t==`string`&&typeof n==`string`&&typeof r==`string`}function isWorkflowToolRunCall(e){if(typeof e!=`object`||!e)return!1;let{agentContext:t,auth:n,callId:r,input:i,sequence:a,stepIndex:o,turnId:s}=e;return typeof t==`object`&&!!t&&typeof n==`object`&&!!n&&typeof r==`string`&&typeof i==`object`&&!!i&&typeof a==`number`&&typeof o==`number`&&typeof s==`string`}export{isWorkflowToolRunAskDecision,isWorkflowToolRunControlMessage,runMessageBatchBudget};
@@ -1,4 +1,4 @@
1
- import type { WorkflowToolRunMessage, WorkflowToolRunRequestMessage, WorkflowToolAuthorizationRequest } from "#execution/tools/workflow/messages.js";
1
+ import { type WorkflowToolRunMessage, type WorkflowToolRunRequestMessage, type WorkflowToolAuthorizationRequest } from "#execution/tools/workflow/messages.js";
2
2
  import { type ChannelReader } from "#execution/tools/workflow/owner-channels.js";
3
3
  /**
4
4
  * The run's inbox as its body sees it. Everything the body sends its session,
@@ -8,17 +8,29 @@ import { type ChannelReader } from "#execution/tools/workflow/owner-channels.js"
8
8
  export interface WorkflowToolRunInbox {
9
9
  /** Messages that reached the run's inbox so far. */
10
10
  readonly sent: number;
11
- send(message: Exclude<WorkflowToolRunMessage, {
12
- readonly kind: "outcome";
13
- }>): Promise<void>;
11
+ send(message: WorkflowToolRunBodyMessage): Promise<void>;
14
12
  }
13
+ /** What a body sends its session through the run: everything but the outcome, which the run sends. */
14
+ type WorkflowToolRunBodyMessage = Exclude<WorkflowToolRunMessage, {
15
+ readonly kind: "outcome";
16
+ }>;
15
17
  export interface WorkflowToolRunOwnerInbox {
16
18
  readonly owner: WorkflowToolRunInbox;
17
- readonly reader: ChannelReader<"workflow", WorkflowToolRunMessage>;
19
+ /** What was sent since the last read, in order, up to a batch's size cap. */
20
+ readonly reader: ChannelReader<"workflow", WorkflowToolRunBodyMessage[]>;
18
21
  }
19
- /** Receives body messages before routing them to the waiting turn. */
22
+ /**
23
+ * Receives body messages before routing them to the waiting turn. The body
24
+ * and the run share one workflow, which replays both deterministically, so
25
+ * the inbox is an in-memory queue; a durable hop would add a step and a
26
+ * replay to every message. The run relays what queued up together, within a
27
+ * size cap, so a fan-out's messages share a relay. A relay can run before hooks created in
28
+ * the same suspension are registered, so a body that hands the session a
29
+ * hook token registers that hook before sending it.
30
+ */
20
31
  export declare function openWorkflowToolRunOwnerInbox(): WorkflowToolRunOwnerInbox;
21
32
  /** Acknowledge only step-owned events, after delivery or deliberate discard. */
22
33
  export declare function deliverWorkflowAuthorization(message: WorkflowToolRunRequestMessage & {
23
34
  readonly request: WorkflowToolAuthorizationRequest;
24
35
  }, deliver: () => Promise<void>): Promise<void>;
36
+ export {};
@@ -1 +1 @@
1
- import{createHook}from"#compiled/@workflow/core/index.js";import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";import{createChannelReader}from"#execution/tools/workflow/owner-channels.js";function openWorkflowToolRunOwnerInbox(){let e=createHook(),t=0;return{owner:{get sent(){return t},async send(n){await resumeHookStep(e.token,n),t+=1}},reader:createChannelReader(`workflow`,e)}}async function deliverWorkflowAuthorization(e,t){await t(),e.request.event.childSessionId===e.from.runId&&await resumeHookStep(e.replyTo,null,{ifPresent:!0})}export{deliverWorkflowAuthorization,openWorkflowToolRunOwnerInbox};
1
+ import{runMessageBatchBudget}from"#execution/tools/workflow/messages.js";import{createChannelReader}from"#execution/tools/workflow/owner-channels.js";import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";function openWorkflowToolRunOwnerInbox(){let e=[],t,n=0;async function*read(){for(;;){if(e.length>0){let t=runMessageBatchBudget(),n=e.findIndex(e=>!t(e));yield e.splice(0,n===-1?e.length:n);continue}await new Promise(e=>{t=e})}}return{owner:{get sent(){return n},async send(r){e.push(r),n+=1;let i=t;t=void 0,i?.()}},reader:createChannelReader(`workflow`,read())}}async function deliverWorkflowAuthorization(e,t){await t(),e.request.event.childSessionId===e.from.runId&&await resumeHookStep(e.replyTo,null,{ifPresent:!0})}export{deliverWorkflowAuthorization,openWorkflowToolRunOwnerInbox};
@@ -19,9 +19,19 @@ export interface StartWorkflowTaskInput {
19
19
  };
20
20
  readonly owner: WorkflowToolRunOwner;
21
21
  readonly parentSession: SessionParent | undefined;
22
+ /**
23
+ * The call's run, when its batch already started it alongside the others.
24
+ * The dispatch records it in place of starting one.
25
+ */
26
+ readonly prestarted?: PrestartedWorkflowToolRun;
22
27
  readonly session: HarnessSessionBase;
23
28
  readonly task: RuntimeWorkflowTaskRequest;
24
29
  }
30
+ /** A call's run its batch started early, and the entry it was started with. */
31
+ export interface PrestartedWorkflowToolRun {
32
+ readonly entry: WorkflowToolRunEntry;
33
+ readonly run: Promise<WorkflowToolRunAddress>;
34
+ }
25
35
  /** Starts the run for one call, which invokes `entry`. */
26
36
  export declare function startWorkflowToolCallRun(input: StartWorkflowTaskInput, entry: WorkflowToolRunEntry): Promise<WorkflowToolRunAddress>;
27
37
  /** Starts the run of an `execute` call the turn waits on and records it on the owning session. */
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{toError}from"#shared/errors.js";import{startWorkflowOnCurrentDeployment,workflowToolRunWorkflowReference}from"#execution/workflow-runtime.js";import{registerWorkflowToolRun}from"#harness/workflow-tool-runs.js";import{createRuntimeToolResultFromValue}from"#harness/action-result-helpers.js";const log=createLogger(`execution.workflow-tool-run`);async function startWorkflowToolRun(e){let t=e.entry.entryPoint===`execute`?crypto.randomUUID():taskRunHookToken(e.session.id,e.entry.taskId);return{hookToken:t,runId:(await startWorkflowOnCurrentDeployment(workflowToolRunWorkflowReference,[{...e,hookToken:t}])).runId}}function taskRunHookToken(e,t){return`eve:task:${e}:${t}`}async function startWorkflowToolCallRun(e,t){let{task:n,batchEvent:r,session:i}=e;return await startWorkflowToolRun({agentContext:e.agentContext,callId:n.callId,entry:t,executeInput:n.executeInput,input:n.input,owner:e.owner,session:{auth:e.auth,id:i.sessionId,parent:e.parentSession,turn:{id:r.turnId,sequence:r.sequence}},stepIndex:r.stepIndex,toolName:n.toolName,workflowId:n.workflowId})}async function startWorkflowTask(e){let{task:t,batchEvent:n,session:r}=e;try{let i=await startWorkflowToolCallRun(e,{entryPoint:`execute`});return{session:registerWorkflowToolRun(r,{callId:t.callId,origin:{turnId:n.turnId,stepIndex:n.stepIndex},address:i,toolName:t.toolName})}}catch(e){return logError(log,`workflow tool run failed to start`,e,{callId:t.callId,toolName:t.toolName}),{result:startFailureResult(t,e),session:r}}}function startFailureResult(e,t){return createRuntimeToolResultFromValue({callId:e.callId,isError:!0,output:toError(t),toolName:e.toolName})}export{startFailureResult,startWorkflowTask,startWorkflowToolCallRun,startWorkflowToolRun};
1
+ import{createLogger,logError}from"#internal/logging.js";import{toError}from"#shared/errors.js";import{startWorkflowOnCurrentDeployment,workflowToolRunWorkflowReference}from"#execution/workflow-runtime.js";import{registerWorkflowToolRun}from"#harness/workflow-tool-runs.js";import{createRuntimeToolResultFromValue}from"#harness/action-result-helpers.js";const log=createLogger(`execution.workflow-tool-run`);async function startWorkflowToolRun(e){let t=e.entry.entryPoint===`execute`?crypto.randomUUID():taskRunHookToken(e.session.id,e.entry.taskId);return{hookToken:t,runId:(await startWorkflowOnCurrentDeployment(workflowToolRunWorkflowReference,[{...e,hookToken:t}])).runId}}function taskRunHookToken(e,t){return`eve:task:${e}:${t}`}async function startWorkflowToolCallRun(e,t){let{prestarted:n}=e;if(n!==void 0){if(!isSameRunEntry(n.entry,t))throw Error(`Call "${e.task.callId}" was started for a different entry point.`);return await n.run}let{task:r,batchEvent:i,session:a}=e;return await startWorkflowToolRun({agentContext:e.agentContext,callId:r.callId,entry:t,executeInput:r.executeInput,input:r.input,owner:e.owner,session:{auth:e.auth,id:a.sessionId,parent:e.parentSession,turn:{id:i.turnId,sequence:i.sequence}},stepIndex:i.stepIndex,toolName:r.toolName,workflowId:r.workflowId})}function isSameRunEntry(e,t){return e.entryPoint===`execute`||t.entryPoint===`execute`?e.entryPoint===t.entryPoint:e.entryPoint===t.entryPoint&&e.taskId===t.taskId}async function startWorkflowTask(e){let{task:t,batchEvent:n,session:r}=e;try{let i=await startWorkflowToolCallRun(e,{entryPoint:`execute`});return{session:registerWorkflowToolRun(r,{callId:t.callId,origin:{turnId:n.turnId,stepIndex:n.stepIndex},address:i,toolName:t.toolName})}}catch(e){return logError(log,`workflow tool run failed to start`,e,{callId:t.callId,toolName:t.toolName}),{result:startFailureResult(t,e),session:r}}}function startFailureResult(e,t){return createRuntimeToolResultFromValue({callId:e.callId,isError:!0,output:toError(t),toolName:e.toolName})}export{startFailureResult,startWorkflowTask,startWorkflowToolCallRun,startWorkflowToolRun};
@@ -1 +1 @@
1
- import{createHook,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{disposeHook}from"#execution/hook-ownership.js";import{runSignIn}from"#harness/session-machine/transitions.js";import{findWorkflowToolRunContext}from"#execution/tools/workflow/ask.js";function workflowToolStep(e,t){return new Proxy(e,{apply(e,n,r){let i=findWorkflowContextArgument(r);return i===void 0?Reflect.apply(e,n,r):executeAuthorizedStep(t,n,r,i)}})}function findWorkflowContextArgument(e){for(let t of e){let e=findWorkflowToolRunContext(t);if(e!==void 0)return{ctx:t,run:e}}}async function executeAuthorizedStep(e,t,n,r){let{ctx:i,run:a}=r,o=[],s=new Map;for(;;){let r=createHook();try{let c;try{c=await invokeAuthorizedStep({args:n,authorizationResults:o,callbackToken:r.token,ctx:i,execute:e,receiver:t})}catch(e){throw i.abortSignal.aborted||await reportPendingAsFailed(a,i.abortSignal,s),e}if(await reconcileCompletedAuthorizations(a,i.abortSignal,s,o,c.authorized),c.kind===`result`)return await reportPendingAsFailed(a,i.abortSignal,s),c.output;await collectAuthorizationCallbacks({authorizationResults:o,callback:r,challenges:c.signal.challenges,ctx:i,pending:s,run:a})}finally{await disposeHook(r)}}}async function invokeAuthorizedStep(e){let{args:t,authorizationResults:n,callbackToken:r,ctx:i,execute:a,receiver:o}=e,s={callId:i.callId,toolName:i.toolName,session:i.session,abortSignal:i.abortSignal,baseUrl:getWorkflowMetadata().url,token:r,authorizationResults:n},c={args:t.map(e=>e===i?null:e),context:s,contextIndexes:t.flatMap((e,t)=>e===i?[t]:[])};return await a.call(o,c)}async function reconcileCompletedAuthorizations(e,t,n,r,i){let a=new Set(i);for(let r of a){let i=n.get(r);i!==void 0&&await reportAuthorization(e,t,i,`authorized`),n.delete(r)}for(let e=r.length-1;e>=0;e--){let t=r[e];t!==void 0&&a.has(t.attemptId)&&r.splice(e,1)}}async function collectAuthorizationCallbacks(e){let{authorizationResults:t,callback:n,challenges:r,ctx:i,pending:a,run:o}=e;for(let e of r){let r=requireAttemptId(e);a.set(r.attemptId,r),await reportAuthorization(o,i.abortSignal,r);try{let e=await waitForCallback(n,r,i.abortSignal);t.push({name:r.name,instanceId:r.instanceId,attemptId:r.attemptId,hookUrl:r.hookUrl,principal:r.principal,resume:r.resume,callback:e})}catch(e){throw i.abortSignal.aborted||await reportAuthorization(o,i.abortSignal,r,`failed`),e}}}function requireAttemptId(e){if(e.attemptId===void 0)throw Error(`Workflow authorization challenge "${e.name}" has no attempt id.`);return e}async function reportPendingAsFailed(e,t,n){for(let r of n.values())await reportAuthorization(e,t,r,`failed`)}async function reportAuthorization(e,t,n,r){let i=runSignIn(e.from,n,r),a=createHook();try{await withAbort(e.owner.send({kind:`request`,from:e.from,replyTo:a.token,request:{kind:`authorization-request`,event:{kind:`subagent-authorization-event`,callId:e.from.callId,childSessionId:e.from.runId,subagentName:e.from.toolName,event:i}}}),t),await withAbort(a,t)}finally{await disposeHook(a)}}async function waitForCallback(e,t,n){let r=e[Symbol.asyncIterator]();for(;;){let e=await withAbort(r.next(),n);if(e.done)throw Error(`Authorization callback closed before sign-in completed.`);let i=readCallback(e.value,t);if(i!==void 0)return i}}async function withAbort(e,t){let abort,n=new Promise((e,n)=>{abort=()=>n(t.reason??Error(`Workflow authorization cancelled.`)),t.addEventListener(`abort`,abort,{once:!0}),t.aborted&&abort()});try{return await Promise.race([e,n])}finally{t.removeEventListener(`abort`,abort)}}function readCallback(e,t){if(typeof e==`object`&&e&&`payloads`in e&&Array.isArray(e.payloads))for(let n of e.payloads){let e=n?.authorizationCallback;if(e?.attemptId!==t.attemptId||e?.connectionName!==t.name)continue;let r=e.callback;if(!(typeof r?.method!=`string`||typeof r.params!=`object`||r.params===null||Array.isArray(r.params))&&Object.values(r.params).every(e=>typeof e==`string`)&&(r.body===void 0||typeof r.body==`string`))return r}}export{workflowToolStep};
1
+ import{createHook,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{disposeHook}from"#execution/hook-ownership.js";import{runSignIn}from"#harness/session-machine/transitions.js";import{findWorkflowToolRunContext}from"#execution/tools/workflow/ask.js";function workflowToolStep(e,t){return new Proxy(e,{apply(e,n,r){let i=findWorkflowContextArgument(r);return i===void 0?Reflect.apply(e,n,r):executeAuthorizedStep(t,n,r,i)}})}function findWorkflowContextArgument(e){for(let t of e){let e=findWorkflowToolRunContext(t);if(e!==void 0)return{ctx:t,run:e}}}async function executeAuthorizedStep(e,t,n,r){let{ctx:i,run:a}=r,o=[],s=new Map;for(;;){let r=createHook();try{let c;try{c=await invokeAuthorizedStep({args:n,authorizationResults:o,callbackToken:r.token,ctx:i,execute:e,receiver:t})}catch(e){throw i.abortSignal.aborted||await reportPendingAsFailed(a,i.abortSignal,s),e}if(await reconcileCompletedAuthorizations(a,i.abortSignal,s,o,c.authorized),c.kind===`result`)return await reportPendingAsFailed(a,i.abortSignal,s),c.output;await collectAuthorizationCallbacks({authorizationResults:o,callback:r,challenges:c.signal.challenges,ctx:i,pending:s,run:a})}finally{await disposeHook(r)}}}async function invokeAuthorizedStep(e){let{args:t,authorizationResults:n,callbackToken:r,ctx:i,execute:a,receiver:o}=e,s={callId:i.callId,toolName:i.toolName,session:i.session,abortSignal:i.abortSignal,baseUrl:getWorkflowMetadata().url,token:r,authorizationResults:n},c={args:t.map(e=>e===i?null:e),context:s,contextIndexes:t.flatMap((e,t)=>e===i?[t]:[])};return await a.call(o,c)}async function reconcileCompletedAuthorizations(e,t,n,r,i){let a=new Set(i);for(let r of a){let i=n.get(r);i!==void 0&&await reportAuthorization(e,t,i,`authorized`),n.delete(r)}for(let e=r.length-1;e>=0;e--){let t=r[e];t!==void 0&&a.has(t.attemptId)&&r.splice(e,1)}}async function collectAuthorizationCallbacks(e){let{authorizationResults:t,callback:n,challenges:r,ctx:i,pending:a,run:o}=e;for(let e of r){let r=requireAttemptId(e);a.set(r.attemptId,r),await reportAuthorization(o,i.abortSignal,r);try{let e=await waitForCallback(n,r,i.abortSignal);t.push({name:r.name,instanceId:r.instanceId,attemptId:r.attemptId,hookUrl:r.hookUrl,principal:r.principal,resume:r.resume,callback:e})}catch(e){throw i.abortSignal.aborted||await reportAuthorization(o,i.abortSignal,r,`failed`),e}}}function requireAttemptId(e){if(e.attemptId===void 0)throw Error(`Workflow authorization challenge "${e.name}" has no attempt id.`);return e}async function reportPendingAsFailed(e,t,n){for(let r of n.values())await reportAuthorization(e,t,r,`failed`)}async function reportAuthorization(e,t,n,r){let i=runSignIn(e.from,n,r),a=createHook();try{await a.getConflict(),await withAbort(e.owner.send({kind:`request`,from:e.from,replyTo:a.token,request:{kind:`authorization-request`,event:{kind:`subagent-authorization-event`,callId:e.from.callId,childSessionId:e.from.runId,subagentName:e.from.toolName,event:i}}}),t),await withAbort(a,t)}finally{await disposeHook(a)}}async function waitForCallback(e,t,n){let r=e[Symbol.asyncIterator]();for(;;){let e=await withAbort(r.next(),n);if(e.done)throw Error(`Authorization callback closed before sign-in completed.`);let i=readCallback(e.value,t);if(i!==void 0)return i}}async function withAbort(e,t){let abort,n=new Promise((e,n)=>{abort=()=>n(t.reason??Error(`Workflow authorization cancelled.`)),t.addEventListener(`abort`,abort,{once:!0}),t.aborted&&abort()});try{return await Promise.race([e,n])}finally{t.removeEventListener(`abort`,abort)}}function readCallback(e,t){if(typeof e==`object`&&e&&`payloads`in e&&Array.isArray(e.payloads))for(let n of e.payloads){let e=n?.authorizationCallback;if(e?.attemptId!==t.attemptId||e?.connectionName!==t.name)continue;let r=e.callback;if(!(typeof r?.method!=`string`||typeof r.params!=`object`||r.params===null||Array.isArray(r.params))&&Object.values(r.params).every(e=>typeof e==`string`)&&(r.body===void 0||typeof r.body==`string`))return r}}export{workflowToolStep};
@@ -4,7 +4,19 @@ import type { WorkflowToolRunInput } from "#execution/tools/workflow/types.js";
4
4
  export interface BlockingWorkflowOwner {
5
5
  /** The session's commands, from the run's control hook. */
6
6
  readonly commands: ChannelReader<"control", WorkflowToolRunControlMessage>;
7
+ /**
8
+ * Waits until the control hook is registered, so the session's commands
9
+ * reach the run, and resolves `false` when another run already holds its
10
+ * token. A pending wait keeps the suspension that registers the hook from
11
+ * running its steps inline, so call it only once the run needs the answer.
12
+ */
13
+ register(): Promise<boolean>;
7
14
  handleMessage(message: WorkflowToolRunMessage): Promise<void>;
15
+ /**
16
+ * Relays the body's messages to the session in one delivery, which is one
17
+ * durable write: the session gets all of them or none, never a prefix.
18
+ */
19
+ relay(messages: readonly WorkflowToolRunMessage[]): Promise<void>;
8
20
  }
9
21
  /** The run's link to its session: commands arrive on its control hook, and its messages go to the session's inbox. */
10
22
  export declare function createBlockingWorkflow(input: WorkflowToolRunInput): BlockingWorkflowOwner;
@@ -1 +1 @@
1
- import{createHook}from"#compiled/@workflow/core/index.js";import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";import{createChannelReader}from"#execution/tools/workflow/owner-channels.js";function createBlockingWorkflow(e){let t=createHook({token:e.hookToken});return{commands:createChannelReader(`control`,t),handleMessage(t){return resumeHookStep(e.owner.inbox,t,{ifPresent:t.kind===`outcome`&&t.result.status===`cancelled`})}}}export{createBlockingWorkflow};
1
+ import{createHook}from"#compiled/@workflow/core/index.js";import{isHookConflictError}from"#execution/hook-ownership.js";import{createChannelReader}from"#execution/tools/workflow/owner-channels.js";import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";function createBlockingWorkflow(e){let t=createHook({token:e.hookToken}),n,handleMessage=t=>resumeHookStep(e.owner.inbox,t,{ifPresent:t.kind===`outcome`&&t.result.status===`cancelled`});return{commands:createChannelReader(`control`,t),register(){return n??=t.getConflict().then(e=>e===null,e=>{if(isHookConflictError(e))return!1;throw e}),n},handleMessage,relay(t){if(t.length===1)return handleMessage(t[0]);let n={kind:`workflow-batch`,messages:t};return resumeHookStep(e.owner.inbox,n)}}}export{createBlockingWorkflow};
@@ -1 +1 @@
1
- import{sleep}from"#compiled/@workflow/core/index.js";import{normalizeSerializableError}from"#execution/workflow-errors.js";import{openWorkflowToolRunOwnerInbox}from"#execution/tools/workflow/owner.js";import{WORKFLOW_CANCELLATION_CLEANUP_MS}from"#execution/tools/workflow/cancellation-policy.js";import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";import{createChannelReader,raceChannelReads}from"#execution/tools/workflow/owner-channels.js";import{createWorkflowBodyRef,startCallBody}from"#execution/tools/workflow/body.js";import{isWorkflowToolRunAskDecision,isWorkflowToolRunControlMessage}from"#execution/tools/workflow/messages.js";import{createBlockingWorkflow}from"#execution/tools/workflow/workflow-owner-blocking.js";import{startServeBody}from"#execution/tools/workflow/serve.js";async function workflowToolRunWorkflow(e){"use workflow";let t=createBlockingWorkflow(e),n=openWorkflowToolRunOwnerInbox();e.entry.entryPoint!==`execute`&&await reportTaskStarted(e);let r=startWorkflowBody({...e,owner:n.owner}),i=r.control.runSignal,a=createChannelReader(`body`,awaitBodyOutcome(r.outcome)),o=!0,s=0,c,l,u;try{for(;;){if(r.control.unwinding&&(l??=sleep(WORKFLOW_CANCELLATION_CLEANUP_MS).then(()=>`cancel`)),c!==void 0&&s>=n.owner.sent&&t.commands.landed.length===0&&t.commands.failure===void 0){u=c;break}let e;try{let r=[];o&&r.push(t.commands),r.push(n.reader),c===void 0&&r.push(a),e=await raceChannelReads(r,l)}catch(e){if(t.commands.failure!==void 0)throw e;u={status:`failed`,error:normalizeSerializableError(e)};break}if(e===`cancel`){if(!r.control.unwinding){l=void 0;continue}i.aborted||r.control.apply({kind:`end`,reason:`The task was cancelled and its serve body didn't return to receive() within 30 seconds.`});break}if(e.next.done){if(e.channel===`control`){o=!1;continue}if(e.channel===`body`){u={status:`failed`,error:`Workflow body ended without an outcome.`};break}if(i.aborted)break;return}if(e.channel===`control`){r.control.unwinding||(l=void 0),applyControlMessage(r,e.next.value);continue}if(e.channel===`body`){c=e.next.value;continue}let d=e.next.value;d.kind!==`outcome`&&(s+=1,await t.handleMessage(d))}}finally{await r.close()}if(i.aborted&&(u={status:`cancelled`,reason:i.reason instanceof Error?i.reason.message:String(i.reason??``)}),u!==void 0){let n=r.usage.total();await t.handleMessage({from:createWorkflowBodyRef(e),kind:`outcome`,result:u,...n!==void 0&&{usage:n}})}}async function reportTaskStarted(e){await resumeHookStep(e.owner.inbox,{from:createWorkflowBodyRef(e),kind:`started`},{ifPresent:!0})}function applyControlMessage(e,t){if(isWorkflowToolRunControlMessage(t)){if(isWorkflowToolRunAskDecision(t)){e.asks.settle(t);return}e.control.apply(t)}}function startWorkflowBody(e){switch(e.entry.entryPoint){case`execute`:case`task`:return startCallBody(e);case`serve`:return startServeBody(e)}}async function*awaitBodyOutcome(e){yield await e}workflowToolRunWorkflow.workflowId=`workflow//eve//workflowToolRunWorkflow`;export{workflowToolRunWorkflow};
1
+ import{sleep}from"#compiled/@workflow/core/index.js";import{isWorkflowToolRunAskDecision,isWorkflowToolRunControlMessage}from"#execution/tools/workflow/messages.js";import{normalizeSerializableError}from"#execution/workflow-errors.js";import{openWorkflowToolRunOwnerInbox}from"#execution/tools/workflow/owner.js";import{WORKFLOW_CANCELLATION_CLEANUP_MS}from"#execution/tools/workflow/cancellation-policy.js";import{createChannelReader,raceChannelReads}from"#execution/tools/workflow/owner-channels.js";import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";import{createWorkflowBodyRef,startCallBody}from"#execution/tools/workflow/body.js";import{createBlockingWorkflow}from"#execution/tools/workflow/workflow-owner-blocking.js";import{startServeBody}from"#execution/tools/workflow/serve.js";async function workflowToolRunWorkflow(e){"use workflow";let t=createBlockingWorkflow(e),n=openWorkflowToolRunOwnerInbox(),r=e.entry.entryPoint!==`execute`;if(r&&!await t.register()){await reportTaskStarted(e);return}let i=startWorkflowBody({...e,owner:n.owner}),a=r?reportTaskStarted(e):void 0,o=i.control.runSignal,s=createChannelReader(`body`,awaitBodyOutcome(i.outcome)),c=!0,l=0,u,d,f;try{for(await a;;){if(i.control.unwinding&&(d??=sleep(WORKFLOW_CANCELLATION_CLEANUP_MS).then(()=>`cancel`)),u!==void 0&&l>=n.owner.sent&&t.commands.landed.length===0&&t.commands.failure===void 0){f=u;break}let e;try{let r=[];c&&r.push(t.commands),r.push(n.reader),u===void 0&&r.push(s),e=await raceChannelReads(r,d)}catch(e){if(t.commands.failure!==void 0)throw e;f={status:`failed`,error:normalizeSerializableError(e)};break}if(e===`cancel`){if(!i.control.unwinding){d=void 0;continue}o.aborted||i.control.apply({kind:`end`,reason:`The task was cancelled and its serve body didn't return to receive() within 30 seconds.`});break}if(e.next.done){if(e.channel===`control`){c=!1;continue}f={status:`failed`,error:`Workflow body ended without an outcome.`};break}if(e.channel===`control`){i.control.unwinding||(d=void 0),applyControlMessage(i,e.next.value);continue}if(e.channel===`body`){u=e.next.value;continue}let r=e.next.value;l+=r.length,r.some(isAnsweredOnControlHook)&&await t.register(),await t.relay(r)}}finally{await i.close()}if(o.aborted&&(f={status:`cancelled`,reason:o.reason instanceof Error?o.reason.message:String(o.reason??``)}),f!==void 0){let n=i.usage.total();await t.handleMessage({from:createWorkflowBodyRef(e),kind:`outcome`,result:f,...n!==void 0&&{usage:n}})}}async function reportTaskStarted(e){await resumeHookStep(e.owner.inbox,{from:createWorkflowBodyRef(e),kind:`started`},{ifPresent:!0})}function applyControlMessage(e,t){if(isWorkflowToolRunControlMessage(t)){if(isWorkflowToolRunAskDecision(t)){e.asks.settle(t);return}e.control.apply(t)}}function isAnsweredOnControlHook(e){return e.kind===`withdraw`||e.kind===`request`&&e.request.kind===`ask`}function startWorkflowBody(e){switch(e.entry.entryPoint){case`execute`:case`task`:return startCallBody(e);case`serve`:return startServeBody(e)}}async function*awaitBodyOutcome(e){yield await e}workflowToolRunWorkflow.workflowId=`workflow//eve//workflowToolRunWorkflow`;export{workflowToolRunWorkflow};
@@ -1 +1 @@
1
- import{isIP}from"node:net";import{isLoopbackHostname,isPrivateOrReservedIpAddress}from"#shared/network-address.js";import{lookup}from"node:dns";const REDIRECT_STATUSES=new Set([301,302,303,307,308]),UNSAFE_DESTINATION_ERROR=`URL must not target localhost, private, link-local, or reserved IP addresses.`;async function requestPublicUrl(e,t){let n=parseHttpsUrl(e);for(let e=0;;e++){let{dispatcher:r,response:i}=await requestOnce(n,t);try{let r=i.headers.get(`location`);if(r!==null&&REDIRECT_STATUSES.has(i.status)&&e<10){await cancelResponseBody(i),n=parseHttpsUrl(new URL(r,n).toString());continue}return await consumeResponse(i,t.maxResponseSize)}finally{await r.close()}}}function parseHttpsUrl(e){let t;try{t=new URL(e)}catch{throw Error(`URL must be a valid absolute https:// URL.`)}if(t.protocol!==`https:`)throw Error(`URL must start with https://`);return t}async function requestOnce(e,t){assertPublicHostname(e.hostname);let{Agent:n,Dispatcher1Wrapper:r}=await import(`undici`),i=new r(new n({connect:{lookup:createPublicLookup()}}));try{return{dispatcher:i,response:await fetchWithDispatcher(e,{dispatcher:i,headers:t.headers,redirect:`manual`,signal:t.signal})}}catch(e){throw await i.close(),e}}function fetchWithDispatcher(e,t){return fetch(e,t)}function assertPublicHostname(e){let t=e.replace(/^\[(.*)\]$/u,`$1`);if(isIP(t)!==0){assertPublicAddress(t);return}if(isLoopbackHostname(t))throw Error(UNSAFE_DESTINATION_ERROR)}function assertPublicAddress(e){if(isPrivateOrReservedIpAddress(e))throw Error(UNSAFE_DESTINATION_ERROR)}function createPublicLookup(){return(e,t,n)=>{lookup(e,{all:!0,verbatim:!0},(r,i)=>{if(r!==null){n(r,``,0);return}try{for(let{address:e}of i)assertPublicAddress(e)}catch(e){n(e,``,0);return}let a=t.family===void 0||t.family===0?i:i.filter(({family:e})=>e===t.family);if(a.length===0){let t=Error(`Unable to resolve URL hostname "${e}" in the requested IP family.`);Object.assign(t,{code:`ENOTFOUND`}),n(t,``,0);return}if(t.all===!0){n(null,a);return}let o=a[0];n(null,o.address,o.family)})}}async function consumeResponse(e,t){let n=parseContentLength(e.headers.get(`content-length`));if(n!==void 0&&n>t)throw await cancelResponseBody(e),createResponseTooLargeError();let r=await readBoundedBody(e,t),i=r.byteLength===0?null:Uint8Array.from(r).buffer;return new Response(i,{headers:e.headers,status:e.status,statusText:e.statusText})}function parseContentLength(e){if(e===null)return;let t=Number.parseInt(e,10);return Number.isFinite(t)&&t>=0?t:void 0}async function readBoundedBody(e,t){if(e.body===null)return new Uint8Array;let n=e.body.getReader(),r=[],i=0;try{for(;;){let{done:e,value:a}=await n.read();if(e)break;if(i+=a.byteLength,i>t)throw await n.cancel(),createResponseTooLargeError();r.push(a)}}finally{n.releaseLock()}let a=new Uint8Array(i),o=0;for(let e of r)a.set(e,o),o+=e.byteLength;return a}async function cancelResponseBody(e){try{await e.body?.cancel()}catch{}}function createResponseTooLargeError(){return Error(`Response too large (exceeds 5 MB limit).`)}export{requestPublicUrl};
1
+ import{isIP}from"node:net";import{isLoopbackHostname,isPrivateOrReservedIpAddress}from"#shared/network-address.js";import{lookup}from"node:dns";const REDIRECT_STATUSES=new Set([301,302,303,307,308]),UNSAFE_DESTINATION_ERROR=`URL must not target localhost, private, link-local, or reserved IP addresses.`;async function requestPublicUrl(e,t){let n=parseHttpsUrl(e);for(let e=0;;e++){let{dispatcher:r,response:i}=await requestOnce(n,t);try{let r=i.headers.get(`location`);if(r!==null&&REDIRECT_STATUSES.has(i.status)&&e<10){await cancelResponseBody(i),n=parseHttpsUrl(new URL(r,n).toString());continue}return await consumeResponse(i,t.maxResponseSize)}finally{await r.close()}}}function parseHttpsUrl(e){let t;try{t=new URL(e)}catch{throw Error(`URL must be a valid absolute https:// URL.`)}if(t.protocol!==`https:`)throw Error(`URL must start with https://`);return t}async function requestOnce(e,t){assertPublicHostname(e.hostname);let{Agent:n,Dispatcher1Wrapper:r}=await import(`undici`),i=new r(new n({connect:{lookup:createPublicLookup()}}));try{return{dispatcher:i,response:await fetchWithDispatcher(e,{dispatcher:i,headers:t.headers,redirect:`manual`,signal:t.signal})}}catch(e){throw await i.close(),e}}function fetchWithDispatcher(e,t){return fetch(e,t)}function assertPublicHostname(e){let t=e.replace(/^\[(.*)\]$/u,`$1`);if(isIP(t)!==0){assertPublicAddress(t);return}if(isLoopbackHostname(t))throw Error(UNSAFE_DESTINATION_ERROR)}function assertPublicAddress(e){if(isPrivateOrReservedIpAddress(e))throw Error(UNSAFE_DESTINATION_ERROR)}function createPublicLookup(){return(e,t,n)=>{lookup(e,{all:!0,verbatim:!0},(r,i)=>{if(r!==null){n(r,``,0);return}try{for(let{address:e}of i)assertPublicAddress(e)}catch(e){n(e,``,0);return}let a=t.family===void 0||t.family===0?i:i.filter(({family:e})=>e===t.family);if(a.length===0){let t=Error(`Unable to resolve URL hostname "${e}" in the requested IP family.`);Object.assign(t,{code:`ENOTFOUND`}),n(t,``,0);return}if(t.all===!0){n(null,a);return}let o=a[0];n(null,o.address,o.family)})}}async function consumeResponse(e,t){let n=parseContentLength(e.headers.get(`content-length`));if(n!==void 0&&n>t)throw await cancelResponseBody(e),createResponseTooLargeError(t);let r=await readBoundedBody(e,t),i=r.byteLength===0?null:Uint8Array.from(r).buffer;return new Response(i,{headers:e.headers,status:e.status,statusText:e.statusText})}function parseContentLength(e){if(e===null)return;let t=Number.parseInt(e,10);return Number.isFinite(t)&&t>=0?t:void 0}async function readBoundedBody(e,t){if(e.body===null)return new Uint8Array;let n=e.body.getReader(),r=[],i=0;try{for(;;){let{done:e,value:a}=await n.read();if(e)break;if(i+=a.byteLength,i>t)throw await n.cancel(),createResponseTooLargeError(t);r.push(a)}}finally{n.releaseLock()}let a=new Uint8Array(i),o=0;for(let e of r)a.set(e,o),o+=e.byteLength;return a}async function cancelResponseBody(e){try{await e.body?.cancel()}catch{}}function createResponseTooLargeError(e){return Error(`Response too large (exceeds ${e} bytes).`)}export{requestPublicUrl};
@@ -1,4 +1,4 @@
1
- import type { CancelTurnInput, CancelTurnResult, DispatchSessionInput, Runtime, SessionCommand, SessionCommandResult } from "#channel/types.js";
1
+ import type { DispatchSessionInput, Runtime, SessionCommand, SessionCommandResult } from "#channel/types.js";
2
2
  import { type Run, type StartOptionsWithoutDeploymentId, type WorkflowFunction, type WorkflowMetadata } from "#internal/workflow/runtime.js";
3
3
  import type { RuntimeCompiledArtifactsSource } from "#runtime/compiled-artifacts-source.js";
4
4
  import { type SessionHandoffStart } from "#execution/session/entry-input.js";
@@ -48,14 +48,29 @@ export declare function startSessionOwnerStep(input: SessionOwnerStartInput): Pr
48
48
  * stranded one is refused rather than replaced.
49
49
  */
50
50
  export declare function dispatchWorkflowSessionCommand<TCommand extends SessionCommand>(input: DispatchSessionInput<TCommand>): Promise<SessionCommandResult<TCommand>>;
51
- /** Requests cancellation through a session's stable command inbox. */
52
- export declare function requestWorkflowTurnCancellation(input: CancelTurnInput): Promise<CancelTurnResult>;
51
+ /** The session holding a continuation token's inbox, if any does. */
52
+ export declare function resolveContinuation(continuationToken: string): Promise<{
53
+ sessionId: string;
54
+ } | undefined>;
53
55
  /**
54
56
  * Resolves hook ownership for replay-idempotent work already running inside a
55
57
  * durable step. Request handlers must return from start/resume acceptance and
56
58
  * leave ownership arbitration to the workflow.
57
59
  */
58
60
  export declare function waitForCommandHookOwner(token: string): Promise<WorkflowHookRecord>;
61
+ /**
62
+ * Waits until a started session claims its inbox, which it does when its run
63
+ * first suspends. Resolves `false` when the run ended without an inbox, so
64
+ * there is nothing left to command.
65
+ */
66
+ export declare function waitForSessionInbox(sessionId: string): Promise<boolean>;
67
+ /**
68
+ * Calls `check` until it returns a value, backing off from 20 ms to 200 ms
69
+ * between calls, and resolves `undefined` once `timeoutMs` passes without one.
70
+ */
71
+ export declare function pollUntil<T>(check: () => Promise<T | undefined>, timeoutMs: number): Promise<T | undefined>;
72
+ /** A run `start()` accepted may not be readable yet, which is not an ended run. */
73
+ export declare function hasRunEnded(runId: string): Promise<boolean>;
59
74
  /** Starts a workflow on the deployment executing this call. */
60
75
  export declare function startWorkflowOnCurrentDeployment<TArgs extends unknown[], TResult>(workflow: WorkflowFunction<TArgs, TResult> | WorkflowMetadata, args: TArgs, options?: StartOptionsWithoutDeploymentId): Promise<Run<unknown> | Run<TResult>>;
61
76
  export {};
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{SessionPredecessorKey}from"#context/keys.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{walkCauseChain}from"#shared/errors.js";import{validateToolStubTargets}from"#tool-stubs/validate-targets.js";import{getHookByToken,getRun,getWorld,start}from"#internal/workflow/runtime.js";import{SessionStrandedError,describeStrandedSession}from"#channel/session-stranded-error.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{ROOT_RUNTIME_AGENT_NODE_ID}from"#runtime/graph.js";import{serializeContext}from"#context/serialize.js";import{AcceptedSessionIdentityError,SessionHandoffPendingError,logicalSessionToken,resolveSessionInbox,resumeSessionInbox}from"#execution/session-inbox/resume.js";import{resolveEffectiveAgentRuntime}from"#execution/effective-agent-config.js";import{context,trace}from"#compiled/@opentelemetry/api/index.js";import{EntityConflictError,HookNotFoundError,RunExpiredError,WorkflowRunNotFoundError}from"#compiled/@workflow/errors/index.js";import{StrandedSessionOwnerError,assertRunnableSessionInbox}from"#execution/session-inbox/owner.js";import{initializeSessionInstrumentation}from"#instrumentation/runtime.js";import{EVE_VERSION_ATTRIBUTE,buildSessionAttributes,buildSubagentRootAttributes,readParentLineage}from"#execution/eve-workflow-attributes.js";import{endStrandedSession}from"#execution/session-inbox/end-stranded-session.js";import{SESSION_HOOK_HANDOVER_TIMEOUT_MS,waitForSessionHooksRelease}from"#execution/session-inbox/hook-release.js";import{SESSION_TIMEOUT_WORKFLOW_NAME,WORKFLOW_ENTRY_NAME,WORKFLOW_TOOL_RUN_WORKFLOW_NAME}from"#execution/stable-workflow-names.js";import{normalizeEveAttributes}from"#runtime/attributes/normalize.js";import{buildRunContext}from"#execution/runtime-context.js";import{readSessionEventHistory,readSessionEventStream,readSessionStreamTailIndex}from"#execution/session-event-stream.js";import{SESSION_HANDOFF_VERSION}from"#execution/session/entry-input.js";import{buildInvocationAttributes}from"#internal/invocation/metadata.js";import{isAgentTraceContext}from"#tracing/agent-trace-context.js";const EVE_PACKAGE_INFO=resolveInstalledPackageInfo(),STABLE_ID_BASE=EVE_PACKAGE_INFO.name,log=createLogger(`execution.workflow-runtime`),workflowEntryReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_ENTRY_NAME}`},sessionTimeoutWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${SESSION_TIMEOUT_WORKFLOW_NAME}`},workflowToolRunWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_TOOL_RUN_WORKFLOW_NAME}`};function createWorkflowRuntime(e){let startSession=async(t,n)=>{let r=await getCompiledRuntimeAgentBundle({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:e.nodeId});t.toolStubs!==void 0&&t.toolStubs.rootSessionId===void 0&&validateToolStubTargets(t.toolStubs.rules,r.graph);let i=buildRunContext({bundle:r,dynamicSubagentAgentConfig:e.dynamicSubagentAgentConfig,run:t});n!==void 0&&i.set(SessionPredecessorKey,n);let a=resolveEffectiveAgentRuntime(r,i);initializeSessionInstrumentation({agentName:a.turnAgent.id,ctx:i});let o=a.limits?.sessionTimeoutMs,s=r.resolvedAgent.config?.experimental?.workflow?.retention,c=serializeContext(i),l=readParentLineage(c),u={kind:`initial`,input:t.input,ownerDeploymentId:await resolveCurrentWorkflowDeploymentId(),serializedContext:c};t.limits!==void 0&&(u.limits=t.limits),t.continuationConflictCommand!==void 0&&(u.continuationConflictCommand=t.continuationConflictCommand),o!==void 0&&(u.sessionTimeoutMs=o),s!==void 0&&(u.retention=s);let d={...l.sessionId===void 0?buildSessionAttributes({serializedContext:c}):buildSubagentRootAttributes({identity:{nodeId:r.nodeId??ROOT_RUNTIME_AGENT_NODE_ID},parentCallId:l.callId,parentSessionId:l.sessionId,parentTurnId:l.turnId,rootSessionId:l.rootSessionId??l.sessionId,serializedContext:c}),...t.externalInvocation===void 0?{}:buildInvocationAttributes(t.externalInvocation)},f;try{let e={allowReservedAttributes:!0,attributes:normalizeEveAttributes(d)};s!==void 0&&(e.experimental_retention=s),f=await startWorkflowOnDeployment(workflowEntryReference,[u],u.ownerDeploymentId,e)}catch(e){throw logError(log,`failed to start workflow run`,e,{continuationToken:t.continuationToken}),e}let p,getEvents=()=>(p??=readSessionEventStream(f.runId),p);return{get events(){return getEvents()},sessionId:f.runId}};return{async createSession(e){return await startSession(e)},async dispatchContinuation(e){let{command:t,continuationToken:n,successor:r}=e;try{return await dispatchWorkflowCommand(n,t)}catch(e){if(!(e instanceof StrandedSessionOwnerError))throw e;if(t.kind!==`send`||r===void 0)return await settleStrandedCommand(n,t,e);if((t.payload.inputResponses?.length??0)>0)throw sessionStrandedError(e,`Its pending requests can no longer be answered; send a new message to start a fresh session.`);let i=await endStrandedSession(e,n,`message`);return{sessionId:(await startSession(r,{sessionId:i})).sessionId,status:`accepted`}}},async dispatchSession(e){return await dispatchWorkflowSessionCommand(e)},async getEventStream(e,t){if(t?.follow===!1)return readSessionEventHistory(e,t.startIndex);try{await assertRunnableSessionInbox(sessionInboxHookToken(sessionCommandHookToken(e)))}catch(e){throw e instanceof StrandedSessionOwnerError?sessionStrandedError(e):e}return readSessionEventStream(e,t?.startIndex)},async getStreamTailIndex(e){return await readSessionStreamTailIndex(e)},async resolveContinuation(e){try{return await resolveSessionInbox(e)}catch(t){if(HookNotFoundError.is(t))return;throw logError(log,`failed to resolve session by continuation token`,t,{continuationToken:e}),t}}}}async function startSessionOwnerStep(e){"use step";let{activationToken:t,anchorRunId:n,checkpoint:r,targetDeploymentId:i,...a}=e,o={...a,activationToken:t,checkpoint:r,handoffVersion:SESSION_HANDOFF_VERSION,kind:`handoff`,ownerDeploymentId:i,sessionWritable:getRun(n).getWritable(),sessionId:n};await startWorkflowOnDeployment(workflowEntryReference,[o],i,r.retention===void 0?void 0:{experimental_retention:r.retention})}async function dispatchWorkflowCommand(e,t){let n;try{let r=await resumeSessionInbox(e,t);n={runId:r.ownerRunId,sessionId:await r.sessionId}}catch(n){if(n instanceof StrandedSessionOwnerError)throw n;let r=t.kind===`send`&&typeof e!=`string`,i={status:`session_not_active`,retryable:!0};if(n instanceof SessionHandoffPendingError){if(r)return i;throw n}if(isInactiveCommandTarget(n))return r&&await isRunActive(e.sessionId)?i:inactiveCommandResult(t);throw logError(log,`failed to dispatch session command`,n,{command:t.kind,token:e}),n}return t.kind===`reset`&&await waitForSessionHooksRelease([sessionCommandHookToken(n.sessionId),logicalSessionToken(e)],n.runId),activeCommandResult(t,n.sessionId)}async function settleStrandedCommand(e,t,n){switch(t.kind){case`reset`:return{previousSessionId:await endStrandedSession(n,e,`reset`),status:`reset`};case`send`:case`clear`:throw sessionStrandedError(n);default:return inactiveCommandResult(t)}}function sessionStrandedError(e,t){let n=e.eveVersion===void 0?{}:{eveVersion:e.eveVersion};return new SessionStrandedError(n,describeStrandedSession(n,t))}function activeCommandResult(e,t){return e.kind===`reset`?{previousSessionId:t,status:`reset`}:e.kind===`send`&&e.delivery!==void 0?{sessionId:t,status:`accepted`,deliveryId:e.delivery.deliveryId}:{sessionId:t,status:`accepted`}}function inactiveCommandResult(e){return e.kind===`send`?{status:`session_not_active`}:e.kind===`cancel`?{status:`no_active_turn`}:{status:`no_active_session`}}async function dispatchWorkflowSessionCommand(e){let t={sessionId:e.sessionId};try{return await dispatchWorkflowCommand(t,e.command)}catch(n){if(!(n instanceof StrandedSessionOwnerError))throw n;return await settleStrandedCommand(t,e.command,n)}}async function requestWorkflowTurnCancellation(e){let t={kind:`cancel`};return e.turnId!==void 0&&(t.turnId=e.turnId),await dispatchWorkflowSessionCommand({command:t,sessionId:e.sessionId})}async function isRunActive(e){try{let t=await getRun(e).status;return t===`pending`||t===`running`}catch(e){if(isInactiveCommandTarget(e))return!1;throw e}}function isInactiveCommandTarget(e){if(e instanceof AcceptedSessionIdentityError)return!1;if(HookNotFoundError.is(e))return!0;for(let t of walkCauseChain(e))if(WorkflowRunNotFoundError.is(t)||RunExpiredError.is(t)||EntityConflictError.is(t))return!0;return!1}async function waitForCommandHookOwner(e){let t=Date.now()+SESSION_HOOK_HANDOVER_TIMEOUT_MS;for(;;)try{return normalizeWorkflowHook(await getHookByToken(e))}catch(e){if(!HookNotFoundError.is(e)||Date.now()>=t)throw e;await new Promise(e=>setTimeout(e,20))}}async function startWorkflowOnCurrentDeployment(e,t,n){return await startWorkflowOnDeployment(e,t,await resolveCurrentWorkflowDeploymentId(),n)}async function startWorkflowOnDeployment(e,t,n,r){return await withWorkflowStartContext(async()=>{if(n.length===0||n===`latest`)throw Error(`Workflow starts require an exact deployment id.`);return await start(e,t,{...r,allowReservedAttributes:!0,attributes:{...r?.attributes,[EVE_VERSION_ATTRIBUTE]:EVE_PACKAGE_INFO.version},deploymentId:n})})}async function resolveCurrentWorkflowDeploymentId(){let e=process.env.VERCEL_DEPLOYMENT_ID?.trim()||await(await getWorld()).getDeploymentId();if(e.length===0||e===`latest`)throw Error(`Workflow runtime could not resolve an exact deployment id.`);return e}async function withWorkflowStartContext(e){let t=context.active(),n=isAgentTraceContext(t)?trace.deleteSpan(t):t;return await context.with(n,e)}function normalizeWorkflowHook(e){if(typeof e!=`object`||!e||!(`runId`in e))throw Error(`Workflow hook did not include a run id.`);let t=e.runId;if(typeof t!=`string`||t.length===0)throw Error(`Workflow hook did not include a run id.`);return{runId:t}}export{createWorkflowRuntime,dispatchWorkflowSessionCommand,requestWorkflowTurnCancellation,sessionTimeoutWorkflowReference,startSessionOwnerStep,startWorkflowOnCurrentDeployment,waitForCommandHookOwner,workflowEntryReference,workflowToolRunWorkflowReference};
1
+ import{createLogger,logError}from"#internal/logging.js";import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{SessionPredecessorKey}from"#context/keys.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{walkCauseChain}from"#shared/errors.js";import{validateToolStubTargets}from"#tool-stubs/validate-targets.js";import{getHookByToken,getRun,getWorld,start}from"#internal/workflow/runtime.js";import{SessionStrandedError,describeStrandedSession}from"#channel/session-stranded-error.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{ROOT_RUNTIME_AGENT_NODE_ID}from"#runtime/graph.js";import{serializeContext}from"#context/serialize.js";import{AcceptedSessionIdentityError,SessionHandoffPendingError,logicalSessionToken,resolveSessionInbox,resumeSessionInbox}from"#execution/session-inbox/resume.js";import{resolveEffectiveAgentRuntime}from"#execution/effective-agent-config.js";import{context,trace}from"#compiled/@opentelemetry/api/index.js";import{EntityConflictError,HookNotFoundError,RunExpiredError,WorkflowRunNotFoundError}from"#compiled/@workflow/errors/index.js";import{StrandedSessionOwnerError,assertRunnableSessionInbox,findSessionHookHolder}from"#execution/session-inbox/owner.js";import{initializeSessionInstrumentation}from"#instrumentation/runtime.js";import{EVE_VERSION_ATTRIBUTE,buildSessionAttributes,buildSubagentRootAttributes,readParentLineage}from"#execution/eve-workflow-attributes.js";import{endStrandedSession}from"#execution/session-inbox/end-stranded-session.js";import{SESSION_HOOK_HANDOVER_TIMEOUT_MS,waitForSessionHooksRelease}from"#execution/session-inbox/hook-release.js";import{SESSION_TIMEOUT_WORKFLOW_NAME,WORKFLOW_ENTRY_NAME,WORKFLOW_TOOL_RUN_WORKFLOW_NAME}from"#execution/stable-workflow-names.js";import{normalizeEveAttributes}from"#runtime/attributes/normalize.js";import{buildRunContext}from"#execution/runtime-context.js";import{readSessionEventHistory,readSessionEventStream,readSessionStreamTailIndex}from"#execution/session-event-stream.js";import{SESSION_HANDOFF_VERSION}from"#execution/session/entry-input.js";import{buildInvocationAttributes}from"#internal/invocation/metadata.js";import{isAgentTraceContext}from"#tracing/agent-trace-context.js";const EVE_PACKAGE_INFO=resolveInstalledPackageInfo(),STABLE_ID_BASE=EVE_PACKAGE_INFO.name,log=createLogger(`execution.workflow-runtime`),workflowEntryReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_ENTRY_NAME}`},sessionTimeoutWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${SESSION_TIMEOUT_WORKFLOW_NAME}`},workflowToolRunWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_TOOL_RUN_WORKFLOW_NAME}`};function createWorkflowRuntime(e){let startSession=async(t,n)=>{let r=await getCompiledRuntimeAgentBundle({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:e.nodeId});t.toolStubs!==void 0&&t.toolStubs.rootSessionId===void 0&&validateToolStubTargets(t.toolStubs.rules,r.graph);let i=buildRunContext({bundle:r,dynamicSubagentAgentConfig:e.dynamicSubagentAgentConfig,run:t});n!==void 0&&i.set(SessionPredecessorKey,n);let a=resolveEffectiveAgentRuntime(r,i);initializeSessionInstrumentation({agentName:a.turnAgent.id,ctx:i});let o=a.limits?.sessionTimeoutMs,s=r.resolvedAgent.config?.experimental?.workflow?.retention,c=serializeContext(i),l=readParentLineage(c),u={kind:`initial`,input:t.input,ownerDeploymentId:await resolveCurrentWorkflowDeploymentId(),serializedContext:c};t.limits!==void 0&&(u.limits=t.limits),t.continuationConflictCommand!==void 0&&(u.continuationConflictCommand=t.continuationConflictCommand),o!==void 0&&(u.sessionTimeoutMs=o),s!==void 0&&(u.retention=s);let d={...l.sessionId===void 0?buildSessionAttributes({serializedContext:c}):buildSubagentRootAttributes({identity:{nodeId:r.nodeId??ROOT_RUNTIME_AGENT_NODE_ID},parentCallId:l.callId,parentSessionId:l.sessionId,parentTurnId:l.turnId,rootSessionId:l.rootSessionId??l.sessionId,serializedContext:c}),...t.externalInvocation===void 0?{}:buildInvocationAttributes(t.externalInvocation)},f;try{let e={allowReservedAttributes:!0,attributes:normalizeEveAttributes(d)};s!==void 0&&(e.experimental_retention=s),f=await startWorkflowOnDeployment(workflowEntryReference,[u],u.ownerDeploymentId,e)}catch(e){throw logError(log,`failed to start workflow run`,e,{continuationToken:t.continuationToken}),e}let p,getEvents=()=>(p??=readSessionEventStream(f.runId),p);return{get events(){return getEvents()},sessionId:f.runId}};return{async createSession(e){return await startSession(e)},async dispatchContinuation(e){let{command:t,continuationToken:n,successor:r}=e;try{return await dispatchWorkflowCommand(n,t)}catch(e){if(!(e instanceof StrandedSessionOwnerError))throw e;if(t.kind!==`send`||r===void 0)return await settleStrandedCommand(n,t,e);if((t.payload.inputResponses?.length??0)>0)throw sessionStrandedError(e,`Its pending requests can no longer be answered; send a new message to start a fresh session.`);let i=await endStrandedSession(e,n,`message`);return{sessionId:(await startSession(r,{sessionId:i})).sessionId,status:`accepted`}}},async dispatchSession(e){return await dispatchWorkflowSessionCommand(e)},async getEventStream(e,t){if(t?.follow===!1)return readSessionEventHistory(e,t.startIndex);try{await assertRunnableSessionInbox(sessionInboxHookToken(sessionCommandHookToken(e)))}catch(e){throw e instanceof StrandedSessionOwnerError?sessionStrandedError(e):e}return readSessionEventStream(e,t?.startIndex)},async getStreamTailIndex(e){return await readSessionStreamTailIndex(e)},resolveContinuation}}async function startSessionOwnerStep(e){"use step";let{activationToken:t,anchorRunId:n,checkpoint:r,targetDeploymentId:i,...a}=e,o={...a,activationToken:t,checkpoint:r,handoffVersion:SESSION_HANDOFF_VERSION,kind:`handoff`,ownerDeploymentId:i,sessionWritable:getRun(n).getWritable(),sessionId:n};await startWorkflowOnDeployment(workflowEntryReference,[o],i,r.retention===void 0?void 0:{experimental_retention:r.retention})}async function dispatchWorkflowCommand(e,t){let n;try{let r=await resumeSessionInbox(e,t);n={runId:r.ownerRunId,sessionId:await r.sessionId}}catch(n){if(n instanceof StrandedSessionOwnerError)throw n;let r=t.kind===`send`&&typeof e!=`string`,i={status:`session_not_active`,retryable:!0};if(n instanceof SessionHandoffPendingError){if(r)return i;throw n}if(isInactiveCommandTarget(n))return r&&await isRunActive(e.sessionId)?i:inactiveCommandResult(t);throw logError(log,`failed to dispatch session command`,n,{command:t.kind,token:e}),n}return t.kind===`reset`&&await waitForSessionHooksRelease([sessionCommandHookToken(n.sessionId),logicalSessionToken(e)],n.runId),activeCommandResult(t,n.sessionId)}async function settleStrandedCommand(e,t,n){switch(t.kind){case`reset`:return{previousSessionId:await endStrandedSession(n,e,`reset`),status:`reset`};case`send`:case`clear`:throw sessionStrandedError(n);default:return inactiveCommandResult(t)}}function sessionStrandedError(e,t){let n=e.eveVersion===void 0?{}:{eveVersion:e.eveVersion};return new SessionStrandedError(n,describeStrandedSession(n,t))}function activeCommandResult(e,t){return e.kind===`reset`?{previousSessionId:t,status:`reset`}:e.kind===`send`&&e.delivery!==void 0?{sessionId:t,status:`accepted`,deliveryId:e.delivery.deliveryId}:{sessionId:t,status:`accepted`}}function inactiveCommandResult(e){return e.kind===`send`?{status:`session_not_active`}:e.kind===`cancel`?{status:`no_active_turn`}:{status:`no_active_session`}}async function dispatchWorkflowSessionCommand(e){let t={sessionId:e.sessionId};try{return await dispatchWorkflowCommand(t,e.command)}catch(n){if(!(n instanceof StrandedSessionOwnerError))throw n;return await settleStrandedCommand(t,e.command,n)}}async function isRunActive(e){try{let t=await getRun(e).status;return t===`pending`||t===`running`}catch(e){if(isInactiveCommandTarget(e))return!1;throw e}}function isInactiveCommandTarget(e){if(e instanceof AcceptedSessionIdentityError)return!1;if(HookNotFoundError.is(e))return!0;for(let t of walkCauseChain(e))if(WorkflowRunNotFoundError.is(t)||RunExpiredError.is(t)||EntityConflictError.is(t))return!0;return!1}async function resolveContinuation(e){try{return await resolveSessionInbox(e)}catch(t){if(HookNotFoundError.is(t))return;throw logError(log,`failed to resolve session by continuation token`,t,{continuationToken:e}),t}}async function waitForCommandHookOwner(e){let t=await pollUntil(async()=>{try{return normalizeWorkflowHook(await getHookByToken(e))}catch(e){if(!HookNotFoundError.is(e))throw e;return}},SESSION_HOOK_HANDOVER_TIMEOUT_MS);if(t===void 0)throw new HookNotFoundError(e);return t}async function waitForSessionInbox(e){let t=sessionInboxHookToken(sessionCommandHookToken(e)),n=await pollUntil(async()=>await findSessionHookHolder(t)!==void 0||!await hasRunEnded(e)&&void 0,SESSION_HOOK_HANDOVER_TIMEOUT_MS);if(n===void 0)throw Error(`Session "${e}" did not start taking commands within ${SESSION_HOOK_HANDOVER_TIMEOUT_MS/1e3} seconds.`);return n}async function pollUntil(e,t){let n=Date.now()+t;for(let t=20;;t=Math.min(t*2,200)){let r=await e();if(r!==void 0||Date.now()>=n)return r;await new Promise(e=>setTimeout(e,t))}}async function hasRunEnded(e){try{let t=await getRun(e).status;return t!==`pending`&&t!==`running`}catch(e){for(let t of walkCauseChain(e))if(WorkflowRunNotFoundError.is(t))return!1;if(isInactiveCommandTarget(e))return!0;throw e}}async function startWorkflowOnCurrentDeployment(e,t,n){return await startWorkflowOnDeployment(e,t,await resolveCurrentWorkflowDeploymentId(),n)}async function startWorkflowOnDeployment(e,t,n,r){return await withWorkflowStartContext(async()=>{if(n.length===0||n===`latest`)throw Error(`Workflow starts require an exact deployment id.`);return await start(e,t,{...r,allowReservedAttributes:!0,attributes:{...r?.attributes,[EVE_VERSION_ATTRIBUTE]:EVE_PACKAGE_INFO.version},deploymentId:n})})}async function resolveCurrentWorkflowDeploymentId(){let e=process.env.VERCEL_DEPLOYMENT_ID?.trim()||await(await getWorld()).getDeploymentId();if(e.length===0||e===`latest`)throw Error(`Workflow runtime could not resolve an exact deployment id.`);return e}async function withWorkflowStartContext(e){let t=context.active(),n=isAgentTraceContext(t)?trace.deleteSpan(t):t;return await context.with(n,e)}function normalizeWorkflowHook(e){if(typeof e!=`object`||!e||!(`runId`in e))throw Error(`Workflow hook did not include a run id.`);let t=e.runId;if(typeof t!=`string`||t.length===0)throw Error(`Workflow hook did not include a run id.`);return{runId:t}}export{createWorkflowRuntime,dispatchWorkflowSessionCommand,hasRunEnded,pollUntil,resolveContinuation,sessionTimeoutWorkflowReference,startSessionOwnerStep,startWorkflowOnCurrentDeployment,waitForCommandHookOwner,waitForSessionInbox,workflowEntryReference,workflowToolRunWorkflowReference};