18 · Documents、Artifacts 与 Work Products¶
一句话结论: Paperclip 把“正在编辑的结构化文档”“上传附件”“工作目录中的文件引用”和“供审查的工作产物”分别建模,既保留完整历史,也不把本地路径误当成远程可交付结果。
1. 为什么需要四种输出对象¶
Agent 完成工作后,可能得到:
| 对象 | 典型内容 | 是否依赖本地工作区 |
|---|---|---|
| Document | 计划、决策、说明、Case 文档 | 否,内容存储在 DB |
| Attachment / Asset | 图片、视频、PDF、压缩包 | 否,内容由 storage provider 管理 |
| Workspace File Resource | 源码、报告、变更文件的相对路径 | 是,需注册 workspace 才能解析 |
| Work Product | PR、branch、preview、artifact、文档等交付摘要 | 可能,通常带 provider/ref |
如果把这些全塞进 Issue description,会失去版本、权限、下载、清理、外部链接与审查状态。
2. Document 是版本化的可编辑对象¶
documents 表保存:
- company/title/format;
latestBody、latestRevisionId、latestRevisionNumber;- created/updated actor;
- lock actor/time;
- source trust;
- timestamps。
document_revisions 保存:
- document + revision number;
- title/format/body;
- change summary;
- created actor/run;
- created time。
当前 body 是快速读模型,revision 是历史事实。(documentId, revisionNumber) 唯一约束防止并发保存同一版本。
3. Document 的保存路径¶
sequenceDiagram
participant U as User / Agent
participant R as Route
participant D as Document Service
participant DB as PostgreSQL
participant E as Activity / Annotation
U->>R: PUT document body + expected revision
R->>D: validate actor + resource membership
D->>DB: lock/compare current revision
D->>DB: insert revision + update latest pointer
D->>E: activity / mention / annotation effects
DB-->>R: current document + revision
R-->>U: canonical response
如果当前文档已锁定或 revision 不匹配,服务应返回冲突而不是静默覆盖他人编辑。
4. Document Annotation¶
Annotations 把评论绑定到文档中的 anchor:
- thread/comment;
- text position/quote selector;
- anchor snapshot;
- confidence/state;
- open/resolved status。
它们不直接修改正文;解决 thread 也不等同接受文本变更。这使文档 review 可以与 revision 独立演进。
5. Legacy Plan 与 Issue Document¶
旧 Issue 描述中可能嵌有 plan body。Document service 提供 extractLegacyPlanBody 等兼容路径,把历史内容逐步映射到独立 Issue document,而不要求一次迁移所有任务。
这是一种重要的迁移策略:先提供读兼容,再让新写路径使用版本化对象。
6. Attachment 与 Asset¶
issue_attachments 只保存 Issue、Comment 和 Asset 的关系;实际文件由 assets 和 storage provider 管理。
上传流程通常是:
- 检查 company/issue 写权限;
- 校验 MIME、大小和 attachment limit;
- 流式写入 local disk/S3;
- 保存 asset 元数据;
- 建立 issue attachment/comment 关联;
- 生成可审查的 artifact/work product(按调用方式)。
普通 activity/log 不应内联二进制或完整 base64。
7. Artifact 与 Workspace File 的根本差异¶
内部交付手册把规则说得很清楚:
- Board/reviewer 要检查的生成文件应上传成 artifact;
- 本地 workspace path 不是云端用户可访问的交付物;
- 只有需要继续在项目中使用的源文件才适合 workspace_file metadata;
- workspace file link 必须携带 company/issue/workspace 语境,不能是 host absolute path。
8. Work Product 模型¶
issue_work_products 记录:
- company/project/issue;
- execution workspace/runtime service;
type、provider、external ID;- title/url/status/reviewState;
- primary 标记;
- health status;
- summary/metadata/source trust;
- creator run。
可表达:
- GitHub PR;
- branch/commit;
- preview URL;
- runtime service;
- uploaded artifact;
- document;
- workspace file。
它是“任务交付物索引”,不是再次存储所有内容。
9. 交付物为什么关联 Execution Workspace¶
PR、preview、artifact 常常来源于某次具体 run/workspace。关联它们能回答:
- 哪次执行生成;
- 哪个 workspace/branch;
- 哪个 runtime service 提供 preview;
- workspace 关闭后哪些外部产物仍保留;
- 哪个 source trust 等级产生了它。
如果只存一个 URL,审计者无法判断它是否真的来自本次任务。
10. Company Artifact Read Model¶
Company artifacts service 会:
- 按 cursor 分页;
- 按 media kind/content type 分类;
- 读取文本 attachment preview;
- 按 Issue 根/父任务分组;
- 生成带 company prefix 的 deep link;
- 处理 group-by issue/project 等过滤。
Cursor 使用 (updatedAt, id),比 offset 更适合不断产生新产物的时间线。
11. Workspace File Resource 安全路径¶
flowchart TD
REQ["issue + relativePath"] --> CAND["authorized workspace candidates"]
CAND --> NORM["normalize relative path"]
NORM --> ROOT["realpath workspace root"]
ROOT --> TARGET["realpath target"]
TARGET --> INSIDE{"inside root?"}
INSIDE -->|no| DENY["deny"]
INSIDE -->|yes| SIZE{"kind/size/preview policy"}
SIZE --> READ["read/list/download resource"]
它拒绝绝对路径、..、symlink escape、系统/秘密路径,并对 unknown binary 做类型 sniff 和 preview 上限。
远端 workspace 只能返回 provider-backed resource 或 unavailable 状态,不能伪造本地 fs.readFile。
12. Artifact upload 的可审查闭环¶
一份视频/PDF/截图等交付物应该经历:
生成 → 本地渲染/验证 → 上传 → canonicalize metadata
→ 创建 artifact work product → issue comment/link → final status
如果先把 Issue 标为 done,再上传失败,Board 会看到一个没有证据的完成任务。因此上传和 work product 创建应在最终 disposition 前完成。
13. Source Trust 传播¶
Document、Work Product、Issue attachment 可以保存 source trust metadata。它表达内容来自:
- 用户;
- Agent;
- 外部 webhook/tool;
- untrusted PR/remote source。
后续 low-trust promotion/review 会据此决定是否可进入更高信任的流程。复制内容时不能丢掉 provenance。
14. 外部对象与 Work Product¶
GitHub/Linear 等 provider 对象通常通过 external_objects + mentions/link 归一。Work Product 保存人类可点的外部 URL/status,external object service 负责刷新状态、回写 activity 和治理上下文。
外部 provider 更新不应直接覆盖 Issue status;它们之间通过映射规则和显式 sync/automation 关联。
15. 删除、归档与保留¶
- Document revision 和 activity 通常保留;
- Attachment asset 可按 retention/storage policy 清理,但关系与审计要有明确结果;
- Work product 更偏向 archive/health 状态,外部 PR 不随 Issue 删除;
- Workspace file 只是引用,workspace 关闭后可变为 unavailable;
- Artifact upload 是独立持久化,不应因临时 workspace cleanup 被删。
16. 常见失败¶
| 失败 | 结果 |
|---|---|
| 文件超 attachment limit | 上传前拒绝,不产生半个 artifact |
| storage upload 成功但 DB 关联失败 | reconciliation/孤儿 asset 检查,不能标记已交付 |
| workspace path 不可见 | 返回 unavailable/授权错误,而非 host path |
| 文档 revision 冲突 | 409,用户重新加载/合并 |
| preview service 已终止 | work product health 更新,URL 可保留但标记 unhealthy |
| 外部 PR 状态变化 | refresh external object/work product,不伪造本地完成 |
17. 可复用经验¶
- 正文、文件、路径引用和交付摘要要分对象。
- Artifact 是给审查者看的 durable upload,不是本地路径的别名。
- Document 使用 latest read model + immutable revisions。
- Work Product 记录 provider/ref/status/health,并关联生成它的 run/workspace。
- Workspace file resolver 只允许注册 workspace root 内的相对路径。
- 交付物上传应在最终状态前完成,失败要可见。
- provenance/trust 随内容传播,不能复制时丢失。
源码入口¶
packages/db/src/schema/documents.ts、document_revisions.tspackages/db/src/schema/assets.ts、issue_attachments.tspackages/db/src/schema/issue_work_products.tsserver/src/services/documents.tsserver/src/services/company-artifacts.tsserver/src/services/work-products.tsserver/src/services/workspace-file-resources.tsserver/src/services/company-artifacts.tsdoc/AGENT-ARTIFACTS.md
下一章说明怎样从本地命令启动并部署控制面:19 · CLI、配置与部署形态。