重构基线

This commit is contained in:
Agent Board
2026-06-25 21:08:17 +08:00
parent cc4f975466
commit dabaf03bd7
42 changed files with 7720 additions and 138 deletions
@@ -0,0 +1,439 @@
# 7-62 [recycle] Page AI Board-first full rewrite v1
> 创建时间:2026-06-19
>
> 当前状态:`RECYCLE`
>
> Owner07-ai / Agent Board bridge / Page AI shell / MNote capability plugins
>
> 上位依据:
> - `ARCHITECTURE.md`
> - `CURRENT_ARCHITECTURE.md`
> - `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
> - `design/07-ai/done/7-38-page-ai-sidebar-runtime-owner-split-v1.md`
> - `design/07-ai/done/7-39-page-ai-agent-selector-context-authorization-settings-v1.md`
> - `design/07-ai/done/7-40-page-ai-context-envelope-and-run-receipt-v1.md`
> - `design/07-ai/done/7-50-lightrag-knowledge-rag-provider-v1.md`
> - `design/07-ai/done/7-60-page-ai-settings-ia-cleanup-v1.md`
> 过时原因:已由 `design/07-ai/process/7-65-opencode-webui-embed-page-ai-v1.md` 替代;Page AI 新主路径只接入 opencode 官方 runtime + 官方 WebUI。
## 1. 第一结论
当前 Page AI 继续维护 Hermes / Reasonix / Chat-only / ACP runtime / provider session / skill toggle / tool event 映射,会让 MNote 重复承担 Agent Board 已经承担的中介层职责。后续不应再“小修小补”当前 Page AI,而应完整重构为 **Board-first Page AI**
```text
MNote Page AI = 页面入口 + 上下文/权限/目标封装 + 运行态展示
Agent Board = worker 选择 + provider 适配 + workflow 编排 + QA/review/失败回流
ZCode/Reasonix/Codex/GenericAgent = Board worker,不直接成为 MNote Page AI provider
```
重构目标不是“把 ZCode 接进 Page AI”,而是“让 Page AI 不再适配 provider”。ZCode 胜出只决定 Board 默认 workerMNote 只调用 Board。
## 2. 当前问题
### 2.1 Page AI 责任过载
当前 Page AI 同时负责:
- agent/provider selectorHermes / Reasonix / Chat-only。
- ACP runtime lifecyclesession、resume、queue、event、permission。
- provider 特化逻辑:Reasonix native-live、Hermes profile、Chat-only remote conversation。
- skills/tools UIMNote skills、Hermes skills、Reasonix skills 混合展示。
- run historyMNote 本地 session、外部 provider conversation、runtime audit 混合展示。
- 写入主路径:既有 MNote tool 写入,又有 agent 原生文件编辑。
这导致每新增一个 agent 或 provider 都要重复改 Page AI 前端、Rust route、session store、event parser、设置页和 smoke。
### 2.2 与 Agent Board 职责重复
Agent Board 已经具备:
- worker preset 与角色路由。
- ZCode / Reasonix / Codex / GenericAgent / reviewer / QA browser worker。
- workflow run、task group、review、QA、git gate。
- provider event 映射、任务状态、summary、MemPalace 归档。
- ZCode app-server / CLI fallback 链路。
MNote 再维护一套 provider 层会形成双中介,长期 bug 面大于收益。
## 3. 新系统边界
### 3.1 MNote Page AI 只保留四件事
1. **上下文采集**:当前页、选区、打开资源、页面标题、rootUri、workspaceId、sourceKind、Page Aggregate snapshot。
2. **权限与目标**allowed roots、write/read policy、当前目标文件、是否允许修改真实文件。
3. **任务入口**:选择 worker / workflow / intent,提交 Board run。
4. **可视化回放**:展示 Board run/task/group 状态、事件、summary、文件变更提示、QA 截图链接。
### 3.2 Agent Board 承担中介层
Board 负责:
- provider 适配:ZCode / Reasonix / Codex / future agents。
- worker 选择:developer / reviewer / qa / designer / researcher / workflow。
- workflow:快速编辑、问答、bug 修复、功能开发、QA 验证、review gate。
- run 状态:running / blocked / failed / complete。
- 事件:file_read / file_edit / command / command_output / screenshot / summary。
- 失败回流与人工介入。
### 3.3 MNote skills / plugins 重新定义
MNote 的 skill/plugin 不再是 “Hermes/Reasonix profile 内的技能开关”,而是 Board 可消费的 **MNote capability manifest**
```text
mnote.current_page.read
mnote.selection.read
mnote.open_resources.snapshot
mnote.allowed_roots.describe
mnote.lightrag.query
mnote.reference.open
mnote.page_aggregate.snapshot
mnote.local_file.receipt
```
这些 capability 由 MNote 生成 manifest/envelopeBoard worker 通过任务 prompt、MCP 或后续 bridge tool 使用。MNote 不再为每个 worker 维护单独 skill UI。
## 4. 新 Page AI 信息架构
### 4.1 顶层只保留四个页签
| 页签 | 作用 | Owner |
| --- | --- | --- |
| `对话/任务` | 用户输入、当前目标、提交 Board run | MNote |
| `工作流` | worker / workflow 选择、执行策略 | Agent Board |
| `运行` | Board run/task/group 状态、事件、summary | Agent Board |
| `上下文` | 当前页、选区、资源、权限、LightRAG capability | MNote |
删除旧一级页签:
- `Hermes`
- `Reasonix`
- `Chat-only`
- `Runtime`
- `高级`
- provider-specific skills 面板
如确需保留,只能放在 debug/legacy 折叠区,不作为默认主链。
### 4.2 默认入口
默认按钮不再是“发送给 Reasonix/Hermes”,而是:
```text
交给 Agent Board
```
默认配置:
```text
projectId = mnote 项目
workflow = builtin-page-ai-developer-direct
worker = Board direct workflow developer(现为 zcode-deepseek-flash
writePolicy = 按 MNote allowed roots
```
## 5. 接口契约
### 5.1 MNote → Board envelope
新增 `MNoteBoardTaskEnvelope`
```json
{
"schema": "mnote.page_ai.board_task.v1",
"intent": "ask|edit|fix|feature|qa|review|custom_workflow",
"message": "用户原始输入",
"workspaceId": "...",
"sourceKind": "local-folder",
"rootUri": "file:///...",
"documentId": "...",
"pageTitle": "...",
"primaryTarget": {
"kind": "markdown_file",
"relativePath": "docs/page.md",
"absolutePath": "/.../docs/page.md"
},
"selection": {
"text": "...",
"range": null
},
"contextRefs": ["current_page", "selection", "active_editor", "folder"],
"allowedRoots": [
{ "rootUri": "file:///...", "permission": "write" }
],
"capabilities": [
"mnote.current_page.read",
"mnote.allowed_roots.describe",
"mnote.lightrag.query"
],
"writePolicy": {
"allowFileWrite": true,
"requireHumanApproval": false,
"forbidMnoteInternalStateWrite": true
}
}
```
### 5.2 Board API 选择
MNote 服务端先封装 Board API,不让前端直连 `3901`
新增 MNote routes
```text
GET /api/page-ai/board/status
GET /api/page-ai/board/workers
GET /api/page-ai/board/workflows
POST /api/page-ai/board/runs
GET /api/page-ai/board/runs/:id
POST /api/page-ai/board/runs/:id/cancel
```
内部对应 Board
```text
GET http://127.0.0.1:3901/api/health
GET http://127.0.0.1:3901/api/workers/catalog?projectId=<mnote>
GET http://127.0.0.1:3901/api/workflow-presets?projectId=<mnote>
POST http://127.0.0.1:3901/api/workflow-runs
GET http://127.0.0.1:3901/api/workflow-runs/:id
```
优先使用 `/api/workflow-runs`,而不是 `/api/controller/message`,因为 Page AI 需要可预测的 workflow/worker 选择和 run id。
### 5.4 Board 需要补给 MNote 的接口
这不是单向的“ MNote 适配 Board ”,而是双向协议。为了让 Page AI 真正瘦身,Board 侧还需要补出一组面向 MNote 的稳定接口:
#### A. Page AI envelope 预检
```text
POST /api/page-ai/envelopes/validate
```
作用:在真正创建 run 前,校验 envelope 是否满足 workflow/worker 的最小要求,返回:
- 缺失的字段。
- 是否需要 worker 具备 vision / browser / filesystem / multimodal。
- 是否需要人工确认。
- 推荐 workflowId / workerPresetId。
这样 MNote 可以在 UI 层先提示“当前上下文不够”或“建议切换到 QA workflow”,避免无效提交。
#### B. Page AI envelope 到 workflow 的映射
```text
POST /api/page-ai/envelopes/route
```
作用:Board 根据 envelope 自动选择 workflow / worker / reviewer / QA 路线,返回最终路由结果:
- workflowId。
- workerPresetId。
- groupId 或 runId。
- 是否需要用户二次确认。
- 预估阶段序列。
这能让 MNote 不再内置 worker 选择逻辑,只保留“意图 + 上下文”。
#### C. Run 级事件流
```text
GET /api/workflow-runs/:id/events
GET /api/workflow-runs/:id/node-runs/:nodeRunId/events
```
作用:MNote 不只看最终 run summary,而是直接消费 Board 的结构化事件流,渲染:
- 当前节点。
- 进度阶段。
- file_read / file_edit / command / screenshot / artifact。
- block / retry / resume 原因。
如果 Board 未来提供 WS/SSE,这两条可退化为 snapshot/polling 兼容层,但 MNote 默认应面向事件流抽象,而不是 provider 私有日志。
#### D. Run receipt / artifact receipt
```text
GET /api/workflow-runs/:id/receipt
```
作用:返回统一的运行收据,便于 MNote 做历史展示和刷新同步:
- `runId` / `projectId` / `workflowId`
- `workerPresetId` / `workerName`
- `summary` / `status` / `completedAt`
- `artifactRefs`
- `targetSnapshot` / `allowedRoots` / `capabilities`
这会让 Page AI history 直接依赖 Board receipt,而不是再保留一套 Hermes session 语义。
#### E. Board 侧能力目录
```text
GET /api/workers/catalog?projectId=<mnote>
GET /api/workflow-presets?projectId=<mnote>
GET /api/projects/:id/capabilities
```
作用:让 MNote 能展示“Board 当前能做什么”,而不是自己猜 worker。尤其是:
- 默认 developer 是谁。
- 哪些 worker 具备 vision/browser。
- 哪些 workflow 可用于编辑、QA、review、research。
#### F. Board 侧回写钩子
```text
POST /api/workflow-runs/:id/report
POST /api/workflow-runs/:id/artifacts
POST /api/workflow-runs/:id/feedback
```
作用:让 MNote 能把 UI 侧额外信息回写给 Board:
- 浏览器截图。
- 用户补充说明。
- 失败后的重新定界信息。
- 页面刷新后的 targetSnapshot 变化。
这样 Board 的 workflow 才能逐步成为真正的 Page AI 控制面,而不是一次性任务提交器。
### 5.5 Board → MNote 展示模型
MNote 只归一化 Board 状态,不解析 provider 私有事件:
```text
Board run -> Page AI run card
Workflow node -> stage timeline
Task event -> visible event row
Task summary -> assistant final message
Artifact refs -> screenshot/link/file changed chips
```
MNote 不再关心事件来自 ZCode、Reasonix 还是 Codex。
## 6. 删除与迁移边界
### 6.1 默认主链删除
以下能力退出默认主链:
- Page AI 前端 `pageAiAcpRuntime` 作为主选择器。
- Reasonix quick controls 作为默认控件。
- Hermes profile select 作为默认控件。
- Chat-only provider conversation 作为默认路径。
- MNote 内部 provider-specific run resume。
- provider-specific skill source 切换。
### 6.2 Legacy 保留原则
旧链路只允许:
- debug/internal route。
- 历史 session 读取/导出。
- 明确 fallback:Board 不可用时提示用户,而不是自动静默切回 Reasonix。
不允许:
- 新功能继续写进 `sidebar-page-ai-runtime.js` 的 provider 分支。
- 新增 Hermes/Reasonix 专属 UI 作为默认交互。
- 新增 MNote 自己的 provider adapter。
## 7. 实施计划
### Phase ABoard bridge 与新 shell 并行上线(已完成)
- [x] 新增 `page_ai_board.rs`,封装 Board status/workers/workflows/runs。
- [x] 前端默认路径已切为 Board-first run 提交和状态展示;当前以 `sidebar-page-ai-runtime.js` 内 Board-first 分支承接,后续可继续拆到独立 runtime 文件。
- [x] Board 侧补齐 `envelopes/validate``envelopes/route``runs/:id/events``runs/:id/receipt``projects/:id/capabilities` 稳定接口。
- [x] 当前 Page AI 默认入口切到 Board shell。
- [x] 旧 provider 入口默认隐藏,仅通过 legacy/debug 边界保留。
- [x] smoke:从页面提交任务,Board 创建 workflow runPage AI 能显示 run id、complete、summary。
### Phase Bworker / workflow 选择(已完成默认链路)
- [x] MNote bridge 提供 Board workers/workflows catalog API,默认 UI 先收口为 Board direct workflow。
- [x] 默认选中 Board direct workflow developer`zcode-deepseek-flash`
- [ ] 后续增强:在工作流页开放更多 built-in workflow 选择。
- [x] smokeZCode developer 执行最小文件编辑任务,MNote 页面通过 watcher 刷新。
### Phase CMNote capability manifest(已完成默认 envelope
- [x] 定义并随 `mnote.page_ai.board_task.v1` envelope 下发 MNote capabilities。
- [x] 把当前页/选区/allowed roots/LightRAG/source registry 统一注入 Board input。
- [x] 默认路径收口为 capability manifest;旧 provider skill 面板隐藏为 legacy/debug。
- [x] smokeBoard worker 能看到 primary target 与 allowed roots,并只在授权目录内改文件。
### Phase D:事件与 artifact 回放(后续增强)
- [ ] Page AI 展示 Board node timeline。
- [ ] 展示 task eventsfile read/edit、command、command output、QA screenshot。
- [ ] 支持打开 Board project/run/task 链接。
- [ ] smoke:功能开发 workflow 完成后,Page AI 能看到 QA 截图 artifact 和 final summary。
### Phase E:旧链路下线(默认主链已下线,代码删除后续)
- [x] 默认 UI 隐藏 Hermes/Reasonix/Chat-only provider 入口,Board-first shell 成为默认主链。
- [ ] 后续清理:`hermes_client.rs` 中 Page AI provider-specific run 创建逻辑迁入 legacy/debug 边界。
- [ ] 后续清理:更新旧设计归档默认主链说明为 legacy。
- [x] smoke:默认 Page AI Board-first 代码路径不再依赖 Reasonix/Hermes provider 即可运行。
## 8. 验收标准
### 8.1 功能验收
- Page AI 默认提交创建 Board workflow run。
- 默认 worker 来自 Board,而不是 MNote 写死 Reasonix/Hermes。
- ZCode 作为 Board 默认 developer 时,Page AI 不需要任何 ZCode 专属代码即可使用。
- Board 不可用时,Page AI 明确显示“Agent Board 不可用”,不伪装为 provider 失败。
- 文件写入通过真实文件编辑完成,MNote watcher/Page Aggregate 刷新页面。
### 8.2 维护性验收
- 新 provider 只需要 Agent Board 适配,不改 MNote Page AI provider 分支。
- Page AI 前端默认路径不再包含 `reasonix/hermes/chat_only` 三套选择逻辑。
- MNote skills/plugins 只表达能力,不表达 provider。
- Rust route 中 Board bridge 与 Hermes legacy route 分离。
### 8.3 浏览器 smoke
- 登录 `http://localhost:3000/auth` 测试账号。
- 打开 local-folder Markdown 页面。
- 打开 Page AI。
- 选择默认 Board workflow。
- 提交“总结当前页并提出一个最小改进建议”。
- 页面显示 Board run id、worker、阶段、最终 summary。
- 再提交“在当前文件末尾追加一行测试内容”,确认真实 `.md` 文件变化,页面刷新可见。
## 9. 风险与处理
| 风险 | 处理 |
| --- | --- |
| Board 服务不可用 | Page AI 显示 Board health 错误与启动提示,不自动回退旧 provider |
| Board workflow 太重 | 默认使用 minimal workflow,完整 QA workflow 由用户选择 |
| Page AI 历史 session 断裂 | 旧 session 只读保留,新增 run 以 Board run 为历史主键 |
| Board 改文件后页面不同步 | 依赖现有 watcher/Page Aggregate;缺口作为 05-editor-mainline bug 处理 |
| MNote capability 被 worker 忽略 | Board prompt/template 中明确 envelope schema 与 allowed roots,后续再补 MCP bridge |
## 10. 立即决策
本稿确认后,后续实现不再以“接入 ZCode provider”为任务拆分,而以“Page AI Board-first full rewrite”为主线拆分。第一批代码应直接新增 Board bridge 和新 Page AI shell,而不是继续在旧 `sidebar-page-ai-runtime.js` 中叠加 provider 分支。
## 11. 完成记录(2026-06-19
- MNote 新增 `/api/page-ai/board/*` bridge,浏览器不直连 Board `3901`
- Agent Board 新增 Page AI envelope validate/route/events/receipt/capabilities 接口,并新增 `builtin-page-ai-developer-direct` workflow。
- Page AI 默认发送 `mnote.page_ai.board_task.v1` envelope,默认 workflow 为 `builtin-page-ai-developer-direct`worker 为 ZCode developer。
- MNote capability 默认随 envelope 下发:`mnote.current_page.read``mnote.selection.read``mnote.open_resources.snapshot``mnote.allowed_roots.describe``mnote.lightrag.query``mnote.reference.open``mnote.page_aggregate.snapshot``mnote.local_file.receipt`
- 浏览器 smoke `scripts/task762-page-ai-board-first-smoke.js` 已验证:Page AI 可创建 Board run、可见 shell 显示 Agent Board、capability 已加载、ZCode 真实编辑当前 Markdown 文件、磁盘与编辑器可见内容同步。
验证命令:
```bash
cd /mnt/Data1T/mnote/rust && cargo check -p mnote-web
cd /mnt/Data1T/ai-agent-board && npm run build:server
cd /mnt/Data1T/mnote && node scripts/task762-page-ai-board-first-smoke.js
```
@@ -0,0 +1,403 @@
# 7-63 [recycle] Page AI Board-first product shell v1
> 创建时间:2026-06-20
>
> 当前状态:`RECYCLE`
>
> Owner07-ai / Page AI product shell / Agent Board MNote runtime / session history
>
> 上位依据:
> - `design/07-ai/done/7-62-page-ai-board-first-full-rewrite-v1.md`
> - `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
> - `design/07-ai/done/7-38-page-ai-sidebar-runtime-owner-split-v1.md`
> - `design/07-ai/done/7-40-page-ai-context-envelope-and-run-receipt-v1.md`
> - `design/07-ai/done/7-60-page-ai-settings-ia-cleanup-v1.md`
> 过时原因:已由 `design/07-ai/process/7-65-opencode-webui-embed-page-ai-v1.md` 替代;Page AI 新主路径只接入 opencode 官方 runtime + 官方 WebUI。
## 1. 当前结论
7-62 已经证明 Board-first 主链能跑:MNote Page AI 可以通过 Agent Board 创建 run,可以把 MNote capability/envelope 下发给 worker`mnote-page-ai-zcode` 能回复,也能真实编辑当前 Markdown 文件并触发编辑器刷新。
但这还不是合格的页面 AI。当前问题不是“再给用户更多 Board 选择”,而是 **MNote 页面 AI 需要自己的产品壳**
```text
MNote Page AI Product Shell
= 聊天体验 + 当前页上下文 + MNote 白名单 worker/workflow + worker 内模型选择 + session/history + run detail
Agent Board MNote Runtime
= MNote 专用 worker + MNote 专用 workflow + provider/model 执行 + receipt/event 持久化
```
Page AI 不是 Agent Board 控制台的缩小版。默认 UI 不应该暴露 Board 全量 worker、全量 workflow、provider adapter 或通用任务报告。用户只需要面对少量 MNote 语义清楚的选择。
## 2. 要解决的四个问题
### 2.1 Worker 怎么选
Page AI 只能选择 MNote Page AI 白名单 worker。当前默认只有:
```text
workerPresetId = mnote-page-ai-zcode
name = MNote 页面 AI · ZCode
surface = mnote-page-ai
capabilities = text, repo-edit, terminal, mnote-capability-envelope, local-markdown-edit
```
不暴露 Board 全量 worker catalog。Reasonix、Codex、ZCode、QA worker 都是 Board 内部 worker 类型,不直接成为 MNote 页面用户的选择项。后续如果需要新增 worker,必须在代码中显式登记为 `surface=mnote-page-ai`,同时补齐:
- 用户可见名称。
- 适合场景。
- 允许模型档位。
- 权限能力。
- smoke 验收。
当白名单只有一个 worker 时,UI 不显示“可切换 worker”的伪入口,只显示当前 worker 和模型档位。
### 2.2 模型怎么改
模型选择挂在特定 MNote worker 下,不做 provider picker
```text
workerPresetId = mnote-page-ai-zcode
modelOverride = zcode-default | zcode-fast | zcode-strong
```
UI 展示为 worker chip 旁的 model chip,例如:
```text
MNote 页面 AI · ZCode / 默认
```
用户可以切换模型档位,但不能直接选择 provider。MNote 不重新维护 Hermes/Reasonix/Codex/ZCode provider adapterprovider 和 credential 仍归 Board。
### 2.3 Workflow 怎么选
Page AI 只能选择 MNote Page AI 白名单 workflow。当前默认只有:
```text
workflowId = builtin-mnote-page-ai-chat
name = MNote 页面 AI
surface = mnote-page-ai
```
该 workflow 覆盖默认聊天、当前页轻编辑、当前页总结、当前页问答。通用 Board workflow 不出现在 Page AI picker 中。
后续确实需要时,再通过代码加入特定 MNote workflow
| Workflow | 加入条件 | 默认 UI |
| --- | --- | --- |
| `builtin-mnote-page-ai-chat` | 已有默认主链 | 默认启用 |
| `builtin-mnote-page-ai-edit` | 需要更明确的编辑阶段和 diff/receipt | 加入白名单后显示 |
| `builtin-mnote-page-ai-review` | 需要当前页审阅、总结、检查 | 加入白名单后显示 |
复杂开发、hotfix、QA/browser workflow 不作为默认页面 AI 能力。只有当它们被改造成 MNote 专用 workflow,并明确加入白名单后,才允许显示。
### 2.4 Session 怎么选、怎么看历史
Page AI session 迁移为 Board-first session。每条 assistant 消息必须知道它来自哪个 Board run,但主聊天只显示用户需要的回答。
```json
{
"schema": "mnote.page_ai.session.v2",
"sessionId": "...",
"workspaceId": "...",
"documentId": "...",
"rootUri": "file:///...",
"messages": [
{ "role": "user", "content": "hi,收到请回复收到。" },
{
"role": "assistant",
"content": "收到。",
"boardRunId": "...",
"workflowId": "builtin-mnote-page-ai-chat",
"workerPresetId": "mnote-page-ai-zcode",
"modelOverride": "zcode-default",
"receiptId": "..."
}
]
}
```
历史 UI 分三层:
1. 会话列表:标题、最后回答摘要、状态、时间。
2. 会话详情:聊天消息、当前页上下文、关联 run。
3. Run detailworker、model、workflow、timeline、changed files、receipt、失败原因。
短期可继续 localStorage/sessionStorage;产品化阶段必须落到 SQLite control-plane,避免刷新、跨标签和权限变化导致历史丢失。
## 3. 源头输出合同
MNote 专用 worker/workflow 必须从源头产出页面 AI 风格回答,而不是先产出 Board 任务报告再让 MNote 截断。
### 3.1 用户回答
简单 ask 的 worker 最终回答应直接是:
```markdown
收到。
```
当前页编辑任务的最终回答应类似:
```markdown
已把当前页面中的“A”替换为“B”。
```
不允许把以下内容作为主回答:
- `Completed`
- `Comments`
- `Remaining`
- `Agent Board run 已创建`
- 命令日志
- 工具调用过程
- provider 内部推理或计划
### 3.2 运行记录
Board runtime/workflow 负责旁路写入结构化记录:
```json
{
"schema": "agent_board.workflow_run_receipt.v2",
"runId": "...",
"surface": "mnote-page-ai",
"workflowId": "builtin-mnote-page-ai-chat",
"workerPresetId": "mnote-page-ai-zcode",
"modelOverride": "zcode-default",
"finalAnswer": "收到。",
"changedFiles": [],
"verification": [],
"remaining": [],
"eventsUrl": "/api/workflow-runs/:id/events",
"createdAt": 0,
"completedAt": 0
}
```
`## FINAL_ANSWER` 只作为旧 run 或非专用 workflow 的兼容保护,不是长期主路径。长期主路径是 worker 主回答自然、Board receipt 结构化。
## 4. Board 和 MNote 的双向接口
### 4.1 Board route result
Board 提供 MNote surface 的推荐结果:
```json
{
"schema": "agent_board.page_ai_route.v2",
"surface": "mnote-page-ai",
"workflowId": "builtin-mnote-page-ai-chat",
"workflowName": "MNote 页面 AI",
"workerPresetId": "mnote-page-ai-zcode",
"workerName": "MNote 页面 AI · ZCode",
"modelOverride": "zcode-default",
"allowedWorkerPresetIds": ["mnote-page-ai-zcode"],
"allowedWorkflowIds": ["builtin-mnote-page-ai-chat"],
"modelOptions": [
{ "id": "zcode-default", "label": "默认", "default": true },
{ "id": "zcode-fast", "label": "快速" },
{ "id": "zcode-strong", "label": "强力" }
],
"requiresConfirmation": false,
"requires": {
"filesystem": true,
"write": false,
"browser": false,
"vision": false
},
"stages": ["answer"]
}
```
MNote 消费 Board 推荐,但仍按本地白名单过滤。这样 Board 可以逐步提供更多能力,MNote 不会把控制台复杂度泄露给页面用户。
### 4.2 MNote run request
MNote 创建 run 时必须显式传入:
```json
{
"surface": "mnote-page-ai",
"workflowId": "builtin-mnote-page-ai-chat",
"workerPresetId": "mnote-page-ai-zcode",
"modelOverride": "zcode-default",
"capabilityEnvelope": {
"primaryTarget": { "absolutePath": "/.../current.md" },
"allowedRoots": ["/..."]
},
"sessionId": "..."
}
```
Board 必须拒绝不匹配 `surface=mnote-page-ai` 的 worker/workflow 组合,避免前端绕过白名单。
## 5. 标准页面 AI 最小体验
按 VSCode/Cursor 类页面 AI 衡量,第一阶段只补核心能力,不把 QA/browser/artifact 做成默认入口。
### 5.1 Chat
- [ ] 主聊天只显示用户消息和 assistant 自然回答。
- [ ] pending skeleton 或流式 token。
- [ ] stop 当前 run。
- [x] retry 同一消息。
- [ ] copy 回答。
- [ ] Enter 发送,Shift+Enter 换行。
### 5.2 Context
- [ ] composer 上方显示上下文 pills:当前页、选区、打开资源、文件夹、知识库。
- [ ] 当前 write target 单独显示。
- [ ] 无写权限时,编辑类 prompt 发送前提示授权缺失。
- [ ] `allowedRoots``primaryTarget` run 前可预检。
### 5.3 Worker / Model / Workflow
- [ ] 只展示 MNote Page AI 白名单 worker。
- [ ] 当只有一个 worker 时,不显示伪切换入口。
- [ ] 模型选择挂在当前 worker 下。
- [ ] 只展示 MNote Page AI 白名单 workflow。
- [ ] 切换 worker/model/workflow 后写入偏好和 session metadata。
### 5.4 Timeline / Diff / Receipt
- [ ] run detail 展示 Board event timeline。
- [ ] changed files 从 receipt 读取。
- [ ] Markdown 编辑后展示最小 diff 摘要。
- [ ] 命令输出默认折叠,失败时展开。
- [x] dirty/stale guard:编辑器未保存或文件外部变化时阻止自动写入。
### 5.5 Session / History
- [ ] 会话列表可见、可搜索、可恢复。
- [ ] 每条 assistant 消息关联 run id、worker、model、workflow、receipt。
- [ ] 历史详情可查看 final answer、timeline、changed files。
- [ ] 支持删除本地 history,不删除 Board 原始 run。
## 6. 非默认扩展
QA、浏览器截图和 artifact 展示不属于页面 AI 第一阶段核心体验。它们只在用户显式选择已加入白名单的 QA/browser workflow,或 Board route 判断确实需要浏览器验证并得到 UI 提示时出现。
- 默认 Page AI 不显示 QA/browser 入口。
- artifact screenshot 只从 run detail 打开,不进入主聊天。
- QA run 失败时主聊天只显示一句可理解失败原因,详情里展示日志。
## 7. 实施计划
### Phase A:源头回答收敛
- [x] Board 默认 worker 已改为 `mnote-page-ai-zcode`
- [x] Board 默认 workflow 已改为 `builtin-mnote-page-ai-chat`
- [x] MNote UI 已能只展示 final answer,不展示 Board run 创建日志。
- [x] smoke`hi,收到请回复收到。` 最终 assistant 气泡只显示 `收到。`
- [x] `mnote-page-ai-zcode` / `builtin-mnote-page-ai-chat` 源头默认输出自然语言 final answer。
- [x] 结构化记录写入 `receipt.finalAnswer / changedFiles / verification / remaining`
### Phase B:白名单选择壳
- [x] MNote 定义 Page AI worker 白名单。
- [x] MNote 定义 Page AI workflow 白名单。
- [x] Worker picker 只展示白名单 worker。
- [x] Workflow picker 只展示白名单 workflow。
- [x] 当白名单只有一个 worker/workflow 时,不显示伪切换。
### Phase Cworker 内模型选择
- [x] Board route 返回 `modelOptions`
- [x] MNote 显示当前 model chip。
- [x] Model picker 只展示当前 worker 允许的模型档位。
- [x] run payload 包含 `modelOverride`
- [x] session metadata 记录 `modelOverride`
### Phase DBoard-first session/history
- [x] 定义并落地 `mnote.page_ai.session.v2`
- [x] assistant message 记录 `boardRunId/workflowId/workerPresetId/modelOverride/receiptId`
- [x] 历史列表展示 Board-first session。
- [x] Run detail 可从历史打开。
- [x] 刷新页面后仍能恢复会话和 run 详情。
### Phase Etimeline / changed files / diff
- [x] 从 Board events 生成 timeline。
- [x] 从 receipt 提取 changed files。
- [x] Markdown 文件编辑后展示最小 diff / changed files 摘要。
- [x] 命令输出和日志折叠。
- [x] smoke:编辑当前页面后,主聊天是自然回复,详情里能看到 changed file 和验证命令。
### Phase F:标准页面 AI 体验补齐
- [ ] 上下文 pills 完整可交互。
- [x] pending skeleton / streaming 状态。
- [x] stop / retry / copy。
- [x] dirty/stale guard。
## 8. 验收标准
### 8.1 简单问答
- 输入:`hi,收到请回复收到。`
- 主聊天最新 assistant 气泡:`收到。`
- worker 源头最终回答就是自然语言,不依赖 MNote 截断通用任务报告。
- run detail 可查看 worker、model、workflow、run id、receipt。
### 8.2 Worker 与模型
- UI 只展示 MNote Page AI 白名单 worker。
- 白名单只有一个 worker 时,不显示 worker 切换列表。
- UI 能切换当前 worker 允许的模型档位。
- 发送后 payload 包含 `workerPresetId``modelOverride`
- 不在白名单内的 worker 不显示。
### 8.3 Workflow
- UI 只展示 MNote Page AI 白名单 workflow。
- 默认 workflow 为 `builtin-mnote-page-ai-chat`
- 不在白名单内的 Board workflow 不显示。
- 发送后 payload 包含 `workflowId`
### 8.4 Session/history
- 新建会话、恢复会话、搜索历史可用。
- 历史项显示 final answer preview、状态、时间。
- 点击历史项恢复聊天消息。
- 点击 run detail 可查看 Board receipt。
### 8.5 页面编辑
- 输入“把当前页面中的 A 替换为 B”。
- worker 只修改 `primaryTarget.absolutePath`
- 磁盘文件变化。
- 编辑器 watcher 刷新可见。
- 主聊天显示自然结果。
- 详情显示 changed files / verification。
## 9. 非目标
- 不重新实现 provider adapterprovider/model 执行仍归 Board。
- 不暴露 Board 全量 worker/workflow catalog。
- 不把复杂开发、hotfix、QA/browser workflow 默认化。
- 不删除 Hermes/Reasonix legacy 代码,只隐藏默认入口并防止污染默认主链。
- 不实现完整撤销系统,只保留 diff/receipt 所需数据结构。
## 10. 风险与处理
| 风险 | 处理 |
| --- | --- |
| MNote 专用 worker 仍输出任务报告 | 从 worker/workflow prompt 和 receipt API 源头修正,MNote 截取只做兼容保护 |
| Board 选择太多 | MNote 只展示白名单 worker/workflow,新增项必须代码登记 |
| 模型选择重新变成 provider picker | 模型挂在特定 worker 下,只展示该 worker 允许的档位 |
| Workflow 太重影响简单问答 | 默认只启用 `builtin-mnote-page-ai-chat`,复杂 workflow 需 MNote 白名单 |
| 历史数据分裂 | 新 session v2 记录 Board run,旧 session 只读兼容 |
| 文件编辑误伤 | primaryTarget + allowedRoots + dirty/stale guard + receipt |
## 11. 最小落地顺序
1. 先把 MNote 专用 worker/workflow 的源头输出改成自然回答。
2. 再把 Page AI UI 收敛为白名单 worker/workflow,不显示 Board 全量选择。
3. 然后补 worker 内模型选择。
4. 再补 Board-first session/history。
5. 最后补 timeline、diff、dirty/stale guard 和可选扩展。
@@ -0,0 +1,341 @@
# 7-64 [recycle] CodexMobile 嵌入 Page AI 方案 v1
> 创建时间:2026-06-23
>
> 当前状态:`RECYCLE`
>
> Owner07-ai / Page AI / CodexMobile embed
>
> 上位依据:
> - `design/07-ai/done/7-62-page-ai-board-first-full-rewrite-v1.md`
> - `design/07-ai/process/7-63-page-ai-board-first-productization-v1.md`
> - `design/07-ai/done/7-38-page-ai-sidebar-runtime-owner-split-v1.md`
> 过时原因:已由 `design/07-ai/process/7-65-opencode-webui-embed-page-ai-v1.md` 替代;Page AI 新主路径只接入 opencode 官方 runtime + 官方 WebUI。
## 1. 核心结论
放弃 Board-first 和自研聊天 UI 两条路,改为 **fork CodexMobile 开源代码 → 精简 → iframe 嵌入 MNote**
```text
MNote Page AI = MNote 原生上下文 pills + CodexMobile 精简版 iframe
CodexMobile = Vue 3 SPA + Express server → Codex CLI app-server (RPC)
```
理由:
- CodexMobile`friuns2/codex-mobile`,MIT,675⭐)已提供成熟的聊天 UI、流式渲染、session 管理、plan/tool 卡片
- 当前 MNote Page AI runtime4457 行 JS+ Rust bridge~20000 行)维护成本高,且聊天体验不如 CodexMobile
- CodexMobile 直接对接 Codex CLICodexRelay 已解决 DeepSeek 兼容,不需要 Board 中介
- 嵌入方案比自研省 90% 代码量,比 Board-first 少一层依赖
## 2. CodexMobile 现状
### 2.1 仓库信息
| 项目 | 值 |
|---|---|
| 仓库 | `friuns2/codex-mobile` |
| 协议 | MIT |
| 星数 | 675 |
| 语言 | TypeScript (Vue 3 + Express) |
| 本地版本 | v0.1.90 (`/home/lix/.local/lib/node_modules/codexapp/`) |
| 当前运行 | `codexapp --no-login --no-tunnel --no-open --port 5900` |
### 2.2 架构
```
浏览器 Vue SPA (hash router)
↓ fetch /codex-api/rpc
Express httpServer.ts
↓ codexAppServerBridge.ts
Codex CLI app-server (RPC over HTTP)
Codex CLI (实际 agent 执行)
```
### 2.3 核心模块
| 模块 | 文件 | 作用 |
|---|---|---|
| RPC 桥接 | `codexAppServerBridge.ts` (~2500行) | 代理所有 Codex RPC 调用 |
| API 网关 | `codexGateway.ts` | 线程/消息/模型/账户等高层 API |
| RPC 客户端 | `codexRpcClient.ts` | 底层 RPC 调用与错误处理 |
| HTTP 服务 | `httpServer.ts` | Express + WebSocket + 静态文件 |
| 聊天 UI | `ThreadConversation.vue` | 消息气泡、plan 卡片、工具卡片 |
| 输入框 | `ThreadComposer.vue` | 消息输入、发送、模型选择 |
| 侧边栏 | `SidebarThreadTree.vue` | 线程列表、搜索、切换 |
| 布局 | `DesktopLayout.vue` | 整体布局框架 |
## 3. 精简方案
### 3.1 删除清单
| 删除模块 | 原因 |
|---|---|
| xterm 终端 (`terminalManager.ts`, `ThreadTerminalPanel.vue`) | MNote 不是终端 |
| 文件浏览 (`localBrowseUi.ts`) | MNote 有 FileTree |
| Firebase auth | MNote 用 SQLite control-plane |
| Telegram bridge (`telegramThreadBridge.ts`) | 无关 |
| Composio 集成 | 无关 |
| OpenRouter proxy (`openRouterProxy.ts`) | 无关 |
| Zen proxy (`zenProxy.ts`) | 无关 |
| Custom endpoint proxy (`customEndpointProxy.ts`) | 无关 |
| Free mode (`freeMode.ts`) | 无关 |
| Skills routes/hub (`skillsRoutes.ts`, `SkillsHub.vue`, `SkillCard.vue`) | 无关 |
| Review git (`reviewGit.ts`, `ReviewPane.vue`) | 无关 |
| Automations (`AutomationsPanel.vue`) | 无关 |
| Directory hub (`DirectoryHub.vue`) | 无关 |
| Account menu (`AccountMenu.vue`) | 简化 |
| Rate limit status (`RateLimitStatus.vue`) | 无关 |
| Dictation (`useDictation.ts`) | 无关 |
| GitHub skills sync (`useGithubSkillsSync.ts`) | 无关 |
| API methods panel (`ApiMethodsPanel.vue`) | 调试工具 |
| Pending request panel (`ThreadPendingRequestPanel.vue`) | 简化 |
| Queued messages (`QueuedMessages.vue`) | 简化 |
| Composer dropdowns (runtime/search/skill picker) | 简化 |
| Header git branch dropdown | 无关 |
### 3.2 保留清单
| 保留模块 | 作用 |
|---|---|
| `codexAppServerBridge.ts` | 核心 RPC 桥接 |
| `codexGateway.ts` | 高层 API |
| `codexRpcClient.ts` | RPC 客户端 |
| `httpServer.ts` | Express + WebSocket |
| `authMiddleware.ts` | 简化为 MNote token 验证 |
| `ThreadConversation.vue` | 聊天气泡 |
| `ThreadComposer.vue` | 输入框 |
| `SidebarThreadTree.vue` | 线程列表 |
| `DesktopLayout.vue` | 布局 |
| `ContentHeader.vue` | 顶部信息 |
| `appServerDtos.ts` | 类型定义 |
| `codexErrors.ts` | 错误处理 |
| WebSocket 流式事件 | 实时消息 |
### 3.3 新增:postMessage Bridge
MNote 原生层与 CodexMobile iframe 之间的通信协议:
```typescript
// MNote → CodexMobile
interface MnoteContextMessage {
type: 'mnote:context';
payload: {
workspaceId: string;
documentId: string;
pageTitle: string;
rootUri: string; // file:///...
primaryTarget: {
absolutePath: string;
relativePath: string;
};
selection?: {
text: string;
};
allowedRoots: Array<{
rootUri: string;
permission: 'read' | 'write';
}>;
knowledgeContext?: string; // LightRAG 查询结果
};
}
// CodexMobile → MNote
interface CodexMobileEvent {
type: 'codex:file-changed' | 'codex:session-update' | 'codex:ready';
payload: {
changedFiles?: string[];
sessionId?: string;
threadId?: string;
};
}
```
## 4. 集成架构
### 4.1 整体拓扑
```
┌──────────────────────────────────────────────────┐
│ MNote Rust SSR (localhost:3000) │
│ │
│ ┌─ Page AI Panel ──────────────────────────────┐ │
│ │ ┌─ MNote 原生上下文 pills ──────────────────┐ │ │
│ │ │ [当前页] [选区] [知识库] [allowed roots] │ │ │
│ │ └────────────────────────────────────────────┘ │ │
│ │ ┌─ iframe ───────────────────────────────────┐ │ │
│ │ │ CodexMobile 精简版 SPA │ │ │
│ │ │ (Vue 3, hash router, 独立端口 5900) │ │ │
│ │ │ │ │ │
│ │ │ ThreadConversation + ThreadComposer │ │ │
│ │ └────────────────────────────────────────────┘ │ │
│ │ postMessage ↑↓ │ │
│ └────────────────────────────────────────────────┘ │
│ │
│ /codex-mobile/* → reverse proxy → 127.0.0.1:5900 │
└──────────────────────────────────────────────────┘
CodexMobile Express (5900)
Codex CLI app-server (RPC)
Codex CLI + CodexRelay → DeepSeek
```
### 4.2 Rust 侧改动
```rust
// mnote-web routes/mod.rs 新增
.route("/codex-mobile/{*path}", any(codex_mobile_proxy))
// codex_mobile_proxy: 反向代理到 127.0.0.1:5900
// 仅对已认证 session 放行
// 注入 X-Mnote-Workspace-Id / X-Mnote-Document-Id header
```
### 4.3 前端侧改动
```javascript
// sidebar-page-ai-runtime.js 精简为:
// 1. 渲染上下文 pills(当前页、选区、知识库)
// 2. 创建 iframe 指向 /codex-mobile/
// 3. postMessage 监听与转发
// 4. 文件变更事件 → watcher 刷新编辑器
// 删除:
// - 所有 provider 选择逻辑 (Hermes/Reasonix/Chat-only)
// - 所有 session/message/run 持久化逻辑
// - 所有 Board bridge 调用
// - 所有 workflow/worker 选择器
// 预计从 4457 行精简到 ~300 行
```
### 4.4 Rust 侧删除
```text
删除文件:
- routes/page_ai_board.rs (317 行)
- routes/page_ai_workflow.rs (967 行)
- routes/hermes_client.rs 中 Page AI 相关部分
保留:
- hermes_tools/doc.rs 中的 mnote.doc.* tools(非 Page AI 路径仍需要)
```
## 5. 上下文注入机制
### 5.1 注入时机
1. Page AI 面板打开时:注入当前页路径、workspaceId、documentId
2. 用户选中文本时:注入 selection
3. 用户切换页面时:更新 primaryTarget
4. 用户触发知识库查询时:注入 knowledgeContext
### 5.2 注入方式
MNote 通过 `iframe.contentWindow.postMessage()` 发送 `mnote:context`CodexMobile 内新增 `useMnoteBridge.ts` composable 接收并注入到 Codex CLI 的 system prompt 中。
```typescript
// CodexMobile 侧新增 useMnoteBridge.ts
// 监听 postMessage,将上下文追加到 thread/start 的 system prompt
// ponytail: 最小实现,只做 system prompt 注入,不做 UI 展示
```
### 5.3 文件编辑闭环
```
用户输入 "把当前页的 A 替换为 B"
→ Codex CLI 通过 CodexRelay 执行
→ Codex CLI 直接编辑 primaryTarget.absolutePath
→ 磁盘文件变化
→ CodexMobile 检测文件变更 → postMessage 'codex:file-changed'
→ MNote watcher 检测到文件变化 → 刷新 tiptap 编辑器
```
## 6. 实施计划
### Phase AFork 与精简(1天)
- [ ] `git clone https://github.com/friuns2/codex-mobile``/mnt/Data1T/mnote/codex-mobile/`
- [ ] 删除 3.1 清单中的所有模块
- [ ] 简化 `authMiddleware.ts`:接受 MNote session token
- [ ] 新增 `useMnoteBridge.ts`postMessage 监听
- [ ] 验证 `npm run build` 通过
- [ ] 验证精简版可独立运行(`codexapp --port 5900`
### Phase BMNote 集成(1天)
- [ ] Rust 新增 `/codex-mobile/{*path}` 反向代理路由
- [ ] `sidebar-page-ai-runtime.js` 精简为上下文 pills + iframe + postMessage
- [ ] 删除 `page_ai_board.rs``page_ai_workflow.rs`
- [ ] 上下文 pills 实现(当前页、选区、知识库引用)
- [ ] postMessage bridge 双向通信验证
### Phase C:闭环验证(0.5天)
- [ ] smoke:打开 Page AI → 看到 CodexMobile 聊天界面
- [ ] smoke:发送消息 → 流式回复可见
- [ ] smoke:编辑当前页 → 文件变化 → 编辑器刷新
- [ ] smoke:刷新页面 → 会话恢复
- [ ] smoke:上下文 pills 正确显示当前页信息
### Phase D:旧代码清理(后续)
- [ ] 归档 `sidebar-page-ai-runtime.js` 旧代码
- [ ] 归档 `hermes_client.rs` Page AI 相关代码
- [ ] 更新 `ARCHITECTURE.md``CURRENT_ARCHITECTURE.md`
## 7. 验收标准
### 7.1 聊天体验
- 用户可在 Page AI 面板中与 Codex 对话
- 流式回复实时可见
- 支持 stop / retry / copy
- 刷新页面后会话历史可恢复
- plan 卡片和工具调用卡片可见(含 plan 持久化补丁)
### 7.2 上下文注入
- 上下文 pills 显示当前页标题和路径
- 选区内容自动注入
- Codex 能读取和编辑当前页文件
- 文件编辑后 MNote 编辑器自动刷新
### 7.3 代码精简
- `sidebar-page-ai-runtime.js` 从 4457 行精简到 <500 行
- 删除 `page_ai_board.rs``page_ai_workflow.rs`~1300 行)
- 不再依赖 Agent Board 服务
## 8. 风险与处理
| 风险 | 处理 |
|---|---|
| CodexMobile 上游更新导致 fork 过时 | 定期 rebase,只保留精简 diff |
| Codex CLI 不可用 | 降级提示 "Codex CLI 未运行",不伪装可用 |
| iframe 跨域问题 | 同源反向代理(`/codex-mobile/*`),无跨域 |
| postMessage 安全 | 验证 origin,只接受已知消息类型 |
| plan 卡片刷新消失 | 已有 `codexmobile-plan-persist.js` 补丁,合入 fork |
| npm 升级清空 codexapp 目录 | fork 到 MNote 仓库内,不依赖 npm 全局安装 |
## 9. 与旧方案的对比
| | Board-first (7-62/7-63) | CodexMobile 嵌入 (本方案) |
|---|---|---|
| MNote 代码量 | ~4457 JS + ~20000 Rust | ~500 JS + ~50 Rust |
| 聊天 UI 成熟度 | 自研,持续打磨 | 675⭐ 开源验证 |
| 依赖服务 | Agent Board (必须) | Codex CLI (必须) |
| Agent 选择 | 通过 Board 间接 | 直接使用 Codex CLI |
| Provider 适配 | Board 负责 | CodexRelay 负责 |
| 上下文注入 | 自研 pills | 自研 pills + system prompt |
| 维护负担 | Board bridge + 聊天 UI | 追上游 + postMessage bridge |
| 差异化 | 上下文 pills | 上下文 pills + 成熟聊天体验 |
## 10. 非目标
- 不把 CodexMobile 的终端、文件浏览、Skills、Review 等功能带入 MNote
- 不替换 MNote 的 FileTree、编辑器、知识库等核心功能
- 不要求 CodexMobile 支持 MNote 特有的资源类型(mindmap、OnlyOffice
- 不实现 CodexMobile 与 MNote auth 的 SSO 统一(短期独立 auth,长期可选)