Persist PageTree expand state via control-plane view-state and align chevron/DOM with restored expansion; keep Sidex-style shallow page-tree scan and drop the unused recursive scanner that only added cargo noise. Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi into a module package, and retire Hermes/ACP/OpenHub recycle + root harness evidence from the index while gitignoring recycle and local diag dumps. Archive superseded design/bugs docs under old/, point architecture at ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor regressions so the working tree can stay clean.
86 KiB
[recycle] 7-4 [done] 页面 AI Hermes 面板顺序执行 checklist v1
更新时间:2026-05-14
当前状态:
DONE。A-M 的实现、旧链退场、持久化审计和正式3000全矩阵已完成;N 文档治理已把活跃设计口径统一为 Hermes 页面内客户端 + mnote Hermes skill/plugin。本文已从process/迁入done/;后续页面 AI 体验与设置面收口由design/07-ai/process/7-7-page-ai-mini-hermes-control-surface-v1.md继续承接。上位依据:
/mnt/Data1T/mnote/ARCHITECTURE.md/mnt/Data1T/mnote/design/01-05-current-priority-overview.md/mnt/Data1T/mnote/design/03-rust-web/reference/3-rust-web-long-term-architecture-v1.md/mnt/Data1T/mnote/design/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-v1.md/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md/mnt/Data1T/mnote/design/05-editor-mainline/done/5-10-wolai-page-settings-and-ai-surface-alignment-v1.md/mnt/Data1T/mnote/design/05-editor-mainline/done/5-11-wolai-page-settings-and-ai-surface-checklist-v1.md/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18/mnt/Data1T/mnote/design/07-ai/done/7-2-phase7-structured-artifact-write-chain-v1.md/mnt/Data1T/mnote/design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md目标:
- 把页面 AI 从旧
/api/ai-agent/run/mnote-cli host/ sidecar 路径迁到 Hermes 页面内客户端。- Hermes 持有 AI session/message/tool event/usage/model 真相。
- mnote 只通过 Hermes skill/plugin 暴露页面、树、artifact、edge 等业务工具。
- Leptos 负责页面内 Hermes 面板体验,不负责 AI 编排或聊天真相存储。
0. 使用方式
每次只领取一个 task,按顺序执行。除非前一 task 的验收标准全部满足,否则不要进入下一 task。
勾选规则:
- 已有代码、文档和可复跑验证证据。
- 还没有完整证据,或只有局部实现。
PARTIAL项不能当作完成项;必须继续拆到对应未勾选子项。
状态标记:
TODO:未开始RED:已补失败测试或失败 smokeGREEN:当前 task 本地通过BLOCKED:依赖外部 Hermes、auth、模型网关或数据权限,无法在本轮闭环DONE:代码、测试、文档证据都已回填
执行硬规则:
- 不新增 Web 私有 AI tool registry。
- 不把 Hermes 聊天消息复制进 mnote page aggregate / Convex 页面数据。
- 不让 Hermes plugin 直接写 Convex,写入必须回到 Rust runtime / kernel。
- 不把
mnote-cli写回页面 AI 唯一长期执行面;它最多是 plugin 内部 adapter 或调试入口。 - 不在页面 AI 抽屉里复刻 Hermes 管理台;只实现页面内 chat/session/run/tool event 子集。
- 不在同一阶段同时迁移所有工具;先读、再写正文、再 artifact、再树与 edge。
当前进度快照:
| Task | 状态 | 已有证据 | 剩余门槛 |
|---|---|---|---|
| A | [x] GREEN | scripts/task-hermes-page-ai-baseline-smoke.js、bugs/07-ai/done/7-1-page-ai-provider-hermes-old-run-502-v1.md |
无 |
| B | [x] GREEN | design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md |
无 |
| C | [x] GREEN | rust/crates/mnote-web/src/routes/hermes_client.rs、cargo test -p mnote-web hermes_ |
无 |
| D | [x] GREEN | design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md |
无 |
| E | [x] GREEN | rust/crates/mnote-web/src/routes/hermes_tools.rs、rust/crates/mnote-web/src/hermes_tools/*、task-hermes-page-ai-tool-smoke.js |
后续可扩 manifest 全量 schema,不阻塞第一版只读工具 |
| F | [x] GREEN | rust/crates/mnote-web/src/ssr/pages/layout.rs、task-hermes-page-ai-smoke.js |
无 |
| G | [x] GREEN | 真实 Hermes upstream run 已触发 mnote_page_get / mnote.page.get;Hermes session export 与刷新恢复已验证 |
无 |
| H | [x] GREEN | mnote.page.save route、dryRun、未认证拒绝、workspace ACL 失败、同 key replay、主编辑区立即回显与刷新后持久化 smoke 已有 |
无 |
| I | [x] GREEN | mnote.page.update_title、mnote.page.update_options route 与 smoke 已有;标题 dryRun / idempotency、wired-only warning、页头 / breadcrumb / sidebar / 刷新后一致性已验证 |
无 |
| J | [x] GREEN | mnote.artifact.create_summary、mnote.artifact.create_ai_note route 与 smoke 已有;summary 重试、ai_note 独立创建、真实 kernel/projection edge 查询、AI Artifacts projection-only 验收和页面 AI Hermes intent 快捷入口已通过 |
无 |
| K | [x] GREEN | 新页面 AI 主链已不请求 /api/ai-agent/run;旧 endpoint 统一返回 410 legacy_ai_agent_run_retired;旧 smoke 默认退役;legacy 调用方已清点并归类 |
无 |
| L | [x] GREEN | tool 响应已有基础 audit 字段;routes/hermes_tools.rs 已记录 started/completed/failed 结构化日志;写工具 audit.commandId 已指向 Rust command id;审计已追加 JSONL 持久化并支持 persistedOnly=true 反查 |
无 |
| M | [x] GREEN | 正式 http://127.0.0.1:3000 已复跑 8 个 E2E smoke:session/run、tool、writeback、title/options、artifact、retirement、mobile、audit |
无 |
| N | [x] GREEN | 7-3/7-4/7-5/7-6 已写入主线口径;1-1、3-1、5-6、5-9、10-review 已统一旧 AI 口径为历史/兼容/已覆盖 |
后续若移动本文件到 done/,需同步更新引用 |
1. Hermes Web UI 参考索引
需要参考 /mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18 时,只参考下表列出的文件。参考目标是理解 Hermes 的 session / run / stream / tool event / usage / model 语义,不照搬 Vue、Naive UI、整站导航或后台管理页面。
执行时按 task 精确打开文件,不要整目录通读。需要进一步定位时,优先按下表的“搜索点”打开,不要从整站 UI 或无关管理页开始看:
| 参考主题 | 文件 | 搜索点 / 具体位置 | 在 mnote 中用于什么 |
|---|---|---|---|
| 浏览器发起 run 与事件分发 | packages/client/src/api/hermes/chat.ts |
StartRunRequest、RunEvent、registerSessionHandlers、connectChatRun、startRunViaSocket |
对齐 mnote Leptos 面板发起 run、订阅 message.delta / tool.started / tool.completed / run.completed 的事件语义 |
| session 刷新恢复 | packages/client/src/api/hermes/chat.ts、packages/client/src/stores/hermes/chat.ts |
resumeSession、switchSession、refreshActiveSession、mapHermesMessages |
对齐页面刷新后从 Hermes session detail / resume 恢复消息,而不是从 mnote 本地 state 恢复聊天真相 |
| tool message 前端归并 | packages/client/src/stores/hermes/chat.ts |
Message.role = 'tool'、toolCallId、toolArgs、toolResult、case 'tool.started'、case 'tool.completed' |
对齐 mnote 面板如何把 tool started / completed 合并成可读消息项 |
| tool message 展示 | packages/client/src/components/hermes/chat/MessageItem.vue |
message.role === 'tool'、formatToolPayload、toolExpanded、tool-preview、tool-details |
对齐 tool 结果默认折叠、摘要展示、详细 JSON 展开的交互边界 |
| 页面面板分层 | packages/client/src/components/hermes/chat/ChatPanel.vue |
showSessions、activeSessionTitle、handleNewChat、MessageList、ChatInput、SessionListItem |
只参考 session list / message list / input 的分层,不复制 Vue / Naive UI / Hermes 全屏布局 |
| 后端 run 与 resume 房间 | packages/server/src/services/hermes/chat-run-socket.ts |
ChatRunSocket、onConnection、resumeSession、handleRun、emit、markCompleted |
对齐 upstream run 生命周期、刷新恢复、房间广播与终止态,不在 mnote 里重建 Hermes 编排器 |
| OpenAI Responses tool event 映射 | packages/server/src/services/hermes/chat-run-socket.ts |
applyResponseStreamEvent、response.output_item.done、function_call、function_call_output、tool.started、tool.completed、flushResponseRunToDb |
对齐真实 Hermes upstream run 如何产生 tool event,并把 tool call / tool result 写回 Hermes session 存储 |
| Hermes session 存储真相 | packages/server/src/db/hermes/session-store.ts |
HermesSessionRow、HermesMessageRow、createSession、getSessionDetail、addMessage、updateSessionStats |
明确 session/message/tool call 真相在 Hermes,不在 mnote page aggregate / Convex 页面数据 |
| session HTTP detail | packages/client/src/api/hermes/sessions.ts、packages/server/src/routes/hermes/sessions.ts |
fetchSessions、fetchSession、HermesMessage、/api/hermes/sessions/:id |
对齐 session list/detail 的字段名,用于 mnote proxy 返回兼容形状 |
| plugin/skill 清单发现 | packages/server/src/services/hermes/plugins.ts |
PYTHON_BRIDGE、PluginManager、user_dir = get_hermes_home() / "plugins"、manifest_list、providesTools、listHermesPlugins |
对齐 Hermes Web UI 如何发现 user/project plugin 和 provides_tools;mnote 的真正工具必须进入 Hermes plugin/tool registry,不能只停在 mnote-web 私有 route |
| plugin/skill API 外观 | packages/client/src/api/hermes/plugins.ts、packages/client/src/api/hermes/skills.ts、packages/server/src/routes/hermes/plugins.ts、packages/server/src/routes/hermes/skills.ts |
list / get / enable / disable 类 route 与响应字段 |
只用于清单和状态展示口径;页面 AI 第一版不复刻 Hermes plugin 管理台 |
可快速 grep:
cd /mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18
rg -n "StartRunRequest|RunEvent|registerSessionHandlers|startRunViaSocket|resumeSession|tool\\.started|tool\\.completed|applyResponseStreamEvent|flushResponseRunToDb|PluginManager|providesTools|listHermesPlugins" packages/client/src packages/server/src
已分类的常用入口:
- session / run / SSE:先看
packages/client/src/api/hermes/chat.ts、packages/server/src/routes/hermes/chat-run.ts、packages/server/src/services/hermes/chat-run-socket.ts。 - session 真相恢复:先看
packages/server/src/db/hermes/session-store.ts、packages/server/src/db/hermes/sessions-db.ts、packages/server/src/services/hermes/session-sync.ts。 - 面板组件分层:先看
packages/client/src/views/hermes/ChatView.vue、packages/client/src/components/hermes/chat/ChatPanel.vue、ChatInput.vue、MessageList.vue、MessageItem.vue。 - tool event:先看
packages/client/src/stores/hermes/chat.ts、packages/client/src/components/hermes/chat/MessageItem.vue、packages/server/src/db/hermes/conversations-db.ts。 - plugin / skill 清单:先看
packages/client/src/api/hermes/plugins.ts、packages/client/src/api/hermes/skills.ts、packages/server/src/routes/hermes/plugins.ts、packages/server/src/routes/hermes/skills.ts、packages/server/src/services/hermes/plugins.ts。
| mnote 任务 | 参考文件 | 只参考什么 | 不采用什么 |
|---|---|---|---|
| Hermes API client 合同 | packages/client/src/api/hermes/chat.ts、packages/client/src/api/hermes/sessions.ts、packages/client/src/api/hermes/conversations.ts |
chat run、session detail、conversation list/detail 的请求和响应形状 | 不直接复用 TS client,不让浏览器绕过 mnote-web proxy |
| Hermes proxy / route 形态 | packages/server/src/routes/hermes/chat-run.ts、packages/server/src/routes/hermes/sessions.ts、packages/server/src/routes/hermes/proxy.ts、packages/server/src/routes/hermes/proxy-handler.ts |
服务端 route 如何接收 run、session、proxy 请求以及错误透传边界 | 不把 Hermes server route 复制进 mnote;mnote 只做同源薄代理 |
| session 真相与恢复 | packages/server/src/db/hermes/session-store.ts、packages/server/src/db/hermes/sessions-db.ts、packages/server/src/db/hermes/conversations-db.ts、packages/server/src/services/hermes/conversations.ts、packages/server/src/services/hermes/session-sync.ts |
session/message/conversation 的存储、搜索、恢复、thread/lineage 摘要 | 不在 mnote 里重建这些表或复制聊天历史 |
| usage / model 真相 | packages/server/src/db/hermes/usage-store.ts、packages/client/src/stores/hermes/usage.ts、packages/client/src/stores/hermes/models.ts、packages/client/src/components/layout/ModelSelector.vue |
usage、model selection、model display 的字段和展示语义 | 不在 mnote page aggregate 保存 usage/model 真相 |
| chat 面板结构 | packages/client/src/views/hermes/ChatView.vue、packages/client/src/components/hermes/chat/ChatPanel.vue、packages/client/src/components/hermes/chat/ChatInput.vue、packages/client/src/components/hermes/chat/MessageList.vue、packages/client/src/components/hermes/chat/MessageItem.vue、packages/client/src/components/hermes/chat/HistoryMessageList.vue、packages/client/src/components/hermes/chat/SessionListItem.vue |
session list、message list、输入框、消息项、历史消息的组件分层 | 不采用 Vue / Naive UI / Hermes 全屏布局;mnote 仍用 Leptos island 和 Wolai drawer 壳 |
| markdown / thinking 展示 | packages/client/src/components/hermes/chat/MarkdownRenderer.vue、packages/client/src/utils/thinking-parser.ts、tests/client/chat-store-thinking.test.ts、tests/client/thinking-parser.test.ts |
markdown 渲染、think/thinking/reasoning 片段解析、streaming 中的 thinking 边界 |
不直接照搬样式;mnote 只实现页面 AI 抽屉需要的折叠展示 |
| stream / abort / resume | packages/client/src/stores/hermes/chat.ts、packages/client/src/api/hermes/chat.ts、packages/server/src/routes/hermes/chat-run.ts、packages/server/src/services/hermes/chat-run-socket.ts |
run stream 事件、resume session room、abort started/completed、queue/server-working 状态 | 不强制采用 Socket.IO;mnote proxy 可用 SSE 或项目现有 stream 机制,但事件语义要对齐 |
| tool event 展示 | packages/client/src/stores/hermes/chat.ts、packages/client/src/components/hermes/chat/MessageItem.vue、packages/client/src/components/hermes/chat/HistoryMessageList.vue、packages/server/src/db/hermes/conversations-db.ts |
tool_call_id、tool message、tool started/completed/failed 的归并与历史展示 |
不把 tool result 写入 mnote 正文;只展示 Hermes tool event |
| session 搜索 | packages/client/src/components/hermes/chat/SessionSearchModal.vue、packages/client/src/composables/useSessionSearch.ts、tests/client/session-search.test.ts、tests/client/sidebar-search.test.ts |
后续 session search 的交互和过滤语义 | 第一版可后置,不进入最小验收 |
| plugins / skills 列表 | packages/client/src/api/hermes/plugins.ts、packages/client/src/api/hermes/skills.ts、packages/server/src/routes/hermes/plugins.ts、packages/server/src/routes/hermes/skills.ts、packages/server/src/services/hermes/plugins.ts、packages/client/src/components/hermes/skills/SkillList.vue、packages/client/src/components/hermes/skills/SkillDetail.vue |
Hermes 如何表达 plugin/skill 清单、启停和详情 | 不采用 Hermes skills 管理页面;mnote 只暴露 mnote.* tool manifest |
| 不属于 mnote 页面 AI 第一版 | packages/client/src/views/hermes/ChannelsView.vue、JobsView.vue、FilesView.vue、TerminalView.vue、GroupChatView.vue、SettingsView.vue、ProfilesView.vue、LogsView.vue、UsageView.vue |
仅作为边界参考,说明这些是 Hermes 管理台能力 | 不进入页面 AI 抽屉第一版 |
2. 总体验收标准
7-4 完成时必须同时满足:
- 页面 AI 抽屉打开后创建或恢复的是 Hermes session。
- Hermes session 存储里能看到页面 AI 的消息历史。
- mnote 本地不保存聊天消息真相,只保存业务写入 audit、artifact、edge、page/body/title/options 结果。
- 页面 AI 发送消息后,事件流来自 Hermes run,而不是旧
/api/ai-agent/runprovider / fallback 分支。 - tool call 展示来自 Hermes tool event;真实 Hermes upstream run 已触发
mnote.page.get,刷新后从 Hermes session detail 恢复。 - Hermes 至少能调用一个只读 mnote 工具读取当前页面。
- Hermes 至少能调用一个写入 mnote 工具,经 Rust runtime 写回当前页面正文或创建 artifact。
- 页面刷新后,AI 会话从 Hermes 恢复,而不是从 mnote 本地 state 恢复。
- 旧
provider=hermes502 不再出现在新页面 AI 主链。 rg检查活跃设计稿与代码注释不再把mnote-cli写成页面 AI 唯一长期执行面;命中已逐条归类为历史/兼容/已覆盖。
最终验收命令建议:
cd /mnt/Data1T/mnote
rg -n "mnote-cli.*唯一|唯一长期 agent|页面 AI.*mnote-cli|provider=hermes" design rust wolai-frontend --glob '*.md' --glob '*.rs' --glob '*.ts' --glob '*.tsx'
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-smoke.js
通过标准:
rg只允许命中design/old/或明确标注“历史/兼容/已覆盖”的段落。task-hermes-page-ai-smoke.js证明页面 AI 使用 Hermes session / run / stream,并验证刷新后从 Hermes session detail 恢复。task-hermes-page-ai-tool-smoke.js证明 Hermes tool call 能回到 mnote Rust runtime 并产生可读业务结果。
2026-05-14 验证记录:
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web hermes_ -- --nocapture:15 passed。MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-smoke.js:通过,捕获session -> session-detail -> run -> events -> session-detail,渲染mnote.page.gettool event,刷新恢复命中 Hermes session detail 2 次。MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-tool-smoke.js:通过,mnote.page.get返回标题、正文摘要和 read audit。MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-writeback-smoke.js:通过,mnote.page.save写入走page.body.save。MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-title-options-smoke.js:通过,标题走page.head.updateTitle,页面设置走page.layout.updateOptions。MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-artifact-smoke.js:通过,summary / ai_note 都走tree.node.create。- 早期临时
3019验证曾确认旧/api/ai-agent/run不再静默 fallback;最终正式3000验收已由 Task K/M 覆盖,当前稳定退场码为410 legacy_ai_agent_run_retired。 - 上述临时
3019证据已被正式http://127.0.0.1:3000全矩阵复跑覆盖;最终以 Task M 的 8 个3000smoke 证据为准。 - 追加验证:
task-hermes-page-ai-writeback-smoke.js、task-hermes-page-ai-title-options-smoke.js、task-hermes-page-ai-artifact-smoke.js已断言audit.commandId == result.commandId,临时3019通过。 - 追加验证:临时
3019日志已输出mnote Hermes tool call started/completed,字段包含trace_id/session_id/run_id/tool_call_id/tool_name/workspace_id/document_id/actor_id/effect。 - 追加验证:
MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-mobile-smoke.js通过,390px 窄屏下 drawer / panel / document 均无横向溢出。 - 追加验证:
task-hermes-page-ai-writeback-smoke.js已在 dryRun 后立即读取/api/documents/content,确认写入标记不存在;随后正式写入再确认标记存在。 - 追加验证:
hermes_tools_write_tools_require_auth已覆盖未认证写工具返回 401。 - 追加验证:
task-hermes-page-ai-writeback-smoke.js已用同一idempotencyKey重试正式写入,断言返回同一result.commandId/audit.commandId;临时3019日志出现mnote Hermes tool call idempotency replay。 - 追加验证:
task-hermes-page-ai-title-options-smoke.js已打开真实文档页,确认刷新后标题输入、breadcrumb/current title、data-page-wide-layout=true、data-page-small-text=true均生效。 - 追加验证:
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-title-options-smoke.js通过,tree_1778720870666_1标题更新为TEST-HERMES-AI-title-updated-mp4shbjq,页头 / breadcrumb/current title / sidebar 均一致。 - 追加验证:
task-hermes-page-ai-title-options-smoke.js已断言pageFont返回ignoredOptions=["pageFont"]与warningCodes=["page_option_not_wired"],不进入page.layout.updateOptions写入 payload。 - 追加验证:
task-hermes-page-ai-title-options-smoke.js已打开页面 AI 面板,确认data-mnote-page-ai-session-owner=hermes,mnote localStorage 只保存 HermesactiveSessionId,不保存或驱动 mnote 页面标题真相。 - 追加验证:
task-hermes-page-ai-title-options-smoke.js已验证mnote.page.update_titledryRun 后 meta 不变化,并验证同一idempotencyKey重试返回同一commandId。 - 追加验证:
task-hermes-page-ai-artifact-smoke.js已验证 summary 同 key 重试返回同一commandId/artifactDocumentId,ai_note 第二次创建得到独立artifactDocumentId,并验证工具结果里的referenceEdge.from/to/kind。 - 追加验证:
task-hermes-page-ai-audit-smoke.js已调用mnote.page.get与mnote.page.save,并通过/api/hermes/tools/mnote/audit?traceId=...反查started/completed事件,写工具 audit 可串到 RustcommandId,且不包含完整正文内容。
3. Task A:运行态基线与旧 502 复现
目标:
先固定当前问题和旧链入口,避免后续改动时把“没有复现”误认为“已经修好”。
建议修改范围:
- 新增或复用 smoke:
scripts/task-hermes-page-ai-baseline-smoke.js
- 只读记录:
rust/crates/mnote-web/src/routes/**wolai-frontend/src/**/ai-agent/**design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md
执行步骤:
- 启动当前前后端,确保测试入口可访问。
- 用真实测试账号登录。历史执行时使用旧 Auth 后端;当前默认应使用 SQLite control-plane Auth / session。
- 打开任意测试页面,点击右下角页面 AI。
- 发送一条只读问题,例如“概括当前页面标题和第一段”。
- 记录当前请求是否仍命中旧
/api/ai-agent/run。 - 记录是否出现
provider=hermes相关 502、ai_provider_bridge_unavailable或旧 fallback 文案。 - 将证据写入本 task 对应 bug 或执行记录,不修改业务逻辑。
验收标准:
- 有一份可复跑 smoke 或手动执行记录,明确当前页面 AI 主请求 URL。
- 能区分以下三类状态:
- 旧
/api/ai-agent/run仍被页面 AI 调用。 - 页面 AI 已调用 Hermes proxy,但 proxy 未接通。
- 页面 AI 已调用 Hermes proxy 且 session/run 可恢复。
- 旧
- 若仍出现 502,记录请求 URL、响应 body、mnote-web 日志时间戳和页面截图。
- 不把本 task 的 502 修复写进同一个提交;本 task 只做基线。
4. Task B:冻结 Hermes client proxy 合同
目标:
先冻结浏览器到 mnote-web 的同源 Hermes client proxy 合同,防止 Leptos 面板直接绑定 Hermes 私有 API 或暴露 key。
建议修改范围:
- 新增设计/协议文档:
design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md
- 后续代码位置建议:
rust/crates/mnote-web/src/routes/hermes_client.rsrust/crates/mnote-web/src/routes/mod.rsrust/crates/mnote-web/src/config.rs
合同路径第一版:
GET /api/hermes/client/sessionsPOST /api/hermes/client/sessionsGET /api/hermes/client/sessions/{session_id}POST /api/hermes/client/runsGET /api/hermes/client/events/{run_id}POST /api/hermes/client/runs/{run_id}/abortGET /api/hermes/client/modelsGET /api/hermes/client/tools
必须统一的请求字段:
workspaceIddocumentIdsessionIdmessagepageContextselectedBlockIdselectedTexttraceId
必须统一的响应字段:
sessionIdrunIdmessageIdevents[]error.codeerror.messagetraceId
执行步骤:
- 写明每个 proxy route 的输入输出 JSON 示例。
- 写明 proxy 只做 auth、同源安全、上下文注入和错误码标准化。
- 写明 proxy 不保存 session/message/tool event。
- 写明 Hermes API key 或 token 只存在服务端环境变量中。
- 写明
pageContext是运行输入,不是 Hermes session 的长期事实源。 - 写明旧
/api/ai-agent/run与新 proxy 的并存期规则。
验收标准:
- 合同文档里每个 route 都有请求/响应示例。
- 文档明确禁止浏览器直接持有 Hermes API key。
- 文档明确禁止 mnote 保存 Hermes 聊天历史。
- 文档明确旧
/api/ai-agent/run不是新 Hermes 面板主代理。 - 后续实现者不需要读 Hermes Web UI 源码也能知道 mnote 侧 proxy 的稳定合同。
5. Task C:实现 Hermes client proxy 最小只读链
目标:
让页面 AI 可以通过 mnote-web 同源代理创建/恢复 Hermes session,并发起一个无工具写入的只读 run。
建议修改范围:
- 新增:
rust/crates/mnote-web/src/routes/hermes_client.rs
- 修改:
rust/crates/mnote-web/src/routes/mod.rsrust/crates/mnote-web/src/config.rsrust/crates/mnote-web/src/error.rs
- 测试:
rust/crates/mnote-web/tests/hermes_client_proxy.rs或同 crate 现有 route 测试文件
执行步骤:
- 先写 route 测试:未登录请求返回 401 或项目统一 auth 错误。
- 写 route 测试:未配置 Hermes upstream 时返回稳定错误码
hermes_client_unconfigured。 - 写 route 测试:
POST /api/hermes/client/sessions只代理 session 创建,不写 mnote 数据。 - 写 route 测试:
POST /api/hermes/client/runs会带上workspaceId/documentId/pageContext/traceId。 - 实现最小 upstream client,先只支持 session create、session get、run create。
- 统一错误响应:Hermes 连接失败、401、429、5xx 必须映射成可展示的错误码。
- 记录日志字段:
traceId/sessionId/runId/documentId/workspaceId。
验收标准:
cargo test -p mnote-web hermes_client通过。- 未配置 Hermes 时,页面 AI 不出现 502,而是得到稳定
hermes_client_unconfigured。 - 配置 Hermes upstream 后,session create 和 run create 请求能从 mnote-web 代理到 Hermes。
- mnote 数据库、page aggregate、Convex 页面内容没有新增聊天消息字段。
- 网络请求中浏览器看不到 Hermes API key。
6. Task D:冻结 mnote Hermes plugin tool 合同
目标:
先定义 Hermes 看到的 mnote 工具清单和工具结果格式,避免工具从页面前端私有函数开始长出来。
建议新增文档:
design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md
第一批工具:
mnote.page.getmnote.page.savemnote.page.update_titlemnote.page.update_optionsmnote.artifact.create_summarymnote.artifact.create_ai_note
第二批工具:
mnote.tree.createmnote.tree.movemnote.search.documentsmnote.kernel.attach_reference
统一入参:
workspaceIddocumentIdactorIdsessionIdrunIdtoolCallIdtraceIdidempotencyKeydryRuncapabilityScope
统一出参:
oktoolNametoolCallIdtraceIdresultauditerror
执行步骤:
- 为每个第一批工具写 JSON schema。
- 为每个第一批工具写成功响应示例。
- 为每个第一批工具写失败响应示例。
- 写明权限校验点:登录、workspace member、页面读、页面写、artifact 写。
- 写明幂等规则:同一
idempotencyKey重试不得重复创建 artifact。 - 写明
dryRun=true时只能返回计划和 diff,不得写入。 - 写明 plugin 内部可以暂时调用
mnote-cliJSON adapter,但对 Hermes 暴露的名字必须是mnote.*。
验收标准:
- 合同文档覆盖所有第一批工具。
- 每个写工具都有
dryRun、idempotencyKey、权限失败、业务失败示例。 - 文档明确 tool 结果最终来自 Rust runtime / kernel。
- 文档明确 Hermes plugin 不直接写 Convex。
- 文档明确
mnote-cli是内部 adapter,不是 Hermes 看到的长期 tool 名称。
7. Task E:实现 mnote tool manifest 与只读工具
目标:
先让 Hermes 能发现 mnote 工具,并调用
mnote.page.get读取当前页面。
建议修改范围:
- 新增:
rust/crates/mnote-web/src/routes/hermes_tools.rsrust/crates/mnote-web/src/hermes_tools/mod.rsrust/crates/mnote-web/src/hermes_tools/manifest.rsrust/crates/mnote-web/src/hermes_tools/page.rs
- 修改:
rust/crates/mnote-web/src/routes/mod.rsrust/crates/bridge-runtime/src/lib.rs只在缺少正式 query 时补窄入口
- 测试:
rust/crates/mnote-web/tests/hermes_tools.rs
建议 route:
GET /api/hermes/tools/mnote/manifestPOST /api/hermes/tools/mnote/call
执行步骤:
- 写 manifest 测试:返回第一批工具名称、schema version、capability scope。
- 写
mnote.page.get测试:未登录失败。 - 写
mnote.page.get测试:无 workspace 权限失败。 - 写
mnote.page.get测试:有权限时返回当前 page aggregate 摘要。 - 实现 manifest route。
- 实现统一 tool call dispatcher,只接
mnote.page.get。 - 将
mnote.page.get接到现有 Rust runtime / page aggregate query。
验收标准:
cargo test -p mnote-web hermes_tools通过。GET /api/hermes/tools/mnote/manifest返回稳定mnote.page.getschema。POST /api/hermes/tools/mnote/call调用mnote.page.get返回当前页面标题、正文摘要、page options、可用 block 摘要。- 权限失败不会泄露页面标题或正文。
- 工具返回中包含
traceId/toolCallId/sessionId。
8. Task F:Leptos Hermes 面板最小只读 UI
目标:
在保留 Wolai 右下角入口和右侧抽屉壳的前提下,把页面 AI 面板改为调用 Hermes client proxy。
建议修改范围:
- Leptos / Rust SSR 侧按当前真实结构定位:
rust/crates/mnote-web/src/ssr/**rust/crates/mnote-web/src/routes/web_shell.rs- 页面内 island 挂载资源所在目录
- 若仍需 React compat,只能作为旧 panel 参考,不得扩展旧执行链:
wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx
- smoke:
scripts/task-hermes-page-ai-smoke.js
第一版 UI 子集:
- session 创建/恢复
- message list
- chat input
- streaming delta
- reasoning 展开
- tool started / completed 展开
- error / retry / abort
- model selector 可先只读展示默认模型
执行步骤:
- 写 smoke:打开页面 AI 后,不允许发送请求到
/api/ai-agent/run。 - 写 smoke:打开页面 AI 后,会请求
/api/hermes/client/sessions。 - 写 smoke:发送消息后,会请求
/api/hermes/client/runs。 - 写 smoke:页面刷新后,面板可从 Hermes session 恢复消息。
- 实现 Leptos 面板数据层,只保存 UI 临时状态,不保存聊天真相。
- 接入 session create / restore。
- 接入 run create / event stream。
- 接入 abort / retry 的最小状态。
- 保留右下角入口、右侧 drawer、Esc / close 行为与
5-11证据一致。
验收标准:
node scripts/task-hermes-page-ai-smoke.js通过。- 页面 AI 主链不再请求
/api/ai-agent/run。 - 页面 AI 消息刷新后来自 Hermes session。
- mnote 本地页面 state 里没有完整聊天消息数组。
- 抽屉入口、关闭语义、移动端不溢出继续符合
5-11的历史 Wolai 对齐要求。 - Hermes 不可用时展示稳定错误态,不出现 502 空白或旧
page_ai_failed_502。
9. Task G:接入 Hermes tool event 展示与只读工具调用
目标:
让 Hermes run 调用
mnote.page.get时,页面 AI 能展示 tool started / completed,并把结果作为 Hermes 消息链的一部分呈现。
建议修改范围:
rust/crates/mnote-web/src/routes/hermes_client.rsrust/crates/mnote-web/src/routes/hermes_tools.rs- Leptos 面板 island 相关文件
scripts/task-hermes-page-ai-tool-smoke.js
执行步骤:
- 写 smoke:发送“读取当前页面标题和页面设置”,期望出现
mnote.page.gettool started。 - 写 smoke:同一次 run 出现
mnote.page.gettool completed。 - 写 smoke:tool result 中的标题与当前页头标题一致。
- 实现 tool event 渲染:started、completed、failed 三态。
- 实现 tool result 折叠展示,默认只显示 tool 名和摘要。
- 确保 tool result 不被写入 mnote 页面正文。
- 确保 Hermes session 中保留 tool event,刷新后可恢复。
验收标准:
node scripts/task-hermes-page-ai-tool-smoke.js通过。- 工具事件来自真实 Hermes upstream run,而不是前端本地伪造。
mnote.page.get权限失败时,UI 显示 tool failed,正文不泄露。- 刷新页面后 tool event 仍从 Hermes session 恢复。
- mnote page aggregate 不包含 tool event 历史。
10. Task H:接入正文写入工具 mnote.page.save
目标:
让 Hermes 可以通过 mnote plugin 对当前页正文做最小写入,写入仍走正式
page.body.save链。
建议修改范围:
rust/crates/mnote-web/src/hermes_tools/page.rsrust/crates/bridge-runtime/src/lib.rs仅补必要正式 command adapter- 页面保存相关 route / command adapter
- smoke:
scripts/task-hermes-page-ai-writeback-smoke.js
执行步骤:
- 写 tool contract 测试:
mnote.page.save必须要求documentId、idempotencyKey、dryRun。 - 写 dryRun 测试:
dryRun=true返回 diff,不写入。 - 写权限失败测试:未认证时不进入页面写链。
- 写幂等测试:同一
idempotencyKey重试不重复执行写链。 - 实现
mnote.page.save到page.body.save的 adapter。 - 在 Hermes 面板里对写工具结果展示 diff 摘要。
- smoke 执行:让 AI 在当前测试页面写入一段带测试前缀的文本。
- smoke 读取
/api/documents/content或当前正式内容接口,确认刷新后文本存在。
验收标准:
- dryRun 不改变页面内容。
- 未认证不进入写链。
- 同一幂等键不会重复写入。
- 正式写入后,主编辑区 island 能立即回显。
- 刷新后内容仍存在。
- 写入链路日志包含
sessionId/runId/toolCallId/traceId/documentId/actor。 - 写入不经过旧
/api/ai-agent/run。
11. Task I:接入标题与页面设置工具
目标:
把 AI 修改标题和页面设置收口到同一组 Page Aggregate command family,而不是靠面板本地副作用。
建议修改范围:
rust/crates/mnote-web/src/hermes_tools/page.rsrust/crates/bridge-runtime/src/lib.rsdesign/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md仅回填完成证据- smoke:
scripts/task-hermes-page-ai-title-options-smoke.js
执行步骤:
- 写
mnote.page.update_titledryRun / permission / idempotency 测试。 - 写
mnote.page.update_optionsdryRun / permission / wired-only 字段测试。 - 实现标题工具到
page.head.updateTitle。 - 实现页面设置工具到
page.layout.updateOptions。 - 禁止写入
runtimeSupport !== "wired"的页面设置字段。 - smoke 修改当前测试页标题,确认页头与 breadcrumb/current title 一致。
- smoke 修改
smallText或wideLayout,确认主编辑区 page shell 属性变化。
验收标准:
- 标题修改后页头、breadcrumb、sidebar、刷新后标题一致。
- 页面设置修改只允许 wired 字段。
- planned / ui_only 字段返回明确错误或 dryRun 警告。
- AI 面板不维护独立标题状态。
- 所有写入都经 Rust runtime / Page Aggregate command family。
12. Task J:接入结构化 Artifact 工具
目标:
落地
7-2的summary node / ai_note node / reference edge,触发方改为 Hermes tool call。
建议修改范围:
rust/crates/mnote-web/src/hermes_tools/artifact.rsrust/crates/bridge-runtime/src/lib.rsrust/crates/core-protocol/src/**若缺少正式类型再补- smoke:
scripts/task-hermes-page-ai-artifact-smoke.js
执行步骤:
- 写
mnote.artifact.create_summaryschema 测试。 - 写
mnote.artifact.create_ai_noteschema 测试。 - 写 summary 单例更新测试:同一页面重复创建 summary 不生成多个 summary node。
- 写 ai_note 多次创建测试:每次生成独立 ai_note node。
- 写 reference edge 测试:artifact 与当前页面之间有可查询 reference edge。
- 实现工具到 Rust runtime / kernel。
- 页面 AI 面板可提供
创建 Summary/创建 AI Note快捷入口,但入口只发送 Hermes intent。 - smoke 验证
AI Artifactsprojection-only 分组可见。
2026-05-14 J1 执行证据:
- 修正
rust/crates/bridge-runtime/src/lib.rs:从 artifact 文档命名与父子关系派生metadata.kind="ai_artifact_reference"的source_ofkernel edge,并在 file-tree projectionmeta.aiArtifacts中标记projectionOnly=true、kernelNodeId=null。 - 新增 bridge-runtime 单测
kernel_edges_list_exposes_ai_artifact_reference_edges与file_tree_projection_marks_ai_artifacts_group_as_projection_only。 - 验证命令:
cd rust && cargo test -p bridge-runtime ai_artifact -- --nocapture:2 passed。 - 验证命令:
cd rust && cargo build -p mnote-web:通过;正式3000已重启到新二进制,PID2043001。 - 扩展
scripts/task-hermes-page-ai-artifact-smoke.js:调用/api/kernel/edges查询 summary / ai_note 的ai_artifact_reference,调用/api/tree/projections/file查询meta.aiArtifacts.projectionOnly=true,并回查 artifact audit。 - 修正
rust/crates/mnote-web/src/ssr/pages/layout.rs与rust/crates/mnote-web/src/ssr/styles.rs:页面 AI 抽屉提供创建 Summary/创建 AI Note快捷入口,点击后只调用sendPageAiMessage(...)发送 Hermes intent。 - 验证命令:
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-artifact-smoke.js:通过;最终复跑测试页tree_1778721933687_1,summarysummary_tree_1778721933687_1,ai_noteai_note_tree_1778721933687_1_req_1778721933785_11、ai_note_tree_1778721933687_1_req_1778721933813_13,referenceEdgeCount=6,auditEventCount=6;快捷入口发送的 Hermes intent 分别包含mnote.artifact.create_summary与mnote.artifact.create_ai_note,且页面路由已禁止直连/api/hermes/tools/mnote/call。
验收标准:
- artifact 创建不绕过 Hermes tool call。
- artifact 创建不绕过 Rust runtime / kernel。
AI Artifacts仍是 projection-only 分组,不是真实 kernel node。- summary node 可重复更新但不重复创建。
- ai_note node 每次新建。
- reference edge 可通过 kernel query 或 projection 验证。
- artifact 写入 audit 包含 Hermes
sessionId/runId/toolCallId。
13. Task K:退役旧页面 AI 主执行链
目标:
新 Hermes 面板通过后,旧
/api/ai-agent/run不再作为页面 AI 主入口。
建议修改范围:
rust/crates/mnote-web/src/routes/**wolai-frontend/src/app/api/ai-agent/run/route.tswolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsxdesign/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-v1.md
执行步骤:
- 全仓搜索页面 AI 发送路径。
- 删除或禁用页面 AI 对
/api/ai-agent/run的主路径调用。 - 保留 legacy endpoint 时,响应必须明确
legacy_ai_agent_run_retired或项目统一退场码。 - 删除
provider=hermes作为旧 endpoint provider/fallback 的语义。 - 更新旧 smoke:不再期待
/api/ai-agent/run -> mnote-cli。 - 保留历史 smoke 到
old或改名为 legacy guard。
2026-05-14 K 执行证据:
- 修正
rust/crates/mnote-web/src/routes/compat.rs:POST /api/ai-agent/run不再进入mnote-cli host,统一返回410 legacy_ai_agent_run_retired,响应头x-mnote-ai-execution-owner=legacy-ai-agent-run-retired。 - 更新 compat 单测:
direct_ai_agent_run_returns_legacy_retired_guard、explicit_agent_provider_returns_legacy_retired_guard、explicit_hermes_provider_fails_instead_of_using_legacy_next_or_direct_bridge。 - 验证命令:
cd rust && cargo test -p mnote-web ai_agent_run -- --nocapture:1 passed。 - 验证命令:
cd rust && cargo test -p mnote-web explicit_ -- --nocapture:2 passed。 - 验证命令:
cd rust && cargo build -p mnote-web:通过;正式3000已重启到新二进制,PID2108896。 - 验证命令:
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-retirement-guard.js:通过,status410,codelegacy_ai_agent_run_retired,ownerlegacy-ai-agent-run-retired。 - 默认退役历史 smoke:
task155-e27-ai-edit-smoke.js、task156-e27-ai-writeback-smoke.js、task178-page-ai-local-subtree-context-smoke.js、task052-ai-tools-runtime-smoke.js、task161-wolai-page-ai-shell-smoke.js、task111-phase7-document-ai-online-smoke.js已移入本机 gitignoredrecycle/scripts/retired-ai-agent-run-smokes/,历史版本默认输出{ retired: true },不再期待旧/api/ai-agent/run -> mnote-cli成功;如需历史对照,必须显式设置MNOTE_ALLOW_RETIRED_AI_AGENT_RUN_SMOKE=1。 - legacy 调用方清点:
wolai-frontend/src/components/ai-agent/AiAgentPanel.tsx、wolai-frontend/src/components/editor/blocks/MindmapAiAgentPanel.runtime.tsx、wolai-frontend/src/components/onlyoffice/OnlyOfficeAiAgentPanel.runtime.tsx、wolai-frontend/src/app/api/mindmap-ai/expand-node/route.ts仍是旧域/兼容调用点,不属于当前 mnote-web 页面 AI 主链;若被调用会命中legacy_ai_agent_run_retiredguard,后续按各自 domain 另拆 Hermes plugin / Rust bridge 迁移。 - 活跃设计口径同步:
5-6、5-9、10-review已改为历史/已覆盖/legacy guard 说明,不再把/api/ai-agent/run写作页面 AI 长期入口。
验收标准:
- 新页面 AI 主链无
/api/ai-agent/run请求。 - 访问旧
/api/ai-agent/run不会静默 fallback 到 Hermes、Codex、旧 orchestrator。 provider=hermes不再产生新页面 AI 主链 502。- 活跃文档不再把
/api/ai-agent/run描述为页面 AI 长期入口。 - legacy 调用方清单为空,或全部有明确退场说明。
14. Task L:权限、审计与可观测性闭环
目标:
让 Hermes 调用 mnote 工具后的每一次业务影响都可审计、可追踪、可复盘。
建议修改范围:
rust/crates/mnote-web/src/hermes_tools/**rust/crates/bridge-runtime/src/**- audit / event log 相关 crate 或 route
- smoke:
scripts/task-hermes-page-ai-audit-smoke.js
执行步骤:
- 定义统一 trace 字段:
traceId/sessionId/runId/toolCallId/documentId/workspaceId/actorId/toolName。 - 所有 tool call 开始时记录 intent。
- 所有成功写入记录 result 和 command id。
- 所有失败记录错误码,不记录完整隐私正文。
- smoke 执行一次
mnote.page.get和一次写工具。 - smoke 从日志或审计接口确认两次 tool call 都可追踪。
2026-05-14 L 执行证据:
- 修正
rust/crates/mnote-web/src/routes/hermes_tools.rs:audit_push同步写入内存缓存与 JSONL 持久化落点,默认路径tmp/mnote-hermes-tool-audit.jsonl,可用MNOTE_HERMES_TOOL_AUDIT_LOG覆盖;GET /api/hermes/tools/mnote/audit?persistedOnly=true只读取持久化审计。 - workspace 上下文冲突现在也会写入
started -> failed审计链,失败审计只包含 trace / tool / actor / workspace / document / status / message,不写入页面标题或正文。 - 扩展
scripts/task-hermes-page-ai-audit-smoke.js:执行mnote.page.get、mnote.page.save、workspace 权限失败三类调用;分别查询内存 audit 与persistedOnly=trueaudit;断言写工具持久化 audit 串到 RustcommandId,权限失败持久化 audit 不包含正文 marker 或页面标题。 - 验证命令:
cd rust && cargo test -p mnote-web hermes_tools_ -- --nocapture:9 passed。 - 验证命令:
cd rust && cargo build -p mnote-web:通过;正式3000已重启到新二进制,PID2175265。 - 验证命令:
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-audit-smoke.js:通过;测试页tree_1778723140835_1,写命令page_body_save_req_1778723140928_9,writePersistedPhases=["started","completed"],deniedPersistedPhases=["started","failed"]。
验收标准:
- 每个 tool call 都有稳定 trace。
- 写工具能追踪到最终 Rust command。
- 失败不会泄露无权限页面内容。
- 日志可以把页面 AI 面板请求、Hermes run、mnote tool call、Rust command 串起来。
- 审计只保存业务影响,不保存完整 Hermes 聊天历史。
15. Task M:端到端验收矩阵
目标:
用一组固定 smoke 证明新主线能覆盖只读、写正文、写标题/设置、artifact 和旧链退役。
必须具备的 smoke:
scripts/task-hermes-page-ai-smoke.jsscripts/task-hermes-page-ai-tool-smoke.jsscripts/task-hermes-page-ai-writeback-smoke.jsscripts/task-hermes-page-ai-title-options-smoke.jsscripts/task-hermes-page-ai-artifact-smoke.jsscripts/task-hermes-page-ai-retirement-guard.jsscripts/task-hermes-page-ai-mobile-smoke.jsscripts/task-hermes-page-ai-audit-smoke.js
执行顺序:
- 只读 session/run smoke。
- 只读 tool smoke。
- 正文写入 smoke。
- 标题与页面设置 smoke。
- artifact smoke。
- 旧链退役 guard。
- 移动端 / 窄屏抽屉 smoke。
- 刷新恢复 smoke。
2026-05-14 M 执行证据:
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-smoke.js:通过;tree_1778723249255_3,sessionmnote_smoke_mp4twavi,runrun_smoke_mp4twavi,sessionDetailHits=2。MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-smoke.js:通过;tree_1778723260375_5,工具mnote.page.get,标题TEST-HERMES-AI-tool-mp4twjgi。MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-writeback-smoke.js:通过;tree_1778723271226_7,markerTEST-HERMES-AI-WRITEBACK-mp4twrtt,commandpage_body_save_req_1778723271849_379。MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-title-options-smoke.js:通过;tree_1778723295128_9,标题TEST-HERMES-AI-title-updated-mp4txa9v,pageFont返回page_option_not_wiredwarning。MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-artifact-smoke.js:通过;tree_1778723316873_11,referenceEdgeCount=6,meta.aiArtifacts.projectionOnly=true。MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-retirement-guard.js:通过;旧入口返回410 legacy_ai_agent_run_retired。MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-mobile-smoke.js:通过;390px viewport 下 drawer/panel 均无横向溢出。MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-audit-smoke.js:通过;tree_1778723372948_15,写命令page_body_save_req_1778723373026_707,持久化 audit 可查started/completed与权限失败started/failed。
总体验收标准:
- 所有 smoke 在真实
http://127.0.0.1:3000上通过。 - 使用默认真实测试账号,不使用
MNOTE_DEV_AUTH=1伪登录作为正式验收。历史执行时使用旧 Auth 后端;当前默认应使用 SQLite control-plane Auth / session。 - smoke 只操作本轮新建测试数据,测试数据前缀统一为
TEST-HERMES-AI-<timestamp>。 - 测试结束后可定位创建的页面、artifact、edge、audit。
- 任一 smoke 失败时,必须记录到
bugs/对应分类,而不是在 checklist 中直接标 GREEN。
16. Task N:文档回填与 old 目录治理
目标:
代码主链切换后,设计目录继续反映真实状态,避免旧 CLI-first 口径回流。
2026-05-14 口径审计记录:
find design/07-ai -maxdepth 3 -type f | sort已确认当前 07-ai 活跃结构为:7-1、7-2、7-3、7-4、7-5、7-6在done/;后续 Mini Hermes 控制面由design/07-ai/process/7-7-page-ai-mini-hermes-control-surface-v1.md承接。design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md仍保留为历史决策记录,并已标[recycle]。design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md的mnote-cli命中均用于说明历史 CLI-first / 被覆盖 / 禁止继续采用的口径。design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md的mnote-cli与provider=hermes命中均用于迁移目标、legacy guard 或验收条件,不把它写成长期主线。- 活跃设计命中已收口:
5-6、5-9、10-review/04、10-review/06、1-1、3-1均已把旧/api/ai-agent/run/mnote-cli host写成历史、兼容、已覆盖或 legacy guard。 design/10-review/04-secondary-domains-and-design-governance-review.md已继续指向 Hermes plugin / Rust bridge,并明确旧openai-agents-python/mnote-cli host只按历史/兼容/对照链处理。
建议修改范围:
design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.mddesign/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.mddesign/03-rust-web/reference/3-rust-web-long-term-architecture-v1.mddesign/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-v1.mddesign/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.mddesign/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.mddesign/old/07-ai/process/*
执行步骤:
- 把完成证据回填到本 checklist 对应 task。
- 7-4 的实现证据已满足完成定义,本文已归档到
design/07-ai/done/并同步更新引用。 - 保留
7-3为主线设计稿;7-4作为实现与验收执行清单,不覆盖7-3的架构口径。 - 活跃设计稿中只允许历史、兼容、已覆盖或 legacy guard 说明提到
mnote-cli host。 - 旧 CLI-first 文档必须继续留在
design/old/07-ai/process/并标[recycle]。 - 更新
design/10-review中旧建议,使其指向 Hermes plugin / Rust bridge。
验收标准:
find design/07-ai -maxdepth 3 -type f | sort能清楚看到当前 process/done 状态。rg -n "mnote-cli.*唯一|唯一长期 agent|CLI-first" design --glob '*.md'的活跃目录命中都带有“历史/回收/已覆盖”说明。design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md仍保留为历史决策记录。- 没有把未完成代码能力提前标成 done。
16.1 剩余顺序执行 checklist(按 G-N 顺序)
这一段只收纳当前仍未完成的项,按顺序逐项勾选。每个 task 都必须在本段回填“执行命令 / 证据路径 / 结果”,不能只写口头结论。
Hermes Web UI 参考目录固定为
/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18。下文所有packages/...路径都相对此目录。需要对照时按列出的文件和符号打开,不整目录通读,不照搬 Vue / Naive UI / 管理台页面。
G1:把 tool event 刷新恢复补成真实 Hermes upstream 闭环
目标: 证明 mnote.page.get 是由真实 Hermes upstream run 触发,并由 Hermes session 存储回灌;mnote 页面 AI 只消费 Hermes 事件。
必须参考 Hermes Web UI 的位置:
| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
|---|---|---|---|
| run 请求与事件字段 | packages/client/src/api/hermes/chat.ts |
StartRunRequest 第 14 行;RunEvent 第 28 行 |
对齐 mnote proxy / Leptos 面板消费的 run event 字段 |
| session handler 注册 | packages/client/src/api/hermes/chat.ts |
registerSessionHandlers 第 297 行;resumeSession 第 420 行;startRunViaSocket 第 432 行 |
对齐“按 session 订阅事件、刷新后 resume”的语义 |
| tool event 归并到消息 | packages/client/src/stores/hermes/chat.ts |
mapHermesMessages 第 125 行;case 'tool.started' 第 910 / 1340 行;case 'tool.completed' 第 948 / 1378 行 |
对齐 tool started / completed 与 session detail 里的消息形态 |
| tool message 展示 | packages/client/src/components/hermes/chat/MessageItem.vue |
message.role === 'tool' 第 508 行;formatToolPayload 第 263 行;tool-preview 第 543 行;tool-details 第 555 行 |
对齐默认折叠、摘要和详情展开,不照搬样式 |
| upstream tool event 生成 | packages/server/src/services/hermes/chat-run-socket.ts |
applyResponseStreamEvent 第 1035 行;function_call 第 1101 / 1110 行;tool.started 第 1131 行;function_call_output 第 1145 行;tool.completed 第 1165 行;flushResponseRunToDb 第 1207 行 |
确认 tool event 来源于 upstream response stream,并最终 flush 到 Hermes DB |
| Hermes plugin 发现 | packages/server/src/services/hermes/plugins.ts |
PluginManager 第 63 / 120 行;user_dir = get_hermes_home() / "plugins" 第 137 行;providesTools 第 200 行;listHermesPlugins 第 310 行 |
确认 mnote 工具必须进入 Hermes plugin / tool registry |
顺序执行 checklist:
- G1.1 运行
hermes plugins list,确认当前 Hermes 是否已经能发现mnoteplugin;把输出摘要回填到本 task。 - G1.2 运行
hermes tools list --platform api_server,确认mnotetoolset 或mnote_page_get是否已经可见;把输出摘要回填到本 task。 - G1.3 如果
mnote不可见,创建或修正用户插件目录/home/lix/.hermes/plugins/mnote/,其中plugin.yaml必须声明name: mnote与provides_tools,__init__.py必须通过ctx.register_tool(..., toolset="mnote")注册工具。 - G1.4 插件对 Hermes 暴露的函数名使用 OpenAI function-name 兼容名,例如
mnote_page_get;插件内部再映射到 mnote-web tool route 的toolName: "mnote.page.get"。 - G1.5 插件 handler 只调用
POST http://127.0.0.1:3000/api/hermes/tools/mnote/call或MNOTE_UI_BASE_URL指向的同源 mnote-web route,不直接读写 Convex。 - G1.6 将
mnote加入/home/lix/.hermes/config.yaml的plugins.enabled后,重新运行hermes plugins list与hermes tools list --platform api_server。 - G1.7 触发一次真实 Hermes upstream run,请求内容使用“读取当前页面标题和页面设置”,确认模型实际选择
mnote_page_get/mnote.page.get。 - G1.8 在 mnote 页面 AI 面板网络记录里确认事件来自
/api/hermes/client/runs与/api/hermes/client/events/{run_id}或当前 Hermes proxy 等价入口,不是前端本地拼出的假事件。 - G1.9 刷新页面后重新打开 AI 面板,确认同一 tool event 从 Hermes session detail 恢复,顺序与首次流式展示一致。
- G1.10 回填证据:Hermes run id、session id、tool call id、mnote trace id、截图或 smoke 输出路径。
2026-05-14 G1 执行证据:
python -m py_compile /home/lix/.hermes/plugins/mnote/__init__.py:通过。hermes plugins list:mnote显示为enableduser plugin。hermes tools list --platform api_server:Plugin toolsets 中mnote显示为 enabled。/home/lix/.hermes/hermes-agent/venv/bin/python调用get_tool_definitions(enabled_toolsets=["mnote"]):可见mnote_page_get、mnote_page_save、mnote_page_update_title、mnote_page_update_options、mnote_artifact_create_summary、mnote_artifact_create_ai_note。- 发现并修复运行态差异:Hermes gateway 长进程启动早于 mnote plugin 接入,首次
/v1/runs只看到 MemPalace 等旧工具;执行hermes gateway restart后真实 upstream run 可见mnote_page_get。 - 3000 主入口已重启为当前
mnote-web,并配置MNOTE_WEB_HERMES_UPSTREAM_URL=http://127.0.0.1:8642与服务端 Hermes API key;GET /api/hermes/client/models经 mnote-web proxy 返回hermes-agent。 - 修正
rust/crates/mnote-web/src/routes/hermes_client.rs:Hermes run context 透传actorId/actorType/sessionId/traceId,并在toolGuidance中要求读取标题/页面设置时传includeBody=false/includeOptions=true/includeBlocks=false。 - 验证命令:
cd rust && cargo test -p mnote-web hermes_client_run_body_carries_page_context_into_run_input -- --nocapture:1 passed。 - 验证命令:
cd rust && cargo build -p mnote-web:通过。 - 真实页面 AI 面板不 mock 验证:测试页
TEST-HERMES-AI-realpanel-green-mp4rv3w3,页面 AI 捕获网络请求POST /api/hermes/client/sessions、GET /api/hermes/client/sessions/{sessionId}、POST /api/hermes/client/runs、GET /api/hermes/client/events/run_4a8b09db7fbc45b8bb1bbea68b436093,未请求/api/ai-agent/run。 - Hermes run:
run_4a8b09db7fbc45b8bb1bbea68b436093,statuscompleted,sessionmnote_tree_1778719834312_1_page-ai-mp4rv470,输出包含标题TEST-HERMES-AI-realpanel-green-mp4rv3w3与页面设置。 - Hermes session export:
mnote_tree_1778719834312_1_page-ai-mp4rv470,message_count=4,tool_call_count=1;assistant tool call 为mnote_page_get,Hermes tool call id 为call_00_5B7fVip245331pk4zYyd5532;tool message 内容ok=true、toolName=mnote.page.get。 - mnote audit:
trace_1778719842620_2b05ef8600,mnote tool call idtool_1778719842620_7687c1860a,phase=started/completed,effect=read,actorId=a4b72c17-49e3-46d3-8456-24a0a7044d64。 - 刷新恢复:同一页面刷新后重新打开 AI 面板,请求
GET /api/hermes/client/sessions/mnote_tree_1778719834312_1_page-ai-mp4rv470,抽屉文本恢复出 Hermes session 中的页面标题与 tool message。
验收标准:
- 真实 Hermes upstream run 触发
mnote.page.get,不是直接调用 mnote-web tool smoke 假代替。 - tool event 通过 Hermes run stream / session detail 回灌到页面。
- 页面刷新后仍能从 Hermes session detail 恢复同一批 tool event。
- 前端本地 state 只承担临时渲染,不作为 tool event 最终真相。
H1:补 workspace ACL 负向验证与正文立即回显
目标: 写正文工具必须证明权限失败不泄露、成功写入后主编辑区立即可见,且 AI 面板不保存正文真相。
必须参考 Hermes Web UI 的位置:
| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
|---|---|---|---|
| 权限失败事件形态 | packages/client/src/api/hermes/chat.ts |
RunEvent 第 28 行;onToolStarted / onToolCompleted 第 69-70 行;onRunFailed 第 73 行 |
失败也走稳定事件,不出现空白 502 |
| 失败事件持久化 | packages/server/src/services/hermes/chat-run-socket.ts |
emit 第 574 / 963 行;markCompleted 第 978 / 1276 行;flushResponseRunToDb 第 1207 行 |
确认失败信息也能进入可恢复 session |
| session 只保存消息真相 | packages/server/src/db/hermes/session-store.ts |
HermesMessageRow 第 35 行;addMessage 第 331 行;getSessionDetail 第 313 行 |
失败消息留在 Hermes session,不写入 mnote 正文 |
| tool failed 展示 | packages/client/src/components/hermes/chat/MessageItem.vue |
tool-error-badge 第 551 行;tool-details 第 555 行 |
权限失败显示错误摘要,不泄露正文 |
| 写入后 UI 刷新边界 | packages/client/src/stores/hermes/chat.ts |
sendMessage 第 646 行;runHadToolActivity 第 737 行;cleanup 附近 |
tool 完成后刷新业务事实,不复制正文真相到 AI 面板 |
顺序执行 checklist:
- H1.1 新增或扩展
scripts/task-hermes-page-ai-writeback-smoke.js:构造无 workspace 权限或无页面写权限场景,调用mnote.page.save。 - H1.2 断言权限失败返回稳定错误码,例如
permission_denied/workspace_access_denied,响应体不得包含页面标题、正文全文或 block 原文。 - H1.3 在页面 AI 面板断言失败展示为 tool failed / permission denied,不是 502、空白或旧 provider 错误。
- H1.4 正向写入时,使用测试前缀
TEST-HERMES-AI-<timestamp>调用mnote.page.save。 - H1.5 写入完成后不刷新页面,直接断言主编辑区 island 可见新内容。
- H1.6 刷新页面后再次断言新内容存在,证明业务事实已回到正式正文链。
- H1.7 检查 AI 面板状态或 session detail,确认不保存完整正文副本,只保存 tool event / tool result 摘要。
2026-05-14 H1 执行证据:
- 修正
rust/crates/mnote-web/src/routes/hermes_tools.rs:当请求头x-mnote-workspace-id与 tool payloadworkspaceId不一致时,返回403 workspace_context_conflict,不进入页面读写链。 - 新增单测
hermes_tools_reject_workspace_context_conflict_without_content_leak:断言响应不包含测试 fixture 标题服务端页面与正文章节一。 - 验证命令:
cd rust && cargo test -p mnote-web hermes_tools_reject_workspace_context_conflict_without_content_leak -- --nocapture:1 passed。 - 扩展
scripts/task-hermes-page-ai-writeback-smoke.js:先构造 workspace 上下文冲突负向调用,断言403 workspace_context_conflict且不泄露页面标题 / 正文标记;再用页面 AI 面板 mock Hermestool.failed事件断言 UI 展示mnote.page.save与permission_denied,不是 502 / 空白 / 旧 provider 错误;最后执行 dryRun、正式写入、主编辑区即时回显、幂等重试和刷新后读取。 - 验证命令:
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-writeback-smoke.js:通过;最终复跑测试页tree_1778720381778_4,标记TEST-HERMES-AI-WRITEBACK-mp4s6ubg,写入命令page.body.save,commandId=page_body_save_req_1778720382427_413。 - smoke 在正式
3000运行,写入完成后未刷新页面即等待主编辑区出现TEST-HERMES-AI-WRITEBACK-*标记;随后通过/api/documents/content读取确认刷新后仍存在。
验收标准:
- 未授权不能写正文,且失败响应不泄露正文。
- 成功写入后主编辑区即时可见。
- 刷新后正文仍存在。
- 页面 AI 不持有正文真相副本。
I1:补标题与 sidebar 一致性验证
目标: mnote.page.update_title 与 mnote.page.update_options 只改变 mnote 页面事实;Hermes session 标题、模型状态和页面标题不能混成一份真相。
必须参考 Hermes Web UI 的位置:
| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
|---|---|---|---|
| session title 只是会话标题 | packages/server/src/db/hermes/session-store.ts |
HermesSessionRow 第 9 行;renameSession 第 202 行 |
区分 Hermes 会话标题与 mnote 页面标题 |
| session detail 字段 | packages/server/src/db/hermes/session-store.ts |
HermesSessionDetailRow 第 56 行;getSessionDetail 第 313 行 |
刷新恢复 AI 会话,不恢复页面标题草稿 |
| 面板标题展示 | packages/client/src/components/hermes/chat/ChatPanel.vue |
activeSessionTitle 第 193 行;headerTitle 第 197 行;SessionListItem 第 598 / 636 行;MessageList 第 790 行;ChatInput 第 791 行 |
AI 面板只展示 session 语义,不维护页面标题草稿 |
| session 列表标题 | packages/client/src/components/hermes/chat/SessionListItem.vue |
session-item-title 第 94 行;session.title 第 96 行;session-item-model 第 100 行 |
不把 sidebar 页面标题同步需求写进 Hermes session list |
| model 展示边界 | packages/client/src/components/layout/ModelSelector.vue |
selectedDisplayName 第 16 行;handleSelect 第 64 行;model-name 第 105 行;model-item 第 142 行 |
model 真相不回写 mnote page aggregate |
顺序执行 checklist:
- I1.1 扩展
scripts/task-hermes-page-ai-title-options-smoke.js,修改标题为TEST-HERMES-AI-<timestamp>。 - I1.2 断言页头标题、breadcrumb/current title、sidebar 树节点标题三处立即一致。
- I1.3 刷新页面后再次断言三处标题一致,且值来自页面真源。
- I1.4 断言 AI 面板 session 标题没有被当成 mnote 页面标题真相。
- I1.5 调用
mnote.page.update_options修改smallText或wideLayout,确认只接受runtimeSupport == "wired"字段。 - I1.6 对
planned/ui_only字段执行 dryRun 或正式调用,确认返回明确警告或错误,不产生页面事实写入。
2026-05-14 I1 执行证据:
- 修正
rust/crates/mnote-web/src/hermes_tools/page.rs:mnote.page.update_options对未接线字段返回ignoredOptions与warnings,并只把 wired 字段放入page.layout.updateOptionspayload。 - 扩展单测
hermes_tools_update_options_dry_run_filters_unwired_fields:断言pageFont不进入diff.payload.options,并返回ignoredOptions[0]="pageFont"与warnings[0].code="page_option_not_wired"。 - 验证命令:
cd rust && cargo test -p mnote-web hermes_tools_update_options_dry_run_filters_unwired_fields -- --nocapture:1 passed。 - 验证命令:
cd rust && cargo build -p mnote-web:通过。 - 验证命令:
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-title-options-smoke.js:通过;测试页tree_1778720870666_1,标题TEST-HERMES-AI-title-updated-mp4shbjq。 - smoke 已断言页头标题、breadcrumb/current title、sidebar 树节点标题一致;
data-page-wide-layout=true与data-page-small-text=true生效。 - smoke 已打开页面 AI 面板,确认
data-mnote-page-ai-session-owner=hermes,localStorage 仅保存{"activeSessionId":"mnote_tree_1778720870666_1_page-ai-mp4shbwk"},不保存页面标题。
验收标准:
- 标题修改后页头、breadcrumb、sidebar、刷新后标题一致。
- 页面设置修改只允许 wired 字段。
- AI 面板没有独立标题状态。
J1:补 artifact reference edge 与 projection-only 验收
目标: artifact 工具经 Hermes tool call 与 Rust kernel 创建业务事实,AI Artifacts 只是 projection 分组,不是真实 kernel node。
必须参考 Hermes Web UI 的位置:
| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
|---|---|---|---|
| artifact 工具作为 plugin/tool 暴露 | packages/server/src/services/hermes/plugins.ts |
providesTools 第 200 行;providesHooks 第 201 行;requiresEnv 第 202 行 |
artifact 能力挂到 Hermes plugin,不做 mnote-web 私有按钮直写 |
| artifact 结果仍是 tool event | packages/client/src/api/hermes/chat.ts |
RunEvent 第 28 行;onToolCompleted 第 70 行 |
summary / ai_note 结果作为 tool event 展示 |
| tool result 展示 | packages/client/src/components/hermes/chat/MessageItem.vue |
toolPreview 第 543 行;toolResultPayload 第 332 行;tool-details 第 555 行 |
artifact 结果只展示摘要和详情,不写入正文 |
| 历史 tool message 恢复 | packages/client/src/stores/hermes/chat.ts |
mapHermesMessages 第 125 行;case 'tool.completed' 第 948 / 1378 行 |
刷新后 artifact tool event 仍从 session 恢复 |
| session DB tool 字段 | packages/server/src/db/hermes/session-store.ts |
tool_call_id 第 40 行;tool_calls 第 41 行;tool_name 第 42 行;addMessage 第 331 行 |
tool call id 与 artifact audit 能串联 |
顺序执行 checklist:
- J1.1 扩展
scripts/task-hermes-page-ai-artifact-smoke.js,创建或更新 summary,记录artifactDocumentId。 - J1.2 通过 kernel query 或稳定 projection route 查询 summary 与当前页面之间的 reference edge。
- J1.3 再创建两次 ai_note,断言每次得到独立
artifactDocumentId。 - J1.4 查询每个 ai_note 与当前页面之间的 reference edge,确认
from/to/kind可追踪。 - J1.5 查询
AI Artifacts分组来源,确认它是 projection-only 分组,不是真实 kernel node。 - J1.6 回查 artifact audit,确认包含
sessionId/runId/toolCallId/traceId。
2026-05-14 J1 执行证据:
cargo test -p bridge-runtime ai_artifact -- --nocapture:2 passed。MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-artifact-smoke.js:通过;referenceEdgeCount=6,meta.aiArtifacts.projectionOnly=true,kernelNodeId=null,auditEventCount=6。
验收标准:
- reference edge 可通过 kernel query 或 projection 查询。
AI Artifacts只是 projection-only 分组。- summary 与 ai_note 行为符合既定幂等 / 新建规则。
- artifact 写入 audit 能串到 Hermes tool call。
K1:补 legacy 调用方清点与退场文档
目标: 旧 /api/ai-agent/run 只保留为 legacy guard / 历史说明,不再被活跃设计或页面 AI 主链描述为长期入口。
必须参考 Hermes Web UI 的位置:
| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
|---|---|---|---|
| 新 run 入口 | packages/client/src/api/hermes/chat.ts |
startRunViaSocket 第 432 行 |
对照新页面 AI 主链,不回到旧 /api/ai-agent/run |
| run server 注册 | packages/server/src/routes/hermes/chat-run.ts |
setChatRunServer 第 5 行;getChatRunServer 第 9 行 |
确认 Hermes run server 是真实入口 |
| upstream run 生命周期 | packages/server/src/services/hermes/chat-run-socket.ts |
handleRun 第 488 行;markCompleted 第 1276 行 |
长期主链是 Hermes upstream run |
| plugin 发现 | packages/server/src/services/hermes/plugins.ts |
listHermesPlugins 第 310 行 |
旧入口退场后,mnote 能力从 Hermes plugin/tool 面进入 |
顺序执行 checklist:
- K1.1 运行
rg -n "/api/ai-agent/run|provider=hermes|mnote-cli host|CLI-first" design rust wolai-frontend scripts --glob '*.md' --glob '*.rs' --glob '*.ts' --glob '*.tsx' --glob '*.js'。 - K1.2 将命中逐项归类为:
历史证据、legacy guard、仍需迁移、误导性活跃口径。 - K1.3 对
仍需迁移的代码调用方补迁移或补退场 guard。 - K1.4 对
误导性活跃口径的设计稿改写为“历史/兼容/已覆盖”,必要时移入design/old/并标[recycle]。 - K1.5 更新旧 smoke:不再期待
/api/ai-agent/run -> mnote-cli成功,只验证 legacy guard 返回稳定退场码。 - K1.6 在本 checklist 回填 rg 输出摘要和修改文件清单。
2026-05-14 K1 执行证据:
- rg 命中已归类:
design/old/**与design/07-ai/done/7-1**为历史证据;scripts/task-hermes-page-ai-retirement-guard.js与rust/crates/mnote-web/src/routes/compat.rs为 legacy guard;旧 E27/phase7/page-ai smoke 已默认退役;wolai-frontend中 Mindmap / OnlyOffice / generic AI 面板调用点归为非当前页面 AI 主链的 legacy domain 调用点,后续按各自 domain 迁移。 - 修改文件:
rust/crates/mnote-web/src/routes/compat.rs、scripts/task-hermes-page-ai-retirement-guard.js、历史退役 smoke 当前本机归档于 gitignoredrecycle/scripts/retired-ai-agent-run-smokes/、design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md、design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md、design/10-review/04-secondary-domains-and-design-governance-review.md。 - 旧 smoke 默认退役验证:上述 6 个历史 smoke 均返回
{ ok: true, retired: true }。
验收标准:
- 活跃设计稿不再把
/api/ai-agent/run描述为页面 AI 长期入口。 - legacy 调用方清单为空,或每一项都有明确退场说明。
- 旧入口不会静默 fallback 到 Hermes、Codex 或旧 orchestrator。
L1:把审计从进程内缓存收口到持久化可追踪链
目标: 每次 Hermes 调用 mnote 工具都能从页面 AI 请求串到 Hermes run、mnote tool call、Rust command 和最终业务结果。
必须参考 Hermes Web UI 的位置:
| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
|---|---|---|---|
| 前端事件字段 | packages/client/src/api/hermes/chat.ts |
RunEvent 第 28 行,重点看 run_id、session_id、tool、name |
前端事件字段要能和审计字段串联 |
| run / tool / session 追踪 | packages/server/src/services/hermes/chat-run-socket.ts |
emit 第 574 / 963 行;applyResponseStreamEvent 第 1035 行;flushResponseRunToDb 第 1207 行;markCompleted 第 1276 行 |
对齐 run、tool、session 三段追踪模型 |
| tool call 持久字段 | packages/server/src/db/hermes/session-store.ts |
tool_call_id 第 40 行;tool_calls 第 41 行;tool_name 第 42 行;addMessage 第 331 行 |
mnote audit 至少能关联 Hermes tool call id |
| usage 不进页面事实 | packages/server/src/db/hermes/usage-store.ts |
recordUsage 第 16 行;getUsage 第 53 行;getUsageBatch 第 73 行;deleteUsage 第 118 行 |
usage/model 是 Hermes 真相,不写入 mnote page aggregate |
顺序执行 checklist:
- L1.1 定义持久化审计落点:复用现有 audit/event log,或新增最小
mnote_hermes_tool_audit存储;不得只依赖进程内缓存。 - L1.2 审计字段固定包含
traceId/sessionId/runId/toolCallId/documentId/workspaceId/actorId/toolName/effect/commandId/errorCode。 - L1.3 在 tool call start / success / failure 三个阶段写入同一条可查询链。
- L1.4 更新
scripts/task-hermes-page-ai-audit-smoke.js,重启进程或绕过进程内缓存后仍能按traceId回查审计。 - L1.5 权限失败场景必须断言审计里没有完整正文、无权限页面标题或 block 原文。
- L1.6 写工具成功场景必须断言审计能追踪到最终 Rust command id。
2026-05-14 L1 执行证据:
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-audit-smoke.js:通过,persistedOnly=true查询确认持久化审计可按 traceId 回查。- 权限失败审计:
deniedPersistedPhases=["started","failed"],smoke 已断言持久化 audit 不含正文 marker 与页面标题。
验收标准:
- 每个 tool call 都能追踪到 session、run、toolCall 和最终业务结果。
- 失败不泄露内容。
- 审计不是只存在于进程内缓存。
M1:把正式 3000 的 E2E smoke 跑成最终验收矩阵
目标: 临时 3019 证据不能作为最终完成;必须在正式 3000 + 真实 SQLite control-plane Auth / session 上复跑全矩阵。历史记录中的 Convex Auth 只作为当时验收背景。
必须参考 Hermes Web UI 的位置:
| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
|---|---|---|---|
| run / resume / abort 客户端入口 | packages/client/src/api/hermes/chat.ts |
startRunViaSocket 第 432 行;resumeSession 第 420 行;registerSessionHandlers 第 297 行 |
作为 E2E smoke 的网络断言依据 |
| session detail | packages/client/src/api/hermes/sessions.ts |
SessionSummary 第 3 行;HermesMessage 第 36 行;fetchSessions 第 50 行;fetchSession 第 81 行 |
刷新恢复 smoke 必须断言 session detail |
| run 生命周期 | packages/server/src/services/hermes/chat-run-socket.ts |
resumeSession 第 427 行;handleRun 第 488 行;markCompleted 第 1276 行 |
正式 3000 上断言 run 生命周期完整 |
| 面板组件边界 | packages/client/src/components/hermes/chat/ChatPanel.vue |
SessionListItem import 第 22 行、使用第 598 / 636 行;MessageList 第 790 行;ChatInput 第 791 行 |
只对齐页面 AI 抽屉需要的子集 |
顺序执行 checklist:
- M1.1 确认主入口
http://127.0.0.1:3000运行的是包含本轮改动的mnote-web,不是旧进程。 - M1.2 使用默认 SQLite control-plane 测试账号
mnote.e2e@example.com登录,不使用MNOTE_DEV_AUTH=1伪登录作为正式验收;旧 Convex Auth 仅作 compat 回归。 - M1.3 运行
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-smoke.js。 - M1.4 运行
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-smoke.js。 - M1.5 运行
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-writeback-smoke.js。 - M1.6 运行
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-title-options-smoke.js。 - M1.7 运行
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-artifact-smoke.js。 - M1.8 运行
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-retirement-guard.js。 - M1.9 运行
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-mobile-smoke.js。 - M1.10 运行
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-audit-smoke.js。 - M1.11 确认 smoke 只操作本轮新建测试数据,统一前缀
TEST-HERMES-AI-<timestamp>。 - M1.12 任一 smoke 失败时,把失败写入
bugs/07-ai/process/或真实 owner 分类,不在 checklist 里标 GREEN。
验收标准:
- 所有 smoke 在正式
3000通过。 - 可以定位每次 smoke 生成的页面、artifact、edge 和 audit。
- 任一 smoke 失败都会落到
bugs/,不会在 checklist 中假装通过。
N1:把活跃设计口径和 old 目录治理收口
目标: 设计目录与真实主线一致:页面 AI 是 Hermes 面板,mnote 通过 Hermes skill/plugin 被调用,旧 CLI-first 口径只保留为历史。
必须参考的本仓设计文件:
| 参考目的 | 具体文件 | 具体位置 / 搜索点 | 处理方式 |
|---|---|---|---|
| Page Aggregate 口径 | design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md |
搜索 /api/ai-agent/run、mnote-cli host、页面 AI |
改成历史残留 / 已覆盖 / 待迁移证据,不写成长期主线 |
| Wolai-aline 过渡基线 | design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md |
搜索 E27、mnote-cli、页面 AI |
保留为对标基线时必须标明过渡状态 |
| 二级域 review 建议 | design/10-review/04-secondary-domains-and-design-governance-review.md |
搜索 Hermes、plugin、mnote-cli、CLI-first |
指向 Hermes plugin / Rust bridge 的当前口径 |
| 07-ai 历史稿 | design/old/07-ai/process/ |
搜索 CLI-first、mnote-cli |
继续标 [recycle],不迁回活跃 process |
顺序执行 checklist:
- N1.1 运行
rg -n "mnote-cli.*唯一|唯一长期 agent|CLI-first|/api/ai-agent/run|provider=hermes" design --glob '*.md'。 - N1.2 把命中分为
design/old历史命中、活跃历史说明、活跃误导口径三类。 - N1.3 修改
5-6、5-9、10-review中仍残留的旧 CLI-first 说法,使其明确为历史/兼容/已覆盖。 - N1.4 确认
design/old/07-ai/process/中历史稿继续标[recycle]。 - N1.5 7-4 全部验收标准已满足,本文已按 design 归档规则移动到
design/07-ai/done/;新的活跃执行清单改由7-7承接。 - N1.6 回填最终 rg 输出摘要和 design 文件迁移清单。
2026-05-14 N1 执行证据:
rg -n "mnote-cli.*唯一|唯一长期 agent|CLI-first|/api/ai-agent/run|provider=hermes" design --glob '*.md'已跑完,活跃命中已逐项归类。- 活跃命中主要落在
design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md、design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md、design/10-review/04-secondary-domains-and-design-governance-review.md、design/10-review/06-execution-checklist-and-acceptance.md、design/01-tree-first-graph-kernel/reference/1-1-tree-first-graph-kernel-checklist-v2.md、design/03-rust-web/reference/3-1-rust-web-long-term-checklist-v2.md、design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md、design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md、design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md、design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md。 design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md与同目录旧稿继续保留[recycle],只作为历史证据。- 本轮对
5-6、5-9、10-review/04、10-review/06、1-1、3-1的旧口径改写已完成;活跃文档现已统一为 Hermes 页面内客户端 + mnote Hermes plugin/tool 口径。 - 本文件仍保留在
process/,原因是它是执行清单而不是代码实现文件;若后续需要归档,可按N1.5的规则移动并同步更新引用。
验收标准:
- 活跃目录的旧 CLI-first 命中都带有历史/回收/已覆盖说明。
design/old/07-ai/process/保持历史记录定位。- 未完成能力不会被提前标 done。
17. 推荐执行顺序总表
| 顺序 | Task | 目标 | 退出门槛 |
|---|---|---|---|
| 1 | A | 固定旧链与 502 基线 | 有可复跑证据 |
| 2 | B | 冻结 Hermes client proxy 合同 | route 输入输出示例齐全 |
| 3 | C | 实现 Hermes client proxy 只读链 | session/run 可代理 |
| 4 | D | 冻结 mnote plugin tool 合同 | 第一批 tool schema 齐全 |
| 5 | E | 实现 manifest + mnote.page.get |
Hermes 可读当前页 |
| 6 | F | 实现 Leptos Hermes 面板 | 页面 AI 不再请求旧 run route |
| 7 | G | 展示 tool event | tool started/completed 可刷新恢复 |
| 8 | H | 正文写入工具 | page.body.save 闭环 |
| 9 | I | 标题与页面设置工具 | 标题/设置走 Page Aggregate |
| 10 | J | artifact 工具 | summary / ai_note / reference edge 闭环 |
| 11 | K | 退役旧主链 | 旧 route 不再承载页面 AI 主路径 |
| 12 | L | 审计与可观测性 | tool call 到 Rust command 可追踪 |
| 13 | M | 端到端验收矩阵 | 全 smoke 通过 |
| 14 | N | 文档治理回填 | design 口径无旧主线残留 |
18. 最终完成定义
只有同时满足以下条件,才能宣布本 checklist 完成:
- Hermes session 是页面 AI 会话真相。
- mnote 只保存业务事实和审计,不保存聊天真相。
- 页面 AI 面板是 Leptos Hermes client,不是
mnote-cli面板。 - mnote Hermes plugin 至少覆盖读取当前页、写正文、改标题/设置、创建 summary、创建 ai_note。
- 所有写入经 Rust runtime / kernel。
- 旧
/api/ai-agent/run不再是页面 AI 主入口。 - E2E smoke 覆盖只读、写入、artifact、刷新恢复、旧链退役;正式
http://127.0.0.1:3000已复跑 8 个 smoke,见 Task M。 - 活跃设计文档和执行清单一致;旧 CLI-first /
/api/ai-agent/run命中均已标为历史、兼容、已覆盖或 legacy guard。
18.1 最终完成审计记录
2026-05-14 最终复核按“完成定义 -> 真实证据”逐项检查,不只依赖本文勾选状态。
- 运行态入口存在:
ss -ltnp | rg ':3000\b|:8642\b'确认mnote-web监听0.0.0.0:3000,Hermes API server 监听127.0.0.1:8642。 - Rust tool / client / legacy guard 测试通过:
cargo test -p bridge-runtime ai_artifact -- --nocapture:2 passed。cargo test -p mnote-web hermes_client -- --nocapture:4 passed。cargo test -p mnote-web hermes_tools_ -- --nocapture:9 passed。cargo test -p mnote-web ai_agent_run -- --nocapture:1 passed。cargo test -p mnote-web explicit_ -- --nocapture:2 passed。cargo build -p mnote-web:通过。
- Hermes plugin/toolset 可见:
hermes plugins list:mnote为 enabled user plugin。hermes tools list --platform api_server:Plugin toolsets 中mnote为 enabled。/home/lix/.hermes/plugins/mnote/plugin.yaml声明mnote_page_get、mnote_page_save、mnote_page_update_title、mnote_page_update_options、mnote_artifact_create_summary、mnote_artifact_create_ai_note。
- 正式
3000smoke 全矩阵通过:task-hermes-page-ai-smoke.js:tree_1778724401995_17,sessionmnote_smoke_mp4ul0c2,runrun_smoke_mp4ul0c2,sessionDetailHits=2。task-hermes-page-ai-tool-smoke.js:tree_1778724413742_19,mnote.page.get返回标题TEST-HERMES-AI-tool-mp4ul9ei。task-hermes-page-ai-writeback-smoke.js:tree_1778724445965_21,page.body.save,commandpage_body_save_req_1778724446747_1371。task-hermes-page-ai-title-options-smoke.js:tree_1778724480369_23,page.head.updateTitle与page.layout.updateOptions通过,pageFont返回page_option_not_wired。task-hermes-page-ai-artifact-smoke.js:tree_1778724511207_25,summary / ai_note 都走tree.node.create,referenceEdgeCount=6,projectionOnly=true。task-hermes-page-ai-retirement-guard.js:旧入口返回410 legacy_ai_agent_run_retired。task-hermes-page-ai-mobile-smoke.js:390pxviewport 下 drawer / panel 未横向溢出。task-hermes-page-ai-audit-smoke.js:tree_1778724538669_29,写命令page_body_save_req_1778724538893_1707,持久化 audit 覆盖started/completed与权限失败started/failed。
- 真实 Hermes upstream session 补充验证:页面 AI 不拦截 Hermes 请求时触发真实 run,
hermes sessions export --session-id mnote_tree_1778724800891_37_page-ai-mp4utko0 -显示message_count=4、tool_call_count=1、api_call_count=2、has_mnote_page_get=true。 - 文档治理检查通过:
rg -n "mnote-cli.*唯一|唯一长期 agent|CLI-first|/api/ai-agent/run|provider=hermes" design --glob '*.md'的活跃命中均为历史、兼容、已覆盖、禁止项或 legacy guard 说明。git diff --check覆盖本轮已跟踪设计稿,无空白错误。rg -n "[ \t]+$"覆盖本轮设计稿,无尾随空白。