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.
- package/CHANGELOG.md +16 -0
- package/dist/src/compiled/.vendor-stamp.json +1 -1
- package/dist/src/context/keys.d.ts +16 -0
- package/dist/src/context/keys.js +1 -1
- package/dist/src/execution/agent-sessions/steps.d.ts +2 -0
- package/dist/src/execution/agent-sessions/steps.js +1 -1
- package/dist/src/execution/cancelled-model-call-batch.js +1 -1
- package/dist/src/execution/catalog/search.js +1 -1
- package/dist/src/execution/catalog/step-catalog.d.ts +12 -3
- package/dist/src/execution/catalog/step-catalog.js +1 -1
- package/dist/src/execution/coordination-dispatch-shared.d.ts +1 -2
- package/dist/src/execution/coordination-dispatch-shared.js +1 -1
- package/dist/src/execution/coordination-dispatch-step.js +1 -1
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/sandbox/bindings/docker-container.js +1 -1
- package/dist/src/execution/sandbox/bindings/docker.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/execution/sandbox/session.d.ts +6 -0
- package/dist/src/execution/sandbox/session.js +2 -2
- package/dist/src/execution/session/active-turn.d.ts +9 -1
- package/dist/src/execution/session/active-turn.js +1 -1
- package/dist/src/execution/session/checkpoint-migrations.js +1 -1
- package/dist/src/execution/session/handoff.d.ts +1 -1
- package/dist/src/execution/session/handoff.js +1 -1
- package/dist/src/execution/session/next-input.js +1 -1
- package/dist/src/execution/session/turn.d.ts +11 -4
- package/dist/src/execution/session/turn.js +1 -1
- package/dist/src/execution/session-inbox/inbox.d.ts +3 -0
- package/dist/src/execution/session-inbox/inbox.js +1 -1
- package/dist/src/execution/session-workflow-tool-run.d.ts +14 -12
- package/dist/src/execution/session-workflow-tool-run.js +1 -1
- package/dist/src/execution/tasks/start.d.ts +14 -1
- package/dist/src/execution/tasks/start.js +1 -1
- package/dist/src/execution/tasks/steps.d.ts +7 -4
- package/dist/src/execution/tasks/steps.js +1 -1
- package/dist/src/execution/tools/agent-router-workflow.js +1 -1
- package/dist/src/execution/tools/workflow/apply-run-messages-step.d.ts +20 -0
- package/dist/src/execution/tools/workflow/apply-run-messages-step.js +1 -0
- package/dist/src/execution/tools/workflow/ask.d.ts +0 -1
- package/dist/src/execution/tools/workflow/ask.js +1 -1
- package/dist/src/execution/tools/workflow/interrupt.d.ts +5 -2
- package/dist/src/execution/tools/workflow/interrupt.js +1 -1
- package/dist/src/execution/tools/workflow/messages.d.ts +14 -0
- package/dist/src/execution/tools/workflow/messages.js +1 -1
- package/dist/src/execution/tools/workflow/owner.d.ts +18 -6
- package/dist/src/execution/tools/workflow/owner.js +1 -1
- package/dist/src/execution/tools/workflow/start.d.ts +10 -0
- package/dist/src/execution/tools/workflow/start.js +1 -1
- package/dist/src/execution/tools/workflow/step.js +1 -1
- package/dist/src/execution/tools/workflow/workflow-owner-blocking.d.ts +12 -0
- package/dist/src/execution/tools/workflow/workflow-owner-blocking.js +1 -1
- package/dist/src/execution/tools/workflow/workflow.js +1 -1
- package/dist/src/execution/workflow-runtime.d.ts +18 -3
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/harness/hitl/approvals.d.ts +4 -7
- package/dist/src/harness/hitl/approvals.js +1 -1
- package/dist/src/harness/hitl/approved-calls.d.ts +11 -0
- package/dist/src/harness/hitl/approved-calls.js +1 -1
- package/dist/src/harness/hitl/candidates.d.ts +0 -4
- package/dist/src/harness/hitl/candidates.js +1 -1
- package/dist/src/harness/hitl/delivery.d.ts +0 -1
- package/dist/src/harness/hitl/delivery.js +1 -1
- package/dist/src/harness/hitl/index.d.ts +2 -2
- package/dist/src/harness/hitl/index.js +1 -1
- package/dist/src/harness/hitl/intake.d.ts +2 -2
- package/dist/src/harness/hitl/intake.js +1 -1
- package/dist/src/harness/model-call/call.js +1 -1
- package/dist/src/harness/model-call/run.js +1 -1
- package/dist/src/harness/session-machine/state.d.ts +0 -2
- package/dist/src/harness/session-machine/view.d.ts +0 -3
- package/dist/src/harness/session-machine/view.js +1 -1
- package/dist/src/harness/step/after-model.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/internal/application/stamped-package-version.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/tools/provided/ask-question-workflow.js +1 -1
- package/dist/src/tools/provided/sleep-workflow.js +1 -1
- package/docs/agent-config.md +12 -4
- package/docs/concepts/built-in-tools.md +9 -9
- package/docs/guides/dynamic-capabilities.md +6 -2
- package/docs/sandbox/index.mdx +2 -0
- package/docs/tools/human-in-the-loop.md +1 -1
- package/package.json +1 -1
- package/dist/src/context/caller-scope.d.ts +0 -7
- package/dist/src/context/caller-scope.js +0 -1
- package/dist/src/execution/tools/workflow/emit-workflow-tool-run-report-step.d.ts +0 -13
- package/dist/src/execution/tools/workflow/emit-workflow-tool-run-report-step.js +0 -1
- package/dist/src/harness/hitl/approved-call-callers.d.ts +0 -14
- 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
|
|
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 =
|
|
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=
|
|
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
|
|
38
|
-
* An ending session drops
|
|
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
|
-
|
|
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,
|
|
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(
|
|
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 {
|
|
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
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export declare function
|
|
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{
|
|
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=
|
|
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
|
-
/**
|
|
11
|
-
|
|
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<
|
|
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
|
|
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.
|
|
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(
|
|
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
|
|
4
|
-
*
|
|
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{
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
-
/**
|
|
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 {};
|