Files
mnote/design/07-ai/done/7-69-page-ai-pi-first-lab-spike-record-v1.md

8.4 KiB
Raw Permalink Blame History

7-69 Page AI Pi-first Lab Spike 验收记录 v1

状态:done(最小可验证 spike Owner07-ai / mnote-web / control-plane 日期:2026-07-03

1. 本轮结论

7-69 已完成 MNote 侧最小可验证 Pi-first Page AI Lab spikeOpenHub 仍是默认 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/statusbootstrapstartsendaborteventstool-call/page-ai/pi
  • 新增 MNote 托管 runtimepi --mode rpc subprocess 或 MNOTE_PAGE_AI_PI_LAB_RUNTIME=mocksessionDir 派生到 MNote 管控目录。
  • 默认禁用 Pi builtin tools:启动参数包含 --no-builtin-tools,状态响应显式标注 bash/read/write/edit 不开放。
  • 实现 MNote-owned tool facademnote.current_page.readmnote.selection.readmnote.allowed_roots.describemnote.local_file.readmnote.local_file.patchmnote.knowledge_rag.querymnote.reference.openmnote.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 时复用原抽屉与 iframeOpenHub 仍是默认入口。
  • 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 checklistdesign/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 railsession、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;证据 JSONtmp/page-ai-pi-omniroute-freefirst-final-ok-20260704-v3.json。最终 assistant 可见文本为 OKassistantStreaming=falseinDrawer=true,模型为 omniroute/freefirstruntime 为 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.3MNote 以 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 facadesallowed 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 验证命令

# 启动 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 验证命令:

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