UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

1 lines 5.7 kB
import{randomUUID}from"node:crypto";import{expectDockerSuccess}from"#execution/sandbox/bindings/docker-utils.js";import{writeSandboxSeedFiles}from"#execution/sandbox/bindings/local-backend-utils.js";import{assertDockerDaemonAvailable,createDockerCli}from"#execution/sandbox/bindings/docker-cli.js";import{DOCKER_SANDBOX_LABEL,runDockerBaseSetup,startDockerContainer,stopDockerContainerIfRunning}from"#execution/sandbox/bindings/docker-container.js";import{setDockerNetworkPolicy}from"#execution/sandbox/bindings/docker-network.js";import{createDockerSandboxOptionsHash,resolveDockerSandboxOptions}from"#execution/sandbox/bindings/docker-options.js";import{createDockerInternalSession}from"#execution/sandbox/bindings/docker-session.js";import{DOCKER_TEMPLATE_IMAGE_REPOSITORY,dockerImageExists,dockerTemplateImageReference,ensureDockerBaseImage,pruneDockerSandboxTemplates,resolveDockerTemplateMarkerPath,touchDockerTemplateMarker}from"#execution/sandbox/bindings/docker-templates.js";import{createLoggingSandboxSession}from"#execution/sandbox/logging-session.js";import{buildSandboxSession}from"#execution/sandbox/session.js";import{SandboxTemplateNotProvisionedError}from"#public/definitions/sandbox-backend.js";const DOCKER_BACKEND_NAME=`docker`;function createDockerSandboxBackend(e={}){let t=e.dockerCli??createDockerCli(),n=resolveDockerSandboxOptions(e.createOptions),r=createDockerSandboxOptionsHash(n),i;function ensureDaemon(){return i??=assertDockerDaemonAvailable(t).catch(e=>{throw i=void 0,e}),i}return{name:DOCKER_BACKEND_NAME,async prewarm(e){e.log?.(`checking Docker daemon`),await ensureDaemon();let i={optionsHash:r,templateKey:e.templateKey},a=dockerTemplateImageReference(i),o=resolveDockerTemplateMarkerPath(e.runtimeContext.appRoot,i);if(e.log?.(`checking cached template image "${a}"`),await dockerImageExists(t,a))return e.log?.(`reusing cached template image`),await touchDockerTemplateMarker(o,a),{reused:!0};e.log?.(`checking base image "${n.image}"`),await ensureDockerBaseImage(t,n);let s=`${e.templateKey}-build-${randomUUID().slice(0,8)}`;e.log?.(`starting template build container`),await startDockerContainer({cli:t,containerName:s,image:n.image,initialNetworkPolicy:`allow-all`,options:n,role:`template-build`});try{let r=await resolveDockerHandleIdentity(t,s);e.log?.(`preparing base runtime inside container`),await runDockerBaseSetup(t,r),n.networkPolicy!==`allow-all`&&(e.log?.(`applying network policy`),await setDockerNetworkPolicy(t,r,n.networkPolicy));let i=buildSandboxSession(createDockerInternalSession({cli:t,containerIdentity:r,id:e.templateKey}),e=>setDockerNetworkPolicy(t,r,e));e.seedFiles.length>0&&e.log?.(`writing ${e.seedFiles.length} seed file(s)`),await writeSandboxSeedFiles(i,e.seedFiles),e.bootstrap!==void 0&&(e.log?.(`running sandbox bootstrap`),await e.bootstrap({use:async()=>createLoggingSandboxSession({log:e.log,session:i})})),e.log?.(`stopping template build container`),expectDockerSuccess(await t.run([`stop`,`-t`,`0`,r]),`stop template build container "${s}"`),e.log?.(`committing template image "${a}"`),expectDockerSuccess(await t.run([`commit`,`--change`,`LABEL ${DOCKER_SANDBOX_LABEL}=1`,`--change`,`LABEL ${DOCKER_SANDBOX_LABEL}.role=template`,`--change`,`LABEL ${DOCKER_SANDBOX_LABEL}.template-key=${e.templateKey}`,r,a]),`commit sandbox template image "${a}"`),await touchDockerTemplateMarker(o,a)}finally{await t.run([`rm`,`-f`,s]).catch(()=>{})}return{reused:!1}},async create(e){await ensureDaemon();let i=getDockerContainerName(e.existingMetadata)??e.sessionKey,a=await t.run([`container`,`inspect`,`--format`,`{{.State.Running}}`,i]);if(a.exitCode===0)a.stdout.trim()!==`true`&&expectDockerSuccess(await t.run([`start`,i]),`restart sandbox session container "${i}"`);else{let a;if(e.templateKey===null)await ensureDockerBaseImage(t,n),a=n.image;else{let n={optionsHash:r,templateKey:e.templateKey};if(a=dockerTemplateImageReference(n),!await dockerImageExists(t,a))throw new SandboxTemplateNotProvisionedError({backendName:DOCKER_BACKEND_NAME,templateKey:e.templateKey});await touchDockerTemplateMarker(resolveDockerTemplateMarkerPath(e.runtimeContext.appRoot,n),a)}try{await startDockerContainer({cli:t,containerName:i,image:a,initialNetworkPolicy:e.templateKey===null?`allow-all`:n.networkPolicy,options:n,role:`session`,tags:e.tags})}catch(t){throw e.templateKey===null?t:new SandboxTemplateNotProvisionedError({backendName:DOCKER_BACKEND_NAME,templateKey:e.templateKey})}e.templateKey===null&&(await runDockerBaseSetup(t,i),n.networkPolicy!==`allow-all`&&await setDockerNetworkPolicy(t,i,n.networkPolicy))}let o=await resolveDockerHandleIdentity(t,i),s=buildSandboxSession(createDockerInternalSession({cli:t,containerIdentity:o,id:e.sessionKey}),e=>setDockerNetworkPolicy(t,o,e));return{session:s,useSessionFn:async()=>s,async captureState(){return{backendName:DOCKER_BACKEND_NAME,metadata:{containerName:i},sessionKey:e.sessionKey}},async delete(){await stopDockerContainerIfRunning(t,o),expectDockerSuccess(await t.run([`rm`,`-f`,o]),`delete sandbox session container "${i}"`)},async stop(){await stopDockerContainerIfRunning(t,o)},async shutdown(){await stopDockerContainerIfRunning(t,o)}}}}}function getDockerContainerName(e){let t=e?.containerName;return typeof t==`string`?t:void 0}async function resolveDockerHandleIdentity(e,t){let n=await e.run([`container`,`inspect`,`--format`,`{{.Id}}`,t]);expectDockerSuccess(n,`resolve sandbox container identity for "${t}"`);let r=n.stdout.trim();if(r.length===0)throw Error(`Docker returned an empty identity for sandbox container "${t}".`);return r}export{DOCKER_BACKEND_NAME,DOCKER_TEMPLATE_IMAGE_REPOSITORY,createDockerSandboxBackend,pruneDockerSandboxTemplates};