eve 0.77.0 → 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 (94) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/src/compiled/.vendor-stamp.json +1 -1
  3. package/dist/src/context/keys.d.ts +16 -0
  4. package/dist/src/context/keys.js +1 -1
  5. package/dist/src/execution/agent-sessions/steps.d.ts +2 -0
  6. package/dist/src/execution/agent-sessions/steps.js +1 -1
  7. package/dist/src/execution/cancelled-model-call-batch.js +1 -1
  8. package/dist/src/execution/catalog/search.js +1 -1
  9. package/dist/src/execution/catalog/step-catalog.d.ts +12 -3
  10. package/dist/src/execution/catalog/step-catalog.js +1 -1
  11. package/dist/src/execution/coordination-dispatch-shared.d.ts +1 -2
  12. package/dist/src/execution/coordination-dispatch-shared.js +1 -1
  13. package/dist/src/execution/coordination-dispatch-step.js +1 -1
  14. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  15. package/dist/src/execution/sandbox/bindings/docker-container.js +1 -1
  16. package/dist/src/execution/sandbox/bindings/docker.js +1 -1
  17. package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
  18. package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
  19. package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
  20. package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
  21. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  22. package/dist/src/execution/sandbox/session.d.ts +6 -0
  23. package/dist/src/execution/sandbox/session.js +2 -2
  24. package/dist/src/execution/session/active-turn.d.ts +9 -1
  25. package/dist/src/execution/session/active-turn.js +1 -1
  26. package/dist/src/execution/session/checkpoint-migrations.js +1 -1
  27. package/dist/src/execution/session/handoff.d.ts +1 -1
  28. package/dist/src/execution/session/handoff.js +1 -1
  29. package/dist/src/execution/session/next-input.js +1 -1
  30. package/dist/src/execution/session/turn.d.ts +11 -4
  31. package/dist/src/execution/session/turn.js +1 -1
  32. package/dist/src/execution/session-inbox/inbox.d.ts +3 -0
  33. package/dist/src/execution/session-inbox/inbox.js +1 -1
  34. package/dist/src/execution/session-workflow-tool-run.d.ts +14 -12
  35. package/dist/src/execution/session-workflow-tool-run.js +1 -1
  36. package/dist/src/execution/tasks/start.d.ts +14 -1
  37. package/dist/src/execution/tasks/start.js +1 -1
  38. package/dist/src/execution/tasks/steps.d.ts +7 -4
  39. package/dist/src/execution/tasks/steps.js +1 -1
  40. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  41. package/dist/src/execution/tools/workflow/apply-run-messages-step.d.ts +20 -0
  42. package/dist/src/execution/tools/workflow/apply-run-messages-step.js +1 -0
  43. package/dist/src/execution/tools/workflow/ask.d.ts +0 -1
  44. package/dist/src/execution/tools/workflow/ask.js +1 -1
  45. package/dist/src/execution/tools/workflow/interrupt.d.ts +5 -2
  46. package/dist/src/execution/tools/workflow/interrupt.js +1 -1
  47. package/dist/src/execution/tools/workflow/messages.d.ts +14 -0
  48. package/dist/src/execution/tools/workflow/messages.js +1 -1
  49. package/dist/src/execution/tools/workflow/owner.d.ts +18 -6
  50. package/dist/src/execution/tools/workflow/owner.js +1 -1
  51. package/dist/src/execution/tools/workflow/start.d.ts +10 -0
  52. package/dist/src/execution/tools/workflow/start.js +1 -1
  53. package/dist/src/execution/tools/workflow/step.js +1 -1
  54. package/dist/src/execution/tools/workflow/workflow-owner-blocking.d.ts +12 -0
  55. package/dist/src/execution/tools/workflow/workflow-owner-blocking.js +1 -1
  56. package/dist/src/execution/tools/workflow/workflow.js +1 -1
  57. package/dist/src/execution/workflow-runtime.d.ts +18 -3
  58. package/dist/src/execution/workflow-runtime.js +1 -1
  59. package/dist/src/harness/hitl/approvals.d.ts +4 -7
  60. package/dist/src/harness/hitl/approvals.js +1 -1
  61. package/dist/src/harness/hitl/approved-calls.d.ts +11 -0
  62. package/dist/src/harness/hitl/approved-calls.js +1 -1
  63. package/dist/src/harness/hitl/candidates.d.ts +0 -4
  64. package/dist/src/harness/hitl/candidates.js +1 -1
  65. package/dist/src/harness/hitl/delivery.d.ts +0 -1
  66. package/dist/src/harness/hitl/delivery.js +1 -1
  67. package/dist/src/harness/hitl/index.d.ts +2 -2
  68. package/dist/src/harness/hitl/index.js +1 -1
  69. package/dist/src/harness/hitl/intake.d.ts +2 -2
  70. package/dist/src/harness/hitl/intake.js +1 -1
  71. package/dist/src/harness/model-call/call.js +1 -1
  72. package/dist/src/harness/model-call/run.js +1 -1
  73. package/dist/src/harness/session-machine/state.d.ts +0 -2
  74. package/dist/src/harness/session-machine/view.d.ts +0 -3
  75. package/dist/src/harness/session-machine/view.js +1 -1
  76. package/dist/src/harness/step/after-model.js +1 -1
  77. package/dist/src/harness/tool-loop.js +1 -1
  78. package/dist/src/harness/tools.js +1 -1
  79. package/dist/src/internal/application/stamped-package-version.js +1 -1
  80. package/dist/src/setup/scaffold/create/project.js +1 -1
  81. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  82. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  83. package/docs/agent-config.md +12 -4
  84. package/docs/concepts/built-in-tools.md +9 -9
  85. package/docs/guides/dynamic-capabilities.md +6 -2
  86. package/docs/sandbox/index.mdx +2 -0
  87. package/docs/tools/human-in-the-loop.md +1 -1
  88. package/package.json +1 -1
  89. package/dist/src/context/caller-scope.d.ts +0 -7
  90. package/dist/src/context/caller-scope.js +0 -1
  91. package/dist/src/execution/tools/workflow/emit-workflow-tool-run-report-step.d.ts +0 -13
  92. package/dist/src/execution/tools/workflow/emit-workflow-tool-run-report-step.js +0 -1
  93. package/dist/src/harness/hitl/approved-call-callers.d.ts +0 -14
  94. package/dist/src/harness/hitl/approved-call-callers.js +0 -1
@@ -4,6 +4,12 @@ type NetworkPolicySandboxSession = SandboxSession & {
4
4
  };
5
5
  import type { InternalSandboxSession, SandboxSession } from "#shared/sandbox-session.js";
6
6
  export type { InternalSandboxSession };
7
+ /**
8
+ * Tells agent-aware CLIs (such as `vercel`) that an automated agent runs
9
+ * the command, so they skip interactive prompts. Built-in providers apply it
10
+ * beneath environment-level and per-call env so authors can override it.
11
+ */
12
+ export declare const SANDBOX_AGENT_ENV: Readonly<Record<string, string>>;
7
13
  /**
8
14
  * Builds a public {@link SandboxSession} from provider-specific primitives.
9
15
  *
@@ -1,3 +1,3 @@
1
- import{bufferToStream,streamToBuffer}from"./stream-utils.js";function buildSandboxSession(e,t){async function run(t){let n=await e.spawn(t),[r,i,{exitCode:a}]=await Promise.all([collectStreamToString(n.stdout),collectStreamToString(n.stderr),n.wait()]);return{exitCode:a,stderr:i,stdout:r}}let n={resolvePath(t){return e.resolvePath(t)},run,async spawn(t){return await e.spawn(t)},async readFile(t){return await e.readFile({abortSignal:t.abortSignal,path:e.resolvePath(t.path)})},async readBinaryFile(t){let n=await e.readFile({abortSignal:t.abortSignal,path:e.resolvePath(t.path)});return n===null?null:await streamToBuffer(n)},async readTextFile(t){validateReadTextFileOptions(t);let n=await e.readFile({abortSignal:t.abortSignal,path:e.resolvePath(t.path)});return n===null?null:applyLineRange(decodeBytes(await streamToBuffer(n),t.encoding??`utf-8`),t)},async writeFile(t){await e.writeFile({abortSignal:t.abortSignal,content:t.content,path:e.resolvePath(t.path)})},async writeBinaryFile(t){await e.writeFile({abortSignal:t.abortSignal,content:bufferToStream(t.content),path:e.resolvePath(t.path)})},async writeTextFile(t){let n=encodeString(t.content,t.encoding??`utf-8`);await e.writeFile({abortSignal:t.abortSignal,content:bufferToStream(n),path:e.resolvePath(t.path)})},async removePath(t){await e.removePath({abortSignal:t.abortSignal,force:t.force,path:e.resolvePath(t.path),recursive:t.recursive})}};return t===void 0?n:{...n,setNetworkPolicy:t}}async function collectStreamToString(e){let t=await streamToBuffer(e);return new TextDecoder().decode(t)}function validateReadTextFileOptions(e){let{startLine:t,endLine:n}=e;if(t!==void 0&&(!Number.isInteger(t)||t<1))throw Error(`startLine must be a positive integer (1-based).`);if(n!==void 0&&(!Number.isInteger(n)||n<1))throw Error(`endLine must be a positive integer (1-based).`);if(t!==void 0&&n!==void 0&&t>n)throw Error(`startLine must not be greater than endLine.`)}function splitLinesPreservingEndings(e){let t=[],n=0;for(let r=0;r<e.length;r++)e[r]===`\r`?r+1<e.length&&e[r+1]===`
1
+ import{bufferToStream,streamToBuffer}from"./stream-utils.js";const SANDBOX_AGENT_ENV={AI_AGENT:`eve`};function buildSandboxSession(e,t){async function run(t){let n=await e.spawn(t),[r,i,{exitCode:a}]=await Promise.all([collectStreamToString(n.stdout),collectStreamToString(n.stderr),n.wait()]);return{exitCode:a,stderr:i,stdout:r}}let n={resolvePath(t){return e.resolvePath(t)},run,async spawn(t){return await e.spawn(t)},async readFile(t){return await e.readFile({abortSignal:t.abortSignal,path:e.resolvePath(t.path)})},async readBinaryFile(t){let n=await e.readFile({abortSignal:t.abortSignal,path:e.resolvePath(t.path)});return n===null?null:await streamToBuffer(n)},async readTextFile(t){validateReadTextFileOptions(t);let n=await e.readFile({abortSignal:t.abortSignal,path:e.resolvePath(t.path)});return n===null?null:applyLineRange(decodeBytes(await streamToBuffer(n),t.encoding??`utf-8`),t)},async writeFile(t){await e.writeFile({abortSignal:t.abortSignal,content:t.content,path:e.resolvePath(t.path)})},async writeBinaryFile(t){await e.writeFile({abortSignal:t.abortSignal,content:bufferToStream(t.content),path:e.resolvePath(t.path)})},async writeTextFile(t){let n=encodeString(t.content,t.encoding??`utf-8`);await e.writeFile({abortSignal:t.abortSignal,content:bufferToStream(n),path:e.resolvePath(t.path)})},async removePath(t){await e.removePath({abortSignal:t.abortSignal,force:t.force,path:e.resolvePath(t.path),recursive:t.recursive})}};return t===void 0?n:{...n,setNetworkPolicy:t}}async function collectStreamToString(e){let t=await streamToBuffer(e);return new TextDecoder().decode(t)}function validateReadTextFileOptions(e){let{startLine:t,endLine:n}=e;if(t!==void 0&&(!Number.isInteger(t)||t<1))throw Error(`startLine must be a positive integer (1-based).`);if(n!==void 0&&(!Number.isInteger(n)||n<1))throw Error(`endLine must be a positive integer (1-based).`);if(t!==void 0&&n!==void 0&&t>n)throw Error(`startLine must not be greater than endLine.`)}function splitLinesPreservingEndings(e){let t=[],n=0;for(let r=0;r<e.length;r++)e[r]===`\r`?r+1<e.length&&e[r+1]===`
2
2
  `?(t.push(e.slice(n,r+2)),n=r+2,r++):(t.push(e.slice(n,r+1)),n=r+1):e[r]===`
3
- `&&(t.push(e.slice(n,r+1)),n=r+1);return n<e.length&&t.push(e.slice(n)),t}function applyLineRange(e,t){if(t.startLine===void 0&&t.endLine===void 0)return e;let n=splitLinesPreservingEndings(e),r=n.length,i=t.startLine??1,a=Math.min(t.endLine??r,r);return i>r?``:n.slice(i-1,a).join(``)}function decodeBytes(e,t){return t===`utf-8`||t===`utf8`?new TextDecoder(`utf-8`,{fatal:!0}).decode(e):Buffer.from(e.buffer,e.byteOffset,e.byteLength).toString(t)}function encodeString(e,t){return t===`utf-8`||t===`utf8`?new TextEncoder().encode(e):Buffer.from(e,t)}export{buildSandboxSession};
3
+ `&&(t.push(e.slice(n,r+1)),n=r+1);return n<e.length&&t.push(e.slice(n)),t}function applyLineRange(e,t){if(t.startLine===void 0&&t.endLine===void 0)return e;let n=splitLinesPreservingEndings(e),r=n.length,i=t.startLine??1,a=Math.min(t.endLine??r,r);return i>r?``:n.slice(i-1,a).join(``)}function decodeBytes(e,t){return t===`utf-8`||t===`utf8`?new TextDecoder(`utf-8`,{fatal:!0}).decode(e):Buffer.from(e.buffer,e.byteOffset,e.byteLength).toString(t)}function encodeString(e,t){return t===`utf-8`||t===`utf8`?new TextEncoder().encode(e):Buffer.from(e,t)}export{SANDBOX_AGENT_ENV,buildSandboxSession};
@@ -2,7 +2,8 @@ import type { DeliverHookPayload, TurnCaller } from "#channel/types.js";
2
2
  import { type SteeringOptions } from "#execution/session/input-queue.js";
3
3
  import type { SessionExecutionInput } from "#execution/session/turn.js";
4
4
  import { type TurnControl } from "#execution/session/turn-control.js";
5
- import type { WorkflowToolRunMessage } from "#execution/tools/workflow/messages.js";
5
+ import { type WorkflowToolRunMessage } from "#execution/tools/workflow/messages.js";
6
+ import type { AppliedRunMessage } from "#execution/tools/workflow/apply-run-messages-step.js";
6
7
  import type { RuntimeActionResult } from "#shared/action-types.js";
7
8
  export type RuntimeEvent = {
8
9
  readonly kind: "runtime-action-result";
@@ -73,6 +74,13 @@ export declare class ActiveTurn {
73
74
  * in a runtime wait, or only those of `kind`.
74
75
  */
75
76
  takeBoundaryMessages(kind?: "agent-started"): WorkflowToolRunMessage[];
77
+ /**
78
+ * Removes the run messages read after one the session just took, as long as
79
+ * each is one it applies as it reads it and they fit one batch. Those it
80
+ * already admitted come first, then those still in the inbox, so arrival
81
+ * order holds.
82
+ */
83
+ takeAppliedRunMessages(): AppliedRunMessage[];
76
84
  /**
77
85
  * Next runtime result, workflow message, steering, or timeout, admitting
78
86
  * inbox traffic while waiting. Deliveries admitted before the wait began are
@@ -1 +1 @@
1
- import{coalesceDeliveries}from"#harness/messages.js";import{activeTurnId,storedProjection,turnPosition}from"#harness/session-machine/view.js";import{readDurableSession}from"#execution/durable-session-read.js";import{mapHeldInputResponsesStep}from"#execution/proxied-deliver-step.js";import{routeDeliverToChildren}from"#execution/route-child-delivery.js";import{admitSessionInboxPayload}from"#execution/session/admission.js";import{isSteeringDelivery,isSteeringMessage}from"#execution/session/input-queue.js";import{routeSelectedDelivery}from"#execution/session/route-selected-delivery.js";import{createTurnControl}from"#execution/session/turn-control.js";import{decodeSessionInboxPayload}from"#execution/session-inbox/protocol.js";import{TurnCancelledError}from"#harness/turn-cancellation.js";var ActiveTurn=class{admitted=new Set;routedToChildren=new Set;mappedForHeldRequest=new Set;runtimeResults=[];controller;expectedTurnId;input;identity;unsubscribe;unsubscribeDelivery;steeringController;caller;compacted=!1;constructor(e,t,n=createTurnControl()){this.controller=n.cancellation,this.steeringController=n.steering,this.input=e,this.caller=t.caller,this.identity={callerCallId:t.caller?.callId,principal:t.principal},this.expectedTurnId=activeTurnId(turnPosition(storedProjection(readDurableSession(e.cursor.sessionState).state))),this.unsubscribe=e.inbox.onInterrupt(e=>{this.cancelsThisTurn(e)&&this.abort()}),this.unsubscribeDelivery=e.inbox.onDelivery(this.signalSteering)}signalSteering=e=>{let t;try{t=decodeSessionInboxPayload(e)}catch{return}t.kind===`deliver`&&isSteeringMessage(t,this.identity)&&!this.input.cursor.sessionState.hasProxyInputRequests&&this.steeringController.abort()};get signal(){return this.controller.signal}dispose(){this.unsubscribe(),this.unsubscribeDelivery()}get steeringSignal(){return this.steeringController.signal}resetSteering(){this.steeringController.signal.aborted&&(this.unsubscribeDelivery(),this.steeringController=new AbortController,this.unsubscribeDelivery=this.input.inbox.onDelivery(this.signalSteering))}async admitBoundary(){let e=this.input.inbox.drain();for(let t of e)await this.admit(t)}async takeSteering(e){let t=[];for(;;){let n=this.input.queue.takeSteering(this.admitted,this.identity,e);if(n===void 0)break;for(let e of n.sequences)this.admitted.delete(e);let r=await routeSelectedDelivery(n,this.input.cursor);if(r.kind===`cancel-turn`){this.abort();break}r.kind===`turn`&&t.push(r.delivery)}if(this.resetSteering(),t.length===0)return;let n=t.length===1?t[0]:coalesceDeliveries(t);return n.caller!==void 0&&(this.caller=n.caller),n}takeBoundaryMessages(e){let t=[],n=[];for(let r of this.runtimeResults){let i=asBoundaryMessage(r);i===void 0||e!==void 0&&i.kind!==e?n.push(r):t.push(i)}return this.runtimeResults.splice(0,this.runtimeResults.length,...n),t}async nextRuntimeEvent(e){for(;;){let t=await this.routeAdmittedToChildren();if(this.signal.aborted)return`cancelled`;if(t)return{kind:`steering`};let n=this.runtimeResults.shift();if(n!==void 0)return n;let r=await this.waitForInboxOrTimer(e);if(r!==void 0)return{callId:r,kind:`timeout`};let i=await this.input.inbox.next();if(i===void 0)throw Error(`Session inbox closed before runtime actions completed.`);if(await this.admit(i))return{kind:`input`}}}async takeInputResponses(e){for(let t of this.admitted){let n=this.input.queue.delivery(t);if(n===void 0)continue;let r=n.payloads.flatMap(e=>e.inputResponses??[]);if(r.length===0)continue;if(!r.some(t=>e.has(t.requestId))){if(this.mappedForHeldRequest.has(t))continue;this.mappedForHeldRequest.add(t);let r=n,i=await this.input.cursor.advance(t=>mapHeldInputResponsesStep({delivery:r,requestIds:[...e],...t}));if(i.delivery===void 0)continue;n=i.delivery}this.admitted.delete(t);let i=isSteeringDelivery(n,this.identity,{heldOnPerson:!0})?void 0:splitAnswers(n);return this.input.queue.replaceDelivery(t,i?.rest),i?.answers??n}}async waitForInboxOrTimer(e){if(e.length===0||this.input.inbox.hasPending())return;let t=this.input.inbox.whenPending().then(()=>void 0);return await Promise.race([t,...e])}cancelsThisTurn(e){return e.kind===`reset`||e.kind===`session-failure`?!0:e.kind===`cancel`?e.turnId===void 0||e.turnId===this.expectedTurnId:!1}async admit(e){let t=await admitSessionInboxPayload(e,this.input);switch(t.kind){case`delivery`:return this.admitted.add(t.admission.sequence),!0;case`runtime-action-result`:return this.runtimeResults.push({kind:`runtime-action-result`,results:t.payload.results}),!1;case`workflow`:return this.runtimeResults.push({kind:`workflow`,message:t.message}),!1;case`cancel`:return this.cancelsThisTurn(e)&&this.abort(),!1;case`consumed`:return e.kind===`authorization-callback`}}async routeAdmittedToChildren(){let e=!1;for(let t of this.admitted){if(this.routedToChildren.has(t))continue;let n=this.input.queue.delivery(t);if(n===void 0){this.admitted.delete(t);continue}this.routedToChildren.add(t);let r=await this.input.cursor.advance(e=>routeDeliverToChildren({delivery:n,...e}));if(r.kind===`cancel-turn`)return this.input.queue.replaceDelivery(t,void 0),this.admitted.delete(t),this.abort(),!1;if(this.input.queue.replaceDelivery(t,r.remainder),r.remainder===void 0){this.admitted.delete(t);continue}isSteeringMessage(r.remainder,this.identity)&&(e=!0)}return e}abort(){this.controller.signal.aborted||this.controller.abort(new TurnCancelledError)}};function asBoundaryMessage(e){if(e!==`cancelled`&&e.kind===`workflow`&&(e.message.from.taskId!==void 0||e.message.kind===`agent-started`))return e.message}function splitAnswers(e){let t=e.payloads.flatMap(e=>e.inputResponses===void 0?[]:[{inputResponses:e.inputResponses}]),n=e.payloads.flatMap(e=>{let{inputResponses:t,...n}=e;return Object.keys(n).length===0?[]:[n]});return{answers:{...e,payloads:t},rest:n.length===0?void 0:{...e,payloads:n}}}export{ActiveTurn};
1
+ import{coalesceDeliveries}from"#harness/messages.js";import{activeTurnId,storedProjection,turnPosition}from"#harness/session-machine/view.js";import{readDurableSession}from"#execution/durable-session-read.js";import{mapHeldInputResponsesStep}from"#execution/proxied-deliver-step.js";import{routeDeliverToChildren}from"#execution/route-child-delivery.js";import{admitSessionInboxPayload}from"#execution/session/admission.js";import{isSteeringDelivery,isSteeringMessage}from"#execution/session/input-queue.js";import{routeSelectedDelivery}from"#execution/session/route-selected-delivery.js";import{createTurnControl}from"#execution/session/turn-control.js";import{decodeSessionInboxPayload}from"#execution/session-inbox/protocol.js";import{runMessageBatchBudget}from"#execution/tools/workflow/messages.js";import{isAppliedRunMessage,takeLeadingAppliedRunMessages}from"#execution/session-workflow-tool-run.js";import{TurnCancelledError}from"#harness/turn-cancellation.js";var ActiveTurn=class{admitted=new Set;routedToChildren=new Set;mappedForHeldRequest=new Set;runtimeResults=[];controller;expectedTurnId;input;identity;unsubscribe;unsubscribeDelivery;steeringController;caller;compacted=!1;constructor(e,t,n=createTurnControl()){this.controller=n.cancellation,this.steeringController=n.steering,this.input=e,this.caller=t.caller,this.identity={callerCallId:t.caller?.callId,principal:t.principal},this.expectedTurnId=activeTurnId(turnPosition(storedProjection(readDurableSession(e.cursor.sessionState).state))),this.unsubscribe=e.inbox.onInterrupt(e=>{this.cancelsThisTurn(e)&&this.abort()}),this.unsubscribeDelivery=e.inbox.onDelivery(this.signalSteering)}signalSteering=e=>{let t;try{t=decodeSessionInboxPayload(e)}catch{return}t.kind===`deliver`&&isSteeringMessage(t,this.identity)&&!this.input.cursor.sessionState.hasProxyInputRequests&&this.steeringController.abort()};get signal(){return this.controller.signal}dispose(){this.unsubscribe(),this.unsubscribeDelivery()}get steeringSignal(){return this.steeringController.signal}resetSteering(){this.steeringController.signal.aborted&&(this.unsubscribeDelivery(),this.steeringController=new AbortController,this.unsubscribeDelivery=this.input.inbox.onDelivery(this.signalSteering))}async admitBoundary(){let e=this.input.inbox.drain();for(let t of e)await this.admit(t)}async takeSteering(e){let t=[];for(;;){let n=this.input.queue.takeSteering(this.admitted,this.identity,e);if(n===void 0)break;for(let e of n.sequences)this.admitted.delete(e);let r=await routeSelectedDelivery(n,this.input.cursor);if(r.kind===`cancel-turn`){this.abort();break}r.kind===`turn`&&t.push(r.delivery)}if(this.resetSteering(),t.length===0)return;let n=t.length===1?t[0]:coalesceDeliveries(t);return n.caller!==void 0&&(this.caller=n.caller),n}takeBoundaryMessages(e){let t=[],n=[];for(let r of this.runtimeResults){let i=asBoundaryMessage(r);i===void 0||e!==void 0&&i.kind!==e?n.push(r):t.push(i)}return this.runtimeResults.splice(0,this.runtimeResults.length,...n),t}takeAppliedRunMessages(){let e=runMessageBatchBudget(),t=[];for(let n=this.runtimeResults[0];n!==void 0;n=this.runtimeResults[0]){if(n===`cancelled`||n.kind!==`workflow`||!isAppliedRunMessage(n.message)||!e(n.message))return t;t.push(n.message),this.runtimeResults.shift()}return[...t,...takeLeadingAppliedRunMessages(this.input.inbox,e)]}async nextRuntimeEvent(e){for(;;){let t=await this.routeAdmittedToChildren();if(this.signal.aborted)return`cancelled`;if(t)return{kind:`steering`};let n=this.runtimeResults.shift();if(n!==void 0)return n;let r=await this.waitForInboxOrTimer(e);if(r!==void 0)return{callId:r,kind:`timeout`};let i=await this.input.inbox.next();if(i===void 0)throw Error(`Session inbox closed before runtime actions completed.`);if(await this.admit(i))return{kind:`input`}}}async takeInputResponses(e){for(let t of this.admitted){let n=this.input.queue.delivery(t);if(n===void 0)continue;let r=n.payloads.flatMap(e=>e.inputResponses??[]);if(r.length===0)continue;if(!r.some(t=>e.has(t.requestId))){if(this.mappedForHeldRequest.has(t))continue;this.mappedForHeldRequest.add(t);let r=n,i=await this.input.cursor.advance(t=>mapHeldInputResponsesStep({delivery:r,requestIds:[...e],...t}));if(i.delivery===void 0)continue;n=i.delivery}this.admitted.delete(t);let i=isSteeringDelivery(n,this.identity,{heldOnPerson:!0})?void 0:splitAnswers(n);return this.input.queue.replaceDelivery(t,i?.rest),i?.answers??n}}async waitForInboxOrTimer(e){if(e.length===0||this.input.inbox.hasPending())return;let t=this.input.inbox.whenPending().then(()=>void 0);return await Promise.race([t,...e])}cancelsThisTurn(e){return e.kind===`reset`||e.kind===`session-failure`?!0:e.kind===`cancel`?e.turnId===void 0||e.turnId===this.expectedTurnId:!1}async admit(e){let t=await admitSessionInboxPayload(e,this.input);switch(t.kind){case`delivery`:return this.admitted.add(t.admission.sequence),!0;case`runtime-action-result`:return this.runtimeResults.push({kind:`runtime-action-result`,results:t.payload.results}),!1;case`workflow`:return this.runtimeResults.push({kind:`workflow`,message:t.message}),!1;case`cancel`:return this.cancelsThisTurn(e)&&this.abort(),!1;case`consumed`:return e.kind===`authorization-callback`}}async routeAdmittedToChildren(){let e=!1;for(let t of this.admitted){if(this.routedToChildren.has(t))continue;let n=this.input.queue.delivery(t);if(n===void 0){this.admitted.delete(t);continue}this.routedToChildren.add(t);let r=await this.input.cursor.advance(e=>routeDeliverToChildren({delivery:n,...e}));if(r.kind===`cancel-turn`)return this.input.queue.replaceDelivery(t,void 0),this.admitted.delete(t),this.abort(),!1;if(this.input.queue.replaceDelivery(t,r.remainder),r.remainder===void 0){this.admitted.delete(t);continue}isSteeringMessage(r.remainder,this.identity)&&(e=!0)}return e}abort(){this.controller.signal.aborted||this.controller.abort(new TurnCancelledError)}};function asBoundaryMessage(e){if(e!==`cancelled`&&e.kind===`workflow`&&(e.message.from.taskId!==void 0||e.message.kind===`agent-started`))return e.message}function splitAnswers(e){let t=e.payloads.flatMap(e=>e.inputResponses===void 0?[]:[{inputResponses:e.inputResponses}]),n=e.payloads.flatMap(e=>{let{inputResponses:t,...n}=e;return Object.keys(n).length===0?[]:[n]});return{answers:{...e,payloads:t},rest:n.length===0?void 0:{...e,payloads:n}}}export{ActiveTurn};
@@ -1 +1 @@
1
- import{initialSessionProjection}from"#protocol/session-projection.js";import{isObject}from"#shared/guards.js";import{getBlockingWorkflowToolRuns}from"#harness/workflow-tool-runs.js";import{SESSION_CHECKPOINT_VERSION}from"#execution/session/handoff.js";const MIN_SESSION_CHECKPOINT_VERSION=8,CHECKPOINT_UPGRADES={8:e=>{let{mode:t,...n}=e;return{...n,serializedContext:omitKeys(readRecord(n,`serializedContext`),[`eve.mode`])}},9:(e,t)=>{let n=readRecord(e,`sessionState`),r=readRecord(n,`snapshot`),{taskId:i,...a}=readRecord(r,`session`);return{...e,serializedContext:upgradeLegacyCaller(omitKeys(readRecord(e,`serializedContext`),[`eve.activityObserver`,`eve.activityPendingBlockers`,`eve.activityRootTurnId`,`eve.connectionSearchResults`,`eve.internal.backgroundToolExecution`,`eve.runtime.taskDeliveryPolicy`,`eve.turnTaskDelivery`])),sessionState:{...n,snapshot:{...r,session:{...a,history:readArray(a,`history`).map(renameBackgroundTaskMessage),state:upgradeSessionState(a.state,t)}}}}},10:e=>{let t=readRecord(e,`sessionState`),n=readRecord(t,`snapshot`),{history:r,...i}=readRecord(n,`session`);return t.version!==1&&refuse(`durable session version is not 1`),Array.isArray(r)||refuse(`session history is missing`),{...e,history:r,sessionState:{...t,snapshot:{...n,session:i},version:2}}},11:upgradeIdleLifecycle,12:e=>e};function migrateSessionCheckpoint(e){if(!isObject(e))return{kind:`incompatible`,detail:`checkpoint is not an object`};let{version:t}=e;if(typeof t!=`number`||!Number.isSafeInteger(t)||t<8||t>SESSION_CHECKPOINT_VERSION)return{kind:`incompatible`,detail:`checkpoint version ${JSON.stringify(t)} is outside the supported range 8-${SESSION_CHECKPOINT_VERSION}`};let n={childRunIdsToStop:[]},r=e;try{for(let e=t;e<SESSION_CHECKPOINT_VERSION;e++){let t=CHECKPOINT_UPGRADES[e];t===void 0&&refuse(`no upgrade from checkpoint version ${e}`),r={...t(r,n),version:e+1}}}catch(e){if(!(e instanceof CheckpointRefusal))throw e;return{kind:`incompatible`,detail:`checkpoint version ${t}: ${e.message}`}}return isCurrentCheckpoint(r)?{kind:`current`,checkpoint:r,childRunIdsToStop:n.childRunIdsToStop}:{kind:`incompatible`,detail:`checkpoint version ${t} is incomplete`}}function upgradeIdleLifecycle(e){let t=readRecord(e,`sessionState`);t.version!==2&&refuse(`durable session version is not 2`);let n=readRecord(t,`snapshot`),r=readRecord(n,`session`),i=r.state===void 0?{}:readRecord(r,`state`),a=i[`eve.harness.emission`]??t.emissionState;(!isObject(a)||typeof a.sessionStarted!=`boolean`||!Number.isSafeInteger(a.sequence)||a.sequence<0||!Number.isSafeInteger(a.stepIndex)||a.stepIndex<0||a.turnId!==``)&&refuse(`lifecycle position is malformed or a turn is still open`),[`eve.runtime.pendingAuthorization`,`eve.runtime.pendingInputBatch`,`eve.runtime.pendingCoordinationBatch`,`eve.runtime.deferredStepInput`,`eve.harness.pendingWorkflowInterrupt`].some(e=>i[e]!==void 0)&&refuse(`session holds pending work`);let o=i[`eve.runtime.pendingInputBatches`];o!==void 0&&(!Array.isArray(o)||o.length>0)&&refuse(`session holds pending input`);let s=i[`eve.runtime.proxyInputRequests`];(t.hasProxyInputRequests!==!1||s!==void 0&&(!isObject(s)||Object.keys(s).length>0))&&refuse(`session holds relayed input`);try{getBlockingWorkflowToolRuns(i).length>0&&refuse(`session holds workflow runs`)}catch(e){if(e instanceof CheckpointRefusal)throw e;refuse(`workflow tool run registry is incompatible`)}let c=i[`eve.runtime.hitl.approvalState`];c!==void 0&&(!isObject(c)||!isObject(c.activeCandidates)||Object.keys(c.activeCandidates).length>0)&&refuse(`session holds approval candidates or malformed approval state`);let l=i[`eve.runtime.hitl.approvedTools`]??[];(!Array.isArray(l)||!l.every(e=>typeof e==`string`))&&refuse(`approval grants are malformed`),(i[`eve.harness.turnState`]!==void 0||i[`eve.harness.sessionProjection`]!==void 0)&&refuse(`v11 checkpoint already contains machine state`);let u={...initialSessionProjection(),nextSequence:a.sequence};a.sessionStarted&&(u.started=!0);let d={...omitKeys(i,[`eve.harness.emission`,`eve.runtime.hitl.approvedTools`,`eve.runtime.pendingInputBatches`,`eve.runtime.proxyInputRequests`]),"eve.harness.sessionProjection":u};l.length>0&&(d[`eve.harness.turnState`]={grants:[...l],suspended:[]});let{emissionState:f,...p}=t;return{...e,sessionState:{...p,snapshot:{...n,session:{...r,state:d}}}}}function isCurrentCheckpoint(e){return isObject(e)&&e.version===SESSION_CHECKPOINT_VERSION&&Array.isArray(e.history)&&isObject(e.serializedContext)&&isObject(e.sessionState)}var CheckpointRefusal=class extends Error{};function refuse(e){throw new CheckpointRefusal(e)}function readRecord(e,t){let n=e[t];return isObject(n)||refuse(`${t} is not an object`),n}function readArray(e,t){let n=e[t];return Array.isArray(n)||refuse(`${t} is not an array`),n}function omitKeys(e,t){return Object.fromEntries(Object.entries(e).filter(([e])=>!t.includes(e)))}function upgradeLegacyCaller(e){let t=e[`eve.sessionCallback`];if(!isObject(t))return e;let{taskId:n,...r}=t;return{...e,"eve.legacyRemoteAgentCaller":typeof n==`string`&&n.length>0?{taskId:n}:{},"eve.sessionCallback":r}}function renameBackgroundTaskMessage(e){return isObject(e)&&e.role===`user`&&e.kind===`execution.background_task`?{...e,kind:`task.result`}:e}function upgradeSessionState(e,t){return isObject(e)?omitKeys(e,[...dropSettledWorkflowToolRuns(e),...stopIdleSubagents(e,t)]):e}function dropSettledWorkflowToolRuns(e){let t=e[`eve.workflowTool`];if(!isObject(t)||t.version!==3)return[];let n=t.runs;return(!Array.isArray(n)||!n.every(e=>isObject(e)&&e.lifetime===`session`&&isObject(e.task)&&e.task.outcome!==void 0))&&refuse(`workflow tool run registry version 3 holds unsettled runs`),[`eve.workflowTool`]}function stopIdleSubagents(e,t){let n=e[`eve.agent.handles`];if(n===void 0)return[];(!isObject(n)||!Array.isArray(n.handles))&&refuse(`subagent handles are malformed`);for(let e of n.handles){(!isObject(e)||e.phase!==`parked`&&e.phase!==`available`)&&refuse(`a subagent session is still working`);let n=e.address;isObject(n)&&(n.kind===`agent/local`||n.kind===`agent/self`)&&typeof n.sessionId==`string`&&n.sessionId.length>0&&t.childRunIdsToStop.push(n.sessionId)}return[`eve.agent.handles`]}export{MIN_SESSION_CHECKPOINT_VERSION,migrateSessionCheckpoint};
1
+ import{initialSessionProjection}from"#protocol/session-projection.js";import{isObject}from"#shared/guards.js";import{getBlockingWorkflowToolRuns}from"#harness/workflow-tool-runs.js";import{SESSION_CHECKPOINT_VERSION}from"#execution/session/handoff.js";const MIN_SESSION_CHECKPOINT_VERSION=8,CHECKPOINT_UPGRADES={8:e=>{let{mode:t,...n}=e;return{...n,serializedContext:omitKeys(readRecord(n,`serializedContext`),[`eve.mode`])}},9:(e,t)=>{let n=readRecord(e,`sessionState`),r=readRecord(n,`snapshot`),{taskId:i,...a}=readRecord(r,`session`);return{...e,serializedContext:upgradeLegacyCaller(omitKeys(readRecord(e,`serializedContext`),[`eve.activityObserver`,`eve.activityPendingBlockers`,`eve.activityRootTurnId`,`eve.connectionSearchResults`,`eve.internal.backgroundToolExecution`,`eve.runtime.taskDeliveryPolicy`,`eve.turnTaskDelivery`])),sessionState:{...n,snapshot:{...r,session:{...a,history:readArray(a,`history`).map(renameBackgroundTaskMessage),state:upgradeSessionState(a.state,t)}}}}},10:e=>{let t=readRecord(e,`sessionState`),n=readRecord(t,`snapshot`),{history:r,...i}=readRecord(n,`session`);return t.version!==1&&refuse(`durable session version is not 1`),Array.isArray(r)||refuse(`session history is missing`),{...e,history:r,sessionState:{...t,snapshot:{...n,session:i},version:2}}},11:upgradeIdleLifecycle,12:e=>e,13:e=>e};function migrateSessionCheckpoint(e){if(!isObject(e))return{kind:`incompatible`,detail:`checkpoint is not an object`};let{version:t}=e;if(typeof t!=`number`||!Number.isSafeInteger(t)||t<8||t>SESSION_CHECKPOINT_VERSION)return{kind:`incompatible`,detail:`checkpoint version ${JSON.stringify(t)} is outside the supported range 8-${SESSION_CHECKPOINT_VERSION}`};let n={childRunIdsToStop:[]},r=e;try{for(let e=t;e<SESSION_CHECKPOINT_VERSION;e++){let t=CHECKPOINT_UPGRADES[e];t===void 0&&refuse(`no upgrade from checkpoint version ${e}`),r={...t(r,n),version:e+1}}}catch(e){if(!(e instanceof CheckpointRefusal))throw e;return{kind:`incompatible`,detail:`checkpoint version ${t}: ${e.message}`}}return isCurrentCheckpoint(r)?{kind:`current`,checkpoint:r,childRunIdsToStop:n.childRunIdsToStop}:{kind:`incompatible`,detail:`checkpoint version ${t} is incomplete`}}function upgradeIdleLifecycle(e){let t=readRecord(e,`sessionState`);t.version!==2&&refuse(`durable session version is not 2`);let n=readRecord(t,`snapshot`),r=readRecord(n,`session`),i=r.state===void 0?{}:readRecord(r,`state`),a=i[`eve.harness.emission`]??t.emissionState;(!isObject(a)||typeof a.sessionStarted!=`boolean`||!Number.isSafeInteger(a.sequence)||a.sequence<0||!Number.isSafeInteger(a.stepIndex)||a.stepIndex<0||a.turnId!==``)&&refuse(`lifecycle position is malformed or a turn is still open`),[`eve.runtime.pendingAuthorization`,`eve.runtime.pendingInputBatch`,`eve.runtime.pendingCoordinationBatch`,`eve.runtime.deferredStepInput`,`eve.harness.pendingWorkflowInterrupt`].some(e=>i[e]!==void 0)&&refuse(`session holds pending work`);let o=i[`eve.runtime.pendingInputBatches`];o!==void 0&&(!Array.isArray(o)||o.length>0)&&refuse(`session holds pending input`);let s=i[`eve.runtime.proxyInputRequests`];(t.hasProxyInputRequests!==!1||s!==void 0&&(!isObject(s)||Object.keys(s).length>0))&&refuse(`session holds relayed input`);try{getBlockingWorkflowToolRuns(i).length>0&&refuse(`session holds workflow runs`)}catch(e){if(e instanceof CheckpointRefusal)throw e;refuse(`workflow tool run registry is incompatible`)}let c=i[`eve.runtime.hitl.approvalState`];c!==void 0&&(!isObject(c)||!isObject(c.activeCandidates)||Object.keys(c.activeCandidates).length>0)&&refuse(`session holds approval candidates or malformed approval state`);let l=i[`eve.runtime.hitl.approvedTools`]??[];(!Array.isArray(l)||!l.every(e=>typeof e==`string`))&&refuse(`approval grants are malformed`),(i[`eve.harness.turnState`]!==void 0||i[`eve.harness.sessionProjection`]!==void 0)&&refuse(`v11 checkpoint already contains machine state`);let u={...initialSessionProjection(),nextSequence:a.sequence};a.sessionStarted&&(u.started=!0);let d={...omitKeys(i,[`eve.harness.emission`,`eve.runtime.hitl.approvedTools`,`eve.runtime.pendingInputBatches`,`eve.runtime.proxyInputRequests`]),"eve.harness.sessionProjection":u};l.length>0&&(d[`eve.harness.turnState`]={grants:[...l],suspended:[]});let{emissionState:f,...p}=t;return{...e,sessionState:{...p,snapshot:{...n,session:{...r,state:d}}}}}function isCurrentCheckpoint(e){return isObject(e)&&e.version===SESSION_CHECKPOINT_VERSION&&Array.isArray(e.history)&&isObject(e.serializedContext)&&isObject(e.sessionState)}var CheckpointRefusal=class extends Error{};function refuse(e){throw new CheckpointRefusal(e)}function readRecord(e,t){let n=e[t];return isObject(n)||refuse(`${t} is not an object`),n}function readArray(e,t){let n=e[t];return Array.isArray(n)||refuse(`${t} is not an array`),n}function omitKeys(e,t){return Object.fromEntries(Object.entries(e).filter(([e])=>!t.includes(e)))}function upgradeLegacyCaller(e){let t=e[`eve.sessionCallback`];if(!isObject(t))return e;let{taskId:n,...r}=t;return{...e,"eve.legacyRemoteAgentCaller":typeof n==`string`&&n.length>0?{taskId:n}:{},"eve.sessionCallback":r}}function renameBackgroundTaskMessage(e){return isObject(e)&&e.role===`user`&&e.kind===`execution.background_task`?{...e,kind:`task.result`}:e}function upgradeSessionState(e,t){return isObject(e)?omitKeys(e,[...dropSettledWorkflowToolRuns(e),...stopIdleSubagents(e,t)]):e}function dropSettledWorkflowToolRuns(e){let t=e[`eve.workflowTool`];if(!isObject(t)||t.version!==3)return[];let n=t.runs;return(!Array.isArray(n)||!n.every(e=>isObject(e)&&e.lifetime===`session`&&isObject(e.task)&&e.task.outcome!==void 0))&&refuse(`workflow tool run registry version 3 holds unsettled runs`),[`eve.workflowTool`]}function stopIdleSubagents(e,t){let n=e[`eve.agent.handles`];if(n===void 0)return[];(!isObject(n)||!Array.isArray(n.handles))&&refuse(`subagent handles are malformed`);for(let e of n.handles){(!isObject(e)||e.phase!==`parked`&&e.phase!==`available`)&&refuse(`a subagent session is still working`);let n=e.address;isObject(n)&&(n.kind===`agent/local`||n.kind===`agent/self`)&&typeof n.sessionId==`string`&&n.sessionId.length>0&&t.childRunIdsToStop.push(n.sessionId)}return[`eve.agent.handles`]}export{MIN_SESSION_CHECKPOINT_VERSION,migrateSessionCheckpoint};
@@ -13,7 +13,7 @@ import type { AgentWorkflowRetentionDefinition } from "#shared/agent-definition.
13
13
  * A newer successor must always accept older checkpoints: every bump adds the
14
14
  * upgrade from the previous version in `checkpoint-migrations.ts`.
15
15
  */
16
- export declare const SESSION_CHECKPOINT_VERSION = 13;
16
+ export declare const SESSION_CHECKPOINT_VERSION = 14;
17
17
  /** Everything a successor needs to continue an idle session. Hooks are derived from the state. */
18
18
  export interface SessionCheckpoint {
19
19
  readonly version: typeof SESSION_CHECKPOINT_VERSION;
@@ -1 +1 @@
1
- import{isObject}from"#shared/guards.js";import{sessionHandoffMarkerToken}from"#execution/session-inbox/address.js";import{startSessionOwnerStep}from"#execution/workflow-runtime.js";import{createHook,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{claimHookOwnership,disposeHook}from"#execution/hook-ownership.js";import{sessionHookTokens}from"#execution/session/hook-tokens.js";import{isSessionIdleForHandoffStep,reportSessionHandoffRetainedStep}from"#execution/session/handoff-steps.js";import{readAcceptedDeploymentId}from"#execution/session/accepted-deployment.js";const SESSION_CHECKPOINT_VERSION=13;function sessionAnchorToken(e){return`${e}:anchor`}var SessionHandoff=class{input;anchor;incompatibleTargetDeploymentIds=new Set;constructor(e){this.input=e}async tryTransfer(e,t,n={}){let{delivery:r}=e,i=readAcceptedDeploymentId(r);return(i===void 0||i===this.input.deploymentId)&&n.compaction!==void 0?e.handoffEligible?await this.tryCompactionTransfer(t,{...n.compaction,delivery:r}):{kind:`retained`,reason:`busy`}:i===void 0?{kind:`retained`,reason:`missing-deployment`}:i===this.input.deploymentId?{kind:`retained`,reason:`same-deployment`}:this.incompatibleTargetDeploymentIds.has(i)?{kind:`retained`,reason:`known-incompatible`}:e.handoffEligible?await this.transfer(t,i,{delivery:r}):{kind:`retained`,reason:`busy`}}async tryCompactionTransfer(e,t){let{deploymentId:n}=this.input;return this.incompatibleTargetDeploymentIds.has(n)?{kind:`retained`,reason:`known-incompatible`}:await this.transfer(e,n,{...t,reason:`compaction`})}async transfer(e,t,n){let{inbox:r}=this.input;if(!await isSessionIdleForHandoffStep({sessionState:e.sessionState}))return{kind:`retained`,reason:`not-idle`};let i={...this.input.checkpoint,...e,version:13},a=sessionHookTokens(e);await this.ensureAnchor();let o=a.map(e=>createHook({token:sessionHandoffMarkerToken(e)}));await Promise.all(o.map(e=>claimHookOwnership(e)));let s;try{let e=await r.release();if(e.length>0)return await this.recover(a,e),{kind:`retained`,reason:`accepted-during-release`};let o=[];try{let e=await this.startAndActivate(i,n,t);if(e.kind===`active`)return{kind:`transferred`};o=e.payloads,e.kind===`incompatible`?(this.incompatibleTargetDeploymentIds.add(t),s={reason:`checkpoint-incompatible`}):s={error:e.error,reason:`activation-failed`}}catch(e){s={error:e,reason:`activation-failed`}}await this.recover(a,o)}finally{await Promise.all(o.map(e=>disposeHook(e)))}return await this.reportRetained(s.reason,t,s.error),{kind:`retained`,reason:s.reason}}async awaitAnchoredResult(){if(this.anchor===void 0)throw Error(`Session anchor was never claimed.`);try{return await this.anchor}finally{await this.disposeAnchor()}}async disposeAnchor(){if(this.anchor===void 0)return;let e=this.anchor;this.anchor=void 0,await disposeHook(e)}async startAndActivate(e,t,n){let r=createHook({token:`${getWorkflowMetadata().workflowRunId}:handoff`});await claimHookOwnership(r);try{return await startSessionOwnerStep({...t,activationToken:r.token,anchorRunId:this.input.sessionId,checkpoint:e,targetDeploymentId:n}),await r}finally{await disposeHook(r)}}async recover(e,t){await this.input.inbox.claimSessionHooks(e),this.input.inbox.restore(t)}async reportRetained(e,t,n){let r=isObject(n)&&typeof n.message==`string`?n.message:void 0;await reportSessionHandoffRetainedStep({error:r,reason:e,sessionId:this.input.sessionId,sourceDeploymentId:this.input.deploymentId,targetDeploymentId:t})}async ensureAnchor(){this.input.isInitialOwner&&this.anchor===void 0&&(this.anchor=createHook({token:sessionAnchorToken(this.input.sessionId)}),await claimHookOwnership(this.anchor))}};export{SESSION_CHECKPOINT_VERSION,SessionHandoff,sessionAnchorToken};
1
+ import{isObject}from"#shared/guards.js";import{sessionHandoffMarkerToken}from"#execution/session-inbox/address.js";import{startSessionOwnerStep}from"#execution/workflow-runtime.js";import{createHook,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{claimHookOwnership,disposeHook}from"#execution/hook-ownership.js";import{sessionHookTokens}from"#execution/session/hook-tokens.js";import{isSessionIdleForHandoffStep,reportSessionHandoffRetainedStep}from"#execution/session/handoff-steps.js";import{readAcceptedDeploymentId}from"#execution/session/accepted-deployment.js";const SESSION_CHECKPOINT_VERSION=14;function sessionAnchorToken(e){return`${e}:anchor`}var SessionHandoff=class{input;anchor;incompatibleTargetDeploymentIds=new Set;constructor(e){this.input=e}async tryTransfer(e,t,n={}){let{delivery:r}=e,i=readAcceptedDeploymentId(r);return(i===void 0||i===this.input.deploymentId)&&n.compaction!==void 0?e.handoffEligible?await this.tryCompactionTransfer(t,{...n.compaction,delivery:r}):{kind:`retained`,reason:`busy`}:i===void 0?{kind:`retained`,reason:`missing-deployment`}:i===this.input.deploymentId?{kind:`retained`,reason:`same-deployment`}:this.incompatibleTargetDeploymentIds.has(i)?{kind:`retained`,reason:`known-incompatible`}:e.handoffEligible?await this.transfer(t,i,{delivery:r}):{kind:`retained`,reason:`busy`}}async tryCompactionTransfer(e,t){let{deploymentId:n}=this.input;return this.incompatibleTargetDeploymentIds.has(n)?{kind:`retained`,reason:`known-incompatible`}:await this.transfer(e,n,{...t,reason:`compaction`})}async transfer(e,t,n){let{inbox:r}=this.input;if(!await isSessionIdleForHandoffStep({sessionState:e.sessionState}))return{kind:`retained`,reason:`not-idle`};let i={...this.input.checkpoint,...e,version:14},a=sessionHookTokens(e);await this.ensureAnchor();let o=a.map(e=>createHook({token:sessionHandoffMarkerToken(e)}));await Promise.all(o.map(e=>claimHookOwnership(e)));let s;try{let e=await r.release();if(e.length>0)return await this.recover(a,e),{kind:`retained`,reason:`accepted-during-release`};let o=[];try{let e=await this.startAndActivate(i,n,t);if(e.kind===`active`)return{kind:`transferred`};o=e.payloads,e.kind===`incompatible`?(this.incompatibleTargetDeploymentIds.add(t),s={reason:`checkpoint-incompatible`}):s={error:e.error,reason:`activation-failed`}}catch(e){s={error:e,reason:`activation-failed`}}await this.recover(a,o)}finally{await Promise.all(o.map(e=>disposeHook(e)))}return await this.reportRetained(s.reason,t,s.error),{kind:`retained`,reason:s.reason}}async awaitAnchoredResult(){if(this.anchor===void 0)throw Error(`Session anchor was never claimed.`);try{return await this.anchor}finally{await this.disposeAnchor()}}async disposeAnchor(){if(this.anchor===void 0)return;let e=this.anchor;this.anchor=void 0,await disposeHook(e)}async startAndActivate(e,t,n){let r=createHook({token:`${getWorkflowMetadata().workflowRunId}:handoff`});await claimHookOwnership(r);try{return await startSessionOwnerStep({...t,activationToken:r.token,anchorRunId:this.input.sessionId,checkpoint:e,targetDeploymentId:n}),await r}finally{await disposeHook(r)}}async recover(e,t){await this.input.inbox.claimSessionHooks(e),this.input.inbox.restore(t)}async reportRetained(e,t,n){let r=isObject(n)&&typeof n.message==`string`?n.message:void 0;await reportSessionHandoffRetainedStep({error:r,reason:e,sessionId:this.input.sessionId,sourceDeploymentId:this.input.deploymentId,targetDeploymentId:t})}async ensureAnchor(){this.input.isInitialOwner&&this.anchor===void 0&&(this.anchor=createHook({token:sessionAnchorToken(this.input.sessionId)}),await claimHookOwnership(this.anchor))}};export{SESSION_CHECKPOINT_VERSION,SessionHandoff,sessionAnchorToken};
@@ -1 +1 @@
1
- import{admitSessionInboxPayload}from"#execution/session/admission.js";import{routeSelectedDelivery}from"#execution/session/route-selected-delivery.js";async function nextTurnDelivery(e){let{inbox:t,cursor:n,queue:r}=e,i;for(;;){let a=r.takeNext({freshSequence:t.hasPending()?void 0:i});if(a?.kind===`control`)return{kind:a.control};if(a?.kind===`turn`){let e=await routeSelectedDelivery(a,n);if(e.kind===`cancel-turn`)return e;if(e.kind===`consumed`)continue;return e}let o=r.pendingCount===0,s=await t.next();if(s===void 0)return{kind:`closed`};let c=await admitSessionInboxPayload(s,e);if(i=o&&c.kind===`delivery`?c.admission.sequence:void 0,c.kind===`workflow`)return{kind:`workflow`,message:c.message};if(c.kind===`cancel`&&e.hasWorkingTasks())return{kind:`cancel-working-tasks`}}}export{nextTurnDelivery};
1
+ import{openInputs}from"#protocol/session-projection.js";import{storedProjection}from"#harness/session-machine/view.js";import{admitSessionInboxPayload}from"#execution/session/admission.js";import{routeSelectedDelivery}from"#execution/session/route-selected-delivery.js";async function nextTurnDelivery(e){let{inbox:t,cursor:n,queue:r}=e,i;for(;;){let a=r.takeNext({freshSequence:t.hasPending()?void 0:i});if(a?.kind===`control`)return{kind:a.control};if(a?.kind===`turn`){let e=await routeSelectedDelivery(a,n);if(e.kind===`cancel-turn`)return e;if(e.kind===`consumed`)continue;return e}let o=r.pendingCount===0,s=await t.next();if(s===void 0)return{kind:`closed`};let c=await admitSessionInboxPayload(s,e);if(i=o&&c.kind===`delivery`?c.admission.sequence:void 0,c.kind===`workflow`)return{kind:`workflow`,message:c.message};if(c.kind===`cancel`&&openInputs(storedProjection(n.sessionState.snapshot.session.state)).some(e=>e.request.kind===`session-limit`))return{kind:`cancel-turn`};if(c.kind===`cancel`&&e.hasWorkingTasks())return{kind:`cancel-working-tasks`}}}export{nextTurnDelivery};
@@ -4,6 +4,7 @@ import type { SessionInboxReader } from "#execution/session-inbox/inbox.js";
4
4
  import type { SessionStateCursor } from "#execution/session/state-cursor.js";
5
5
  import type { WorkflowToolRunMessage } from "#execution/tools/workflow/messages.js";
6
6
  import type { TurnOutcome, TurnStepPayload } from "#execution/session/turn-step-types.js";
7
+ import { ActiveTurn } from "#execution/session/active-turn.js";
7
8
  import type { TurnControl } from "#execution/session/turn-control.js";
8
9
  import type { RuntimeActionResult } from "#shared/action-types.js";
9
10
  /** True when a delegating parent (local or remote) receives this session's input requests. */
@@ -34,11 +35,12 @@ export declare class SessionExecution {
34
35
  }): Promise<TurnOutcome>;
35
36
  /**
36
37
  * Applies what runs reported while the model step ran, so the next step sees
37
- * it. Consecutive `agent-started` messages, such as a fan-out's, share one step.
38
- * An ending session drops them: its stream is closed, and finalizing the
39
- * session terminates the children.
38
+ * it. Consecutive messages the session applies as it reads them, such as a
39
+ * fan-out's, share one step. An ending session drops `agent-started`: its
40
+ * stream is closed, and finalizing the session terminates the children.
40
41
  */
41
42
  private handleBoundaryMessages;
43
+ private applyRunMessages;
42
44
  private runTurnSteps;
43
45
  /**
44
46
  * Starts the workflow tool runs a parked step requested, and returns the
@@ -46,7 +48,12 @@ export declare class SessionExecution {
46
48
  * session answers them itself.
47
49
  */
48
50
  private dispatchRuns;
49
- handleWorkflowMessage(message: WorkflowToolRunMessage): Promise<RuntimeActionResult | undefined>;
51
+ /**
52
+ * Handles a run message the session just read. One it applies as it reads
53
+ * it takes along those read after it, from `turn` while a turn runs, so a
54
+ * fan-out's messages share one step.
55
+ */
56
+ handleWorkflowMessage(message: WorkflowToolRunMessage, turn?: ActiveTurn): Promise<RuntimeActionResult | undefined>;
50
57
  /**
51
58
  * Stops the work a cancelled turn leaves behind: the workflow tool runs it
52
59
  * waits on and every working task. A turn that waits on no run, the common
@@ -1 +1 @@
1
- import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{TASK_WAIT_TOOL_NAME}from"#protocol/task-tools.js";import{renderTaskWaitResult}from"#execution/tasks/render.js";import{taskWaitResult}from"#execution/tasks/table.js";import{sleep}from"#compiled/@workflow/core/index.js";import{findBlockingWorkflowToolRun,getBlockingWorkflowToolRuns,isInboxToolResultFromRecordedWorkflowToolRun}from"#harness/workflow-tool-runs.js";import{resolveTurnPrincipal}from"#execution/session/principal.js";import{answerTaskCancel,cancelWorkingTasks,isTaskRunMessage,sessionTaskTable}from"#execution/tasks/session.js";import{cancelDescendantTurnsStep}from"#execution/cancel-descendant-turns-step.js";import{dispatchCoordinationStep}from"#execution/coordination-dispatch-step.js";import{taskToolResult}from"#execution/tasks/calls.js";import{applyTaskRunMessageStep}from"#execution/tasks/steps.js";import{publishTurnWaitingStep}from"#execution/session/turn-waiting-step.js";import{batchAgentStarts,handleWorkflowToolRunMessage}from"#execution/session-workflow-tool-run.js";import{emitAgentStartedStep}from"#execution/tools/workflow/emit-workflow-tool-run-report-step.js";import{interruptWorkflowToolRun}from"#execution/tools/workflow/interrupt.js";import{turnStep}from"#execution/session/turn-step.js";import{ActiveTurn}from"#execution/session/active-turn.js";import{resolveRuntimeActionResultsForCallIds}from"#runtime/actions/results.js";import{startTaskToolCallsStep,traceTaskToolCallStep}from"#execution/session/task-tool-tracing-step.js";function hasDelegatedCallerContext(e){if(e[`eve.sessionCallback`]!==void 0)return!0;let t=e[`eve.channel`];return typeof t==`object`&&!!t&&Reflect.get(t,`kind`)===`subagent`}var SessionExecution=class{input;constructor(e){this.input=e}get cursor(){return this.input.cursor}async runTurn(e,t={}){let n;try{n=new ActiveTurn(this.input,{caller:t.caller,principal:resolveTurnPrincipal(e,this.input.cursor.serializedContext)},t.control)}catch(e){throw t.control?.dispose(),e}try{let t=await this.runTurnSteps(n,e);return await this.handleBoundaryMessages(n.takeBoundaryMessages(),t.kind===`done`),t.kind===`park`&&t.settled!==void 0&&await cancelWorkingTasks(this.input.cursor,`turn_ended`),{...t,...n.caller!==void 0&&{caller:n.caller},...n.compacted&&{compacted:!0}}}finally{n.dispose()}}async handleBoundaryMessages(e,t=!1){for(let n of batchAgentStarts(e))n.kind===`message`?await this.handleWorkflowMessage(n.message):t||await this.input.cursor.advance(e=>emitAgentStartedStep({...e,messages:n.messages}))}async runTurnSteps(e,t){let n=t,r=e.caller;for(;;){let{cursor:t}=this.input,i=r;r=void 0;let a=await t.advanceWithHistory(t=>turnStep({...t,abortSignal:e.signal,caller:i,input:n,steeringSignal:e.steeringSignal}));a.compacted===!0&&(e.compacted=!0);let o=a.action===`park`?a.pendingCoordinationCallIds:void 0,s=a.action===`park`&&a.settled!==void 0;if(await e.admitBoundary(),await this.handleBoundaryMessages(e.takeBoundaryMessages(),a.action===`done`),a.action===`cancelled`||!s&&e.signal.aborted&&o===void 0)return await this.finishCancelledTurn(e);if(a.action===`done`)return{isError:a.isError,kind:`done`,output:a.output??``,usage:a.usage,usageDelta:a.usageDelta};if(a.action===`held`&&a.hold===`request`){if(a.hasPendingInputBatch&&this.input.capabilities?.requestInput!==!0&&!hasDelegatedCallerContext(this.input.cursor.serializedContext))throw Error(`This session cannot request human input, so it cannot wait for a tool approval or question. Configure unattended tools with an approval policy that does not require human input.`);let t=await this.waitForHeldRequest(e,a);if(t===`cancelled`)return await this.finishCancelledTurn(e);n={delivery:t};continue}if(a.action===`held`){if(await this.waitForHeldTurn(e)===`cancelled`)return await this.finishCancelledTurn(e);let t=await e.takeSteering();n=t===void 0?void 0:{delivery:t};continue}if(o!==void 0&&a.action===`park`){let t=a.hasRunsToDispatch===!1?[]:await this.dispatchRuns(),r=t.length===0?void 0:Date.now(),i=await this.waitForRuntimeActionResults({initialAcceptedAtMs:r,initialResults:t,taskToolCalls:a.pendingTaskToolCalls??[],pendingCallIds:o,turn:e});if(i===`cancelled`)return await this.finishCancelledTurn(e);n={delivery:await e.takeSteering(),runtimeResults:i};continue}if(a.action===`park`)return{kind:`park`,settled:a.settled};let c=await e.takeSteering();n=c===void 0?void 0:{delivery:c}}}async dispatchRuns(){return(await this.input.cursor.advance(e=>dispatchCoordinationStep({action:`park`,workflowToolRunOwner:{inbox:sessionInboxHookToken(sessionCommandHookToken(this.input.sessionId))},...e}))).results}async handleWorkflowMessage(e){if(isTaskRunMessage(e)){await this.input.cursor.advance(t=>applyTaskRunMessageStep({...t,message:e}));return}return await handleWorkflowToolRunMessage({cursor:this.input.cursor,message:e})}async cancelTurnWork(){let{cursor:e}=this.input;mayWaitOnWorkflowToolRuns(e.sessionState)&&await cancelDescendantTurnsStep({serializedContext:e.serializedContext,sessionState:e.sessionState}),await cancelWorkingTasks(e,`turn_cancelled`)}async finishCancelledTurn(e){return await this.handleBoundaryMessages(e.takeBoundaryMessages(`agent-started`)),await this.cancelTurnWork(),{cancelled:!0,kind:`park`}}async waitForHeldTurn(e){let t=!1;for(;;){let n={interrupted:t,timedOut:!1};if(taskWaitResult(sessionTaskTable(this.input.cursor),n)!==void 0)return`woke`;let r=await e.nextRuntimeEvent([]);if(r===`cancelled`)return r;switch(r.kind){case`steering`:t=!0;continue;case`workflow`:await this.handleWorkflowMessage(r.message);continue;case`input`:case`runtime-action-result`:case`timeout`:continue}}}async waitForHeldRequest(e,t){let n=new Set(t.authorizationAttemptIds),r=new Set(t.inputRequestIds);for(;;){let t=this.input.queue.takeAuthorizations(n);if(t!==void 0)return{kind:`deliver`,payloads:t};let i=await e.takeInputResponses(r);if(i!==void 0)return i;let a=await e.takeSteering({heldOnPerson:!0});if(a!==void 0)return a;let o=await e.nextRuntimeEvent([]);if(o===`cancelled`)return o;o.kind===`workflow`&&await this.handleWorkflowMessage(o.message)}}async waitForRuntimeActionResults(e){let t=[...e.initialResults],n=!1,r=new Map,i=new Map;if(e.initialAcceptedAtMs!==void 0)for(let n of t)r.set(n.callId,e.initialAcceptedAtMs);let accept=e=>{t.push(e),r.set(e.callId,Date.now())},a=await this.answerTaskToolCalls(e.taskToolCalls,accept);try{for(;;){a=await this.resolveTaskWaits(a,n,accept);let o=resolveRuntimeActionResultsForCallIds({pendingCallIds:e.pendingCallIds,results:t});if(o!==void 0){let e=o.flatMap(e=>{let t=i.get(e.callId);return t===void 0?[]:[t]});return{acceptedAtMsByCallId:Object.fromEntries(o.map(e=>[e.callId,r.get(e.callId)])),...e.length>0&&{delegatedUsage:e},results:o}}let s=a.flatMap(e=>e.timer===void 0?[]:[e.timer]),c=await e.turn.nextRuntimeEvent(s);if(c===`cancelled`)return c;if(c.kind===`timeout`){for(let e of a)e.callId===c.callId&&(e.timedOut=!0);continue}if(c.kind===`input`)continue;if(c.kind===`steering`){n||await this.interruptWaitedWorkflowCalls(e.pendingCallIds,t),n=!0;continue}if(c.kind===`runtime-action-result`){let e=this.input.cursor.sessionState.snapshot.session.state,n=c.results.filter(t=>t.kind===`tool-result`&&isInboxToolResultFromRecordedWorkflowToolRun(e,t));if(n.length>0){let e=Date.now();t.push(...n);for(let t of n)r.set(t.callId,e)}continue}let l=await this.handleWorkflowMessage(c.message);l!==void 0&&(accept(l),c.message.kind===`outcome`&&c.message.usage!==void 0&&i.set(l.callId,c.message.usage))}}finally{for(let e of a)await this.traceTaskWait(e,void 0,!0)}}async resolveTaskWaits(e,t,n){let r=sessionTaskTable(this.input.cursor),i=[];for(let a of e){let e=taskWaitResult(r,{interrupted:t,timedOut:a.timedOut});if(e===void 0){i.push(a);continue}let o=renderTaskWaitResult(e,Date.now()-a.startedAtMs);await this.traceTaskWait(a,o,t),n(taskToolResult(a.callId,TASK_WAIT_TOOL_NAME,o))}return i}async answerTaskToolCalls(e,t){let n=[],r=e.length===0?0:await startTaskToolCallsStep();for(let i of e)if(i.kind===TASK_WAIT_TOOL_NAME)n.push(startTaskWait(i,r));else{let e;try{e=await answerTaskCancel(this.input.cursor,i)}catch(e){throw await this.input.cursor.advance(e=>traceTaskToolCallStep(e,{callId:i.callId,toolName:i.kind,startedAtMs:r,completedAtMs:Date.now(),input:{taskId:i.taskId},failed:!0})),e}await this.input.cursor.advance(t=>traceTaskToolCallStep(t,{callId:i.callId,toolName:i.kind,startedAtMs:r,completedAtMs:Date.now(),input:{taskId:i.taskId},output:e.output})),t(e)}let i=await this.resolveTaskWaits(n,!1,t);return i.length>0&&await this.input.cursor.advance(publishTurnWaitingStep),i}async traceTaskWait(e,t,n=!1){await this.input.cursor.advance(r=>traceTaskToolCallStep(r,{callId:e.callId,toolName:TASK_WAIT_TOOL_NAME,startedAtMs:e.startedAtMs,completedAtMs:Date.now(),input:e.input,output:t,failed:n}))}async interruptWaitedWorkflowCalls(e,t){let n=this.input.cursor.sessionState.snapshot.session.state,r=new Set(t.map(e=>e.callId)),i=e.filter(e=>!r.has(e)).flatMap(e=>{let t=findBlockingWorkflowToolRun(n,e);return t===void 0?[]:[t.address]});await Promise.all(i.map(e=>interruptWorkflowToolRun(e)))}};function startTaskWait(e,t){let{callId:n,timeoutMs:r}=e,i=r===void 0?void 0:sleep(r).then(()=>n);return{callId:n,startedAtMs:t,input:r===void 0?{}:{timeoutSeconds:r/1e3},timedOut:r===0,timer:i}}function mayWaitOnWorkflowToolRuns(e){try{return getBlockingWorkflowToolRuns(e.snapshot?.session?.state).length>0}catch{return!0}}export{SessionExecution,hasDelegatedCallerContext};
1
+ import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{TASK_WAIT_TOOL_NAME}from"#protocol/task-tools.js";import{renderTaskWaitResult}from"#execution/tasks/render.js";import{taskWaitResult}from"#execution/tasks/table.js";import{sleep}from"#compiled/@workflow/core/index.js";import{findBlockingWorkflowToolRun,getBlockingWorkflowToolRuns,isInboxToolResultFromRecordedWorkflowToolRun}from"#harness/workflow-tool-runs.js";import{handleWorkflowToolRunMessage,isAppliedRunMessage,takeLeadingAppliedRunMessages}from"#execution/session-workflow-tool-run.js";import{resolveTurnPrincipal}from"#execution/session/principal.js";import{answerTaskCancel,cancelWorkingTasks,sessionTaskTable}from"#execution/tasks/session.js";import{cancelDescendantTurnsStep}from"#execution/cancel-descendant-turns-step.js";import{dispatchCoordinationStep}from"#execution/coordination-dispatch-step.js";import{taskToolResult}from"#execution/tasks/calls.js";import{publishTurnWaitingStep}from"#execution/session/turn-waiting-step.js";import{applyRunMessagesStep}from"#execution/tools/workflow/apply-run-messages-step.js";import{interruptWorkflowToolRun}from"#execution/tools/workflow/interrupt.js";import{turnStep}from"#execution/session/turn-step.js";import{ActiveTurn}from"#execution/session/active-turn.js";import{resolveRuntimeActionResultsForCallIds}from"#runtime/actions/results.js";import{startTaskToolCallsStep,traceTaskToolCallStep}from"#execution/session/task-tool-tracing-step.js";function hasDelegatedCallerContext(e){if(e[`eve.sessionCallback`]!==void 0)return!0;let t=e[`eve.channel`];return typeof t==`object`&&!!t&&Reflect.get(t,`kind`)===`subagent`}var SessionExecution=class{input;constructor(e){this.input=e}get cursor(){return this.input.cursor}async runTurn(e,t={}){let n;try{n=new ActiveTurn(this.input,{caller:t.caller,principal:resolveTurnPrincipal(e,this.input.cursor.serializedContext)},t.control)}catch(e){throw t.control?.dispose(),e}try{let t=await this.runTurnSteps(n,e);return await this.handleBoundaryMessages(n.takeBoundaryMessages(),t.kind===`done`),t.kind===`park`&&t.settled!==void 0&&await cancelWorkingTasks(this.input.cursor,`turn_ended`),{...t,...n.caller!==void 0&&{caller:n.caller},...n.compacted&&{compacted:!0}}}finally{n.dispose()}}async handleBoundaryMessages(e,t=!1){let n=[];for(let r of e)isAppliedRunMessage(r)?(!t||r.kind!==`agent-started`)&&n.push(r):(await this.applyRunMessages(n),n=[],await handleWorkflowToolRunMessage({cursor:this.input.cursor,message:r}));await this.applyRunMessages(n)}async applyRunMessages(e){e.length!==0&&await this.input.cursor.advance(t=>applyRunMessagesStep({...t,messages:e}))}async runTurnSteps(e,t){let n=t,r=e.caller;for(;;){let{cursor:t}=this.input,i=r;r=void 0;let a=await t.advanceWithHistory(t=>turnStep({...t,abortSignal:e.signal,caller:i,input:n,steeringSignal:e.steeringSignal}));a.compacted===!0&&(e.compacted=!0);let o=a.action===`park`?a.pendingCoordinationCallIds:void 0,s=a.action===`park`&&a.settled!==void 0;if(await e.admitBoundary(),await this.handleBoundaryMessages(e.takeBoundaryMessages(),a.action===`done`),a.action===`cancelled`||!s&&e.signal.aborted&&o===void 0)return await this.finishCancelledTurn(e);if(a.action===`done`)return{isError:a.isError,kind:`done`,output:a.output??``,usage:a.usage,usageDelta:a.usageDelta};if(a.action===`held`&&a.hold===`request`){if(a.hasPendingInputBatch&&this.input.capabilities?.requestInput!==!0&&!hasDelegatedCallerContext(this.input.cursor.serializedContext))throw Error(`This session cannot request human input, so it cannot wait for a tool approval or question. Configure unattended tools with an approval policy that does not require human input.`);let t=await this.waitForHeldRequest(e,a);if(t===`cancelled`)return await this.finishCancelledTurn(e);n={delivery:t};continue}if(a.action===`held`){if(await this.waitForHeldTurn(e)===`cancelled`)return await this.finishCancelledTurn(e);let t=await e.takeSteering();n=t===void 0?void 0:{delivery:t};continue}if(o!==void 0&&a.action===`park`){let t=a.hasRunsToDispatch===!1?[]:await this.dispatchRuns(),r=t.length===0?void 0:Date.now(),i=await this.waitForRuntimeActionResults({initialAcceptedAtMs:r,initialResults:t,taskToolCalls:a.pendingTaskToolCalls??[],pendingCallIds:o,turn:e});if(i===`cancelled`)return await this.finishCancelledTurn(e);n={delivery:await e.takeSteering(),runtimeResults:i};continue}if(a.action===`park`)return{kind:`park`,settled:a.settled};let c=await e.takeSteering();n=c===void 0?void 0:{delivery:c}}}async dispatchRuns(){return(await this.input.cursor.advance(e=>dispatchCoordinationStep({action:`park`,workflowToolRunOwner:{inbox:sessionInboxHookToken(sessionCommandHookToken(this.input.sessionId))},...e}))).results}async handleWorkflowMessage(e,t){if(isAppliedRunMessage(e)){let n=t?.takeAppliedRunMessages()??takeLeadingAppliedRunMessages(this.input.inbox);await this.applyRunMessages([e,...n]);return}return await handleWorkflowToolRunMessage({cursor:this.input.cursor,message:e})}async cancelTurnWork(){let{cursor:e}=this.input;mayWaitOnWorkflowToolRuns(e.sessionState)&&await cancelDescendantTurnsStep({serializedContext:e.serializedContext,sessionState:e.sessionState}),await cancelWorkingTasks(e,`turn_cancelled`)}async finishCancelledTurn(e){return await this.handleBoundaryMessages(e.takeBoundaryMessages(`agent-started`)),await this.cancelTurnWork(),{cancelled:!0,kind:`park`}}async waitForHeldTurn(e){let t=!1;for(;;){let n={interrupted:t,timedOut:!1};if(taskWaitResult(sessionTaskTable(this.input.cursor),n)!==void 0)return`woke`;let r=await e.nextRuntimeEvent([]);if(r===`cancelled`)return r;switch(r.kind){case`steering`:t=!0;continue;case`workflow`:await this.handleWorkflowMessage(r.message,e);continue;case`input`:case`runtime-action-result`:case`timeout`:continue}}}async waitForHeldRequest(e,t){let n=new Set(t.authorizationAttemptIds),r=new Set(t.inputRequestIds);for(;;){let t=this.input.queue.takeAuthorizations(n);if(t!==void 0)return{kind:`deliver`,payloads:t};let i=await e.takeInputResponses(r);if(i!==void 0)return i;let a=await e.takeSteering({heldOnPerson:!0});if(a!==void 0)return a;let o=await e.nextRuntimeEvent([]);if(o===`cancelled`)return o;o.kind===`workflow`&&await this.handleWorkflowMessage(o.message,e)}}async waitForRuntimeActionResults(e){let t=[...e.initialResults],n=!1,r=new Map,i=new Map;if(e.initialAcceptedAtMs!==void 0)for(let n of t)r.set(n.callId,e.initialAcceptedAtMs);let accept=e=>{t.push(e),r.set(e.callId,Date.now())},a=await this.answerTaskToolCalls(e.taskToolCalls,accept);try{for(;;){a=await this.resolveTaskWaits(a,n,accept);let o=resolveRuntimeActionResultsForCallIds({pendingCallIds:e.pendingCallIds,results:t});if(o!==void 0){let e=o.flatMap(e=>{let t=i.get(e.callId);return t===void 0?[]:[t]});return{acceptedAtMsByCallId:Object.fromEntries(o.map(e=>[e.callId,r.get(e.callId)])),...e.length>0&&{delegatedUsage:e},results:o}}let s=a.flatMap(e=>e.timer===void 0?[]:[e.timer]),c=await e.turn.nextRuntimeEvent(s);if(c===`cancelled`)return c;if(c.kind===`timeout`){for(let e of a)e.callId===c.callId&&(e.timedOut=!0);continue}if(c.kind===`input`)continue;if(c.kind===`steering`){n||await this.interruptWaitedWorkflowCalls(e.pendingCallIds,t),n=!0;continue}if(c.kind===`runtime-action-result`){let e=this.input.cursor.sessionState.snapshot.session.state,n=c.results.filter(t=>t.kind===`tool-result`&&isInboxToolResultFromRecordedWorkflowToolRun(e,t));if(n.length>0){let e=Date.now();t.push(...n);for(let t of n)r.set(t.callId,e)}continue}let l=await this.handleWorkflowMessage(c.message,e.turn);l!==void 0&&(accept(l),c.message.kind===`outcome`&&c.message.usage!==void 0&&i.set(l.callId,c.message.usage))}}finally{for(let e of a)await this.traceTaskWait(e,void 0,!0)}}async resolveTaskWaits(e,t,n){let r=sessionTaskTable(this.input.cursor),i=[];for(let a of e){let e=taskWaitResult(r,{interrupted:t,timedOut:a.timedOut});if(e===void 0){i.push(a);continue}let o=renderTaskWaitResult(e,Date.now()-a.startedAtMs);await this.traceTaskWait(a,o,t),n(taskToolResult(a.callId,TASK_WAIT_TOOL_NAME,o))}return i}async answerTaskToolCalls(e,t){let n=[],r=e.length===0?0:await startTaskToolCallsStep();for(let i of e)if(i.kind===TASK_WAIT_TOOL_NAME)n.push(startTaskWait(i,r));else{let e;try{e=await answerTaskCancel(this.input.cursor,i)}catch(e){throw await this.input.cursor.advance(e=>traceTaskToolCallStep(e,{callId:i.callId,toolName:i.kind,startedAtMs:r,completedAtMs:Date.now(),input:{taskId:i.taskId},failed:!0})),e}await this.input.cursor.advance(t=>traceTaskToolCallStep(t,{callId:i.callId,toolName:i.kind,startedAtMs:r,completedAtMs:Date.now(),input:{taskId:i.taskId},output:e.output})),t(e)}let i=await this.resolveTaskWaits(n,!1,t);return i.length>0&&await this.input.cursor.advance(publishTurnWaitingStep),i}async traceTaskWait(e,t,n=!1){await this.input.cursor.advance(r=>traceTaskToolCallStep(r,{callId:e.callId,toolName:TASK_WAIT_TOOL_NAME,startedAtMs:e.startedAtMs,completedAtMs:Date.now(),input:e.input,output:t,failed:n}))}async interruptWaitedWorkflowCalls(e,t){let n=this.input.cursor.sessionState.snapshot.session.state,r=new Set(t.map(e=>e.callId)),i=e.filter(e=>!r.has(e)).flatMap(e=>{let t=findBlockingWorkflowToolRun(n,e);return t===void 0?[]:[t.address]});await Promise.all(i.map(e=>interruptWorkflowToolRun(e)))}};function startTaskWait(e,t){let{callId:n,timeoutMs:r}=e,i=r===void 0?void 0:sleep(r).then(()=>n);return{callId:n,startedAtMs:t,input:r===void 0?{}:{timeoutSeconds:r/1e3},timedOut:r===0,timer:i}}function mayWaitOnWorkflowToolRuns(e){try{return getBlockingWorkflowToolRuns(e.snapshot?.session?.state).length>0}catch{return!0}}export{SessionExecution,hasDelegatedCallerContext};
@@ -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.77.0//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 {};