22
33> AI Agent 统一 Workspace Agent Harness — 一个 Workspace,多种后端沙盒。
44
5- Sandbank 是面向 AI Agent 的统一 workspace harness。它把 Agent 身份、memory、artifact、audit log、文件和 checkpoint 固化在 ` Workspace ` 协议里,再把具体执行任务调度到 Dynamic Worker、E2B、BoxLite、Fly.io、Daytona、Cloudflare Workers 等后端沙盒。底层 provider SDK 仍然可单独使用,但 Sandbank 的顶层抽象已经从“统一沙箱接口”升级为“跨后端同步 Workspace 的 Agent Harness”。
5+ Sandbank 是面向 AI Agent 的统一 workspace harness。它把 Agent 身份、memory、artifact、audit log、文件和 checkpoint 固化在 ` Workspace ` 协议里,再把具体执行任务调度到 Sandbank Cloud、 Dynamic Worker、E2B、BoxLite、Fly.io、Daytona、Cloudflare Workers 等后端沙盒。底层 provider SDK 仍然可单独使用,但 Sandbank 的顶层抽象已经从“统一沙箱接口”升级为“跨后端同步 Workspace 的 Agent Harness”。默认推荐的通用计算后端是 Sandbank Cloud:我们的托管 BoxLite 云服务 。
66
77** [ 官网] ( https://sandbank.dev ) ** | ** [ English] ( ./README.en.md ) ** | ** [ 日本語] ( ./README.ja.md ) **
88
99<img src =" ./docs/assets/sandbank-robots-vacation-pixel.png " alt =" 像素画风格的一群小机器人 Agent 在海中沙滩上度假,每个机器人都有不同的开发者角色 " width =" 100% " />
1010
1111## 为什么选择 Sandbank?
1212
13- AI Agent 需要的不只是一个隔离沙箱。它需要一个可恢复、可审计、可跨运行时迁移的长期 Workspace,同时还要能按任务选择合适的计算后端:短 JS code mode 可以跑在 Cloudflare Dynamic Worker,Python 可以派发到 E2B 或 BoxLite,长任务可以落到 VM/container,最终输出再同步回同一个 Workspace。
13+ AI Agent 需要的不只是一个隔离沙箱。它需要一个可恢复、可审计、可跨运行时迁移的长期 Workspace,同时还要能按任务选择合适的计算后端:短 JS code mode 可以跑在 Cloudflare Dynamic Worker,Python、Codex 和 shell 任务默认优先派发到 Sandbank Cloud(托管 BoxLite),特殊场景再切到 E2B、本地 BoxLite、Fly.io 或 VM/container,最终输出同步回同一个 Workspace。
1414
1515底层沙箱 provider SDK 仍然可用,用来屏蔽 Daytona、Fly.io、Cloudflare Workers 等不同 API:
1616
1717``` typescript
1818import { createProvider } from ' @sandbank.dev/core'
19- import { DaytonaAdapter } from ' @sandbank.dev/daytona '
19+ import { SandbankCloudAdapter } from ' @sandbank.dev/cloud '
2020
21- const provider = createProvider (new DaytonaAdapter ({ apiKey: ' ...' }))
21+ const provider = createProvider (new SandbankCloudAdapter ({
22+ apiToken: process .env .SANDBANK_API_TOKEN ,
23+ }))
2224const sandbox = await provider .create ({ image: ' node:22' })
2325
2426const result = await sandbox .exec (' echo "Hello from the sandbox"' )
@@ -27,7 +29,7 @@ console.log(result.stdout) // Hello from the sandbox
2729await provider .destroy (sandbox .id )
2830```
2931
30- 把 ` DaytonaAdapter ` 换成 ` FlyioAdapter ` 或 ` CloudflareAdapter ` ,沙箱创建/执行代码无需重写 。更高一层的 harness 会把这些 provider 当作计算后端,而不是 Agent 的长期家。
32+ Sandbank Cloud 是默认推荐 provider; 把 ` SandbankCloudAdapter ` 换成 ` DaytonaAdapter ` 、 ` FlyioAdapter ` 或 ` CloudflareAdapter ` ,沙箱创建/执行代码仍无需重写 。更高一层的 harness 会把这些 provider 当作计算后端,而不是 Agent 的长期家。
3133
3234## 架构
3335
@@ -45,14 +47,14 @@ await provider.destroy(sandbox.id)
4547│ @sandbank.dev/agent 沙箱内 Agent 客户端 │
4648│ @sandbank.dev/relay 多 Agent 通信中枢 │
4749├──────────────────────────────────────────────────────┤
48- │ @sandbank.dev/daytona @sandbank.dev/flyio @sandbank.dev/cloudflare │
49- │ @sandbank.dev/boxlite @sandbank.dev/e2b │
50+ │ @sandbank.dev/cloud @sandbank.dev/boxlite @sandbank.dev/e2b │
51+ │ @sandbank.dev/daytona @sandbank.dev/flyio @sandbank.dev/cloudflare │
5052│ Provider 适配器(计算) │
5153├──────────────────────────────────────────────────────┤
5254│ @sandbank.dev/db9 Service Adapter(数据) │
5355├──────────────────────────────────────────────────────┤
54- │ Daytona Fly.io Machines Cloudflare Workers │
55- │ BoxLite (自托管 Docker) E2B Cloud Sandboxes │
56+ │ Sandbank Cloud (托管 BoxLite) BoxLite (自托管 Docker) │
57+ │ E2B Cloud Sandboxes Daytona Fly.io Machines Cloudflare Workers │
5658│ db9.ai (PostgreSQL) │
5759└──────────────────────────────────────────────────────┘
5860```
@@ -65,6 +67,7 @@ await provider.destroy(sandbox.id)
6567| [ ` @sandbank.dev/core ` ] ( ./packages/core ) | 底层 Provider SDK、能力系统、错误类型 |
6668| [ ` @sandbank.dev/skills ` ] ( ./packages/skills ) | Skill 注册表、本地文件系统加载器 |
6769| [ ` @sandbank.dev/workspace ` ] ( ./packages/workspace ) | 持久 Workspace 协议、checkpoint、沙箱 materialize/sync helper |
70+ | [ ` @sandbank.dev/cloud ` ] ( ./packages/cloud ) | Sandbank Cloud 托管 BoxLite 云服务适配器,推荐默认 provider,支持 API token 或 x402 付费 |
6871| [ ` @sandbank.dev/daytona ` ] ( ./packages/daytona ) | Daytona 云沙箱适配器 |
6972| [ ` @sandbank.dev/flyio ` ] ( ./packages/flyio ) | Fly.io Machines 适配器 |
7073| [ ` @sandbank.dev/cloudflare ` ] ( ./packages/cloudflare ) | Cloudflare Workers 适配器 |
@@ -80,28 +83,28 @@ await provider.destroy(sandbox.id)
8083
8184所有 Provider 都必须实现的最小契约:
8285
83- | 操作 | Daytona | Fly.io | Cloudflare | BoxLite | E2B |
84- | ------| :-------:| :------:| :----------:| :-------:| :---:|
85- | 创建 / 销毁 | ✅ | ✅ | ✅ | ✅ | ✅ |
86- | 列出沙箱 | ✅ | ✅ | ✅ | ✅ | ✅ |
87- | 执行命令 | ✅ | ✅ | ✅ | ✅ | ✅ |
88- | 读写文件 | ✅ | ✅ | ✅ | ✅ | ✅ |
89- | Skill 注入 | ✅ | ✅ | ✅ | ✅ | ✅ |
86+ | 操作 | Sandbank Cloud | Daytona | Fly.io | Cloudflare | BoxLite | E2B |
87+ | ------| :--------------: | :------- :| :------:| :----------:| :-------:| :---:|
88+ | 创建 / 销毁 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
89+ | 列出沙箱 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
90+ | 执行命令 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
91+ | 读写文件 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
92+ | Skill 注入 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
9093
9194### 扩展能力
9295
9396能力是可选的。通过 ` withVolumes(provider) ` 、` withPortExpose(sandbox) ` 等函数在运行时安全检测并访问。
9497
95- | 能力 | Daytona | Fly.io | Cloudflare | BoxLite | E2B | db9 | 说明 |
96- | ------| :-------:| :------:| :----------:| :-------:| :---:| :---:| ------|
97- | ` volumes ` | ✅ | ✅ | ⚠️* | ❌ | ⚠️*** | — | 持久卷管理 |
98- | ` port.expose ` | ✅ | ✅ | ⚠️** | ✅ | ✅ | — | 将沙箱端口暴露到公网 |
99- | ` exec.stream ` | ❌ | ❌ | ✅ | ✅ | ❌ | — | 实时流式输出 stdout/stderr |
100- | ` snapshot ` | ❌ | ❌ | ✅ | ✅ | ❌ | — | 沙箱状态快照与恢复 |
101- | ` terminal ` | ✅ | ✅ | ✅ | ✅ | ✅ | — | 交互式 Web 终端 (ttyd) |
102- | ` sleep ` | ❌ | ❌ | ❌ | ✅ | ✅ | — | 休眠与唤醒 |
103- | ` skills ` | ✅ | ✅ | ✅ | ✅ | ✅ | — | 加载并注入 Skill 定义到沙箱 |
104- | ` services ` | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | 将数据服务 (PostgreSQL) 绑定到沙箱 |
98+ | 能力 | Sandbank Cloud | Daytona | Fly.io | Cloudflare | BoxLite | E2B | db9 | 说明 |
99+ | ------| :--------------: | :------- :| :------:| :----------:| :-------:| :---:| :---:| ------|
100+ | ` volumes ` | ❌ | ✅ | ✅ | ⚠️* | ❌ | ⚠️*** | — | 持久卷管理 |
101+ | ` port.expose ` | ✅ | ✅ | ✅ | ⚠️** | ✅ | ✅ | — | 将沙箱端口暴露到公网 |
102+ | ` exec.stream ` | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | — | 实时流式输出 stdout/stderr |
103+ | ` snapshot ` | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | — | 沙箱状态快照与恢复 |
104+ | ` terminal ` | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | — | 交互式 Web 终端 (ttyd) |
105+ | ` sleep ` | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | — | 休眠与唤醒 |
106+ | ` skills ` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | 加载并注入 Skill 定义到沙箱 |
107+ | ` services ` | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | 将数据服务 (PostgreSQL) 绑定到沙箱 |
105108
106109\* Cloudflare 的 ` volumes ` 需要在适配器配置中启用 ` storage ` 选项。
107110
@@ -111,13 +114,14 @@ await provider.destroy(sandbox.id)
111114
112115### Provider 特性对比
113116
114- | | Daytona | Fly.io | Cloudflare | BoxLite | E2B |
115- | ---| ---------| --------| ------------| ---------| -----|
116- | ** 运行时** | 完整 VM | Firecracker 微虚拟机 | V8 隔离 + 容器 | Docker 容器 | E2B 云沙箱 |
117- | ** 冷启动** | ~ 10s | ~ 3-5s | ~ 1s | ~ 2-5s | Provider 管理 |
118- | ** 文件 I/O** | 原生 SDK | 通过 exec (base64) | 原生 SDK | 通过 exec (base64) | 原生 SDK |
119- | ** 区域** | 多区域 | 多区域 | 全球边缘 | 自托管 | E2B 管理 |
120- | ** 外部依赖** | ` @daytonaio/sdk ` | 无 (纯 fetch) | ` @cloudflare/sandbox ` | BoxLite API | ` e2b ` |
117+ | | Sandbank Cloud | Daytona | Fly.io | Cloudflare | BoxLite | E2B |
118+ | ---| ----------------| ---------| --------| ------------| ---------| -----|
119+ | ** 定位** | 推荐默认 provider | 云沙箱 | VM/microVM | 边缘 Worker | 自托管 BoxLite | 云沙箱 |
120+ | ** 运行时** | 托管 BoxLite 容器 | 完整 VM | Firecracker 微虚拟机 | V8 隔离 + 容器 | Docker 容器 | E2B 云沙箱 |
121+ | ** 冷启动** | 托管服务优化 | ~ 10s | ~ 3-5s | ~ 1s | ~ 2-5s | Provider 管理 |
122+ | ** 文件 I/O** | Archive API | 原生 SDK | 通过 exec (base64) | 原生 SDK | 通过 exec (base64) | 原生 SDK |
123+ | ** 区域** | Sandbank 管理 | 多区域 | 多区域 | 全球边缘 | 自托管 | E2B 管理 |
124+ | ** 外部依赖** | ` @sandbank.dev/cloud ` + API token/x402 | ` @daytonaio/sdk ` | 无 (纯 fetch) | ` @cloudflare/sandbox ` | BoxLite API | ` e2b ` |
121125
122126## 多 Agent 会话
123127
@@ -169,7 +173,7 @@ await session.complete({ status: 'success', summary: '完成了 5 个 API 端点
169173
170174## Workspace Agent Harness
171175
172- Sandbank 的 harness 以 ` WorkspaceAdapter ` 为 Agent 的权威状态边界。一次 agent run 可以先让模型规划,再用 Dynamic Worker 执行受限 JS code mode,把生成的 Python 写入 Workspace,随后由 provider scheduler 选择 E2B、BoxLite、Daytona、Fly.io 或其他声明 ` runtime.python ` 的后端执行,最后把产物、日志和 memory 写回 Workspace。
176+ Sandbank 的 harness 以 ` WorkspaceAdapter ` 为 Agent 的权威状态边界。一次 agent run 可以先让模型规划,再用 Dynamic Worker 执行受限 JS code mode,把生成的 Python 写入 Workspace,随后由 provider scheduler 优先选择 Sandbank Cloud,或按策略切换到 E2B、BoxLite、Daytona、Fly.io 等声明 ` runtime.python ` 的后端执行,最后把产物、日志和 memory 写回 Workspace。
173177
174178这种结构让调用方可以替换计算后端,而不用把 Agent 的长期状态绑在某个 VM、container、volume 或 Workers storage binding 上。权限边界也在 harness 层统一处理:Tool Use 请求先经过 Agent policy/resource grants/approval rules,再调用宿主注册的工具或调度 sandbox provider。
175179
@@ -218,13 +222,15 @@ import {
218222const taskConfig = {
219223 workspace ,
220224 providers: [
225+ { provider: sandbankCloudProvider , capabilities: [' runtime.python' , ' codex.exec' ], priority: 30 },
221226 { provider: e2bProvider , capabilities: [' runtime.python' ], priority: 10 },
222227 { provider: boxliteProvider , capabilities: [' runtime.python' ] },
223228 ],
224229 task: { kind: ' python' as const , path: ' /workspace/generated/task.py' , image: ' python-agent' },
225230 imageCatalog: {
226231 ' python-agent' : {
227232 default: ' python:3.12' ,
233+ ' sandbank-cloud' : ' python:3.12-slim' ,
228234 e2b: ' e2b-python-template' ,
229235 boxlite: ' python:3.12-slim' ,
230236 },
@@ -279,6 +285,7 @@ const supervisor = new AgentSupervisor({
279285 registry ,
280286 dynamicWorker ,
281287 sandboxProviders: [
288+ { provider: sandbankCloudProvider , capabilities: [' runtime.python' , ' codex.exec' ] },
282289 { provider: e2bProvider , capabilities: [' runtime.python' ] },
283290 { provider: boxliteProvider , capabilities: [' runtime.python' ] },
284291 ],
@@ -291,6 +298,7 @@ const supervisor = new AgentSupervisor({
291298 { kind: ' external.search' , id: ' perplexity' , actions: [' query' ] },
292299 { kind: ' http.egress' , id: ' api.example.com' , actions: [' fetch' ] },
293300 { kind: ' workspace.path' , scope: ' /runs' , actions: [' write' ] },
301+ { kind: ' sandbox.provider' , id: ' sandbank-cloud' , actions: [' execute' ] },
294302 { kind: ' sandbox.provider' , id: ' e2b' , actions: [' execute' ] },
295303 { kind: ' runtime.python' , actions: [' execute' ] },
296304 ],
@@ -309,19 +317,21 @@ Tool 注册目前由第三方宿主代码完成:调用方在初始化 harness/
309317## 快速开始
310318
311319``` bash
312- # 安装
313- pnpm add @sandbank.dev/core @sandbank.dev/daytona # 或 @sandbank.dev/flyio、@sandbank.dev/cloudflare、@sandbank.dev/e2b
320+ # 安装推荐 provider
321+ pnpm add @sandbank.dev/core @sandbank.dev/cloud
314322
315323# 配置 Provider
316- export DAYTONA_API_KEY=your-key
324+ export SANDBANK_API_TOKEN=your-key
325+ # 或使用 x402 按次付费
326+ export WALLET_PRIVATE_KEY=0x...
317327```
318328
319329``` typescript
320330import { createProvider } from ' @sandbank.dev/core'
321- import { DaytonaAdapter } from ' @sandbank.dev/daytona '
331+ import { SandbankCloudAdapter } from ' @sandbank.dev/cloud '
322332
323333const provider = createProvider (
324- new DaytonaAdapter ({ apiKey : process .env .DAYTONA_API_KEY ! })
334+ new SandbankCloudAdapter ({ apiToken : process .env .SANDBANK_API_TOKEN })
325335)
326336
327337// 创建沙箱
@@ -399,6 +409,9 @@ benchmark 会把每个 case POST 到 `/api/db-native-agent-harness/stream`,记
399409集成测试会调用真实 API,通过环境变量控制开关:
400410
401411``` bash
412+ # Sandbank Cloud(推荐默认 provider)
413+ SANDBANK_API_TOKEN=... pnpm test
414+
402415# Daytona
403416DAYTONA_API_KEY=... pnpm test
404417
0 commit comments