eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
2 lines • 10.4 kB
JavaScript
import{resolveSandboxModelPath}from"#shared/skill-paths.js";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{VERCEL_EVE_SANDBOX_IMAGE}from"#execution/sandbox/bindings/eve-image.js";import{streamToBuffer}from"#execution/sandbox/stream-utils.js";import{createLoggingSandboxSession}from"#execution/sandbox/logging-session.js";import{buildSandboxSession}from"#execution/sandbox/session.js";import{createSandboxProviderIdentity}from"#execution/sandbox/provider-identity.js";import{isSandboxPreparedArtifactRecord,providerResourceTargetFiles,sandboxProviderResourceIdentity}from"#shared/sandbox-provider.js";import{SandboxTemplateNotProvisionedError}from"#shared/sandbox-template-error.js";import{adaptMultiplexedCommandToSandboxProcess}from"#execution/sandbox/multiplexed-command.js";import{isVercelSandboxMissingError,isVercelSnapshotUnavailableError}from"#execution/sandbox/bindings/vercel-errors.js";import{ensureVercelSandboxTags,errorMessage,resolveVercelSandboxTags}from"#execution/sandbox/bindings/vercel-options.js";import{applyInitialVercelNetworkPolicy,createVercelNetworkPolicySetter,ensureVercelSandboxBaseRuntime,withBaseSetupNetworkPolicy}from"#execution/sandbox/bindings/vercel-base-runtime.js";import{createVercelEveImageSandbox}from"#execution/sandbox/bindings/vercel-create-sdk.js";import{getNamedVercelSandbox}from"#execution/sandbox/bindings/vercel-lookup.js";import{deleteUnusableVercelSandbox,deleteVercelSandbox,stopVercelSandbox}from"#execution/sandbox/bindings/vercel-lifecycle.js";import{normalizeVercelReadStream}from"#execution/sandbox/bindings/vercel-read-stream.js";function createVercelSandboxProvider(e){let{prepare:t,...n}=e??{};return createVercelSandbox({createOptions:n,prepare:t})}function createVercelSandbox(e={}){let t=e.loadSandboxModule??(async()=>await import(`#compiled/@vercel/sandbox/index.js`)),n=e.loadDeleteSandboxModule??(async()=>await import(`#compiled/@vercel/sandbox/index.js`)),r={timeout:DEFAULT_SANDBOX_TIMEOUT_MS,...e.createOptions},i=e.createSandbox??createVercelEveImageSandbox;async function openSession(e,a,o,s){let c=requirePreparedVercelTemplate(o),{mounts:l,...u}=a??{},d={...r,...u},f=resolveVercelSandboxTags(d.tags,{sessionId:e.session.id}),p=await t(),m={createOptions:d,createSandbox:i,resolveSessionCreateOptions:l===void 0?void 0:async()=>({mounts:l}),sandboxModule:p,sessionKey:s,snapshotId:c.snapshotId,tags:f},h;try{if(h=await ensureSession(m),h=await ensureUsableSession({input:m,loadDeleteSandboxModule:n,session:h}),h.created&&c.snapshotId===void 0&&u.networkPolicy!==void 0)try{await applyInitialVercelNetworkPolicy(h.sandbox,u.networkPolicy)}catch(t){try{await deleteVercelSandbox({createOptions:d,loadDeleteSandboxModule:n,sandbox:h.sandbox})}catch(n){throw AggregateError([t,n],`Failed to apply network policy and discard Vercel sandbox session "${e.session.id}".`,{cause:t})}throw t}}catch(t){throw isVercelSnapshotUnavailableError(t)&&c.snapshotId!==void 0?new SandboxTemplateNotProvisionedError({providerName:`vercel`,templateKey:c.snapshotId}):Error(`Failed to open Vercel sandbox session "${e.session.id}": ${errorMessage(t)}`,{cause:t})}return createHandle({createOptions:d,loadDeleteSandboxModule:n,sandbox:h.sandbox})}return{async prepare(n){let a=providerResourceTargetFiles(n.resources);if(e.skipEmptyPreparation===!0&&e.prepare===void 0&&a.length===0)return{};let o=`eve-sbx-tpl-vercel-${createSandboxProviderIdentity({createOptions:vercelIdentityOptions(r),resolvedImage:r.source===void 0?r.image??VERCEL_EVE_SANDBOX_IMAGE:void 0,resources:sandboxProviderResourceIdentity(n.resources),sourceRevision:n.sourceRevision,version:2}).slice(0,32)}`;try{return{snapshotId:(await ensureTemplateWithUnavailableRetry({createOptions:r,createSandbox:i,loadSandboxModule:t,log:n.log,prepareSandbox:e.prepare,seedFiles:a,templateKey:o})).template.snapshotId}}catch(e){throw Error(`Failed to prepare Vercel sandbox snapshot: ${errorMessage(e)}`,{cause:e})}},async resume(e,i,a){requirePreparedVercelTemplate(i);let o=requireVercelSessionState(a),s=await t(),c=await getNamedVercelSandbox({createOptions:r,sandboxModule:s,sandboxName:o.sandboxName});if(c===null)throw Error(`Vercel sandbox session "${o.sandboxName}" no longer exists.`);return await ensureVercelSandboxBaseRuntime(c),createHandle({createOptions:r,loadDeleteSandboxModule:n,sandbox:c})},async start(e,t,n){let i=vercelSessionName(e.session.id,t,n,r);return{handle:await openSession(e,t,n,i),state:{sandboxName:i,version:3}}}}}function vercelSessionName(e,t,n,r){let i=requirePreparedVercelTemplate(n);return`eve-sbx-vercel-${createSandboxProviderIdentity({artifact:i,createOptions:vercelIdentityOptions(r),options:vercelIdentityOptions(t),sessionId:e,version:1}).slice(0,32)}`}function vercelIdentityOptions(e){if(e===void 0)return;let t=new Set([`fetch`,`projectId`,`signal`,`teamId`,`token`]);return Object.fromEntries(Object.entries(e).filter(([e])=>!t.has(e)))}function requireVercelSessionState(e){if(!isSandboxPreparedArtifactRecord(e)||e.version!==3||typeof e.sandboxName!=`string`)throw Error(`Invalid Vercel sandbox session state.`);return{sandboxName:e.sandboxName,version:3}}function requirePreparedVercelTemplate(e){if(!isSandboxPreparedArtifactRecord(e)||e.snapshotId!==void 0&&typeof e.snapshotId!=`string`)throw Error(`Invalid prepared Vercel sandbox artifact.`);return e.snapshotId===void 0?{}:{snapshotId:e.snapshotId}}async function ensureTemplateWithUnavailableRetry(e){try{return await ensureTemplate(e)}catch(t){if(!isVercelSnapshotUnavailableError(t)&&!isVercelSandboxMissingError(t))throw t;return e.log?.(`cached template disappeared; rebuilding sandbox template`),await ensureTemplate(e)}}async function ensureTemplate(e){let t=await e.loadSandboxModule(),n=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:t,sandboxName:e.templateKey}),r=resolveVercelSandboxTags(e.createOptions.tags,e.tags),i=extractAuthorSnapshotId(e.createOptions);n!==null&&isUnprovisionedTerminalTemplateSandbox(n,i)&&(await n.delete(),n=null),n===null?n=await e.createSandbox({sandboxModule:t,createOptions:withBaseSetupNetworkPolicy({...e.createOptions,name:e.templateKey,persistent:!0,tags:r})}):await ensureVercelSandboxTags(n,r);let a=typeof n.currentSnapshotId==`string`&&n.currentSnapshotId.length>0&&n.currentSnapshotId!==i?n.currentSnapshotId:null;if(a!==null)return{template:{sandboxName:n.name,snapshotId:a,templateKey:e.templateKey}};e.log?.(`preparing base runtime inside sandbox`),await ensureVercelSandboxBaseRuntime(n),await applyInitialVercelNetworkPolicy(n,e.createOptions.networkPolicy);let o=buildSandboxSession(createVercelInternalSandboxSession(n),createVercelNetworkPolicySetter(n));await writeVercelSandboxSeedFiles({sandbox:n,seedFiles:e.seedFiles,session:o}),e.log?.(`running sandbox preparation`),await e.prepareSandbox?.(createLoggingSandboxSession({log:e.log,session:o}));let s=await n.snapshot();return{template:{sandboxName:n.name,snapshotId:s.snapshotId,templateKey:e.templateKey}}}async function ensureUsableSession(e){try{return await ensureVercelSandboxBaseRuntime(e.session.sandbox),e.session}catch(t){if(e.session.created||!isVercelSnapshotUnavailableError(t))throw t}await deleteUnusableVercelSandbox({createOptions:e.input.createOptions,loadDeleteSandboxModule:e.loadDeleteSandboxModule,sandbox:e.session.sandbox});let t=await ensureSession(e.input);return await ensureVercelSandboxBaseRuntime(t.sandbox),t}async function ensureSession(e){let t=e.sessionKey,n=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:e.sandboxModule,sandboxName:t});if(n!==null)return await ensureVercelSandboxTags(n,e.tags),{created:!1,sandbox:n};let r=createSessionCreateParams(e,t,await e.resolveSessionCreateOptions?.());return e.tags!==void 0&&(r.tags=e.tags),{created:!0,sandbox:await e.createSandbox({createOptions:r,sandboxModule:e.sandboxModule})}}function createSessionCreateParams(e,t,n={}){let r={...e.createOptions,...n};if(e.snapshotId===void 0)return withBaseSetupNetworkPolicy({...r,name:t,persistent:!0});let{image:i,runtime:a,source:o,...s}=r;return{...s,name:t,persistent:!0,source:{snapshotId:e.snapshotId,type:`snapshot`}}}function createHandle(e){let{sandbox:t}=e;return{sandbox:buildSandboxSession(createVercelInternalSandboxSession(t),createVercelNetworkPolicySetter(t)),async onSessionDelete(n){await deleteVercelSandbox({createOptions:e.createOptions,loadDeleteSandboxModule:e.loadDeleteSandboxModule,sandbox:t,signal:n?.abortSignal})},async onSessionStop(){await stopVercelSandbox(t)},async onRuntimeShutdown(){try{await stopVercelSandbox(t)}catch{}}}}function createVercelInternalSandboxSession(e){return{resolvePath:resolveVercelSandboxPath,async spawn(t){let n=await e.runCommand({args:[`-lc`,t.command],cmd:`bash`,cwd:t.workingDirectory??WORKSPACE_ROOT,detached:!0,env:t.env,signal:t.abortSignal});return adaptMultiplexedCommandToSandboxProcess({command:n,getOutput:e=>e.stream})},async readFile(t){return normalizeVercelReadStream(await e.readFile({path:t.path}))},async writeFile(t){let n=await streamToBuffer(t.content),r=await resolveVercelWritePath(e,t.path,t.abortSignal);await e.writeFiles([{content:n,path:r}],{signal:t.abortSignal})},async removePath(t){await e.fs.rm(t.path,{force:t.force,recursive:t.recursive,signal:t.abortSignal})}}}async function writeVercelSandboxSeedFiles(e){if(e.seedFiles.length===0)return;let t=await Promise.all(e.seedFiles.map(async t=>({content:typeof t.content==`string`?Buffer.from(t.content):t.content,path:await resolveSandboxModelPath({path:t.path,sandbox:e.session})})));await e.sandbox.writeFiles(t)}function resolveVercelSandboxPath(e){return e.startsWith(`/`)?e:`${WORKSPACE_ROOT}/${e}`}async function resolveVercelWritePath(e,t,n){let r=await e.runCommand({args:[`-m`,`--`,t],cmd:`realpath`,signal:n}),i=(await r.stdout()).trim();if(r.exitCode!==0||!i.startsWith(`/`)||i.includes(`
`))throw Error(`Failed to resolve Vercel Sandbox write path: ${t}`);return i}function isUnprovisionedTerminalTemplateSandbox(e,t){let n=e.currentSnapshotId;return typeof n==`string`&&n.length>0&&n!==t?!1:e.status===`aborted`||e.status===`failed`||e.status===`stopped`}function extractAuthorSnapshotId(e){let t=e.source;if(t?.type===`snapshot`&&typeof t.snapshotId==`string`)return t.snapshotId}const DEFAULT_SANDBOX_TIMEOUT_MS=18e5;export{createVercelSandbox,createVercelSandboxProvider};