eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
1 lines • 5.48 kB
JavaScript
import{projectInvocationInputRequest}from"./result.js";import{Client,ClientError}from"#client/index.js";import{resolveLinkedDevelopmentOidcToken}from"#services/dev-client/request-headers.js";import{formatVercelTrustedSourcesFailure,isVercelAuthChallenge,vercelTrustedSourcesErrorCode}from"#services/dev-client/vercel-auth-error.js";import{resolveLocalDevelopmentClientOptions}from"#services/dev-client/client-options.js";import{collectTurnEvents,summarizeTurnEvents}from"#client/session-utils.js";import{resolveVerifiedRemoteDevelopmentClient}from"#setup/verified-remote-client.js";async function runInvoke(e){let{client:t,deploymentResolution:n}=await createInvokeClient(e),r=e.operation.resume;if(e.operation.kind===`follow`){let i=t.sessions.attach(r.session.sessionId,{streamIndex:r.session.streamIndex});return observeSafely(e,i,i.stream({signal:e.signal}),n)}let i,a;try{let n={...e.operation.payload,signal:e.signal};if(r===void 0){if(n.message===void 0)throw Error(`Cannot answer an input request before the session starts.`);let e=await t.sessions.create({...n,message:n.message});a=e.session,i=e.response}else{a=t.sessions.attach(r.session.sessionId,{streamIndex:r.session.streamIndex});let{inputResponses:e,message:o,...s}=n;i=e===void 0?await a.send(o,s):await a.respond(e,s)}}catch(e){let t=authenticationFailure(e,void 0,n);if(t!==void 0)return t;throw e}return observeSafely(e,a,i,n)}function resolveInvokeOperation(e){let t=e.prompt?.trim(),n=e.previous;if(n===void 0){if(!t)throw Error(`eve invoke requires a prompt unless --resume is provided.`);return{kind:`send`,payload:{message:t}}}if(n.status===`input-required`){if(!t)throw Error(`This invocation is waiting for an input response.`);return{kind:`send`,payload:{message:t},resume:n.resume}}if(n.status===`running`||n.status===`authorization-required`||n.status===`authentication-required`){if(t)throw Error(n.status===`running`?`A running invocation cannot accept a follow-up prompt.`:`Complete the requested authorization, then resume without a prompt.`);return{kind:`follow`,resume:n.resume}}if(n.status!==`ready`)throw Error(`A terminal ${n.status} invocation cannot be resumed.`);if(!t)throw Error(`A ready invocation requires a follow-up prompt.`);return{kind:`send`,payload:{message:t},resume:n.resume}}async function createInvokeClient(e){if(e.target.kind===`local`)return{client:new Client({...resolveLocalDevelopmentClientOptions({headers:e.headers,serverUrl:e.target.serverUrl,token:()=>resolveLinkedDevelopmentOidcToken(e.target.workspaceRoot)})})};let{deploymentResolution:t,options:n}=await resolveVerifiedRemoteDevelopmentClient({headers:e.headers,serverUrl:e.target.serverUrl,signal:e.signal,vercelScope:e.vercelScope,workspaceRoot:e.target.workspaceRoot});return{client:new Client(n),deploymentResolution:t}}async function observeSafely(e,t,n,r){try{return await observeInvocation(e.target,t,n)}catch(n){if(e.signal?.aborted===!0)return runningResult(e.target,t.state);let i=authenticationFailure(n,createResume(e.target,t.state),r);if(i!==void 0)return i;throw n}}async function observeInvocation(e,t,n){let r=summarizeTurnEvents(await collectTurnEvents(n));if(r.boundary===void 0)return runningResult(e,t.state);if(r.boundary.type===`session.failed`)return{status:`failed`,message:r.boundary.data.message};let i=createResume(e,t.state);if(r.failure?.type===`turn.failed`)return{status:`ready`,outcome:{status:`failed`,message:r.failure.data.message},resume:i};if(r.inputRequests.length>0)return{status:`input-required`,requests:r.inputRequests.map(projectInvocationInputRequest),resume:i};let a=r.pendingAuthorizations;return a.length>0?e.kind===`local`&&a.some(e=>e.webhookUrl!==void 0)?{status:`failed`,message:`Local eve invoke cannot pause for connection authorization because its temporary server must remain available for the callback. Run eve dev, then invoke its URL with --url.`}:{status:`authorization-required`,authorizations:a,resume:i}:{status:`ready`,outcome:r.message===void 0?{status:`completed`}:{status:`completed`,message:r.message},resume:i}}function runningResult(e,t){return{status:`running`,resume:createResume(e,t)}}function createResume(e,t){return{session:t,target:e.kind===`local`?{kind:`local`}:{kind:`remote`,serverUrl:e.serverUrl}}}function authenticationFailure(e,t,n){let r,i;if(n?.kind===`not-found`?r=`Vercel could not resolve this deployment in the selected scope. Retry with the owning team's slug via --scope <team-slug>, or provide an explicit Authorization header with -H.`:isVercelAuthChallenge(e)?r=`Vercel Deployment Protection rejected the available credentials. Configure Trusted Sources or set VERCEL_AUTOMATION_BYPASS_SECRET, then retry.`:e instanceof ClientError&&(i=vercelTrustedSourcesErrorCode(e.message),e.status===403&&i===`TRUSTED_SOURCES_ENVIRONMENT_MISMATCH`?r=formatVercelTrustedSourcesFailure(e.message):isEveAuthorizationError(e)&&(r=`The deployment rejected the available credentials. Confirm its eve channel authorization and that your account can access the owning project.`)),r!==void 0)return t===void 0?i===void 0?{status:`authentication-required`,message:r}:{status:`authentication-required`,code:i,message:r}:i===void 0?{status:`authentication-required`,message:r,resume:t}:{status:`authentication-required`,code:i,message:r,resume:t}}function isEveAuthorizationError(e){if(e.status!==401)return!1;try{let t=JSON.parse(e.body);return t.ok===!1&&t.code===`unauthorized`}catch{return!1}}export{resolveInvokeOperation,runInvoke};