Skip to content
agent-nextPublic
forked from chekusu/sandbank

About

unified agent workspace

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

 
 

Repository files navigation

Sandbank

AI Agent 统一 Workspace Agent Harness — 一个 Workspace,多种后端沙盒。

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 云服务。

官网 | English | 日本語

像素画风格的一群小机器人 Agent 在海中沙滩上度假,每个机器人都有不同的开发者角色

为什么选择 Sandbank?

AI Agent 需要的不只是一个隔离沙箱。它需要一个可恢复、可审计、可跨运行时迁移的长期 Workspace,同时还要能按任务选择合适的计算后端:短 JS code mode 可以跑在 Cloudflare Dynamic Worker,Python、Codex 和 shell 任务默认优先派发到 Sandbank Cloud(托管 BoxLite),特殊场景再切到 E2B、本地 BoxLite、Fly.io 或 VM/container,最终输出同步回同一个 Workspace。

底层沙箱 provider SDK 仍然可用,用来屏蔽 Daytona、Fly.io、Cloudflare Workers 等不同 API:

import { createProvider } from '@sandbank.dev/core'
import { SandbankCloudAdapter } from '@sandbank.dev/cloud'

const provider = createProvider(new SandbankCloudAdapter({
  apiToken: process.env.SANDBANK_API_TOKEN,
}))
const sandbox = await provider.create({ image: 'node:22' })

const result = await sandbox.exec('echo "Hello from the sandbox"')
console.log(result.stdout) // Hello from the sandbox

await provider.destroy(sandbox.id)

Sandbank Cloud 是默认推荐 provider;把 SandbankCloudAdapter 换成 DaytonaAdapter、FlyioAdapter 或 CloudflareAdapter,沙箱创建/执行代码仍无需重写。更高一层的 harness 会把这些 provider 当作计算后端,而不是 Agent 的长期家。

架构

┌──────────────────────────────────────────────────────┐
│  你的应用 / AI Agent / 第三方调用方                    │
├──────────────────────────────────────────────────────┤
│  sandbank                   Workspace Agent Harness      │
│  AgentSupervisor            policy / memory / tool use   │
│  Provider Scheduler         多后端计算调度与同步          │
│  @sandbank.dev/workspace    持久 Workspace 与 Checkpoint  │
├──────────────────────────────────────────────────────┤
│  @sandbank.dev/core         底层 Provider SDK             │
│  @sandbank.dev/skills       Skill 注册表与注入            │
│  @sandbank.dev/agent        沙箱内 Agent 客户端           │
│  @sandbank.dev/relay        多 Agent 通信中枢             │
├──────────────────────────────────────────────────────┤
│  @sandbank.dev/cloud    @sandbank.dev/boxlite  @sandbank.dev/e2b       │
│  @sandbank.dev/daytona  @sandbank.dev/flyio    @sandbank.dev/cloudflare│
│  Provider 适配器(计算)                               │
├──────────────────────────────────────────────────────┤
│  @sandbank.dev/db9       Service Adapter(数据)       │
├──────────────────────────────────────────────────────┤
│  Sandbank Cloud (托管 BoxLite)    BoxLite (自托管 Docker) │
│  E2B Cloud Sandboxes    Daytona    Fly.io Machines    Cloudflare Workers │
│  db9.ai (PostgreSQL)                                  │
└──────────────────────────────────────────────────────┘

包一览

包名 说明
sandbank Workspace Agent Harness、Agent Supervisor、Tool Use、provider scheduler、CLI/Worker entrypoints
@sandbank.dev/core 底层 Provider SDK、能力系统、错误类型
@sandbank.dev/skills Skill 注册表、本地文件系统加载器
@sandbank.dev/workspace 持久 Workspace 协议、checkpoint、沙箱 materialize/sync helper
@sandbank.dev/cloud Sandbank Cloud 托管 BoxLite 云服务适配器,推荐默认 provider,支持 API token 或 x402 付费
@sandbank.dev/daytona Daytona 云沙箱适配器
@sandbank.dev/flyio Fly.io Machines 适配器
@sandbank.dev/cloudflare Cloudflare Workers 适配器
@sandbank.dev/boxlite BoxLite 自托管 Docker 适配器
@sandbank.dev/docker 本地 Docker 容器适配器(CLI,无 SDK 依赖)
@sandbank.dev/e2b E2B 云沙箱适配器
@sandbank.dev/sbx agent-next sandbox (sbx) 适配器,E2B 兼容云沙箱
@sandbank.dev/instabox InstaBox 云沙箱适配器
@sandbank.dev/db9 db9.ai serverless PostgreSQL 适配器 (ServiceProvider)
@sandbank.dev/relay WebSocket 中继,用于多 Agent 通信
@sandbank.dev/agent 沙箱内 Agent 轻量客户端

Provider 支持情况

基础操作

所有 Provider 都必须实现的最小契约:

操作 Sandbank Cloud Daytona Fly.io Cloudflare BoxLite E2B sbx Docker
创建 / 销毁 ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
列出沙箱 ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
执行命令 ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
读写文件 ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
Skill 注入 ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅

扩展能力

能力是可选的。通过 withVolumes(provider)、withPortExpose(sandbox) 等函数在运行时安全检测并访问。

能力 Sandbank Cloud Daytona Fly.io Cloudflare BoxLite E2B sbx Docker db9 说明
volumes ❌ ✅ ✅ ⚠️* ❌ ⚠️*** ❌ ✅ — 持久卷管理
port.expose ✅ ✅ ✅ ⚠️** ✅ ✅ ✅ ✅ — 将沙箱端口暴露到公网
exec.stream ✅ ❌ ❌ ✅ ✅ ❌ ❌ ✅ — 实时流式输出 stdout/stderr
snapshot ❌ ❌ ❌ ✅ ✅ ❌ ❌ ❌ — 沙箱状态快照与恢复
terminal ❌ ✅ ✅ ✅ ✅ ✅ ✅ ❌ — 交互式 Web 终端 (ttyd)
sleep ❌ ❌ ❌ ❌ ✅ ✅ ✅ ✅ — 休眠与唤醒
skills ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ — 加载并注入 Skill 定义到沙箱
services ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ✅ 将数据服务 (PostgreSQL) 绑定到沙箱

* Cloudflare 的 volumes 需要在适配器配置中启用 storage 选项。

** Cloudflare 保留了 3000 端口用于沙箱控制面板,可用范围为 1024–65535(不含 3000)。

*** E2B volumes 目前需要 E2B volume beta 权限。Sandbank 会用卷 id 连接 E2B Volume 后挂载。

Provider 特性对比

Sandbank Cloud Daytona Fly.io Cloudflare BoxLite E2B sbx Docker
定位 推荐默认 provider 云沙箱 VM/microVM 边缘 Worker 自托管 BoxLite 云沙箱 agent-next 云沙箱 本地 / 自托管
运行时 托管 BoxLite 容器 完整 VM Firecracker 微虚拟机 V8 隔离 + 容器 Docker 容器 E2B 云沙箱 E2B 兼容云沙箱 (CPU/GPU) Docker 容器
冷启动 托管服务优化 ~10s ~3-5s ~1s ~2-5s Provider 管理 ~1s <1s (镜像已缓存)
文件 I/O Archive API 原生 SDK 通过 exec (base64) 原生 SDK 通过 exec (base64) 原生 SDK 原生 SDK 通过 exec (stdin)
区域 Sandbank 管理 多区域 多区域 全球边缘 自托管 E2B 管理 agent-next 管理 本地或 DOCKER_HOST
外部依赖 @sandbank.dev/cloud + API token/x402 @daytonaio/sdk 无 (纯 fetch) @cloudflare/sandbox BoxLite API e2b e2b docker CLI

多 Agent 会话

Sandbank 内置编排层,支持多 Agent 实时协作。Relay 负责沙箱间的消息传递和共享上下文。

import { createSession } from '@sandbank.dev/core'

const session = await createSession({
  provider,
  relay: { type: 'memory' },
})

// 在隔离沙箱中启动 Agent
const architect = await session.spawn('architect', {
  image: 'node:22',
  env: { ROLE: 'architect' },
})

const developer = await session.spawn('developer', {
  image: 'node:22',
  env: { ROLE: 'developer' },
})

// 共享上下文 — 所有 Agent 均可读写
await session.context.set('spec', { endpoints: ['/users', '/posts'] })

// 等待所有 Agent 完成
await session.waitForAll()
await session.close()

在沙箱内部,Agent 使用 @sandbank.dev/agent:

import { connect } from '@sandbank.dev/agent'

const session = await connect() // 自动读取 SANDBANK_* 环境变量

session.on('message', async (msg) => {
  if (msg.type === 'task') {
    // 执行任务...
    await session.send(msg.from, 'done', result)
  }
})

await session.complete({ status: 'success', summary: '完成了 5 个 API 端点' })

Workspace Agent Harness

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。

这种结构让调用方可以替换计算后端,而不用把 Agent 的长期状态绑在某个 VM、container、volume 或 Workers storage binding 上。权限边界也在 harness 层统一处理:Tool Use 请求先经过 Agent policy/resource grants/approval rules,再调用宿主注册的工具或调度 sandbox provider。

Provider-Neutral Workspaces(跨 Provider Workspace)

Provider 原生 volume 都是 provider-specific 资源。Fly.io volume、E2B volume、Daytona volume、Cloudflare storage binding 并不是同一块持久磁盘。要在不同 sandbox provider 之间切换并保持状态连续,需要把权威状态放在 WorkspaceAdapter 里:运行前 materialize 到沙箱,运行后把变更 sync 回 Workspace,并在后端支持时创建 checkpoint。

import {
  MemoryWorkspaceAdapter,
  materializeWorkspaceToSandbox,
  syncWorkspaceFromSandbox,
} from '@sandbank.dev/workspace'

const workspace = new MemoryWorkspaceAdapter()
await workspace.write('/workspace/task.md', 'ship it')

const sandbox = await provider.create({ image: 'node:22' })
await materializeWorkspaceToSandbox(workspace, sandbox, {
  workspacePath: '/workspace',
  sandboxPath: '/workspace',
})

await sandbox.exec('echo done > /workspace/result.txt')

await syncWorkspaceFromSandbox(workspace, sandbox, {
  workspacePath: '/workspace',
  sandboxPath: '/workspace',
  deleteMissing: true,
  checkpointLabel: 'after provider run',
})

Provider-native volumes 适合作为本地 cache 或 provider 内部持久化;跨 provider rollback、checkpoint、连续运行和一致性合并应以 Workspace 为准。

Provider Scheduler 与 Preflight

顶层 sandbank 包导出 selectSandboxProvider、preflightWorkspaceSandboxTask 和 runWorkspaceSandboxTask。调度器把 sandbox provider 当作计算候选,根据 runtime.python、runtime.codex、codex.exec、codex.goal、workspace.snapshot、workspace.live 等声明能力选择 provider。

import {
  preflightWorkspaceSandboxTask,
  runWorkspaceSandboxTask,
} from 'sandbank'

const taskConfig = {
  workspace,
  providers: [
    { provider: sandbankCloudProvider, capabilities: ['runtime.python', 'codex.exec'], priority: 30 },
    { provider: e2bProvider, capabilities: ['runtime.python'], priority: 10 },
    { provider: boxliteProvider, capabilities: ['runtime.python'] },
  ],
  task: { kind: 'python' as const, path: '/workspace/generated/task.py', image: 'python-agent' },
  imageCatalog: {
    'python-agent': {
      default: 'python:3.12',
      'sandbank-cloud': 'python:3.12-slim',
      e2b: 'e2b-python-template',
      boxlite: 'python:3.12-slim',
    },
  },
  preflight: { runtime: true },
}

const preflight = await preflightWorkspaceSandboxTask(taskConfig)
if (!preflight.ok) throw new Error(preflight.errors.join('; '))

await runWorkspaceSandboxTask({
  ...taskConfig,
  consistency: { mode: 'branch-merge', conflictResolution: 'keep-both' },
  preflight: false,
})

Static preflight 会在执行前检查 Workspace 和 provider 能力;runtime preflight 会创建临时 sandbox 探测镜像工具,例如 python、codex、git、tmux、tar、gzip。codex.goal 会启动 vas 风格的 tmux 会话并保留沙箱,方便终端 attach 和后续 Workspace sync。更多细节见 Provider Scheduler And Workspace Consistency 和 Sandbank Agent Configuration。

Agent Tool Use

Sandbank Tool Use 是比单一模型 adapter 更底层的协议。模型循环、Dynamic Worker capsule 或托管 Agent 都提交结构化的 tool.use 请求;Agent Supervisor 会先检查该 Agent 的 tool/resource policy,然后才调用 handler 或 sandbox provider。

import {
  AgentSupervisor,
  ToolUseRegistry,
  createCloudflareResourceTool,
  createSearchCodeRunTool,
  createSandboxPythonTool,
} from 'sandbank'

const registry = new ToolUseRegistry()
  .register(createCloudflareResourceTool('read', async input => {
    // 这里可以连接 Cloudflare D1/KV/R2 等 bindings 或 API。
    return { ok: true, resource: input.resource }
  }))
  .register(createSearchCodeRunTool({
    search: {
      provider: 'perplexity',
      search: async query => searchProvider.search(query),
      fetchJson: async url => searchProvider.fetchJson(url),
    },
  }))
  .register(createSandboxPythonTool())

const supervisor = new AgentSupervisor({
  agentId: 'agent-a',
  workspace,
  modelId: 'deepseek-v4-pro',
  toolUse: {
    registry,
    dynamicWorker,
    sandboxProviders: [
      { provider: sandbankCloudProvider, capabilities: ['runtime.python', 'codex.exec'] },
      { provider: e2bProvider, capabilities: ['runtime.python'] },
      { provider: boxliteProvider, capabilities: ['runtime.python'] },
    ],
    policy: {
      allowedTools: ['cloudflare.resource.read', 'search.code.run', 'sandbox.python'],
      resources: [
        { kind: 'cloudflare.d1', id: 'analytics', actions: ['read'] },
        { kind: 'dynamic_worker.execution', actions: ['execute'] },
        { kind: 'runtime.javascript', actions: ['execute'] },
        { kind: 'external.search', id: 'perplexity', actions: ['query'] },
        { kind: 'http.egress', id: 'api.example.com', actions: ['fetch'] },
        { kind: 'workspace.path', scope: '/runs', actions: ['write'] },
        { kind: 'sandbox.provider', id: 'sandbank-cloud', actions: ['execute'] },
        { kind: 'sandbox.provider', id: 'e2b', actions: ['execute'] },
        { kind: 'runtime.python', actions: ['execute'] },
      ],
      requireApproval: [
        { kind: 'cloudflare.d1', action: 'write' },
      ],
    },
  },
})

Tool 注册目前由第三方宿主代码完成:调用方在初始化 harness/supervisor 时创建 ToolUseRegistry,通过 .register(...) 注入工具定义,再用每个 agent/run 的 policy 启用白名单。当前没有开放“远程任意用户注册 tool”的管理端点。

resources 是 Agent 启用时的计算和数据资源白名单。即使 prompt 要求 Agent 修改用户数据库,请求也必须匹配允许的 resource/action,并满足对应的 approval rule。search.code.run 是 code mode:模型可以生成 JavaScript 函数体,由 Dynamic Worker 执行,并只能通过 ctx.search、ctx.workspace、ctx.runtime 这些受控 binding 访问能力;裸网络访问仍要匹配 http.egress grant。sandbox.python 会走 provider scheduler,因此 Dynamic Worker 生成的 Python 可以派发到 E2B、BoxLite、Sandbank Cloud 或任何声明 runtime.python 的 provider。Dynamic Worker capsule 通过 SANDBANK_TOOLS.list() 和 SANDBANK_TOOLS.use(request) 走同一条 supervisor policy,不会绕过权限控制。

快速开始

# 安装推荐 provider
pnpm add @sandbank.dev/core @sandbank.dev/cloud

# 配置 Provider
export SANDBANK_API_TOKEN=your-key
# 或使用 x402 按次付费
export WALLET_PRIVATE_KEY=0x...
import { createProvider } from '@sandbank.dev/core'
import { SandbankCloudAdapter } from '@sandbank.dev/cloud'

const provider = createProvider(
  new SandbankCloudAdapter({ apiToken: process.env.SANDBANK_API_TOKEN })
)

// 创建沙箱
const sandbox = await provider.create({
  image: 'node:22',
  resources: { cpu: 2, memory: 2048 },
  autoDestroyMinutes: 30,
})

// 执行命令
const { stdout } = await sandbox.exec('node --version')

// 文件操作
await sandbox.writeFile('/app/index.js', 'console.log("hi")')
await sandbox.exec('node /app/index.js')

// 清理
await provider.destroy(sandbox.id)

开发

git clone https://github.com/chekusu/sandbank.git
cd sandbank
pnpm install

# 运行全部单元测试
pnpm test

# 运行跨 Provider 一致性测试
pnpm test:conformance

# 类型检查
pnpm typecheck

DB-native Harness API

sandbank CLI 和 Worker entrypoint 暴露了公开的 Sandbank harness API,底层由 Agent Supervisor、db9 Workspace storage 和 DeepSeek V4 Pro 驱动:

DB9_DATABASE_ID=... DB9_TOKEN=... DEEPSEEK_API_KEY=... \
  vas dev sandbank-harness pnpm --filter ./packages/sandbank exec tsx src/cli/index.ts harness-api --host 0.0.0.0 --port 8789

Routes:

  • GET /health
  • GET /api/db-native-agent-harness/capabilities
  • POST /api/sandbank-agent-harness/stream
  • POST /api/db-native-agent-harness/stream

stream 会发送通用 Sandbank SSE events,把 run input/output 持久化到 /runs/...,把 supervisor state/audit data 写入 /agents/...,并在 Workspace 后端支持时创建 checkpoint。默认模型是 deepseek-v4-pro。它还会把 Agent memory 存在 /agents/{agentId}/memory/memories.jsonl,将 active pinned / insight / session 记忆注入模型 prompt,并把显式的 remember / 记住 请求写成 pinned memory。Worker-compatible entrypoint 导出为 sandbank/harness-worker;Node CLI 用于通过 vas dev 或等价部署路径托管服务,不是 localhost-only preview。模型、Workspace、provider 和镜像要求见 Sandbank Agent Configuration。

用一个 prompt 对线上 harness 做 benchmark:

pnpm --filter ./packages/sandbank exec tsx src/cli/index.ts harness-benchmark \
  --base-url https://your-sandbank-worker.example \
  --question "@agent run a Sandbank harness health check" \
  --json

运行默认 benchmark suite:

SANDBANK_HARNESS_BASE_URL=https://your-sandbank-worker.example pnpm bench:harness -- --json

benchmark 会把每个 case POST 到 /api/db-native-agent-harness/stream,记录 SSE timeline,并按 HTTP/SSE transport、harness lifecycle、Workspace persistence、Dynamic Worker capsule execution、model streaming、case expectations 和 latency 计分,满分 100。

运行集成测试

集成测试会调用真实 API,通过环境变量控制开关:

# Sandbank Cloud(推荐默认 provider)
SANDBANK_API_TOKEN=... pnpm test

# Daytona
DAYTONA_API_KEY=... pnpm test

# Fly.io
FLY_API_TOKEN=... FLY_APP_NAME=... pnpm test

# Cloudflare
E2E_WORKER_URL=... pnpm test

# db9
DB9_TOKEN=... pnpm --filter @sandbank.dev/db9 test:e2e

测试覆盖率

Package Stmts Branch Funcs Lines Unit Integration
@sandbank.dev/core 84% 77% 74% 88% 98 —
@sandbank.dev/db9 100% 97% 93% 100% 35 3

本地运行 coverage:

pnpm --filter @sandbank.dev/db9 test -- --coverage

设计原则

  1. 最小接口,最大互操作 — 只做真正的最大公约数 (exec + files + lifecycle)
  2. 显式优于隐式 — 不自动 fallback、不缓存、不隐式重试
  3. 能力检测,而非假实现 — 不支持就报错,不返回假数据
  4. 幂等操作 — 销毁已销毁的沙箱不报错
  5. 完全解耦 — Provider 层和 Session 层独立,自由组合

许可证

MIT

About

unified agent workspace

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages