跳到主要内容
路径文档

E2B 云沙箱

一句话版e2b 是一组实验性 provider 组合 POC——把一整套"文件系统 + 子进程"执行世界放进 E2B 的 Linux 沙箱。E2B 只提供沙箱生命周期和两个底层 OS 适配器(fs-e2b / subprocess-e2b),与 provider 无关的消费者在这之上搭更高层能力。

它不搬 harness 进程本身,只把"可变的执行世界"挪进远端沙箱。

一、是什么

这个 POC 的目标是可移植执行世界:让文件工具、Bash、PTY、LSP 跑在同一个 E2B Linux 沙箱里。E2B 只负责两件事——沙箱的创建/销毁,以及两个 OS 适配器缝(文件系统、子进程)。更高的能力(Bash、PTY、LSP)不需要 E2B 专属 fork:

现成的 bash-localterminal-bashlsp-stdio 把每一次执行世界操作都委托给 ctx.fsctx.subprocess,所以挂上两个 E2B 适配器,它们的可变工作就落进同一个沙箱。

这条边界不搬 harness 进程、Cordis 对象、模型调用、agent/session 状态、会话持久化、技能、更高层协议状态,也不搬 E2B SDK 缓冲区——它们留在宿主进程。

二、包

ctx key角色
e2bctx.e2b创建一个沙箱、准备其工作/运行时目录、暴露共享 SDK 句柄,并在超时或销毁时删除它
fs-e2bctx.fs在 E2B Filesystem API 之上实现文件系统缝
subprocess-e2bctx.subprocess在 E2B Commands 与 PTY API 之上实现可执行查找、受管进程组与 stdio、远端 spill 文件、终端会话

三、生命周期与所有权(e2b

e2b 包是共享生命周期所有者:文件系统与子进程适配器注入 ctx.e2b、等待它的单一 SDK 句柄,因此栖身于同一个远端 Linux 工作树与进程世界。

  • 构造即创建沙箱:解析 getSandbox() 之前,服务先创建 cwd 和私有 cwd/.dsh-e2b 适配器状态目录,校验保留路径是真实目录(而非 symlink 或其他文件类型),再设为 0700
  • 命令 shell 隔离:每个适配器内部的 E2B 命令 shell 收到一个随机的根级 HOME,避免 SDK 固定登录 shell 在控制命令前从可变的用户家目录解析 profile 文件
  • 销毁:先阻止新的句柄获取,再等待 setup 完成,最后删除沙箱。SandboxNotFoundError 意味着已超时或别的所有者已删除,视为静默
  • 初始目录 setup 失败会尝试删除一次;配置的 E2B 超时约束第二次失败。provider 插件必须在此所有者之后加载、之前销毁

模型可见性:无——这个共享运行时所有者不注册任何模型可见上下文。

四、两个适配器

fs-e2b 实现 dsh-fs 的 provider 契约,无配置:先加载 e2b,再用它替换 fs-local。文件工具与 E2B 后端 Bash 进程看到同一个世界。

  • 远端身份与元数据:相对路径按 POSIX 对调用方 cwd 或 ctx.e2b.cwd 解析;stat/lstat/一级目录列表把 E2B 元数据投影进文件系统缝;版本是 E2B 元数据 + 每次写入扩展属性的不透明哈希
  • 执行世界路径:规范目标暴露绝对 POSIX 进程路径、百分号编码 file: URI,以及 provider 自有的 containment 检查
  • 有界读readBytes 在 stat 大小处短路,流式读远端对象并在超过 maxBytes 时取消(FS_TOO_LARGE),宿主机不整块缓冲超限文件
  • 原子写:写入先建随机 sibling 暂存目录(0700),通过 E2B 同文件系统原子 rename 发布;createIfAbsent 用远端 ln -T 保证原子 no-replace

subprocess-e2b 实现 dsh-subprocess 缝,用它替换 subprocess-local

  • 异步远端启动:同步缝立即返回句柄,Sandbox.commands.run(..., { background: true }) 远端启动;pid 在 wrapper 发布并校验进程组 id 前为 -1
  • Linux 进程组:quoted wrapper 用 exec setsid --wait 启动每个 argv,记录真实进程组 id;终止先 SIGTERM、等 graceMs,再升级 SIGKILL 与 SDK kill 兜底
  • 环境边界:一个可信控制 shell 探针解析沙箱用户登录家目录;wrapper 移除环境里的 DSH_* 与凭据形状(*KEY*/*SECRET*/*TOKEN*)名字,仅恢复显式 spec.env 条目
  • stdio 投影:远端 wrapper 把原始字节分流到可选的有界 spill 文件,每个 live chunk 以换行分隔 base64 帧回传,宿主增量还原
  • 终端会话spawnTerminal() 走 E2B 字节 PTY API,私有 0600 文件写入 argv 与净化后的环境,发送真实信号,terminate() 清理终端会话里的每个活进程组

五、配置

- id: e2b
name: '@deepseek-ai/dsh-e2b'
config:
cwd: /home/user/workspace
timeoutMs: 300000

- id: subprocess-e2b
name: '@deepseek-ai/dsh-subprocess-e2b'

- id: fs-e2b
name: '@deepseek-ai/dsh-fs-e2b'
  • apiKey 可选,缺省读 E2B_API_KEY;它配置宿主 SDK 连接,从不装进沙箱
  • cwd 缺省 /home/user/workspace,必须是绝对 POSIX 路径
  • timeoutMs 缺省五分钟,控制沙箱生命周期;到期即删除沙箱

subprocess-e2b 另有:

Key默认含义
pollMs20远端状态/存活轮询周期(毫秒);每 tick 是一次控制面请求,调大以请求数换退出观察延迟

六、挂载状态

e2b实验 POC,opt-in:任何出厂组合(base / headless / web-app)都不默认挂载。要使用需在 profile 的 cordis 配置里显式声明上面三个插件,且 fs-e2b/subprocess-e2b 必须在 e2b 之后加载。

七、已知限制

  • 不是整机运行时:Cordis 服务、agent/session 状态、会话日志、LLM 请求、技能、SDK 侧缓冲区都留在宿主进程
  • 沙箱状态是短暂的:销毁与超时都删除沙箱;重连、暂停/离开保留、模板、卷、快照都在 POC 之外
  • 未配置部署平台:网络策略、宿主工作区同步、沙箱发现都在 POC 之外
  • cwd 是解析约定,不是 containment:适配器与命令可以寻址其他沙箱路径;E2B 网络访问沿用基础镜像的策略

八、验证

# e2b 默认不挂载,dump-config 里应看不到这三个 id
dsh web --dump-config | grep -iE "e2b"
# 显式挂载后,确认三个插件都在组合树里
dsh web --dump-config | grep -iE "e2b"

下一步