ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零编写 Sandcastle 沙箱提供商:Bind-Mount 与 Isolated 双模式完整指南

从零编写 Sandcastle 沙箱提供商:Bind-Mount 与 Isolated 双模式完整指南 从零编写 Sandcastle 沙箱提供商Bind-Mount 与 Isolated 双模式完整指南【免费下载链接】sandcastleOrchestrate sandboxed coding agents in TypeScript with sandcastle.run()项目地址: https://gitcode.com/gh_mirrors/sandcastl/sandcastle️Sandcastle是一个用 TypeScript 编排 AI 编码智能体的开源库你只调用一次sandcastle.run()它就把智能体关进隔离沙箱干活、再把分支上的提交合并回来。内置了 Docker、Podman、Vercel 三种沙箱提供商但真正的亮点是——你可以编写自定义沙箱提供商。本文将带你从零开始用两种方式接入任意隔离环境Bind-Mount绑定挂载与Isolated完全隔离从接口契约到跑通第一次运行全程只讲核心步骤。为什么需要自定义沙箱提供商当你想在自己的环境里跑智能体时会遇到这些场景️ 公司内网有自研的容器运行时或轻量虚拟机☁️ 想接 E2B、Daytona 这类云端沙箱服务 写测试时不想依赖 Docker想用一个纯本地临时目录模拟沙箱Sandcastle 的架构把怎么执行命令抽象成了SandboxProvider接口定义在 src/SandboxProvider.ts你只要实现一个小巧的 Promise 接口Sandcastle 会替你处理 worktree 创建、git 挂载解析、提交提取这些脏活。先选模式Bind-Mount 与 Isolated 的 3 秒判断法两种模式的本质区别只有一句话沙箱能不能直接访问宿主机的文件系统对比项 Bind-Mount绑定挂载 Isolated完全隔离适用场景Docker、Podman 等本地容器运行时云端 VM、微虚拟机等独立文件系统环境代码同步宿主机建好 worktree 后直接挂载进沙箱零同步由你实现copyIn/copyFileOut手动搬文件分支策略支持head、merge-to-head、branch三种仅支持merge-to-head、branch无法写宿主机默认分支策略head智能体直写宿主机工作目录merge-to-head临时分支 合并回 HEAD工厂函数createBindMountSandboxProvider()createIsolatedSandboxProvider()一句话决策本地容器 → Bind-Mount远端 VM / 云端沙箱 → Isolated。更多模式的选型背景可以参考仓库里的调研文档 research/sandbox-provider-research.md。核心契约沙箱 Handle 只需要 3~4 个方法两种提供商的create()函数都返回一个沙箱句柄handle契约非常小方法Bind-MountIsolated作用exec(command, opts)✅ 必须✅ 必须在沙箱中执行命令必须支持逐行流式输出close()✅ 必须✅ 必须销毁沙箱worktreePath✅ 必须✅ 必须仓库目录在沙箱内的绝对路径copyFileIn/copyFileOut✅ 必须— / ✅ 必须单文件在宿主机与沙箱间拷贝copyIn—✅ 必须拷贝文件或整个目录进沙箱两个关键细节官方在 src/SandboxProvider.ts 的注释里写得非常明确exec必须支持onLine逐行流式回调——这是 Sandcastle 给用户实时反馈、执行空闲超时的唯一通道。等进程结束再一次性吐出全部输出的实现不满足契约空闲超时和实时日志都会失效。每次exec返回统一的ExecResult{ stdout, stderr, exitCode }。第一步5 分钟写出你的 Bind-Mount 提供商以把本地进程当沙箱为例适合快速理解契约也适合写测试完整代码见 src/sandboxes/test-bind-mount.tsimport { createBindMountSandboxProvider } from ai-hero/sandcastle; const localProcess () createBindMountSandboxProvider({ name: local-process, create: async (options) { const worktreePath options.worktreePath; return { worktreePath, // 逐行流式执行命令spawn readline每行回调一次 onLine exec: (command, opts) { /* spawn(sh, [-c, command]) … */ }, copyFileIn: async (hostPath, sandboxPath) { /* 拷入单文件 */ }, copyFileOut: async (sandboxPath, hostPath) { /* 拷出单文件 */ }, close: async () { /* 本地进程无需清理 */ }, }; }, });create收到的BindMountCreateOptions包含worktreePath宿主机 worktree 路径、hostRepoPath、mounts宿主:沙箱路径对和env——写容器提供商时把这些映射成你的-v挂载参数即可。真实实现可参考 src/sandboxes/docker.ts含 SELinux 标签支持和 src/sandboxes/podman.ts。第二步5 分钟写出你的 Isolated 提供商Isolated 提供商多了两件事目录级拷贝和独立文件系统的清理。最小示例临时目录模拟远端 VM见 src/sandboxes/test-isolated.tsimport { createIsolatedSandboxProvider } from ai-hero/sandcastle; const tempDir () createIsolatedSandboxProvider({ name: temp-dir, create: async () { const root await mkdtemp(join(tmpdir(), sandbox-)); const worktreePath join(root, workspace); await mkdir(worktreePath, { recursive: true }); return { worktreePath, exec: (command, opts) { /* 同上的流式执行实现 */ }, // 目录递归拷入文件单拷 copyIn: async (hostPath, sandboxPath) { const isDir (await stat(hostPath)).isDirectory(); isDir ? await cp(hostPath, sandboxPath, { recursive: true }) : await copyFile(hostPath, sandboxPath); }, copyFileOut: async (sandboxPath, hostPath) { await mkdir(dirname(hostPath), { recursive: true }); await copyFile(sandboxPath, hostPath); }, close: async () { await rm(root, { recursive: true, force: true }); }, }; }, });接真实云服务时把copyIn换成 SDK 的上传接口即可例如 src/sandboxes/vercel.tsVercel Firecracker 微虚拟机和 src/sandboxes/daytona.tsDaytona 云沙箱含输出尾部长度限制防止长日志撑爆内存。第三步接入 run()第一次运行就跑通提供商写好后通过sandbox选项传给run()——用法和内置docker()完全一样import { run, claudeCode } from ai-hero/sandcastle; const result await run({ agent: claudeCode(claude-opus-4-8), sandbox: localProcess(), // 你的自定义提供商 prompt: Fix issue #42 in this repo., }); console.log(result.commits); // [{ sha: abc123 }]⚠️别忘了分支策略的差异详见 README.md 的Custom Sandbox Providers章节Bind-Mount 提供商默认为head——智能体直接写宿主机工作目录快但无分支隔离Isolated 提供商默认merge-to-head——提交先在临时分支产生结束后自动合并回 HEAD出问题时 HEAD 毫发无损是 CI 与无人值守场景的安全默认值想指定分支比如给 PR 用时显式传branchStrategy: { type: branch, branch: agent/fix-42 }两种模式都支持。避坑清单与参考实现 写提供商时最容易踩的四个坑exec不做流式输出→ 实时日志消失、空闲超时失效最常见的坑Isolated 的copyIn只拷文件不拷目录→ worktree 整体搬不进去智能体开工即报错close()没有清理资源→ 云端沙箱泄漏账单刺客Isolated 提供商配了head分支策略→ 类型层面直接报错因为它无法写宿主机。 官方参考实现索引文件模式说明src/sandboxes/docker.tsBind-MountDocker 容器含 SELinux 标签src/sandboxes/podman.tsBind-MountPodman 容器无守护进程src/sandboxes/vercel.tsIsolatedVercel Firecracker 微虚拟机src/sandboxes/daytona.tsIsolatedDaytona 云沙箱SDK 动态导入src/sandboxes/test-bind-mount.tsBind-Mount临时目录版适合写单测src/sandboxes/test-isolated.tsIsolated临时目录版适合写单测接口类型BindMountSandboxHandle、IsolatedSandboxHandle、ExecResult等全部集中在 src/SandboxProvider.ts完整使用文档见 README.md。总结三种提供商一张表带走提供商类型工厂函数文件同步分支策略典型代表Bind-MountcreateBindMountSandboxProvider挂载共享零同步全部三种Docker / Podman / 你的本地运行时IsolatedcreateIsolatedSandboxProvidercopyIncopyFileOutmerge-to-head/branchVercel / Daytona / 你的云 VMNo-SandboxnoSandbox()无直接跑在宿主机全部三种本地交互式会话掌握契约后你会发现写一个 Sandcastle 沙箱提供商核心代码其实只有exec、文件拷贝、close三块——剩下的一切sandcastle.run()都替你编排好了。【免费下载链接】sandcastleOrchestrate sandboxed coding agents in TypeScript with sandcastle.run()项目地址: https://gitcode.com/gh_mirrors/sandcastl/sandcastle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表