chore: land tree view-state, vault, Pi module split, and repo hygiene
Persist PageTree expand state via control-plane view-state and align chevron/DOM with restored expansion; keep Sidex-style shallow page-tree scan and drop the unused recursive scanner that only added cargo noise. Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi into a module package, and retire Hermes/ACP/OpenHub recycle + root harness evidence from the index while gitignoring recycle and local diag dumps. Archive superseded design/bugs docs under old/, point architecture at ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor regressions so the working tree can stay clean.
This commit is contained in:
@@ -0,0 +1,708 @@
|
||||
# [recycle] 7-12 [reference] 页面 AI Hermes 工具路由与编辑审阅面设计 v1
|
||||
|
||||
> 更新时间:2026-05-19
|
||||
>
|
||||
> 当前状态:`reference / frozen`
|
||||
>
|
||||
> 归档说明(2026-05-22):本文保留 Hermes 工具路由、manifest 和 review surface 的设计边界;Phase C Review Mode 继续冻结。`7-14` 已移入 `design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`,当前 active AI 编辑口径以 `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md` 为准。
|
||||
>
|
||||
> 本稿目的:修正“页面 AI 快速块编辑”后续方向,明确 mnote 不再建设独立 AI agent runtime;mnote 只建设 Hermes 可消费的编辑工具路由、工具 manifest、上下文冻结、dry-run/review 和 Rust 写入安全边界。
|
||||
>
|
||||
> 关联文档:
|
||||
> - `/mnt/Data1T/mnote/design/10-review/done/09-page-ai-fast-block-edit-runtime-review.md`
|
||||
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-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/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/cli-main`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/blocknote-ai`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/tiptap-apcore`
|
||||
|
||||
---
|
||||
|
||||
## 0. 2026-05-18 状态更新
|
||||
|
||||
本稿仍作为 Hermes 工具路由与审阅面设计保留在 `process/`,但以下口径已经更新:
|
||||
|
||||
- `/api/page-ai/block-edit-workflow` 当前不再以 `local_rule -> apply_block_ops` 作为主路径;local-first 普通 Markdown 编辑默认给 Hermes / Reasonix 授权文件引用,由 agent 使用自身 patch / diff / 文件编辑能力写本地 `.md`。
|
||||
- `mnote.doc.markdown_edit` 不再作为 local-first 默认、fallback 或 remote fallback;本文后续出现的 `markdown_edit` 只代表历史 tool / review surface 证据,不指导新 agent 文件编辑主路径。当前 active 口径见 `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`。
|
||||
- `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。
|
||||
- 当前已闭合缺陷见 `bugs/07-ai/done/7-18` 到 `7-25`。
|
||||
|
||||
### 0.1 2026-05-21 Batch J 状态更新
|
||||
|
||||
- profile disabled tool list 已在 `/api/hermes/client/tools` listing、前端 UI、`execute_mnote_tool_call()` guard 三处同源,均读取 Hermes profile YAML 的 `mnote.tools.disabled`。
|
||||
- `capabilityScope` 已由 `7-34` 接入 `execute_mnote_tool_call()` 中心校验:缺省 scope 兼容旧调用方,显式声明但不足时拒绝执行;写 scope 可覆盖同前缀 read scope。
|
||||
- `is_read_tool()` 仍是硬编码读工具列表;它与 manifest annotations 的同源化属于维护性缺口,后续可随 capabilityScope 校验一起处理。
|
||||
- Phase C Review Mode 继续冻结,不因 `dryRun` / changedBlocks 已可用而提前实现新的审阅 UI。
|
||||
|
||||
## 1. 本轮结论
|
||||
|
||||
页面 AI 编辑卡顿的根因不是“Rust apply 慢”,而是模型和工具之间缺少稳定、低歧义、可审计的编辑命令面:
|
||||
|
||||
```text
|
||||
用户说一句自然语言
|
||||
-> Hermes/模型需要猜:读哪个范围、改哪个块、调用哪个工具、如何传参
|
||||
-> 如果猜错 blockId 或工具参数,mnote 再 fallback / 重跑 / 整页写入
|
||||
-> 用户感知为慢、卡、偶发失败
|
||||
```
|
||||
|
||||
正确方向不是再造一个 mnote 自有 AI runtime,而是:
|
||||
|
||||
> **Hermes 继续作为唯一页面 AI agent runtime;mnote 提供 Agent-native editor command layer。**
|
||||
|
||||
**新增(2026-05-16,按 7-14)**:AI 编辑的主路径应降维到 markdown 文本层。`mnote.doc.markdown_edit`(搜索替换文本对)是 AI 写入的主入口,覆盖 80%+ 场景;`mnote.block.*` 保留为结构性辅助。在线 Convex 文档和本地 `.md` 文件通过 `mnote.doc.fetch(format: "markdown")` + `mnote.doc.markdown_edit` 共用同一条 AI 写入路径。
|
||||
|
||||
因此,`本地意图解析 + Rust apply` 必须被重新定义为:
|
||||
|
||||
- Hermes 的工具路由提示层。
|
||||
- 低风险确定性编辑的本地 shortcut。
|
||||
- Rust 写工具的参数校验和执行面。
|
||||
- review/dry-run/session 的安全边界。
|
||||
|
||||
它不是:
|
||||
|
||||
- 第二套对话 runtime。
|
||||
- 第二套 agent tool loop。
|
||||
- 绕过 Hermes profile/tool toggle/audit 的长期写入口。
|
||||
- 让模型直接产 operations 并立刻写入的通用方案。
|
||||
|
||||
---
|
||||
|
||||
## 2. 现有问题
|
||||
|
||||
### 2.1 `/api/page-ai/block-edit-workflow` 方向需要收口
|
||||
|
||||
**当前口径修正(2026-05-16,按 7-14)**:
|
||||
|
||||
- `direct_block_edit_operations`(正则抠「」内文本的快路径)应退役。这不是 AI,是命令行。
|
||||
- `/api/page-ai/block-edit-workflow` 底层应切换到 `mnote.doc.markdown_edit`:用户自然语言 → 模型产出 search/replace 文本对 → markdown_edit apply。
|
||||
- 不再维持 direct path / model fallback 双路径,markdown_edit 是唯一主路径。
|
||||
|
||||
当前 route 对低歧义中文的加速效果不应成为保留一条非 AI 路径的理由。快路径作为 deterministic shortcut 的定位不变,但其实现必须改为调用 `mnote.doc.markdown_edit`,而不是绕过模型直接拼 operations。
|
||||
|
||||
### 2.2 模型直接输出 operations 仍不可靠
|
||||
|
||||
`09-page-ai-fast-block-edit-runtime-review.md` 已记录失败案例:模型输出了 operations,但 block 定位没有命中 Page Aggregate projection,最终触发 fallback 并拉长耗时。
|
||||
|
||||
长期规则应改为:
|
||||
|
||||
- 模型可以建议工具调用。
|
||||
- 模型可以输出候选 operations。
|
||||
- mnote 必须用 Page Aggregate projection 解析、校验、dry-run。
|
||||
- blockId、revisionRef、allowedTargetBlockIds、editable、scope 必须由 mnote 校验。
|
||||
- 未通过校验不能隐式 fallback 到整页写或另一次 agent run。
|
||||
|
||||
### 2.3 当前工具面还缺少 `cli-main` 式 agent 合同
|
||||
|
||||
`cli-main` 的关键价值是把平台能力压成 Agent 可靠调用的命令面:
|
||||
|
||||
- shortcut / API / generic 三层调用。
|
||||
- `--dry-run` 预览真实请求。
|
||||
- `Risk: high-risk-write` 与 `confirmation_required`。
|
||||
- structured error / hint。
|
||||
- skill 文档指导 agent 何时调用什么。
|
||||
- event consume 的 schema、ready marker、bounded run。
|
||||
|
||||
mnote 当前已有 Hermes tool manifest,但还需要把 manifest 提升为 Hermes/model 可直接消费的编辑合同,而不是只做 UI 列表。
|
||||
|
||||
---
|
||||
|
||||
## 3. 设计原则
|
||||
|
||||
### 3.1 单一 agent runtime
|
||||
|
||||
```text
|
||||
Hermes owns:
|
||||
session / message / model / tool loop / streaming / usage / profile / memory / skill
|
||||
|
||||
mnote owns:
|
||||
Page Aggregate / tool manifest / context snapshot / validation / Rust command / audit / readback
|
||||
```
|
||||
|
||||
页面 AI 面板只是 Hermes 的页面内客户端;mnote 不再新增独立 agent 编排中心。
|
||||
|
||||
### 3.2 本地层只做“路由和校验”
|
||||
|
||||
本地层可以做:
|
||||
|
||||
- 判断是不是低歧义块编辑。
|
||||
- 生成 `recommendedToolCall`。
|
||||
- 附带 `confidence`、`risk`、`requiresReview`。
|
||||
- 生成 `allowedTargetBlockIds`。
|
||||
- 做 dry-run、validate、readback。
|
||||
|
||||
本地层不能做:
|
||||
|
||||
- 自己维护长期对话状态。
|
||||
- 自己成为默认模型调用链。
|
||||
- 自己绕过 Hermes tool manifest 和 profile 开关。
|
||||
- 自己吞掉工具错误并隐式改走其他写入口。
|
||||
|
||||
### 3.3 所有写入都通过 Rust-owned mnote tools
|
||||
|
||||
写工具必须满足:
|
||||
|
||||
- `dryRun` 显式传入。
|
||||
- `idempotencyKey` 显式传入。
|
||||
- `revision/conflictDetectionKey/revisionRef` 或等价冲突键参与校验。
|
||||
- `allowedTargetBlockIds` 限制 selection / scoped run。
|
||||
- 返回 `diff/warnings/risk/blocked/changedBlocks/audit`。
|
||||
- 写入后通过 Page Aggregate 和 `mnote.doc.fetch` 回读验证。
|
||||
|
||||
### 3.4 快路径是 shortcut,不是 runtime
|
||||
|
||||
低歧义场景可以保留快路径,但必须改口径:
|
||||
|
||||
```text
|
||||
PageAICommandRouter
|
||||
-> recommendedToolCall
|
||||
-> direct tool shortcut 或 Hermes run with tool hint
|
||||
-> shared mnote tool executor
|
||||
-> shared audit/readback
|
||||
```
|
||||
|
||||
如果走 direct tool shortcut,也必须产生 Hermes-compatible tool event / audit 语义,避免 UI 与历史记录断裂。
|
||||
|
||||
---
|
||||
|
||||
## 4. 总体架构
|
||||
|
||||
```text
|
||||
Browser Page AI panel
|
||||
-> PageAIContextBuilder
|
||||
-> MnoteAIToolManifestProvider
|
||||
-> PageAICommandRouter
|
||||
-> deterministic shortcut? ---- yes -> MnoteToolExecutor
|
||||
| -> PageAIReviewSession/readback
|
||||
no
|
||||
-> Hermes run request with:
|
||||
- frozen page context
|
||||
- tool manifest
|
||||
- recommendedToolCall hint
|
||||
- risk/review policy
|
||||
-> Hermes tool loop
|
||||
-> /api/hermes/tools/mnote/call
|
||||
-> Rust mnote tools
|
||||
-> PageAIReviewSession/readback
|
||||
```
|
||||
|
||||
这里 `PageAICommandRouter` 不是 agent,只是类似 `cli-main` shortcut 的工具路由器。
|
||||
|
||||
---
|
||||
|
||||
## 5. 组件设计
|
||||
|
||||
### 5.1 `PageAIContextBuilder`
|
||||
|
||||
职责:
|
||||
|
||||
- 从 Page Aggregate block projection 构建冻结上下文。
|
||||
- 支持 `scope=full/outline/block/selection/keyword`。
|
||||
- 输出 `text/page_xml/json` 三种视图。
|
||||
- 生成 `allowedTargetBlockIds`。
|
||||
- 记录 `revision/conflictDetectionKey/revisionRef`。
|
||||
- 大页面默认裁剪,返回 `truncated/warnings/continuation`。
|
||||
|
||||
输出示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "mnote.page_ai_context.v1",
|
||||
"workspaceId": "tree_workspace",
|
||||
"documentId": "tree_doc",
|
||||
"scope": "selection",
|
||||
"revision": 12,
|
||||
"conflictDetectionKey": "body:12:hash",
|
||||
"allowedTargetBlockIds": ["p_1", "p_2"],
|
||||
"selectedBlockIds": ["p_1", "p_2"],
|
||||
"pageText": "第一段\n第二段",
|
||||
"pageXml": "<page id=\"tree_doc\" revision=\"12\"><block id=\"p_1\">第一段</block></page>",
|
||||
"blocks": [
|
||||
{
|
||||
"blockId": "p_1",
|
||||
"type": "paragraph",
|
||||
"text": "第一段",
|
||||
"revisionRef": "body:12:p_1",
|
||||
"editable": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 `MnoteAIToolManifestProvider`
|
||||
|
||||
职责:
|
||||
|
||||
- 从 Rust Hermes tool manifest 输出当前页面可用工具。
|
||||
- 合并 profile tool toggle、capability、scope、document permissions。
|
||||
- 输出 Hermes/model 可直接使用的 tool schema。
|
||||
- 输出风险和审批语义。
|
||||
|
||||
工具 manifest 必须包含:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "mnote.doc.apply_block_ops",
|
||||
"description": "Apply validated block operations to the current mnote document.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"required": ["operations", "dryRun", "idempotencyKey"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": {
|
||||
"readonly": false,
|
||||
"destructive": false,
|
||||
"idempotent": false,
|
||||
"requiresApproval": true,
|
||||
"approvalMode": "review",
|
||||
"selectionEffect": "destroy",
|
||||
"runtimeOwner": "mnote-web",
|
||||
"writeOwner": "rust-runtime-kernel"
|
||||
},
|
||||
"availability": {
|
||||
"enabled": true,
|
||||
"unsupportedReason": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 `PageAICommandRouter`
|
||||
|
||||
替代当前继续扩大的 `block-edit-workflow` 概念。
|
||||
|
||||
**新增(2026-05-16,按 7-14)**:Router 的 `recommendedToolCall` 主输出改为 `mnote.doc.markdown_edit`(search/replace 文本对),块级 `mnote.doc.apply_block_ops` 仅在明确的结构性编辑场景(拖拽排序等)下推荐。
|
||||
|
||||
输入:
|
||||
|
||||
- 用户 prompt。
|
||||
- 冻结后的 `mnote.page_ai_context.v1`。
|
||||
- 当前 tool manifest。
|
||||
- 当前 profile / approval mode。
|
||||
|
||||
输出:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "mnote.page_ai_command_route.v1",
|
||||
"intent": "markdown_edit",
|
||||
"confidence": 0.94,
|
||||
"recommendedToolCall": {
|
||||
"toolName": "mnote.doc.markdown_edit",
|
||||
"args": {
|
||||
"operations": [
|
||||
{"search": "原文片段", "replace": "新文本"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"risk": "low",
|
||||
"requiresHermesRun": false,
|
||||
"requiresReview": false,
|
||||
"reason": "明确文本替换表达,目标文本唯一命中"
|
||||
}
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
- 默认推荐 `mnote.doc.markdown_edit`(search/replace 文本对,AI 不需要理解 blockId)。
|
||||
- 仅在明确的结构性编辑场景("把第三块拖到第一块后面")推荐 `mnote.doc.apply_block_ops`。
|
||||
- 不能为复杂改写、总结、跨页面直接生成写入。
|
||||
- 不能调用第二套长链模型;如需模型,交给 Hermes run。
|
||||
- 输出必须可被 Hermes 当作 tool hint 消费。
|
||||
|
||||
### 5.4 Hermes run hint 注入
|
||||
|
||||
当 `requiresHermesRun=true` 或 router 不确定时,页面 AI 发起 Hermes run,并附带:
|
||||
|
||||
```json
|
||||
{
|
||||
"pageContext": "mnote.page_ai_context.v1",
|
||||
"toolManifest": "mnote.ai_tool_manifest.v1",
|
||||
"toolHint": "mnote.page_ai_command_route.v1",
|
||||
"reviewPolicy": {
|
||||
"mode": "yolo|review|required",
|
||||
"defaultDryRun": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Hermes 仍负责:
|
||||
|
||||
- 选择模型。
|
||||
- 工具调用循环。
|
||||
- stream message / tool event。
|
||||
- abort/retry。
|
||||
- session persistence。
|
||||
|
||||
mnote 只负责工具结果和写入安全。
|
||||
|
||||
### 5.5 `PageAIReviewSession`
|
||||
|
||||
职责:
|
||||
|
||||
- 承接所有写工具 `dryRun=true` 或 `requiresApproval=true` 的结果。
|
||||
- 保存 plan/diff/warnings/risk/blocked。
|
||||
- 提供 accept/reject/retry/abort。
|
||||
- accept 时二次读取 Page Aggregate 并校验 revision。
|
||||
|
||||
状态:
|
||||
|
||||
```text
|
||||
draft
|
||||
planning
|
||||
previewing
|
||||
awaiting_user
|
||||
accepted
|
||||
rejected
|
||||
applying
|
||||
applied
|
||||
failed
|
||||
aborted
|
||||
stale
|
||||
```
|
||||
|
||||
第一阶段可以保留 yolo,但仍应让工具返回 review-compatible 数据结构,避免后续 UI 重写。
|
||||
|
||||
最小稳定合同:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "mnote.page_ai_review_session.v1",
|
||||
"sessionId": "review_01",
|
||||
"workspaceId": "tree_workspace",
|
||||
"documentId": "tree_doc",
|
||||
"runId": "run_01",
|
||||
"toolCallId": "tool_01",
|
||||
"traceId": "trace_01",
|
||||
"state": "awaiting_user",
|
||||
"mode": "review",
|
||||
"source": {
|
||||
"runtimeOwner": "mnote-web",
|
||||
"writeOwner": "rust-runtime-kernel",
|
||||
"toolName": "mnote.doc.markdown_edit"
|
||||
},
|
||||
"base": {
|
||||
"revision": 12,
|
||||
"conflictDetectionKey": "body:12:hash",
|
||||
"allowedTargetBlockIds": ["p_1"]
|
||||
},
|
||||
"proposal": {
|
||||
"format": "markdown",
|
||||
"operations": [
|
||||
{
|
||||
"op": "replace",
|
||||
"search": "旧文本",
|
||||
"replace": "新文本"
|
||||
}
|
||||
],
|
||||
"fullContent": null
|
||||
},
|
||||
"preview": {
|
||||
"dryRun": true,
|
||||
"changedBlocks": [
|
||||
{
|
||||
"blockId": "p_1",
|
||||
"before": "旧文本",
|
||||
"after": "新文本",
|
||||
"revisionRef": "pageRev:12:block:p_1"
|
||||
}
|
||||
],
|
||||
"diff": [],
|
||||
"warnings": [],
|
||||
"risk": "low",
|
||||
"blocked": false
|
||||
},
|
||||
"actions": {
|
||||
"accept": {
|
||||
"requiresFreshRevision": true,
|
||||
"requiresIdempotencyKey": true
|
||||
},
|
||||
"reject": true,
|
||||
"retry": {
|
||||
"allowed": true,
|
||||
"requiresNewToolCallId": true
|
||||
},
|
||||
"abort": true
|
||||
},
|
||||
"audit": {
|
||||
"createdAt": "2026-05-18T00:00:00Z",
|
||||
"createdBy": "actor_01"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
状态语义:
|
||||
|
||||
- `draft`:已创建 session,但尚未生成 dry-run preview。
|
||||
- `planning`:正在构造 tool args 或请求模型生成候选。
|
||||
- `previewing`:正在执行 `dryRun=true`。
|
||||
- `awaiting_user`:preview 已完成,等待 accept / reject / retry / abort。
|
||||
- `accepted`:用户已确认,等待正式 apply。
|
||||
- `rejected`:用户拒绝,本 session 不可再写入。
|
||||
- `applying`:accept 后正在正式写入。
|
||||
- `applied`:正式写入已完成,并已通过 Page Aggregate / `mnote.doc.fetch` 回读。
|
||||
- `failed`:preview 或 apply 失败,需保留 structured error / hint。
|
||||
- `aborted`:用户或系统中断,不能继续写入。
|
||||
- `stale`:accept 时 revision / conflictDetectionKey / revisionRef 过期,必须重新 preview,不能直接 apply。
|
||||
|
||||
动作约束:
|
||||
|
||||
- `accept` 必须重新读取 Page Aggregate,并校验 `revision/conflictDetectionKey/revisionRef`;过期时转 `stale`。
|
||||
- `accept` 必须提供新的或既有合法 `idempotencyKey`,重复提交必须 replay 同一结果。
|
||||
- `reject` 与 `abort` 不能产生写入。
|
||||
- `retry` 不能复用旧 `toolCallId` 伪装成同一次写入;必须生成新 proposal 或新 dry-run preview。
|
||||
- yolo 模式可以跳过 `awaiting_user` UI,但仍应生成同构的 review-compatible audit 数据。
|
||||
|
||||
---
|
||||
|
||||
## 6. 关键流程
|
||||
|
||||
### 6.1 低歧义块替换
|
||||
|
||||
```text
|
||||
用户:把「第二段」替换为「第二段已修改」
|
||||
-> ContextBuilder 冻结页面与 block ids
|
||||
-> CommandRouter 命中 direct_block_edit
|
||||
-> recommendedToolCall=mnote.doc.apply_block_ops
|
||||
-> dryRun validate 唯一命中
|
||||
-> yolo 模式:direct tool shortcut 正式 apply
|
||||
-> 记录 tool event/audit
|
||||
-> Page Aggregate readback
|
||||
```
|
||||
|
||||
验收:
|
||||
|
||||
- 不进入通用 Hermes agent run 也可以,但必须复用 mnote tool/audit/readback 语义。
|
||||
- 若非 yolo 模式,则停在 review session。
|
||||
|
||||
### 6.2 复杂自然语言改写
|
||||
|
||||
```text
|
||||
用户:把这段整理得更专业,并保留原意
|
||||
-> Router 无法确定操作
|
||||
-> Hermes run with context + manifest + hint
|
||||
-> Hermes 调 mnote.doc.fetch / block.fetch
|
||||
-> Hermes 调 mnote.doc.plan_update(dryRun=true)
|
||||
-> mnote 返回 review session draft
|
||||
-> 用户 accept 后 Rust apply
|
||||
```
|
||||
|
||||
验收:
|
||||
|
||||
- 模型不能直接改正文。
|
||||
- dry-run 不改变 Page Aggregate。
|
||||
- accept 时校验 revision。
|
||||
|
||||
### 6.3 selection 编辑
|
||||
|
||||
```text
|
||||
用户选中块 A/B:改成列表
|
||||
-> ContextBuilder 冻结 selectedBlockIds
|
||||
-> allowedTargetBlockIds=[A,B]
|
||||
-> 所有写工具自动带 allowedTargetBlockIds
|
||||
-> 写工具尝试修改 C 时 blocked=true
|
||||
```
|
||||
|
||||
验收:
|
||||
|
||||
- 用户后续改变选区不影响当前 run。
|
||||
- selection 外写入被阻断。
|
||||
|
||||
### 6.4 工具禁用
|
||||
|
||||
```text
|
||||
profile disabled mnote.block.fetch
|
||||
-> ToolManifestProvider 输出 enabled=false 或不输出该工具
|
||||
-> Router 不推荐该工具
|
||||
-> Hermes 直接调用仍被 /api/hermes/tools/mnote/call 拦截
|
||||
```
|
||||
|
||||
验收:
|
||||
|
||||
- UI 工具列表、Hermes manifest、后端执行拦截一致。
|
||||
|
||||
---
|
||||
|
||||
## 7. 与参考代码的吸收边界
|
||||
|
||||
### 7.1 `cli-main`
|
||||
|
||||
吸收:
|
||||
|
||||
- shortcut/API/generic 三层工具面。
|
||||
- dry-run 作为写入前置能力。
|
||||
- structured error/hint。
|
||||
- risk/confirmation_required。
|
||||
- skill 文档让 agent 不靠猜。
|
||||
- event/schema/ready marker 的 agent-friendly contract。
|
||||
|
||||
不吸收:
|
||||
|
||||
- 不复制 Go CLI 框架。
|
||||
- 不把 CLI 作为页面 AI 唯一执行面。
|
||||
- 不用命令行 prompt 作为 Web 审批 UI。
|
||||
|
||||
### 7.2 `blocknote-ai`
|
||||
|
||||
吸收:
|
||||
|
||||
- `DocumentStateBuilder` 的 selection/full context 分离。
|
||||
- `StreamToolsProvider` 的工具集合思想。
|
||||
- AI lifecycle:thinking / ai-writing / user-reviewing / error。
|
||||
- accept/reject/retry/abort 的交互形态。
|
||||
|
||||
不吸收:
|
||||
|
||||
- 不引入 `@blocknote/xl-ai` 运行时依赖。
|
||||
- 不复制 GPL/PROPRIETARY 代码。
|
||||
- 不让 BlockNote/ProseMirror suggestion 成为 mnote 事实源。
|
||||
|
||||
### 7.3 `tiptap-apcore`
|
||||
|
||||
吸收:
|
||||
|
||||
- tool schema。
|
||||
- annotations。
|
||||
- ACL / role。
|
||||
- query/content/destructive/selection/history 分类。
|
||||
- executor 前置检查。
|
||||
|
||||
不吸收:
|
||||
|
||||
- 不把 Tiptap command 作为长期写入事实源。
|
||||
- 不让浏览器 editor instance 直接持久化写入。
|
||||
|
||||
### 7.4 AI SDK / Context7 核验结论
|
||||
|
||||
可用方向:
|
||||
|
||||
- 用 schema/structured output 约束模型输出。
|
||||
- 用 tool calling 让模型选择工具。
|
||||
- 用 repair/validation 处理无效参数。
|
||||
- 工具执行结果必须由 mnote 校验后返回。
|
||||
|
||||
不可用方向:
|
||||
|
||||
- 不把 structured output 当最终写入结果。
|
||||
- 不让模型输出的 blockId 绕过 projection resolve。
|
||||
|
||||
---
|
||||
|
||||
## 8. 迁移计划
|
||||
|
||||
### Phase A:设计治理
|
||||
|
||||
- [x] 新增本文作为当前口径。
|
||||
- [x] `7-10` 继续作为执行 checklist。
|
||||
- [x] `7-11` 作为旧“自有 AI runtime”口径移入 `design/old/07-ai/process/`。
|
||||
|
||||
### Phase B:Manifest 合同收口
|
||||
|
||||
- [ ] `mnote.doc.*` / `mnote.block.*` manifest 输出完整 `inputSchema/outputSchema/annotations/availability`。
|
||||
- [ ] profile toggle、capability、scope 共同影响 manifest。
|
||||
- [ ] manifest 可直接转换为 Hermes/model tools。
|
||||
- [ ] 禁用工具在 manifest、UI、执行拦截三处一致。
|
||||
|
||||
### Phase C:`block-edit-workflow` 改造成 router
|
||||
|
||||
- [ ] 将 route 命名和返回 schema 改为 `mnote.page_ai_command_route.v1` 或新增等价 route。
|
||||
- [ ] 本地规则只输出 `recommendedToolCall`。
|
||||
- [ ] 低风险 yolo shortcut 走共享 mnote tool executor。
|
||||
- [ ] 非低风险或低置信度任务发起 Hermes run with tool hint。
|
||||
- [ ] 删除“模型 fallback 后再 Hermes agent run”的重复链路。
|
||||
|
||||
### Phase D:Review session
|
||||
|
||||
- [x] 定义 `mnote.page_ai_review_session.v1` 最小 schema 与状态机边界(2026-05-18 已补;Phase C UI 仍冻结)。
|
||||
- [ ] `mnote.doc.plan_update` 与 `mnote.doc.apply_block_ops dryRun=true` 返回 review-compatible draft。
|
||||
- [ ] 页面 AI UI 展示 diff/warnings/risk/blocked。
|
||||
- [ ] accept/reject/retry/abort 可用。
|
||||
- [ ] stale revision 被阻断。
|
||||
|
||||
### Phase E:状态与事件统一
|
||||
|
||||
- [ ] direct shortcut 和 Hermes run 都产生统一 tool event 形态。
|
||||
- [ ] 页面 AI 面板按 `runId/toolCallId/reviewSessionId` 聚合展示。
|
||||
- [ ] abort 不留下半写入正文。
|
||||
- [ ] 刷新后未提交 review session 不自动写入。
|
||||
|
||||
### Phase F:验收 smoke
|
||||
|
||||
- [ ] 低歧义替换:可 <1s 可见,且有 tool audit。
|
||||
- [ ] 复杂改写:进入 Hermes run,先 dry-run/review。
|
||||
- [x] selection 外写入:blocked。
|
||||
- [ ] 禁用工具:manifest 不推荐,后端仍拦截。
|
||||
- [ ] 旧 revision accept:stale。
|
||||
|
||||
2026-05-16 补充验收证据:
|
||||
|
||||
- `scripts/task-page-block-ai-context-format-smoke.js` 已验证 `mnote.doc.apply_block_ops dryRun=true` 携带 `allowedTargetBlockIds=["p_2"]` 时,尝试 replace `p_1` 会被 Rust mnote tool 拒绝。
|
||||
- 证据:`tmp/page-block-ai-context-format-smoke/mp8ddr4n.json`;错误路径为 HTTP `400`、`mnote_block_target_out_of_scope`。
|
||||
- 同一 smoke 还验证了 context / manifest 基础合同:`mnote.doc.fetch scope=selection format=page_xml/text`、`mnote.block.fetch format=page_xml/text`、manifest annotations 与 `mnote.page.save` 粗粒度兜底定位。
|
||||
- 边界:本证据不代表完整 review session、旧 revision accept、复杂改写或单个 `mnote.block.*` selection guard 已完成。
|
||||
|
||||
---
|
||||
|
||||
## 9. `7-10` 与 `7-11` 的处理结论
|
||||
|
||||
### 9.1 `7-10` 继续执行
|
||||
|
||||
`7-10` 是页面块 AI 工具执行 checklist,包含真实代码和 smoke 证据。它仍然有效,继续保留在:
|
||||
|
||||
```text
|
||||
design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md
|
||||
```
|
||||
|
||||
但后续执行必须按本文修正口径:
|
||||
|
||||
- `PageAIIntentParser` 读作 `PageAICommandRouter`。
|
||||
- `PageAIOperationPlanner` 读作 `recommendedToolCall` 构造器。
|
||||
- `PageAIOperationValidator` 继续有效,但归属 mnote tool executor / Rust validation。
|
||||
- `PageAIApplyController` 不应成为独立 runtime,改为 review session / tool executor / readback controller。
|
||||
- “不进入 Hermes run”只能表示 deterministic shortcut,不表示 mnote 新建了 agent runtime。
|
||||
|
||||
### 9.2 `7-11` 移入 old
|
||||
|
||||
`7-11` 的参考资料价值仍然成立,但标题和核心分层写成了“mnote 自有 AI 工具 runtime”。这会误导后续实现继续扩出第二套 runtime。
|
||||
|
||||
因此本轮将其移入:
|
||||
|
||||
```text
|
||||
design/old/07-ai/process/7-11-blocknote-tiptap-ai-reference-and-mnote-ai-tool-runtime-v1.md
|
||||
```
|
||||
|
||||
保留原因:
|
||||
|
||||
- 记录 BlockNote / Tiptap 参考取证。
|
||||
- 保留 GPL/PROPRIETARY 许可证边界。
|
||||
- 保留 selection/context/review 的参考价值。
|
||||
|
||||
不再作为当前执行口径;当前执行口径以本文为准。
|
||||
|
||||
---
|
||||
|
||||
## 10. 禁止项
|
||||
|
||||
- 不新增 mnote 自有 agent runtime。
|
||||
- 不把 `/api/page-ai/block-edit-workflow` 扩成通用 AI 编排中心。
|
||||
- 不让模型直接输出未经校验的 blockId 并写入。
|
||||
- 不绕过 Hermes profile/tool toggle/audit。
|
||||
- 不让前端 editor instance 直接执行正式持久化写入。
|
||||
- 不以 HTML / Tiptap JSON / ProseMirror position 作为长期 AI tool contract。
|
||||
- 不复制 BlockNote XL AI 或 GPL/PROPRIETARY 实现代码。
|
||||
- 不把 `mnote.page.save` 描述为精确块编辑主入口。
|
||||
|
||||
---
|
||||
|
||||
## 11. 成功标准
|
||||
|
||||
完成本文后,页面 AI 编辑应满足:
|
||||
|
||||
- 简单明确块编辑有低延迟 shortcut。
|
||||
- 复杂编辑仍走 Hermes agent runtime。
|
||||
- Hermes 不再盲猜工具和参数,而是拿到 mnote 提供的 context、manifest、tool hint。
|
||||
- 所有写入都能 dry-run、review、audit、readback。
|
||||
- 工具禁用、权限、scope、selection 与后端执行一致。
|
||||
- 设计文档不再鼓励建设第二套 AI runtime。
|
||||
@@ -0,0 +1,481 @@
|
||||
# [recycle] 7-17 [reference] ACP Session 与控制面账号作用域 / 分享合同 v1
|
||||
|
||||
> 创建时间:2026-05-18
|
||||
>
|
||||
> 当前状态:`reference / future`
|
||||
>
|
||||
> 归档说明(2026-05-21):本文冻结 ACP session 与控制面分享/账号作用域远期合同;当前只作为 future reference,不作为 MVP 后阶段 active implementation checklist。
|
||||
>
|
||||
> 2026-05-22 口径补充:本文标题中的 Convex 是历史控制面语境。当前默认控制面已由 Rust SQLite `control-plane` 承接;ACP/Hermes runtime session、auth、share grants、AI policy 默认不再依赖 Convex。下文涉及 Convex store 的内容只作为历史 / compat / sync replica 对照。
|
||||
>
|
||||
> 本稿目的:
|
||||
> 1. 明确 ACP session 必须绑定当前账号权限与控制面作用域,不能以内存态绕过权限。
|
||||
> 2. 冻结后续“复制会话 / 只读分享 / 多人共同会话”的产品语义,避免当前实现误扩。
|
||||
> 3. 区分 MNote 产品层 AI session 与 ACP Hermes / ACP Reasonix 执行层 session。
|
||||
> 4. 为后续项目基本完成后扩展共享能力预留 schema、API 和验证边界。
|
||||
>
|
||||
> 关联文档:
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/done/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/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`
|
||||
> - `/mnt/Data1T/mnote/recycle/design/07-ai/retired-http-hermes/`
|
||||
|
||||
---
|
||||
|
||||
## 0. 当前结论
|
||||
|
||||
ACP 默认主链已经替代旧 Hermes HTTP 主链,但这不意味着 ACP runtime session 可以成为产品层会话真相。
|
||||
|
||||
当前必须成立的规则:
|
||||
|
||||
- **Rust SQLite control-plane 持有产品层 AI session 的账号作用域真相;Convex 只作为历史 / compat / sync replica 对照,不应被写死成唯一真相。**
|
||||
- **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 是产品层会话对象,长期应该由控制面持有;当前默认控制面是 Rust SQLite control-plane,目标不是把消息全文和权限真相永久绑死在 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 默认路径下创建 SQLite control-plane runtime session 索引;Convex 仅保留显式 legacy compat。
|
||||
- `POST /api/hermes/client/runs` 创建 run 并默认持久化到 SQLite control-plane 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 时使用当前 SQLite control-plane auth/session 解析出的真实 user / actor 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 必须账号作用域写入 Rust SQLite control-plane;Convex 只作为显式 compat / sync replica。
|
||||
- 旧 Hermes HTTP 主链进入 `recycle`。
|
||||
- 不实现复制、分享、多人会话。
|
||||
- 文档与测试明确禁止内存降级绕过权限。
|
||||
|
||||
### Phase B:项目基本完成后,补产品层 session 表
|
||||
|
||||
目标:
|
||||
|
||||
- 增加 `ai_sessions` / `ai_session_members` / `ai_runtime_bindings`。
|
||||
- 将现有 `acp_runtime_runs` 从“运行态索引”升级为 session 下的 run 记录。
|
||||
- UI 从 localStorage 历史逐步迁到 Rust control-plane 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,不创建内存会话。
|
||||
@@ -0,0 +1,150 @@
|
||||
# [recycle] Reasonix Browser Test Contract v1
|
||||
|
||||
## 状态
|
||||
|
||||
- 状态:reference
|
||||
- Owner:AI runtime / browser verification
|
||||
- 背景:Reasonix 已能作为独立辅助 agent 执行只读审计,但浏览器验收若只输出自然语言结论,主控仍需重测,无法稳定节省 token。
|
||||
|
||||
## 目标
|
||||
|
||||
把 Reasonix 浏览器测试从“描述性结论”收口为“可审计证据包”。Codex/Hermes 主控只接受带截图、日志、网络、断言和环境前置条件的 Reasonix 浏览器结论。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不让 Reasonix 直接裁决业务 bug 是否完成。
|
||||
- 不让 Reasonix 修改源码、提交 git、回滚文件。
|
||||
- 不把浏览器测试结论写成长期产品事实源;长期事实仍以 bug/design/checklist 和真实验证日志为准。
|
||||
|
||||
## 合同
|
||||
|
||||
每个 Reasonix 浏览器测试任务必须产出以下文件:
|
||||
|
||||
```text
|
||||
result.json
|
||||
final.md
|
||||
process-handoff.md
|
||||
process-handoff.json
|
||||
artifacts/
|
||||
screenshots/
|
||||
console.json
|
||||
network.json
|
||||
trace-or-steps.md
|
||||
```
|
||||
|
||||
`result.json` 至少包含:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "passed | failed | blocked",
|
||||
"run_id": "reasonix-...",
|
||||
"target_url": "http://127.0.0.1:3000",
|
||||
"environment": {
|
||||
"dev_server_restarted": true,
|
||||
"cache_cleared": true,
|
||||
"browser_context": "isolated",
|
||||
"auth_mode": "test-account",
|
||||
"workspace_root": "/tmp/..."
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "upload first attachment",
|
||||
"action": "drag file into editor",
|
||||
"screenshot": "artifacts/screenshots/01-upload-first.png"
|
||||
}
|
||||
],
|
||||
"assertions": [
|
||||
{
|
||||
"name": "attachment opens in tab after second upload",
|
||||
"expected": "tab count increases and active tab kind is resource",
|
||||
"actual": "click produced no tab change",
|
||||
"passed": false,
|
||||
"evidence": "artifacts/screenshots/04-click-after-second-upload.png"
|
||||
}
|
||||
],
|
||||
"console_errors": [],
|
||||
"network_failures": [],
|
||||
"screenshots": [],
|
||||
"modified_files": []
|
||||
}
|
||||
```
|
||||
|
||||
## 浏览器前置条件
|
||||
|
||||
- 测试前重启 `npm run dev:hot` 或复用主控明确提供的已重启服务。
|
||||
- 使用全新 isolated browser context;清空 cookies、localStorage、sessionStorage、IndexedDB、Cache Storage。
|
||||
- 默认使用 `http://127.0.0.1:3000/auth` 的测试账号快速登录。
|
||||
- local-first 测试必须创建临时页面或临时 workspace,并记录路径。
|
||||
- 所有上传文件路径必须记录,不能只写“上传文件”。
|
||||
|
||||
## 截图要求
|
||||
|
||||
用户可见 bug 至少保留:
|
||||
|
||||
- 初始状态截图。
|
||||
- 关键动作后截图。
|
||||
- 失败状态截图。
|
||||
- 修复验证时的通过状态截图。
|
||||
|
||||
如果 bug 涉及 “点击无反应”,必须同时记录:
|
||||
|
||||
- 点击前 tab 列表。
|
||||
- 点击后 tab 列表。
|
||||
- 点击目标节点截图。
|
||||
- console/network。
|
||||
|
||||
## 0524 试验集映射
|
||||
|
||||
`bugs/0524.md` 可作为第一批协同测试样本:
|
||||
|
||||
1. 我的空间拖入附件路径错误:
|
||||
- 验收:上传后文件实际路径应在当前页面 bundle/下级,而不是与主文件夹同级。
|
||||
- Reasonix 输出:文件树截图、实际磁盘路径、上传请求、编辑区附件截图。
|
||||
2. 上传后文件冲突:
|
||||
- 验收:本页面不误报自写冲突;新建页面不继承旧冲突状态。
|
||||
- Reasonix 输出:冲突弹窗截图、页面切换后截图、console/network。
|
||||
3. 隐藏本地 Markdown 标题设置:
|
||||
- 验收:不同 workspace/source 的默认值区分,用户选择刷新后保持。
|
||||
- Reasonix 输出:设置变更前后截图、刷新后截图、local/session storage 或后端请求证据。
|
||||
4. Ctrl+Z/Ctrl+Y 删除链接:
|
||||
- 验收:删除附件链接后 undo/redo 可恢复/再次删除。
|
||||
- Reasonix 输出:键盘动作步骤、编辑区 DOM/截图、断言结果。
|
||||
5. md 文件上传后黑色方块刷新变灰:
|
||||
- 验收:上传前后和刷新后附件 icon 状态一致,或有明确缺失状态样式。
|
||||
- Reasonix 输出:刷新前后截图、附件节点属性。
|
||||
|
||||
## 主控接受条件
|
||||
|
||||
Codex/Hermes 只有在以下条件满足时,才能把 Reasonix 浏览器结果作为验收证据:
|
||||
|
||||
- `result.json` 存在且能解析。
|
||||
- 至少一张截图能直接显示用户可见状态。
|
||||
- console/network 不为空时已被解释;为空时明确记录为空。
|
||||
- `modified_files` 为 `[]` 或 `none`,确认 Reasonix 没有改源码。
|
||||
- `process-handoff` 已 retain 到 Hindsight,主控可 recall。
|
||||
|
||||
## 失败处理
|
||||
|
||||
- 缺截图:结果降级为线索,不作为验收。
|
||||
- 缺 console/network:UI 失败只可作为复现证据,不可作为根因证据。
|
||||
- 没清缓存或没隔离 browser context:结果标记 `blocked` 或 `needs_rerun`。
|
||||
- Reasonix 修改源码:本次测试作废,主控检查 diff 后决定是否保留建议。
|
||||
|
||||
## 评价指标
|
||||
|
||||
- accepted_browser_findings:Reasonix 浏览器发现最终被主控采纳的数量。
|
||||
- false_browser_leads:Reasonix 浏览器结论导致主控走错方向的数量。
|
||||
- retest_required_ratio:主控必须完全重测的比例。
|
||||
- artifact_read_time:主控读取证据包并形成判断所需时间。
|
||||
- missing_artifact_count:缺失截图、console、network、断言的数量。
|
||||
|
||||
## Done Gate
|
||||
|
||||
- [ ] `reasonix-browser-tester` skill 已补入本合同的最小 artifact 要求。
|
||||
- [ ] 使用 `bugs/0524.md` 中至少 1 个 bug 进行 Reasonix 浏览器试跑。
|
||||
- [ ] 试跑后记录 accepted findings / false leads / retest required。
|
||||
- [ ] 根据试跑结果更新本合同或 Reasonix skill。
|
||||
|
||||
## 2026-06-01 降级说明
|
||||
|
||||
本合同对应的全局 `reasonix-browser-tester` skill 已存在,并已包含 `result.json`、截图、console/network、isolated context、`modified_files` 等 artifact 要求。本文不再作为 MNote 产品 runtime 的 active process 项,降级为协作参考;后续若要继续试跑 `bugs/0524.md`,应在 Reasonix skill 维护流程或独立复盘文档中跟踪。
|
||||
@@ -0,0 +1,150 @@
|
||||
# [recycle] Reasonix Skill Maintainer v1
|
||||
|
||||
## 状态
|
||||
|
||||
- 状态:reference
|
||||
- Owner:AI runtime / multi-agent collaboration
|
||||
- 背景:Hindsight 解决了 Reasonix 过程可追溯问题,但不能自动让 Reasonix 下一次更好。需要一个主控驱动的最小自进化机制,由 Codex/Hermes 根据真实 run 修改 Reasonix skill、任务模板和 handoff 合同。
|
||||
|
||||
## 目标
|
||||
|
||||
建立“真实任务 -> 复盘 -> 修改 Reasonix skill/模板 -> 小 smoke -> 再试跑”的闭环,让 Reasonix 从通用辅助逐步变成可审计、低噪声、能节省主控 token 的 worker。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不让 Reasonix 自主修改自己的 skill。
|
||||
- 不照搬 Hermes 的完整自进化机制。
|
||||
- 不把一次失败就提升为长期规则。
|
||||
- 不修改项目 `AGENTS.md`,除非用户明确要求。
|
||||
|
||||
## 角色边界
|
||||
|
||||
- Codex/Hermes:主控,负责判断哪些协作缺陷值得固化为 skill 规则。
|
||||
- Reasonix:被维护的 worker,负责执行明确任务。
|
||||
- Hindsight:热记忆,保存过程 handoff 和协作复盘。
|
||||
- MemPalace:冷归档,保存长期可检索的会话摘要。
|
||||
|
||||
## 输入
|
||||
|
||||
每次维护 Reasonix skill 前,主控必须先读取:
|
||||
|
||||
- Reasonix run 输出目录:
|
||||
- `result.json`
|
||||
- `process-handoff.json`
|
||||
- `process-handoff.md`
|
||||
- `final.md`
|
||||
- 必要时 `reasonix-transcript.jsonl`
|
||||
- Hindsight recall:
|
||||
- `hindsight-embed -p agents memory recall reasonix "<run-id 或任务关键词>"`
|
||||
- 当前相关 skill:
|
||||
- `reasonix-coding-worker`
|
||||
- `reasonix-browser-tester`
|
||||
- `reasonix-parallel-coding-flow`
|
||||
- 新增 `reasonix-skill-maintainer`
|
||||
|
||||
## 复盘维度
|
||||
|
||||
每个 Reasonix run 至少评估:
|
||||
|
||||
- accepted_findings:被主控采纳的关键发现数。
|
||||
- false_leads:误导主控的判断数。
|
||||
- missing_evidence:缺失证据项。
|
||||
- verification_strength:是否有真实命令、截图、日志、网络、diff。
|
||||
- handoff_cleanliness:handoff 是否能快速读懂。
|
||||
- modified_files_accuracy:是否准确记录修改文件。
|
||||
- retest_required:主控是否必须完全重测。
|
||||
- token_saving_estimate:是否减少主控探索或验证成本。
|
||||
|
||||
## 维护决策
|
||||
|
||||
只有满足以下至少一项,才修改 Reasonix skill:
|
||||
|
||||
- 同类缺陷出现两次以上。
|
||||
- 单次缺陷导致主控明显走错方向。
|
||||
- 缺失 artifact 使浏览器结果无法验收。
|
||||
- `process-handoff` 的结构缺陷导致主控必须重读 transcript。
|
||||
- 用户明确指出 Reasonix 协同方式需要调整。
|
||||
|
||||
不应修改 skill 的情况:
|
||||
|
||||
- 只是单次措辞不佳。
|
||||
- 是当前任务本身不清楚,而不是 Reasonix 规则缺失。
|
||||
- 可通过更好的任务书解决,不需要变成长期规则。
|
||||
|
||||
## 修改范围
|
||||
|
||||
优先顺序:
|
||||
|
||||
1. 修改任务书模板:成本最低,适合单类任务。
|
||||
2. 修改 Reasonix skill:适合跨任务重复规则。
|
||||
3. 修改 runner/extractor schema:适合结构化输出缺陷。
|
||||
4. 修改 Codex/Hermes 主控 skill:适合复核顺序和验收口径。
|
||||
|
||||
每次只做最小修改,并记录:
|
||||
|
||||
- 修改前问题。
|
||||
- 修改文件。
|
||||
- 预期改善。
|
||||
- smoke 验证方式。
|
||||
|
||||
## Smoke 验证
|
||||
|
||||
修改 Reasonix skill 后,必须至少做一个轻量 smoke:
|
||||
|
||||
- 只读任务优先,不改业务代码。
|
||||
- 要求 Reasonix 产出新格式字段。
|
||||
- 主控检查字段是否存在、是否可解析、是否减少噪声。
|
||||
|
||||
浏览器类 smoke 应检查:
|
||||
|
||||
- 是否有截图路径。
|
||||
- 是否有 console/network 摘要。
|
||||
- 是否有 `cache_cleared`、`browser_context`。
|
||||
- 是否有 `assertions[]`。
|
||||
|
||||
## 0524 试跑计划
|
||||
|
||||
使用 `bugs/0524.md` 作为真实任务池,不一次性全交给 Reasonix:
|
||||
|
||||
1. 第一轮:只让 Reasonix 浏览器复现第 2 个 bug“上传后文件冲突”,不修代码。
|
||||
- 目标:验证 browser artifact contract 是否足够。
|
||||
2. 第二轮:让 Reasonix 只读审计第 1 个 bug“我的空间附件路径错误”。
|
||||
- 目标:验证 coding-worker handoff 是否能给出可采纳根因。
|
||||
3. 第三轮:Codex 修复其中一个 bug 后,让 Reasonix 做回归。
|
||||
- 目标:评估 Reasonix 是否能减少主控浏览器验证 token。
|
||||
|
||||
每轮都记录:
|
||||
|
||||
- Reasonix 耗时。
|
||||
- 主控读取 handoff 所需时间。
|
||||
- 主控是否重测。
|
||||
- 被采纳发现。
|
||||
- 误导点。
|
||||
- 需要修改的 skill 规则。
|
||||
|
||||
## 输出记录
|
||||
|
||||
建议每次维护后在对应 bug/design 中补一段:
|
||||
|
||||
```text
|
||||
Reasonix 协同复盘:
|
||||
- run id:
|
||||
- 任务类型:
|
||||
- accepted findings:
|
||||
- false leads:
|
||||
- missing artifacts:
|
||||
- skill changes:
|
||||
- next iteration:
|
||||
```
|
||||
|
||||
## Done Gate
|
||||
|
||||
- [ ] 创建 `reasonix-skill-maintainer` skill。
|
||||
- [ ] `reasonix-browser-tester` 已引用 browser artifact contract。
|
||||
- [ ] 用 `bugs/0524.md` 至少跑一轮真实 Reasonix 协同测试。
|
||||
- [ ] 根据真实结果更新 skill 或明确“不需要修改”。
|
||||
- [ ] 在 Hindsight / MemPalace 中保留协作复盘摘要。
|
||||
|
||||
## 2026-06-01 降级说明
|
||||
|
||||
全局 `reasonix-skill-maintainer` skill 已存在,并已要求读取 `result.json`、`process-handoff`、Hindsight recall,评估 `accepted_findings`、`false_leads`、`missing_evidence`、`retest_required` 和 `token_saving_estimate`。本文不再作为 MNote 产品 runtime 的 active process 项,降级为协作参考;后续真实 run 复盘直接走全局 skill。
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
# [recycle] 7-37 Claude Code / Reasonix Worker 评估协议:0524 Bug2 v1
|
||||
|
||||
## 目标
|
||||
|
||||
用 `bugs/0524.md` 第 2 条“本地 Markdown 上传/文件树拖入后误报文件冲突”作为真实任务,评估 Claude Code 与 Reasonix 作为 worker 的可用性:
|
||||
|
||||
1. 编码能力:是否能在相同基线下定位根因、做小范围修复、补测试并通过验证。
|
||||
2. 网页测试能力:是否能在真实浏览器中复现/验收,产出可审计截图、console、network 和结构化结论。
|
||||
|
||||
Codex 仍是主控,负责设计、派发、复核、合并和最终验收。
|
||||
|
||||
## 公平性约束
|
||||
|
||||
- 两个 coding worker 使用从同一 `HEAD` 创建的独立 worktree,不共享当前主工作区未提交改动。
|
||||
- 两个 coding worker 使用同一份任务书,允许修改范围一致,验收命令一致。
|
||||
- 两个 browser worker 对同一个主工作区修复结果做只读验证,不允许改源码。
|
||||
- 评分只基于可复核产物:diff、测试输出、process handoff、截图、console/network,不凭 final 文本。
|
||||
- 若 worker 卡住、超时、无 handoff、无截图或修改范围失控,按实际情况扣分,不手工补完其证据。
|
||||
|
||||
## Coding Worker 任务切片
|
||||
|
||||
输入:
|
||||
|
||||
- bug:`bugs/0524.md` 第 2 条。
|
||||
- 参考设计:`design/05-editor-mainline/process/5-27-local-markdown-working-copy-conflict-contract-v1.md`。
|
||||
- 允许修改:
|
||||
- `rust/crates/mnote-web/src/routes/web_shell.rs`
|
||||
- `rust/crates/mnote-web/src/routes/local_folder_events.rs`
|
||||
- `scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`
|
||||
- 必要时新增/更新同目录小测试
|
||||
- 禁止修改:无关设计、AGENTS、其它 bugs、git 提交、回滚用户改动。
|
||||
|
||||
验收:
|
||||
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web document_event_filter_rejects_resource_only_changes -- --nocapture`
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web document_shell_renders_local_markdown_with_same_sidebar_surfaces -- --nocapture`
|
||||
- `cargo fmt --manifest-path rust/Cargo.toml --all --check`
|
||||
- 若能启动浏览器 smoke,运行 `node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js` 并记录结果。
|
||||
|
||||
## Browser Worker 任务切片
|
||||
|
||||
输入:
|
||||
|
||||
- 被测主工作区当前修复结果。
|
||||
- 入口:`http://127.0.0.1:3000`。
|
||||
- 登录:`/auth` 的“测试账号快速登录”。
|
||||
|
||||
必须验证:
|
||||
|
||||
- 打开本地 Markdown 页面,上传附件后,不出现 `mnote-editor-conflict-panel`。
|
||||
- 新建/切换页面后,旧冲突面板不残留到新页面。
|
||||
- 向文件树文件夹拖入文件后,不出现 `external-change-conflict`。
|
||||
- 真实冲突路径仍可用:dirty 当前 Markdown 后外部修改同一 `.md` 文件,应显示冲突。
|
||||
|
||||
必须产出:
|
||||
|
||||
- `result.json`
|
||||
- `process-handoff.md/json`
|
||||
- 至少一张显示通过或失败状态的截图
|
||||
- console/network 摘要
|
||||
- `modified_files` 必须为空
|
||||
|
||||
## 评分维度
|
||||
|
||||
- `root_cause`:是否找到两个核心根因:document event 越界、冲突 DOM 残留。
|
||||
- `patch_scope`:是否只改必要文件,未引入架构外补丁。
|
||||
- `test_quality`:是否补了能失败/能防回归的测试。
|
||||
- `verification`:是否实际运行命令并记录输出。
|
||||
- `handoff_quality`:是否有过程证据,而不是只给最终摘要。
|
||||
- `latency_cost`:完成时间、工具调用量、是否卡住。
|
||||
- `mislead_risk`:错误假设、过度修改、把无关失败归因到本 bug 的风险。
|
||||
|
||||
## 初步观察
|
||||
|
||||
- Reasonix 只读分析较快完成,正确指出空 `documentId` 会污染 session,但对新建页时序有部分猜测,需要主控复核。
|
||||
- Claude Code 修复后本轮可产出 handoff,明确指出冲突面板 DOM 生命周期缺口;耗时更长,但对第二个根因帮助明显。
|
||||
- 后续需要用隔离 coding 任务和真实 browser 任务继续比较,而不是只比较只读分析。
|
||||
|
||||
## 0524 Bug2 本轮实测记录
|
||||
|
||||
### 主控基线
|
||||
|
||||
- 主控修复覆盖三个切片:
|
||||
- document event channel 从 `rootUri` 收窄到 `rootUri#documentId`。
|
||||
- 空 `documentId` 的资源事件不再进入正文冲突链路。
|
||||
- editor view unmount 清理旧 session 冲突面板 DOM。
|
||||
- 主控验证:
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web document_event_filter_rejects_resource_only_changes -- --nocapture`:通过。
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web document_shell_renders_local_markdown_with_same_sidebar_surfaces -- --nocapture`:通过。
|
||||
- `cargo fmt --manifest-path rust/Cargo.toml --all --check`:通过。
|
||||
- `node scripts/task451-local-markdown-conflict-resolution-ui-smoke.js`:通过,真实冲突仍可用。
|
||||
- `node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`:上传附件和文件树拖入 no-conflict 断言通过;后续 broken-link 检查失败,属于其它已知路径,不计入本 bug 修复失败。
|
||||
|
||||
### Coding Worker 对比
|
||||
|
||||
- Reasonix coding:
|
||||
- run id:`reasonix-2026-05-24T07-44-15-864Z-6898e686`。
|
||||
- worktree:`/mnt/Data1T/mnote-wt-0524b-reasonix-coding`。
|
||||
- 正确抓到空 `documentId` 事件污染正文 session。
|
||||
- 补了前端 `if (!documentId) return;` 和后端映射测试。
|
||||
- 漏掉冲突面板 DOM 残留,也没有做 `rootUri#documentId` channel 隔离。
|
||||
- 自报未跑 Playwright,适合作为“定位主因 + 小补丁”证据,不足以直接合并。
|
||||
- Claude Code coding:
|
||||
- run id:`claudecode-2026-05-24T07-44-15-975Z-e03aaf1f`。
|
||||
- worktree:`/mnt/Data1T/mnote-wt-0524b-claudecode-coding`。
|
||||
- 正确抓到空 `documentId` 事件污染。
|
||||
- 额外抓到冲突面板 DOM 生命周期问题。
|
||||
- 修复位置是 `releaseDocumentSession`,比主控采用的 `unmountEditorViewBinding` 更晚,仍可能存在切换瞬间残留风险。
|
||||
- 未做 `rootUri#documentId` channel 隔离,也未补 task479 no-conflict smoke。
|
||||
- 编码帮助大于 Reasonix,但仍需主控补边界。
|
||||
|
||||
### Browser Worker 对比
|
||||
|
||||
- Claude Code browser:
|
||||
- run id:`claudecode-2026-05-24T07-47-11-262Z-46f574f0`。
|
||||
- artifact:`/tmp/mnote-0524-bug2-browser-worker-1779608936242/`。
|
||||
- 产出 `result.json`、截图、console/network。
|
||||
- 上传附件 no-conflict、文件树拖入 no-conflict、dirty + 外部修改真实冲突均通过。
|
||||
- `modified_files=[]`。
|
||||
- 该轮可作为较高质量浏览器验收证据。
|
||||
- Reasonix browser:
|
||||
- run id:`reasonix-2026-05-24T07-47-11-249Z-43f061bb`。
|
||||
- artifact:`/tmp/mnote-0524-bug2-browser-worker-0524T0800/`。
|
||||
- 产出 `result.json`、截图、console/network。
|
||||
- 上传附件 no-conflict、文件树拖入 no-conflict 通过。
|
||||
- runner status 为 `error` / handoff status 为 `failed`,但 `result.json.status=passed`,状态合同不一致。
|
||||
- 将 `/api/local-folder/events` 500 判断为真实冲突阻塞;主控 `task451` 和 Claude Code browser 已证明真实冲突仍可验证,因此该判断有误导风险。
|
||||
- 可作为部分 UI 证据,但不能单独作为最终验收。
|
||||
|
||||
### 可审计性结论
|
||||
|
||||
- Hindsight recall 可召回本轮 Claude Code 与 Reasonix 过程 handoff,但 Reasonix recall 混入了无关项目结果,主控不能只看 recall 摘要。
|
||||
- Claude Code 的 browser artifact 更适合验收:`result.json`、截图路径、console/network、`modified_files=[]` 之间一致。
|
||||
- Reasonix 的 browser artifact 可作为辅助证据,但 runner `status=error` 与 artifact `status=passed` 冲突时,必须降级为线索。
|
||||
- 本轮公平测试说明:worker 能节省主控定位和浏览器操作 token,但不能替代主控做架构边界、diff 取舍和最终验收。
|
||||
|
||||
## 当前评分倾向
|
||||
|
||||
- 编码能力:Claude Code 略优,能补出 DOM 生命周期根因;Reasonix 更快但更像最小局部补丁。
|
||||
- 浏览器测试能力:Claude Code 本轮明显优于 Reasonix,证据更完整且能覆盖真实冲突;Reasonix 产物可审计但状态和结论自相矛盾。
|
||||
- 主控策略:以后可让 Reasonix 做低风险定位/快速 smoke,让 Claude Code 做更完整的 browser artifact;两者结论都必须由 Codex 复核 diff、截图和命令输出。
|
||||
@@ -0,0 +1,170 @@
|
||||
# [recycle] 7-68 WeKnora 知识库页面 UI 参考
|
||||
|
||||
状态:reference
|
||||
范围:只记录 WeKnora 知识库页面可嫁接的页面结构、状态与 MNote 字段映射;不修改 MNote runtime,不修改 WeKnora 源码。
|
||||
|
||||
## 结论
|
||||
|
||||
7-68 的知识库页不应继续保留 MNote 原来的简陋“知识库设置面板”形态。更合适的嫁接目标是复用 WeKnora 的“知识库列表 + 知识库详情文档管理页”体验:列表页提供知识库卡片、分组、上传进度和能力徽标;详情页提供面包屑、文档/ Wiki / 图谱页签、标签侧栏、文档筛选栏、网格/列表切换、上传入口、解析状态和批量管理。
|
||||
|
||||
MNote 应保留本地 source registry、allowed roots、workspace path、provider 映射和打开引用能力;WeKnora 页面结构只作为 UI / 交互参考,不直接接管 MNote 的事实源、鉴权、文件写入或索引生命周期。
|
||||
|
||||
## WeKnora 源文件
|
||||
|
||||
- `/mnt/Data1T/Mnote_data/weknora/WeKnora/frontend/src/views/knowledge/KnowledgeBaseList.vue`
|
||||
- 知识库列表页主入口。
|
||||
- 核心结构:`kb-list-container`、`ListSpaceSidebar`、标题区、未初始化提示、上传进度面板、知识库卡片网格、分组标题、收藏 / 置顶 / 设置 / 删除菜单、能力徽标。
|
||||
- `/mnt/Data1T/Mnote_data/weknora/WeKnora/frontend/src/views/knowledge/KnowledgeBase.vue`
|
||||
- 单个知识库详情页主入口。
|
||||
- 核心结构:`knowledge-layout`、面包屑 + `KBSwitcherDropdown`、`KBInfoPopover`、设置按钮、Documents / Wiki / Graph 页签、标签侧栏、文档筛选栏、文档卡片网格、列表视图、`DocContent` 抽屉。
|
||||
- `/mnt/Data1T/Mnote_data/weknora/WeKnora/frontend/src/views/knowledge/components/DocumentListView.vue`
|
||||
- 文档列表视图。
|
||||
- 核心结构:吸顶表头、复选框、多列 row、来源、大小、解析状态、更新时间、行菜单。
|
||||
- `/mnt/Data1T/Mnote_data/weknora/WeKnora/frontend/src/views/knowledge/components/KbUploadSourceDropdown.vue`
|
||||
- 添加文档入口。
|
||||
- 支持上传文件、上传文件夹、导入 URL,可选手动创建。
|
||||
- `/mnt/Data1T/Mnote_data/weknora/WeKnora/frontend/src/views/knowledge/components/DocumentBatchBar.vue`
|
||||
- 批量选择后的浮动操作条。
|
||||
- `/mnt/Data1T/Mnote_data/weknora/WeKnora/frontend/src/components/knowledge-processing-timeline.vue`
|
||||
- 解析 / 后处理 trace 时间线。
|
||||
- 显示 docreader、chunking、embedding、multimodal、postprocess 等阶段,以及 live polling、失败、取消和耗时。
|
||||
- `/mnt/Data1T/Mnote_data/weknora/WeKnora/frontend/src/components/empty-knowledge.vue`
|
||||
- 空知识库占位。
|
||||
- `/mnt/Data1T/Mnote_data/weknora/WeKnora/frontend/src/api/knowledge-base/index.ts`
|
||||
- API 字段参考:`listKnowledgeBases`、`getKnowledgeBaseById`、`uploadKnowledgeFile`、`createKnowledgeFromURL`、`listKnowledgeFiles`、`reparseKnowledge`、`cancelKnowledgeParse`、`batchDeleteKnowledge`、`getKnowledgeSpans`。
|
||||
- `/mnt/Data1T/Mnote_data/weknora/WeKnora/frontend/src/i18n/locales/zh-CN.ts`
|
||||
- 中文文案参考:`knowledgeBase`、`knowledgeList`、`knowledgeEditor`。
|
||||
|
||||
## 可嫁接页面结构
|
||||
|
||||
### 1. 知识库列表
|
||||
|
||||
最小结构:
|
||||
|
||||
- 左侧范围筛选:全部 / 我的 / 收藏 / 最近 / 空间,MNote 首版可降级为全部 + 当前 workspace。
|
||||
- 顶部标题:`知识库`,副标题采用 WeKnora 语义“管理和组织您的知识库,支持文档型和问答型知识库”。
|
||||
- 新建按钮:图标按钮或小按钮,接 MNote 创建 KB / 绑定本地 folder 的流程。
|
||||
- 全局状态提示:
|
||||
- 未初始化 / provider 未连接提示。
|
||||
- 上传或索引中的 progress panel。
|
||||
- 卡片网格:
|
||||
- 标题、描述。
|
||||
- 文档数量 / FAQ 数量 / processing loading。
|
||||
- 能力徽标:知识图谱、多模态、问题生成、共享。
|
||||
- 卡片菜单:置顶、设置、删除。
|
||||
- hover 显示边框与更多按钮。
|
||||
|
||||
MNote 首版不需要完整照搬 WeKnora 的组织共享分组,但应保留分组能力的视觉槽位,避免后续 workspace / shared KB 接入时重做页面。
|
||||
|
||||
### 2. 知识库详情
|
||||
|
||||
最小结构:
|
||||
|
||||
- 面包屑:`知识库 / 当前知识库 / 文档`。
|
||||
- 当前 KB 下拉切换:参考 `KBSwitcherDropdown`,MNote 可映射为当前 workspace 下 KB registry。
|
||||
- 右侧动作:信息 popover、设置按钮。
|
||||
- 文档页签:
|
||||
- `文档` 为默认主视图。
|
||||
- 若 provider 暴露 wiki / graph 能力,再显示 `Wiki`、`图谱` 页签。
|
||||
- 左侧标签侧栏:
|
||||
- `文档分类` 标题、数量、搜索、标签列表、新建 / 重命名 / 删除。
|
||||
- MNote 首版可先映射为 source kind / folder / tag,不能伪造 WeKnora 后端 tag 写入。
|
||||
- 主内容筛选栏:
|
||||
- 搜索文档。
|
||||
- 文件类型筛选。
|
||||
- 解析状态筛选。
|
||||
- 来源筛选。
|
||||
- 更新时间范围。
|
||||
- 网格 / 列表切换。
|
||||
- 添加文档入口。
|
||||
- 文档区:
|
||||
- skeleton loading。
|
||||
- grid 卡片作为默认视图。
|
||||
- list 作为密集视图。
|
||||
- 空状态。
|
||||
- 批量选择浮动条。
|
||||
- 文档详情:
|
||||
- 点击文档打开 `DocContent` 风格抽屉,展示全文、分块、原文件 / 引用。
|
||||
|
||||
### 3. 上传与导入
|
||||
|
||||
参考 `KbUploadSourceDropdown.vue` 的四类入口:
|
||||
|
||||
- 上传文档。
|
||||
- 上传文件夹。
|
||||
- 导入网页 URL。
|
||||
- 手动创建。
|
||||
|
||||
MNote 映射时应改成:
|
||||
|
||||
- 上传文档 / 文件夹:落到 MNote local-first source registry,记录 local path / providerKnowledgeBaseId / providerKnowledgeId,再交 WeKnora provider ingest。
|
||||
- 导入 URL:可作为 provider source,不对应本地文件。
|
||||
- 手动创建:如果没有明确的 MNote 文档创建语义,首版不启用,避免产生第二套正文事实源。
|
||||
|
||||
### 4. 状态与交互
|
||||
|
||||
WeKnora 的文档状态结构可直接作为 MNote UI 状态模型参考:
|
||||
|
||||
- `pending` / `processing`:显示 loading、解析中,可打开 trace。
|
||||
- `finalizing`:主解析完成但 summary / question / graph 等后处理仍在跑。
|
||||
- `failed`:红色失败状态,可重建 / 查看 trace。
|
||||
- `cancelled`:黄色取消状态。
|
||||
- `draft`:草稿。
|
||||
- `completed`:绿色完成。
|
||||
- `completed + summary pending/processing`:显示“生成摘要中”。
|
||||
|
||||
重要交互:
|
||||
|
||||
- 卡片和列表都能打开文档详情。
|
||||
- 更多菜单提供重建、取消解析、移动、批量管理、删除。
|
||||
- 解析中 / 失败状态应能打开 trace。
|
||||
- 网格 / 列表视图选择可持久化到 localStorage。
|
||||
- 批量选择不能与普通打开文档冲突。
|
||||
|
||||
## MNote 字段映射
|
||||
|
||||
| WeKnora UI 字段 | MNote 映射建议 |
|
||||
| --- | --- |
|
||||
| `kb.id` | MNote `knowledge_base_id` / registry entry id |
|
||||
| `kb.name` | 知识库显示名,默认可来自 folder name |
|
||||
| `kb.description` | registry description / provider description |
|
||||
| `kb.type` | MNote 首版固定 `document`,FAQ 暂不作为主路径 |
|
||||
| `kb.knowledge_count` | provider 文档数 + registry source count |
|
||||
| `kb.chunk_count` | provider chunk count,可从 WeKnora status / search metadata 显示 |
|
||||
| `kb.isProcessing` | registry processing count 或 provider parse in-flight count |
|
||||
| `extract_config.enabled` | WeKnora graph / MNote graph capability |
|
||||
| `vlm_config.enabled` | 多模态 / 图片解析能力 |
|
||||
| `question_generation_config.enabled` | 问题生成能力 |
|
||||
| `storage_provider_config.provider` | provider / vector store / file store 显示,不作为 MNote 文件事实源 |
|
||||
| `knowledge.id` | `providerKnowledgeId` |
|
||||
| `knowledge.file_name` | source display name / local file basename |
|
||||
| `knowledge.file_type` | 文件扩展名 / source kind |
|
||||
| `knowledge.file_size` | source file size,URL/manual 可为空 |
|
||||
| `knowledge.tag_id` | MNote tag / folder / source group 映射,首版可只读 |
|
||||
| `knowledge.parse_status` | provider parse status |
|
||||
| `knowledge.summary_status` | provider postprocess status |
|
||||
| `knowledge.channel` | `web` / `api` / `url` / `manual` / local upload 映射 |
|
||||
| `knowledge.source` | local path / URL / provider source |
|
||||
| `knowledge.updated_at` | registry updated_at 或 provider updated_at |
|
||||
|
||||
## 不能直接接管的边界
|
||||
|
||||
- 不直接把 WeKnora Vue 组件复制进 MNote runtime;MNote 当前主壳是 Rust SSR / browser runtime,不是 WeKnora Vue 应用。
|
||||
- 不让 WeKnora 成为 MNote 的文件事实源;本地 `.md`、source registry、workspace path、allowed roots 仍归 MNote。
|
||||
- 不把 WeKnora 的 tenant / organization / share 语义直接套到 MNote;MNote 的 auth、membership、share grants 由 Rust SQLite control-plane 管。
|
||||
- 不把 WeKnora 的 tag 删除语义直接映射到 MNote folder 删除;WeKnora tag delete 可能级联删除文档,MNote 需要独立确认。
|
||||
- 不直接启用手动创建文档,除非 MNote 明确将其映射到本地文件或页面创建命令。
|
||||
- 不直接复用 WeKnora 的轮询策略作为 MNote 主链;MNote 可展示 provider status,但刷新应优先走 MNote watcher / event / command result。
|
||||
- 不直接暴露 WeKnora 的删除 KB / 删除文档为本地文件删除;首版删除应只删除 provider index 与 registry 映射,是否删除本地文件必须单独确认。
|
||||
- 不把 WeKnora `Wiki` / `Graph` 页签默认显示为可用;只有 provider capability 明确可用时展示。
|
||||
|
||||
## MNote 最小呈现建议
|
||||
|
||||
首版替换原知识库设置面板时,建议至少实现以下可见结构:
|
||||
|
||||
1. 知识库列表页:标题、副标题、新建/绑定入口、KB 卡片网格、文档数、processing 状态、provider 能力徽标、设置入口。
|
||||
2. 知识库详情页:面包屑、KB 切换、文档分类侧栏、搜索/筛选栏、添加文档下拉、网格/列表切换。
|
||||
3. 文档项:文件名、描述/摘要、标签或来源、文件类型、更新时间、解析状态、打开引用。
|
||||
4. 状态层:pending / processing / finalizing / completed / failed / cancelled / draft 至少要有不同视觉表达。
|
||||
5. 安全边界:删除、移动、手动创建、共享、Wiki / Graph、tag 写入可以先隐藏或只读,避免 UI 暗示已具备不可逆能力。
|
||||
|
||||
Reference in New Issue
Block a user