Improve local evidence search and AI capabilities
This commit is contained in:
@@ -896,6 +896,7 @@ LiteParseProvider + MinerUProvider
|
||||
- Hermes tool manifest 已暴露 `mnote.evidence.search/read/open`,运行时 dispatch 到 evidence route helper。
|
||||
- 2026-06-04 复核补强:`scripts/reasonix-acp-wrapper.mjs` 已注册 `mnote_evidence_search/read/open` 三个 Reasonix ACP 只读工具,并把它们转发到 Rust `mnote.evidence.search/read/open`;wrapper selftest 覆盖 evidence payload 继承 `rootUri` 与 evidence search 只读属性。
|
||||
- 2026-06-04 真实服务验证:登录测试账号后,`/api/hermes/client/tools?scope=mnote&profile=reasonix` 已返回 `mnote.evidence.search/read/open`;`/api/hermes/client/skills?runtime=mnote&agentId=reasonix` 已返回启用的 `mnote-document-evidence` skill。
|
||||
- 2026-06-04 索引 skill 合并:公开 skill 改为 `mnote-local-index`,合并 evidence 检索与索引管理说明;`mnote-document-evidence` 仅保留为 `mnote.skill.read` 兼容别名,不再作为公开 skill 摘要展示。新增 `mnote.index.status/refresh/update_settings`,Reasonix ACP 对应 `mnote_index_status/refresh/update_settings`。
|
||||
- 2026-06-04 真 Reasonix ACP 验证:带 `agentId=reasonix`、`contextRefs=[current_page, folder]`、local-folder `rootUri` 发起 `/api/hermes/client/runs`,SSE 中出现 `tool.started/tool.completed`,工具为 `mnote_evidence_search`,返回 `quote="Printer test page"`、`page=1`、`bbox`、`sourceMapPath` 和 `mnote.agent_run_receipt.evidence.v1`。
|
||||
- 2026-06-04 修正:Reasonix wrapper 原先用字符串包含 `"error"` 判断工具失败,导致 `error:null` 的成功结果在 UI/SSE 中被标记成 `tool.failed`;已改为解析 JSON,仅 `ok:false` 或非空 `error` 才标记失败。
|
||||
- Skill 约束明确要求回答保留 quote、source 和 openAction,禁止直接读取 `.mnote/index`、OCR sidecar 或自行拼接 URL。
|
||||
|
||||
@@ -0,0 +1,413 @@
|
||||
# 7-47 MNote 公共 capability/plugin 注册表设计 v1
|
||||
|
||||
> 状态:process
|
||||
>
|
||||
> 目标:把当前分裂的 MNote builtin skill、mnote tool manifest、Hermes plugin、Reasonix wrapper 和 Page AI UI 开关收口为同一个“AI 能力”模型。对用户来说 skill / plugin / tool 都是“授予 AI 的能力”,UI 不应暴露实现层分类;实现层再把一个能力映射到说明书、工具、runtime adapter 和权限策略。本轮只整理 MNote 公共能力;Reasonix / Hermes 自带的 skills/plugins 维持现状,不纳入统一注册表迁移范围。
|
||||
|
||||
## 0. 用户口径
|
||||
|
||||
用户不需要理解 skill、plugin、tool 的区别。Page AI 设置中统一展示为“AI 能力”:
|
||||
|
||||
- `当前页读取`
|
||||
- `本地索引与证据检索`
|
||||
- `本地文件编辑`
|
||||
- `思维导图`
|
||||
- `ONLYOFFICE 实时编辑`
|
||||
- `纯聊天`
|
||||
|
||||
每个能力只有一个主开关。展开后可以显示该能力包含的工具、上下文要求和读写权限,但这些是高级详情,不是主概念。
|
||||
|
||||
实现层映射:
|
||||
|
||||
- `skill`:能力说明书,告诉 agent 什么时候用、怎么用。
|
||||
- `tool`:能力的可执行函数,真正落到 Rust runtime / kernel。
|
||||
- `plugin / adapter`:把同一套工具暴露给 Hermes ACP、Reasonix ACP 或其它 agent runtime。
|
||||
- `policy`:决定该能力是否可见、是否启用、是否允许写入。
|
||||
|
||||
后续 UI 文案统一使用“能力”,不再把 MNote builtin skill、Hermes skill、Reasonix skill、mnote tool 作为并列用户入口。
|
||||
|
||||
## 1. 当前盘点
|
||||
|
||||
### 1.1 MNote builtin skills
|
||||
|
||||
当前入口:`rust/crates/mnote-web/src/hermes_tools/skill.rs`
|
||||
|
||||
现有内置 skill:
|
||||
|
||||
- `mnote-current-page`
|
||||
- `mnote-local-index`
|
||||
- `mnote-local-file`
|
||||
- `mnote-onlyoffice-live`
|
||||
- `mnote-mindmap`
|
||||
- `mnote-chat-only`
|
||||
|
||||
特点:
|
||||
|
||||
- skill 是 Rust 静态注册,正文来自 `skills/*/SKILL.md`。
|
||||
- `/api/hermes/client/skills?runtime=mnote&agentId=...` 通过 `mnote_builtin_skills_payload()` 输出到 UI。
|
||||
- 每个 skill 现在已经带 `toolNames` 和 `requiresContextRefs`,但这些只是弱引用,不是一个正式 capability/plugin 合同。
|
||||
- `mnote.skill.read` 能懒加载正文;旧 `mnote-document-evidence` 已作为兼容别名映射到 `mnote-local-index`。
|
||||
|
||||
### 1.2 MNote tools
|
||||
|
||||
当前入口:`rust/crates/mnote-web/src/hermes_tools/manifest.rs`
|
||||
|
||||
现有工具大类:
|
||||
|
||||
- skill/context:`mnote.skill.read`、`mnote.context.*`
|
||||
- evidence/index:`mnote.evidence.*`、`mnote.index.*`
|
||||
- doc/block/page/artifact:`mnote.doc.*`、`mnote.block.*`、`mnote.page.*`、`mnote.artifact.*`
|
||||
- mindmap:`mnote.mindmap.*`
|
||||
- office/onlyoffice:`mnote.office.*`、`mnote.onlyoffice.*`
|
||||
|
||||
执行入口:
|
||||
|
||||
- `/api/hermes/tools/mnote/manifest`
|
||||
- `/api/hermes/tools/mnote/call`
|
||||
- `execute_mnote_tool_call()` 统一做认证、profile 禁用检查、workspace 校验、capabilityScope 校验、写入 guard、audit、idempotency。
|
||||
|
||||
问题:
|
||||
|
||||
- manifest 只有 plugin 总描述和扁平 tools,没有“哪个 tool 属于哪个公共能力包”的结构。
|
||||
- `/api/hermes/client/tools?scope=mnote&profile=...` 只展示扁平工具列表。
|
||||
- tool 开关写入 Hermes profile 的 `mnote.tools.disabled`,skill 开关写入 MNote SQLite user preference,两个开关域不同步。
|
||||
|
||||
### 1.3 Hermes plugin
|
||||
|
||||
当前本机存在 `/home/lix/.hermes/plugins/mnote/`,包括:
|
||||
|
||||
- `plugin.yaml`
|
||||
- `__init__.py`
|
||||
|
||||
现状:
|
||||
|
||||
- 这是 Hermes 用户插件,不在 mnote repo 内。
|
||||
- `plugin.yaml` 只列出旧批次工具:`mnote_page_get/save/update_title/update_options`、`mnote_doc_*`、`mnote_block_*`、artifact 等。
|
||||
- 没有 `mnote_evidence_*`、`mnote_index_*`、mindmap、onlyoffice live 等新工具。
|
||||
- `__init__.py` 手写 Python wrapper,把 Hermes tool call 转发到 `/api/hermes/tools/mnote/call`。
|
||||
|
||||
问题:
|
||||
|
||||
- Hermes 用户插件和 Rust manifest 已经漂移。
|
||||
- 新增 Rust tool 后不会自动进入 Hermes plugin。
|
||||
- 如果继续维护该插件,必须由 Rust manifest 生成 plugin.yaml / Python adapter,不能手写。
|
||||
|
||||
### 1.4 Reasonix wrapper
|
||||
|
||||
当前入口:`scripts/reasonix-acp-wrapper.mjs`
|
||||
|
||||
现状:
|
||||
|
||||
- 手写 Reasonix ACP 可见工具名,例如 `mnote_evidence_search`、`mnote_index_status`。
|
||||
- 手写 `REASONIX_TOOL_TO_MNOTE_TOOL` 映射到 Rust `mnote.*` 工具。
|
||||
- 手写每个工具的 parameters。
|
||||
|
||||
问题:
|
||||
|
||||
- 与 Rust manifest 重复。
|
||||
- 与 Hermes plugin 重复。
|
||||
- 新增/改名工具必须同步改 wrapper,否则 agent 看得到 skill 也无法调用工具。
|
||||
|
||||
### 1.5 Page AI UI
|
||||
|
||||
当前入口:
|
||||
|
||||
- skills panel:`rust/crates/mnote-web/browser/sidebar-page-ai-skill-runtime.js`
|
||||
- runtime/tools panel:`rust/crates/mnote-web/browser/sidebar-page-ai-render-runtime.js`
|
||||
- data load/toggle:`rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js`
|
||||
|
||||
现状:
|
||||
|
||||
- Skills 页能展示 MNote builtin skills、Reasonix skills、Hermes profile skills。
|
||||
- Runtime/高级页展示扁平 `mnote tools` 列表。
|
||||
- MNote skill 开关调用 `/api/hermes/client/skills/toggle`,写 SQLite user preference。
|
||||
- Tool 开关调用 `/api/hermes/client/tools/toggle`,写 profile YAML `mnote.tools.disabled`。
|
||||
|
||||
问题:
|
||||
|
||||
- 用户想管理的是“索引能力包”,不是单独 skill 或一堆扁平工具。
|
||||
- 现在 UI 上 skill 和 tool 分两个地方,不能表达“启用索引 skill,同时启用对应工具”。
|
||||
- 无法像公共 skill 一样展示 plugin/capability 包的工具内容、权限、启停状态。
|
||||
|
||||
## 2. 设计判断
|
||||
|
||||
当前应该引入 `MnoteAiCapability` / `MnoteCapabilityPack`,而不是继续把 skill、tool、plugin 分开维护。代码中可叫 capability pack;UI 中只叫“AI 能力”。
|
||||
|
||||
定义:
|
||||
|
||||
```rust
|
||||
pub struct MnoteCapabilityPack {
|
||||
pub id: &'static str,
|
||||
pub title: &'static str,
|
||||
pub description: &'static str,
|
||||
pub agent_ids: &'static [&'static str],
|
||||
pub read_only: bool,
|
||||
pub requires_context_refs: &'static [&'static str],
|
||||
pub skill_id: &'static str,
|
||||
pub skill_content: &'static str,
|
||||
pub tool_names: &'static [&'static str],
|
||||
pub ui_kind: &'static str, // capability | chat | compat
|
||||
pub category: &'static str, // mnote, office, resource, chat
|
||||
pub public: bool,
|
||||
}
|
||||
```
|
||||
|
||||
原则:
|
||||
|
||||
- 一个公共能力包可以包含一个 skill 和多个 tools。
|
||||
- UI 主要展示 capability pack,不再让用户先理解 skill/tool/plugin 三套概念。
|
||||
- agent prompt 仍注入短 skill/capability 摘要,正文仍走 `mnote.skill.read` 懒加载。
|
||||
- tool manifest 仍是执行真相,但每个 tool 必须能反查所属 capability pack。
|
||||
- Reasonix wrapper / Hermes plugin 都从同一份 capability/tool manifest 生成或动态注册。
|
||||
|
||||
## 3. 目标 API
|
||||
|
||||
### 3.1 新增 capability 列表
|
||||
|
||||
`GET /api/hermes/client/capabilities?runtime=mnote&agentId=reasonix&profile=...`
|
||||
|
||||
返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"runtime": "mnote",
|
||||
"categories": [
|
||||
{
|
||||
"name": "mnote",
|
||||
"title": "MNote",
|
||||
"capabilities": [
|
||||
{
|
||||
"id": "mnote-local-index",
|
||||
"title": "MNote local index",
|
||||
"description": "Search local documents with evidence locators and manage local index scopes.",
|
||||
"enabled": true,
|
||||
"toggleable": true,
|
||||
"readOnly": false,
|
||||
"skillId": "mnote-local-index",
|
||||
"toolNames": [
|
||||
"mnote.evidence.search",
|
||||
"mnote.evidence.read",
|
||||
"mnote.evidence.open",
|
||||
"mnote.index.status",
|
||||
"mnote.index.refresh",
|
||||
"mnote.index.update_settings"
|
||||
],
|
||||
"tools": [
|
||||
{
|
||||
"name": "mnote.index.update_settings",
|
||||
"kind": "write",
|
||||
"status": "available",
|
||||
"enabled": true,
|
||||
"requiresWritePermission": true
|
||||
}
|
||||
],
|
||||
"requiresContextRefs": ["folder"],
|
||||
"configScope": "user_sqlite+profile_tool_policy"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 新增 capability toggle
|
||||
|
||||
`PUT /api/hermes/client/capabilities/toggle`
|
||||
|
||||
入参:
|
||||
|
||||
```json
|
||||
{
|
||||
"runtime": "mnote",
|
||||
"profile": "reasonix",
|
||||
"id": "mnote-local-index",
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
行为:
|
||||
|
||||
- 写入 MNote SQLite user preference:`ai.agent.mnote_builtin.skill.{id}.enabled`
|
||||
- 对包内 tools 批量更新 profile `mnote.tools.disabled`
|
||||
- 保留单 tool 开关作为高级功能,但 UI 默认展示包开关。
|
||||
|
||||
### 3.3 manifest 扩展
|
||||
|
||||
`/api/hermes/tools/mnote/manifest` 增加:
|
||||
|
||||
```json
|
||||
{
|
||||
"capabilities": [
|
||||
{
|
||||
"id": "mnote-local-index",
|
||||
"skillId": "mnote-local-index",
|
||||
"toolNames": ["mnote.evidence.search", "mnote.index.status"]
|
||||
}
|
||||
],
|
||||
"tools": [
|
||||
{
|
||||
"name": "mnote.index.status",
|
||||
"capabilityId": "mnote-local-index",
|
||||
"capabilityScope": ["index.read", "evidence.read"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 4. UI 设计
|
||||
|
||||
### 4.1 Skills 页改为 AI 能力页
|
||||
|
||||
在 Page AI 的 Skills 页中,用户看到的是统一“AI 能力”列表,不再分 skill / plugin / tool:
|
||||
|
||||
- 行标题:`MNote local index`
|
||||
- 副标题:`索引 / 证据检索 · 6 tools · 需要 folder`
|
||||
- 状态 chip:`只读` / `可写` / `部分工具关闭` / `只读上下文不可写`
|
||||
- 主开关:启用/关闭整个能力包
|
||||
- 展开项:列出 tools,显示 read/write、enabled、status
|
||||
|
||||
不新增单独 landing/settings 页;沿用当前 Skills 页即可,避免再散一处入口。
|
||||
|
||||
页面标题建议从 `Skills` 改为 `能力`;内部 source filter 可以保留 `MNote / Hermes / Reasonix`,但展示为能力来源,不作为用户要理解的能力类型。
|
||||
|
||||
### 4.2 Runtime 高级页保留扁平工具
|
||||
|
||||
Runtime 页继续保留 `mnote tools`,但作为高级调试面:
|
||||
|
||||
- 默认按 capability 分组,而不是纯扁平列表。
|
||||
- 单 tool 开关仍保留,用于排查或临时禁用某个写工具。
|
||||
- 若 capability 关闭,包内工具显示 `disabled_by_capability`。
|
||||
|
||||
### 4.3 索引面板与能力包关系
|
||||
|
||||
Sidebar 的“索引设置”仍是用户直接管理索引范围的产品 UI;Page AI 的 `mnote-local-index` capability 是 agent 能力开关。
|
||||
|
||||
两者职责不同:
|
||||
|
||||
- 索引设置面板:用户手动新增/删除/刷新索引范围。
|
||||
- MNote local index capability:允许 agent 使用工具帮用户查看、新增、刷新、删除索引范围。
|
||||
|
||||
## 5. Runtime 适配
|
||||
|
||||
### 5.1 Reasonix
|
||||
|
||||
短期:
|
||||
|
||||
- 保留 `scripts/reasonix-acp-wrapper.mjs`。
|
||||
- 但 wrapper 启动时请求 `/api/hermes/tools/mnote/manifest`,按 manifest 自动注册工具。
|
||||
- 保留手写 fallback,避免 mnote-web 未启动时 wrapper 不能初始化。
|
||||
|
||||
中期:
|
||||
|
||||
- 删除 `REASONIX_TOOL_TO_MNOTE_TOOL` 手写表。
|
||||
- 工具名转换统一由函数生成:
|
||||
- `mnote.index.status` -> `mnote_index_status`
|
||||
- `mnote.evidence.search` -> `mnote_evidence_search`
|
||||
|
||||
### 5.2 Hermes ACP
|
||||
|
||||
短期:
|
||||
|
||||
- MNote 继续通过 `AcpMnoteToolContext` 把 `availableSkills` 和 capability policy 交给 Hermes ACP。
|
||||
- 如果 Hermes ACP 原生不能消费 Rust manifest 注册工具,则仍依赖 `/home/lix/.hermes/plugins/mnote`。
|
||||
|
||||
中期:
|
||||
|
||||
- 用 Rust manifest 生成 `/home/lix/.hermes/plugins/mnote/plugin.yaml` 和 Python adapter。
|
||||
- 生成内容覆盖当前手写旧插件,确保 Hermes plugin tools 与 Rust manifest 一致。
|
||||
|
||||
长期:
|
||||
|
||||
- Hermes ACP 若支持从 host 动态接收 tools,则不再需要本机 Python plugin,只保留 Rust manifest。
|
||||
|
||||
## 6. 迁移方案
|
||||
|
||||
### Phase A:只加 registry,不改 UI 行为
|
||||
|
||||
- 新增 `hermes_tools/capability.rs`。
|
||||
- 将当前 `SKILLS` 迁到 `CAPABILITY_PACKS`,`skill_summaries_for_agent()` 从 pack 派生。
|
||||
- `manifest()` 给每个 tool 增加 `capabilityId`,并输出 `capabilities`。
|
||||
- 保持 `/client/skills`、`/client/tools` 响应兼容。
|
||||
|
||||
验收:
|
||||
|
||||
- `mnote-local-index` 在 `/client/skills?runtime=mnote` 可见。
|
||||
- `/api/hermes/tools/mnote/manifest` 可看到 `capabilities[]`。
|
||||
- 旧 `mnote.skill.read` 不破。
|
||||
|
||||
### Phase B:UI 展示 capability pack
|
||||
|
||||
- 新增 `/api/hermes/client/capabilities`。
|
||||
- Skills 页对 `runtime=mnote` 优先消费 capabilities。
|
||||
- 能力包行展示 tools 数、read/write、contextRefs。
|
||||
- Runtime 页 tools 按 capability 分组。
|
||||
|
||||
验收:
|
||||
|
||||
- Page AI Skills 页中 `MNote local index` 像公共 skill 一样可见。
|
||||
- 展开能看到 `mnote.evidence.*` 和 `mnote.index.*`。
|
||||
- 开关 capability 后,下一次 run 的 `skillPreferences.mnote` 同步变化。
|
||||
|
||||
### Phase C:能力包开关驱动工具开关
|
||||
|
||||
- 新增 `/api/hermes/client/capabilities/toggle`。
|
||||
- 开关包时同步 skill preference 和 profile tool disabled 列表。
|
||||
- `page_ai_capability_policy()` 过滤 disabled capability,且 `execute_mnote_tool_call()` 对 disabled tool 继续硬拒绝。
|
||||
|
||||
验收:
|
||||
|
||||
- 关闭 `mnote-local-index` 后 agent 不再看到该 skill 摘要。
|
||||
- 关闭后直接调用 `mnote.index.status` 返回 `mnote_tool_disabled` 或 capability disabled。
|
||||
- 再打开后恢复。
|
||||
|
||||
### Phase D:生成 Reasonix/Hermes adapters
|
||||
|
||||
- Reasonix wrapper 从 manifest 自动注册工具。
|
||||
- Hermes plugin 从 manifest 生成或在启动时同步。
|
||||
- 删除手写工具表漂移。
|
||||
|
||||
验收:
|
||||
|
||||
- 新增 Rust tool 后,只改 Rust manifest/capability pack,Reasonix/Hermes UI 与 runtime 均自动出现。
|
||||
- `node scripts/reasonix-acp-wrapper.mjs` selftest 覆盖 manifest 动态注册。
|
||||
- `hermes plugins list` / Hermes tool list 显示与 Rust manifest 一致。
|
||||
|
||||
## 7. 对 mnote-local-index 的落地形态
|
||||
|
||||
`mnote-local-index` 是第一批公共能力包试点:
|
||||
|
||||
- skill:`skills/mnote-local-index/SKILL.md`
|
||||
- tools:
|
||||
- `mnote.evidence.search`
|
||||
- `mnote.evidence.read`
|
||||
- `mnote.evidence.open`
|
||||
- `mnote.index.status`
|
||||
- `mnote.index.refresh`
|
||||
- `mnote.index.update_settings`
|
||||
- requiresContextRefs:`folder`
|
||||
- readOnly:`false`
|
||||
- write guard:只 `mnote.index.update_settings` 写设置;必须 `dryRun/idempotencyKey`;共享只读禁止写。
|
||||
- UI 文案:`索引 / 证据检索 · 可管理索引范围`
|
||||
|
||||
## 8. 非目标
|
||||
|
||||
- 不把索引设置面板挪进 Page AI。
|
||||
- 不让 agent 直接读写 `.mnote/index` 文件。
|
||||
- 不让 Hermes plugin 直接写 Convex 或绕过 Rust runtime。
|
||||
- 不在前端手写工具 schema。
|
||||
- 不把 Reasonix wrapper 作为长期 tool registry 真相。
|
||||
|
||||
## 9. 风险
|
||||
|
||||
- Hermes Python plugin 当前在 `/home/lix/.hermes/plugins/mnote`,不在 repo,自动生成前仍会漂移。
|
||||
- tool 开关现在是 profile 级,skill 开关是用户级;能力包 toggle 需要明确优先级。
|
||||
- `mnote-local-file` 是 agent 原生文件能力指导,当前没有对应 MNote 写工具,放入 capability pack 时需要标记为 `native_agent_tools`,避免误以为 MNote 提供文件 patch tool。
|
||||
- `mnote-chat-only` 不是业务能力包,应保留为 agent mode skill,不参与 tools。
|
||||
|
||||
## 10. 建议执行顺序
|
||||
|
||||
1. 先做 Phase A:Rust `MnoteCapabilityPack` registry,完全兼容现有接口。
|
||||
2. 再做 Phase B:UI 展示 capability pack,保留旧 skills/tools fallback。
|
||||
3. 再做 Phase C:能力包 toggle 批量控制 skill + tools。
|
||||
4. 最后做 Phase D:Reasonix/Hermes adapter 从 manifest 自动生成。
|
||||
@@ -0,0 +1,540 @@
|
||||
# 7-48 [process] Paperless-ngx Reference: Resource Ingestion / Job Ledger / Evidence Index v1
|
||||
|
||||
> 创建时间:2026-06-05
|
||||
>
|
||||
> 当前状态:`PROCESS`
|
||||
>
|
||||
> Owner:07-ai / 03-rust-web / control-plane / 01-tree-first-graph-kernel
|
||||
>
|
||||
> 参考项目:`/mnt/Data1T/mnote/reference-code/paperless-ngx`
|
||||
>
|
||||
> 参考版本:`f56f29111`
|
||||
>
|
||||
> CodeGraph:已单独建立,`712 files / 16,952 nodes / 35,407 edges`
|
||||
>
|
||||
> 上位依据:
|
||||
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
|
||||
> - `/mnt/Data1T/mnote/CURRENT_ARCHITECTURE.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-46-document-evidence-retrieval-kernel-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/03-rust-web/done/3-25-local-folder-mineru-ocr-sidecar-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
|
||||
|
||||
## 1. 第一结论
|
||||
|
||||
Paperless-ngx 对 MNote 最有价值的不是 Django / Angular / Celery 技术栈,而是三套工程结构:
|
||||
|
||||
1. `PaperlessTask`:所有后台任务有统一账本,能记录来源、状态、耗时、输入、结果和用户是否已确认。
|
||||
2. `consume_file` plugin pipeline:资源导入、预检、解析、OCR、存储、索引、通知按阶段推进,失败可以定位到阶段。
|
||||
3. `Tantivy search backend + sanity checker`:索引有 schema 版本、权限字段、锁、延迟补偿和可重建性;文件与派生物有一致性检查。
|
||||
|
||||
MNote 应把这些模式收口成自己的 `Resource Work Kernel`:
|
||||
|
||||
```text
|
||||
- local file / attachment / OCR source / parsed artifact
|
||||
-> ResourceWorkJob control-plane ledger
|
||||
-> ResourceIngestionPipeline stage runner
|
||||
-> sidecar artifact + source-map
|
||||
-> evidence.sqlite / local search projection
|
||||
-> realtime job events
|
||||
-> sanity check / recovery job
|
||||
```
|
||||
|
||||
这不是要引入 paperless-ngx 的运行时。MNote 的数据真相仍然是 local Markdown、附件原文件、resource tree 和 control-plane;索引、OCR Markdown、parse Markdown、source-map 都是可删除重建的派生物。
|
||||
|
||||
## 2. Paperless-ngx 可借鉴点
|
||||
|
||||
### 2.1 统一后台任务账本
|
||||
|
||||
参考路径:
|
||||
|
||||
- `src/documents/models.py`:`PaperlessTask`
|
||||
- `src/documents/signals/handlers.py`:Celery task publish / prerun / postrun / failure handlers
|
||||
- `src-ui/src/app/components/admin/tasks/tasks.component.ts`
|
||||
|
||||
可借鉴点:
|
||||
|
||||
- 任务不是只存在于内存事件或前端状态,而是落库。
|
||||
- 每个任务有 `task_type`、`trigger_source`、`status`、`date_created`、`date_started`、`date_done`、`duration_seconds`、`wait_time_seconds`、`input_data`、`result_data`、`acknowledged`。
|
||||
- 系统任务和用户触发任务统一展示,但保留来源差异。
|
||||
|
||||
MNote 映射:
|
||||
|
||||
- 当前 `JobTicket`、OCR job、index refresh、agent run、OnlyOffice bridge 任务、recovery job 不应继续分散。
|
||||
- 新增 control-plane 表 `resource_work_jobs`,先覆盖 local OCR / evidence parse / index refresh,后续再纳入 agent run 和 recovery job。
|
||||
|
||||
### 2.2 阶段化资源导入管线
|
||||
|
||||
参考路径:
|
||||
|
||||
- `src/documents/tasks.py`:`consume_file`
|
||||
- `src/documents/plugins/base.py`:`ConsumeTaskPlugin`
|
||||
- `src/documents/consumer.py`:解析、OCR、存储、索引、progress
|
||||
- `src/documents/plugins/helpers.py`:`ProgressManager`
|
||||
|
||||
可借鉴点:
|
||||
|
||||
- 导入任务按插件链执行,每个 stage 有 `setup / run / cleanup`。
|
||||
- 阶段状态通过 websocket 通知。
|
||||
- 文件写入、数据库更新、索引更新分层处理,失败时能说明卡在预检、解析、写 sidecar 还是索引。
|
||||
|
||||
MNote 映射:
|
||||
|
||||
- 不引入插件框架泛化;先定义窄的 `ResourceIngestionPipeline`。
|
||||
- stage 只覆盖当前真实需要:`preflight`、`parse_text`、`ocr`、`write_artifact`、`write_source_map`、`refresh_evidence_index`、`broadcast_done`。
|
||||
- 当前 `local_ocr` 里的 stage 字符串和 sidecar 写入逻辑可以作为第一批迁移对象。
|
||||
|
||||
### 2.3 索引生命周期和自愈
|
||||
|
||||
参考路径:
|
||||
|
||||
- `src/documents/search/_backend.py`
|
||||
- `src/documents/search/_schema.py`
|
||||
- `src/documents/search/_query.py`
|
||||
- `src/documents/tasks.py`:`index_document`、`remove_document_from_index`
|
||||
|
||||
可借鉴点:
|
||||
|
||||
- schema version sentinel 决定是否重建。
|
||||
- 写索引用 file lock 和 retry,锁耗尽后排延迟任务,而不是让前台操作失败。
|
||||
- 查询层有权限过滤、autocomplete、highlight、CJK bigram、simple search。
|
||||
|
||||
MNote 映射:
|
||||
|
||||
- `.mnote/index/evidence.sqlite` 当前已存在,但需要更明确的 schema sentinel 和 rebuild reason。
|
||||
- `query_evidence_sqlite_results` 继续作为默认 evidence path;后续补充 autocomplete / CJK / highlight 时仍以 `EvidenceLocator` 为返回真相。
|
||||
- 索引写失败不能悄悄丢失,应写入 `resource_work_jobs` 的 retry-scheduled 状态。
|
||||
|
||||
### 2.4 权限过滤的实时事件
|
||||
|
||||
参考路径:
|
||||
|
||||
- `src/paperless/consumers.py`
|
||||
- `src/documents/plugins/helpers.py`
|
||||
|
||||
可借鉴点:
|
||||
|
||||
- websocket payload 带 owner / visible users / visible groups。
|
||||
- server-side websocket consumer 根据当前用户过滤。
|
||||
|
||||
MNote 映射:
|
||||
|
||||
- local-only 阶段可以先只带 `workspaceId`、`actorId`、`rootUri`、`targetDocumentId`、`grantId`。
|
||||
- 一旦进入 share / team workspace,OCR / index / agent job event 不能只按广播频道粗暴推送。
|
||||
- `AiAccessScope` 和 share grants 应能映射成 job event 可见性字段。
|
||||
|
||||
### 2.5 Sanity checker
|
||||
|
||||
参考路径:
|
||||
|
||||
- `src/documents/sanity_checker.py`
|
||||
- `src/documents/management/commands/document_sanity_checker.py`
|
||||
|
||||
可借鉴点:
|
||||
|
||||
- 独立检查原文件、派生文件、checksum、孤儿文件和空 OCR 内容。
|
||||
- 输出按 error / warning / info 分级,既能 CLI 显示,也能作为后台任务结果。
|
||||
|
||||
MNote 映射:
|
||||
|
||||
- 新增 `workspace_sanity_check`,先检查 local-folder resource evidence:
|
||||
- Markdown owner 是否存在。
|
||||
- 附件路径是否存在且在 allowed root 内。
|
||||
- `{pageStem}.ocr/` sidecar 是否能回到 owner Markdown。
|
||||
- `*.source-map.json` 是否能解析为 `mnote.resource_source_map.v1`。
|
||||
- `evidence.sqlite` 是否能由 sidecar 重建。
|
||||
- evidence locator 的 `openAction` 是否能落回 document / resource tab。
|
||||
|
||||
## 3. 目标架构
|
||||
|
||||
### 3.1 ResourceWorkJob
|
||||
|
||||
新增 control-plane job ledger,不替代 domain event,也不替代 agent run receipt。
|
||||
|
||||
```rust
|
||||
pub struct ResourceWorkJob {
|
||||
pub job_id: String,
|
||||
pub job_type: ResourceWorkJobType,
|
||||
pub trigger_source: ResourceWorkTriggerSource,
|
||||
pub status: ResourceWorkJobStatus,
|
||||
pub stage: Option<String>,
|
||||
pub progress_current: Option<u32>,
|
||||
pub progress_total: Option<u32>,
|
||||
pub stage_label: Option<String>,
|
||||
pub workspace_id: String,
|
||||
pub root_uri: String,
|
||||
pub actor_id: Option<String>,
|
||||
pub target_document_id: Option<String>,
|
||||
pub source_root_relative_path: Option<String>,
|
||||
pub artifact_root_relative_path: Option<String>,
|
||||
pub source_map_root_relative_path: Option<String>,
|
||||
pub input_json: serde_json::Value,
|
||||
pub result_json: Option<serde_json::Value>,
|
||||
pub error_code: Option<String>,
|
||||
pub error_message: Option<String>,
|
||||
pub created_at_ms: u128,
|
||||
pub started_at_ms: Option<u128>,
|
||||
pub finished_at_ms: Option<u128>,
|
||||
pub acknowledged_at_ms: Option<u128>,
|
||||
}
|
||||
```
|
||||
|
||||
首批枚举:
|
||||
|
||||
```text
|
||||
job_type:
|
||||
- local_ocr
|
||||
- resource_parse
|
||||
- evidence_index_refresh
|
||||
- evidence_index_rebuild
|
||||
- workspace_sanity_check
|
||||
|
||||
trigger_source:
|
||||
- web_ui
|
||||
- api
|
||||
- watcher
|
||||
- agent_tool
|
||||
- system
|
||||
- recovery
|
||||
|
||||
status:
|
||||
- pending
|
||||
- running
|
||||
- succeeded
|
||||
- failed
|
||||
- retry_scheduled
|
||||
- canceled
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- `job_id` 由 MNote 生成,不复用外部 provider task id。
|
||||
- MinerU task id、LiteParse request id、Reasonix run id 只进入 `input_json / result_json`。
|
||||
- `result_json` 必须能存 evidence id、artifact path、source-map path、locator count、index row count。
|
||||
- `stage / progress_current / progress_total / stage_label` 是前台任务中心的稳定合同;不能只塞在 provider 私有 payload 里。
|
||||
- job ledger 是 control-plane 事实,不是用户正文真相。
|
||||
|
||||
### 3.2 ResourceIngestionPipeline
|
||||
|
||||
先实现窄接口,不做任意插件市场:
|
||||
|
||||
```text
|
||||
preflight
|
||||
-> detect_resource_kind
|
||||
-> choose_provider
|
||||
-> parse_or_ocr
|
||||
-> write_artifact
|
||||
-> write_source_map
|
||||
-> refresh_evidence_index
|
||||
-> broadcast_job_event
|
||||
```
|
||||
|
||||
Provider 策略:
|
||||
|
||||
- 文本型 PDF / Office parse 优先走 `LiteParseProvider` 或当前轻量 parser。
|
||||
- 扫描件 / 图片走 `MinerUProvider`。
|
||||
- mock provider 仅用于 smoke,不得在真实功能报告中冒充成功链路。
|
||||
|
||||
阶段状态:
|
||||
|
||||
```text
|
||||
queued
|
||||
preflight
|
||||
parsing
|
||||
ocr_uploading
|
||||
ocr_processing
|
||||
writing_artifact
|
||||
writing_source_map
|
||||
indexing
|
||||
done
|
||||
failed
|
||||
retry_scheduled
|
||||
stale
|
||||
```
|
||||
|
||||
当前 `local_ocr.job.updated` 可兼容保留,但 payload 应逐步包含 `jobId / jobType / stage / workspaceId / rootUri / sourceRootRelativePath / targetDocumentId / artifactPath / sourceMapPath`。
|
||||
|
||||
### 3.3 Evidence Index Lifecycle
|
||||
|
||||
当前 `.mnote/index/evidence.sqlite` 继续作为默认 evidence index。升级点:
|
||||
|
||||
- 增加 `schema_version` 和 `build_settings` sentinel。
|
||||
- 每次 write / refresh 记录 `job_id`。
|
||||
- 索引 row 必须能通过 `source_map_root_relative_path` 回到 canonical artifact。
|
||||
- lock 失败进入 `retry_scheduled` job,不直接吞掉。
|
||||
- watcher 增量刷新失败时,不做前端轮询补偿;排 recovery job 并广播一次明确事件。
|
||||
|
||||
建议最小表:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS evidence_index_meta (
|
||||
key TEXT PRIMARY KEY,
|
||||
value_json TEXT NOT NULL,
|
||||
updated_at_ms INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS evidence_index_jobs (
|
||||
job_id TEXT PRIMARY KEY,
|
||||
last_error_code TEXT,
|
||||
last_error_message TEXT,
|
||||
updated_at_ms INTEGER NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
如果 control-plane 已存 job,这里只保存 index-local rebuild metadata,不重复完整 job 账本。
|
||||
|
||||
### 3.4 Workspace Sanity Check
|
||||
|
||||
新增只读检查,不自动删除、不自动修复。
|
||||
|
||||
检查项:
|
||||
|
||||
| 级别 | 检查 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| error | owner Markdown 不存在 | evidence locator 无法打开 |
|
||||
| error | resource file 不存在 | 附件或 OCR source 丢失 |
|
||||
| error | source-map JSON 无法解析 | 定位真相损坏 |
|
||||
| error | evidence.sqlite schema 不匹配 | 需要 rebuild |
|
||||
| warning | sidecar 孤儿文件 | 有 OCR/parse artifact 但找不到 owner link |
|
||||
| warning | source hash / mtime stale | 可重建,但不阻断 |
|
||||
| info | parse/OCR 内容为空 | 允许,但要可见 |
|
||||
|
||||
输出既可作为 API:
|
||||
|
||||
```text
|
||||
POST /api/workspaces/sanity/check
|
||||
GET /api/work/jobs/:jobId
|
||||
```
|
||||
|
||||
也可作为 smoke / CLI helper 的 JSON 结果。
|
||||
|
||||
### 3.5 Unified Task Foreground UI
|
||||
|
||||
统一后台任务必须有统一前台可见入口。否则用户仍然只能在 OCR 设置、索引设置、toast、局部状态灯之间猜系统是否还在运行。
|
||||
|
||||
当前已有的 `mnote-local-ocr-task-dock` 是迁移起点,不是长期终点。它应升级为全局 `Work Task Center`:
|
||||
|
||||
```text
|
||||
Topbar task button
|
||||
-> badge: active / failed / needs attention count
|
||||
-> drawer: current jobs + recent completed + failed
|
||||
-> row: icon + title + stage label + progress bar + actions
|
||||
-> detail: input/result/error + related document/resource + trace/run receipt
|
||||
```
|
||||
|
||||
入口位置:
|
||||
|
||||
- 顶栏保留一个任务中心图标,建议使用 `progress_activity` 或 `pending_actions`。
|
||||
- OCR 和索引设置按钮仍可保留,但它们不再各自承载任务列表。
|
||||
- 任务中心抽屉优先靠右打开,保持轻量;不做全屏管理台作为第一阶段。
|
||||
|
||||
任务行最小字段:
|
||||
|
||||
| 字段 | 来源 | UI 用途 |
|
||||
| --- | --- | --- |
|
||||
| `jobId` | job ledger | 稳定 row key 和详情查询 |
|
||||
| `jobType` | job ledger | 图标、分类、筛选 |
|
||||
| `status` | job ledger | 颜色、分组、是否需要确认 |
|
||||
| `stageLabel` | job event | 当前阶段文案 |
|
||||
| `progressCurrent / progressTotal` | job event | 确定性进度条 |
|
||||
| `createdAtMs / startedAtMs / finishedAtMs` | job ledger | 排队/耗时/最近完成 |
|
||||
| `targetDocumentId` | job ledger | 打开 owner 文档 |
|
||||
| `sourceRootRelativePath` | job ledger | 打开附件或定位资源 |
|
||||
| `artifactRootRelativePath / sourceMapRootRelativePath` | result | 打开 OCR/parse/source-map |
|
||||
| `errorCode / errorMessage` | job ledger | 失败摘要和复现证据 |
|
||||
|
||||
进度规则:
|
||||
|
||||
- 有 `progressCurrent / progressTotal` 时显示确定性进度条。
|
||||
- 没有总量但 status 为 running 时显示细条 indeterminate,不伪造百分比。
|
||||
- `queued / retry_scheduled` 显示排队态,不显示假进度。
|
||||
- `failed` 和 `retry_scheduled` 必须进入“需要处理”计数。
|
||||
- `succeeded` 默认保留在最近完成列表,可由用户清除/ack。
|
||||
|
||||
任务动作:
|
||||
|
||||
| 状态 | 动作 |
|
||||
| --- | --- |
|
||||
| running | 打开目标、查看详情 |
|
||||
| succeeded | 打开结果、打开目标、清除 |
|
||||
| failed | 查看错误、重试、打开目标、复制错误摘要 |
|
||||
| retry_scheduled | 查看重试原因、立即重试、取消重试 |
|
||||
| stale | 重新生成、打开旧结果 |
|
||||
|
||||
事件与数据流:
|
||||
|
||||
```text
|
||||
GET /api/work/jobs?scope=currentWorkspace&active=true
|
||||
GET /api/work/jobs?scope=currentWorkspace&recent=true
|
||||
GET /api/work/jobs/:jobId
|
||||
POST /api/work/jobs/:jobId/ack
|
||||
POST /api/work/jobs/:jobId/retry
|
||||
SSE/WS event: resource_work.job.updated
|
||||
```
|
||||
|
||||
前端运行时:
|
||||
|
||||
- 新增 `browser/work-task-center-runtime.js`,由 `layout.rs` 统一注入。
|
||||
- 现有 `document-resource-tab-runtime.js` 中 OCR task dock 的 state/render 逻辑迁入该 runtime。
|
||||
- `mnote:local-ocr-job-updated` 作为兼容事件继续转发为 `resource_work.job.updated`,直到后端统一 payload 完成。
|
||||
- 前端只在启动时拉一次 active/recent snapshot;后续靠 WS/SSE 事件更新,不新增周期轮询。
|
||||
|
||||
视觉约束:
|
||||
|
||||
- 顶栏只显示一个任务中心 badge,避免 OCR/索引/AI 各自占顶栏状态位。
|
||||
- 抽屉行要密集、可扫描,不能做大卡片堆叠。
|
||||
- 每行必须有可见进度或阶段文本,长路径截断但 title 保留完整路径 tooltip。
|
||||
- 移动端抽屉宽度占满可用宽度,任务行按钮折到第二行,避免文字溢出。
|
||||
|
||||
## 4. 不做什么
|
||||
|
||||
- 不把 paperless-ngx 的 Django model / Angular UI / Celery worker 引入 MNote。
|
||||
- 不把 OCR Markdown、parse Markdown 或 evidence.sqlite 变成正文真相。
|
||||
- 不新增前端轮询来弥补 job 状态;状态更新走现有 WS / SSE / watcher event。
|
||||
- 不把任务 UI 继续拆成 OCR 一套、索引一套、AI 一套;这些只能是任务中心里的分类或过滤。
|
||||
- 不让 workflow UI 先行。先做 event-triggered job 和少量内置动作,再考虑可视化配置。
|
||||
- 不在本轮实现向量 RAG。Paperless 的 FAISS append-only 方案只作为反例和参考,不作为 MNote 默认路径。
|
||||
|
||||
## 5. 实施分期
|
||||
|
||||
### Phase A:设计冻结和接口补齐
|
||||
|
||||
Owner:07-ai / 03-rust-web
|
||||
|
||||
任务:
|
||||
|
||||
- [ ] 在 `core-protocol` 增加 `ResourceWorkJob` / `ResourceWorkJobStatus` / `ResourceWorkTriggerSource` 合同。
|
||||
- [ ] 在 job 合同中加入 `stage / stageLabel / progressCurrent / progressTotal`,作为前台任务中心稳定字段。
|
||||
- [ ] 明确 `local_ocr.job.updated` 与新 `resource_work.job.updated` 的兼容关系。
|
||||
- [ ] 在 `7-46` 里引用本设计作为 job / index lifecycle 的执行补充。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] Rust unit 覆盖 job status 序列化。
|
||||
- [ ] Rust unit 覆盖 progress 字段缺省、确定性进度和 indeterminate 语义。
|
||||
- [ ] 不改变现有 OCR smoke 行为。
|
||||
|
||||
### Phase B:OCR job ledger 收口
|
||||
|
||||
Owner:03-rust-web / control-plane
|
||||
|
||||
任务:
|
||||
|
||||
- [ ] 给 `local_ocr::create_job` 创建 control-plane job 记录。
|
||||
- [ ] 每次 stage advance 同步 job ledger。
|
||||
- [ ] `done / failed` 写入 `finished_at_ms / result_json / error_code`。
|
||||
- [ ] 增加 `GET /api/work/jobs/:jobId`。
|
||||
- [ ] 增加 `GET /api/work/jobs?active=true&recent=true`,供任务中心首屏 snapshot 使用。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] 现有 OCR sidecar smoke 仍通过。
|
||||
- [ ] 新增 smoke 验证 OCR job 可查询、失败错误脱敏、done 后 result 包含 sidecar 和 source-map。
|
||||
- [ ] 新增 smoke 验证 active snapshot 包含运行中 OCR job,完成后转入 recent。
|
||||
|
||||
### Phase B2:统一任务中心 UI
|
||||
|
||||
Owner:03-rust-web / 05-editor-mainline
|
||||
|
||||
任务:
|
||||
|
||||
- [ ] 新增 `browser/work-task-center-runtime.js`。
|
||||
- [ ] 将 `mnote-local-ocr-task-dock` 的状态聚合和 drawer 渲染迁移到 work task center。
|
||||
- [ ] 顶栏新增统一任务中心按钮和 badge,OCR 按钮回归 OCR 设置入口或合并进设置面板。
|
||||
- [ ] 支持 active / needs attention / recent 三个分组。
|
||||
- [ ] 任务行支持确定性 progress bar、indeterminate running bar、失败重试、打开目标、打开结果、ack。
|
||||
- [ ] 兼容接收 `mnote:local-ocr-job-updated`,并在后端统一事件上线后接 `resource_work.job.updated`。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] 浏览器 smoke:触发 OCR 后顶栏 badge 从 0 变 1,抽屉显示阶段和进度。
|
||||
- [ ] 浏览器 smoke:OCR 完成后任务移入 recent,能打开 OCR sidecar。
|
||||
- [ ] 浏览器 smoke:mock 失败任务进入 needs attention,能查看错误和重试。
|
||||
- [ ] 截图验证桌面和移动端抽屉不溢出、不遮挡主编辑区关键内容。
|
||||
|
||||
### Phase C:Evidence index lifecycle
|
||||
|
||||
Owner:07-ai / 03-rust-web
|
||||
|
||||
任务:
|
||||
|
||||
- [ ] 给 evidence.sqlite 增加 schema/settings sentinel。
|
||||
- [ ] index refresh 写入 job id 或 index-local job metadata。
|
||||
- [ ] lock / write / parse source-map 失败时进入 retry-scheduled 或 failed job。
|
||||
- [ ] `mnote.index.status` 返回 schema、last build、last job、pending retry。
|
||||
- [ ] index refresh / rebuild 通过任务中心显示阶段和结果摘要。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] `task528-document-evidence-liteparse-agent-smoke.js` 继续通过。
|
||||
- [ ] 新增 index stale / rebuild smoke,验证删除 evidence.sqlite 后可通过 job 重建。
|
||||
- [ ] 浏览器 smoke 验证 index rebuild 任务出现在任务中心。
|
||||
|
||||
### Phase D:Workspace sanity check
|
||||
|
||||
Owner:03-rust-web / 04-tree-domain
|
||||
|
||||
任务:
|
||||
|
||||
- [ ] 实现只读 `workspace_sanity_check` job。
|
||||
- [ ] 检查 owner Markdown、resource file、sidecar、source-map、evidence.sqlite。
|
||||
- [ ] 结果按 error / warning / info 分级。
|
||||
- [ ] 从任务中心和 index/OCR 设置 surface 都能启动检查;结果统一进入任务中心详情。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] smoke 构造缺失 source-map、孤儿 sidecar、损坏 sqlite,能得到稳定 JSON。
|
||||
- [ ] 不删除、不移动任何用户文件。
|
||||
- [ ] 浏览器 smoke 验证 sanity check 运行时有任务行,完成后详情展示 error / warning / info 摘要。
|
||||
|
||||
### Phase E:内置 workflow actions
|
||||
|
||||
Owner:01-tree-first-graph-kernel / 07-ai
|
||||
|
||||
任务:
|
||||
|
||||
- [ ] 定义内置事件:`resource.created`、`resource.changed`、`ocr.done`、`evidence.index.failed`。
|
||||
- [ ] 定义内置动作:`parse_resource`、`run_ocr`、`refresh_evidence_index`、`schedule_sanity_check`。
|
||||
- [ ] 先用静态配置或 settings 控制,不做复杂 UI。
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] 新增附件后能按 settings 自动排 parse/OCR/index job。
|
||||
- [ ] 失败不会循环重试;必须有 retry budget 和可见错误。
|
||||
|
||||
## 6. 设计验收基线
|
||||
|
||||
本设计完成后,MNote 应具备以下能力:
|
||||
|
||||
- 用户能看到后台 OCR / parse / index / sanity job 的真实状态,而不是只看到散落的 toast 或局部状态灯。
|
||||
- 顶栏任务中心能显示 active / failed / recent 任务,且所有任务进度来自 job ledger 或 job event,不伪造百分比。
|
||||
- agent 调用 evidence 工具时,MNote 能把本次证据索引状态、evidence ids、source-map path 写入 run receipt。
|
||||
- 删除或损坏 evidence.sqlite 不会让系统静默退化;会显示 rebuild required 或排 rebuild job。
|
||||
- OCR sidecar、parse artifact、source-map 和 evidence locator 可以被 sanity check 证明互相可追溯。
|
||||
- 多人 / share 场景下,job event 有明确可见性字段,不把本地单用户广播模型固化成长期事实。
|
||||
|
||||
## 7. 参考代码索引
|
||||
|
||||
Paperless-ngx:
|
||||
|
||||
- `src/documents/models.py`:`PaperlessTask`、workflow model、document version fields。
|
||||
- `src/documents/tasks.py`:`consume_file`、index deferred tasks、bulk update。
|
||||
- `src/documents/consumer.py`:resource consume main path。
|
||||
- `src/documents/plugins/base.py`:plugin lifecycle contract。
|
||||
- `src/documents/plugins/helpers.py`:progress websocket payload。
|
||||
- `src/documents/search/_backend.py`:Tantivy backend、lock retry、autocomplete、highlight。
|
||||
- `src/documents/search/_schema.py`:schema version sentinel。
|
||||
- `src/documents/search/_query.py`:permission filter、date rewrite、CJK/simple query。
|
||||
- `src/documents/sanity_checker.py`:archive consistency checker。
|
||||
- `src/paperless/consumers.py`:permission-aware websocket consumer。
|
||||
|
||||
MNote 当前落点:
|
||||
|
||||
- `rust/crates/core-protocol/src/governance.rs`
|
||||
- `rust/crates/core-protocol/src/evidence.rs`
|
||||
- `rust/crates/core-protocol/src/tool.rs`
|
||||
- `rust/crates/mnote-web/src/routes/local_ocr.rs`
|
||||
- `rust/crates/mnote-web/src/routes/local_search_index.rs`
|
||||
- `rust/crates/mnote-web/src/routes/evidence.rs`
|
||||
- `rust/crates/mnote-web/src/routes/local_folder_events.rs`
|
||||
- `rust/crates/mnote-web/src/routes/ws.rs`
|
||||
- `scripts/task528-document-evidence-liteparse-agent-smoke.js`
|
||||
Reference in New Issue
Block a user