18 KiB
TauriTavern Agent Implementation Plan
本文档记录当前可继续开发的实施基线与后续顺序。历史施工计划已经收敛为当前架构、测试与契约;第 8 节只保留 Phase 台账用于追踪,不作为旧行为的事实来源。
当前事实以 docs/CurrentState/AgentFramework.md 为准,架构边界以 docs/AgentArchitecture.md 与 docs/AgentContract.md 为准。
1. 当前基线
截至 2026-05-27,Agent 当前核心已经落地:
- Rust 后端拥有 Agent domain model、runtime、workspace、journal、checkpoint、commit bridge。
- 聊天删除会清理对应 Agent chat workspace;active run 存在时删除 fail-fast。
- 前端 Host ABI 已挂载
window.__TAURITAVERN__.api.agent。 - Agent System 扩展开关开启时,前端将普通发送、regenerate 与 overswipe 新候选生成接入 Agent;普通切换已有 swipe 候选仍保持 Legacy swipe 行为。
- Agent 启动仍通过
PromptSnapshot兼容桥进入;root run 已支持 Frontend PromptAssemblyBroker 独立组装 Profile preset/model,GenerationIntent + ContextFrame尚未完全接管 context assembly。 startRunFromLegacyGenerate()使用 Legacy dryRun 捕获FrozenRunInputSnapshot、当前 prompt seed 与本轮最终worldInfoActivation。- LLM 调用复用
ChatCompletionService::generate_exchange_with_cancel(),不得绕过现有 provider、secret、日志、endpoint policy、iOS policy、prompt cache 和取消链路。Responses WebSocket 建连已收敛到HttpClientPool的 ChatCompletion WebSocket profile。 - Tool loop 由 Rust runtime 独占推进,不递归调用前端
Generate()。 - Agent runtime 已使用 canonical model IR,不再把 OpenAI-compatible raw JSON 当作运行时事实。
provider_state已用于 run-scoped continuation。OpenAI Responses 通过它驱动 persistent WebSocket、incremental input 与previous_response_id。- Agent Skill repository/service、导入导出、embedded skill 导入确认、
api.skill、skill.list/skill.search/skill.read已落地。 - Phase 3 Agent Profile 基线已落地:built-in
default-writer、file repository、resolver、run snapshot、tool/skill/workspace/output policy、tool budget 与 max rounds。 - Profile
preset.mode = "ref"可加载独立 OpenAI/chat-completion preset;model.mode = "connectionRef"+modelId可通过 LLM Connection 解耦 preset source/model,并在 runtime 发送前再次权威覆盖 payload。 - Profile
run.modelRetry已落地,默认对单次模型调用的 rate limit / transient transport-provider 错误重试 3 次,间隔 3000ms;非瞬时契约错误继续 fail-fast。 instructions.agentSystemPrompt可完整替换默认 Agent system prompt;缺省时使用 resolved profile 默认 prompt。Preset / PromptManager 控制其位置与 role;前端在该位置 materialize Profile 内容,runtime 只消费最终 messages。tools.toolDescriptions可替换 model-facing tool/property descriptions;缺省时使用默认描述。
历史计划只保留为这些不变量:
- Agent Mode off 时,上游 SillyTavern
Generate()、ToolManager、事件顺序与 chat 保存语义不变。 stableChatId是长期聊天身份;workspaceId由kind + stableChatId派生;runId表示单次执行。- 所有 run event 进入 append-only journal,不伪装成上游
GENERATION_*/TOOL_CALLS_*事件。 - 工具结果进入 workspace / journal / 下一轮 model request,不写入 chat 楼层。
- 最终聊天写入由前端 commit bridge 走 SillyTavern
saveReply()。 PromptSnapshot是兼容桥,不是长期上下文架构。
2. 当前 Host ABI
已落地入口:
api.agent.startRunFromLegacyGenerate(input?)
api.agent.startRunWithPromptSnapshot(input)
api.agent.subscribe(runId, handler, options?)
api.agent.cancel(runId)
api.agent.readEvents(input)
api.agent.readWorkspaceFile(input)
api.agent.readModelTurn(input)
api.agent.profiles.*
api.agent.promptAssembly.prepare(input)
api.agent.promptAssembly.buildSnapshot(input)
api.agent.tools.list()
启动输入支持可选 profileId。Profile 管理、prompt assembly broker 与 tools list 已封装到 window.__TAURITAVERN__.api.agent。
明确不存在公共 api.agent.startRun() alias。
当前 future API 只保留显式 throw:
approveToolCall()
listRuns()
readDiff()
rollback()
3. 当前 Model Gateway
当前 Agent model 调用链:
AgentRuntimeService
-> generate_model_with_retry(AgentModelRequest, profile.run.modelRetry)
-> AgentModelGateway.generate_with_cancel(AgentModelRequest)
-> encode_chat_completion_request()
-> ChatCompletionService.generate_exchange_with_cancel(ChatCompletionGenerateRequestDto)
-> decode_chat_completion_response()
-> AgentModelResponse
当前 canonical IR:
AgentModelRequestAgentModelResponseAgentModelMessageAgentModelContentPart
AgentModelContentPart 当前支持:
TextReasoningToolCallToolResultMediaResourceRefNative
当前已落地:
AgentModelGateway已从旧单文件拆成agent_model_gateway/模块目录:mod.rs只保留 trait / wrapper,encode.rs/decode.rs/format.rs/schema.rs/provider_state.rs/providers/*分别承担转换、格式解析、schema 清洗、continuation 与 provider-specific 规则。- provider format detection:OpenAI-compatible、OpenAI Responses、Claude Messages、Gemini、Gemini Interactions。
- canonical tool specs 到 provider-facing function tools 的转换。
- provider-specific schema sanitizer。Gemini / Gemini Interactions 会移除当前不兼容的 JSON Schema 关键字;Claude 只做轻量清洗;OpenAI / Responses 保持完整 schema。
- OpenAI Responses 请求自动 include
reasoning.encrypted_content。 - Agent OpenAI Responses 续接会使用
provider_state.previousResponseId注入previous_response_id,并用messageCursor只发送新消息。 - Agent payload 内部字段
_tauritavern_provider_state不进入 LLM API log,也不会发送给上游 provider。 - missing
tool_call_idfail-fast,不再 fallback 生成tool_call_{index}。 - response decode 保留 text、reasoning、tool calls、native metadata。
仍待:
- 还没有正式
ModelDeltastreaming adapter。 - 还没有 profile-driven provider switch policy。
4. 当前 Native Metadata 策略
Provider native data 是 opaque state,不是 Agent 业务语义。Runtime 可以携带和回放,但不能解释、改写或摘要。
已落地保留:
| Provider format | 保留字段 | 回放位置 |
|---|---|---|
| Claude Messages | assistant content blocks,包含 thinking / tool_use / signature |
Claude payload message conversion |
| Gemini | response content.parts,包含 thoughtSignature |
Makersuite payload message conversion |
| Gemini Interactions | raw outputs |
Gemini Interactions payload message conversion |
| OpenAI Responses | raw output items 与 responseId |
Responses payload input items |
约束:
- tool call id 是不透明字符串。
- same-provider continuation 需要的 native state 丢失时必须 fail-fast 或测试失败。
- cross-provider switch 只能迁移 canonical 语义;旧 provider 的私有 signature/encrypted reasoning 不能伪装为目标 provider 可用状态。
5. 当前工具集
Tool registry 只产 canonical AgentToolSpec,不再暴露 OpenAI-shaped openai_tools()。
| Canonical name | Model alias | 类型 |
|---|---|---|
chat.search |
chat_search |
read-only |
chat.read_messages |
chat_read_messages |
read-only |
worldinfo.read_activated |
worldinfo_read_activated |
read-only |
skill.list |
skill_list |
read-only |
skill.search |
skill_search |
read-only |
skill.read |
skill_read |
read-only |
workspace.list_files |
workspace_list_files |
read-only |
workspace.search_files |
workspace_search_files |
read-only |
workspace.read_file |
workspace_read_file |
read-only |
workspace.write_file |
workspace_write_file |
mutating |
workspace.apply_patch |
workspace_apply_patch |
mutating |
workspace.finish |
workspace_finish |
control |
当前尚未落地:
- MCP 工具
- shell 工具
- 外部 extension tools
- tool approval / policy routing
- provider/model switch policy
- Plan Mode runtime 节点推进
6. 工具结果语义
必须区分两类错误:
- Recoverable tool error:模型参数、路径字符串、可见/可写策略、文件不存在、chat message index 不存在、读取范围非法、结果超过工具预算、patch 未完整读取、sha 过期、匹配 0 次或多次等模型可修正问题。返回
AgentToolResult { is_error: true },写入tool_call_failedwarn event,并作为 tool message 回填下一轮模型。 - Fatal runtime error:journal 写入失败、workspace repository 内部 IO 错误、chat JSONL 损坏、manifest/checkpoint 损坏、模型响应结构不可解析、取消、序列化失败、状态机错误等宿主级问题。直接让 run 进入 failed 或 cancelled。
当前已落地 recent hydration:
- 前 5 轮
workspace.write_file/workspace.apply_patch成功结果会读取目标 workspace 文件,将完整文本加入下一轮模型上下文。 - hydration 只影响 model request,不改变 workspace/journal 真相。
- hydration 会写
context_tool_result_hydrateddebug event。
7. 当前运行流
api.agent.startRunFromLegacyGenerate(input?)
↓
Legacy Generate dryRun 捕获 FrozenRunInputSnapshot / current prompt seed / worldInfoActivation
↓
prepare_agent_prompt_assembly(dto)
↓
若 preset.ref:Frontend PromptAssemblyBroker 用独立 preset/model 真实组装 promptSnapshot
↓
前端解析 chatRef / stableChatId
↓
start_agent_run(dto)
↓
AgentRuntimeService::start_run()
↓
resolve Profile
↓
创建 AgentRun / workspaceId / run workspace
↓
initialize_run 写 manifest / prompt snapshot / resolved profile / workspace root
↓
prepare_agent_tool_request 按 Profile 生成 AgentModelRequest 与 visible tool specs
↓
model -> read-only context tools / skill tools / workspace tools -> model -> ... -> workspace.commit? -> workspace.finish
↓
工具调用参数与结果写入 workspace refs
↓
workspace mutation 成功后 checkpoint
↓
workspace.commit 触发 host bridge 写入同一 chat message
↓
workspace.finish 收尾并提交 persist projection
工具循环轮数来自 profile.tools.maxRounds。超过后以 agent.max_tool_rounds_exceeded 失败。模型直接输出文本且不调用工具会先捕获到 workspace direct_output.md 并触发一次 soft drift recovery;恢复耗尽后以 model.tool_call_required 失败或在已有 commit 时进入 run_partial_success。前台 run 必须在 finish 前至少成功 commit 一次;后台 run 可以无 commit 完成。
8. 后续实施顺序
本节按 Phase 台账追踪,便于提交与回归管理。已完成 Phase 只记录基线和守护项;后续开发从第一个未完成 Phase 继续。
Phase 0:文档、契约、测试守护(已完成,持续维护)
已完成:
- Agent 架构、硬契约、工具系统、workspace、journal、LLM gateway、Skill 与测试策略文档已成体系。
docs/CurrentState/AgentFramework.md与docs/CurrentState/AgentProviderState.md作为当前事实入口。
持续守护:
- Agent 相关实现变更必须同步当前事实、架构边界、Host ABI、工具语义、workspace 语义与测试策略。
Phase 1:Workspace + Journal + One-Step Agent(已完成)
已完成:
- Rust 后端 Agent runtime、run workspace、manifest、journal、checkpoint、commit bridge 已落地。
api.agent.startRunFromLegacyGenerate()/startRunWithPromptSnapshot()/ subscribe / cancel / readEvents / commit bridge 已落地。- Agent Mode off 不改变 Legacy Generate、ToolManager、事件顺序与 chat 保存语义。
Phase 2A:Tool Loop Foundation(已完成)
已完成:
- Rust runtime 独占推进 tool loop,不递归调用前端
Generate()。 - Tool registry 产 canonical
AgentToolSpec,provider-facing alias 由 gateway 渲染。 - 工具调用、工具结果、recoverable tool error、fatal runtime error 与 journal 语义已落地。
Phase 2B:Workspace 读改工具(已完成)
已完成:
workspace.list_files、workspace.search_files、workspace.read_file、workspace.write_file、workspace.apply_patch、workspace.commit、workspace.finish已落地。- workspace mutation 后创建 checkpoint;完整读取 / 写入 read-state 约束已接入。
output/、scratch/、plan/、summaries/、persist/是当前模型可见 root。
Phase 2C:上下文只读工具(已完成)
已完成:
chat.search/chat.read_messages只读取当前 run 绑定的聊天。worldinfo.read_activated只读取本次 run 捕获的最终激活世界书条目。- 只读工具结果以 resource ref / snippet / tool result 回填模型,不写入 chat 楼层。
Phase 2D:Gateway / Provider Contract 硬化(已完成基线,持续守护)
结论:Gateway / Provider Contract 硬化 不应继续列为未完成主任务。当前基线已经完成;后续只按守护项补测试和防回退。
已完成:
AgentModelGateway已拆成agent_model_gateway/模块目录:mod.rswrapper、encode.rs/decode.rs转换、format.rs格式解析、schema.rssanitizer、provider_state.rscontinuation、providers/*provider-specific adapter。- canonical
AgentModelRequest/AgentModelResponse已取代 runtime 直接解析 OpenAI-shaped raw JSON。 - OpenAI-compatible、OpenAI Responses、Claude Messages、Gemini、Gemini Interactions 的 provider format detection 与 schema sanitizer 已落地。
- OpenAI Responses
provider_state.previousResponseId/messageCursor增量输入、persistent WebSocket 与_tauritavern_provider_state内部传递已落地。 - missing
tool_call_id、same-provider native metadata loss、cross-provider private metadata 迁移均有 fail-fast / 测试守护。
持续守护:
- 不退回单文件 Gateway,不让 runtime 直拼 provider-specific payload。
- 继续扩展 schema sanitizer edge case、session close、prompt cache 与 provider-native state 共存测试。
- 新 provider adapter 必须保持 native metadata opaque,不得清洗签名、encrypted reasoning 或 tool call id。
Phase 2E:Skill 管理与读取(已完成基线)
已完成:
- Agent Skill repository/service、导入导出、embedded skill 导入确认、
api.skill已落地。 skill.list/skill.search/skill.read已接入 Agent tool registry。- Preset / Character embedded source refs 与删除清理语义已落地。
Phase 3 基线已在 Agent tool 层接入 Skill 可见性、deny policy 与 read budget;Phase 2E 不再扩展 Skill 运行权限。
Phase 3:Profile / Context / Skill Policy(进行中)
目标:让创作者控制模型、工具、预算和上下文,而不是写死在 runtime。
已完成基线:
- Profile JSON /
AgentProfileRepository/AgentProfileService。 - 缺省 built-in
default-writer;非缺省 profile 缺失 fail-fast。 - run workspace 写入
input/resolved_profile.json。 - Profile 控制 tool allow/deny、
toolDescriptions、tool budget、maxRounds。 - Profile 控制
skill.list/skill.search/skill.read可见性与 read budget。 - Profile 控制 workspace roots 与 messageBody artifact。
agentSystemPrompt内容由 Profile 独占;Preset 控制 PromptManager 中的位置与 role。preset.mode = "ref"+ Frontend PromptAssemblyBroker 已支持 root run 独立 preset 组装;model.mode = "connectionRef"已支持独立 LLM Connection 与modelId。
仍待:
- 运行中 subagent / handoff prompt assembly handshake、invocation-scoped prompt snapshot 与 provider_state。
- 多 Agent provider/model switch policy 与 ContextFrame 资源预算。
- preset / character author resources 复用 Skill-like 索引与 source ref 语义,不另建平行资源系统。
- Plan node 若锁定 profile,runtime 必须拒绝模型自行切换。
Phase 4:Timeline UI 与人工控制
目标:给创作者可理解、可暂停、可提交的 Agent run 体验。
内容:
- Agent run 控制入口与状态摘要。
- 最小 timeline/event viewer。
- workspace artifact viewer。
- tool error / recovery 状态展示。
- commit preview 与手动提交。
- cancel UI。
Phase 5:Diff / Rollback / Resume
目标:让多轮创作具备可控回退能力。
内容:
readDiff():基于 checkpoint 对 workspace 文本文件生成 diff。rollback():先只恢复 run workspace,不修改已提交聊天消息。resumeRun():明确 run continuation 语义,避免复用已 closed run 的状态机。
Phase 6:MCP / Extension Tool
目标:引入外部工具生态,但保持 Tauri-native 安全边界。
约束:
- MCP Host ABI 独立于 Agent Mode。
- STDIO command/config 不得由 prompt、Preset、角色卡、世界书或第三方 JSON 任意写入。
- 危险工具必须进入 capability policy 与审批。
- Agent 消费 MCP tool 前必须经过 profile / policy resolution。
9. 验收命令
Agent 相关 Rust 变更至少运行:
cargo fmt --manifest-path src-tauri/Cargo.toml
cargo check --manifest-path src-tauri/Cargo.toml
cargo test --manifest-path src-tauri/Cargo.toml agent --lib
cargo test --manifest-path src-tauri/Cargo.toml skill --lib
cargo test --manifest-path src-tauri/Cargo.toml agent_tools --lib
git diff --check
涉及 provider adapter / normalizer 时额外运行相关过滤测试:
cargo test --manifest-path src-tauri/Cargo.toml agent_model_gateway
cargo test --manifest-path src-tauri/Cargo.toml openai_responses_payload
cargo test --manifest-path src-tauri/Cargo.toml claude_native_content_blocks_are_replayed
cargo test --manifest-path src-tauri/Cargo.toml normalize_
涉及前端 Host ABI、类型或契约时再运行:
pnpm run check:types
pnpm run check:frontend
pnpm run check:contracts
10. 每次修改必须同步的文档
- 当前事实:
docs/CurrentState/AgentFramework.md - 架构边界:
docs/AgentArchitecture.md - 硬契约:
docs/AgentContract.md - LLM gateway:
docs/Agent/LlmGateway.md - 工具语义:
docs/Agent/ToolSystem.md - workspace 语义:
docs/Agent/Workspace.md - Skill 语义:
docs/Agent/Skill.md - 事件语义:
docs/Agent/RunEventJournal.md - 测试矩阵:
docs/Agent/TestingStrategy.md - Host ABI:
docs/API/Agent.md、docs/API/Skill.md、docs/FrontendHostContract.md、src/types.d.ts