对齐 Wolai 侧栏体验并收拢设计入库
This commit is contained in:
@@ -0,0 +1,717 @@
|
||||
# 02. Command / Query / Tool Protocol v0
|
||||
|
||||
更新时间:2026-04-11
|
||||
适用范围:`/mnt/Data1T/mnote-rust`
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标
|
||||
|
||||
本文件定义 `mnote-rust` 的统一协议面。
|
||||
|
||||
目标只有一个:
|
||||
|
||||
> 让 Web、Desktop、CLI、Agent、批处理任务都通过**同一套正式入口**操作系统。
|
||||
|
||||
它要解决的问题:
|
||||
|
||||
- 怎样避免“每个页面、每个组件、每个 API route 都有自己的写法”
|
||||
- 怎样让 AI 不依赖 UI 模拟,而能直接操作笔记软件
|
||||
- 怎样保证命令可审计、可回放、可测试、可维护
|
||||
|
||||
---
|
||||
|
||||
## 2. 基本原则
|
||||
|
||||
### 2.1 写与读必须分离
|
||||
|
||||
- **Command**:会改变事实层
|
||||
- **Query**:只读,不改变事实层
|
||||
- **Tool**:面向 AI / CLI 的能力暴露层,内部映射到 Command / Query / Job
|
||||
|
||||
### 2.2 Tool 不是第三套业务逻辑
|
||||
|
||||
禁止出现:
|
||||
|
||||
- Web 走一套逻辑
|
||||
- CLI 走一套逻辑
|
||||
- AI Tool 再写一套逻辑
|
||||
|
||||
正确关系:
|
||||
|
||||
```text
|
||||
Tool -> Command / Query / Job -> Domain + Storage + EventLog
|
||||
```
|
||||
|
||||
### 2.3 每条写命令都要可审计
|
||||
|
||||
至少要记录:
|
||||
|
||||
- 谁发起
|
||||
- 从哪里发起
|
||||
- 改了什么
|
||||
- 为什么改
|
||||
- 影响了哪些对象
|
||||
- 是否成功
|
||||
|
||||
### 2.4 AI 默认只能调用系统工具
|
||||
|
||||
AI 不应默认获得:
|
||||
|
||||
- 任意 SQL
|
||||
- 任意文件写入
|
||||
- 任意 UI 按钮点击
|
||||
- 任意内部未定型方法
|
||||
|
||||
AI 应调用:
|
||||
|
||||
- 稳定的 Tool API
|
||||
- 明确的参数模型
|
||||
- 明确的权限模型
|
||||
|
||||
---
|
||||
|
||||
## 3. 三层协议面
|
||||
|
||||
```text
|
||||
Human UI / CLI / Agent Runtime
|
||||
│
|
||||
▼
|
||||
Tool API
|
||||
│
|
||||
┌───────┴────────┐
|
||||
▼ ▼
|
||||
Query API Command API
|
||||
│ │
|
||||
└───────┬────────┘
|
||||
▼
|
||||
Job / Workflow API
|
||||
│
|
||||
▼
|
||||
Rust Note Core
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- Tool API 是面向使用者的稳定能力面
|
||||
- Command / Query API 是内核的正式操作面
|
||||
- Job / Workflow API 负责长任务、异步流程、外部能力编排
|
||||
|
||||
---
|
||||
|
||||
## 4. Actor 模型
|
||||
|
||||
所有命令、查询、工具调用都应带 `actor`。
|
||||
|
||||
建议结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"actor": {
|
||||
"type": "human",
|
||||
"id": "user_123",
|
||||
"session_id": "ui_session_xxx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
或:
|
||||
|
||||
```json
|
||||
{
|
||||
"actor": {
|
||||
"type": "agent",
|
||||
"id": "agent_session_456",
|
||||
"provider": "openai",
|
||||
"model": "gpt-5.4-mini"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
或:
|
||||
|
||||
```json
|
||||
{
|
||||
"actor": {
|
||||
"type": "system",
|
||||
"id": "job_runner"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
用途:
|
||||
|
||||
- 审计
|
||||
- 权限判断
|
||||
- 限流
|
||||
- 错误追踪
|
||||
|
||||
---
|
||||
|
||||
## 5. Command API
|
||||
|
||||
## 5.1 通用结构
|
||||
|
||||
建议所有命令统一壳:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "insert_block",
|
||||
"command_id": "cmd_01",
|
||||
"idempotency_key": "idem_01",
|
||||
"actor": {
|
||||
"type": "agent",
|
||||
"id": "agent_session_1"
|
||||
},
|
||||
"source": {
|
||||
"channel": "tool",
|
||||
"client": "mcp"
|
||||
},
|
||||
"target": {
|
||||
"workspace_id": "ws_1",
|
||||
"page_id": "page_1"
|
||||
},
|
||||
"payload": {},
|
||||
"reason": "补充总结段落",
|
||||
"refs": ["ref_1"],
|
||||
"dry_run": false,
|
||||
"validate_only": false,
|
||||
"requested_at": "2026-04-11T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 通用返回
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"command_id": "cmd_01",
|
||||
"event_ids": ["evt_1", "evt_2"],
|
||||
"affected_objects": [
|
||||
{ "type": "block", "id": "block_123" }
|
||||
],
|
||||
"revision": {
|
||||
"workspace_id": "ws_1",
|
||||
"page_id": "page_1",
|
||||
"value": 42
|
||||
},
|
||||
"warnings": [],
|
||||
"rollback_hint": {
|
||||
"kind": "compensating_command",
|
||||
"command": "delete_block",
|
||||
"target_id": "block_123"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 观测字段约束
|
||||
|
||||
从 task-034 开始,所有正式 `Command / Query / Tool / Job` 面都要默认带上并统一解释下面这些字段:
|
||||
|
||||
- `request_id`:一次入口请求级别的稳定编号,用于串起 route、runtime、日志和回查接口
|
||||
- `trace_id`:一次完整调用链的稳定编号,用于跨 query / command / tool / job 串联同一条执行路径
|
||||
- `command_id`:写命令的唯一编号,也是 `command_log_id`、`event_id` 推导的基础
|
||||
- `idempotency_key`:CLI、AI、Web 共享的幂等语义主键,不能三端各自解释
|
||||
- `command_log_id` / `event_id`:进入审计与回放链后的稳定对象编号,供 request/trace/command 回查与恢复命令复用
|
||||
|
||||
如果某条能力不能带出这组字段,它就还不能算“可供 CLI 与 AI 稳定运行的正式协议面”。
|
||||
|
||||
### 5.3 命令分类
|
||||
|
||||
#### 页面类
|
||||
- `create_page`
|
||||
- `rename_page`
|
||||
- `move_page`
|
||||
- `archive_page`
|
||||
- `restore_page`
|
||||
- `set_page_property`
|
||||
|
||||
#### 块类
|
||||
- `insert_block`
|
||||
- `update_block`
|
||||
- `delete_block`
|
||||
- `move_block`
|
||||
- `batch_apply_block_ops`
|
||||
- `replace_block_content`
|
||||
|
||||
#### 引用类
|
||||
- `create_reference`
|
||||
- `remove_reference`
|
||||
- `rebind_reference_anchor`
|
||||
|
||||
#### 资产类
|
||||
- `attach_asset`
|
||||
- `replace_asset_version`
|
||||
- `set_asset_metadata`
|
||||
- `extract_asset_outline`
|
||||
|
||||
#### 工作区 / 系统类
|
||||
- `create_task`
|
||||
- `cancel_task`
|
||||
- `rebuild_search_index`
|
||||
- `run_import_job`
|
||||
- `run_export_job`
|
||||
|
||||
---
|
||||
|
||||
## 6. Command 设计约束
|
||||
|
||||
### 6.1 命令应小而明确
|
||||
|
||||
优先:
|
||||
|
||||
- `insert_block`
|
||||
- `move_block`
|
||||
- `set_page_property`
|
||||
|
||||
避免:
|
||||
|
||||
- `save_everything`
|
||||
- `update_editor_state`
|
||||
- `mutate_page_with_ui_payload`
|
||||
|
||||
### 6.2 支持幂等键
|
||||
|
||||
AI 可能重试、网络可能重放,因此:
|
||||
|
||||
- 所有外部写命令建议支持 `idempotency_key`
|
||||
- 同一作用域内重复提交应可去重
|
||||
|
||||
### 6.3 支持 dry-run / validate-only
|
||||
|
||||
这样 AI 可以先问:
|
||||
|
||||
- 这个操作是否合法?
|
||||
- 会影响哪些对象?
|
||||
- 是否需要确认?
|
||||
|
||||
这对 Agent 很重要。
|
||||
|
||||
### 6.4 支持批量 ops,但要有边界
|
||||
|
||||
对于 Mindmap、结构调整、导入转换,可以提供:
|
||||
|
||||
- `batch_apply_block_ops`
|
||||
- `apply_mindmap_ops`
|
||||
- `apply_document_transform_ops`
|
||||
|
||||
但要求:
|
||||
|
||||
- ops 必须结构化
|
||||
- 单条失败策略明确
|
||||
- 返回逐条结果
|
||||
|
||||
---
|
||||
|
||||
## 7. Query API
|
||||
|
||||
## 7.1 通用结构
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "page.get",
|
||||
"actor": {
|
||||
"type": "human",
|
||||
"id": "user_1"
|
||||
},
|
||||
"scope": {
|
||||
"workspace_id": "ws_1"
|
||||
},
|
||||
"params": {
|
||||
"page_id": "page_1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 查询分类
|
||||
|
||||
#### 页面与块
|
||||
- `page.get`
|
||||
- `page.tree`
|
||||
- `page.list_children`
|
||||
- `block.get`
|
||||
- `block.subtree`
|
||||
|
||||
#### 检索
|
||||
- `search.text`
|
||||
- `search.reference`
|
||||
- `search.asset`
|
||||
- `search.page_by_title`
|
||||
|
||||
#### 资产
|
||||
- `asset.get`
|
||||
- `asset.list_versions`
|
||||
- `asset.resolve_anchor`
|
||||
|
||||
#### 日志与会话
|
||||
- `command_log.list`
|
||||
- `command_log.get`
|
||||
- `event.list`
|
||||
- `agent_session.get`
|
||||
- `task.list`
|
||||
|
||||
### 7.3 输出要求
|
||||
|
||||
- 输出稳定、字段可预期
|
||||
- 支持分页、游标、过滤
|
||||
- 避免直接返回前端组件所需临时形态
|
||||
- 对大型对象支持摘要与展开模式
|
||||
|
||||
---
|
||||
|
||||
## 8. Tool API
|
||||
|
||||
## 8.1 Tool API 的职责
|
||||
|
||||
Tool API 是给:
|
||||
|
||||
- AI Agent
|
||||
- CLI
|
||||
- 自动化脚本
|
||||
- 外部集成方
|
||||
|
||||
用的能力层。
|
||||
|
||||
它的原则是:
|
||||
|
||||
- 工具名清晰
|
||||
- 参数结构明确
|
||||
- 返回格式稳定
|
||||
- 明确确认策略与权限策略
|
||||
|
||||
## 8.2 工具命名风格
|
||||
|
||||
建议按领域分组:
|
||||
|
||||
- `note.read_page`
|
||||
- `note.list_children`
|
||||
- `note.insert_block`
|
||||
- `note.update_block`
|
||||
- `note.move_block`
|
||||
- `note.search`
|
||||
- `asset.attach_file`
|
||||
- `asset.extract_outline`
|
||||
- `office.get_selection`
|
||||
- `office.replace_selection`
|
||||
- `mindmap.apply_ops`
|
||||
- `system.get_recent_commands`
|
||||
|
||||
也可以对外映射为 MCP 风格扁平命名,但内核层建议保留层级语义。
|
||||
|
||||
## 8.3 Tool 与 Command/Query 的映射
|
||||
|
||||
例如:
|
||||
|
||||
- `note.read_page` -> `page.get`
|
||||
- `note.insert_block` -> `insert_block`
|
||||
- `note.search` -> `search.text`
|
||||
- `asset.attach_file` -> `attach_asset`
|
||||
- `mindmap.apply_ops` -> `apply_mindmap_ops`
|
||||
|
||||
### 8.4 Tool 返回
|
||||
|
||||
建议统一包含:
|
||||
|
||||
- `ok`
|
||||
- `data`
|
||||
- `warnings`
|
||||
- `requires_confirmation`
|
||||
- `confirmation_reason`
|
||||
- `next_actions`
|
||||
|
||||
例如:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"data": {
|
||||
"page_id": "page_1",
|
||||
"title": "项目计划"
|
||||
},
|
||||
"warnings": [],
|
||||
"requires_confirmation": false,
|
||||
"next_actions": []
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Job / Workflow API
|
||||
|
||||
有些操作不是同步命令,而是长任务。
|
||||
|
||||
例如:
|
||||
|
||||
- 导入大型 PDF
|
||||
- OCR
|
||||
- 构建索引
|
||||
- 批量转换文档
|
||||
- Office 文件解析
|
||||
- 全库引用修复
|
||||
- AI 长链路整理
|
||||
|
||||
因此需要 `Job API`:
|
||||
|
||||
### 9.1 Job 通用结构
|
||||
|
||||
```json
|
||||
{
|
||||
"job": "import_document",
|
||||
"job_id": "job_1",
|
||||
"actor": { "type": "agent", "id": "agent_1" },
|
||||
"input": {
|
||||
"asset_id": "asset_1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 Job 状态
|
||||
|
||||
- `queued`
|
||||
- `running`
|
||||
- `waiting_confirmation`
|
||||
- `succeeded`
|
||||
- `failed`
|
||||
- `cancelled`
|
||||
|
||||
### 9.3 Job 输出
|
||||
|
||||
- 结果对象
|
||||
- 生成的 page / asset / reference
|
||||
- 日志摘要
|
||||
- 错误详情
|
||||
|
||||
---
|
||||
|
||||
## 10. Confirmation Policy
|
||||
|
||||
不是所有工具都应直接执行。
|
||||
|
||||
建议分级:
|
||||
|
||||
### 10.1 无需确认
|
||||
|
||||
- 只读查询
|
||||
- 本地摘要生成
|
||||
- 小范围插入草稿块
|
||||
|
||||
### 10.2 建议确认
|
||||
|
||||
- 批量删除
|
||||
- 批量重排
|
||||
- 覆盖资产版本
|
||||
- 导出到外部位置
|
||||
|
||||
### 10.3 强制确认
|
||||
|
||||
- 大范围页面删除
|
||||
- 全库重建/迁移
|
||||
- 覆盖性导入
|
||||
- 对外同步/发布
|
||||
|
||||
确认策略应由内核或 policy 层判断,不能完全由前端决定。
|
||||
|
||||
---
|
||||
|
||||
## 11. Error Model
|
||||
|
||||
错误必须结构化。
|
||||
|
||||
建议格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": false,
|
||||
"error": {
|
||||
"code": "BLOCK_NOT_FOUND",
|
||||
"message": "目标块不存在",
|
||||
"details": {
|
||||
"block_id": "block_xxx"
|
||||
},
|
||||
"retryable": false,
|
||||
"suggested_action": "请先刷新页面树或重新读取块子树"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
分类建议:
|
||||
|
||||
- `VALIDATION_ERROR`
|
||||
- `PERMISSION_DENIED`
|
||||
- `NOT_FOUND`
|
||||
- `CONFLICT`
|
||||
- `STALE_REVISION`
|
||||
- `RATE_LIMITED`
|
||||
- `EXTERNAL_ADAPTER_ERROR`
|
||||
- `INTERNAL_ERROR`
|
||||
|
||||
这样 AI 才能根据错误做下一步,而不是只看到一段字符串。
|
||||
|
||||
---
|
||||
|
||||
## 12. Revision / Concurrency
|
||||
|
||||
### 12.1 为什么必须有 revision
|
||||
|
||||
AI 与人可能同时修改。
|
||||
|
||||
如果没有 revision:
|
||||
|
||||
- 很容易覆盖彼此内容
|
||||
- 工具重试会写乱
|
||||
- 无法做冲突判断
|
||||
|
||||
### 12.2 建议
|
||||
|
||||
- `Page` 级 revision
|
||||
- `Block` 级 revision
|
||||
- `AssetVersion` 级 version_no
|
||||
|
||||
命令可支持:
|
||||
|
||||
- `expected_revision`
|
||||
- `on_conflict` 策略(fail / merge_if_possible / create_patch)
|
||||
|
||||
---
|
||||
|
||||
## 13. OnlyOffice 协议边界
|
||||
|
||||
OnlyOffice 不应直接暴露为“让 AI 操控 iframe”。
|
||||
|
||||
建议拆成两层:
|
||||
|
||||
### 13.1 Office Adapter Query
|
||||
|
||||
- `office.get_active_asset`
|
||||
- `office.get_selection`
|
||||
- `office.get_current_page`
|
||||
- `office.list_bookmarks`
|
||||
|
||||
### 13.2 Office Adapter Command
|
||||
|
||||
- `office.insert_text`
|
||||
- `office.replace_selection`
|
||||
- `office.insert_comment`
|
||||
- `office.save_as_new_version`
|
||||
- `office.extract_outline`
|
||||
|
||||
原则:
|
||||
|
||||
- Tool 面暴露的是“Office 文档能力”
|
||||
- 不是浏览器点击坐标或 iframe DOM
|
||||
- 若插件不可用,应返回结构化不可用错误
|
||||
|
||||
---
|
||||
|
||||
## 14. Mindmap 协议边界
|
||||
|
||||
继续保留既有设计里最有价值的部分:`ops`。
|
||||
|
||||
建议:
|
||||
|
||||
- `mindmap.get`
|
||||
- `mindmap.apply_ops`
|
||||
- `mindmap.expand_node`
|
||||
- `mindmap.attach_refs`
|
||||
|
||||
其中 `mindmap.apply_ops` 入参可以继续沿用:
|
||||
|
||||
- `addChild`
|
||||
- `addSiblingAfter`
|
||||
- `updateText`
|
||||
- `setHyperlink`
|
||||
- `setRefs`
|
||||
- `appendNote`
|
||||
- `deleteNode`
|
||||
|
||||
但要求:
|
||||
|
||||
- 所有调用都写入统一命令日志
|
||||
- mindmap 不再走单独一套野生落盘体系
|
||||
|
||||
---
|
||||
|
||||
## 15. CLI 协议面
|
||||
|
||||
CLI 不是开发附属品,而是系统正式壳层。
|
||||
|
||||
建议 CLI 优先覆盖:
|
||||
|
||||
- `mnote page get <page-id>`
|
||||
- `mnote page tree`
|
||||
- `mnote block insert`
|
||||
- `mnote block move`
|
||||
- `mnote search text`
|
||||
- `mnote asset attach`
|
||||
- `mnote office selection`
|
||||
- `mnote job run import-document`
|
||||
- `mnote log recent`
|
||||
|
||||
CLI 应满足:
|
||||
|
||||
- 输出 JSON 模式
|
||||
- 退出码稳定
|
||||
- 适合 shell / AI / 自动化脚本调用
|
||||
|
||||
---
|
||||
|
||||
## 16. MCP / Agent Runtime 暴露面
|
||||
|
||||
如果后续提供 MCP:
|
||||
|
||||
- MCP 工具层应直接包装 Tool API
|
||||
- 不应重新发明一套独立业务逻辑
|
||||
- 返回值尽量和 CLI JSON 输出接近
|
||||
|
||||
这样好处是:
|
||||
|
||||
- Web agent、桌面 agent、本地 Hermes/Codex 都共用一套系统能力
|
||||
- 文档里只需维护一份工具协议
|
||||
|
||||
---
|
||||
|
||||
## 17. 最小 v0 清单
|
||||
|
||||
建议 v0 最先固化以下协议:
|
||||
|
||||
### Command
|
||||
- `create_page`
|
||||
- `rename_page`
|
||||
- `insert_block`
|
||||
- `update_block`
|
||||
- `delete_block`
|
||||
- `move_block`
|
||||
- `attach_asset`
|
||||
- `create_reference`
|
||||
|
||||
### Query
|
||||
- `page.get`
|
||||
- `page.tree`
|
||||
- `block.subtree`
|
||||
- `search.text`
|
||||
- `asset.get`
|
||||
- `command_log.list`
|
||||
|
||||
### Tool
|
||||
- `note.read_page`
|
||||
- `note.insert_block`
|
||||
- `note.update_block`
|
||||
- `note.move_block`
|
||||
- `note.search`
|
||||
- `asset.attach_file`
|
||||
- `system.get_recent_commands`
|
||||
|
||||
这套足以先打通:
|
||||
|
||||
- 人类基础编辑
|
||||
- CLI 基础操作
|
||||
- AI 基础介入
|
||||
- 审计与回放链路
|
||||
|
||||
---
|
||||
|
||||
## 18. 一句话结论
|
||||
|
||||
`mnote-rust` 的协议设计应坚持:
|
||||
|
||||
> **Command 负责改,Query 负责读,Tool 负责给 AI/CLI 用,Job 负责长流程;所有入口最终收敛到同一 Rust 内核,不再允许页面私有接口、编辑器私有接口、临时胶水接口长期并存。**
|
||||
Reference in New Issue
Block a user