12 KiB
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.patchtool event 后会走 local-folder event bus + document pane refresh,不新增轮询;真实浏览器截图已验证当前.mdpatch 后.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和 Omniroutefreefirst。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、.mdpatch、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、.mdpatch、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、.mdpatch、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、.mdpatch 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:返回 401page_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、runtimemock、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。
- 显示 runtime
- 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 builtinbash/read/write/editdisabled。 - 显示当前页读取、选区、allowed roots deny receipt、patch diff receipt、changed files chip、assistant 可见回复。
- 显示真实 MNote 文档页默认独立
- 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 已通过真实文档页
.mdpatch 后.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 落盘风险。