556 lines
38 KiB
Markdown
556 lines
38 KiB
Markdown
> 状态补充(2026-06-25):本稿降级为 opencode runtime / iframe fallback 参考;Page AI 产品主线由 `7-68-openhub-weknora-mnote-deep-fusion-v1.md` 接管。
|
||||
|
|
|
|||
|
|
# 7-65 [process] Page AI opencode WebUI embed v1
|
|||
|
|
|
|||
|
|
> 创建时间:2026-06-23
|
|||
|
|
>
|
|||
|
|
> 当前状态:`PROCESS / opencode-chat style iframe MVP 已落地,bridge 与 event receipt 已补第一版`
|
|||
|
|
>
|
|||
|
|
> Owner:07-ai / Page AI / opencode WebUI embed
|
|||
|
|
>
|
|||
|
|
> 替代方案:
|
|||
|
|
> - `design/old/07-ai/process/7-62-recycle-page-ai-board-first-full-rewrite-v1.md`
|
|||
|
|
> - `design/old/07-ai/process/7-63-recycle-page-ai-board-first-productization-v1.md`
|
|||
|
|
> - `design/old/07-ai/process/7-64-recycle-codexmobile-embed-page-ai-v1.md`
|
|||
|
|
>
|
|||
|
|
> 上位依据:
|
|||
|
|
> - `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
|
|||
|
|
> - `design/07-ai/done/7-38-page-ai-sidebar-runtime-owner-split-v1.md`
|
|||
|
|
> - `design/07-ai/done/7-40-page-ai-context-envelope-and-run-receipt-v1.md`
|
|||
|
|
> - `design/07-ai/done/7-50-lightrag-knowledge-rag-provider-v1.md`
|
|||
|
|
|
|||
|
|
## 1. 核心结论
|
|||
|
|
|
|||
|
|
废弃 MNote Page AI 自研 provider 接入与 Board-first 产品壳,改为 **只接入 opencode 官方 runtime + 官方 WebUI**。
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
MNote Page AI = MNote 宿主壳 + opencode 官方 WebUI + MNote 打开/刷新/上下文集成
|
|||
|
|
opencode = 官方 WebUI + 官方 HTTP server/OpenAPI/SSE + 官方 SDK + opencodego provider
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
MNote 不再直接维护 Reasonix / ZCode / Hermes / Chat-only / Board worker 作为页面 AI provider。它们可以继续存在于历史、调试或外部工作流边界,但不进入 Page AI 主路径。
|
|||
|
|
|
|||
|
|
选择 opencode 的原因:
|
|||
|
|
- `opencode web` 官方提供本地 WebUI,不需要 MNote 自研完整聊天前端。
|
|||
|
|
- `opencode serve` 官方提供 headless HTTP server 和 OpenAPI,适合 MNote 做轻量 adapter。
|
|||
|
|
- `@opencode-ai/sdk` 覆盖 session、message、diff、permission、event,足够承接上下文注入与回写 receipt。
|
|||
|
|
- opencode 原生支持 SSE、权限审批、文件 diff、MCP、ACP、session export/import。
|
|||
|
|
- 本机已有 `opencode` 和 opencodego 订阅链路,provider/runtime/UI 属于同一生态,少一层兼容债。
|
|||
|
|
|
|||
|
|
## 2. 明确废弃
|
|||
|
|
|
|||
|
|
### 2.1 Page AI 主路径不再接入
|
|||
|
|
|
|||
|
|
- Reasonix native session / Reasonix desktop bridge。
|
|||
|
|
- ZCode worker / Board worker selector。
|
|||
|
|
- Hermes profile / Hermes Web control surface。
|
|||
|
|
- Chat-only remote conversation。
|
|||
|
|
- Agent Board run/workflow 作为默认 Page AI 后端。
|
|||
|
|
- CodexMobile iframe 作为默认 Page AI 后端。
|
|||
|
|
|
|||
|
|
这些能力不删除历史代码,不立刻清理工具层,只从 Page AI 新主路径退出。
|
|||
|
|
|
|||
|
|
### 2.2 仍可保留的边界
|
|||
|
|
|
|||
|
|
- `mnote.doc.*`、`mnote.block.*`、LightRAG facade 等工具可继续作为 opencode 可调用的 MCP/工具能力。
|
|||
|
|
- Agent Board 仍可作为外部 workflow/QA/review 系统,不再作为 Page AI 默认聊天后端。
|
|||
|
|
- CodexMobile 可保留为备选 spike 或体验对照,不作为当前实现目标。
|
|||
|
|
|
|||
|
|
## 3. 新系统边界
|
|||
|
|
|
|||
|
|
### 3.1 MNote 只做四件事
|
|||
|
|
|
|||
|
|
1. **上下文**:当前页、选区、页面标题、真实 `.md` 路径、workspaceId、allowed roots、LightRAG 引用。
|
|||
|
|
2. **授权**:把 MNote local-first 文件权限转换为 opencode permission / external_directory / working directory。
|
|||
|
|
3. **嵌入**:第一版通过 MNote 同源受登录态保护反代嵌入 opencode 官方 WebUI;`npm run dev:hot` 默认拉起 `opencode serve --hostname=127.0.0.1 --port 4096`。
|
|||
|
|
4. **回执**:监听 opencode event/diff,触发 MNote watcher 刷新,记录 Page AI session binding。
|
|||
|
|
|
|||
|
|
### 3.2 opencode 负责完整 agent runtime
|
|||
|
|
|
|||
|
|
- 聊天 UI。
|
|||
|
|
- 流式事件。
|
|||
|
|
- session 管理与恢复。
|
|||
|
|
- provider/model 调用。
|
|||
|
|
- tool call 展示。
|
|||
|
|
- permission ask/allow/deny。
|
|||
|
|
- 文件读写、patch、diff。
|
|||
|
|
- MCP / ACP / agent 配置。
|
|||
|
|
|
|||
|
|
### 3.3 集成形态:不是新的 Leptos island
|
|||
|
|
|
|||
|
|
当前 MNote 文档编辑器已经是 `leptos_tiptap_island`,但 Page AI 不应该再做一个重前端 island。Page AI 更像 VSCode 里的 Cline:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
VSCode workbench host + Cline webview/extension
|
|||
|
|
MNote web shell host + opencode WebUI iframe/bridge
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
因此第一版形态是 **mnote-web sidebar host runtime**:
|
|||
|
|
- 继续使用 `rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js` 作为宿主入口,但把它瘦身成 opencode host。
|
|||
|
|
- iframe 内尽量保留 opencode 官方 UI,包括消息、tool、permission、diff/session 页面。
|
|||
|
|
- iframe 外只放 MNote 必要宿主控件:当前页 context bar、打开变更、刷新当前页、授权状态、运行状态。
|
|||
|
|
- 不新建 Leptos island,不引入 React/Vue 到 MNote 主壳,不重写 opencode 消息 UI。
|
|||
|
|
|
|||
|
|
如果后续必须深度定制 opencode UI,也优先 fork opencode WebUI 的少量页面,而不是在 MNote 里复刻一套聊天前端。
|
|||
|
|
|
|||
|
|
## 4. 集成拓扑
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
MNote Rust SSR :3000
|
|||
|
|
└─ Page AI sidebar
|
|||
|
|
├─ MNote host chrome
|
|||
|
|
│ [当前页] [选区] [可写目录] [知识库引用]
|
|||
|
|
│ [打开变更] [刷新当前页] [在主编辑区打开]
|
|||
|
|
└─ iframe http://127.0.0.1:4096/<project>/session
|
|||
|
|
↓ first MVP direct localhost iframe
|
|||
|
|
opencode web :4096
|
|||
|
|
├─ 官方 WebUI
|
|||
|
|
├─ 官方 HTTP server / OpenAPI
|
|||
|
|
├─ SSE /event
|
|||
|
|
├─ session/message/diff/permission APIs
|
|||
|
|
└─ opencodego / configured providers
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
第一版优先 iframe 官方 WebUI,不 fork、不精简、不重写样式。实测 opencode WebUI 使用根路径 `/assets`、`/session`、`/global/health` 等资源/API,子路径 `/page-ai/opencode/` iframe 会产生 root path 错位;因此 MVP 采用 MNote 同源根路径反代 `/<base64-project>/session/<sessionId>`,让 iframe 内 `location.pathname` 与 opencode 官方 WebUI 预期保持一致,同时通过 MNote 登录态保护反代入口。`/api/page-ai/opencode/*` 负责 session binding、context 注入、status、diff/receipt adapter。只有 iframe/adapter 实测无法满足产品嵌入时,才考虑 fork WebUI。
|
|||
|
|
|
|||
|
|
### 4.1 MNote host chrome
|
|||
|
|
|
|||
|
|
Page AI 抽屉由 MNote 控制尺寸、开关、上下文和跨应用动作,opencode 只负责 AI 交互主体。
|
|||
|
|
|
|||
|
|
宿主控件最小集:
|
|||
|
|
- 当前页 pill:标题、相对路径、读写状态。
|
|||
|
|
- 选区 pill:有选区才展示,点击可重新注入上下文。
|
|||
|
|
- 变更 pill:来自 opencode diff/event,点击用 MNote 打开对应文件。
|
|||
|
|
- 刷新按钮:调用 `window.__mnoteDocumentPaneRuntime.refreshPrimaryDocument()`。
|
|||
|
|
- 打开按钮:调用 `window.__mnoteDocumentPaneRuntime.openResourceInActiveTab()`。
|
|||
|
|
|
|||
|
|
这些控件由 MNote 渲染,避免修改 opencode 官方页面结构。
|
|||
|
|
|
|||
|
|
### 4.2 MNote 打开 opencode 变更
|
|||
|
|
|
|||
|
|
opencode WebUI 里的 diff / changed file 默认按 opencode 自己的 UI 打开。MNote 需要额外提供宿主打开能力:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
opencode diff/event
|
|||
|
|
→ MNote adapter 归一化 changed files
|
|||
|
|
→ Page AI host chrome 显示 changed file chips
|
|||
|
|
→ 用户点击 chip
|
|||
|
|
→ window.__mnoteDocumentPaneRuntime.openResourceInActiveTab({ path })
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
第一版不强行改 opencode diff 内部点击行为;先在 iframe 外给 MNote-native changed file chips。这样即使 opencode DOM 改版,MNote 打开变更仍可用。
|
|||
|
|
|
|||
|
|
### 4.3 可选 bridge:只做宿主动作,不接管 UI
|
|||
|
|
|
|||
|
|
如果需要让 opencode 官方 UI 内部的文件链接也能用 MNote 打开,可在同源反代 HTML 中注入一个很小的 bridge 脚本:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
opencode iframe click(file/diff link)
|
|||
|
|
→ postMessage({ type: 'mnote:open-file', path })
|
|||
|
|
→ parent MNote host 调用 openResourceInActiveTab
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
bridge 只允许三类消息:
|
|||
|
|
- `mnote:open-file`
|
|||
|
|
- `mnote:refresh-file`
|
|||
|
|
- `mnote:session-ready`
|
|||
|
|
|
|||
|
|
不通过 bridge 解析模型事件、不重绘消息、不替换 permission UI。DOM 选择器脆弱时立即退回 host chrome chips。
|
|||
|
|
|
|||
|
|
## 5. 最小实现
|
|||
|
|
|
|||
|
|
### Phase A:runtime spike
|
|||
|
|
|
|||
|
|
- [x] 运行 `opencode --version`、`opencode web --help`、`opencode serve --help`;当前版本已升级到 `1.17.9`。
|
|||
|
|
- [x] 卸载 oh-my-openagent / oh-my-opencode 默认插件:`opencode.json` 中 `plugin` 已为空,`oh-my-openagent.jsonc` 已移除并备份。
|
|||
|
|
- [x] 启动/复用 `opencode serve --hostname=127.0.0.1 --port=4096`,`/global/health` 返回 healthy。
|
|||
|
|
- [x] 验证 WebUI 可打开、可进入 `/mnt/Data1T/mnote` project session、可真实回复。
|
|||
|
|
- [x] 验证 opencodego/OmniRoute 模型可用:iframe 内真实回复 `OPENCODE_MNOTE_IFRAME_OK_*`。
|
|||
|
|
- [x] 验证当前工作目录指向 MNote workspace:`/session` 返回 `directory=/mnt/Data1T/mnote`。
|
|||
|
|
- [x] 验证编辑一个 `.md` 文件后,`/session/:id/diff` 能返回文件 diff:`opencode-smoke-test.md` 返回 `modified` diff。
|
|||
|
|
- [ ] `/event` SSE 只做了接口可达性探索,尚未接入持续事件消费。
|
|||
|
|
|
|||
|
|
### Phase B:MNote iframe embed
|
|||
|
|
|
|||
|
|
- [x] Rust 新增 `/page-ai/opencode/{*path}` 反向代理到 `127.0.0.1:4096`,并新增 `/api/page-ai/opencode/status`、`/api/page-ai/opencode/diff`。
|
|||
|
|
- [x] 只允许已登录 MNote session 访问反代/API;未登录请求返回 `401 page_ai_opencode_unauthorized`。
|
|||
|
|
- [x] Page AI sidebar 精简为:MNote host chrome + iframe + basic status。
|
|||
|
|
- [x] 尽量不改 opencode WebUI,保留官方页面布局、消息样式、tool/diff/permission UI。
|
|||
|
|
- [x] iframe 容器与 host chrome 由 `sidebar-page-ai-runtime.js` + `page-ai.css` 承载,不新增 Page AI Leptos island。
|
|||
|
|
- [x] WebUI 默认 iframe 使用 MNote 同源 `/<base64-project>/session` 反代;避免局域网浏览器访问自身 `127.0.0.1:4096`,同时保留 opencode 官方 URL 形态。
|
|||
|
|
|
|||
|
|
### Phase B2:MNote-native changed files
|
|||
|
|
|
|||
|
|
- [x] 建立 opencode sessionId ↔ MNote host 状态的持久 binding:`/api/page-ai/opencode/session` 创建/复用 session,并落 SQLite/control-plane,按用户/session/workspace 区分。
|
|||
|
|
- [x] 通过 `/api/page-ai/opencode/events` 代理 opencode `/event`,收到 session/message/diff/file 事件后触发有界 refresh。
|
|||
|
|
- [x] 通过 `/session/:id/diff` 生成 changed file chips。
|
|||
|
|
- [x] chip 点击走 `window.__mnoteDocumentPaneRuntime.openResourceInActiveTab()`。
|
|||
|
|
- [x] 当前页刷新按钮已走 `refreshPrimaryDocument({ reason: 'page-ai-opencode-host' })`;changed files 命中当前页时由 event/diff refresh 链路自动触发刷新。
|
|||
|
|
|
|||
|
|
### Phase C:context 注入
|
|||
|
|
|
|||
|
|
优先不修改 opencode WebUI,通过官方 API/SDK 注入上下文:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
MNote open Page AI
|
|||
|
|
→ create or resume opencode session
|
|||
|
|
→ session.prompt(noReply=true, parts=[MNote context envelope])
|
|||
|
|
→ iframe 打开对应 session
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
上下文 envelope 内容:
|
|||
|
|
- 当前页标题。
|
|||
|
|
- 当前页真实 Markdown 路径。
|
|||
|
|
- selection 文本。
|
|||
|
|
- allowed roots 与读写权限。
|
|||
|
|
- LightRAG 引用摘要。
|
|||
|
|
- 当前任务约束:优先编辑 primaryTarget,禁止越权修改。
|
|||
|
|
|
|||
|
|
当前状态:`done for MVP`。host chrome 已展示当前页、真实 Markdown path(可定位时)、selection、allowed roots/writable 状态;打开 Page AI 时会调用 `/api/page-ai/opencode/session`,用 `noReply=true` 向 opencode session 注入 MNote context envelope,并把 iframe 打到绑定 session URL。2026-06-24 已按 opencode-chat 参考改回官方 WebUI iframe 主路径,MNote-native timeline 仅保留为 debug/receipt 边界。
|
|||
|
|
|
|||
|
|
### Phase D:writeback / receipt
|
|||
|
|
|
|||
|
|
- [x] 监听 opencode `/event` 或 SDK `event.subscribe()`:当前通过 `/api/page-ai/opencode/events` 代理 `/event`,EventSource 收到相关事件后触发有界 refresh。
|
|||
|
|
- [partial] prompt / event 后通过绑定 session 的 `/session/:id/diff` 刷新 changed files;仍需继续核对 opencode 各类 file/diff event payload。
|
|||
|
|
- [x] changed files 命中当前页时调用 `refreshPrimaryDocument({ reason: 'page-ai-opencode-event' })`;手动刷新按钮保留。
|
|||
|
|
- [x] 保存 MNote pageId ↔ opencode sessionId binding:当前已落 SQLite/control-plane,按用户/session/workspace 区分;浏览器刷新后可恢复同一 binding。
|
|||
|
|
- [x] Page AI context bar 显示最近一次 changed files / runtime / error 摘要。
|
|||
|
|
|
|||
|
|
### Phase E:可选 WebUI bridge
|
|||
|
|
|
|||
|
|
- [ ] 只有 host chrome chips 体验不足时,才在反代层注入 `mnote-opencode-bridge.js`。
|
|||
|
|
- [ ] bridge 只把 opencode UI 内部文件点击转成 `postMessage`。
|
|||
|
|
- [ ] bridge 不解析/修改 opencode 消息流、tool UI、permission UI。
|
|||
|
|
- [ ] selector 失效时不阻塞主流程,回退 host chrome chips。
|
|||
|
|
|
|||
|
|
## 6. 安全与权限
|
|||
|
|
|
|||
|
|
- opencode 只监听 `127.0.0.1`;MVP iframe 直连本机地址,同源反代/API 仍必须受 MNote 登录态保护。
|
|||
|
|
- 生产/长期运行必须设置 `OPENCODE_SERVER_PASSWORD`,或改为完整同源反代 + MNote 反代层隔离。
|
|||
|
|
- opencode working directory 优先指向当前 workspace root。
|
|||
|
|
- MNote allowed roots 映射到 opencode permission:
|
|||
|
|
- 当前 workspace root:允许读,写按用户授权。
|
|||
|
|
- 当前页文件:允许读写。
|
|||
|
|
- workspace 外路径:默认 deny,必要时显式 `external_directory`。
|
|||
|
|
- 不使用 `--dangerously-skip-permissions` 作为默认路径。
|
|||
|
|
|
|||
|
|
## 7. 验收标准
|
|||
|
|
|
|||
|
|
### 7.1 UI
|
|||
|
|
|
|||
|
|
- Page AI 面板内显示 opencode 官方 WebUI。
|
|||
|
|
- 官方消息流、tool 卡片、permission 交互、diff/session UI 尽量原样保留。
|
|||
|
|
- MNote 只在 iframe 外展示 host chrome,不重做 opencode UI。
|
|||
|
|
- opencode 产生的 changed files 可以用 MNote 主编辑区或资源 tab 打开。
|
|||
|
|
|
|||
|
|
### 7.2 Runtime
|
|||
|
|
|
|||
|
|
- 可创建/恢复 opencode session。
|
|||
|
|
- 可用 opencodego 模型完成真实回复。
|
|||
|
|
- 流式回复浏览器可见。
|
|||
|
|
- 权限审批走 opencode 原生机制。
|
|||
|
|
- 文件修改后 MNote 当前页面能刷新。
|
|||
|
|
|
|||
|
|
### 7.3 代码收敛
|
|||
|
|
|
|||
|
|
- `sidebar-page-ai-runtime.js` 不再承载 Reasonix/ZCode/Hermes/Board provider 状态机。
|
|||
|
|
- 不新增 MNote 自研聊天 message store。
|
|||
|
|
- 不 fork opencode WebUI,除非 spike 证明 iframe 方案不可用。
|
|||
|
|
- 不新增 Page AI Leptos island;Page AI 是 mnote-web sidebar host runtime。
|
|||
|
|
|
|||
|
|
## 8. 与旧方案对比
|
|||
|
|
|
|||
|
|
| 方案 | 优点 | 主要问题 | 当前结论 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| Board-first | 可接多 worker/workflow | MNote 仍要维护产品壳和 Board adapter,聊天体验不成熟 | 废弃为主路径 |
|
|||
|
|
| CodexMobile embed | Codex 体验强,贴近现有 Codex 体系 | 需要 fork/精简/修 bug,维护派生产品 | 备胎/对照 |
|
|||
|
|
| opencode WebUI embed | 官方 runtime + 官方 WebUI + 官方 API,维护成本低 | opencode 能力可能不如 Codex 先进,嵌入细节需实测 | 当前主路径 |
|
|||
|
|
|
|||
|
|
## 9. 非目标
|
|||
|
|
|
|||
|
|
- 不重写 opencode WebUI。
|
|||
|
|
- 不把 opencode WebUI 拆成 MNote 原生组件。
|
|||
|
|
- 不同时接入 Reasonix/ZCode/Hermes/CodexMobile 多后端。
|
|||
|
|
- 不把 Agent Board 控制台嵌入 Page AI。
|
|||
|
|
- 不在第一版实现完整 MNote SSO 到 opencode;先由 MNote 反代保护。
|
|||
|
|
|
|||
|
|
## 10. 退出条件
|
|||
|
|
|
|||
|
|
只有出现以下任一情况,才重新启用 CodexMobile 或自研 UI 方案:
|
|||
|
|
|
|||
|
|
- opencode WebUI 无法稳定 iframe/反代嵌入。
|
|||
|
|
- opencode session 无法通过 API 定位并打开指定 session。
|
|||
|
|
- opencode 无法可靠编辑 MNote workspace 文件。
|
|||
|
|
- opencode permission/diff/event 无法满足 MNote 最小安全闭环。
|
|||
|
|
- opencodego/provider 链路在真实使用中明显不稳定且短期不可修。
|
|||
|
|
|
|||
|
|
|
|||
|
|
## 9. 2026-06-24 iframe 主路径验证记录
|
|||
|
|
|
|||
|
|
- [x] `opencode --version`:`1.17.9`。
|
|||
|
|
- [x] `opencode serve --hostname=127.0.0.1 --port 4096 --print-logs`:真实可启动;官方 WebUI URL `http://127.0.0.1:4096/L21udC9EYXRhMVQvbW5vdGU/session` 可显示 `Build anything`。
|
|||
|
|
- [x] `npm run dev:hot`:真实拉起 `mnote-web :3000` 和 `opencode :4096`。
|
|||
|
|
- [x] 浏览器 smoke:登录 `mnote.e2e@example.com` 后打开 Page AI,iframe URL 为 `http://127.0.0.1:3000/L21udC9EYXRhMVQvbW5vdGU/session`,显示官方 opencode WebUI;截图 `/tmp/mnote-page-ai-opencode-iframe.png`。
|
|||
|
|
- [partial] 发送真实消息:官方 WebUI 可输入并进入 `Thinking/Stop` 运行态;截图 `/tmp/mnote-page-ai-opencode-send.png`。本轮未等待到最终回复,不能声明 provider 回复完成。
|
|||
|
|
- [x] binding 持久化 smoke:浏览器 reload 后仍恢复同一 session `ses_106555512ffe5wDz9eMlP4v2i2`。
|
|||
|
|
- [x] 静态检查:`node --check rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js`。
|
|||
|
|
- [x] Rust 检查:`cd rust && cargo check -p mnote-web`。
|
|||
|
|
|
|||
|
|
剩余 gap:
|
|||
|
|
- [x] 在同源反代层补最小 `postMessage` bridge:`open-file / refresh-file / insert-text`,不接管消息流。
|
|||
|
|
- [partial] 更完整核对 opencode `/event` 的 file/diff payload:已递归解析常见 changed/diff/file payload 并由 event 触发有界 refresh;仍需真实编辑文件后补最终证据。
|
|||
|
|
- [ ] 若要局域网访问,继续确认所有 opencode WebUI root-level API 路由都已被 MNote 登录态反代覆盖,避免直接暴露 4096。
|
|||
|
|
|
|||
|
|
|
|||
|
|
## 10. 2026-06-25 bridge / receipt 补充记录
|
|||
|
|
|
|||
|
|
- [x] HTML 反代注入极小 bridge:只处理 `insert-text / open-file / refresh-file / session-ready`,不接管 opencode 消息流、tool UI、permission UI。
|
|||
|
|
- [x] MNote host chrome 新增“插入当前页上下文”按钮,通过 `postMessage` 把当前页标题、路径、选区、allowed roots 插入 opencode 官方输入框。
|
|||
|
|
- [x] 浏览器 smoke:`/tmp/mnote-page-ai-opencode-bridge-final.png`,验证 iframe 内 `window.__mnoteOpencodeBridgeInstalled === true`,点击 host 按钮后官方输入框出现 `MNote 当前页上下文标题:主页`。
|
|||
|
|
- [x] postMessage smoke:模拟 iframe 发 `open-file / refresh-file`,确认 MNote host 调用 `openResourceInActiveTab()` 与 `refreshPrimaryDocument()`;输出见 `tmp/mnote-opencode-postmessage-smoke.cjs` 运行结果。
|
|||
|
|
- [x] event receipt 强化:`pageAiOpencodeNormalizeChangedFiles()` 改为递归收集 `changedFiles / files / diff / changes / edited / created / deleted / data / properties`,事件到达时先更新 chips,再做有界 projection refresh。
|
|||
|
|
- [x] 静态检查:`node --check rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js`。
|
|||
|
|
- [x] Rust 检查:`cd rust && cargo check -p mnote-web`。
|
|||
|
|
|
|||
|
|
剩余 gap:
|
|||
|
|
- [ ] 让 opencode 真实修改一个测试 Markdown 文件,等待 `/event` + `/session/:id/diff` 产出 changed file chips,再截图验证 chip 点击打开 MNote 主编辑区。
|
|||
|
|
- [ ] 若 opencode 官方 WebUI 后续 CSP 变化,需要把 inline bridge 改成 nonce/hash 或外部小脚本。
|
|||
|
|
|
|||
|
|
## 11. 2026-06-25 opencode 用户隔离与工作目录结论
|
|||
|
|
|
|||
|
|
### 11.1 当前结论
|
|||
|
|
|
|||
|
|
- [x] Page AI 工作目录应简化为“当前用户打开的根文件夹”:MNote 当前只能打开一个大的本地根目录,`rootUri` 对应的真实目录就是 opencode `directory` / project directory。
|
|||
|
|
- [x] 切换根文件夹应视为新的 opencode session 边界:同一用户同一根目录内可按页面恢复 binding;根目录变化时默认新建 session,不把旧 session 带到新根目录。
|
|||
|
|
- [x] MNote 自身 binding 已按 `user_id + workspace_id + mnote_session_id + provider` 隔离;`mnote_session_id` 内包含 workspace/page/directory,因此同一用户跨根目录不会复用同一 binding。
|
|||
|
|
- [partial] opencode 自身默认实例没有 MNote 用户概念;如果所有 MNote 用户共用一个 `opencode serve`,opencode 的 session、permission、credential、account、skill、MCP、snapshot、tool-output 会共用同一套本机状态。
|
|||
|
|
|
|||
|
|
### 11.2 opencode 1.17.9 真实机制证据
|
|||
|
|
|
|||
|
|
本机 spike 使用临时环境启动:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
HOME=/tmp/.../home \
|
|||
|
|
XDG_CONFIG_HOME=/tmp/.../config \
|
|||
|
|
XDG_DATA_HOME=/tmp/.../data \
|
|||
|
|
XDG_CACHE_HOME=/tmp/.../cache \
|
|||
|
|
XDG_STATE_HOME=/tmp/.../state \
|
|||
|
|
opencode serve --port 4197 --hostname 127.0.0.1 --print-logs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
观察结果:
|
|||
|
|
|
|||
|
|
- 配置读取路径变为 `$XDG_CONFIG_HOME/opencode/{config.json,opencode.json,opencode.jsonc}`。
|
|||
|
|
- 持久数据写入 `$XDG_DATA_HOME/opencode/opencode.db`。
|
|||
|
|
- 日志写入 `$XDG_DATA_HOME/opencode/log/opencode.log`。
|
|||
|
|
- 锁写入 `$XDG_STATE_HOME/opencode/locks/*`。
|
|||
|
|
- 当前全局实例的默认持久库是 `/home/lix/.local/share/opencode/opencode.db`。
|
|||
|
|
- `opencode.db` 内包含 `session`、`message`、`part`、`permission`、`credential`、`account`、`account_state`、`project`、`workspace`、`event` 等表;这些表没有 MNote 用户维度。
|
|||
|
|
- `permission` 只按 `project_id + action + resource` 唯一;共用实例会导致不同 MNote 用户在同一 project/directory 下共享 opencode 权限记忆。
|
|||
|
|
- `session` 表包含 `directory` / `project_id` / `workspace_id` / `metadata`,但不包含 MNote `user_id`;共用实例不能作为安全隔离边界。
|
|||
|
|
- opencode 会从当前用户 HOME/配置路径加载 skill/MCP;未隔离时可看到 `/home/lix/.claude`、`/home/lix/.agents`、`/home/lix/.config/opencode/skill` 等重复 skill 警告。
|
|||
|
|
|
|||
|
|
### 11.3 推荐隔离方案
|
|||
|
|
|
|||
|
|
第一版不要试图在单个 opencode server 内实现多用户隔离;改为 **MNote 用户/根目录维度的 opencode runtime profile**:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
MNote user + workspace/rootUri
|
|||
|
|
-> runtime profile id
|
|||
|
|
-> dedicated XDG_CONFIG_HOME / XDG_DATA_HOME / XDG_CACHE_HOME / XDG_STATE_HOME
|
|||
|
|
-> dedicated opencode serve process on 127.0.0.1:dynamic_port
|
|||
|
|
-> MNote 登录态反代 /page-ai/opencode/...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
目录建议:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
$MNOTE_DATA/users/<user-id>/opencode/<workspace-hash>/config/opencode/opencode.json
|
|||
|
|
$MNOTE_DATA/users/<user-id>/opencode/<workspace-hash>/data/opencode/opencode.db
|
|||
|
|
$MNOTE_DATA/users/<user-id>/opencode/<workspace-hash>/cache/opencode/
|
|||
|
|
$MNOTE_DATA/users/<user-id>/opencode/<workspace-hash>/state/opencode/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
配置策略:
|
|||
|
|
|
|||
|
|
- provider/API key 可由 MNote 管理后写入每个 profile 的最小 `opencode.json`,或在本机单用户 dev 模式从 `/home/lix/.config/opencode/opencode.json` 复制 provider/model 白名单。
|
|||
|
|
- skill/MCP 默认不继承宿主 HOME 的全部内容;只显式安装 MNote 允许的 skill/MCP,例如 `codegraph`、`mempalace`、后续 MNote MCP。
|
|||
|
|
- opencode 原生 permission 继续保留,但存储在该 profile 的独立 `opencode.db` 中。
|
|||
|
|
- MNote 的 allowed roots 仍作为上下文与反代边界;opencode 的工作目录固定为当前打开根目录。
|
|||
|
|
|
|||
|
|
### 11.4 session 策略
|
|||
|
|
|
|||
|
|
- 同一 `user_id + workspace_id/rootUri + pageAbsolutePath`:优先恢复 MNote control-plane binding 指向的 opencode session。
|
|||
|
|
- `rootUri` 变化:默认新建 session;旧 binding 保留但不跨根目录复用。
|
|||
|
|
- `pageAbsolutePath` 变化:默认新建或按页面 binding 恢复,不把旧页面上下文继续注入到新页面。
|
|||
|
|
- opencode 原生 session 恢复只作为 profile 内部能力;MNote 是否恢复以 control-plane binding 为准。
|
|||
|
|
- 跨浏览器恢复依赖 SQLite control-plane binding + per-user opencode data profile,不依赖 `sessionStorage`。
|
|||
|
|
|
|||
|
|
### 11.5 后续实现项
|
|||
|
|
|
|||
|
|
- [ ] 新增 opencode runtime profile manager:按 MNote user/rootUri 分配 XDG 目录、端口、启动/健康检查、生命周期。
|
|||
|
|
- [ ] `dev:hot` 继续可一键启动,但默认只启动 dev 单用户 profile;多用户 profile 由后端按需拉起。
|
|||
|
|
- [ ] 反代不再只读 `MNOTE_OPENCODE_BASE_URL` 全局值,需按当前登录用户和 rootUri 解析到对应 profile base URL。
|
|||
|
|
- [ ] session binding metadata 写入 `runtimeProfileId`、`rootUri`、`projectDirectory`、`opencodeDataDir`,方便审计和恢复。
|
|||
|
|
- [ ] 增加最小测试:两个不同 MNote 用户同一 Markdown 根目录下创建 session,不共享 opencode `opencode.db`、permission、session list。
|
|||
|
|
|
|||
|
|
### 11.6 官方/社区多用户实现调研补充
|
|||
|
|
|
|||
|
|
本轮先核验豆包给出的项目名,再补充搜索到的真实社区线索。结论:**没有发现可直接嵌入 MNote 的官方/社区“单 opencode 进程多 MNote 用户强隔离”实现**;官方当前也把多用户 Web/serve 部署视为待增强能力。
|
|||
|
|
|
|||
|
|
豆包列表验真:
|
|||
|
|
|
|||
|
|
| 项目 | 验真结果 | 对 MNote 的价值 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `anomalyco/opencode-orchestrator` | 未找到公开仓库;真实相近项目是 `agnusdei1207/opencode-orchestrator` | 后者是 opencode 多 agent 编排插件,不是多用户 runtime 隔离层 |
|
|||
|
|
| `pRizz/opencode-cloud` / `gitea.com/pRizz/opencode-cloud` | 真实存在 | Docker/container 级隔离参考;安全强但本地 MNote 开销偏大 |
|
|||
|
|
| `oc-ext/ocx` | 未找到公开仓库 | 暂不可作为依据 |
|
|||
|
|
| `daytonaio/daytona-opencode-plugin` | 未找到公开仓库 | 暂不可作为依据 |
|
|||
|
|
| `anomalyco/openwork` | 未找到公开仓库 | 暂不可作为依据 |
|
|||
|
|
| `lucentia/opencode-svip-proxy` | 未找到公开仓库 | 暂不可作为依据 |
|
|||
|
|
| `kwickramasekara/opencode-chat` | 真实存在 | VSCode WebView 嵌入参考:启动/复用 `opencode serve`、固定端口保留 localStorage、WebView proxy、剪贴板/键盘 bridge;不是多用户隔离实现 |
|
|||
|
|
|
|||
|
|
额外发现:
|
|||
|
|
|
|||
|
|
| 项目/线索 | 结论 |
|
|||
|
|
|---|---|
|
|||
|
|
| 官方 `anomalyco/opencode` issue `#20067` | open:请求 `opencode web` 支持 multi-user auth 与 per-user provider credentials;issue 描述确认共享 Web 实例会共享身份、session、provider credentials |
|
|||
|
|
| 官方 `anomalyco/opencode` issue `#5784` | closed:请求多租户 `serve` 下 MCP auth/config;说明多租户 MCP/资源隔离是社区真实痛点,但不是已可用的完整 MNote 用户隔离方案 |
|
|||
|
|
| 官方 `SECURITY.md` | 明确 opencode 不提供安全 sandbox;server mode 只支持 `OPENCODE_SERVER_PASSWORD` Basic Auth;需要真隔离时建议 Docker/VM |
|
|||
|
|
| `millerjes37/opencode-multiplexer` | 真实存在,是 opencode fork 的 multi-client server 支持;文档承认“知道 sessionID 即可交互”的 session hijacking 风险,session ownership 仍是 future enhancement;不适合作 MNote 多用户隔离底座 |
|
|||
|
|
| `joeyism/opencode-multiplexer` | 真实存在,是多 session/多项目终端 dashboard,不是 Web 多用户隔离 |
|
|||
|
|
|
|||
|
|
对当前方案的修正:
|
|||
|
|
|
|||
|
|
- 不应引入豆包描述的“单进程多租户 opencode”作为近期主路径;目前没有可靠公开实现,官方也还在 issue 层面。
|
|||
|
|
- 也不应一开始上 Docker/container;它解决安全隔离但会显著增加本地笔记软件的启动、资源和运维成本。
|
|||
|
|
- 近期最稳妥路线是 **单 opencode 进程 + 单 MNote 当前用户/当前根目录 profile**,先满足本机单用户和局域网同一登录用户;等 MNote 真正进入多用户同时在线场景,再升级为按需 profile manager。
|
|||
|
|
- 若要减少端口/生命周期复杂度,可先采用 `opencode-chat` 的轻量做法:固定一个 dev/local 端口、优先复用已存活 server、MNote 反代统一入口;不要提前实现多实例调度。
|
|||
|
|
- 多用户隔离仍必须作为设计约束保留:不能把共享 opencode `opencode.db` 声称为安全隔离,只能标为单用户/dev 模式。
|
|||
|
|
|
|||
|
|
更新后的分阶段建议:
|
|||
|
|
|
|||
|
|
1. **Phase MVP-local**:一个 MNote 登录用户 + 一个当前根目录 + 一个 opencode server;工作目录固定为 `rootUri`;MNote control-plane 做跨浏览器 session binding。
|
|||
|
|
2. **Phase shared-device**:为每个 MNote 用户准备独立 XDG profile,但不常驻多进程;登录/打开 Page AI 时按需启动,空闲回收。
|
|||
|
|
3. **Phase SaaS/团队**:再评估 `opencode-cloud`/Docker 或等待官方 multi-user auth/per-user credentials 落地;不要自己 fork 官方 opencode 做单进程多租户。
|
|||
|
|
|
|||
|
|
### 11.7 OpenHub 对照结论
|
|||
|
|
|
|||
|
|
`xcl1989/OpenHub` 是目前找到的最接近“opencode 多用户平台”的社区实现,README 明确主张:一个 `opencode serve (:4096)`,后端按用户 workspace 通过 `?directory=` 路由到不同目录,并在应用 SQLite 中维护 users、sessions、messages、permissions、skills、tools 等业务层权限。
|
|||
|
|
|
|||
|
|
可复用点:
|
|||
|
|
|
|||
|
|
- 单 opencode server + per-user workspace:后端调用 `/session`、`/session/{id}/prompt_async`、`/global/event` 时统一带 `directory=<user workspace>`。
|
|||
|
|
- 应用层 session ownership:OpenHub 自己用 SQLite 记录 `conversation_sessions` / messages / user_id,不把 opencode 原生 session 列表直接暴露给所有用户。
|
|||
|
|
- 应用层权限面板:模型权限、工具权限、skill 权限都在业务 DB 中维护,再同步/注入到用户 workspace。
|
|||
|
|
- per-user `.opencode` 目录:README 架构图显示每个 workspace 下有独立 `.opencode/skills`、`.opencode/tools`。
|
|||
|
|
- 单进程运维简单:固定 `OPENCODE_BASE_URL=http://127.0.0.1:4096`,Basic Auth 保护后端到 opencode 的内部访问。
|
|||
|
|
|
|||
|
|
关键风险:
|
|||
|
|
|
|||
|
|
- OpenHub 不是 opencode 原生多租户;它仍依赖一个全局 opencode server 和全局 opencode 数据库/credential/account 状态。
|
|||
|
|
- 隔离主要靠 `directory` 与 OpenHub 后端不暴露跨用户 session;如果绕过 OpenHub 直接访问 opencode,或知道别人的 session id,仍要依赖外层鉴权/反代拦截。
|
|||
|
|
- provider credentials 是 opencode server 全局配置;OpenHub 的用户模型/工具权限是应用层控制,不等于 opencode 内核 per-user credentials。
|
|||
|
|
- 它自研了聊天前端、消息库、知识/记忆/任务系统;这不符合 MNote 当前“尽量保留 opencode 官方 WebUI,不复刻消息 UI”的边界。
|
|||
|
|
|
|||
|
|
对 MNote 的启发:
|
|||
|
|
|
|||
|
|
- OpenHub 证明“单 opencode serve + `?directory=` 按用户工作区隔离”在产品上可跑,比一开始做多进程 profile manager 更轻。
|
|||
|
|
- MNote MVP 可以采用 OpenHub 的轻量隔离思路:固定一个本机 opencode server,所有请求由 MNote 登录态反代,MNote 后端只允许当前用户的 `rootUri` 作为 `directory`,并用 control-plane binding 限制 session ownership。
|
|||
|
|
- 但必须把这种模式标为 **应用层隔离 / 单机可信 opencode 后端**,不能标为强安全多租户。强隔离仍需后续 XDG profile 或 Docker。
|
|||
|
|
|
|||
|
|
更新后的推荐:
|
|||
|
|
|
|||
|
|
1. **立即采用 OpenHub-lite**:单 `opencode serve`、固定端口、MNote 反代、`directory=rootUri`、control-plane session ownership。
|
|||
|
|
2. **不复刻 OpenHub UI**:仍保留 opencode 官方 WebUI iframe;MNote 只做 host chrome、context、open/refresh、changed files。
|
|||
|
|
3. **补安全闸**:所有 `/api/page-ai/opencode/*` 和 iframe 反代必须校验当前登录用户、rootUri、session binding;不允许前端任意传 directory 打开非当前 root。
|
|||
|
|
4. **后续 shared-device 再升级**:当确实有多 MNote 用户同时使用同一机器时,再做 per-user XDG profile manager。
|
|||
|
|
|
|||
|
|
### 11.8 OpenHub 融合可行性评估
|
|||
|
|
|
|||
|
|
用户新判断:OpenHub 的前端、消息库、权限、记忆、文件、任务等功能与 MNote Page AI 长期目标高度重合,应评估是否直接融合,减少 MNote 自研量。
|
|||
|
|
|
|||
|
|
结论:**可融合,但不建议整套 OpenHub 作为 MNote 新后端;推荐抽取 OpenHub Page-AI 子系统,形成 MNote 内的 `OpenHub-lite`。**
|
|||
|
|
|
|||
|
|
可最大化复用的部分:
|
|||
|
|
|
|||
|
|
- **React/AntD 聊天前端**:`SmartQueryPage.jsx`、`ChatInput`、`AssistantMessage`、`ToolCall`、`QuestionForm`、`HistoryDrawer`、`DiffViewer`、`FileManager`、`GitTimeMachine` 等,可作为 Page AI 的 micro frontend,而不是继续维护当前简陋 host UI。
|
|||
|
|
- **消息库模型**:`conversation_sessions`、`conversation_messages`、图片、turn、opencode message id、归档、retry、last-turn delete 等,适合迁移到 MNote control-plane,替代 `sessionStorage` 和当前临时 binding。
|
|||
|
|
- **opencode 单进程接入模式**:后端按用户 workspace/rootUri 调 `/session`、`/session/{id}/prompt_async`、`/global/event` 并带 `directory=`,适合 MNote 当前“一个打开根目录”的简化模型。
|
|||
|
|
- **应用层权限面板**:模型权限、工具权限、skill 权限、usage 统计可以映射到 MNote 用户体系;短期先只做 Page AI 所需的模型/工具/skill 白名单。
|
|||
|
|
- **任务/团队/记忆模块**:Smart Entity、Team、Memory、Scheduler 与 MNote 长期 agent 目标相关,但第一阶段只作为后续模块,不应阻塞 Page AI MVP。
|
|||
|
|
|
|||
|
|
不建议直接搬入的部分:
|
|||
|
|
|
|||
|
|
- OpenHub 自带登录、用户管理、admin 页,与 MNote control-plane auth 重叠;应替换成 MNote 登录态。
|
|||
|
|
- OpenHub FastAPI 后端与 MNote Rust SSR/control-plane 双后端并存会增加部署复杂度;长期应把必要 API/DB schema 移植到 Rust,而不是新增常驻 Python 服务。
|
|||
|
|
- OpenHub 自研知识库/记忆/任务会与 MNote 现有 LightRAG、workspace、tree/file resource、control-plane 产生事实源冲突;应按模块逐步映射。
|
|||
|
|
- OpenHub 不是 opencode 内核级强隔离,仍需 MNote 反代和 session ownership 限制。
|
|||
|
|
|
|||
|
|
推荐融合路线:
|
|||
|
|
|
|||
|
|
1. **Phase 1:iframe micro frontend spike**
|
|||
|
|
- 直接运行 OpenHub 前端的 Page-AI/Chat 子集,嵌入 MNote sidebar。
|
|||
|
|
- 后端 API 不直接用 OpenHub FastAPI,而是由 MNote 提供兼容 `/api/query/stream`、`/api/sessions/*`、`/api/files/*` 的最小 Rust adapter。
|
|||
|
|
- 目标是快速验证 UI/消息体验是否明显优于 opencode 官方 iframe。
|
|||
|
|
|
|||
|
|
2. **Phase 2:消息库迁移**
|
|||
|
|
- 在 MNote control-plane 增加 OpenHub-like `page_ai_sessions` / `page_ai_messages` / `page_ai_message_parts` / `page_ai_turns`。
|
|||
|
|
- 将 opencode session id、message id、tool calls、diff、reasoning、attachments、rootUri、pageAbsolutePath 统一持久化。
|
|||
|
|
- 替代当前临时 Page AI binding;支持跨浏览器、跨会话恢复。
|
|||
|
|
|
|||
|
|
3. **Phase 3:UI 组件裁剪融合**
|
|||
|
|
- 从 OpenHub 前端抽出 Chat shell、消息列表、工具调用、历史抽屉、Diff/File/GitTimeMachine 组件。
|
|||
|
|
- 去掉 Login/Admin/Knowledge/SmartEntity/Team 等非 Page AI 首屏模块。
|
|||
|
|
- 适配 MNote host chrome、当前页 context、changed file chip、MNote open/refresh。
|
|||
|
|
|
|||
|
|
4. **Phase 4:高级能力选择性引入**
|
|||
|
|
- FileManager 映射 MNote resource/file tree。
|
|||
|
|
- GitTimeMachine 映射 MNote changed files / snapshot / restore 设计。
|
|||
|
|
- Memory/Skill/Tool permission 映射 MNote 用户权限和未来 MNote MCP。
|
|||
|
|
- Smart Entity/Team 作为 Page AI 后续 agent team,不进入当前 MVP。
|
|||
|
|
|
|||
|
|
技术判断:
|
|||
|
|
|
|||
|
|
- 如果目标是“尽快有成熟 Page AI UI”,OpenHub 前端比 opencode 官方 iframe 更适合深度定制,因为它已经是普通 React/AntD 应用,消息、工具、历史、文件、diff 都在前端组件内。
|
|||
|
|
- 如果目标是“最少维护债”,opencode 官方 iframe 仍最省事,但 MNote 与页面/文件/权限/历史的融合会受 iframe 限制。
|
|||
|
|
- 当前更适合改为 **OpenHub UI + MNote Rust adapter + opencode runtime**:UI 和消息体验复用 OpenHub,用户/文件/权限/工作区真相仍归 MNote,agent runtime 仍归 opencode。
|
|||
|
|
|
|||
|
|
新的建议:
|
|||
|
|
|
|||
|
|
- 把 `7-65` 当前 iframe 方案降级为 runtime spike 与 fallback。
|
|||
|
|
- 新增或接续设计 `7-67-openhub-page-ai-fusion-v1`,目标是用 OpenHub Chat 子系统替代当前 Page AI UI。
|
|||
|
|
- 第一阶段只做 Chat/Session/Message/Diff/File open 五件事,不引入 OpenHub 登录/admin/知识库/team。
|
|||
|
|
### 11.9 OpenHub 知识库实现与 WeKnora 对照
|
|||
|
|
|
|||
|
|
用户最新判断:Page AI 要做深度融合;MNote 当前已放弃 LightRAG,知识库方向原计划是 WeKnora。因此需要单独核验 OpenHub 自带知识库是否能替代 WeKnora。
|
|||
|
|
|
|||
|
|
源码核验结论:**OpenHub 自带知识库是轻量 SQLite 文本知识库,不是完整 RAG/知识库底座;适合复用 UI、API 形状和 prompt 注入链路,不建议替代 WeKnora。**
|
|||
|
|
|
|||
|
|
OpenHub 知识库真实实现:
|
|||
|
|
|
|||
|
|
- 数据表只有 `knowledge_bases` 与 `knowledge_sources`:字段包括 `scope=enterprise/user`、`owner_id`、`title`、`source_type`、`content`、`tags`、统计字段;没有 chunk 表、embedding 表、向量库、图谱或 citation 表。
|
|||
|
|
- 上传解析支持 `.md/.txt/.pdf/.docx/.xlsx/.csv`:PDF 走 PyMuPDF 文本抽取,DOCX 走 python-docx 段落抽取,表格转文本行;没有 OCR、版面恢复、图片解析或复杂文档结构保真。
|
|||
|
|
- `chunker.py` 存在 Markdown/文本/表格切块逻辑,但当前知识库主链没有把 chunk 持久化到 DB,检索与注入仍围绕整份 `knowledge_sources.content`。
|
|||
|
|
- 检索分两层:DB 层用 `LIKE` 关键字筛出候选;服务层再对候选全文做 CJK/英文 token 的 BM25 + TF-IDF 重排;没有 embedding、semantic search、rerank model、hybrid vector search。
|
|||
|
|
- 注入方式是 prompt stuffing:小型个人知识库全量或近似全量注入,大型个人知识库取 2 条结果,企业知识库最多取 1 条结果,每条截取相关片段,总上下文默认限制约 1200 字符。
|
|||
|
|
- opencode 集成点是在发送用户问题前构造 `<context>...</context>`,并提示模型如果上下文不足就调用 `knowledge_knowledge_search` 工具继续查。
|
|||
|
|
- 前端 `KnowledgeManager.jsx` 和 admin 企业知识库 UI 可直接参考:列表、搜索、上传、添加、编辑、删除、统计、企业只读提示这些产品能力与 MNote 需要高度重合。
|
|||
|
|
|
|||
|
|
与 WeKnora 的关系:
|
|||
|
|
|
|||
|
|
- WeKnora 应继续作为 MNote 长期知识库底座候选:负责文档解析、索引、检索、召回、引用、权限过滤与跨文档问答。
|
|||
|
|
- OpenHub 知识库不应替代 WeKnora;它更像“用户短记忆/轻量知识片段/企业公告文本”的 fallback。
|
|||
|
|
- 最优融合方式是 **OpenHub Knowledge UI + MNote Rust 知识库 adapter + WeKnora provider**:前端交互复用 OpenHub,后端接口形状兼容 OpenHub,但真正的 ingestion/search/citation 由 MNote 调 WeKnora。
|
|||
|
|
- OpenHub 的 `knowledge_sources` schema 可以作为 MNote control-plane 的 source registry 参考,但需要增加 `workspace_id/root_uri/resource_id/source_uri/provider_doc_id/index_status/permission_scope/citation_locator` 等 MNote 字段。
|
|||
|
|
- OpenHub 的 prompt 注入链路可以短期复用为 Page AI context block,但 WeKnora 命中结果必须带 citation/open-reference 映射,不能只塞纯文本。
|
|||
|
|
|
|||
|
|
对 7-67 深度融合设计的影响:
|
|||
|
|
|
|||
|
|
1. Page AI 主 UI 继续选 OpenHub Chat 子系统,而不是官方 opencode iframe。
|
|||
|
|
2. Knowledge 模块第一阶段只迁移 UI 与 API contract,不迁移其 SQLite 文本检索为长期底座。
|
|||
|
|
3. MNote Rust adapter 提供 OpenHub-compatible `/api/knowledge/*`,内部走 WeKnora 或本地 fallback。
|
|||
|
|
4. 保留 OpenHub 轻量知识库作为“未配置 WeKnora 时的 local fallback / 用户手工短知识”,但不能称为默认知识库主线。
|
|||
|
|
5. 新设计稿应明确:`OpenHub UI` 负责交互,`MNote control-plane` 负责用户与权限,`WeKnora` 负责知识库索引与检索,`opencode` 负责 agent 执行。
|
|||
|
|
|