feat: align local-first workspace direction
Document the VSCode-like local-first product shape, demote Convex to a control-plane role, and retire stale architecture drafts. Add local workspace migration/export references plus smoke coverage for no-Convex managed workspace startup, local markdown title/body/options persistence, asset upload behavior, and Convex fixture export. Verification: git diff --cached --check; node scripts/check-local-first-convex-guard.js --staged; node scripts/task444-convex-workspace-export-local-fixture-smoke.js; node scripts/task166-local-first-managed-workspace-no-convex-smoke.js; node scripts/task167-local-markdown-title-body-options-no-convex-smoke.js
This commit is contained in:
@@ -29,15 +29,16 @@
|
||||
- `PageAIApplyController` 后续应收口为 review session / tool executor / readback controller,不能成为第二套 agent 编排中心。
|
||||
- 当前 `usedHermesRun=false` 的快路径只能理解为 deterministic shortcut,不代表 mnote 新建长期 agent runtime。
|
||||
|
||||
## 1.0.1 当前主路径修正(2026-05-18)
|
||||
## 1.0.1 当前主路径修正(2026-05-19)
|
||||
|
||||
`7-18` 到 `7-25` 修复后,本文中的页面 AI fast workflow 口径进一步收口:
|
||||
`2-2 local-first` 完成后,本文继续保留为页面块 / 结构性工具 checklist,但普通 Markdown 正文编辑主路径已经转为 VSCode-like 文件编辑:
|
||||
|
||||
- 普通正文编辑主路径是 `mnote.doc.markdown_edit`,模型生成 markdown `search/replace` 或 `full_content`,再由统一 mnote tool executor 写入。
|
||||
- `/api/page-ai/block-edit-workflow` 仍是简单编辑 fast-path 入口,但不再把 `local_rule -> mnote.doc.apply_block_ops` 作为当前主路径。
|
||||
- local-first 普通正文编辑默认给 Hermes / Reasonix 当前文件引用、selection 和 allowed roots,由 agent 使用自身 patch / diff / 文件编辑能力写本地 `.md`。
|
||||
- `mnote.doc.markdown_edit` 是 cloud / remote agent / compat fallback,不再是 local-first 普通 Markdown 编辑唯一主路径。
|
||||
- `/api/page-ai/block-edit-workflow` 只保留为兼容门面或非 local source 的快捷路径,不作为 local-first 默认主路径。
|
||||
- `mnote.doc.apply_block_ops` / `mnote.block.*` 保留为结构性块操作辅助,例如块移动、资源块、复杂子块或必须按 blockId 精确处理的场景。
|
||||
- Phase C 的 review session / streaming apply 仍冻结;本文只继续跟踪基础工具合同、上下文、冲突校验、幂等和审阅面边界。
|
||||
- 当前 page AI runtime 口径以 `design/07-ai/process/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`、`design/10-review/done/10-current-mnote-ai-runtime-review-v1.md` 和 `bugs/07-ai/done/7-18` 到 `7-25` 为准。
|
||||
- 当前 page AI runtime 口径以 `design/02-convex-rust-long-term-architecture/done/2-2-local-first-workspace-convex-control-plane-v1.md`、`design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md` 和 `design/07-ai/process/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md` 为准。
|
||||
|
||||
## 1.1 当前执行状态(2026-05-16)
|
||||
|
||||
@@ -262,14 +263,14 @@ cargo test -p mnote-web block_fetch
|
||||
- [x] 支持 `command=block_replace`。
|
||||
- [x] 支持 `command=block_insert_after`。
|
||||
- [x] 支持 `command=block_move_after` dry-run。
|
||||
- [x] `command=str_replace` 不再作为本 checklist 当前目标;普通正文 search/replace 已收口到 `mnote.doc.markdown_edit`,多重匹配/无法安全映射阻断由 markdown_edit 合同覆盖。
|
||||
- [x] `command=str_replace` 不再作为本 checklist 当前目标;cloud / remote / compat 的普通正文 search/replace 已收口到 `mnote.doc.markdown_edit`,多重匹配/无法安全映射阻断由 markdown_edit 合同覆盖。local-first 普通 Markdown 编辑默认走授权文件 + agent 原生 patch/diff。
|
||||
- [x] 缺少 `revision/conflictDetectionKey` 时只允许 dry-run。
|
||||
- [x] 返回 `planId`、`diff`、`warnings`、`risk`、`blocked`。
|
||||
|
||||
2026-05-18 口径修正:
|
||||
2026-05-19 口径修正:
|
||||
|
||||
- `7-18` 到 `7-25` 收口后,普通正文替换不再继续扩 `mnote.doc.plan_update command=str_replace`;当前实现路径是 `page_ai_workflow.rs -> mnote.doc.markdown_edit`。
|
||||
- `mnote.doc.markdown_edit` 已覆盖精确匹配、归一化匹配、多操作同块合并、无法安全映射时失败;相关测试由 `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocapture` 覆盖。
|
||||
- `7-18` 到 `7-25` 收口后,普通正文替换不再继续扩 `mnote.doc.plan_update command=str_replace`;compat 实现路径是 `page_ai_workflow.rs -> mnote.doc.markdown_edit`。
|
||||
- `mnote.doc.markdown_edit` 已覆盖精确匹配、归一化匹配、多操作同块合并、无法安全映射时失败;相关测试由 `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocapture` 覆盖。它不再代表 local-first 普通 Markdown 编辑默认入口。
|
||||
|
||||
验证命令:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 7-12 [process] 页面 AI Hermes 工具路由与编辑审阅面设计 v1
|
||||
|
||||
> 更新时间:2026-05-16
|
||||
> 更新时间:2026-05-19
|
||||
>
|
||||
> 当前状态:`PROCESS`
|
||||
>
|
||||
@@ -21,7 +21,8 @@
|
||||
|
||||
本稿仍作为 Hermes 工具路由与审阅面设计保留在 `process/`,但以下口径已经更新:
|
||||
|
||||
- `/api/page-ai/block-edit-workflow` 当前不再以 `local_rule -> apply_block_ops` 作为主路径;简单正文编辑主路径已切到模型生成 markdown `search/replace` 或 `full_content`,再调用 `mnote.doc.markdown_edit`。
|
||||
- `/api/page-ai/block-edit-workflow` 当前不再以 `local_rule -> apply_block_ops` 作为主路径;local-first 普通 Markdown 编辑默认给 Hermes / Reasonix 授权文件引用,由 agent 使用自身 patch / diff / 文件编辑能力写本地 `.md`。
|
||||
- `mnote.doc.markdown_edit` 保留为 cloud / remote agent / compat fallback;模型生成 markdown `search/replace` 或 `full_content` 后调用该工具,只适用于 agent 不能直接访问授权文件或需要受控代理写入的场景。
|
||||
- `page_ai_workflow` 已复用统一 mnote tool executor,不再绕过 Hermes tool toggle / audit / write contract。
|
||||
- `mnote.doc.apply_block_ops` / `mnote.block.*` 保留为结构性块操作辅助,不再作为普通正文 search/replace 的优先入口。
|
||||
- 本稿中的 `PageAIReviewSession` 只定义 Phase C 的安全合同和状态机边界;当前 Phase C 仍冻结,不实施流式 apply 或新的审阅 UI。
|
||||
|
||||
@@ -4,13 +4,18 @@
|
||||
>
|
||||
> 更新时间:2026-05-16(v3:深度参考 CLI Main skill 系统,补全成熟度采纳清单)
|
||||
>
|
||||
> 2026-05-18 口径补充:
|
||||
> - local-first workspace 已成为早期产品默认形态;本地 `.md` 是默认 AI 编辑目标,在线 Convex 文档降级为可选 cloud / sync / share source。
|
||||
> - 本文早期把 `mnote.doc.markdown_edit` 描述为统一主路径;最新口径改为:local-first 普通 Markdown 编辑优先给 agent 授权文件引用,由 agent 使用自身成熟的 diff / apply_patch / 文件编辑能力完成;`mnote.doc.markdown_edit` 保留为 cloud / remote agent / compat fallback。
|
||||
> - 页面内图片 / 附件上传已在 local source 下写入 `{mdBase}.assets/` 并保存相对 Markdown 路径,AI 后续处理附件引用时也应保留相对路径,不改写为 Convex media asset。
|
||||
>
|
||||
> 当前状态:`PROCESS`
|
||||
>
|
||||
> 本稿目的:
|
||||
> 1. 纠正 7-9 / 7-10 / 7-12 / 7-13 中隐含的「块级编辑是 AI 唯一写入路径」假设
|
||||
> 2. 基于 CLI Main 参考实现,确立 mnote 的「文本级搜索替换为主 + 块级结构性操作为辅」两层模型
|
||||
> 2. 基于 CLI Main 参考实现,确立 mnote 的「agent 原生文件 patch/diff 为 local-first 默认路径,MNote 文本级兼容工具 + 块级结构性操作为 fallback / 辅助」两层模型
|
||||
> 3. 规划 BlockNote AI 流式/review 能力的远期方向(当前不实施)
|
||||
> 4. 统一在线 Convex 文档和本地 `.md` 文件的 AI 写入路径
|
||||
> 4. 统一 cloud / remote / compat 文档和本地 `.md` 文件的 AI 读取、权限、冲突与回读口径
|
||||
>
|
||||
> 关联文档:
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`
|
||||
@@ -37,7 +42,7 @@
|
||||
|
||||
## 1. 结论
|
||||
|
||||
**在线 Convex 文档和本地 `.md` 文件本质上是同一个东西:一段 markdown 文本,Tiptap 只是块级 UI 表现层。** 当前 07-ai 设计把 AI 编辑契约钉死在 `EditorBlockDocument` 的块级操作上,导致三个连锁问题:
|
||||
**在线 Convex 文档和本地 `.md` 文件本质上是同一个东西:一段 markdown 文本,Tiptap 只是块级 UI 表现层。** 进一步切到 local-first 后,本地 `.md` 已经是普通文件,因此不需要再为常规正文编辑发明一套 MNote 专用工具。当前 07-ai 设计把 AI 编辑契约钉死在 `EditorBlockDocument` 的块级操作上,导致三个连锁问题:
|
||||
|
||||
1. **AI 被迫在块级操作**:对「改写这段话」「补充一段总结」「调整语气」「把所有 TODO 改成 DONE」等自然请求,AI 必须产出 `{ op: "replace", blockId: "block_1", ... }` 格式的块操作,而不能直接产出修改后的文本或搜索替换对。这增加了 AI 的认知负担和出错概率。
|
||||
|
||||
@@ -55,15 +60,15 @@
|
||||
| **BlockNote AI** | 纯块级 `add/update/delete`(依赖 blockId),流式 apply + suggest/review | ✅ **远期参考**:流式/review 能力,Phase C 规划 |
|
||||
| **Tiptap AI Autocomplete** | 纯文本补全,单句接龙,无工具 | ⏳ 独立功能:内联 AI 补全(非本文讨论范围) |
|
||||
|
||||
**CLI Main 最关键的设计决策**:它不把 AI 钉死在某一层。`str_replace` 用于文本级修改(不需要 blockId),`block_*` 用于精确块结构调整。格式上,**XML 用于精确编辑场景,Markdown 用于整篇导入/导出**。mnote 的不同之处在于——在线文档和本地 `.md` 文件的共同分母是 **markdown 而非 XML**,因此我们的主格式是 markdown。
|
||||
**CLI Main 最关键的设计决策**:它不把 AI 钉死在某一层。`str_replace` 用于文本级修改(不需要 blockId),`block_*` 用于精确块结构调整。格式上,**XML 用于精确编辑场景,Markdown 用于整篇导入/导出**。mnote 的不同之处在于:local-first 之后,默认对象就是本地 `.md` 文件,因此可以直接复用 Codex / Hermes / Reasonix 自身成熟的 diff、apply_patch、文件编辑能力;MNote 的职责收口为权限沙箱、文件引用解析、审计和刷新。
|
||||
|
||||
### 正确方向
|
||||
|
||||
> mnote 的 AI 编辑路线:**CLI Main 的两层操作模型 + BlockNote AI 的流式/review 能力 + mnote 自己的 markdown 优先策略。**
|
||||
> mnote 的 AI 编辑路线:**本地授权文件 + agent 原生 patch/diff 为主;MNote 兼容工具为 cloud/remote/结构化辅助;BlockNote AI 的流式/review 只作为远期交互参考。**
|
||||
|
||||
具体:
|
||||
|
||||
- **当前实施**(Phase A/B):`mnote.doc.markdown_edit` 作为 AI 编辑主路径,文本级搜索替换为第一操作原语。`mnote.block.*` 保留为结构性辅助。
|
||||
- **当前实施**(Phase A/B):local-first 页面 AI 只传当前文件引用、可选 selection 和用户指令;MNote 校验 `AiAccessScope` 后让 agent 在受限目录中使用原生 patch/diff 编辑 `.md`。`mnote.doc.markdown_edit` 作为兼容 / 远端代理 fallback,`mnote.block.*` 作为复杂结构辅助。
|
||||
- **远期规划**(Phase C):BlockNote AI 的流式增量 apply + suggest/review 层。当前先设计,不实施。
|
||||
|
||||
---
|
||||
@@ -377,36 +382,37 @@ mnote 当前:Hermes 只知道 workspace/document 模型,不知道本地文
|
||||
|
||||
AI 最自然的编辑方式是对文本进行操作。块是 UI 概念,不是 AI 概念。在线文档的持久化格式和本地文件的持久化格式都可以投影为 markdown。
|
||||
|
||||
### 4.2 两层操作模型
|
||||
### 4.2 两层操作模型(兼容层)
|
||||
|
||||
| 层 | 工具 | 寻址方式 | 适用场景 | 占比 |
|
||||
|----|------|---------|---------|------|
|
||||
| **文本级(主)** | `mnote.doc.markdown_edit` | search/replace 文本对 | "把这段改简洁"、"把所有 TODO 改 DONE"、"补充一段总结" | 80%+ |
|
||||
| **文件级(主)** | agent 原生 `diff/apply_patch/文件编辑` | 授权文件引用 / selection | local-first 普通 Markdown 改写 | 80%+ |
|
||||
| **文本级(兼容)** | `mnote.doc.markdown_edit` | search/replace 文本对 | cloud / remote agent / 兼容旧页面 AI | 次要 |
|
||||
| **块级(辅助)** | `mnote.doc.apply_block_ops` | blockId / matchText | "把第三块拖到第一块后面"、"精确删除引用块" | <20% |
|
||||
|
||||
### 4.3 在线和本地共用同一条写入路径
|
||||
### 4.3 在线和本地的主写入路径
|
||||
|
||||
```
|
||||
mnote.doc.markdown_edit
|
||||
页面 AI / ACP
|
||||
→ resolve_source(documentId) → Convex | LocalFS
|
||||
→ 读取当前 markdown
|
||||
→ 应用 operations(搜索替换)
|
||||
→ 写入目标(Convex 或文件系统)
|
||||
→ 返回 delta
|
||||
→ local-first: 传授权文件引用给 agent runtime
|
||||
→ agent 原生 patch/diff 写入文件
|
||||
→ MNote 做权限 / 审计 / refresh
|
||||
→ cloud / remote fallback: mnote.doc.markdown_edit
|
||||
```
|
||||
|
||||
差异仅存在于 `resolve_source` 和 `write_target` 两个 adapter,中间的 markdown 操作逻辑完全共享。这和 CLI Main 的 `docs +update` 可以操作任何 `doc-token` 的设计一致。
|
||||
差异主要在执行层:local-first 直接让 agent 修改授权文件;cloud 或受限 remote runtime 无法直接访问本地文件时,再走 `mnote.doc.markdown_edit` 代理。这和 CLI Main 的 `docs +update` 可以操作任何 `doc-token` 的设计一致,只是 mnote 进一步把“编辑算法”让渡给 agent runtime。
|
||||
|
||||
### 4.4 Diff 是内部实现细节
|
||||
|
||||
AI **不**产出 unified diff(行号/上下文极易出错),也不调用独立的 diff/patch 工具。AI 产出两种形式之一:
|
||||
对兼容 `mnote.doc.markdown_edit` 来说,AI **不**产出 unified diff(行号/上下文极易出错),而是产出两种形式之一:
|
||||
|
||||
| 形式 | 适用场景 | AI 负担 |
|
||||
|------|---------|---------|
|
||||
| `operations: [{ search, replace }]` | 局部修改 | 低:只需找原文片段 |
|
||||
| `full_content: "..."` | 小文档全文改写 | 低:直接写完整 markdown |
|
||||
|
||||
服务端内部做 diff(用于 delta 推送和冲突检测),但 AI 无感知。
|
||||
而在 local-first 主路径中,agent runtime 自己可以安全使用成熟的 diff / apply_patch / 直接文件编辑能力;MNote 只要求这些写入被限制在授权路径内,并把 changed files / diff 摘要收回审计。
|
||||
|
||||
---
|
||||
|
||||
@@ -446,7 +452,7 @@ AI **不**产出 unified diff(行号/上下文极易出错),也不调用
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 `mnote.doc.markdown_edit`(新增,主路径)
|
||||
### 5.2 `mnote.doc.markdown_edit`(新增,兼容 / fallback)
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -580,11 +586,13 @@ GhostTextOverlay(新增,编辑器)
|
||||
|
||||
## 8. 实施阶段(当前)
|
||||
|
||||
### Phase A:`mnote.doc.fetch` 增强 + `mnote.doc.markdown_edit` 核心实现
|
||||
### Phase A:文件引用主路径 + `mnote.doc.*` 兼容层
|
||||
|
||||
- [x] `mnote.doc.fetch` 增加 `format: "markdown"`(在线文档 Page Aggregate → PageMarkdown)
|
||||
- [x] `mnote.doc.fetch` 增加本地文件 source 路由(自动检测 Convex vs 文件系统路径)
|
||||
- [x] 实现 `resolve_source(documentId)` — 本地文件路径 `local_fs` vs 其余走 Convex
|
||||
- [ ] 页面 AI / ACP 普通正文编辑默认只传当前文件引用、可选 selection 和用户指令,不再默认构造完整 page context
|
||||
- [ ] 本地 agent runtime 在 `allowed_roots / allowed_file_paths` 内执行 patch/diff,并把 changed files / diff 摘要回传 MNote
|
||||
- [x] 实现 `search_replace(text, operations)` — 四级匹配策略(精确→宽松→段落 fuzzy→失败)
|
||||
- [x] 实现 Convex 写入 adapter(复用 `doc_apply_block_ops` 链路)
|
||||
- [x] 实现本地文件写入 adapter(`mnote.doc.markdown_edit` 检测到本地文件路径时直接 `fs::write` 写回,不经过 Convex)
|
||||
@@ -599,7 +607,7 @@ GhostTextOverlay(新增,编辑器)
|
||||
### Phase B:`page_ai_workflow.rs` 收口
|
||||
|
||||
- [x] 退役 `direct_block_edit_operations`(正则抠「」的快路径,代码保留但路由跳过)
|
||||
- [x] `/api/page-ai/block-edit-workflow` 底层切换到 `mnote.doc.markdown_edit`
|
||||
- [x] `/api/page-ai/block-edit-workflow` 不再被当作 local-first 主路径
|
||||
- [x] 模型 system prompt 重构:从产块操作 JSON 改为产 search/replace 文本对
|
||||
- [x] 补全 operation schema:`extract_markdown_operations_from_model_text` 处理新旧格式
|
||||
- [x] 浏览器 smoke:`markdown_edit` 搜索替换通过,自然语言编辑路径可用
|
||||
@@ -620,7 +628,7 @@ GhostTextOverlay(新增,编辑器)
|
||||
|
||||
| CLI Main 概念 | mnote 对应 |
|
||||
|--------------|-----------|
|
||||
| `str_replace`(文本级) | `mnote.doc.markdown_edit`(主路径) |
|
||||
| `str_replace`(文本级) | `mnote.doc.markdown_edit`(兼容 / fallback) |
|
||||
| `block_replace/insert_after/delete/move_after`(块级) | `mnote.doc.apply_block_ops`(辅助路径) |
|
||||
| XML 用于精确编辑 | mnote 不用 XML(没有 XML 存储层),direct path 退役后全部走 markdown |
|
||||
| Markdown 用于导入/导出/对话引用 | mnote 全部 AI 交互走 markdown |
|
||||
@@ -640,7 +648,7 @@ GhostTextOverlay(新增,编辑器)
|
||||
|
||||
| 设计稿 | 关系 | 修正状态 |
|
||||
|--------|------|---------|
|
||||
| 7-9 路线图 | 块级编辑降级为辅助,markdown_edit 为主路径 | ✅ 已修正 |
|
||||
| 7-9 路线图 | 块级编辑降级为辅助,local-first 普通编辑改为授权文件 + agent patch/diff,markdown_edit 退到兼容层 | ✅ 已修正 |
|
||||
| 7-10 checklist | 新增 Phase 9 markdown_edit | ✅ 已修正 |
|
||||
| 7-12 工具路由 | PageAICommandRouter 主输出改为 markdown_edit | ✅ 已修正 |
|
||||
| 7-13 EditorRuntimeActor | 补充 markdown_edit 的 delta 适配 | ✅ 已修正 |
|
||||
@@ -651,10 +659,10 @@ GhostTextOverlay(新增,编辑器)
|
||||
## 10. 禁止项
|
||||
|
||||
- 不删除 `mnote.block.*` 工具(保留为辅助路径)。
|
||||
- 不让 AI 产出 unified diff(行号/上下文极易出错)。
|
||||
- 不强迫 local-first agent 产出 MNote 自定义 diff;Hermes / Reasonix 可使用自身成熟 patch / diff / apply_patch 能力,MNote 负责白名单权限、文件版本冲突和审计。
|
||||
- 不要求本地文件有稳定的 `blockId`(本地文件没有 block identity)。
|
||||
- 不在 markdown_edit 内部引入新的 AI 模型调用(diff 是确定性算法)。
|
||||
- 不改变 Convex `documents:updateContent` 的持久化链路(markdown_edit 复用现有保存路径)。
|
||||
- 不把 Convex `documents:updateContent` 重新提升为 local-first 正文主存储;`markdown_edit` 在 cloud / compat 场景可复用受控保存路径。
|
||||
- 不把 `mnote.page.save` 重新描述为精确编辑主入口(它仍是兜底工具)。
|
||||
- **不照搬 BlockNote AI 的纯 blockId 寻址模式**(与 mnote 的 markdown 优先策略冲突)。
|
||||
|
||||
@@ -663,10 +671,10 @@ GhostTextOverlay(新增,编辑器)
|
||||
## 11. 成功标准
|
||||
|
||||
- [x] `mnote.doc.fetch(documentId, format: "markdown")` 对在线文档返回正确 markdown
|
||||
- [ ] `mnote.doc.fetch(documentId, format: "markdown")` 对本地 `.md` 文件返回正确 markdown(读取已实现,待浏览器 smoke)
|
||||
- [ ] `mnote.doc.fetch(documentId, format: "markdown")` 对本地 `.md` 文件返回正确 markdown(兼容路径)
|
||||
- [x] `mnote.doc.markdown_edit` 的简单搜索替换(1 条 operation)浏览器 smoke 通过
|
||||
- [ ] `mnote.doc.markdown_edit` 的复杂改写(3+ 条 operations)成功率 > 80%
|
||||
- [ ] 本地 `.md` 文件通过页面 AI 面板可被读取和写入(读取已实现,写入待本地文件 adapter)
|
||||
- [ ] 本地 `.md` 文件通过页面 AI 面板可被读取和写入,且默认通过 agent 原生 patch/diff 完成
|
||||
- [x] 在线文档的 markdown_edit 不增加 Convex RTT(和当前块操作持平)
|
||||
- [x] `direct_block_edit_operations` 已退役(路由跳过,代码保留)
|
||||
- [x] `page_ai_workflow.rs` 的 system prompt 已补全 search/replace schema
|
||||
@@ -682,7 +690,7 @@ GhostTextOverlay(新增,编辑器)
|
||||
|
||||
| # | CLI Main 模式 | mnote 实施项 | 状态 | 参考文件 |
|
||||
|---|-------------|-------------|------|---------|
|
||||
| 1 | 两层操作模型 | `markdown_edit`(主)+ `apply_block_ops`(辅助)已在 7-10 Phase 9 登记 | 📋 设计完成,待实施 | `lark-doc-update.md` |
|
||||
| 1 | 两层操作模型 | local-first 默认 agent 原生 patch/diff;`markdown_edit`(compat fallback)+ `apply_block_ops`(结构辅助)已在 7-10 Phase 9 登记 | 📋 设计完成,已按 2-2 改口径 | `lark-doc-update.md` |
|
||||
| 2 | Scope 四级控制 | `mnote.doc.fetch` 增加 `scope: full/section/outline/keyword` | 🔜 Phase A | `lark-doc-fetch.md` |
|
||||
| 3 | Detail 三级控制 | `mnote.doc.fetch` 增加 `detail: simple/with_ids/full` | 🔜 Phase A | `lark-doc-fetch.md` |
|
||||
| 4 | 片段包装 | fetch 返回中标记 `<!-- fragment -->` / `<!-- excerpt -->` 告知 AI 部分视图 | 🔜 Phase A | `lark-doc-fetch.md`(fragment/excerpt 模式) |
|
||||
@@ -726,7 +734,7 @@ Phase A(当前立即)
|
||||
├── #3 Detail 三级控制 ← mnote.doc.fetch 增强
|
||||
├── #4 片段包装 ← fetch 返回值增强
|
||||
├── #8 Markdown 优先 ← 已确认
|
||||
└── mnote.doc.markdown_edit 核心实现
|
||||
└── 授权文件引用 + agent 原生 patch/diff 主路径;mnote.doc.markdown_edit 作为 compat fallback
|
||||
|
||||
Phase B(Phase A 完成后)
|
||||
├── #5 Code-Act Loop ← Hermes plugin SKILL.md
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
> 4. 复用现有参考代码,最小化重复实现工作
|
||||
>
|
||||
> 关联文档:
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md`
|
||||
> - `/mnt/Data1T/mnote/recycle/design/07-ai/retired-http-hermes/7-5-hermes-client-proxy-contract-v1.md`(已退役历史背景)
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-17-acp-session-convex-sharing-contract-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-vscode-main/`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/DeepSeek-Reasonix-main/`
|
||||
|
||||
@@ -35,10 +36,10 @@ mnote-web (Rust Axum)
|
||||
│ get /api/hermes/runs/{id}/events
|
||||
│
|
||||
├─ hermes_tools.rs (mnote.doc.* / mnote.block.*)
|
||||
│ └─ Rust 工具实现,通过 HTTP/Convex 读写文档
|
||||
│ └─ Rust 兼容工具实现,通过 HTTP/Convex 或本地代理读写文档
|
||||
│
|
||||
└─ page_ai_workflow.rs (fast-path 块编辑)
|
||||
└─ local_rule planner, 不经过 Hermes
|
||||
└─ page_ai_workflow.rs (兼容门面)
|
||||
└─ local-first 下不再是主路径
|
||||
```
|
||||
|
||||
**问题:**
|
||||
@@ -67,15 +68,21 @@ mnote-web (Rust Axum)
|
||||
│ │ └─ session/update ≫ SSE 转发
|
||||
│ └─ 代理层:向下游工具通知
|
||||
│
|
||||
├─ hermes_tools.rs (不变)
|
||||
├─ hermes_tools.rs (兼容层)
|
||||
│ └─ mnote.doc.* / mnote.block.* / mnote.page.*
|
||||
│
|
||||
└─ page_ai_workflow.rs (不变)
|
||||
└─ fast-path 块编辑
|
||||
└─ page_ai_workflow.rs (兼容保留)
|
||||
└─ local-first 普通正文编辑默认不经过它
|
||||
```
|
||||
|
||||
ACP 是整个架构的支点——它是一个**开放协议**,不是某个产品的私有接口。
|
||||
|
||||
> 2026-05-18 local-first 口径补充:
|
||||
>
|
||||
> - 目标不是把 Hermes / Reasonix 再包进一层重型 MNote 工具系统,而是让它们尽量像在 VSCode 中那样直接面对授权后的本地工作区。
|
||||
> - MNote 主要负责:页面定位、白名单目录授权、ACP 会话管理、审计、文件变化同步到 tiptap / File Tree / Page Aggregate。
|
||||
> - local-first 普通 Markdown 编辑默认不要求 runtime 调 `mnote.doc.markdown_edit`;兼容工具只为 cloud / remote / 复杂结构场景保留。
|
||||
|
||||
---
|
||||
|
||||
## 2. ACP 协议标准
|
||||
@@ -216,6 +223,25 @@ profile "reasonix" → runtime "reasonix" (spawn node reasonix-acp-wrapper.mjs)
|
||||
|
||||
前端获取可用运行时列表:`GET /api/hermes/client/profiles`(现有接口,扩展字段)
|
||||
|
||||
### 4.1.1 白名单目录即 runtime 权限边界
|
||||
|
||||
对 local-first 而言,真正重要的不是再做一套“文档工具能力矩阵”,而是把 workspace 白名单准确传给 runtime:
|
||||
|
||||
```text
|
||||
登录用户
|
||||
-> 解析 access-policy.json / owner / admin / grant
|
||||
-> 得到 allowedRoots = ["/mnt/Data1T/Mnote_data/users/.../my-space", ...]
|
||||
-> 启动 Hermes / Reasonix 时把 allowedRoots / cwd / read-write scope 传入 runtime
|
||||
-> runtime 直接在这些目录里工作
|
||||
```
|
||||
|
||||
这与 VSCode / Codex 的工作模型一致:
|
||||
|
||||
- runtime 看到的是一个受限 workspace,而不是一堆抽象页面 API。
|
||||
- 页面 AI 只额外提供“当前文件是谁”以及可选选区信息。
|
||||
- 对 `.md` 的普通编辑不强制走 `mnote.doc.markdown_edit`。
|
||||
- 一旦文件写回磁盘,MNote 再负责把变化同步回前端显示。
|
||||
|
||||
### 4.2 会话生命周期 (ACP Session Manager)
|
||||
|
||||
```
|
||||
@@ -244,9 +270,9 @@ profile "reasonix" → runtime "reasonix" (spawn node reasonix-acp-wrapper.mjs)
|
||||
|
||||
### 4.3 工具桥接
|
||||
|
||||
当前 `hermes_tools.rs` 中注册的 mnote 工具(`mnote.doc.fetch`、`mnote.doc.markdown_edit`、`mnote.block.*`、`mnote.page.*`)对 ACP 来说只是一组 HTTP 端点。
|
||||
当前 `hermes_tools.rs` 中注册的 mnote 工具(`mnote.doc.fetch`、`mnote.doc.markdown_edit`、`mnote.block.*`、`mnote.page.*`)对 ACP 来说只是一组 HTTP 兼容端点,而不是 local-first 普通 Markdown 编辑的唯一主路径。
|
||||
|
||||
对于 Reasonix 作为 runtime 的场景,需要一个 Reasonix-side 的工具注册包装脚本,将 mnote 工具注册到 `ToolRegistry`:
|
||||
对于 Reasonix 作为 runtime 的场景,仍需要一个 Reasonix-side 的工具注册包装脚本,将 mnote 兼容工具注册到 `ToolRegistry`;但 local-first 默认应优先让 runtime 直接拿到授权文件引用,在受限 cwd 中使用自身成熟的 patch/diff/文件编辑能力。
|
||||
|
||||
```typescript
|
||||
// reasonix-acp-wrapper.mjs — ACP 包装层
|
||||
@@ -287,7 +313,27 @@ agent → tool call → (通过 TCP/localhost HTTP) → mnote-web Rust hermes_to
|
||||
→ Convex / 文档系统
|
||||
```
|
||||
|
||||
**不需要在 Rust 侧重新注册工具到 Reasonix。** mnote-web 的工具 HTTP 端点 (`/api/hermes/tools/mnote/call`) 不变,只通过 ACP 换掉了 agent runtime。
|
||||
**不需要在 Rust 侧重新注册工具到 Reasonix。** mnote-web 的工具 HTTP 端点 (`/api/hermes/tools/mnote/call`) 仍可保留,只通过 ACP 换掉了 agent runtime;但这些端点主要承担 cloud / remote agent / compat fallback,而不是把所有本地文件编辑都重新包成 mnote 工具。
|
||||
|
||||
### 4.3.1 local-first 默认工作流
|
||||
|
||||
local-first 页面 AI 的默认工作流应是:
|
||||
|
||||
```text
|
||||
当前页面 URL / documentId
|
||||
-> MNote 解析出真实 markdown 文件路径
|
||||
-> MNote 校验该路径是否落在 runtime allowedRoots 白名单内
|
||||
-> 把 currentFile / selection / allowedRoots 传给 runtime
|
||||
-> runtime 直接读写该文件
|
||||
-> watcher / refresh 触发前端 page aggregate 与 tiptap 更新
|
||||
```
|
||||
|
||||
只有在以下情况,runtime 才需要走 mnote 兼容工具:
|
||||
|
||||
- runtime 本身无法直接访问本地文件
|
||||
- 当前 source 是 cloud / sync replica
|
||||
- 当前对象不是普通 markdown,而是 mindmap / table / 资源块 / 分享受限对象
|
||||
- 需要显式审计某种结构化操作
|
||||
|
||||
### 4.4 前端 SSE 扩展
|
||||
|
||||
@@ -570,11 +616,11 @@ AiAgentPanel 增加下拉框 + 切换逻辑:
|
||||
|
||||
### 7.2 对 7-14 (markdown 编辑收敛) 的影响
|
||||
|
||||
7-14 确立的「两层操作模型」(`mnote.doc.markdown_edit` 主 + `mnote.block.*` 辅)不受影响——工具在 Rust 侧 `hermes_tools.rs` 实现不变。ACP 只是换掉了 driver(从 Hermes 换成 Reasonix),不改 driver 调用的工具。
|
||||
7-14 的最新口径是:local-first 普通 Markdown 编辑优先走“授权文件引用 + agent 原生 patch/diff”,`mnote.doc.markdown_edit` / `mnote.block.*` 退到兼容与辅助层。ACP 只是换掉 driver(从 Hermes 换成 Reasonix),不改变这个权限与执行边界。
|
||||
|
||||
### 7.3 对 `page_ai_workflow.rs` 的影响
|
||||
|
||||
不影响。`block_edit_workflow` 作为独立 fast-path 与 ACP 无关。
|
||||
最新口径下,`block_edit_workflow` 只保留为兼容门面;local-first 普通正文编辑不应再依赖它。ACP 主要服务 agent runtime 选择、权限隔离、事件桥接和审计。
|
||||
|
||||
---
|
||||
|
||||
@@ -638,7 +684,7 @@ AiAgentPanel 增加下拉框 + 切换逻辑:
|
||||
|
||||
| 改动 | 文件 | 说明 |
|
||||
|------|------|------|
|
||||
| ACP 下拉选择器 | `layout.rs` | Agent 标签页新增 `<select data-page-ai-acp-runtime>`,3 个选项:默认 (Hermes HTTP)、ACP · Hermes、ACP · Reasonix |
|
||||
| ACP 下拉选择器 | `layout.rs` | Agent 标签页新增 `<select data-page-ai-acp-runtime>`;2026-05-18 起只保留 ACP · Hermes / ACP · Reasonix,移除“默认 (Hermes HTTP)”选项 |
|
||||
| 状态存储 | `layout.rs` | `pageAiAcpRuntime` + `pageAiAcpRuntimes` 从 `/api/hermes/client/profiles` 加载 |
|
||||
| 运行时切换 | `layout.rs` | `acpRuntime` 只表示运行时/传输层;Hermes ACP 继续保留当前 Hermes profile,Reasonix ACP 使用 `profile=reasonix` |
|
||||
| UI 自适应 | `layout.rs` | ACP Hermes 模式下继续显示 Hermes profile 下拉;ACP Reasonix 模式下隐藏 Hermes profile 下拉;Agent 面板显示 ACP 配置 |
|
||||
@@ -909,7 +955,14 @@ node /home/lix/.codex/skills/page-ai-browser-verify/scripts/verify_mnote_page_ai
|
||||
|
||||
### [ ] Step 16:退役旧的 Hermes HTTP proxy 代码
|
||||
|
||||
> 待 ACP 路径稳定后执行(至少 1 周灰度观察期)。
|
||||
> 2026-05-18 已开始执行第一阶段退役:
|
||||
>
|
||||
> - 页面 AI 前端默认 `acpRuntime=reasonix`,不再以空 runtime 表示“默认 Hermes HTTP”;用户仍可在下拉中切换到 `ACP · Hermes`。
|
||||
> - mnote-web 服务端默认把 `/api/hermes/client/runs` 的空 `acpRuntime` 归入 ACP 默认 runtime(默认 `reasonix`),避免继续落到 `configured_upstream_for_profile()` 的 HTTP proxy 分支。
|
||||
> - `GET /api/hermes/client/gateway/health` 在 ACP 默认路径下返回 ACP transport 状态,不再探测 `8642/8644` HTTP gateway。
|
||||
> - 旧 Hermes HTTP proxy 合同与 `/v1/runs` 默认主链设计稿已移入 `recycle/design/07-ai/retired-http-hermes/`,避免干扰后续 ACP 主线判断。
|
||||
>
|
||||
> 剩余工作:删除或进一步隔离 `hermes_client.rs` 内的 HTTP proxy 兼容分支;当前阶段只保留显式兼容开关,避免一次性删除影响 profile/memory/tools 管理能力。
|
||||
|
||||
### [ ] Step 17:基准测试 — Reasonix 缓存收益量化
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
|
||||
本文只承接这些剩余 smoke,不新增 AI 功能面,不改变当前主路径:
|
||||
|
||||
- 简单正文编辑主路径仍是 `mnote.doc.markdown_edit`。
|
||||
- local-first 普通 Markdown 编辑主路径仍是“授权文件引用 + agent 原生 patch/diff + watcher 同步”;本文只验证 mnote tools 的结构性辅助和 compat fallback。
|
||||
- `mnote.doc.markdown_edit` 只作为 cloud / remote agent / compat fallback 的 smoke 对象。
|
||||
- `mnote.block.*` 仍只作为结构性辅助。
|
||||
- `mnote.page.save` 仍只作为页面级粗粒度兜底。
|
||||
- Phase C review / streaming apply 仍冻结,当前只验证基础合同和安全边界。
|
||||
|
||||
@@ -0,0 +1,477 @@
|
||||
# 7-17 [process] ACP Session 与控制面账号作用域 / 分享合同 v1
|
||||
|
||||
> 创建时间:2026-05-18
|
||||
>
|
||||
> 当前状态:`PROCESS / FUTURE`
|
||||
>
|
||||
> 本稿目的:
|
||||
> 1. 明确 ACP session 必须绑定当前账号权限与控制面作用域,不能以内存态绕过权限。
|
||||
> 2. 冻结后续“复制会话 / 只读分享 / 多人共同会话”的产品语义,避免当前实现误扩。
|
||||
> 3. 区分 MNote 产品层 AI session 与 ACP Hermes / ACP Reasonix 执行层 session。
|
||||
> 4. 为后续项目基本完成后扩展共享能力预留 schema、API 和验证边界。
|
||||
>
|
||||
> 关联文档:
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/done/7-25-acp-session-runtime-enhancement-plan-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md`
|
||||
> - `/mnt/Data1T/mnote/recycle/design/07-ai/retired-http-hermes/`
|
||||
|
||||
---
|
||||
|
||||
## 0. 当前结论
|
||||
|
||||
ACP 默认主链已经替代旧 Hermes HTTP 主链,但这不意味着 ACP runtime session 可以成为产品层会话真相。
|
||||
|
||||
当前必须成立的规则:
|
||||
|
||||
- **控制面持有产品层 AI session 的账号作用域真相;在当前实现里它可以暂时落在 Convex,但长期不应把“Convex”写死成唯一真相。**
|
||||
- **ACP runtime session 只是执行层会话**,可以被控制面 session 绑定或索引,但不能直接作为跨用户共享对象。
|
||||
- **ACP session 记录必须带 `userId / workspaceId / documentId / sessionId / runId / actorId / acpRuntime / profile`**。
|
||||
- **写入控制面 session store 失败时,不允许静默降级为可继续写入的内存 session**。这会破坏账号隔离、审计和后续分享语义。
|
||||
- 当前只实现单用户页面 AI session 基础路径;复制、分享、多人共同会话全部是后续功能,不在当前阶段实施。
|
||||
|
||||
---
|
||||
|
||||
## 1. 术语边界
|
||||
|
||||
### 1.1 MNote AI Session
|
||||
|
||||
MNote AI Session 是产品层会话对象,长期应该由控制面持有;当前实现可以暂存在 Convex,但目标不是把消息全文和权限真相永久绑死在 Convex。
|
||||
|
||||
它回答:
|
||||
|
||||
- 谁能看到这段 AI 会话?
|
||||
- 这段会话属于哪个 workspace / document?
|
||||
- 它是否可被复制、分享、共同编辑?
|
||||
- 每条 run 是哪个账号触发的?
|
||||
- 哪些消息、工具调用、结果可以被其他用户看到?
|
||||
|
||||
MNote AI Session 的 id 可以稳定暴露给前端,例如 `mnote_{documentId}_{traceId}`,但它不是 ACP runtime 原生 session id。
|
||||
|
||||
### 1.2 ACP Runtime Session
|
||||
|
||||
ACP Runtime Session 是执行层对象,由 Hermes ACP 或 Reasonix ACP 子进程持有。
|
||||
|
||||
它回答:
|
||||
|
||||
- 某个 agent runtime 当前 prompt 属于哪个协议 session?
|
||||
- 运行时如何接收 `session/prompt`?
|
||||
- `session/update` 事件如何返回?
|
||||
- 运行时内部是否有本地上下文、缓存、memory、tool state?
|
||||
|
||||
ACP Runtime Session 不应作为产品层共享真相。它可以失效、重建、按用户隔离、按 runtime 隔离。
|
||||
|
||||
### 1.3 Run / Event / Tool Audit
|
||||
|
||||
Run 是一次用户触发的执行。
|
||||
|
||||
Event 是 runtime 或 mnote tool 在 run 中产生的结构化事件。
|
||||
|
||||
Tool Audit 是 mnote 侧工具执行与写入结果的审计记录,必须以触发账号为准,而不是 session owner 或 runtime owner。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前实现边界
|
||||
|
||||
当前代码可接受的最小边界:
|
||||
|
||||
- `POST /api/hermes/client/sessions` 在 ACP 默认路径下创建 Convex 侧 runtime session 索引。
|
||||
- `POST /api/hermes/client/runs` 创建 run 并持久化到 Convex runtime store。
|
||||
- `GET /api/hermes/client/events/{runId}` 将 ACP event 转成页面 SSE,并追加 runtime event。
|
||||
- `GET /api/hermes/client/gateway/health` 在 ACP 默认路径下返回 `transport=acp`,不再探测旧 Hermes HTTP gateway。
|
||||
|
||||
当前不应声称已完成:
|
||||
|
||||
- 跨账号共享会话。
|
||||
- 多人共同编辑同一个 AI session。
|
||||
- 复制会话后的上下文重建。
|
||||
- 完整消息历史作为产品层真相。
|
||||
- Hermes ACP 与 Reasonix ACP 的统一长期 resume 语义。
|
||||
- 分享链接、权限继承、脱敏导出。
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据模型草案
|
||||
|
||||
### 3.1 `ai_sessions`
|
||||
|
||||
后续需要从当前 `acp_runtime_runs` 中抽出产品层 session 表。默认建议本地全文 + 控制面 metadata 的双层模型:
|
||||
|
||||
- 会话全文默认落本地 `ai-sessions/private/*.jsonl` 或 `ai-sessions/shared/*/*.jsonl`
|
||||
- 控制面只保存 metadata、分享关系、审计索引、同步状态
|
||||
- 只有显式开启同步或分享时,才把必要副本推到远端
|
||||
|
||||
建议字段:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `id` | 控制面记录 id |
|
||||
| `session_id` | MNote 产品层 session id |
|
||||
| `owner_user_id` | 会话创建者 |
|
||||
| `workspace_id` | 所属 workspace,可为空但必须显式 |
|
||||
| `document_id` | 所属页面 / 文档 |
|
||||
| `title` | 会话标题 |
|
||||
| `visibility` | `private` / `workspace_read` / `shared_link` / `collaborative` |
|
||||
| `source` | `page_ai` / `local_file_ai` / 其他 |
|
||||
| `created_at` / `updated_at` / `deleted_at` | 生命周期 |
|
||||
|
||||
权限规则:
|
||||
|
||||
- 默认 `private`。
|
||||
- 任何 query/mutation 必须先按当前控制面 auth 解析 user,再判断 `owner_user_id`、membership 或 share grant。
|
||||
- 不允许只凭客户端传入的 `userId` 授权。
|
||||
|
||||
### 3.2 `ai_session_members`
|
||||
|
||||
多人共同会话需要独立成员表,不应把共享用户塞进 session JSON。
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `session_id` | 产品层 session |
|
||||
| `user_id` | 成员 |
|
||||
| `role` | `owner` / `editor` / `commenter` / `viewer` |
|
||||
| `added_by` | 添加者 |
|
||||
| `created_at` | 加入时间 |
|
||||
| `revoked_at` | 撤销时间 |
|
||||
|
||||
角色规则:
|
||||
|
||||
- `viewer` 只能读可共享消息和可共享 artifact。
|
||||
- `editor` 可以继续发起 run,但每次 run 的 `actor_id` 必须是本人。
|
||||
- `owner` 可以管理成员和删除会话。
|
||||
|
||||
### 3.3 `ai_runtime_bindings`
|
||||
|
||||
产品层 session 与运行时 session 的绑定必须独立建模。
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `binding_id` | 绑定 id |
|
||||
| `session_id` | MNote 产品层 session |
|
||||
| `run_id` | 当前 run,可选 |
|
||||
| `user_id` | 运行时所属用户 |
|
||||
| `runtime` | `hermes` / `reasonix` |
|
||||
| `profile` | Hermes profile 或 Reasonix preset |
|
||||
| `runtime_session_id` | ACP 对端 session id |
|
||||
| `status` | `active` / `closed` / `expired` / `failed` |
|
||||
| `created_at` / `expires_at` | 生命周期 |
|
||||
|
||||
关键规则:
|
||||
|
||||
- 同一个 MNote session 可以有多个 runtime binding。
|
||||
- 不同用户默认不能复用同一个 runtime binding。
|
||||
- 切换 Hermes / Reasonix runtime 时必须创建新 binding。
|
||||
- binding 是执行层缓存,不是会话权限真相。
|
||||
|
||||
### 3.4 `ai_session_messages`
|
||||
|
||||
后续如需完整历史,应单独建消息表,而不是只依赖 runtime events。
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `message_id` | 消息 id |
|
||||
| `session_id` | 产品层 session |
|
||||
| `run_id` | 关联 run |
|
||||
| `actor_user_id` | 触发者,可为空仅限系统消息 |
|
||||
| `role` | `user` / `assistant` / `tool` / `system` |
|
||||
| `content` | 可展示文本 |
|
||||
| `visibility` | `private` / `members` / `owner_only` |
|
||||
| `redaction` | 脱敏状态 |
|
||||
| `created_at` | 创建时间 |
|
||||
|
||||
当前阶段可以先不落完整 messages,但必须保证已有 run/event store 能按 user 过滤。
|
||||
|
||||
### 3.5 `ai_session_events`
|
||||
|
||||
Runtime event 和 tool event 应保留原始结构,但查询时必须做权限过滤。
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `event_id` | 事件 id |
|
||||
| `session_id` | 产品层 session |
|
||||
| `run_id` | run |
|
||||
| `actor_user_id` | 触发者 |
|
||||
| `runtime` | `hermes` / `reasonix` |
|
||||
| `event_type` | `message.delta` / `tool.started` / `tool.completed` 等 |
|
||||
| `payload` | 原始或规范化 payload |
|
||||
| `visibility` | 默认 `owner_only`,明确脱敏后才可扩大 |
|
||||
| `created_at` | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 权限模型
|
||||
|
||||
### 4.1 单用户私有会话
|
||||
|
||||
当前阶段只要求这个模式稳定。
|
||||
|
||||
规则:
|
||||
|
||||
- 创建 session 时使用当前 Convex Auth 解析出的真实 user id。
|
||||
- `userId` 只可作为服务端派生字段,不可由浏览器任意指定。
|
||||
- run / event / tool audit 都必须与同一 actor 绑定。
|
||||
- 当前请求无法解析用户时,应返回 `401` 或稳定错误,而不是创建匿名共享 session。
|
||||
|
||||
### 4.2 复制会话
|
||||
|
||||
复制不是共享同一个 runtime session。
|
||||
|
||||
复制语义:
|
||||
|
||||
- 生成新的 `session_id`。
|
||||
- 新 session 的 `owner_user_id` 是复制者。
|
||||
- 可以复制已脱敏、可共享的消息、摘要、artifact 引用。
|
||||
- 不复制底层 `runtime_session_id`。
|
||||
- 不复制另一个用户的 Hermes profile memory、Reasonix cache handle、tool permission state。
|
||||
- 复制后第一次继续对话时,为复制者创建新的 runtime binding。
|
||||
|
||||
适用场景:
|
||||
|
||||
- 用户把某段 AI 分析作为模板继续改。
|
||||
- 从只读分享页复制到自己的 workspace。
|
||||
|
||||
### 4.3 只读分享
|
||||
|
||||
只读分享只读产品层 session 的可共享投影。
|
||||
|
||||
必须隐藏:
|
||||
|
||||
- 本地路径、profile 配置路径、API key 状态。
|
||||
- tool args 中含有的敏感字段。
|
||||
- 未授权页面内容、选区内容、私有 workspace 信息。
|
||||
- actor 的内部 user id,除非产品明确展示成员身份。
|
||||
|
||||
分享链接不能恢复 ACP runtime session。
|
||||
|
||||
### 4.4 多人共同会话
|
||||
|
||||
多人共同会话是后续能力,不能直接复用当前 runtime session。
|
||||
|
||||
推荐语义:
|
||||
|
||||
```text
|
||||
共享 MNote AI Session
|
||||
-> 每个用户按自己的权限发起 run
|
||||
-> 每次 run 记录 actor_user_id
|
||||
-> runtime binding 默认按 actor_user_id 隔离
|
||||
-> 前端展示同一个产品层 transcript
|
||||
```
|
||||
|
||||
允许的实现策略:
|
||||
|
||||
- **每用户 runtime binding**:最安全,默认方案。每个成员继续对话时由自己的 runtime 处理。
|
||||
- **共享 transcript 重建上下文**:runtime 不共享,只把已授权 transcript 作为 prompt context 注入。
|
||||
- **共享 runtime binding**:默认禁止。只有当 runtime 明确是服务端多租户安全实例,并且 tool permission 已按 actor 隔离时才可考虑。
|
||||
|
||||
---
|
||||
|
||||
## 5. ACP Hermes 与 ACP Reasonix 差异
|
||||
|
||||
### 5.1 ACP Hermes
|
||||
|
||||
特点:
|
||||
|
||||
- Hermes profile、memory、skills、tools 往往绑定本机用户配置。
|
||||
- `mnoteai` profile 可能包含特定用户偏好、工具开关、记忆文件。
|
||||
- Hermes ACP 的底层 session 适合“当前用户私有 agent runtime”。
|
||||
|
||||
规则:
|
||||
|
||||
- 默认按用户隔离 runtime binding。
|
||||
- 共享会话不能让其他用户复用 owner 的 Hermes profile memory。
|
||||
- 复制会话时只复制可展示 transcript,不复制 Hermes profile 状态。
|
||||
- 如果后续允许团队 Hermes profile,必须单独建 workspace-level profile 权限模型。
|
||||
|
||||
### 5.2 ACP Reasonix
|
||||
|
||||
特点:
|
||||
|
||||
- Reasonix 强调 cache-first / preset / project cache。
|
||||
- 缓存可能跨 prompt 复用,隐私边界比普通 stateless model 更敏感。
|
||||
- Reasonix 的 session 与 cache handle 不应默认跨账号共享。
|
||||
|
||||
规则:
|
||||
|
||||
- 默认按 `userId + workspaceId + documentId + preset` 隔离缓存可见性。
|
||||
- 分享 transcript 不等于分享 Reasonix cache。
|
||||
- 多人共同会话如果要共享 Reasonix 缓存,必须先设计 cache grant。
|
||||
- 只读分享不得暴露 cache hit/miss 细节,除非确认无隐私风险。
|
||||
|
||||
### 5.3 统一抽象
|
||||
|
||||
MNote 不应把 Hermes ACP / Reasonix ACP 的内部 session 当成统一真相。
|
||||
|
||||
统一层只定义:
|
||||
|
||||
- 产品层 session。
|
||||
- run 与 actor。
|
||||
- runtime binding。
|
||||
- event/message 投影。
|
||||
- 权限与分享合同。
|
||||
|
||||
---
|
||||
|
||||
## 6. API 草案
|
||||
|
||||
当前阶段不实现以下 API,只冻结形状。
|
||||
|
||||
### 6.1 Session
|
||||
|
||||
```http
|
||||
GET /api/hermes/client/sessions
|
||||
POST /api/hermes/client/sessions
|
||||
GET /api/hermes/client/sessions/{sessionId}
|
||||
DELETE /api/hermes/client/sessions/{sessionId}
|
||||
POST /api/hermes/client/sessions/{sessionId}/rename
|
||||
POST /api/hermes/client/sessions/{sessionId}/auto-title
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 所有接口服务端解析当前用户。
|
||||
- 查询默认只返回当前用户有权限访问的 session。
|
||||
- 删除默认软删除,不删除 runtime audit。
|
||||
|
||||
### 6.2 复制
|
||||
|
||||
```http
|
||||
POST /api/hermes/client/sessions/{sessionId}/copy
|
||||
```
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"targetWorkspaceId": "ws_1",
|
||||
"targetDocumentId": "doc_2",
|
||||
"copyMode": "summary_and_visible_messages"
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"sessionId": "mnote_doc_2_copy_1",
|
||||
"sourceSessionId": "mnote_doc_1_original",
|
||||
"runtimeBindingCopied": false
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 分享
|
||||
|
||||
```http
|
||||
POST /api/hermes/client/sessions/{sessionId}/shares
|
||||
GET /api/hermes/client/sessions/{sessionId}/shares
|
||||
DELETE /api/hermes/client/sessions/{sessionId}/shares/{shareId}
|
||||
```
|
||||
|
||||
分享 grant 必须包含:
|
||||
|
||||
- `scope`: `user` / `workspace` / `link`
|
||||
- `role`: `viewer` / `editor`
|
||||
- `expiresAt`
|
||||
- `redactionPolicy`
|
||||
|
||||
### 6.4 多人会话成员
|
||||
|
||||
```http
|
||||
POST /api/hermes/client/sessions/{sessionId}/members
|
||||
GET /api/hermes/client/sessions/{sessionId}/members
|
||||
DELETE /api/hermes/client/sessions/{sessionId}/members/{userId}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 不变量
|
||||
|
||||
这些规则后续实现必须写成测试。
|
||||
|
||||
1. 账号 A 创建的 private session,账号 B 不能读取列表、详情、事件、消息。
|
||||
2. 账号 B 复制账号 A 分享给他的 session 后,得到新的 `sessionId` 和新的 owner。
|
||||
3. 复制后的 session 不包含源 session 的 `runtime_session_id`。
|
||||
4. 多人共同会话中,账号 B 发起 run 时 `actor_user_id=B`,不能写成 owner A。
|
||||
5. 只读 viewer 不能发起 run。
|
||||
6. Hermes profile memory 不随 session 分享。
|
||||
7. Reasonix cache handle 不随 session 分享。
|
||||
8. tool args 默认 `owner_only`,只有经过脱敏的摘要可进入 shared transcript。
|
||||
9. Convex store 写入失败时,run 创建必须失败或返回明确可恢复错误,不能静默创建匿名内存会话。
|
||||
10. 本地文件 AI session 分享必须重新核验目标用户是否能访问对应 local root;默认不支持跨用户分享本地文件内容。
|
||||
|
||||
---
|
||||
|
||||
## 8. 实施阶段
|
||||
|
||||
### Phase A:当前阶段,只做约束固化
|
||||
|
||||
状态:当前主线。
|
||||
|
||||
- ACP 默认主链可用。
|
||||
- session/run/event 必须账号作用域写入 Convex。
|
||||
- 旧 Hermes HTTP 主链进入 `recycle`。
|
||||
- 不实现复制、分享、多人会话。
|
||||
- 文档与测试明确禁止内存降级绕过权限。
|
||||
|
||||
### Phase B:项目基本完成后,补产品层 session 表
|
||||
|
||||
目标:
|
||||
|
||||
- 增加 `ai_sessions` / `ai_session_members` / `ai_runtime_bindings`。
|
||||
- 将现有 `acp_runtime_runs` 从“运行态索引”升级为 session 下的 run 记录。
|
||||
- UI 从 localStorage 历史逐步迁到 Convex session 列表。
|
||||
|
||||
### Phase C:复制与只读分享
|
||||
|
||||
目标:
|
||||
|
||||
- 实现 session copy。
|
||||
- 实现只读分享投影。
|
||||
- 建立脱敏策略。
|
||||
- 不实现多人共同编辑。
|
||||
|
||||
### Phase D:多人共同会话
|
||||
|
||||
目标:
|
||||
|
||||
- 成员管理。
|
||||
- 多 actor transcript。
|
||||
- 每 actor runtime binding。
|
||||
- 共享上下文重建策略。
|
||||
|
||||
### Phase E:runtime-specific 高级策略
|
||||
|
||||
目标:
|
||||
|
||||
- Hermes team profile 权限模型。
|
||||
- Reasonix cache grant / cache visibility。
|
||||
- workspace-level AI runtime policy。
|
||||
|
||||
---
|
||||
|
||||
## 9. 当前代码注意事项
|
||||
|
||||
当前代码中 `acp_runtime_runs` / `acp_runtime_events` 仍是运行态索引,不是完整产品层 session 模型。
|
||||
|
||||
因此后续修改时:
|
||||
|
||||
- 不要把 `ACP_RUN_PAYLOADS` 或 `ACP_ACTIVE_RUNS` 视为权限真相。
|
||||
- 不要因为 Convex 写入失败就退回“可继续写”的内存 session。
|
||||
- 不要把 `profile=mnoteai` 当成 user identity。
|
||||
- 不要让 `acpRuntime=hermes` 自动表示可访问 Hermes profile memory;仍需当前账号授权。
|
||||
- 不要把 Reasonix cache 命中结果写入共享 transcript,除非经过脱敏和权限确认。
|
||||
|
||||
---
|
||||
|
||||
## 10. 验收清单
|
||||
|
||||
后续实现本稿时,至少需要以下验证:
|
||||
|
||||
- 两账号隔离 smoke:A 创建 session,B 列表不可见。
|
||||
- 分享 smoke:A 授权 B viewer,B 可读脱敏 transcript,不可 run。
|
||||
- editor smoke:A 授权 B editor,B 可 run,event actor 为 B。
|
||||
- copy smoke:B 复制 A 的分享 session,产生新 session,新 owner 为 B。
|
||||
- runtime binding smoke:复制后没有复用源 runtime session id。
|
||||
- Hermes ACP smoke:共享后不暴露 owner profile memory。
|
||||
- Reasonix ACP smoke:共享后不暴露 cache handle。
|
||||
- 权限失败 smoke:Convex auth 缺失或 user 不匹配时,API 返回 401/403,不创建内存会话。
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
> 更新:2026-05-18(v2:整合 CLI Main 参考实现分析,确认方向,补充见解)
|
||||
>
|
||||
> 2026-05-19 local-first 口径补充:
|
||||
> - 本文仍适用于 `convex_workspace` / 在线文档的 `mnote.doc.markdown_edit` 修复,但当前默认产品形态已切到 local-first workspace。
|
||||
> - 本地 `.md` 路径的默认 AI 编辑主路径是“授权文件引用 + agent 原生 patch/diff + watcher 同步”;`mnote.doc.markdown_edit` 只作为本地受控代理 fallback、cloud / remote agent 或 compat 路径。
|
||||
> - 后续新增 AI 编辑能力默认先保证本地 `.md` 与 `{mdBase}.assets/` 相对路径不被改写为 Convex media asset;在线 Convex 文档路径只作为可选 cloud / sync / share source。
|
||||
>
|
||||
> 当前状态:`PROCESS`
|
||||
>
|
||||
> 关联缺陷:`bugs/07-ai/done/7-24-markdown-edit-online-write-does-not-use-final-markdown-v1.md`
|
||||
|
||||
Reference in New Issue
Block a user