feat: EditorRuntimeActor - 三层缓存/delta/事件架构
Phase A — EditorRuntimeActor 内存缓存层 - 新增 editor_actor.rs: EditorBlockDocument 内存态 + apply_command + load_or_init - block.rs 四个写工具(replace/insert/delete/move)接入 actor 路径 - editor_actor feature flag(MNOTE_WEB_ENABLE_EDITOR_ACTOR=true 默认开启) - bridge-runtime 三个核心函数公开化 - rust-toolchain: 1.89 → stable(修复 spike WASM 编译阻塞) Phase B — 编辑器增量 delta channel - BlockDelta/DeltaOperation 类型 + actor.build_block_delta() - leptos-tiptap spike: mnote:editor:block-delta CustomEvent 监听 + JSON patch - DocumentAiAgentPanel: 拦截 blockDelta → window dispatchEvent - 工具响应含 blockDelta 字段供前端消费 Phase C — 事件 stream delta - broadcast channel 在 AppState/actor/SSE 三层贯通 - tree_events SSE 端点发 block.delta 事件 - 旧客户端降级兼容 环境修复 - rustc recursion_limit = 1024(修复 Leptos SSR 类型深度溢出) - run-convex-deploy.js(封装 Convex function 部署到本地后端 3210) ref: design/07-ai/process/7-13-page-block-editor-runtime-actor-v1.md
This commit is contained in:
+440
@@ -0,0 +1,440 @@
|
||||
# 7-11 [process][recycle] BlockNote / Tiptap AI 参考与 mnote 自有 AI 工具 runtime v1
|
||||
|
||||
> 更新时间:2026-05-16
|
||||
>
|
||||
> 当前状态:`RECYCLE`。
|
||||
>
|
||||
> 回收说明(2026-05-16):
|
||||
> - 本稿的参考取证仍有价值,但“mnote 自有 AI 工具 runtime”口径容易误导后续实现继续扩出第二套页面 AI runtime。
|
||||
> - 当前长期口径已被 `/mnt/Data1T/mnote/design/07-ai/process/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md` 覆盖。
|
||||
> - 后续方向固定为:Hermes 继续作为唯一页面 AI agent runtime;mnote 只建设 Hermes 可消费的工具路由、工具 manifest、上下文冻结、dry-run/review、Rust 写入校验与 readback。
|
||||
> - 本稿仅作为 BlockNote / Tiptap 参考材料和历史判断保留,不再作为当前执行口径。
|
||||
>
|
||||
> 关联文档:
|
||||
> - `/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-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-13-page-block-identity-and-command-contract-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocknote-ai/MNOTE-REFERENCE.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论
|
||||
|
||||
BlockNote AI 和 Tiptap AI Toolkit 都值得参考,但参考层级不同:
|
||||
|
||||
- Tiptap AI Toolkit 适合作为“AI tool contract”参考:`tiptapRead`、`tiptapEdit`、`tiptapReadSelection`、`toolDefinitions()`、`executeTool/streamTool`、review options。
|
||||
- BlockNote AI 适合作为“AI runtime shape”参考:`AIExtension`、`DocumentStateBuilder`、`StreamToolsProvider`、`AIRequest`、`aiMenuState`、`acceptChanges/rejectChanges/retry/abort`。
|
||||
- mnote 不能直接采用 BlockNote / Tiptap 的 editor truth。mnote 的事实源仍是 Rust kernel、Page Aggregate、EditorCommand、Convex revision/conflict key 与 Hermes audit。
|
||||
|
||||
下一步不应把 BlockNote 重新拉回运行时主链,也不应把 Tiptap Pro / BlockNote XL AI 当成硬依赖。正确方向是用它们的架构形态,打造 mnote 自己的 Rust-owned AI tool runtime。
|
||||
|
||||
---
|
||||
|
||||
## 2. 已拉取参考代码
|
||||
|
||||
已将 BlockNote 官方仓库以 sparse clone 方式拉到:
|
||||
|
||||
`/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocknote-ai/`
|
||||
|
||||
当前提交:
|
||||
|
||||
`c255558b2d4f2be6453c67df81bb702a1a586909`
|
||||
|
||||
保留范围:
|
||||
|
||||
- `docs/content/docs/features/ai/`
|
||||
- `examples/09-ai/`
|
||||
- `packages/xl-ai/src/`
|
||||
- `packages/xl-ai-server/src/`
|
||||
- 对应 `package.json` / `LICENSE`
|
||||
|
||||
许可证边界:
|
||||
|
||||
- `@blocknote/xl-ai` 当前标注为 `GPL-3.0 OR PROPRIETARY`。
|
||||
- 本目录只能作为 `reference-code` 研究材料。
|
||||
- 不允许未审查许可证就复制实现进入 mnote runtime。
|
||||
|
||||
---
|
||||
|
||||
## 3. BlockNote AI 可借鉴能力
|
||||
|
||||
### 3.1 AI lifecycle 状态机
|
||||
|
||||
参考:
|
||||
|
||||
- `reference-code/blocknote-ai/packages/xl-ai/src/AIExtension.ts`
|
||||
|
||||
BlockNote 的 AI menu state 包含:
|
||||
|
||||
```text
|
||||
closed
|
||||
user-input
|
||||
thinking
|
||||
ai-writing
|
||||
user-reviewing
|
||||
error
|
||||
```
|
||||
|
||||
并提供:
|
||||
|
||||
- `openAIMenuAtBlock(blockId)`
|
||||
- `closeAIMenu()`
|
||||
- `invokeAI(opts)`
|
||||
- `acceptChanges()`
|
||||
- `rejectChanges()`
|
||||
- `retry()`
|
||||
- `abort(reason)`
|
||||
- `setAIResponseStatus(...)`
|
||||
|
||||
mnote 应吸收为:
|
||||
|
||||
- `PageAIController`
|
||||
- `PageAIRunState`
|
||||
- `PageAIReviewSession`
|
||||
|
||||
但状态源必须绑定 mnote 的 `documentId/workspaceId/blockId/revision/conflictDetectionKey`,不能绑定 BlockNote editor instance。
|
||||
|
||||
### 3.2 DocumentStateBuilder
|
||||
|
||||
参考:
|
||||
|
||||
- `reference-code/blocknote-ai/packages/xl-ai/src/api/formats/DocumentStateBuilder.ts`
|
||||
- `reference-code/blocknote-ai/packages/xl-ai/src/api/aiRequest/builder.ts`
|
||||
|
||||
BlockNote 把 AI 上下文拆成两种:
|
||||
|
||||
- 无选区:全量 document blocks + cursor position。
|
||||
- 有选区:selected blocks + whole document context;模型只能对 selection 发操作。
|
||||
|
||||
mnote 应吸收为 `PageAIContextBuilder`:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "mnote.page_ai_context.v1",
|
||||
"workspaceId": "tree_x",
|
||||
"documentId": "tree_y",
|
||||
"runId": "run_1",
|
||||
"scope": "selection",
|
||||
"revision": 12,
|
||||
"conflictDetectionKey": "body:...",
|
||||
"selectedBlocks": [],
|
||||
"contextBlocks": [],
|
||||
"allowedTargetBlockIds": []
|
||||
}
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- context 必须从 Page Aggregate block projection 生成。
|
||||
- selection 必须在 AI run 开始时冻结,不能随用户后续选区漂移。
|
||||
- `allowedTargetBlockIds` 必须作为写工具校验输入的一部分。
|
||||
|
||||
### 3.3 StreamToolsProvider
|
||||
|
||||
参考:
|
||||
|
||||
- `reference-code/blocknote-ai/packages/xl-ai/src/api/formats/formats.ts`
|
||||
- `reference-code/blocknote-ai/packages/xl-ai/src/api/formats/base-tools/`
|
||||
- `reference-code/blocknote-ai/packages/xl-ai/src/streamTool/`
|
||||
|
||||
BlockNote 的 stream tool 把 add/update/delete block 建模为 schema + validate + executor。
|
||||
|
||||
mnote 已有对应底座:
|
||||
|
||||
- `mnote.doc.fetch`
|
||||
- `mnote.doc.find`
|
||||
- `mnote.block.fetch`
|
||||
- `mnote.doc.plan_update`
|
||||
- `mnote.block.replace`
|
||||
- `mnote.block.insert_after`
|
||||
- `mnote.block.delete`
|
||||
- `mnote.block.move_after`
|
||||
- `mnote.doc.apply_block_ops`
|
||||
|
||||
mnote 下一步要补的不是工具名,而是工具 manifest 的能力注解:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "mnote.block.replace",
|
||||
"annotations": {
|
||||
"readonly": false,
|
||||
"destructive": false,
|
||||
"idempotent": false,
|
||||
"requiresApproval": true,
|
||||
"selectionEffect": "destroy",
|
||||
"runtimeOwner": "mnote-web",
|
||||
"writeOwner": "rust-runtime-kernel"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 Review / accept / reject
|
||||
|
||||
参考:
|
||||
|
||||
- `reference-code/blocknote-ai/packages/xl-ai/src/AIExtension.ts`
|
||||
- `reference-code/blocknote-ai/packages/xl-ai/src/prosemirror/rebaseTool.ts`
|
||||
- `reference-code/tiptap-docs/src/content/content-ai/capabilities/ai-toolkit/api-reference/review-options.mdx`
|
||||
|
||||
BlockNote 在 editor 内通过 suggestions / fork ydoc 完成 review;Tiptap AI Toolkit 则提供 `review/preview/trackedChanges` 模式。
|
||||
|
||||
mnote 不能照搬 ProseMirror suggestion 作为事实源。mnote 应建立自己的 review session:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "mnote.page_ai_review_session.v1",
|
||||
"reviewSessionId": "review_1",
|
||||
"runId": "run_1",
|
||||
"documentId": "tree_y",
|
||||
"workspaceId": "tree_x",
|
||||
"status": "previewing",
|
||||
"baseRevision": 12,
|
||||
"baseConflictDetectionKey": "body:...",
|
||||
"operations": [],
|
||||
"diff": [],
|
||||
"warnings": [],
|
||||
"risk": "low"
|
||||
}
|
||||
```
|
||||
|
||||
状态:
|
||||
|
||||
```text
|
||||
draft
|
||||
planning
|
||||
previewing
|
||||
awaiting_user
|
||||
accepted
|
||||
rejected
|
||||
applying
|
||||
applied
|
||||
failed
|
||||
aborted
|
||||
stale
|
||||
```
|
||||
|
||||
写入规则:
|
||||
|
||||
- AI 写工具默认先生成 review session。
|
||||
- 用户 accept 后才执行 `mnote.doc.apply_block_ops` 或单个 `mnote.block.*`。
|
||||
- accept 时重新校验 `revision/conflictDetectionKey/revisionRef`。
|
||||
- reject 只关闭 session,不改变正文。
|
||||
|
||||
---
|
||||
|
||||
## 4. Tiptap AI Toolkit 可借鉴能力
|
||||
|
||||
Tiptap AI Toolkit 已在 `7-9` 中完成第一轮映射,本文补充它与 BlockNote 的组合边界。
|
||||
|
||||
| Tiptap / BlockNote 能力 | mnote 对应 | 吸收内容 | 禁止吸收 |
|
||||
| --- | --- | --- | --- |
|
||||
| `tiptapRead` | `mnote.doc.fetch` / `mnote.block.fetch` | 先读、带范围、返回 AI 友好表示 | 不把 Tiptap JSON 当长期工具格式 |
|
||||
| `tiptapEdit` | `mnote.doc.plan_update` + `mnote.block.*` | 操作列表、dry-run、diff、reviewable edit | 不让浏览器 editor command 成为事实源 |
|
||||
| `tiptapReadSelection` | `mnote.doc.fetch scope=selection` | selection-aware workflow | 不持久化 ProseMirror selection range |
|
||||
| `toolDefinitions()` | Rust Hermes manifest | schema、description、capability、annotations | 不依赖私有 npm 包 |
|
||||
| `AIExtension` | `PageAIController` | AI lifecycle、menu state、abort/retry | 不引入 BlockNote runtime |
|
||||
| `DocumentStateBuilder` | `PageAIContextBuilder` | selection/context 分离 | 不从 DOM 拼上下文 |
|
||||
| `StreamToolsProvider` | `MnoteAIToolProvider` | 工具集合按能力开放 | 不在前端直接执行正式持久化 |
|
||||
| `acceptChanges/rejectChanges` | `PageAIReviewSession` | preview -> accept/reject | 不以 ProseMirror suggestion 作为最终事实 |
|
||||
|
||||
---
|
||||
|
||||
## 5. mnote 自有 AI runtime 设计
|
||||
|
||||
### 5.1 分层
|
||||
|
||||
```text
|
||||
Page Aggregate / Rust kernel
|
||||
-> PageAIContextBuilder
|
||||
-> MnoteAIToolProvider
|
||||
-> Hermes / model runtime
|
||||
-> PageAIReviewSession
|
||||
-> EditorCommand / page.body.save
|
||||
-> Page Aggregate 回读验证
|
||||
```
|
||||
|
||||
### 5.2 组件职责
|
||||
|
||||
`PageAIContextBuilder`
|
||||
|
||||
- 输入:`workspaceId/documentId/scope/selection/blockId/query/maxBlocks`。
|
||||
- 输出:`mnote.page_ai_context.v1`。
|
||||
- 数据源:Page Aggregate block projection。
|
||||
- 负责 selection 冻结、上下文裁剪、`allowedTargetBlockIds`。
|
||||
|
||||
`MnoteAIToolProvider`
|
||||
|
||||
- 输入:profile、document capability、selection scope、feature flags。
|
||||
- 输出:可用工具 manifest。
|
||||
- 负责 `readonly/destructive/requiresApproval/selectionEffect` 等注解。
|
||||
|
||||
`PageAIController`
|
||||
|
||||
- 管理当前页面 AI run。
|
||||
- 对齐状态:`user-input/thinking/ai-writing/user-reviewing/error/aborted`。
|
||||
- 不直接写正文,只组织 context、tool calls、review session。
|
||||
|
||||
`PageAIReviewSession`
|
||||
|
||||
- 保存 plan/diff/warnings/risk/operations。
|
||||
- 提供 `accept/reject/retry/abort`。
|
||||
- accept 时走 Rust 写工具,并二次校验 revision。
|
||||
|
||||
`PageAIReviewSurface`
|
||||
|
||||
- 页面内展示 AI 结果、工具卡、diff、风险、按钮。
|
||||
- 不把 tool result 当正文。
|
||||
- 不绕过 review session 调写工具。
|
||||
|
||||
---
|
||||
|
||||
## 6. 格式策略
|
||||
|
||||
当前 mnote 不能把 HTML 作为长期 AI contract。推荐格式分三层:
|
||||
|
||||
`json`
|
||||
|
||||
- 面向工具执行。
|
||||
- 保留 block id、type、attrs、children、revisionRef。
|
||||
- 作为写工具输入和回读校验主格式。
|
||||
|
||||
`text`
|
||||
|
||||
- 面向摘要、问答、轻量改写。
|
||||
- 不可直接作为精确写入定位依据。
|
||||
|
||||
`page_xml`
|
||||
|
||||
- 面向模型理解结构。
|
||||
- 形态示例:
|
||||
|
||||
```xml
|
||||
<page id="tree_y" revision="12">
|
||||
<block id="p_1" type="paragraph" revisionRef="body:12:p_1">第一段</block>
|
||||
<block id="h_1" type="heading" level="2" revisionRef="body:12:h_1">标题</block>
|
||||
</page>
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- `page_xml` 只能是 Page Aggregate projection 的序列化视图。
|
||||
- 写入仍必须转成 `mnote.block.*` 或 `mnote.doc.apply_block_ops`。
|
||||
|
||||
---
|
||||
|
||||
## 7. 执行 checklist
|
||||
|
||||
### Phase A:参考口径冻结
|
||||
|
||||
- [x] 拉取 BlockNote AI sparse reference 到 `reference-code/blocknote-ai/`。
|
||||
- [x] 标注来源 commit 与许可证边界。
|
||||
- [x] 明确 BlockNote 只作为 AI runtime shape 参考,不作为 mnote runtime dependency。
|
||||
- [x] 明确 Tiptap AI Toolkit 只作为 tool contract 参考,不作为事实源。
|
||||
|
||||
### Phase B:PageAIContextBuilder
|
||||
|
||||
- [x] 定义 `mnote.page_ai_context.v1` schema。
|
||||
- [x] `doc.fetch` 支持 `scope=selection`。
|
||||
- [x] selection run 开始时冻结 `selectedBlockIds` / `allowedTargetBlockIds`。
|
||||
- [x] `doc.fetch` 支持 `format=text/page_xml/json`。
|
||||
- [x] `block.fetch` 支持 `format=text/page_xml/json`。
|
||||
- [ ] 大页面 context 默认裁剪,返回 `truncated/warnings/continuation`。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] AI run 期间用户改变选区,不影响本 run 的 selection context。
|
||||
- [ ] 写工具不能修改 `allowedTargetBlockIds` 外的块。
|
||||
- [ ] `page_xml` 与 JSON projection 的 block id / revisionRef 一致。
|
||||
|
||||
### Phase C:MnoteAIToolProvider
|
||||
|
||||
- [x] tool manifest 增加 `annotations`。
|
||||
- [x] 当前 yolo 模式下写工具标注 `requiresApproval=false` / `approvalMode=yolo`。
|
||||
- [x] selection scope 下,写工具自动带 `allowedTargetBlockIds` 约束。
|
||||
- [ ] profile tool toggle 与 capability annotation 同时生效。
|
||||
- [ ] manifest 输出能直接转换给 Hermes/model runtime。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] 禁用工具不出现在当前 AI run 的可用工具集中。
|
||||
- [ ] 复杂块工具返回 `unsupportedReason`,不伪装成可编辑。
|
||||
- [ ] manifest 能说明工具是否 destructive / readonly / requiresApproval。
|
||||
|
||||
### Phase D:PageAIReviewSession
|
||||
|
||||
- [ ] 定义 `mnote.page_ai_review_session.v1`。
|
||||
- [ ] `mnote.doc.plan_update` 可创建 review session。
|
||||
- [ ] `mnote.doc.apply_block_ops dryRun=true` 可返回 review session draft。
|
||||
- [ ] 页面 AI UI 展示 diff、warnings、risk、blocked。
|
||||
- [ ] `accept` 执行写入前二次校验 revision/conflictDetectionKey/revisionRef。
|
||||
- [ ] `reject` 不改变正文。
|
||||
- [ ] `abort` 停止 run,关闭未提交 review session。
|
||||
- [ ] `retry` 使用最新 Page Aggregate 重新构建 context。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] accept 后 Page Aggregate 与 `mnote.doc.fetch` 都能读回变化。
|
||||
- [ ] stale revision 时 accept 被阻断,session 进入 `stale`。
|
||||
- [ ] reject 后页面正文、revision、block ids 不变化。
|
||||
|
||||
### Phase E:页面 AI 状态机
|
||||
|
||||
- [ ] 实现 `PageAIController` 状态枚举。
|
||||
- [ ] AI menu / side panel 共享同一 run state。
|
||||
- [ ] tool event 按 `toolCallId` 聚合展示。
|
||||
- [ ] 错误态支持 retry / close。
|
||||
- [ ] abort 态不会留下半写入正文。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] `thinking -> ai-writing -> user-reviewing -> accepted/rejected` 链路可见。
|
||||
- [ ] 网络失败、tool parse 失败、revision stale 三类错误可区分。
|
||||
- [ ] 页面刷新后未提交 review session 不会自动写入正文。
|
||||
|
||||
---
|
||||
|
||||
## 8. 当前优先级
|
||||
|
||||
优先级顺序:
|
||||
|
||||
1. `PageAIContextBuilder + scope=selection`
|
||||
2. `format=page_xml/text`
|
||||
3. `PageAIReviewSession`(后续可选 review 模式;当前默认 yolo 不阻塞写入)
|
||||
4. `PageAIController` 状态机与 UI surface
|
||||
5. 复杂块移动 / 删除 / 多块操作阻断矩阵
|
||||
|
||||
原因:
|
||||
|
||||
- selection 和 context 是 AI 质量与安全边界的前置条件。
|
||||
- `page_xml/text` 能降低模型误读 projection 的概率。
|
||||
- review session 是生产写入前必须补齐的用户确认层。
|
||||
- 状态机和 UI surface 应建立在稳定 session 语义之上。
|
||||
|
||||
---
|
||||
|
||||
## 9. 禁止项
|
||||
|
||||
- 不把 BlockNote 重新设为文档页默认主编辑器。
|
||||
- 不把 `@blocknote/xl-ai` 作为 mnote runtime dependency。
|
||||
- 不复制 GPL/PROPRIETARY 源码进入 mnote 运行时代码。
|
||||
- 不让前端 editor instance 直接执行长期持久化写入。
|
||||
- 不以 HTML / Tiptap JSON / ProseMirror position 作为 mnote 长期 AI tool contract。
|
||||
- 不绕过 `dryRun/idempotencyKey/revision/conflictDetectionKey/revisionRef` 执行 AI 写工具。
|
||||
|
||||
---
|
||||
|
||||
## 10. 与 `7-10` 的关系
|
||||
|
||||
`7-10` 继续作为页面块 AI 工具执行 checklist。
|
||||
|
||||
本文补充的是 `7-10` 后半段缺口的架构口径:
|
||||
|
||||
- `scope=selection`
|
||||
- `format=page_xml/text`
|
||||
- `持久审阅/preview UI`
|
||||
- `AI lifecycle 状态机`
|
||||
- `accept/reject/retry/abort`
|
||||
|
||||
因此本文不替代 `7-10`,而是作为下一阶段 AI runtime 收口设计稿。
|
||||
Reference in New Issue
Block a user