Workspace 管理
Cell 内的文件产出管理,与 Memory 对等的 Handle,涵盖三域模型、API 与路径安全。
Workspace 概念
Workspace 是 Cell 内的文件产出管理系统(INV-IO-05),与 cell.Memory() 对等:
cell.Workspace() // List / Download / Upload / Delete / Stats / GC
cell.Memory() // List / Save / Search / Delete / Counts / GC
每个 Cell 拥有独立的 Workspace 目录,物理隔离在 Cell 数据目录下。
三域模型
wesgine 的文件 I/O 分为三个域:
ArtifactDir — 持久产出
{CellDataDir}/workspace/{actor}/
| 特性 | 说明 |
|---|---|
| 计算方式 | 由引擎从 (CellDataDir, Actor, AgentID) 推算 |
| 外部传入 | ❌ 不从 AppRunRequest 传入(INV-IO-01) |
| 物理位置 | Cell 目录下(INV-IO-04) |
| 满足 | AX-1 隔离 + Export 可移植 |
| 系统提示词 | 不出现在"项目"列表中 |
ScratchDir — 临时计算
{CellDataDir}/.scratch/{runID}/
| 特性 | 说明 |
|---|---|
| 生命周期 | Run 结束后由引擎 GC(os.RemoveAll)(INV-IO-06) |
| Export | 永不包含(INV-IO-08) |
| 用途 | 中间计算结果、临时文件 |
HostPaths — 宿主路径
由 CellSpec.AllowPaths 声明
| 特性 | 说明 |
|---|---|
| 引擎行为 | 只验证边界(INV-IO-07) |
| 不做 | MkdirAll、Chmod、GC、Export |
| 用途 | 宿主机的工作目录、项目路径 |
PrimaryRoot — 主工作上下文
PrimaryRoot 是 Agent 认知的"主工作上下文"——出现在系统提示词标为 active project。
Fallback 链
显式声明 (CellSpec.AgentDefaults.Workspace.PrimaryRoot)
↓ 无
AllowPaths[0]
↓ 无
ArtifactDir
约束
PrimaryRoot 必须在 AllowPaths ∪ {ArtifactDir} 内。
spec := wesgine.CellSpec{
AgentDefaults: wesgine.AgentDefaults{
Workspace: wesgine.WorkspaceDefaults{
PrimaryRoot: "/home/user/projects/myapp",
},
},
AllowPaths: []string{
"/home/user/projects/myapp",
"/home/user/documents",
},
}
与 Exec CWD 的关系
Exec CWD 优先级(INV-IO-03):
显式 cwd 参数 > PrimaryRoot > ScratchDir > ArtifactDir
编程场景下 PrimaryRoot = VS Code 项目根,go build ./... 等命令在项目根执行。
Workspace API
| 方法 | 路径 | 说明 |
|---|---|---|
GET | /workspace/files | 文件列表 |
GET | /workspace/file | 下载文件 |
POST | /workspace/upload | 上传文件 |
DELETE | /workspace/file | 删除文件 |
GET | /workspace/stats | 使用统计 |
POST | /workspace/gc | 触发 GC |
DELETE | /workspace/delete-by-prefix | 按前缀批量删除 |
查询参数
| 端点 | 参数 | 说明 |
|---|---|---|
/workspace/files | ?actor=&path=&depth= | Actor、路径、深度过滤 |
/workspace/file | ?actor=&path= | 指定 Actor 和路径 |
/workspace/upload | ?actor=&path= | 指定上传位置 |
/workspace/stats | ?actor= | 按 Actor 统计 |
/workspace/delete-by-prefix | ?actor=&prefix= | 按前缀批量删除 |
SDK 调用
// 列出文件
files, err := cell.Workspace().List(ctx, workspace.ListRequest{
Actor: "alice",
Path: "reports/",
Depth: 2,
})
// 下载
reader, err := cell.Workspace().Download(ctx, "alice", "reports/weekly.pdf")
// 上传
err := cell.Workspace().Upload(ctx, "alice", "reports/daily.md", bodyReader)
// 删除
err := cell.Workspace().Delete(ctx, "alice", "reports/old.pdf")
// 统计
stats, err := cell.Workspace().Stats(ctx, "alice")
// GC
err := cell.Workspace().GC(ctx)
// 批量删除
err := cell.Workspace().DeleteByPrefix(ctx, "alice", "temp/")
Cell Export
Workspace 在 Cell 导出中的行为:
| 内容 | 默认 | 可配置 |
|---|---|---|
workspace/ | ✅ 包含 | ExportOpts{SkipWorkspace: true} 可排除 |
.scratch/ | ❌ 永不包含 | 无选项(INV-IO-08) |
// 导出(包含 workspace)
reader, err := hyp.Cells().Export(ctx, "dept-legal")
// 导出(排除 workspace)
reader, err := hyp.Cells().Export(ctx, "dept-legal", wesgine.ExportOpts{
SkipWorkspace: true,
})
路径安全
写入路径约束(INV-IO-02)
write / edit / apply_patch 输出必须落入 ArtifactDir 或 HostPaths。
| 路径 | 允许? |
|---|---|
| ArtifactDir 下 | ✅ |
| HostPaths(AllowPaths)下 | ✅ |
/tmp | ❌ 禁止 |
| ScratchDir | ❌ 禁止(write 不应写临时域) |
| Cell 外路径 | ❌ 禁止 |
HostPaths 边界(INV-IO-07)
引擎对 HostPaths 的态度是只验边界:
| 操作 | 是否做 |
|---|---|
| 验证路径在 AllowPaths 内 | ✅ |
| MkdirAll | ❌ |
| Chmod | ❌ |
| GC | ❌ |
| Export | ❌ |
HostPaths 是宿主机的目录,引擎不管理其生命周期。
目录结构示例
cells/dept-legal/
├── workspace/
│ ├── alice/
│ │ ├── reports/
│ │ │ ├── weekly-2026-09-01.pdf
│ │ │ └── monthly-2026-08.docx
│ │ └── notes/
│ │ └── meeting.md
│ └── bob/
│ └── drafts/
│ └── contract-v2.md
├── .scratch/
│ └── run-abc123/ ← Run 结束后 GC
│ └── temp.json
├── meta.db
├── sessions.db
└── state.db
与 Knowledge 的关系
Workspace 和 Knowledge 是互补的文件管理机制:
| 特性 | Workspace | Knowledge |
|---|---|---|
| 定位 | Agent 产出文件 | 知识源文件 |
| 操作 | 上传/下载/删除 | 导入/索引/搜索 |
| 向量化 | ❌ | ✅(Embedding + 搜索) |
| 按 Actor 隔离 | ✅ | ❌(Cell 级共享) |
最佳实践
- 不要手动操作 .scratch/:引擎自动管理临时文件
- PrimaryRoot 声明清晰:编程场景设为项目根目录
- Export 前考虑体积:大量产出文件时用
SkipWorkspace减小导出体积 - 定期 GC:调用
/workspace/gc清理过期产出 - 路径安全意识:Agent 的写入路径受 AllowPaths 约束