12 KiB
TauriTavern Agent Workspace
本文档定义 Agent Workspace 的存储模型、路径约束、Artifact Assembly、Checkpoint 与回滚语义。
Workspace 是 Agent Mode 的中心抽象。Agent 不直接写聊天消息,而是在 workspace 中像编辑项目文件一样多轮修改输出,最后由 runtime 提交 artifact。
1. 核心目标
Workspace 解决四个问题:
- 多轮编辑:允许模型反复修改草稿、计划、状态栏、小剧场等文件。
- 可审计:每次写入、patch、checkpoint 都能追踪。
- 可回滚:用户不满意时回到某个 checkpoint,而不是只能重新生成。
- 可组合:最终聊天消息可以由多个 artifact 组装,而不是只有单个 output。
2. 两级 Workspace
推荐使用两级结构:
agent-workspaces/
chats/
<chat-workspace-id>/
resources/
world/
character/
preset/
user/
skills/
memory/
persist/
runs/
<run-id>/
manifest.json
input/
tool-args/
tool-results/
model-responses/
output/
plan/
scratch/
summaries/
persist/
checkpoints/
patches/
events.jsonl
实际物理根目录为数据根下的 _tauritavern/agent-workspaces。它是 TauriTavern 运行产物空间,不属于上游 SillyTavern default-user 聊天文件布局。
<chat-workspace-id> 必须由稳定聊天身份派生:
stableChatId = window.__TAURITAVERN__.api.chat.open(chatRef).stableId()
chatWorkspaceId = "chat_" + sha256({ kind, stableChatId })[0..16]
它不得直接使用可变的 chat file name、角色显示名或完整 chatRef hash。聊天重命名、角色卡显示名变化、前端当前引用变化,不应该让同一个稳定聊天分裂到新的 chat workspace。
2.1 Chat Workspace
对话级 workspace 保存长期资源引用或 materialized 快照:
- 当前角色卡的 Agent 指导文件。
- 当前 preset 的 Agent policy。
- 用户侧写。
- 可用 skill 索引。
- 长期 memory/resource 索引。
它不应该被某一次 regenerate/swipe 污染。
同一稳定聊天的 normal、regenerate、swipe、continue 等多次 Agent run 共享同一个 chat workspace,但每次 run 必须有独立 run workspace 与独立 journal。
2.2 Run Workspace
一次 Agent Run 拥有独立 run workspace:
- 本次输入快照。
- 本次计划。
- 本次 scratch。
- 本次输出 artifact。
- 本次 checkpoint。
- 本次 journal。
这样不同 run 可以比较、回滚、删除或保留,不互相覆盖。
3. Resource 类型
“万物皆文件”是 Agent 视角的抽象,不代表所有数据都必须物理复制。
Workspace resource 分三类:
MaterializedFile
已落盘到 run workspace 的文本或二进制文件。
VirtualResource
看起来像文件,但内容由 repository/tool 按需读取。
GeneratedArtifact
Agent 生成或修改、准备参与提交的输出文件。
示例:
input/prompt_snapshot.json MaterializedFile
input/world/activated.md MaterializedFile
input/preset/instructions.md MaterializedFile
input/character/card.md MaterializedFile
chat/history.tail.md VirtualResource
chat/history.search://query=... VirtualResource
skills/long-form-romance/SKILL.md VirtualResource or MaterializedFile
output/main.md GeneratedArtifact
output/status.md GeneratedArtifact
原则:
- 大历史、大世界书、大记忆库默认 virtual。
- 本次生成必须固定的输入可以 materialize,但 “materialize input/context” 不等于复制完整上下文。
- 模型要改的文件必须是 materialized/generated,不能直接修改 virtual resource。
4. 路径契约
WorkspacePath 必须是逻辑路径,不直接等同系统路径。
必须满足:
- 相对路径。
- 使用
/作为分隔符。 - 非空。
- UTF-8。
- normalize 后不能包含
..。 - 不能是绝对路径。
- 不能包含 NUL。
- 不能包含 Windows drive prefix。
- 不能逃出 workspace root。
禁止:
../secrets.json
/Users/me/file
C:\Users\me\file
output/../../chat.jsonl
scratch/\0bad
所有 workspace file operation 必须经由 WorkspaceService 统一校验。工具、MCP、extension bridge 不得自行拼接文件系统路径。
5. Manifest
每个 run workspace 必须有 manifest.json。
建议结构:
{
"workspaceVersion": 1,
"runId": "run_...",
"stableChatId": "stable-chat-id",
"chatRef": {
"kind": "character",
"characterId": "...",
"fileName": "..."
},
"createdAt": "2026-04-26T00:00:00Z",
"input": {
"mode": "prompt_snapshot",
"promptSnapshotPath": "input/prompt_snapshot.json"
},
"artifacts": [
{
"id": "main",
"path": "output/main.md",
"kind": "body",
"target": "message_body",
"required": true,
"assemblyOrder": 10
},
{
"id": "status",
"path": "output/status.md",
"kind": "status",
"target": { "message_extra": "status_bar" },
"required": false,
"assemblyOrder": 20
},
{
"id": "theater",
"path": "output/theater.md",
"kind": "side_scene",
"target": "combined_markdown",
"required": false,
"assemblyOrder": 30
}
],
"commitPolicy": {
"defaultTarget": "message_body",
"combineTemplate": "{{main}}\n\n---\n\n{{theater}}",
"storeArtifactsInExtra": true
}
}
Manifest 是 runtime contract:
- required artifact 缺失必须 fail-fast。
- unknown target 必须 fail-fast。
- artifact path 违反 WorkspacePath 必须 fail-fast。
- commitPolicy 不合法必须 fail-fast。
6. 目录职责
input/
本次 run 的不可变输入快照。
output/
准备提交给聊天消息或 extra 的 artifact。
plan/
runtime 可检查的计划文件和用户/模型可读计划。
scratch/
Agent 私有草稿。默认不提交,是否进入 context 由 policy 决定。
summaries/
对历史、工具结果、前序步骤的摘要。
checkpoints/
checkpoint snapshot 与 manifest。
patches/
可选 patch 记录。第一期可以只做 snapshot。
events.jsonl
append-only run journal。
7. Artifact Assembly
Artifact Assembly 把多个 workspace 文件组装为 chat message。
Artifact target:
MessageBody
写入 chat message `mes`。
MessageExtra(key)
写入 chat message extra 的 TauriTavern namespace。
CombinedMarkdown(template)
按模板合并到 message body。
HiddenRunArtifact
不进入 chat,仅保留在 run workspace。
建议优先级:
- 第一版只要求
output/main.md->mes。 - 同时保留 manifest 能力,允许后续扩展状态栏、小剧场、变量。
- optional artifact 缺失时跳过。
- required artifact 缺失时 fail-fast。
8. Commit 语义
Commit 是 workspace 到 chat 的边界。
必须:
- 在 commit 前创建 checkpoint。
- 读取 manifest。
- assemble artifacts。
- 通过现有 chat 保存契约写入。
- 写入 agent metadata。
- journal 记录
artifact_assembled与run_committed。
禁止:
- 直接写 JSONL。
- 绕过 windowed payload cursor 保护。
- 由工具自行 commit。
- commit 半成品 artifact。
Commit metadata 建议:
{
"tauritavern": {
"agent": {
"runId": "run_...",
"stableChatId": "stable-chat-id",
"checkpointId": "ckpt_...",
"profileId": "writer",
"artifactSetId": "artifact_set_...",
"artifacts": [
{ "id": "main", "kind": "body", "path": "output/main.md" }
]
}
}
}
9. Checkpoint
Checkpoint 是 run 内回滚和 commit 后追踪的基础。
第一期建议 snapshot,不引入 git。
结构:
checkpoints/
000001/
checkpoint.json
manifest.json
output/
main.md
status.md
plan/
plan.md
summaries/
...
checkpoint.json 是内部实现元数据,不作为 Agent/UI payload;其中的 bytes 仅服务于存储体积、清理与完整性边界:
{
"id": "ckpt_...",
"seq": 1,
"runId": "run_...",
"createdAt": "2026-04-26T00:00:00Z",
"reason": "after_workspace_patch",
"eventSeq": 42,
"files": [
{ "path": "output/main.md", "sha256": "...", "bytes": 1024 }
]
}
Checkpoint 时机:
- workspace 初始化后。
- plan 创建后。
- 每次 workspace-mutating tool 后。
- 每个 plan node 完成后。
- artifact assembly 前。
- commit 前。
10. 回滚
10.1 Run 内回滚
Run 内回滚只恢复 workspace:
rollback(runId, checkpointId)
-> restore workspace files
-> append rollback event
-> status remains Running/AwaitingApproval or becomes Paused
它不修改 chat。
10.2 Commit 后回滚
Commit 后回滚修改 chat message:
rollbackCommittedMessage(runId, checkpointId)
-> assemble artifacts from checkpoint
-> replace/delete committed chat message
-> save through chat save contract
-> append rollback committed event
必须遵守 windowed payload 保存串行化。
11. Retention
默认 retention 应保守:
- Completed run 可以保留完整 workspace。
- Failed/Cancelled run 默认保留,便于 debug。
- 移动端可以限制 checkpoint 数量或总大小,但删除必须明确记录。
- 用户删除聊天时,关联 chat workspace 必须随聊天生命周期清理,避免静默泄漏大量文件。
当前实现:
- 单个角色聊天删除清理由
chat_metadata.integrity派生的 Agent chat workspace。 - 单个群聊聊天删除清理由 group chat id 派生的 Agent chat workspace。
- 删除角色且级联删除聊天、删除群组时,会批量清理对应聊天 workspace。
- 若 workspace 仍有关联 active run,删除必须 fail-fast;用户应先取消 run 再删除聊天。
- 旧聊天缺少稳定
integrity时,不存在可可靠定位的 Agent workspace,保持普通聊天删除语义。
建议后续提供设置:
keepCompletedRuns
keepFailedRuns
maxRunWorkspacesPerChat
maxCheckpointBytesPerRun
autoPruneAfterDays
12. 性能约束
- 不复制完整聊天历史。
- 不把大 virtual resource materialize 到每个 run。
- checkpoint 第一版只 snapshot 小文本文件;大文件使用引用或跳过,并在 manifest 声明。
- workspace tree 展示应懒加载。
- timeline 读取 journal 应支持分页。
13. 当前 Workspace
当前 run workspace 物理布局:
_tauritavern/agent-workspaces/
index/
runs/
<run-id>.json
chats/
<workspace-id>/
persist/
<promoted persistent files>
runs/
<run-id>/
manifest.json
events.jsonl
input/
prompt_snapshot.json
persist_snapshot.json
tool-args/
<tool-call-id>.json
tool-results/
<tool-call-id>.json
model-responses/
round-XXX.json
output/
main.md
scratch/
plan/
summaries/
persist/
<run projection of chat-level persist files>
checkpoints/
<checkpoint-id>/
checkpoint.json
<snapshotted workspace files...>
当前模型可见 / 可写 workspace 根:
output/
scratch/
plan/
summaries/
persist/
persist/ 是 chat workspace 级持久 root 的 run projection:
chats/<workspace-id>/persist/ # 稳定持久层
chats/<workspace-id>/runs/<run-id>/persist/ # 本 run 投影
run 初始化时,稳定 persist/ 会复制到本次 run 的 persist/,并在 input/persist_snapshot.json 中记录 base sha。模型在 run 中通过普通 workspace 工具读写 persist/;这些写入在 workspace.finish 收尾成功前不会写回稳定层。finish 阶段会计算 persistent changes、检查并发冲突,并 promote 回 chats/<workspace-id>/persist/。Failed、Cancelled 或未 finish 的 run 不会污染后续 run。
早期设计中的最小概念结构仍可作为抽象理解:
runs/<run-id>/
manifest.json
input/prompt_snapshot.json
output/main.md
checkpoints/000001/checkpoint.json
checkpoints/000001/output/main.md
events.jsonl
这个结构足以支撑:
- minimal run
- journal
- checkpoint
- artifact commit
- rollback 基础数据结构(当前尚未开放 rollback API)
- workspace list/read/write/patch 工具循环