Workspace 与 Session 契约(评估)¶
状态: 评估草案,2026-10-24。本页不是 API 承诺。它记录问题、候选形态、
提供商问题,以及把契约提升到 pkg/ 的验收标准。
为什么评估¶
PRAXO-CORE 目前有两个独立接缝:
| 接缝 | 契约 | 当前用途 |
|---|---|---|
| 虚拟文件系统 | vfs.Backend |
读、写、列目录、glob、grep、删除 |
| 命令执行 | vfs.Executor |
VFS backend 上的可选 shell 执行 |
| 沙箱 | sandbox.Sandbox |
一次 Run(ctx, Spec, command) 调用 |
| 解释器 | sandbox.Interpreter |
可选的进程内脚本求值 |
这对无状态执行和本地工作区已经足够。E2B、OpenSandbox、CubeSandbox 等远程 沙箱服务增加了生命周期:
create or attach -> execute -> upload/download -> pause/resume -> close
Deep Agents 把它建模为可插拔 backend 协议,并让 sandbox backend 增加执行能力。 PRAXO-CORE 应学习这种形态,但不复制 LangGraph state、图运行时或提供商 Core。
缺口不是“接入更多 sandbox”,而是能对至少两个实现验证的、提供商中立的 session 契约。
需求¶
- 有状态生命周期。 创建或 attach、执行多次命令、传输文件并关闭。 Pause、resume、snapshot 是可选能力,不是必需方法。
- 组合优先。 Session 应暴露现有
sandbox.Sandbox和vfs.Backend行为, 而不是重新定义它们。 - 不泄漏提供商。 公共契约不包含 E2B、OpenSandbox 或 CubeSandbox 的类型、 凭据、端点或控制平面字段。
- 认证与租户由调用方拥有。 产品通过适配器配置传入凭据和租户上下文, 核心契约不保存它们。
- Context 与超时。 每个操作接收
context.Context;超时和取消可观察, 且不泄漏 session。 - 错误映射。 缺失 session、不支持的能力、策略失败和提供商错误可区分。
- 无控制平面。 池化、镜像目录、快照、网络策略、配额、计费、多租户隔离、 审计和 SLA 由产品拥有。
- 一致性。 共享检查套件必须能对 fake 和至少两个真实提供商运行,之后才能 提升到核心。
候选形态¶
以下是设计草图,不是导出 API。
package workspace
type Spec struct {
Image string
WorkDir string
Env map[string]string
Timeout time.Duration
Metadata map[string]string
}
type Session interface {
ID() string
sandbox.Sandbox
vfs.Backend
Upload(ctx context.Context, path string, data []byte) error
Download(ctx context.Context, path string) ([]byte, error)
Close(ctx context.Context) error
}
type Provider interface {
Create(ctx context.Context, spec Spec) (Session, error)
Attach(ctx context.Context, id string) (Session, error)
}
type Pauser interface {
Pause(ctx context.Context) error
Resume(ctx context.Context) error
}
需要评估的替代方案:
- 嵌入 vs 组合。 嵌入
sandbox.Sandbox和vfs.Backend更方便,但要求 每个 session 同时支持两者。返回Files()和Sandbox()访问器更灵活, 但使用体验较差。 - 可选能力。 Pause/resume 应是独立接口,而不是运行时失败的方法。快照和 端口访问同理。
- Session 标识。 决定
ID()是提供商本地、全局唯一还是不透明。产品不得 解析它。 - Attach 语义。 Attach 可能不支持、可能要求相同调用方身份,或用于恢复 暂停的 session。这些是不同能力。
- 文件传输。 对于 VFS 操作昂贵或异步的提供商,upload/download 可能是 必需能力。不要假设它们成本很低。
- 资源与网络策略。 在两个提供商证明有稳定共同子集前,留在适配器配置中。
提供商评估¶
下表记录离线适配器 spike 实际验证过的内容。“离线”表示该操作在进程内 fake 上 通过共享一致性检查,不代表实网提供商行为。
| 问题 | E2B | Daytona |
|---|---|---|
| Go Core 或稳定 HTTP API | REST + envd Connect/JSON;无官方 Go Core | Go Core v0.226.1 |
| Create / attach / close | 离线通过;实网待验证 | 离线通过;实网待验证 |
| 重复命令执行 | 离线通过 | 离线通过 |
| Upload / download | 离线通过 | 离线通过 |
| Pause / resume | 离线通过;实网待验证 | 离线通过;实网待验证 |
| Snapshot 或模板 | 提供商支持;适配器未映射 | 提供商支持;适配器未映射 |
| 网络与端口策略 | 提供商支持;适配器未暴露 | 提供商支持;适配器未暴露 |
| 超时与取消 | Context + Connect timeout | Context + execution timeout |
| 错误分类 | Connect/envd 错误;仅映射 not-found/closed | Core 错误;仅映射 not-found/closed |
| 认证与租户模型 | API key + envd access token | API key 或 JWT,organization 与 target |
| 许可证兼容性 | Apache-2.0 | cli/ 外为 Apache-2.0;cli/ 为 AGPL-3.0 |
| 控制平面功能 | 提供商拥有 | 提供商拥有 |
适配器 spike 必须记录测试版本、端点类型、许可证,以及哪些能力不可用。
Spike 结论¶
- 共同子集与候选
Session一致:create/attach、execute、upload/download、 VFS 读写、pause/resume。 - 嵌入
vfs.Backend和sandbox.Sandbox对两个适配器都适用;可选Pauser也适用。 - E2B 需要自定义 Connect frame 编解码和 envd 头;Daytona 需要 Core 包装,因为 Core 只返回一个合并的命令输出字符串。
- 两个适配器的
Glob/Grep都是客户端遍历;没有可移植的服务端搜索契约。 - Snapshot 和网络策略是提供商特有能力,不应进入第一版契约。
- 路径和工作目录语义不同。适配器归一化相对路径;实网验证必须确认 home 和 cwd 行为。
- 提升前仍需:实网一致性、最小错误分类、取消与并发测试、大文件传输测试、 attach 语义决策。
后续候选¶
下一轮 spike 还应纳入两个提供商:
- OpenSandbox(Apache-2.0):Go Core
github.com/alibaba/OpenSandbox/sdks/sandbox/go;提供 lifecycle、execd 和 egress API;支持 Docker/Kubernetes、Firecracker pause/resume 和网络策略。 适配器状态:离线 conformance 适配器;实网待验证。 - CubeSandbox(Apache-2.0,列明的第三方组件除外):Go Core
github.com/tencentcloud/CubeSandbox/sdk/go;兼容 E2B API;RustVMM/KVM 隔离;pause/resume、快照、卷和 egress 策略。适配器状态:离线 conformance 适配器;实网待验证。先验证 E2B 适配器能否作为兼容 profile,再决定是否保留 单独实现。
OpenSandbox 增加自托管 Go Core 与出站控制路径;CubeSandbox 增加硬件级隔离和
E2B 兼容面。两者都不改变核心契约,只作为 provider adapter,也不会把控制平面
放进 pkg/。
CubeSandbox 与 E2B 兼容性¶
离线复核发现 CubeSandbox 在 Core 和数据面层面兼容 E2B,但不是当前 E2B 适配器 的直接配置替代:
- CubeSandbox 的
Client.Create和Client.Connect使用/sandboxes,而 E2B 适配器使用/v2/sandboxes。CubeSandbox 确实为列表提供/v2/sandboxes,但这不证明 create/connect 的 v2 路径完全一致。 - CubeSandbox 数据面发送
X-Access-Token,并额外发送e2b-traffic-access-token/cube-traffic-access-token;E2B 适配器只发送X-Access-Token。 - CubeSandbox 接受
E2B_API_URL和E2B_API_KEY作为配置回退,因此实网 验证后共享 profile 仍有可能。
建议:保留独立的 CubeSandbox 适配器。在实网 CubeSandbox 端点确认 create/connect v2 路径和 traffic token 行为前,不要把 E2B 适配器当作 CubeSandbox profile。
原型计划¶
- 在核心之外增加两个适配器模块:
adapters/workspace/e2b和adapters/workspace/daytona。各自独立go.mod和 tag。 - 使用调用方提供的凭据实现 create/attach、execute、upload/download 和 close。 不把提供商 Core 加入核心模块。
- 增加一个实现相同契约的内存 fake,用于离线测试。
- 对 fake 和两个适配器运行同一套 conformance 检查。实网提供商测试必须按需 运行,不能进入默认 CI。
- 记录每个不匹配的能力、每个提供商专用字段,以及无法清晰映射的错误。
- 只有完成上述步骤后,才提议加法式
pkg/契约。现有pkg/vfs和pkg/sandbox声明保持不变。
提升标准¶
只有满足以下条件,workspace/session 契约才可进入 pkg/:
- 两个提供商实现它,且公共契约没有提供商专用字段;
- fake 和两个适配器通过同一套一致性检查;
- 取消和超时不会泄漏 session;
- 错误映射有文档和测试;
- 核心模块仍不依赖提供商 Core;
- API 是加法式的,不改变
vfs.Backend、vfs.Executor或sandbox.Sandbox; - 已编写兼容与迁移说明。
在此之前,契约只存在于适配器或评估模块中。当前 spike 位于
adapters/workspace,
包含候选契约、内存 fake、一致性检查,以及 E2B 和 Daytona 的离线适配器。
当前环境尚未对任一实网提供商进行验证。
实网检查按需运行:缺少凭据时自动跳过。E2B 需要 E2B_API_KEY;Daytona 需要
DAYTONA_API_KEY 和 DAYTONA_IMAGE。在各自模块中运行
go test -run TestLiveConformance。
非目标¶
- Sandbox 控制平面、调度器、热池、镜像仓库或计费系统。
- 图运行时或持久工作流引擎。
- 把提供商专用字段放入
pkg/...。 - 声称 sandbox 接口提供 OS 级隔离。隔离由提供商或产品提供。
待解决问题¶
Session应嵌入vfs.Backend和sandbox.Sandbox,还是通过访问器暴露?Attach是核心生命周期操作,还是提供商能力?- Pause/resume/snapshot 是否共享一个可选能力接口?
- 提供商侧 session ID 如何跨租户和区域隔离?
- 最小可移植错误分类是什么?
- 哪些文件传输语义可以安全标准化:覆盖、原子写、目录上传,还是都不?
- Workspace session 是否需要 lease 或 heartbeat,还是由产品拥有?