256 lines
13 KiB
Markdown
256 lines
13 KiB
Markdown
# 7-74 Page AI Pi RPC Parity 与产品化补全 Checklist v1
|
||||
|
|
|
|||
|
|
状态:done
|
|||
|
|
Owner:07-ai / mnote-web / browser runtime / control-plane
|
|||
|
|
日期:2026-07-10
|
|||
|
|
|
|||
|
|
## 1. 结论
|
|||
|
|
|
|||
|
|
当前 MNote Pi Lab 的架构边界保持不变:MNote Rust Web 托管 `pi_agent_rust` RPC 子进程,MNote 负责 `AiAccessScope`、allowed roots、bridge tools、receipt、MCP、LightRAG 和 control-plane 审计;不迁移到 `pi-web` 的 Next.js / in-process AgentSession 架构。
|
|||
|
|
|
|||
|
|
`pi-web` 与官方 `pi_agent_rust` 的参考价值主要在产品化和 RPC 命令面:
|
|||
|
|
|
|||
|
|
- 补齐官方 RPC 命令:`get_state`、`get_messages`、`compact`、`fork`、`set_steering_mode`、`set_follow_up_mode`、`set_auto_compaction`。
|
|||
|
|
- 用官方 session tree / JSONL entry 模型支撑历史 replay、entry 级 fork、compaction 摘要展示。
|
|||
|
|
- 完善 composer:draft 持久化、`@` 文件补全、运行中 steer/follow-up 队列状态。
|
|||
|
|
- 完善 artifacts:file patch split diff、citation/open-reference、MCP raw、receipt audit 统一入口。
|
|||
|
|
|
|||
|
|
本稿是 `7-69 Page AI Pi-first Lab` 与 `7-72 Page AI Pi UI 补全方案` 之后的执行稿,目标是把 Pi Lab 从“可用实验面板”推进到“能长期作为 MNote-native Page AI runtime 候选”的最小闭环。
|
|||
|
|
|
|||
|
|
## 2. 对照证据
|
|||
|
|
|
|||
|
|
### 2.1 pi-web
|
|||
|
|
|
|||
|
|
本轮只读拉取:
|
|||
|
|
|
|||
|
|
- 仓库:`https://github.com/agegr/pi-web`
|
|||
|
|
- 本地路径:`/tmp/pi-web-analysis`
|
|||
|
|
- commit:`82f9442`
|
|||
|
|
|
|||
|
|
可参考文件:
|
|||
|
|
|
|||
|
|
- `/tmp/pi-web-analysis/lib/session-reader.ts`:读取 Pi JSONL,构建 UI messages、entryIds、compaction、branch summary。
|
|||
|
|
- `/tmp/pi-web-analysis/components/BranchNavigator.tsx`:会话分支树、active path、压缩线性链。
|
|||
|
|
- `/tmp/pi-web-analysis/components/ChatInput.tsx`:draft、slash commands、`@` 文件补全、运行中 steer/follow-up。
|
|||
|
|
- `/tmp/pi-web-analysis/lib/patch.ts`:unified patch 解析为 split diff rows。
|
|||
|
|
- `/tmp/pi-web-analysis/components/FileViewer.tsx`:文件预览、diff、图片/音频/PDF/DOCX 入口。
|
|||
|
|
- `/tmp/pi-web-analysis/lib/worktree.ts`:Git worktree 分组与切换,暂只作为未来 MNote workspace 参考。
|
|||
|
|
|
|||
|
|
不迁移:
|
|||
|
|
|
|||
|
|
- Next API routes 与 `globalThis` hot reload cache。
|
|||
|
|
- `~/.pi/agent/sessions` 作为 MNote 默认事实源。
|
|||
|
|
- in-process `@earendil-works/pi-coding-agent` 生命周期。
|
|||
|
|
- Pi 原生 `bash/read/write/edit` 默认开放策略。
|
|||
|
|
|
|||
|
|
### 2.2 pi_agent_rust
|
|||
|
|
|
|||
|
|
本轮只读核对:
|
|||
|
|
|
|||
|
|
- 仓库:`https://github.com/Dicklesworthstone/pi_agent_rust`
|
|||
|
|
- 本地路径:`/tmp/pi-agent-rust-official-20260710`
|
|||
|
|
- commit:`43fddc06`
|
|||
|
|
- 时间:2026-07-09
|
|||
|
|
|
|||
|
|
关键证据:
|
|||
|
|
|
|||
|
|
- `/tmp/pi-agent-rust-official-20260710/src/rpc.rs`
|
|||
|
|
- `prompt` 支持 `streamingBehavior=steer/followUp/follow_up`。
|
|||
|
|
- `get_state` 返回 model、thinking、context usage、pending queue、auto compaction/retry。
|
|||
|
|
- `compact` 会生成 compaction entry 并替换 agent context。
|
|||
|
|
- `fork` 能从 `entryId` 生成新 session。
|
|||
|
|
- `set_steering_mode` / `set_follow_up_mode` / `set_auto_compaction` 是官方 RPC 命令;queue mode 只接受 `one-at-a-time` / `all`。
|
|||
|
|
- `/tmp/pi-agent-rust-official-20260710/docs/rpc.md`
|
|||
|
|
- 明确 `extension_ui_request` / `extension_ui_response`、`agent_end`、`tool_execution_*`、`auto_compaction_*` 等事件。
|
|||
|
|
- `/tmp/pi-agent-rust-official-20260710/docs/session.md`
|
|||
|
|
- Session JSONL entry 类型包括 `message`、`model_change`、`thinking_level_change`、`compaction`、`branch_summary`、`custom`。
|
|||
|
|
|
|||
|
|
## 3. 当前 MNote 状态
|
|||
|
|
|
|||
|
|
当前已存在能力:
|
|||
|
|
|
|||
|
|
- `rust/crates/mnote-web/src/routes/page_ai_pi.rs`
|
|||
|
|
- `status/start/send/configure/abort/events/tool-call/tool-call-bridge/ui-response/sessions/session-events`。
|
|||
|
|
- session owner 校验、bridge token、allowed roots、tool receipt、MCP sync bridge、permission mode。
|
|||
|
|
- `send` 已透传 `streamingBehavior`。
|
|||
|
|
- `configure` 已在当前工作区脏改动中接入 `set_model` / `set_thinking_level`。
|
|||
|
|
- `rust/crates/mnote-web/browser/sidebar-page-ai-pi-lab-runtime.js`
|
|||
|
|
- `PiRunViewModel`、tool timeline、history drawer、queue badge、Artifacts/Receipts、extension UI、model/thinking controls。
|
|||
|
|
- 已有 `pendingQueue` reducer 入口,但需要后端 `get_state`/官方 queue state 兜底同步。
|
|||
|
|
- `packages/pi-mnote/extensions/mnote-bridge.ts`
|
|||
|
|
- 当前脏改动已把 `mnote.local_file.read/patch` 尽量转为 Pi Rust native fs + context file 路径。
|
|||
|
|
- `scripts/task-pi-lab-*`
|
|||
|
|
- 已有 static/API/UI/real skill MCP/input controls 等 smoke 基线。
|
|||
|
|
|
|||
|
|
主要缺口:
|
|||
|
|
|
|||
|
|
- 缺少 MNote API 层对官方 `get_state`、`compact`、`fork(entryId)`、queue mode、auto compaction 的稳定封装。
|
|||
|
|
- 历史 replay 主要依赖 MNote runtime events,还没有完整读取 Pi JSONL entry tree。
|
|||
|
|
- Composer 没有本地 draft 持久化和 `@` 文件补全。
|
|||
|
|
- Artifact diff 仍偏摘要,缺少 split diff 预览与 open-file 定位。
|
|||
|
|
|
|||
|
|
## 4. 架构边界
|
|||
|
|
|
|||
|
|
### 4.1 MNote 继续拥有权限
|
|||
|
|
|
|||
|
|
Pi 运行时只能通过 MNote 托管的安全面访问 MNote 数据:
|
|||
|
|
|
|||
|
|
- `mnote.current_page.read`
|
|||
|
|
- `mnote.selection.read`
|
|||
|
|
- `mnote.allowed_roots.describe`
|
|||
|
|
- `mnote.local_file.read`
|
|||
|
|
- `mnote.local_file.patch`
|
|||
|
|
- `mnote.knowledge_rag.*`
|
|||
|
|
- `mnote.reference.open`
|
|||
|
|
- `mnote.tool_receipt.write`
|
|||
|
|
|
|||
|
|
原生 Pi `read/write/edit/bash/hashline_edit` 只有在 MNote 明确启用 permission-system 或 debug/admin 模式时才允许。普通用户路径不得绕过 `directory_grants` 与 `AiAccessScope`。
|
|||
|
|
|
|||
|
|
### 4.2 Pi session 是 runtime log,不是正文真相
|
|||
|
|
|
|||
|
|
Pi JSONL 可以作为:
|
|||
|
|
|
|||
|
|
- history replay source
|
|||
|
|
- fork/branch source
|
|||
|
|
- debugging/export source
|
|||
|
|
- runtime recovery source
|
|||
|
|
|
|||
|
|
但不能成为:
|
|||
|
|
|
|||
|
|
- MNote 页面正文真相
|
|||
|
|
- local-folder source truth
|
|||
|
|
- allowed roots 真相
|
|||
|
|
- tool audit 主存储
|
|||
|
|
|
|||
|
|
MNote control-plane 的 `ai_runtime_runs`、`ai_runtime_events`、`ai_tool_events`、`ai_file_patches` 仍是 MNote 侧可查询审计和历史入口。
|
|||
|
|
|
|||
|
|
### 4.3 不新增轮询
|
|||
|
|
|
|||
|
|
前端主路径不新增 `setInterval` 或周期轮询。状态同步优先:
|
|||
|
|
|
|||
|
|
- Pi RPC event -> MNote SSE
|
|||
|
|
- 显式 command response
|
|||
|
|
- `get_state` 只在打开面板、发送前后、SSE reconnect、abort/compact/configure 后定点调用
|
|||
|
|
- 页面/文件变化走 MNote watcher / realtime
|
|||
|
|
|
|||
|
|
## 5. 分阶段 Checklist
|
|||
|
|
|
|||
|
|
### Phase A:RPC parity 最小闭环
|
|||
|
|
|
|||
|
|
- [x] A1. 新增 `/api/page-ai/pi/state`,封装官方 `get_state`。
|
|||
|
|
- 输入:`sessionId`
|
|||
|
|
- 输出:`running/isStreaming/isCompacting/model/thinkingLevel/contextUsage/pendingMessageCount/queuedMessages/autoCompactionEnabled/autoRetryEnabled`
|
|||
|
|
- 约束:mock runtime 返回稳定假数据;未启动返回明确错误。
|
|||
|
|
- 当前真实 runtime 只发送 `get_state` one-way RPC,并返回 MNote session 推导状态;真实 Pi response correlation 进入 A7。
|
|||
|
|
- [x] A2. 前端在 drawer open、start、send ack、abort、SSE reconnect 后定点刷新 state。
|
|||
|
|
- 不使用周期轮询。
|
|||
|
|
- 将 `queuedMessages` 同步到 `PiRunViewModel.pendingQueue`。
|
|||
|
|
- [x] A3. 新增 `/api/page-ai/pi/compact`,封装官方 `compact`。
|
|||
|
|
- 支持 `customInstructions/reserveTokens/keepRecentTokens`。
|
|||
|
|
- 返回 compaction summary、firstKeptEntryId、tokensBefore、details。
|
|||
|
|
- 持久化 `runtime_compacted` event。
|
|||
|
|
- [x] A4. 前端增加 compact 按钮与 compaction result 卡片。
|
|||
|
|
- streaming 中禁用。
|
|||
|
|
- 失败时显示明确 error,不写入正文。
|
|||
|
|
- [x] A5. 新增 queue mode / auto compaction 配置薄 API。
|
|||
|
|
- `/api/page-ai/pi/queue-config`
|
|||
|
|
- 封装 `set_steering_mode`、`set_follow_up_mode`、`set_auto_compaction`。
|
|||
|
|
- mode 值域按官方合同限制为 `one-at-a-time` / `all`,兼容 `oneAtATime` / `one_at_a_time` 输入。
|
|||
|
|
- 第一版 UI 可仅放在折叠设置区。
|
|||
|
|
- [x] A6. smoke 覆盖 state/compact/queue-config 路由存在、禁用态稳定、runtime asset 无轮询。
|
|||
|
|
- [x] A7. 增加 Pi RPC request-response correlation。
|
|||
|
|
- 为 `get_state`、`compact`、`queue-config` 追踪 RPC `id` 与 stdout response。
|
|||
|
|
- 将真实 `contextUsage/queuedMessages/autoCompactionEnabled/autoRetryEnabled/compaction result` 映射到 MNote schema。
|
|||
|
|
- timeout 时返回 `rpcResponsePending=true` 或明确 degraded reason,不伪装成完整真实状态。
|
|||
|
|
|
|||
|
|
### Phase B:Session tree / history replay
|
|||
|
|
|
|||
|
|
- [x] B1. 记录并返回 `pi_session_file`。
|
|||
|
|
- start 后从 Pi RPC response、session dir 扫描或 runtime event 中确定。
|
|||
|
|
- 写入 `ai_runtime_runs`。
|
|||
|
|
- [x] B2. 新增受控读取 Pi JSONL 的内部 helper。
|
|||
|
|
- 限制只能读取当前 session 自己的 `pi_session_file`。
|
|||
|
|
- 单行大小、总字节数、entry 数量有上限。
|
|||
|
|
- 不读任意路径。
|
|||
|
|
- [x] B3. 新增 `/api/page-ai/pi/sessions/{id}/tree`。
|
|||
|
|
- 输出 entry tree、active leaf、compaction/branch summary、message preview。
|
|||
|
|
- [x] B4. 前端 history replay 优先使用 session tree。
|
|||
|
|
- 保留 control-plane events 作为 fallback。
|
|||
|
|
- 显示 compaction summary 和 branch summary。
|
|||
|
|
- [x] B5. 新增 `/api/page-ai/pi/fork`。
|
|||
|
|
- 输入:`sessionId`、可选 `entryId`。
|
|||
|
|
- 优先调用官方 `fork`。
|
|||
|
|
- 输出新 session/run 绑定。
|
|||
|
|
- [x] B6. history UI 支持 entry 级 “从这里继续”。
|
|||
|
|
|
|||
|
|
### Phase C:Composer 可用性
|
|||
|
|
|
|||
|
|
- [x] C1. 输入草稿持久化。
|
|||
|
|
- key:`pi-lab:${workspaceId}:${rootUri}:${pagePath}:${sessionId || new}`。
|
|||
|
|
- 保存 textarea、context selection、model/thinking 临时选择。
|
|||
|
|
- 发送成功后清理当前 draft。
|
|||
|
|
- [x] C2. `@` 文件补全。
|
|||
|
|
- 数据源:MNote allowed roots / FileTree projection。
|
|||
|
|
- 不扫描未授权目录。
|
|||
|
|
- 插入格式优先 `@relative/path`,发送时进入 `contextRefs`。
|
|||
|
|
- [x] C3. composer 中显示已引用文件 chips。
|
|||
|
|
- 可删除。
|
|||
|
|
- 发送时与 `selectedContext` 一起写入 Pi context file。
|
|||
|
|
- [x] C4. streaming 中 steer/follow-up 的队列状态与 state API 对齐。
|
|||
|
|
- abort 后保留未发送文本与 queue summary。
|
|||
|
|
|
|||
|
|
### Phase D:Artifacts / Diff / Citation
|
|||
|
|
|
|||
|
|
- [x] D1. file patch receipt 生成统一 artifact。
|
|||
|
|
- `rootUri/relativePath/beforeFileVersion/afterFileVersion/diffSummary/toolEventId`
|
|||
|
|
- [x] D2. 后端提供受控 diff 预览。
|
|||
|
|
- 优先从 `ai_file_patches.patch_summary_json` 或 receipt payload 取。
|
|||
|
|
- 不允许直接读未授权路径。
|
|||
|
|
- [x] D3. 前端 split diff viewer。
|
|||
|
|
- 借鉴 `pi-web/lib/patch.ts`,但落成 MNote 原生 JS helper。
|
|||
|
|
- 支持折叠 unchanged lines。
|
|||
|
|
- [x] D4. citation/open-reference artifact 与 LightRAG `open_reference` 对齐。
|
|||
|
|
- 引用打开失败时显示 stale/deleted/permission denied。
|
|||
|
|
|
|||
|
|
### Phase E:验证与归档
|
|||
|
|
|
|||
|
|
- [x] E1. 静态 smoke:`node scripts/task-pi-lab-static-smoke.js`
|
|||
|
|
- [x] E2. API smoke:`node scripts/task-pi-lab-api-endpoint-smoke.js`
|
|||
|
|
- [x] E3. UI smoke:复用或扩展 `scripts/task-pi-lab-ui-completion-smoke.js`
|
|||
|
|
- [x] E4. Rust 单元:`cargo test -p mnote-web page_ai_pi --lib`
|
|||
|
|
- [x] E5. 若触及 control-plane schema/helper,补对应 control-plane 测试。
|
|||
|
|
- 本轮未改 control-plane schema/helper;相关验证由 API / browser smoke 覆盖。
|
|||
|
|
- [x] E6. 浏览器验证:
|
|||
|
|
- desktop viewport:`node scripts/task-pi-lab-browser-smoke.js`
|
|||
|
|
- mobile viewport:沿既有 7-72 Phase 1 mobile smoke 证据保留;本轮没有新增移动专属布局改动。
|
|||
|
|
- real Pi runtime:`node scripts/task-pi-lab-browser-smoke.js`
|
|||
|
|
- disabled/missing runtime:`node scripts/task-pi-lab-api-endpoint-smoke.js` 覆盖 disabled may 401/404 稳定返回。
|
|||
|
|
- 补充:`dev:hot` 已默认启用 `MNOTE_WEB_ALLOW_DEV_FIXTURES=1`;重启 Node 主进程后,`node scripts/task-pi-lab-input-controls-smoke.js` 完整通过,证据:`/tmp/mnote-pi-input-controls-1783715878475/result.json`。
|
|||
|
|
- [x] E7. 完成后运行 `codegraph sync . && codegraph status .`。
|
|||
|
|
- [x] E8. 全部完成后把本稿移动到 `design/07-ai/done/`,并在 `7-72` 中补一行后续完成链接。
|
|||
|
|
|
|||
|
|
## 6. 第一批执行范围
|
|||
|
|
|
|||
|
|
第一批已完成 Phase A-D 的产品化闭环:
|
|||
|
|
|
|||
|
|
1. 后端新增 `state`、`compact`、`queue-config` API,并补齐 RPC request-response correlation。
|
|||
|
|
2. 后端新增 session tree、fork、artifact diff 受控 API。
|
|||
|
|
3. 前端接入 state 定点同步、compact 控件、history tree replay、entry fork、draft、`@` 引用、split diff、artifact/citation 打开。
|
|||
|
|
4. smoke 增加路由、runtime 字符串、UI completion 和真实浏览器断言。
|
|||
|
|
|
|||
|
|
暂不做:
|
|||
|
|
|
|||
|
|
- worktree 管理。
|
|||
|
|
- review session / streaming apply 的 Phase C 体验。
|
|||
|
|
|
|||
|
|
本轮已把官方 RPC state/queue/compaction、session tree/fork、composer 引用和 artifact diff 变成 MNote 可观察合同。
|
|||
|
|
|
|||
|
|
## 7. 风险
|
|||
|
|
|
|||
|
|
- 当前工作区已有 Pi Lab 相关未提交改动,后续实现必须基于现状增量修改,不得回滚。
|
|||
|
|
- 官方 `pi_agent_rust` RPC event/response 仍可能变化;MNote API 应只暴露稳定的 MNote schema。
|
|||
|
|
- 真实 runtime 的 `state` / `compact` 已有 request-response correlation;若官方 schema 变化,MNote 仍应返回 `rpcResponsePending=true` / degraded reason,而不是伪装完整真实状态。
|
|||
|
|
- `compact` 会改变 Pi session context,但不应改变 MNote 页面正文。
|
|||
|
|
- JSONL 读取必须严格限定 session 所属路径,否则会变成任意文件读取面。
|
|||
|
|
- 前端不得为了补状态引入周期轮询。
|