feat: add pi lab ai management integration
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# 7-69 Page AI Pi-first Lab Spike Checklist v1
|
||||
|
||||
状态:done(最小可验证 spike)
|
||||
Owner:07-ai / mnote-web / control-plane
|
||||
日期:2026-07-04
|
||||
|
||||
## 1. 结论
|
||||
|
||||
7-69 的最小可验证 spike 已完成:OpenHub 继续作为默认 Page AI 主线,Pi Lab 仅在 `MNOTE_PAGE_AI_PI_LAB=1` 下启用,运行时默认禁用 Pi 原始 `bash/read/write/edit`,文件读写只走 MNote-owned tool facade 与 allowed roots。
|
||||
|
||||
Pi 可以进入下一阶段受控验证,但不能进入生产默认路径。下一阶段的门槛是 Turso/libSQL 正式 receipt 表、登录态 watcher -> tiptap 端到端验证、selection snapshot 注入和 UI 产品化。
|
||||
|
||||
## 2. Phase Checklist
|
||||
|
||||
### Phase A:源码与包可运行性
|
||||
|
||||
- [x] 重新拉取并核验当前 Pi 源码:`tmp/pi-research-20260703/pi-mono`,commit `23d14626 fix(ai): rotate stale Codex websocket sessions`。
|
||||
- [x] 核验当前 npm 包:`@earendil-works/pi-coding-agent@0.80.3`,并通过 `MNOTE_PAGE_AI_PI_BIN` wrapper 跑通真实 RPC。
|
||||
- [x] 跑通 `pi --mode rpc` 最小托管路径。
|
||||
- [x] 记录 RPC event schema 到 MNote SSE `pi_rpc_event` 映射。
|
||||
- [x] 验证 `abort`:MNote 可向 Pi RPC 发送 abort 并清理子进程。
|
||||
- [ ] `steer` / `follow_up` 行为未纳入本轮 spike,留到下一阶段真实 agent turn 验收。
|
||||
|
||||
### Phase B:MNote scoped Pi runtime
|
||||
|
||||
- [x] 新增内部 runtime manager,不替换 OpenHub 默认入口。
|
||||
- [x] `sessionDir` 派生到 MNote 管控目录:`<workspace>/.mnote/ai/pi-sessions/<actor>/<session>`。
|
||||
- [x] 禁止全局 `~/.pi/agent/sessions` 作为默认 MNote session 落点。
|
||||
- [x] 只开放 MNote-owned tools,默认不开放 Pi builtin `bash/read/write/edit`。
|
||||
- [x] 路径越界读写被拒绝,并写入 provider-neutral receipt。
|
||||
|
||||
### Phase C:LightRAG tool
|
||||
|
||||
- [x] 实现 `mnote.knowledge_rag.query` facade。
|
||||
- [x] 通过现有 `knowledge_rag::query_rag` 调用 LightRAG provider facade,不引入第二套 RAG。
|
||||
- [x] tool envelope 保留 citation/open-reference 所需字段。
|
||||
- [x] UI 支持 citation 展示。
|
||||
- [x] 实现 `mnote.reference.open` facade,支持 citation 回跳入口。
|
||||
|
||||
### Phase D:文件 patch 闭环
|
||||
|
||||
- [x] 当前页面可通过 `rootUri + pagePath` 解析到真实 `.md`。
|
||||
- [x] `mnote.local_file.patch` 支持 content 或 text operations patch 当前文件。
|
||||
- [x] patch 写入前后记录 file version 与 diff summary。
|
||||
- [x] patch 响应声明 watcher/document-session refresh,并显式 `polling=false`。
|
||||
- [ ] 登录态浏览器中验证 watcher 实际刷新 tiptap 当前页仍未完成,是下一阶段阻塞项。
|
||||
- [ ] changed file chip 打开对应资源未纳入本轮 spike,是下一阶段 UI 验收项。
|
||||
|
||||
### Phase E:UI 对照
|
||||
|
||||
- [x] 新增 MNote-native Pi Lab internal UI,支持 start/send/events/abort,并集成到当前 MNote Page AI 抽屉。
|
||||
- [x] Pi RPC stream 的 `thinking_*` 事件不进入可见 assistant bubble;截图验证 Omniroute/freefirst 最终可见回复为 `OK`。
|
||||
- [x] UI 支持 SSE stream、tool card、citation、diff summary、receipt 诊断。
|
||||
- [x] 重新拉取并评估 `@earendil-works/pi-web-ui@0.75.3`;确认其 UI 成熟,但默认 browser Agent/IndexedDB/API key/tools/artifacts 边界不适合直接承接 MNote 托管 Pi RPC/SSE。
|
||||
- [x] 采用参考官方 `ChatPanel/AgentInterface` 形态的 MNote-native adapter,并保留后续 remote-session adapter 接官方组件的迁移条件。
|
||||
- [ ] 与 OpenHub 当前面板并排截图对照未纳入本轮 spike。
|
||||
- [ ] 移动端 / 窄 sidebar 布局未纳入本轮 spike。
|
||||
- [ ] retry / session resume 仍是下一阶段 UI 产品化项。
|
||||
|
||||
## 3. 验收结果
|
||||
|
||||
- [x] `pi --mode rpc` 能由 MNote 托管启动,并返回 `runtimePid`。
|
||||
- [x] 当前页读取、LightRAG facade、文件 patch、receipt adapter、SSE UI 已形成最小闭环。
|
||||
- [x] 所有文件读写受 allowed roots 控制。
|
||||
- [x] 所有 tool call 均写 provider-neutral JSONL receipt。
|
||||
- [x] Pi 原始 `bash/read/write/edit` 默认不可用。
|
||||
- [x] citation/open-reference facade 已接入 MNote knowledge_rag 路径。
|
||||
- [x] Pi Lab 与 OpenHub 并存,OpenHub 仍为默认 Page AI。
|
||||
- [ ] Turso/libSQL 正式 receipt 表未完成。
|
||||
- [ ] watcher -> tiptap 真实端到端刷新未完成。
|
||||
- [ ] UI 尚未达到可替代 OpenHub 的生产级体验。
|
||||
|
||||
## 4. 验证命令
|
||||
|
||||
- `node scripts/task-pi-lab-static-smoke.js`:通过,78 checks。
|
||||
- `node scripts/task-pi-lab-api-endpoint-smoke.js`:通过,10/10。
|
||||
- `node scripts/task-pi-lab-mock-api-smoke.js`:通过。
|
||||
- `node scripts/task-pi-lab-browser-smoke.js`:通过。
|
||||
- `node scripts/task-pi-lab-rpc-api-smoke.js`:新增固化 RPC smoke;需以 `MNOTE_PAGE_AI_PI_LAB_RUNTIME=rpc` 和 `MNOTE_PAGE_AI_PI_BIN` 启动服务后运行。
|
||||
- `cd rust && cargo check -p mnote-web`:通过。
|
||||
|
||||
## 5. 下一阶段条件
|
||||
|
||||
进入下一阶段前必须补齐:
|
||||
|
||||
- Turso/libSQL control-plane 表:`ai_provider_sessions`、`ai_tool_events`、`ai_file_patches`。
|
||||
- 登录态浏览器 smoke:Pi patch 当前 `.md` 后,watcher 驱动 tiptap 当前页刷新,不允许高频轮询。
|
||||
- sidebar host 注入真实 selection snapshot。
|
||||
- Pi RPC send 的真实 agent turn 自动化验证,固定兼容版本范围或安装方式。
|
||||
- UI 与 OpenHub baseline 的截图/交互对照。
|
||||
@@ -0,0 +1,94 @@
|
||||
# 7-69 Page AI Pi-first Lab Spike 验收记录 v1
|
||||
|
||||
状态:done(最小可验证 spike)
|
||||
Owner:07-ai / mnote-web / control-plane
|
||||
日期:2026-07-03
|
||||
|
||||
## 1. 本轮结论
|
||||
|
||||
7-69 已完成 MNote 侧最小可验证 Pi-first Page AI Lab spike:OpenHub 仍是默认 Page AI 主线,Pi Lab 仅在 `MNOTE_PAGE_AI_PI_LAB=1` 下作为 dev-only/internal 入口启用。
|
||||
|
||||
当前结论不是“替换 OpenHub”,而是:Pi 值得进入下一阶段受控验证;扩大前必须补真实 Pi CLI/RPC、Turso/libSQL receipt 表、auth 下浏览器 smoke 和 watcher 端到端证据。
|
||||
|
||||
## 2. 已实现内容
|
||||
|
||||
- 新增 Pi Lab 后端路由:`/api/page-ai/pi/status`、`bootstrap`、`start`、`send`、`abort`、`events`、`tool-call`、`/page-ai/pi`。
|
||||
- 新增 MNote 托管 runtime:`pi --mode rpc` subprocess 或 `MNOTE_PAGE_AI_PI_LAB_RUNTIME=mock`,sessionDir 派生到 MNote 管控目录。
|
||||
- 默认禁用 Pi builtin tools:启动参数包含 `--no-builtin-tools`,状态响应显式标注 `bash/read/write/edit` 不开放。
|
||||
- 实现 MNote-owned tool facade:`mnote.current_page.read`、`mnote.selection.read`、`mnote.allowed_roots.describe`、`mnote.local_file.read`、`mnote.local_file.patch`、`mnote.knowledge_rag.query`、`mnote.reference.open`、`mnote.tool_receipt.write`。
|
||||
- 文件读写受 allowed roots 限制,越界读写返回 deny reason 且写 receipt。
|
||||
- LightRAG 保持唯一默认知识 provider;Pi 只通过 `knowledge_rag` facade 查询和 open-reference。
|
||||
- receipt 先落 `provider_neutral_jsonl_adapter_v1`,字段含 session binding、tool event、deny reason、diff summary、file version、allowed roots snapshot,并写明迁移到 Turso/libSQL `ai_provider_sessions` / `ai_tool_events` / `ai_file_patches` 的条件。
|
||||
- 文件 patch 响应声明 `mnote local-folder watcher / document-session external refresh`,并显式 `polling=false`,不新增高频轮询。
|
||||
- 新增 Pi Lab runtime UI:状态机、SSE/EventSource、stream、tool card、citation、diff、abort、receipt 诊断。
|
||||
- Pi Lab 已从简陋独立 debug 页改为当前 MNote Page AI 抽屉内的 dev-only provider 面板,并保留悬浮 `π` 入口;切回 OpenHub 时复用原抽屉与 iframe,OpenHub 仍是默认入口。
|
||||
- Pi RPC stream 中 `thinking_*` 事件默认不进入可见 assistant bubble;可见回复只渲染 `text_*` / assistant final text,避免 Omniroute/freefirst 的 reasoning_content 泄漏到页面。
|
||||
- gateway 仅在 `enable_page_ai_pi_lab` 开启时注入 Pi Lab runtime,默认 body 标记为 hidden,不改变 OpenHub 默认入口。
|
||||
- 新增 smoke:静态结构、禁用态 API endpoint、mock-mode API 验证脚本、浏览器 smoke 脚本。
|
||||
- 新增 spike checklist:`design/07-ai/done/7-69-page-ai-pi-first-lab-checklist-v1.md`,逐项标注 Phase A-E 已完成项与下一阶段 gap。
|
||||
|
||||
## 3. 未完成内容
|
||||
|
||||
- 系统 PATH 仍未安装全局 `pi`,但已通过 `npx -y @earendil-works/pi-coding-agent@0.80.3` 包装器完成真实 `pi --mode rpc` 端到端 smoke;后续需决定是否固定安装方式或配置 `MNOTE_PAGE_AI_PI_BIN`。
|
||||
- receipt 尚未写入 Turso/libSQL 正式表,仍为 provider-neutral JSONL adapter。
|
||||
- `mnote.tool_receipt.write` 当前仍是最小 tool envelope 路径,未作为独立持久化入口深化。
|
||||
- watcher 刷新已按 MNote 文件写入链路声明和返回 metadata,但还需登录态浏览器端 smoke 证明 tiptap 当前页被 watcher 刷新。
|
||||
- 已基于最新 `@earendil-works/pi-web-ui@0.75.3` 源码重新评估,而不是使用 recycle 旧源码。其 `ChatPanel` / `AgentInterface` / `MessageEditor` / message-tool renderer 是成熟 UI 参考,但直接接入会同时引入浏览器端 `pi-agent-core`、IndexedDB session/provider key、API key prompt、proxy、attachments、artifacts 和 `Agent.state.tools` 事实源,与 MNote 托管 Pi RPC/SSE、AiAccessScope 和 MNote-owned tools 边界冲突。
|
||||
- 本轮采用 MNote-native adapter:视觉与交互参考官方 `ChatPanel/AgentInterface` 的消息流、composer、tool timeline、model/runtime controls 和 artifacts-style rail;session、API key、模型、工具权限、receipt 仍由 MNote 后端托管。若下一阶段要直接复用官方组件,迁移条件是先提供不依赖浏览器 API key/IndexedDB/Agent tools 的 remote-session adapter。
|
||||
- API endpoint smoke 当前覆盖禁用态 3000;完整 mock-mode smoke 需要用 `MNOTE_PAGE_AI_PI_LAB=1 MNOTE_PAGE_AI_PI_LAB_RUNTIME=mock` 启动独立服务后运行。
|
||||
|
||||
## 4. Pi 是否进入下一阶段
|
||||
|
||||
建议进入下一阶段,但仍保持 internal/lab:
|
||||
|
||||
- 通过:MNote 侧最小 runtime manager、tool facade、allowed roots、LightRAG facade、file patch、receipt adapter、SSE UI 已形成闭环。
|
||||
- 未通过生产门槛:Turso receipt 表、正式登录态 browser smoke、watcher tiptap 刷新截图/断言仍未完整。
|
||||
|
||||
下一阶段应聚焦真实 runtime 和验收,不扩大默认入口。
|
||||
|
||||
## 5. OpenHub 状态
|
||||
|
||||
OpenHub 继续保持默认 Page AI 主线。Pi Lab 未替换、未破坏 OpenHub / LightRAG / Turso 路径;相关路由和 UI 均受 `MNOTE_PAGE_AI_PI_LAB=1` / `enable_page_ai_pi_lab` 控制。
|
||||
|
||||
## 6. 验证记录
|
||||
|
||||
- `node scripts/task-pi-lab-static-smoke.js`:通过,78 项。
|
||||
- `node scripts/task-pi-lab-api-endpoint-smoke.js`:通过,10/10;当前 3000 服务未启用 Pi Lab,验证禁用态和 asset。
|
||||
- `node scripts/task-pi-lab-mock-api-smoke.js`:通过;覆盖 mock runtime start、SSE events、allowed roots、当前页读取、越界拒绝、当前 `.md` patch、watcher refresh metadata、LightRAG facade、citation/open-reference facade、send、abort。
|
||||
- `node scripts/task-pi-lab-browser-smoke.js`:通过;覆盖当前 MNote Page AI 抽屉、dev-only 悬浮 `π` 入口、Pi/OpenHub 切换、`omniroute/freefirst`、MNote tool rail、composer、status API 和截图;不再把独立 `/page-ai/pi` 当作主要 UI 验收面。
|
||||
- Pi + Omniroute/freefirst 浏览器实测截图:`tmp/page-ai-pi-omniroute-freefirst-final-ok-20260704-v3.png`;证据 JSON:`tmp/page-ai-pi-omniroute-freefirst-final-ok-20260704-v3.json`。最终 assistant 可见文本为 `OK`,`assistantStreaming=false`,`inDrawer=true`,模型为 `omniroute/freefirst`,runtime 为 `rpc`。
|
||||
- `node scripts/task-pi-lab-mock-api-smoke.js`:通过;使用 mock mode 独立 3332 服务与 `MNOTE_PI_LAB_SMOKE_ROOT=/tmp/mnote-pi-lab-smoke`,覆盖 start/send/abort/events、allowed roots、越界拒绝、当前页 read、文件 patch、receipt。
|
||||
- `node scripts/task-pi-lab-api-endpoint-smoke.js`:通过,10/10;支持启用态 + Bearer smoke auth,验证 status schema、disabled builtins、runtime asset 和端点存在。
|
||||
- `codegraph sync . && codegraph status .`:通过;索引 up to date。
|
||||
- 真实 Pi RPC smoke:通过;使用 `/tmp/mnote-pi-cli-wrapper.sh` 调用 `npx -y @earendil-works/pi-coding-agent@0.80.3`,MNote 以 `MNOTE_PAGE_AI_PI_LAB_RUNTIME=rpc` / `MNOTE_PAGE_AI_PI_BIN=/tmp/mnote-pi-cli-wrapper.sh` 启动,验证 `start` 返回 `runtimePid`、当前页读取、越界拒绝、当前 `.md` patch、`send` accepted、`abort` 成功。
|
||||
- `node scripts/task-pi-lab-rpc-api-smoke.js`:新增 RPC API smoke 固化脚本(2026-07-04 7-69 收尾),覆盖 runtimeMode=rpc status、runtimePid 真实子进程验证、start/send/abort 端点、tool-call MNote facades(allowed roots、越界拒绝、.md patch 含 watcher refresh/version change、LightRAG、citation)、SSE 事件流(runtime_started 含 pid/mode/disabledBuiltinTools)、多会话生命周期、Pi 进程清理。需要真实 Pi CLI + API key 完整测试 send 实际 AI 调用。
|
||||
- `cd rust && cargo check -p mnote-web`:通过。
|
||||
- `which pi`:无输出;本轮通过 `MNOTE_PAGE_AI_PI_BIN` 指向 wrapper 完成真实 RPC smoke。
|
||||
|
||||
## RPC 验证命令
|
||||
|
||||
```bash
|
||||
# 启动 mnote-web(真实 Pi RPC 模式)
|
||||
MNOTE_PAGE_AI_PI_LAB=1 \
|
||||
MNOTE_PAGE_AI_PI_LAB_RUNTIME=rpc \
|
||||
MNOTE_PAGE_AI_PI_BIN=/tmp/mnote-pi-cli-wrapper.sh \
|
||||
MNOTE_PI_LAB_ALLOWED_ROOTS=/tmp/mnote-pi-rpc-smoke \
|
||||
npm run desktop:hot
|
||||
|
||||
# 另一个终端运行 smoke
|
||||
MNOTE_PI_LAB_BASE=http://127.0.0.1:3000 \
|
||||
MNOTE_PI_LAB_AUTH="Bearer pi-lab-smoke" \
|
||||
MNOTE_PAGE_AI_PI_BIN=/tmp/mnote-pi-cli-wrapper.sh \
|
||||
MNOTE_PI_LAB_ALLOWED_ROOTS=/tmp/mnote-pi-rpc-smoke \
|
||||
node scripts/task-pi-lab-rpc-api-smoke.js
|
||||
```
|
||||
|
||||
mock 验证命令:
|
||||
|
||||
```bash
|
||||
MNOTE_PAGE_AI_PI_LAB=1 \
|
||||
MNOTE_PAGE_AI_PI_LAB_RUNTIME=mock \
|
||||
MNOTE_PI_LAB_ALLOWED_ROOTS=/tmp/mnote-pi-lab-smoke \
|
||||
MNOTE_PI_LAB_BASE=http://127.0.0.1:3000 \
|
||||
node scripts/task-pi-lab-mock-api-smoke.js
|
||||
```
|
||||
@@ -0,0 +1,51 @@
|
||||
# 7-70 Page AI Pi Lab 原生 OpenHub-like UI Checklist v1
|
||||
|
||||
状态:done(UI spike + P2 Pi tool bridge 回归)
|
||||
Owner:07-ai / mnote-web / page-ai-runtime
|
||||
日期:2026-07-04
|
||||
|
||||
## 1. 验收项
|
||||
|
||||
- [x] OpenHub 继续保持默认 Page AI 主线。
|
||||
- [x] Pi Lab 默认显示独立 `π` 悬浮按钮,不以 `MNOTE_PAGE_AI_PI_LAB=1` 作为显示前置条件。
|
||||
- [x] `MNOTE_PAGE_AI_PI_LAB` 保留为强制关闭开关,默认值为开启。
|
||||
- [x] Pi Lab 点击后打开独立 MNote-native drawer。
|
||||
- [x] Pi Lab 不挂载到 `[data-testid="wolai-page-ai-drawer"]`。
|
||||
- [x] Pi Lab 不 iframe 第二个完整应用。
|
||||
- [x] Pi Lab 不复用 OpenHub provider tab、按钮或 iframe 页面。
|
||||
- [x] topbar 显示 Pi Lab、session/runtime status、model、close/minimize。
|
||||
- [x] context strip 显示当前页、选区、allowed roots、LightRAG、changed files。
|
||||
- [x] message timeline 显示 user / assistant / system、streaming、aborted。
|
||||
- [x] provider thinking 不进入 visible final answer;reasoning 仍默认隐藏。
|
||||
- [x] tool/receipt rail 显示 tool status、deny reason、receipt、file version、diff summary、citation count。
|
||||
- [x] composer 支持多行输入、当前页/选区/LightRAG 快捷按钮、send、abort。
|
||||
- [x] diagnostics 默认折叠,不挤占首屏。
|
||||
- [x] MNote-owned tools 保留,不开放 Pi 原始 `bash/read/write/edit`。
|
||||
- [x] allowed roots 越界读写在 UI 中显示 denied 和 deny reason,并写 receipt。
|
||||
- [x] LightRAG 仍是唯一默认 knowledge provider;Pi 只通过 MNote facade 查询。
|
||||
- [x] patch 响应保持 watcher refresh / `polling=false` contract。
|
||||
- [x] Pi 默认模型继续为 Omniroute `freefirst`。
|
||||
- [x] static smoke(119 checks)、api endpoint smoke、mock/API smoke、RPC API smoke、browser smoke、cargo check、CodeGraph sync/status 已运行。
|
||||
- [x] 真实 Pi RPC + Omniroute/freefirst UI 截图回归已补:`tmp/page-ai-pi-lab-rpc-browser-real-7-71.png`。
|
||||
- [x] 真实 `/documents/local-md:*` 文档页默认注入独立 Pi Lab `π` 入口:`tmp/page-ai-pi-lab-rpc-browser-p1-7-71c.png`。
|
||||
- [x] Pi Lab start session 绑定当前 root/page/title。
|
||||
- [x] “当前页”快捷按钮调用 `mnote.current_page.read` 并读取当前 Markdown。
|
||||
- [x] “选区”快捷按钮读取 tiptap live selection snapshot 并注入 composer。
|
||||
- [x] `.md` patch 后通过 local-folder event bus / document refresh 更新当前 `.ProseMirror`,未新增高频轮询。
|
||||
- [x] 修复 P1 审查发现的任意 Cookie 认证绕过、跨用户 session 查询、selection tool host snapshot 标识、`tool_receipt.write` 空操作和 pagePath smoke 误报。
|
||||
- [x] Pi RPC subprocess 通过 per-session extension 注册 MNote-owned custom tools。
|
||||
- [x] 真实 Pi 主动调用 `mnote_current_page_read`,并经 `/api/page-ai/pi/tool-call-bridge` 回到 MNote `mnote.current_page.read` 的 API smoke 已通过。
|
||||
- [x] bridge token 使用 OS 随机源生成,不序列化到 session JSON,不写入 extension 文件。
|
||||
- [x] bridge endpoint 拒绝非 running session,aborted/error session 不能继续通过 bridge 调 tool。
|
||||
- [x] session TTL、最大 session 数、start/send/tool rate limit 和过期 session 目录清理已补。
|
||||
- [x] P2 真实浏览器截图已补:`tmp/page-ai-pi-lab-rpc-browser-p2-visible-reply-7-70.png`,并断言 assistant bubble 本身包含真实 Pi 回复。
|
||||
- [x] Pi Lab UI 已按 OpenHub-like 方向收敛:设置、上下文、tools、receipts 默认折叠,主对话区优先,模型选择入口保留。
|
||||
- [x] OpenHub-like 折叠 UI 截图已补:`tmp/page-ai-pi-lab-openhub-like-ui-collapsed-v2-7-70.png`。
|
||||
- [x] Pi Lab UI 已按 OpenHub 平台式首屏二次收敛:大标题、水平工具栏、白色对话卡片、居中空状态示例、底部大输入框与 Build/Plan/model/budget 控制条;截图:`tmp/page-ai-pi-lab-openhub-platform-empty-v4-7-70.png`。
|
||||
|
||||
## 2. 下一阶段
|
||||
|
||||
- [ ] Turso/libSQL 正式 receipt 表。
|
||||
- [ ] in-process `AgentSession` / Node sidecar SDK 方案评估,用于替代当前 RPC subprocess + extension bridge spike。
|
||||
- [ ] production Pi binary 显式配置和版本锁定。
|
||||
- [ ] session resume / retry / history drawer 产品化。
|
||||
@@ -0,0 +1,93 @@
|
||||
# 7-70 Page AI Pi Lab 原生 OpenHub-like UI 验收记录 v1
|
||||
|
||||
状态:done(UI spike + P2 Pi tool bridge 回归)
|
||||
Owner:07-ai / mnote-web / page-ai-runtime
|
||||
日期:2026-07-04
|
||||
|
||||
## 1. 结论
|
||||
|
||||
7-70 已完成 Pi Lab 从 7-69 的“OpenHub 抽屉内 provider 面板”到“默认显示的独立 `π` 悬浮入口 + MNote-native 抽屉”的切换。OpenHub 继续作为默认 Page AI 主线,Pi Lab 不复用 OpenHub 按钮、iframe 页面、provider tab 或抽屉容器。
|
||||
|
||||
Pi Lab 可以进入下一阶段受控验证,但仍不替换 OpenHub。2026-07-04 已补跑真实 Pi RPC + Omniroute/freefirst 的浏览器回归,证明真实 Pi text stream 能进入 MNote-native timeline 且 provider thinking 不进入 visible final answer。随后补齐了文档页 `/documents/local-md:*` 默认注入独立 Pi Lab、当前页读取、tiptap live selection snapshot、allowed roots deny、`.md` patch 后 watcher/refresh 刷新当前 tiptap 页的浏览器回归。
|
||||
|
||||
P2 已补齐真实 Pi 主动调用 MNote-owned tools 的最小链路:由于 Pi RPC 协议没有 host 回写 `tool_result` 的 stdin command,当前 spike 采用 per-session Pi extension bridge 注册 `mnote_*` custom tools。Pi 子进程仍使用 `--no-builtin-tools` 禁用原始 `bash/read/write/edit`,只允许 `mnote_current_page_read` 等 MNote 工具名;extension execute 通过内部 `/api/page-ai/pi/tool-call-bridge` 回到 MNote `execute_tool`,由 MNote 执行 allowed roots / LightRAG facade / receipt 写入。真实 Omniroute/freefirst API smoke 已观察到 Pi 发出 `tool_execution_start: mnote_current_page_read`,MNote bridge 执行 `mnote.current_page.read`,并返回最终 marker。
|
||||
|
||||
## 2. 已实现内容
|
||||
|
||||
- `sidebar-page-ai-pi-lab-runtime.js` 改为独立 drawer:`[data-page-ai-pi-lab-launcher]` 默认显示,点击打开 `[data-page-ai-pi-lab="drawer"]`,不再调用 `attachPanelToDrawer` / `setOpenHubVisible`,不再出现 `data-page-ai-pi-lab-openhub-tab`。
|
||||
- UI 补齐 topbar、session/runtime/model/status、context strip、message timeline、composer、right rail receipts/tools、默认折叠 diagnostics;2026-07-04 二次收敛为 OpenHub 平台式首屏:大标题、水平工具栏、白色对话卡片、居中空状态示例、底部大输入框与 Build/Plan/model/budget 控制条。
|
||||
- `MNOTE_PAGE_AI_PI_LAB` 改为默认开启,保留为 `0/false` 强制关闭开关;后端 `status` 返回 `uiMode=independent_mnote_native_drawer`。
|
||||
- 保留 MNote-owned tool set 和 Pi builtin 禁用策略:`bash/read/write/edit` 仍默认不可用。
|
||||
- tool event UI 补充 deny reason、diff summary、file version、citation count、changed files chip。
|
||||
- mock runtime send 事件补充 LightRAG mock citation 与 diff event,用于浏览器截图验证 stream/citation/diff 的 UI 形态。
|
||||
- OpenHub 回归通过浏览器 smoke 验证:OpenHub drawer API 仍存在,OpenHub iframe host 仍独立打开,Pi drawer 不在 OpenHub drawer 内。
|
||||
- 文档页 shell 现在在 `enable_page_ai_pi_lab` 开启时注入 Pi Lab runtime,因此真实 `/documents/local-md:*` 页面默认也显示独立 `π` 入口。
|
||||
- Pi Lab start session 会绑定当前 `rootUri / workspaceId / pagePath / pageTitle`。
|
||||
- “当前页”快捷按钮实际调用 `mnote.current_page.read`,并把当前 Markdown 内容注入 composer / system timeline。
|
||||
- “选区”快捷按钮消费 `window.getSelection()` 与 `mnote:leptos-tiptap-spike:selection` 快照,已在真实 tiptap 页面验证选中文本注入 composer。
|
||||
- `mnote.local_file.patch` tool event 后会走 local-folder event bus + document pane refresh,不新增轮询;真实浏览器截图已验证当前 `.md` patch 后 `.ProseMirror` 显示新内容。
|
||||
- 每个 Pi session 生成独立 tool bridge extension,注册 `mnote_current_page_read / mnote_selection_read / mnote_allowed_roots_describe / mnote_local_file_read / mnote_local_file_patch / mnote_knowledge_rag_query / mnote_reference_open / mnote_tool_receipt_write`。
|
||||
- bridge token 使用 `/dev/urandom` 生成,不随 session JSON 序列化,不写入 extension 文件;token 通过子进程 env 注入。
|
||||
- `/api/page-ai/pi/tool-call-bridge` 只接受匹配 bridge token 且仍处于 `RuntimeRunning/TurnRunning` 的 session。
|
||||
- session TTL、最大 session 数、start/send/tool 简单 rate limit 已补;过期 session 目录和空 rate bucket 会清理。
|
||||
|
||||
## 3. 第三方 UI 复用决策
|
||||
|
||||
- `@earendil-works/pi-web-ui` 继续作为 ChatPanel / AgentInterface / ThinkingBlock / tool renderer / artifacts rail 的交互参考,不直接引入 MNote 主链。
|
||||
- `@assistant-ui/react-pi` 继续作为 HTTP/SSE thread contract 参考,不让其接管 MNote provider key、IndexedDB session、Pi browser Agent 或 tool 权限。
|
||||
- `ai-elements` 继续作为 message / reasoning / tool / source / prompt input 形态参考,不引入 React/Tailwind/shadcn 依赖。
|
||||
|
||||
## 4. 验证记录
|
||||
|
||||
- `node scripts/task-pi-lab-static-smoke.js`:通过,119 checks。
|
||||
- `MNOTE_PI_LAB_BASE=http://127.0.0.1:33170 MNOTE_PI_LAB_AUTH='Bearer pi-lab-smoke' node scripts/task-pi-lab-api-endpoint-smoke.js`:通过,10/10。
|
||||
- `MNOTE_PI_LAB_BASE=http://127.0.0.1:33170 MNOTE_PI_LAB_AUTH='Bearer pi-lab-smoke' MNOTE_PI_LAB_SMOKE_ROOT=/tmp/mnote-pi-lab-smoke node scripts/task-pi-lab-mock-api-smoke.js`:通过。
|
||||
- `MNOTE_PI_LAB_BASE=http://127.0.0.1:33170 MNOTE_PI_LAB_AUTH_HEADER='Bearer pi-lab-smoke' MNOTE_PI_LAB_BROWSER_ROOT=/tmp/mnote-pi-lab-browser-smoke MNOTE_PI_LAB_SCREENSHOT=/mnt/Data1T/mnote/tmp/page-ai-pi-lab-native-drawer-7-70.png node scripts/task-pi-lab-browser-smoke.js`:通过。
|
||||
- `MNOTE_PI_LAB_BASE=http://127.0.0.1:33172 MNOTE_PI_LAB_AUTH='Bearer pi-lab-smoke' MNOTE_PI_LAB_BROWSER_ROOT=/tmp/mnote-pi-real-rpc-smoke-1783130268 MNOTE_PI_LAB_SCREENSHOT=/mnt/Data1T/mnote/tmp/page-ai-pi-lab-rpc-browser-real-7-71.png node scripts/task-pi-lab-rpc-browser-smoke.js`:通过;使用 `MNOTE_PAGE_AI_PI_LAB_RUNTIME=rpc`、`MNOTE_PAGE_AI_PI_BIN=/tmp/mnote-pi-cli-wrapper.sh` 和 Omniroute `freefirst`。
|
||||
- `MNOTE_PI_LAB_BASE=http://127.0.0.1:33172 MNOTE_PI_LAB_AUTH='Bearer pi-lab-smoke' MNOTE_PI_LAB_BROWSER_ROOT=/tmp/mnote-pi-p1-rpc-smoke-1783133999 MNOTE_PI_LAB_SCREENSHOT=/mnt/Data1T/mnote/tmp/page-ai-pi-lab-rpc-browser-p1-7-71c.png node scripts/task-pi-lab-rpc-browser-smoke.js`:通过;覆盖真实文档页 Pi Lab 默认入口、当前页读取、tiptap selection、allowed roots deny、`.md` patch、watcher/refresh 到 `.ProseMirror`、真实 Pi stream、abort、非 iframe;同时收紧 pagePath 绑定断言。
|
||||
- `MNOTE_PI_LAB_BASE=http://127.0.0.1:33172 MNOTE_PI_LAB_AUTH='Bearer pi-lab-smoke' MNOTE_PI_LAB_SMOKE_ROOT=/tmp/mnote-pi-real-rpc-smoke-1783130268 MNOTE_PAGE_AI_PI_BIN=/tmp/mnote-pi-cli-wrapper.sh node scripts/task-pi-lab-rpc-api-smoke.js`:通过;覆盖真实 Pi RPC subprocess、send、SSE、abort、allowed roots deny、`.md` patch、receipt。
|
||||
- `MNOTE_PI_LAB_BASE=http://127.0.0.1:33172 MNOTE_PI_LAB_AUTH='Bearer pi-lab-smoke' OPENAI_API_KEY=<codex auth> node scripts/task-pi-lab-rpc-api-smoke.js`:通过;覆盖真实 Pi custom tool 主动调用 `mnote_current_page_read`、MNote bridge 执行 `mnote.current_page.read`、marker 返回、send、SSE、abort、allowed roots deny、`.md` patch、receipt。
|
||||
- `MNOTE_PI_LAB_BASE=http://127.0.0.1:33172 MNOTE_PI_LAB_AUTH='Bearer pi-lab-smoke' MNOTE_PI_LAB_SCREENSHOT=/mnt/Data1T/mnote/tmp/page-ai-pi-lab-rpc-browser-p2-visible-reply-7-70.png node scripts/task-pi-lab-rpc-browser-smoke.js`:通过;覆盖真实浏览器 Pi Lab 默认入口、原生 drawer、当前页/选区、allowed roots deny、`.md` patch watcher refresh、真实 Pi stream、assistant bubble 可见回复、abort、非 iframe。该 smoke 已修正为断言 assistant bubble 本身包含 marker,而不是误用 drawer 全文里的用户 prompt。
|
||||
- `MNOTE_PI_LAB_BASE=http://127.0.0.1:33172 MNOTE_PI_LAB_AUTH='Bearer pi-lab-smoke' MNOTE_PI_LAB_SCREENSHOT=/mnt/Data1T/mnote/tmp/page-ai-pi-lab-openhub-like-ui-collapsed-v2-7-70.png node scripts/task-pi-lab-rpc-browser-smoke.js`:通过;覆盖 OpenHub-like 折叠 UI,设置/上下文/右侧 tools/receipts 默认收起,主对话区成为视觉重点,同时保留模型选择入口和真实 Pi 可见回复。
|
||||
- `curl -H 'Cookie: foo=bar' http://127.0.0.1:33172/api/page-ai/pi/status`:返回 401 `page_ai_pi_lab_invalid_session_cookie`,验证任意 Cookie 不能绕过 Pi Lab API 认证。
|
||||
- `cd rust && cargo check -p mnote-web`:通过。
|
||||
- `codegraph sync . && codegraph status .`:通过,index up to date;CodeGraph 提示索引由旧 engine 构建,可后续择机 full re-index。
|
||||
|
||||
## 5. 截图证据
|
||||
|
||||
- Pi Lab 原生抽屉:`tmp/page-ai-pi-lab-native-drawer-7-70.png`
|
||||
- 显示独立 `π` 悬浮按钮。
|
||||
- 显示独立 Pi Lab drawer,不是 iframe。
|
||||
- 显示 `omniroute/freefirst`、runtime `mock`、aborted、context strip、tool rail、receipt rail。
|
||||
- 显示 prompt、mock stream、abort、LightRAG mock citation、patch/diff、changed files、allowed roots deny receipt。
|
||||
- OpenHub 默认入口回归:`tmp/page-ai-pi-lab-openhub-default-7-70.png`
|
||||
- 显示 OpenHub drawer 仍可独立打开。
|
||||
- 同屏保留独立 `π` 入口,说明 Pi Lab 未复用 OpenHub 抽屉容器。
|
||||
- 真实 Pi RPC 浏览器回归:`tmp/page-ai-pi-lab-rpc-browser-real-7-71.png`
|
||||
- 显示 runtime `rpc`、模型 `omniroute/freefirst`。
|
||||
- 显示真实 Pi RPC text stream 返回 `REAL_PI_BROWSER_OK_*` 标记。
|
||||
- provider thinking 事件仅进入 diagnostics,不进入 visible final answer。
|
||||
- 同时验证 allowed roots deny、markdown patch receipt、abort UI 状态和非 iframe 独立 drawer。
|
||||
- P1 文档页功能回归:`tmp/page-ai-pi-lab-rpc-browser-p1-7-71c.png`
|
||||
- 显示真实 `/documents/local-md:*` 页面默认存在独立 `π` 入口。
|
||||
- 显示 Pi Lab drawer 内绑定当前页、选区、runtime `rpc`、模型 `omniroute/freefirst`。
|
||||
- 显示当前页已由 patch 从 `Browser RPC Original` 刷新为 `Browser RPC Patched`。
|
||||
- 显示 allowed roots deny receipt、patch diff receipt、changed files chip。
|
||||
- P2 真实 Pi RPC 浏览器回归:`tmp/page-ai-pi-lab-rpc-browser-p2-visible-reply-7-70.png`
|
||||
- 显示真实 MNote 文档页默认独立 `π` 入口与独立 Pi Lab drawer。
|
||||
- 显示 runtime `rpc`、模型 `omniroute/freefirst`、Pi builtin `bash/read/write/edit` disabled。
|
||||
- 显示当前页读取、选区、allowed roots deny receipt、patch diff receipt、changed files chip、assistant 可见回复。
|
||||
- OpenHub-like 折叠 UI 回归:`tmp/page-ai-pi-lab-openhub-like-ui-collapsed-v2-7-70.png`
|
||||
- 显示设置、上下文、MNote tools、Receipts 默认折叠。
|
||||
- 显示模型选择入口 `omniroute/freefirst`,主 timeline 和 composer 保持首屏重点。
|
||||
- OpenHub 平台式空状态回归:`tmp/page-ai-pi-lab-openhub-platform-empty-v4-7-70.png`
|
||||
- 显示独立 Pi Lab 抽屉使用 OpenHub 平台式标题、顶部工具栏、白色对话卡片、居中问号空状态和五个示例。
|
||||
- 设置、上下文、诊断默认不占首屏;通过齿轮展开。
|
||||
- 底部保留大输入框、发送按钮、Build/Plan、`omniroute/freefirst` 模型选择、预算和当前页/选区快捷入口。
|
||||
|
||||
## 6. 未完成内容与风险
|
||||
|
||||
- receipt 仍落 `provider_neutral_jsonl_adapter_v1`,尚未迁移到 Turso/libSQL 正式 `ai_provider_sessions` / `ai_tool_events` / `ai_file_patches` 表。
|
||||
- 真实 Pi RPC + Omniroute/freefirst 已补浏览器回归;真实 Pi 主动调用 MNote tools 的最小 bridge 链路已在 API smoke 中通过。长期更正统方向仍是 in-process `AgentSession` / Node sidecar SDK,避免依赖 RPC subprocess + extension bridge。
|
||||
- watcher refresh 已通过真实文档页 `.md` patch 后 `.ProseMirror` 更新验证;仍需在后续产品化中补更细的 file version 冲突与多 pane 场景。
|
||||
- P1/P2 审查后已修复任意 Cookie 认证绕过、跨用户 session 查询、selection tool 缺少 host snapshot 标识、`tool_receipt.write` 空操作、browser smoke pagePath 误报、bridge token 可预测、aborted session bridge 调用、rate bucket 增长和 token 落盘风险。
|
||||
@@ -0,0 +1,499 @@
|
||||
# 7-70 Page AI Pi Lab 原生 OpenHub-like UI 设计 v1
|
||||
|
||||
状态:done
|
||||
Owner:07-ai / mnote-web / page-ai-runtime
|
||||
日期:2026-07-04
|
||||
|
||||
## 1. 结论
|
||||
|
||||
Pi Lab 下一阶段不做第二个 iframe,也不把 `@earendil-works/pi-web-ui` 或 LibreChat / Open WebUI 这类完整应用直接嵌入 MNote。正确方向是:
|
||||
|
||||
```text
|
||||
MNote Page AI 独立 Pi Lab 浮动入口 + 原生抽屉 UI
|
||||
-> 体验参考当前 OpenHub AI 面板,但入口和容器不依赖 OpenHub
|
||||
-> 运行协议参考 @assistant-ui/react-pi 的 PiClient / HTTP SSE thread contract
|
||||
-> 消息、composer、tool、artifact 形态参考 Pi 官方 web-ui 与 ai-elements
|
||||
-> 权限、知识库、receipt、watcher refresh 继续由 MNote 托管
|
||||
```
|
||||
|
||||
OpenHub 继续作为默认 Page AI 主线。Pi Lab 使用独立浮动按钮与独立抽屉容器,默认在 MNote 页面中显示;目标是把 7-69 的 debug spike UI 升级成可验证的 MNote-native Page AI 体验,而不是替代或复用 OpenHub 的入口。若后续确认不需要 Pi Lab,直接退役这一独立入口和 runtime 即可,不需要先用 feature flag 隔离。
|
||||
|
||||
## 2. 原则
|
||||
|
||||
- **独立入口默认显示**:Pi Lab 新增自己的悬浮按钮和抽屉容器,默认显示,不复用当前 OpenHub 的按钮、iframe 页面或 provider tab 容器;以后退役 OpenHub 或 Pi Lab 任一侧,都不影响另一侧。
|
||||
- **原生承载**:Pi Lab UI 渲染在 MNote 自有 DOM 中,不新增独立产品页作为主验收面,不 iframe 第二个完整 AI 应用。
|
||||
- **优先参考和复用**:能复用当前 OpenHub 已证明的交互、Pi 官方 UI 的事件语义、assistant-ui 的 runtime contract、ai-elements 的组件形态,就不要自造一套孤立协议。
|
||||
- **MNote 拥有真相**:session binding、allowed roots、LightRAG facade、tool receipt、file patch、citation/open-reference、watcher refresh 仍归 MNote;第三方 UI 不能接管这些事实源。
|
||||
- **Debug 后置**:Page AI 首屏必须是对话、输入、上下文和变更结果;runtime health、scope JSON、receipt 原文只进折叠诊断区或开发态右栏。
|
||||
- **不破坏 OpenHub**:OpenHub 仍是默认入口和默认 Page AI 主线;Pi Lab 作为独立入口与 OpenHub 并列但互不依赖,不出现普通用户可见的 fallback/迁移暗示。
|
||||
|
||||
## 3. 参考资源取证
|
||||
|
||||
### 3.1 当前 OpenHub UI
|
||||
|
||||
本地 OpenHub 是当前最接近目标体验的产品基线:
|
||||
|
||||
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/pages/SmartQueryPage.jsx`
|
||||
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/components/ChatInput.jsx`
|
||||
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/components/AssistantMessage.jsx`
|
||||
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/components/ToolCall.jsx`
|
||||
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/components/HistoryDrawer.jsx`
|
||||
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/components/DiffViewer.jsx`
|
||||
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/components/KnowledgeManager.jsx`
|
||||
|
||||
可参考能力:
|
||||
|
||||
- 顶部/底部紧凑控制区:agent mode、model select、当前页面/当前文件夹按钮。
|
||||
- 主消息流:user / assistant bubble、streaming、retry / undo、idle state。
|
||||
- assistant message:reasoning 折叠、tool summary、tool cards、citation chips。
|
||||
- session/history:历史抽屉、恢复会话、归档。
|
||||
- changed files / diff:隐藏索引桥接 MNote,用户侧展示 changed files / diff 入口。
|
||||
- knowledge:知识库入口和 citation 回跳模式。
|
||||
|
||||
不直接复用方式:
|
||||
|
||||
- 不把 OpenHub React/AntD 组件直接搬进 `mnote-web` 主运行时。
|
||||
- 不复制 OpenHub session/message 全文存储作为 Pi Lab 真相。
|
||||
- 不复用 OpenHub iframe shell 实现 Pi Lab,因为用户目标是 MNote-native。
|
||||
|
||||
### 3.2 Pi 官方 web-ui
|
||||
|
||||
`@earendil-works/pi-web-ui@0.75.3` 已核验为 MIT 包,描述为 “Reusable web UI components for AI chat interfaces powered by @earendil-works/pi-ai”。包内包含:
|
||||
|
||||
- `ChatPanel`
|
||||
- `AgentInterface`
|
||||
- `MessageList` / `Messages`
|
||||
- `MessageEditor`
|
||||
- `StreamingMessageContainer`
|
||||
- `ThinkingBlock`
|
||||
- tool renderers
|
||||
- artifacts runtime / sandbox
|
||||
- `ModelSelector`
|
||||
- IndexedDB storage stores
|
||||
|
||||
可参考能力:
|
||||
|
||||
- Pi 消息流与工具流的视觉分层。
|
||||
- thinking / tool / artifact 的独立组件边界。
|
||||
- composer 与 model/thinking selector 的组合方式。
|
||||
- artifacts-style 侧栏。
|
||||
|
||||
不直接整包接入原因:
|
||||
|
||||
- 默认假设 browser 侧持有 `Agent`、provider keys、IndexedDB session/settings。
|
||||
- 默认可暴露 Pi 自带 tools / attachments / artifacts 事实源。
|
||||
- 与 MNote 后端托管 Pi RPC/SSE、AiAccessScope、MNote-owned tools 的边界冲突。
|
||||
|
||||
迁移条件:
|
||||
|
||||
- 先提供 remote-session adapter,使 `ChatPanel` / `AgentInterface` 不直接管理 provider key、IndexedDB 和 `Agent.state.tools`。
|
||||
- 所有 tool call、file read/write、knowledge query、receipt 仍必须走 MNote facade。
|
||||
|
||||
### 3.3 assistant-ui / react-pi
|
||||
|
||||
`@assistant-ui/react-pi@0.0.5` 已核验为 MIT,说明其 browser entry 是 RPC-isomorphic `PiClient`,通过 HTTP/SSE 驱动 Pi-backed threads。其 contract 包含:
|
||||
|
||||
```text
|
||||
GET /threads
|
||||
POST /threads
|
||||
GET /threads/:id
|
||||
PATCH /threads/:id
|
||||
POST /threads/:id/messages
|
||||
POST /threads/:id/cancel
|
||||
GET /models
|
||||
POST /threads/:id/model
|
||||
POST /threads/:id/thinking
|
||||
GET /threads/:id/events
|
||||
```
|
||||
|
||||
可参考能力:
|
||||
|
||||
- thread / message / composer / queue / cancel 的协议边界。
|
||||
- snapshot-first SSE reconnect 语义。
|
||||
- model / thinking controls。
|
||||
- host UI approval requests。
|
||||
- tool-associated approval / interrupt 的 UI 映射。
|
||||
|
||||
当前不直接引 React UI 的原因:
|
||||
|
||||
- `mnote-web` 当前主路径是 Rust SSR + browser JS,不是 React app。
|
||||
- 直接引入 React island、Tailwind/shadcn 体系会扩大构建和运行时边界。
|
||||
- 当前优先目标是把 MNote-owned Pi adapter 做完整,而不是重开前端框架主线。
|
||||
|
||||
设计决策:**先对齐 contract,不先引 UI 框架**。后续如果 MNote 需要 React island,再以该 contract 为迁移桥。
|
||||
|
||||
### 3.4 ai-elements
|
||||
|
||||
`ai-elements@1.9.0` 已核验为 Apache-2.0,定位是基于 shadcn/ui 的 AI-native component registry。
|
||||
|
||||
可参考能力:
|
||||
|
||||
- message / conversation / prompt input / reasoning / tool / source / response card 的组件形态。
|
||||
- 更现代的 AI chat 视觉密度和状态表达。
|
||||
|
||||
当前不直接接入原因:
|
||||
|
||||
- 依赖 React、Tailwind、shadcn registry 和 CSS variables。
|
||||
- 对当前 MNote Rust SSR + browser JS 主路径引入成本偏高。
|
||||
|
||||
设计决策:作为视觉和组件拆分参考,不作为 7-70 第一阶段依赖。
|
||||
|
||||
### 3.5 完整应用类参考
|
||||
|
||||
LibreChat、Open WebUI、AnythingLLM、Continue、Cline、Roo Code 只作为交互模式参考:
|
||||
|
||||
- LibreChat / Open WebUI / AnythingLLM:参考历史会话、多模型、RAG、文件区、设置入口。
|
||||
- Continue / Cline / Roo Code:参考 agent tool timeline、审批、diff、changed files、任务状态。
|
||||
|
||||
不作为直接依赖或嵌入目标。
|
||||
|
||||
## 4. UI 目标结构
|
||||
|
||||
### 4.1 独立入口与抽屉整体
|
||||
|
||||
```text
|
||||
MNote page
|
||||
Pi Lab floating button(default visible)
|
||||
-> Pi Lab native drawer(independent from OpenHub iframe/page)
|
||||
topbar
|
||||
Pi Lab title
|
||||
session title
|
||||
runtime status
|
||||
close / minimize
|
||||
context strip
|
||||
current page chip
|
||||
selection chip
|
||||
allowed roots chip
|
||||
LightRAG chip
|
||||
model / thinking selector
|
||||
body
|
||||
message timeline
|
||||
optional right rail
|
||||
composer
|
||||
prompt input
|
||||
context buttons
|
||||
send / abort / queue state
|
||||
folded diagnostics
|
||||
```
|
||||
|
||||
桌面端允许右侧 rail;移动端不显示右 rail,改为底部 sheet 或折叠 section。
|
||||
|
||||
入口规则:
|
||||
|
||||
- Pi Lab 使用独立悬浮按钮,例如右下角 `π`,默认渲染。
|
||||
- Pi Lab 点击后打开独立抽屉,不借用 OpenHub 当前按钮、OpenHub iframe 页或 OpenHub provider tab。
|
||||
- Pi Lab 抽屉可以视觉参考 OpenHub,但 DOM、状态、session、事件订阅、关闭/最小化都独立。
|
||||
- OpenHub 的现有按钮和页面保持不变;Pi Lab 不在 OpenHub 面板内新增 tab 作为主入口。
|
||||
- 若未来退役 OpenHub,Pi Lab 浮动入口仍可保留;若退役 Pi Lab,OpenHub 入口不受影响。
|
||||
- `MNOTE_PAGE_AI_PI_LAB` 可保留为临时开发/强制关闭开关,但不是产品入口显示的前置条件。
|
||||
|
||||
### 4.2 Topbar
|
||||
|
||||
目标是接近 OpenHub 的 AI 面板,而不是 debug 工具页。
|
||||
|
||||
必须包含:
|
||||
|
||||
- Pi Lab 标题与实验标记;不放 OpenHub/Pi provider tabs 作为主导航。
|
||||
- session label:`Pi Lab · 当前页面标题`,恢复会话后显示短 session id。
|
||||
- runtime status:idle / starting / streaming / error。
|
||||
- model label:默认 `omniroute/freefirst`,可后续扩展 selector。
|
||||
- close/minimize。
|
||||
|
||||
不要在 topbar 放大段 `scope`、`disabled builtins`、raw env 等诊断文案。
|
||||
|
||||
### 4.3 Context Strip
|
||||
|
||||
替代当前偏 debug 的工具列表,参考 OpenHub `ChatInput` 中当前页面/文件夹按钮:
|
||||
|
||||
- 当前页:真实 `.md` 路径或页面标题,点击在 MNote 中定位。
|
||||
- 选区:无选区时 disabled,有选区时显示字符数。
|
||||
- allowed roots:显示 root 名称和数量,点击展开只读详情。
|
||||
- LightRAG:显示 provider 状态;query citation 走 `mnote.reference.open`。
|
||||
- 文件变更:当前 session 有 patch 后显示 changed files chip。
|
||||
|
||||
Context strip 是用户可理解的任务上下文,不展示 JSON。
|
||||
|
||||
### 4.4 Message Timeline
|
||||
|
||||
消息模型要吸收 OpenHub `AssistantMessage` 与 Pi/assistant-ui 的 part 语义:
|
||||
|
||||
```text
|
||||
MNotePiUiMessage
|
||||
id
|
||||
role = user | assistant | system
|
||||
status = queued | streaming | done | error | aborted
|
||||
createdAt
|
||||
model
|
||||
parts[]
|
||||
|
||||
MNotePiUiPart
|
||||
text
|
||||
reasoning
|
||||
toolCall
|
||||
toolResult
|
||||
citation
|
||||
diff
|
||||
fileChange
|
||||
approval
|
||||
error
|
||||
```
|
||||
|
||||
展示规则:
|
||||
|
||||
- user message 右侧气泡。
|
||||
- assistant message 左侧主体块,正文优先。
|
||||
- reasoning 默认折叠,严禁把 provider `reasoning_content` 混入 final answer。
|
||||
- tool timeline 默认折叠成 summary,运行中自动展开当前 tool。
|
||||
- tool 输入/输出长 JSON 默认收起,显示摘要和 deny reason。
|
||||
- citation 显示为来源 chip,点击走 MNote open-reference。
|
||||
- diff / fileChange 显示为 changed file chips + diff summary,点击走 MNote document pane / diff view。
|
||||
- error 明确显示 provider/runtime/tool deny,不伪装成功。
|
||||
|
||||
### 4.5 Tool Timeline
|
||||
|
||||
参考 OpenHub `ToolCall.jsx`、Pi official tool renderers、Cline/Roo 的工具审批流。
|
||||
|
||||
第一阶段必须覆盖:
|
||||
|
||||
- `mnote.current_page.read`
|
||||
- `mnote.selection.read`
|
||||
- `mnote.allowed_roots.describe`
|
||||
- `mnote.local_file.read`
|
||||
- `mnote.local_file.patch`
|
||||
- `mnote.knowledge_rag.query`
|
||||
- `mnote.reference.open`
|
||||
- `mnote.tool_receipt.write`
|
||||
|
||||
每个 tool card 至少显示:
|
||||
|
||||
- tool name
|
||||
- state:pending / running / allowed / denied / error / done
|
||||
- compact params summary
|
||||
- deny reason
|
||||
- receipt id
|
||||
- file version before / after
|
||||
- diff summary
|
||||
- citation count
|
||||
|
||||
默认禁用 Pi 原始 `bash/read/write/edit` 的状态可以放在折叠详情里,不占据首屏。
|
||||
|
||||
### 4.6 Composer
|
||||
|
||||
参考 OpenHub `ChatInput`、Pi `MessageEditor`、assistant-ui composer queue 语义。
|
||||
|
||||
第一阶段:
|
||||
|
||||
- 多行输入。
|
||||
- icon-only 当前页、选区、文件夹/allowed roots、LightRAG 按钮,带 tooltip 和 aria-label。
|
||||
- send 按钮。
|
||||
- streaming 时显示 abort;若后端支持 queue,再允许 follow-up queue。
|
||||
- 发送前自动附带 MNote context envelope,不把上下文 URL 或 JSON 写入 textarea。
|
||||
- 禁用态要有明确原因:未启动 runtime、missing model、missing auth、scope denied。
|
||||
|
||||
后续阶段:
|
||||
|
||||
- model selector。
|
||||
- thinking level selector。
|
||||
- thread queue / steer。
|
||||
- prompt template / skill picker。
|
||||
|
||||
### 4.7 Right Rail / Drawer
|
||||
|
||||
桌面端右侧 rail 承接“有用但不该挤占主对话”的信息:
|
||||
|
||||
- session/history:当前只显示当前 session 与最近 session,完整历史后续做抽屉。
|
||||
- changed files:变更文件列表、patch count、打开按钮。
|
||||
- citations:本轮 citation 列表。
|
||||
- receipts:最近 tool receipts,默认摘要。
|
||||
- runtime:Pi PID / provider session id / runtime mode,只在 dev mode 显示。
|
||||
|
||||
移动端右 rail 不常驻,改为按钮展开底部 sheet。
|
||||
|
||||
### 4.8 Diagnostics
|
||||
|
||||
折叠 diagnostics 只面向开发:
|
||||
|
||||
- raw SSE events tail。
|
||||
- allowed roots raw snapshot。
|
||||
- receipt raw JSON。
|
||||
- runtime command / pid / session dir。
|
||||
- disabled builtin tools。
|
||||
|
||||
默认折叠,不参与普通用户验收截图。
|
||||
|
||||
## 5. 后端与协议设计
|
||||
|
||||
### 5.1 保留现有 7-69 endpoint
|
||||
|
||||
当前 7-69 已有:
|
||||
|
||||
- `/api/page-ai/pi/status`
|
||||
- `/api/page-ai/pi/bootstrap`
|
||||
- `/api/page-ai/pi/start`
|
||||
- `/api/page-ai/pi/send`
|
||||
- `/api/page-ai/pi/abort`
|
||||
- `/api/page-ai/pi/events`
|
||||
- `/api/page-ai/pi/tool-call`
|
||||
- `/page-ai/pi`
|
||||
|
||||
7-70 不要求立即破坏这些 endpoint。
|
||||
|
||||
但前端入口要调整为默认显示的独立浮动按钮与独立 drawer host;`/page-ai/pi` 可保留为 debug/internal 直达页,不作为产品主验收入口。
|
||||
|
||||
### 5.2 新增 PiClient-aligned adapter 层
|
||||
|
||||
为了后续能接 `@assistant-ui/react-pi` 或复用其 reducer 语义,新增 provider-neutral adapter contract:
|
||||
|
||||
```text
|
||||
GET /api/page-ai/pi/threads
|
||||
POST /api/page-ai/pi/threads
|
||||
GET /api/page-ai/pi/threads/:id
|
||||
POST /api/page-ai/pi/threads/:id/messages
|
||||
POST /api/page-ai/pi/threads/:id/cancel
|
||||
GET /api/page-ai/pi/threads/:id/events
|
||||
GET /api/page-ai/pi/models
|
||||
POST /api/page-ai/pi/threads/:id/model
|
||||
POST /api/page-ai/pi/threads/:id/thinking
|
||||
```
|
||||
|
||||
兼容策略:
|
||||
|
||||
- 第一阶段可在前端 adapter 中把旧 endpoint 映射为 thread contract。
|
||||
- 后端可逐步增加新 endpoint;旧 smoke 不被破坏。
|
||||
- SSE 必须 snapshot-first:重连先发当前 thread snapshot,再发 live events。
|
||||
- browser disconnect 不等于 abort;只有 cancel/abort 明确停止 runtime。
|
||||
|
||||
### 5.3 UI event normalization
|
||||
|
||||
Pi RPC / mock / future SDK event 统一归一为:
|
||||
|
||||
```text
|
||||
thread_snapshot
|
||||
message_created
|
||||
message_delta
|
||||
message_completed
|
||||
reasoning_delta
|
||||
tool_call_started
|
||||
tool_call_updated
|
||||
tool_call_completed
|
||||
tool_call_denied
|
||||
citation_added
|
||||
file_patch_applied
|
||||
receipt_written
|
||||
runtime_status_changed
|
||||
thread_error
|
||||
```
|
||||
|
||||
所有 UI 只消费 normalized events,不直接依赖 Pi JSONL 原始字段。
|
||||
|
||||
## 6. 数据与权限边界
|
||||
|
||||
- `AiAccessScope` / allowed roots 是所有 file tool 的唯一授权来源。
|
||||
- Pi Lab UI 只显示 allowed roots 摘要,不允许用户从 UI 临时扩大 root。
|
||||
- `mnote.local_file.read` / `patch` 必须返回 normalized path、root id、deny reason、file version。
|
||||
- LightRAG 继续是唯一默认 knowledge provider;Pi 只能通过 `mnote.knowledge_rag.query` 查询。
|
||||
- citation 点击必须走 `mnote.reference.open` / MNote open-reference,不直接让 Pi 打开文件。
|
||||
- receipt 当前仍可落 provider-neutral adapter,但 UI v2 必须按 Turso/libSQL 迁移目标设计字段。
|
||||
- 文件 patch 后必须通过 MNote watcher / document refresh 链路更新 tiptap;禁止新增轮询刷新。
|
||||
|
||||
## 7. 实施阶段
|
||||
|
||||
### Phase A:Native UI v2 骨架
|
||||
|
||||
修改范围:
|
||||
|
||||
- `rust/crates/mnote-web/browser/sidebar-page-ai-pi-lab-runtime.js`
|
||||
- `scripts/task-pi-lab-static-smoke.js`
|
||||
- `scripts/task-pi-lab-browser-smoke.js`
|
||||
- 必要时补 `rust/crates/mnote-web/src/ssr/styles/components/page-ai.css`
|
||||
|
||||
目标:
|
||||
|
||||
- 当前 Pi Lab 从 debug shell 升级为 OpenHub-like 抽屉。
|
||||
- Pi Lab 使用独立悬浮按钮打开独立抽屉,不复用 OpenHub 按钮、OpenHub iframe 页面或 provider tab。
|
||||
- 首屏只保留对话、context strip、composer。
|
||||
- tool receipts / diagnostics 默认后置。
|
||||
- 截图必须显示:在 MNote 当前页面中通过独立 `π` 浮动按钮打开 Pi Lab 原生抽屉,非 OpenHub iframe、非独立页、非 OpenHub provider tab。
|
||||
|
||||
### Phase B:Event / message model 收口
|
||||
|
||||
修改范围:
|
||||
|
||||
- `sidebar-page-ai-pi-lab-runtime.js`
|
||||
- `rust/crates/mnote-web/src/routes/page_ai_pi.rs`
|
||||
- smoke 脚本
|
||||
|
||||
目标:
|
||||
|
||||
- 新增 normalized event reducer。
|
||||
- reasoning、tool、citation、diff、receipt 不再混杂在一条 debug 文本里。
|
||||
- SSE reconnect snapshot-first。
|
||||
- abort/cancel 明确区分 browser disconnect。
|
||||
|
||||
### Phase C:PiClient-aligned adapter
|
||||
|
||||
目标:
|
||||
|
||||
- 增加或前端模拟 `/threads` contract。
|
||||
- `send` / `cancel` / `events` 对齐 `@assistant-ui/react-pi` 的语义。
|
||||
- 保持旧 endpoint 兼容,直到 smoke 全部迁移。
|
||||
|
||||
### Phase D:OpenHub-like 功能补齐
|
||||
|
||||
目标:
|
||||
|
||||
- session history 抽屉。
|
||||
- changed files rail。
|
||||
- citation list。
|
||||
- diff preview。
|
||||
- model / thinking selector。
|
||||
- tool approval / host UI requests。
|
||||
|
||||
### Phase E:第三方组件复用决策
|
||||
|
||||
进入条件:
|
||||
|
||||
- Phase A-D 浏览器截图和 smoke 通过。
|
||||
- 当前 MNote native UI 已形成稳定 message/event model。
|
||||
|
||||
决策:
|
||||
|
||||
- 若 MNote 仍保持非 React 主路径:继续原生实现,只参考 Pi web-ui / ai-elements。
|
||||
- 若引入 React island:优先评估 `assistant-ui + @assistant-ui/react-pi`,并复用 Phase C contract。
|
||||
- 若官方 Pi web-ui 提供 remote-session adapter:评估局部复用 `AgentInterface` / `Messages` / `MessageEditor`,不得引入 browser provider key 和 IndexedDB 作为 MNote 真相。
|
||||
|
||||
## 8. 验收标准
|
||||
|
||||
- OpenHub 默认入口不变。
|
||||
- MNote 默认显示独立 Pi Lab 浮动按钮;点击后打开独立 Pi Lab 原生抽屉。
|
||||
- Pi Lab 不复用 OpenHub 按钮、OpenHub 页面或 OpenHub iframe 容器。
|
||||
- UI 首屏接近 OpenHub:消息流、上下文、输入框、模型/状态、tool/citation/diff 摘要齐全。
|
||||
- 不出现第二个 iframe AI 应用。
|
||||
- 可发送 prompt、接收 stream、abort。
|
||||
- reasoning 折叠且不泄漏到 final answer。
|
||||
- tool call 显示状态、deny reason、receipt id。
|
||||
- allowed roots 越界读写在 UI 中显示 denied。
|
||||
- LightRAG citation 可点击回跳。
|
||||
- 当前 `.md` patch 后显示 changed file,并通过 watcher refresh 当前 tiptap 页。
|
||||
- diagnostics 默认折叠。
|
||||
- browser smoke 输出截图。
|
||||
|
||||
## 9. 明确非目标
|
||||
|
||||
- 不替换 OpenHub。
|
||||
- 不把 Pi Lab 做成普通用户默认入口。
|
||||
- 不 iframe LibreChat / Open WebUI / AnythingLLM / Pi web-ui demo app。
|
||||
- 不把 Pi Lab 做成 OpenHub 面板内部的 provider tab 或复用 OpenHub 页面容器。
|
||||
- 不把 React / shadcn / Tailwind 作为 7-70 Phase A 必需依赖。
|
||||
- 不开放 Pi 原始 bash、无约束 read/write/edit。
|
||||
- 不新增第二套 RAG。
|
||||
- 不把 OpenHub 或 Pi 的 session JSONL 作为 MNote control-plane 长期真相。
|
||||
|
||||
## 10. 当前后续任务
|
||||
|
||||
- [ ] Phase A:重做 `sidebar-page-ai-pi-lab-runtime.js` 信息架构、独立浮动入口与视觉层级。
|
||||
- [ ] Phase A:更新 browser smoke,截图验证独立 `π` 浮动按钮打开 OpenHub-like Pi Lab 抽屉。
|
||||
- [ ] Phase B:抽出 normalized event reducer。
|
||||
- [ ] Phase C:补 PiClient-aligned thread adapter。
|
||||
- [ ] Phase D:补 changed files / diff / citation rail。
|
||||
- [ ] Phase E:重新评估是否引入 `assistant-ui` 或 Pi official remote-session adapter。
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
# 7-71 统一 AI 管理面板与 Pi Lab 功能接入 — 实施检查清单
|
||||
|
||||
状态:partial — P0/P1/P2 完成;P3/P4/P5 管理员侧 OpenHub-like AI 管理与逐用户配置完成,用户自助偏好与 LightRAG 写管理待后续
|
||||
日期:2026-07-04
|
||||
|
||||
> 本清单与 `design/07-ai/process/7-71-unified-ai-management-control-plane-and-pi-lab-integration-v1.md` 的 §11 进度表保持同步。
|
||||
> process 文档保留架构结论;本文件记录已完成的检查项供快速验证。
|
||||
|
||||
## 已通过验收项
|
||||
|
||||
### P0 — 合同与只读聚合 ✅
|
||||
|
||||
| 检查项 | 通过 |
|
||||
|---|---|
|
||||
| `/api/ai-settings/effective` GET 端点已注册 | ✅ |
|
||||
| `/api/ai-settings/access-scopes` GET 端点已注册 | ✅ |
|
||||
| `/api/ai-admin/access-scopes` GET 端点已注册 | ✅ |
|
||||
| 所有 AI settings/scopes 端点无 POST/PUT/DELETE | ✅ |
|
||||
| `effective_settings` 使用 `load_active_directory_grants` 生成 allowed roots | ✅ |
|
||||
| `load_model_policy_and_quota` 不读取 `allowed_roots_json` | ✅ |
|
||||
| `source_of_truth` 声明为 `"directory_grants"` | ✅ |
|
||||
| 静态 smoke 27/27 通过 | ✅ |
|
||||
|
||||
### P1 — Pi Lab history 入库 ✅
|
||||
|
||||
| 检查项 | 通过 |
|
||||
|---|---|
|
||||
| `persist_upsert_run` 写入 `ai_runtime_runs` | ✅ |
|
||||
| `persist_append_event` 写入 `ai_runtime_events` | ✅ |
|
||||
| `GET /api/page-ai/pi/sessions` 路由注册 | ✅ |
|
||||
| `GET /api/page-ai/pi/sessions/{id}` 路由注册 | ✅ |
|
||||
| `GET /api/page-ai/pi/sessions/{id}/events` 路由注册 | ✅ |
|
||||
| list_sessions 按 pi_lab profile + pi acp_runtime 过滤 | ✅ |
|
||||
|
||||
### P2 — Receipt 与 patch 入库 ✅
|
||||
|
||||
| 检查项 | 通过 |
|
||||
|---|---|
|
||||
| migration v9 新增 `ai_tool_events / ai_file_patches` | ✅ |
|
||||
| SQLite 与 Turso/libSQL store 均实现 append/list | ✅ |
|
||||
| Pi tool receipt 默认写 control-plane | ✅ |
|
||||
| 成功 patch 关联写入 `ai_file_patches` | ✅ |
|
||||
| JSONL 仅在 control-plane 写失败时作为 debug fallback | ✅ |
|
||||
| deny reason、diff summary、file version、citation count 可查询 | ✅ |
|
||||
| receipt 与 patch 按当前用户隔离 | ✅ |
|
||||
|
||||
### P3 — AI 管理中心与管理员模型写管理 ✅
|
||||
|
||||
| 检查项 | 通过 |
|
||||
|---|---|
|
||||
| `/admin/ai` 路由与管理员鉴权 | ✅ |
|
||||
| `/user/ai` 路由与用户鉴权 | ✅ |
|
||||
| 账户菜单有独立 AI 管理入口 → `/admin/ai` 或 `/user/ai` | ✅ |
|
||||
| AI 管理页面 SSR 渲染 OpenHub-like 左侧分页与多 section | ✅ |
|
||||
| Access Scopes 只读展示(无 POST/PUT/DELETE、无写表单) | ✅ |
|
||||
| Sessions & Receipts 显示真实 Pi session、receipt、patch 数量 | ✅ |
|
||||
| Providers & Models 管理写操作 | ✅ |
|
||||
| `/user/ai` 用户可操作设置 | ❌ |
|
||||
|
||||
### 独立入口保留检查
|
||||
|
||||
| 检查项 | 通过 |
|
||||
|---|---|
|
||||
| OpenHub `/page-ai/openhub/ai` | ✅ |
|
||||
| OpenHub admin guard 路由 | ✅ |
|
||||
| OpenHub status API | ✅ |
|
||||
| Pi Lab shell `/page-ai/pi` | ✅ |
|
||||
| Pi Lab event stream `GET /api/page-ai/pi/events` | ✅ |
|
||||
| Pi Lab start/send/abort 路由 | ✅ |
|
||||
|
||||
### P4 — 工具、Skills/MCP 管理 ✅
|
||||
|
||||
| 检查项 | 通过 |
|
||||
|---|---|---|
|
||||
| `GET/PUT /api/ai-admin/settings` 原子策略端点 | ✅ |
|
||||
| 模型 provider、allowed models、角色模型与 failover 写入 | ✅ |
|
||||
| MNote-owned tools allow/ask/deny 写入 | ✅ |
|
||||
| Skill 添加、描述、启停、删除 | ✅ |
|
||||
| MCP transport/command/url/network/secret refs 写入 | ✅ |
|
||||
| MCP 强制 facade-only 与 sandbox | ✅ |
|
||||
| 刷新后配置持久存在 | ✅ |
|
||||
| effective API 投影模型、Skills、MCP | ✅ |
|
||||
|
||||
### P5 — 逐用户 AI 配置 ✅
|
||||
|
||||
| 检查项 | 通过 |
|
||||
|---|---|
|
||||
| OpenHub `UserManagement`、模型/工具/Skill 权限实现已核验 | ✅ |
|
||||
| `GET /api/ai-admin/users` 用户列表 | ✅ |
|
||||
| `GET/PUT /api/ai-admin/users/{user_id}/settings` | ✅ |
|
||||
| 用户可独立选择管理员允许的模型和默认模型 | ✅ |
|
||||
| 用户工具策略只能相对全局降权 | ✅ |
|
||||
| 用户 Skill/MCP 只能在全局启用目录中开关 | ✅ |
|
||||
| 普通用户登录后的 effective API 应用 override | ✅ |
|
||||
| allowed roots 仍只来自 `directory_grants` | ✅ |
|
||||
| 用户抽屉采用 OpenHub-like 分组:模型按 provider、工具按 risk、Skill/MCP 开关、目录只读跳统一授权页 | ✅ |
|
||||
|
||||
## 后续项
|
||||
|
||||
| 项 | 状态 | 说明 |
|
||||
|---|---|---|
|
||||
| `/user/ai` 用户可操作偏好 | 未实现 | 当前只读 effective config,不能提升管理员权限 |
|
||||
| LightRAG source/index/status 写管理 | 未实现 | 继续使用唯一 knowledge provider 与现有 facade |
|
||||
| provider/skill/MCP 专用规范化表 | 未实现 | 当前原子策略存入 `ai_policies.model_policy_json`;出现独立查询、授权或生命周期需求时迁移 |
|
||||
|
||||
## 浏览器证据
|
||||
|
||||
- Pi Lab 原生抽屉:`tmp/7-71-pi-lab-browser-final.png`
|
||||
- AI 管理页:`tmp/7-71-ai-admin-final.png`
|
||||
- 模型写管理:`tmp/7-71-ai-admin-openhub-like-ui-final/models.png`
|
||||
- Skills/MCP 写管理:`tmp/7-71-ai-admin-openhub-like-ui-final/skills-mcp.png`
|
||||
- 逐用户 AI 配置:`tmp/7-71-ai-admin-openhub-like-ui-final/users.png`
|
||||
- 管理页运行时摘要:会话 1、回执 3、文件补丁 1
|
||||
- Pi Lab 截图可见真实 mock 回复、citation、diff、abort,且 OpenHub 默认入口仍独立存在
|
||||
- `mnote-e2e` 通过 control-plane `role=admin` 进入管理员模式;浏览器验收用 dev seed 临时确保测试账号为 admin
|
||||
- OpenHub 的 MCP 实际为用户工作区 `.opencode/mcp` 文件展示,并非 Admin per-user override;MNote 采用更严格的管理员注册 + 用户启停 + facade/sandbox 模型
|
||||
|
||||
## 验证命令
|
||||
|
||||
```bash
|
||||
# 静态 smoke(只读代码审计,无需启动服务器)
|
||||
node scripts/task-ai-management-control-plane-static-smoke.js
|
||||
MNOTE_AI_ADMIN_OUTPUT_DIR=tmp/7-71-ai-admin-openhub-like-ui-final \
|
||||
node scripts/task-ai-management-browser-smoke.js
|
||||
node scripts/task-pi-lab-static-smoke.js
|
||||
|
||||
CARGO_TARGET_DIR=/tmp/mnote-7-71-target cargo check -p mnote-web
|
||||
CARGO_TARGET_DIR=/tmp/mnote-7-71-target cargo test -p control-plane ai_tool_events
|
||||
CARGO_TARGET_DIR=/tmp/mnote-7-71-target cargo test -p control-plane ai_file_patches
|
||||
CARGO_TARGET_DIR=/tmp/mnote-7-71-target cargo test -p control-plane migrations
|
||||
CARGO_TARGET_DIR=/tmp/mnote-7-71-target cargo test -p mnote-web ai_settings
|
||||
CARGO_TARGET_DIR=/tmp/mnote-7-71-target cargo test -p mnote-web page_ai_pi
|
||||
CARGO_TARGET_DIR=/tmp/mnote-7-71-target cargo test -p mnote-web ai_admin
|
||||
|
||||
# 运行时验证(需要 mnote-web 运行于 localhost:3000)
|
||||
# curl -s http://localhost:3000/api/ai-settings/effective | jq '{source: .sourceOfTruth, models: [.models[].id], rootsCount: (.allowedRoots | length)}'
|
||||
# curl -s http://localhost:3000/api/ai-settings/access-scopes | jq '.sourceOfTruth'
|
||||
# curl -s http://localhost:3000/api/ai-admin/access-scopes | jq '.sourceOfTruth'
|
||||
# curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/admin/ai
|
||||
# curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/user/ai
|
||||
```
|
||||
Reference in New Issue
Block a user