eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
1 lines • 8.29 kB
JavaScript
import{INTERNAL_CHANNEL_DELIVER}from"#channel/channel-operations.js";import{parseJsonValue}from"#shared/json.js";import{getRun,getWorld}from"#internal/workflow/runtime.js";import{RunExpiredError,WorkflowRunNotFoundError}from"#compiled/@workflow/errors/index.js";import{parseNdjsonStream}from"#execution/ndjson-stream.js";import{INVOCATION_OWNER_ATTRIBUTE,INVOCATION_TOKEN_ATTRIBUTE,invocationInputRequestId,invocationOwnerKey}from"#internal/invocation/metadata.js";var WorkflowAgentInvocationExecution=class{#e;#t;constructor(e){this.#e=e.createSession,this.#t=e.from}async create(e){let t=`invocation:${crypto.randomUUID()}`,n=await this.#e({auth:e.auth,capabilities:{requestInput:!0},continuationToken:t,externalInvocation:{continuationToken:t,ownerKey:invocationOwnerKey(e.auth)},input:{message:e.message,outputSchema:e.outputSchema},mode:`task`}),r=await this.#n(n.sessionId,e.auth);if(r===void 0)throw Error(`Invocation run was unavailable after durable creation.`);return workingInvocation(n.sessionId,r.createdAt.toISOString(),r.expiredAt?.toISOString())}async read(e){let t=await this.#n(e.invocationId,e.auth);if(t===void 0)return;if(isTerminalRunStatus(t.status))return await terminalInvocation(t,t.status===`failed`?await readRecentPersistedEvents(e.invocationId):[]);let n=await readRecentPersistedEvents(e.invocationId);return projectNonterminal(t.runId,t.createdAt.toISOString(),t.expiredAt?.toISOString(),n)}async update(e){let t=await this.read(e);if(t===void 0)return{type:`not_found`};if(t.status!==`input_required`)return replaysResolvedBatch(await readRecentPersistedEvents(e.invocationId),e.responses)?{invocation:t,type:`success`}:conflict(`Invocation is not waiting for input.`);let n=await this.#n(e.invocationId,e.auth);if(n===void 0)return{type:`not_found`};let r=latestPendingInputBatch(await readRecentPersistedEvents(e.invocationId));if(r===void 0)return conflict(`Invocation input changed before the update could be applied.`);let i=new Set,a=[];for(let t of e.responses){let e=r.rawRequestIds[t.requestId];if(e===void 0)return conflict(`Unknown input request: ${t.requestId}`);i.add(t.requestId),a.push({...t,requestId:e})}if(i.size!==e.responses.length||i.size!==Object.keys(r.requests).length)return conflict(`Responses must answer the complete pending input batch exactly once.`);let o=n.attributes[INVOCATION_TOKEN_ATTRIBUTE];if(o===void 0)return{type:`not_found`};try{await this.#t(o)[INTERNAL_CHANNEL_DELIVER]({inputResponses:a},{auth:e.auth})}catch(e){if(RunExpiredError.is(e))return{type:`not_found`};throw e}return{invocation:workingInvocation(e.invocationId,t.createdAt,t.expiresAt),type:`success`}}async cancel(e){let t=await this.read(e);if(t===void 0||isTerminal(t.status))return t;try{await getRun(e.invocationId).cancel()}catch(e){if(WorkflowRunNotFoundError.is(e)||RunExpiredError.is(e))return;throw e}return await this.read(e)}async#n(e,t){let n=await getWorld();try{let r=await n.runs.get(e);return r.attributes[INVOCATION_TOKEN_ATTRIBUTE]===void 0?void 0:r.attributes[INVOCATION_OWNER_ATTRIBUTE]===invocationOwnerKey(t)?r:void 0}catch(e){if(WorkflowRunNotFoundError.is(e)||RunExpiredError.is(e))return;throw e}}};async function readRecentPersistedEvents(e){let t=getRun(e).getReadable({startIndex:-64}),n=await t.getTailIndex();if(n<0)return await t.cancel(`invocation event stream is empty`).catch(()=>{}),[];let r=Math.min(n+1,64),i=parseNdjsonStream(()=>t).getReader(),a=[];try{for(;a.length<r;){let{done:e,value:t}=await i.read();if(e)break;a.push(t)}}finally{await i.cancel(`invocation event window read complete`).catch(()=>{}),i.releaseLock()}return a}function pendingInputBatch(e){let t={},n={};for(let r of e.data.requests){let i=invocationInputRequestId(e.meta.id,r.requestId);t[i]=r.requestId,n[i]={...r,requestId:i}}return{id:e.meta.id,rawRequestIds:t,requests:n}}function withoutResolved(e,t){let n=new Set(t.map(e=>e.requestId)),r={},i={};for(let[t,a]of Object.entries(e.rawRequestIds)){if(n.has(a))continue;r[t]=a;let o=e.requests[t];o!==void 0&&(i[t]=o)}return Object.keys(r).length===0?void 0:{id:e.id,rawRequestIds:r,requests:i}}function foldInputBatches(e){let t,n,r;for(let i of e)if(i.type===`input.requested`)n=pendingInputBatch(i),t=n;else if(i.type===`input.resolved`){if(n===void 0)continue;let e=new Map;for(let t of i.data.resolutions)e.set(t.requestId,t.response);r={batch:n,responses:e},t!==void 0&&(t=withoutResolved(t,i.data.resolutions))}else i.type===`turn.started`&&(t=void 0);return{pending:t,resolved:r}}function latestPendingInputBatch(e){return foldInputBatches(e).pending}function replaysResolvedBatch(e,t){let n=foldInputBatches(e).resolved;if(n===void 0||t.length!==n.responses.size)return!1;let r=new Set;for(let e of t){let t=n.batch.rawRequestIds[e.requestId];if(t===void 0||r.has(t)||(r.add(t),!n.responses.has(t)))return!1;let i=n.responses.get(t);if(i?.optionId!==e.optionId||i?.text!==e.text)return!1}return!0}function projectNonterminal(e,t,n,r){let i=new Map,a,o;for(let e of r)if(e.type===`input.requested`)a=pendingInputBatch(e);else if(e.type===`input.resolved`)a!==void 0&&(a=withoutResolved(a,e.data.resolutions));else if(e.type===`turn.started`)i.clear(),a=void 0,o=void 0;else if(e.type===`authorization.required`){let t={description:e.data.description,name:e.data.name};e.data.authorization!==void 0&&(t.authorization=e.data.authorization),e.data.webhookUrl!==void 0&&(t.webhookUrl=e.data.webhookUrl),i.set(e.data.name,t)}else e.type===`authorization.completed`?i.delete(e.data.name):e.type===`message.completed`&&e.data.finishReason!==`tool-calls`&&e.data.message!==null&&(o=safeJson(e.data.message));let s=[...i.values()],c={createdAt:t,expiresAt:n,invocationId:e,result:o};return s.length>0?{...c,authorizations:s,pollAfterMs:1e3,status:`authorization_required`}:a===void 0?{...c,pollAfterMs:1e3,status:`working`}:{...c,inputRequests:a.requests,status:`input_required`}}async function terminalInvocation(e,t){let n={createdAt:e.createdAt.toISOString(),expiresAt:e.expiredAt?.toISOString(),invocationId:e.runId};if(e.status===`cancelled`)return{...n,status:`cancelled`};if(e.status===`failed`)return{...n,error:publicInvocationFailure(e.runId,t),status:`failed`};let r=await getRun(e.runId).returnValue;return{...n,result:safeJson(r.output),status:`completed`}}function workingInvocation(e,t,n){return{createdAt:t,expiresAt:n,invocationId:e,pollAfterMs:1e3,status:`working`}}function safeJson(e){try{return parseJsonValue(e)}catch{return String(e)}}function publicInvocationFailure(e,t){let n=[...t].reverse().find(e=>e.type===`session.failed`),r={runId:e};n!==void 0&&(r.eveCode=n.data.code);let i=vercelDeploymentId();i!==void 0&&(r.vercelDeploymentId=i),typeof n?.data.details?.errorId==`string`&&(r.errorId=n.data.details.errorId);let a=n===void 0?null:semanticFailure(n.data);if(a===null){let e=n===void 0?null:fallbackFailure(n.data);return e===null?{code:-32603,data:r,message:`Invocation failed.`}:(e.name!==void 0&&(r.name=e.name),{code:-32603,data:r,message:e.message})}return r.semanticErrorId=a.id,r.name=a.name,a.hint!==void 0&&(r.hint=a.hint),{code:-32603,data:r,message:a.message}}function semanticFailure(e){let t=e.details;if(typeof t?.semanticErrorId!=`string`||t.semanticErrorId.trim().length===0||typeof t.name!=`string`||t.name.trim().length===0)return null;let n=typeof t.message==`string`&&t.message.trim().length>0?t.message.trim():e.message.trim();if(n.length===0)return null;let r=typeof t.hint==`string`&&t.hint.trim().length>0?t.hint.trim():void 0,i={id:t.semanticErrorId,message:n,name:t.name};return r!==void 0&&(i.hint=r),i}function fallbackFailure(e){let t=e.message.trim(),n=typeof e.details?.name==`string`?e.details.name.trim():``;if(t.length===0&&n.length===0)return null;let r={message:t.length===0?n:truncateForDisplay(t)};return n.length>0&&(r.name=n),r}function truncateForDisplay(e,t=160){return e.length<=t?e:`${e.slice(0,t-1).trimEnd()}…`}function vercelDeploymentId(){if(process.env.VERCEL!==`1`)return;let e=process.env.VERCEL_DEPLOYMENT_ID?.trim();return e&&e.length>0?e:void 0}function conflict(e){return{message:e,type:`conflict`}}function isTerminal(e){return e===`completed`||e===`failed`||e===`cancelled`}function isTerminalRunStatus(e){return e===`completed`||e===`failed`||e===`cancelled`}export{WorkflowAgentInvocationExecution};