2026-07-04 21:47:42 +08:00
|
|
|
|
# 7-71 MNote 统一 AI 管理面板与 Pi Lab 功能接入设计 v1
|
|
|
|
|
|
|
|
|
|
|
|
状态:process
|
|
|
|
|
|
Owner:07-ai / mnote-web / control-plane / Page AI
|
|
|
|
|
|
日期:2026-07-04
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 结论
|
|
|
|
|
|
|
2026-07-21 05:13:05 +08:00
|
|
|
|
应该做 MNote 原生统一 AI 管理面板,但顺序不是先堆 UI,而是先把 control-plane 合同、持久化和 effective config API 做成唯一真相,再让 **Pi Rust Page AI / LightRAG** 消费同一套配置。
|
2026-07-04 21:47:42 +08:00
|
|
|
|
|
|
|
|
|
|
文件夹授权必须只有一套:当前 `/admin/access-policy` 与 `/user/access-policy` 管理的 `directory_grants` 同时就是 MNote 工作区访问授权和 AI `allowed roots` 的事实源。AI 管理面板可以把它纳入同一个信息架构,但不能再维护第二套 AI-only allowed roots。
|
|
|
|
|
|
|
2026-07-21 05:13:05 +08:00
|
|
|
|
OpenHub 的 admin 面板(历史)证明了正确产品结构:provider/model、skills、tools、MCP、目录权限、知识库、历史、用量、健康状态必须先有管理面,聊天 UI 只展示用户可用的有效配置。MNote 不能把 OpenHub admin 作为 MNote AI 的长期真相。**2026-07-18:OpenHub 已不再是默认 Page AI 主线;Pi Rust 为默认入口。** MNote AI 管理中心应落在 Turso/libSQL control-plane。上位收口见 checklist 21。
|
2026-07-04 21:47:42 +08:00
|
|
|
|
|
|
|
|
|
|
## 2. 调研依据
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 OpenHub
|
|
|
|
|
|
|
|
|
|
|
|
源码:
|
|
|
|
|
|
|
|
|
|
|
|
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/pages/AdminPage.jsx`
|
|
|
|
|
|
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/components/UserSettingsDrawer.jsx`
|
|
|
|
|
|
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/components/HistoryDrawer.jsx`
|
|
|
|
|
|
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-frontend/src/services/api.js`
|
|
|
|
|
|
- `/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-backend/app/api/admin.py`
|
|
|
|
|
|
|
|
|
|
|
|
可复用的产品模型:
|
|
|
|
|
|
|
|
|
|
|
|
- 管理后台按区段管理:用户、模型配置、工具权限、技能、目录权限、知识库、用量、系统健康。
|
|
|
|
|
|
- 用户设置抽屉只显示管理员已允许的有效配置:模型、技能、MCP、目录、工具、用量。
|
|
|
|
|
|
- 权限是三层:admin global policy -> user override -> effective policy。
|
|
|
|
|
|
- 历史记录是左侧抽屉,支持新建、刷新、归档、分页/滚动。
|
|
|
|
|
|
|
|
|
|
|
|
不应直接搬的部分:
|
|
|
|
|
|
|
|
|
|
|
|
- opencode 服务管理、飞书渠道、WeKnora 配置导出。
|
|
|
|
|
|
- React/AntD 组件主链。
|
|
|
|
|
|
- OpenHub SQLite 表作为 MNote 真相层。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 Pi / Pi Web UI
|
|
|
|
|
|
|
|
|
|
|
|
源码:
|
|
|
|
|
|
|
|
|
|
|
|
- `/mnt/Data1T/tmp/pi-web-ui-shot/node_modules/@earendil-works/pi-web-ui/src/`
|
|
|
|
|
|
- `/mnt/Data1T/tmp/pi-web-ui-shot/node_modules/@earendil-works/pi-agent-core/dist/`
|
|
|
|
|
|
- `rust/crates/mnote-web/src/routes/page_ai_pi.rs`
|
|
|
|
|
|
- `rust/crates/mnote-web/browser/sidebar-page-ai-pi-lab-runtime.js`
|
|
|
|
|
|
|
|
|
|
|
|
可复用的合同:
|
|
|
|
|
|
|
|
|
|
|
|
- `SessionData`: `id/title/model/thinkingLevel/messages/createdAt/lastModified`
|
|
|
|
|
|
- `SessionMetadata`: `id/title/lastModified/messageCount/usage/thinkingLevel/preview`
|
|
|
|
|
|
- `AgentEvent`: `agent_start/end`、`message_update/end`、`tool_execution_start/update/end`
|
|
|
|
|
|
- `ThinkingLevel`: `off/minimal/low/medium/high/xhigh`
|
|
|
|
|
|
- Provider/model 设置形态:SettingsDialog、ModelSelector、ProvidersModelsTab、CustomProvider。
|
|
|
|
|
|
|
|
|
|
|
|
不能照搬的部分:
|
|
|
|
|
|
|
|
|
|
|
|
- IndexedDB 是 Pi standalone browser app 的存储,不是 MNote 真相层。
|
|
|
|
|
|
- Pi 原始 `bash/read/write/edit` 仍必须禁用。
|
|
|
|
|
|
- Pi web-ui 是 Lit Web Components;MNote 当前 Pi Lab 保持原生 runtime,不 iframe、不让 Pi UI 接管 provider key 或工具权限。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.3 MNote 当前底座
|
|
|
|
|
|
|
|
|
|
|
|
已有:
|
|
|
|
|
|
|
|
|
|
|
|
- `directory_grants`:当前文件夹授权事实。
|
|
|
|
|
|
- `ai_policies`:已有 `allowed_roots_json / model_policy_json / quota_json`,但无 HTTP 管理 API 和 UI。
|
|
|
|
|
|
- `ai_runtime_runs / ai_runtime_events`:已有跨 provider run/event journal。
|
|
|
|
|
|
- `ai_external_conversation_bindings`:已有 MNote session 与外部 provider conversation 绑定。
|
|
|
|
|
|
- `/admin/access-policy` 与 `/user/access-policy`:已有文件夹授权面板。
|
|
|
|
|
|
|
|
|
|
|
|
缺口:
|
|
|
|
|
|
|
|
|
|
|
|
- Pi Lab session 仍在内存 HashMap,重启丢失。
|
|
|
|
|
|
- Pi Lab receipt 仍在内存 + JSONL adapter,无法按用户/工作区查询。
|
|
|
|
|
|
- provider/model/skills/MCP/tools 的 MNote-native 管理 API 和 UI 不存在。
|
|
|
|
|
|
- Pi Lab UI 的历史、设置、模型选择还没有接入真实配置源。
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 目标架构
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
MNote AI 管理中心
|
|
|
|
|
|
/admin/ai admin global policy
|
|
|
|
|
|
/user/ai user effective settings
|
|
|
|
|
|
|
|
|
|
|
|
|
v
|
|
|
|
|
|
Turso/libSQL control-plane
|
|
|
|
|
|
directory_grants
|
|
|
|
|
|
ai_policies
|
|
|
|
|
|
ai_runtime_runs / ai_runtime_events
|
|
|
|
|
|
ai_external_conversation_bindings
|
|
|
|
|
|
ai_provider_configs / ai_model_catalog / ai_model_grants
|
|
|
|
|
|
ai_tool_policies / ai_skill_registry / ai_mcp_servers
|
|
|
|
|
|
ai_tool_events / ai_file_patches
|
|
|
|
|
|
|
|
|
|
|
|
|
v
|
|
|
|
|
|
MNote AI Facade APIs
|
|
|
|
|
|
effective config
|
|
|
|
|
|
allowed roots
|
|
|
|
|
|
model/provider catalog
|
|
|
|
|
|
skills/tools/MCP policy
|
|
|
|
|
|
LightRAG facade
|
|
|
|
|
|
session history / receipts
|
|
|
|
|
|
|
|
|
|
|
|
|
+--> OpenHub iframe/default Page AI
|
|
|
|
|
|
+--> Pi Lab native drawer
|
|
|
|
|
|
+--> future native agents
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
OpenHub 继续保持默认 Page AI 入口。MNote 管理中心不替换 OpenHub admin,而是成为 MNote 侧 AI 权限和配置的真相层;需要同步给 OpenHub 时,通过 provider identity sync / OpenHub admin API 做下游同步。
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 管理面板信息架构
|
|
|
|
|
|
|
|
|
|
|
|
### 4.1 Admin:`/admin/ai`
|
|
|
|
|
|
|
|
|
|
|
|
沿用现有 `/admin/access-policy` 的 SSR 页面方式,新增 AI 管理中心。左侧区段建议:
|
|
|
|
|
|
|
|
|
|
|
|
1. `Overview`
|
|
|
|
|
|
- AI runtime 状态、OpenHub 状态、Pi Lab 状态、LightRAG 状态、最近错误。
|
|
|
|
|
|
2. `Providers & Models`
|
|
|
|
|
|
- Omniroute/OpenAI/Anthropic/Google/local providers。
|
|
|
|
|
|
- API key/base URL/认证状态。
|
|
|
|
|
|
- 模型可见性、默认 Build/Plan/Task 模型、failover chain。
|
|
|
|
|
|
- 默认保留 `omniroute/freefirst` 作为 Pi Lab dev/default model。
|
|
|
|
|
|
3. `Access Scopes`
|
|
|
|
|
|
- 直接复用当前 `/admin/access-policy`、`/user/access-policy` 文件夹授权 UI 和既有授权 API,不新增 AI-only 授权目录。
|
|
|
|
|
|
- `directory_grants` 是 MNote 与 AI 共用的 allowed roots 事实源。
|
|
|
|
|
|
- `AiAccessScope.allowed_roots`、OpenHub allowedRoots、Pi Lab allowed roots 都从 `directory_grants` 派生。
|
|
|
|
|
|
- 支持 read/write、recursive、capabilities、workspace/user 维度。
|
|
|
|
|
|
- 该区段只提供授权摘要、effective scope 预览和进入现有授权页的入口;若后续内嵌编辑,也必须调用同一套 `directory_grants` command/API。
|
|
|
|
|
|
4. `Tools`
|
|
|
|
|
|
- MNote-owned tools 全局策略:allow/ask/deny。
|
|
|
|
|
|
- 默认 deny raw bash/read/write/edit。
|
|
|
|
|
|
- Pi 只显示并使用 MNote facade tools。
|
|
|
|
|
|
5. `Skills`
|
|
|
|
|
|
- MNote builtin skills、Codex/Acontext skills、OpenHub/opencode skills 的 registry。
|
|
|
|
|
|
- 全局启停,用户可在授权范围内开关。
|
|
|
|
|
|
6. `MCP`
|
|
|
|
|
|
- MCP server registry、启动命令、allowed roots、network policy、env/secret 引用。
|
|
|
|
|
|
- 默认不让 Pi 直接接管 raw MCP;Pi 通过 MNote facade 调用。
|
|
|
|
|
|
7. `Knowledge`
|
|
|
|
|
|
- LightRAG 是唯一默认 provider。
|
|
|
|
|
|
- 管理 source registry、index 状态、citation/open-reference 映射。
|
|
|
|
|
|
8. `Sessions & Receipts`
|
|
|
|
|
|
- Page AI / OpenHub / Pi Lab / native agent 历史。
|
|
|
|
|
|
- tool events、deny reason、diff summary、file version、citation count。
|
|
|
|
|
|
9. `Usage & Quota`
|
|
|
|
|
|
- 按用户、workspace、provider、model 统计。
|
|
|
|
|
|
- token、cost、request count、失败率。
|
|
|
|
|
|
|
|
|
|
|
|
### 4.2 User:`/user/ai`
|
|
|
|
|
|
|
|
|
|
|
|
用户设置只显示 effective config:
|
|
|
|
|
|
|
|
|
|
|
|
- 可用模型:来自 admin allowed models;用户只能隐藏或选择默认,不提升权限。
|
|
|
|
|
|
- 可用 skills/tools/MCP:只能在 admin 允许范围内开关或降级。
|
|
|
|
|
|
- 目录权限:查看由 `directory_grants` 派生的 allowed roots,并进入 `/user/access-policy` 请求或调整授权;不保存 AI 私有目录配置。
|
|
|
|
|
|
- 历史记录:自己的 Page AI / Pi Lab sessions。
|
|
|
|
|
|
- 用量:自己的 quota 与调用统计。
|
|
|
|
|
|
|
|
|
|
|
|
### 4.3 Pi Lab 抽屉接入
|
|
|
|
|
|
|
|
|
|
|
|
Pi Lab 顶部工具栏:
|
|
|
|
|
|
|
|
|
|
|
|
- 历史按钮:打开 Pi Lab history drawer,数据来自 MNote `/api/page-ai/pi/sessions` 或统一 `/api/page-ai/sessions?provider=pi`。
|
|
|
|
|
|
- 设置按钮:打开 MNote-native user AI settings overlay;管理员可跳到 `/admin/ai`。
|
|
|
|
|
|
- 模型选择:读取 effective model options,不再硬编码单个 select。
|
|
|
|
|
|
- Build/Plan:读取 agent mode policy,决定可用模型、thinkingLevel、tool policy。
|
|
|
|
|
|
- 工具/引用/diff:继续只显示 MNote facade 返回的 receipt 和 citation。
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 数据合同
|
|
|
|
|
|
|
|
|
|
|
|
### 5.1 复用现有表
|
|
|
|
|
|
|
|
|
|
|
|
- `directory_grants`:MNote 与 AI 共用的唯一文件夹授权事实源,也是 allowed roots 派生源。
|
|
|
|
|
|
- `ai_policies`:workspace/user 的模型、配额、工具、skills/MCP 策略汇总层;不得作为第二套 allowed roots 真相。历史字段 `allowed_roots_json` 只能视为缓存/兼容快照,写入时必须由 `directory_grants` 派生。
|
|
|
|
|
|
- `ai_runtime_runs`:统一 AI session/run 元数据。Pi Lab 不新建独立 session 真相表,先复用它。
|
|
|
|
|
|
- `ai_runtime_events`:统一 message/tool/runtime event journal。
|
|
|
|
|
|
- `ai_external_conversation_bindings`:OpenHub remote conversation / future external provider binding。
|
|
|
|
|
|
- `user_ui_preferences`:前端折叠状态、默认 tab 等低风险 UI preference。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.2 授权目录单一真相规则
|
|
|
|
|
|
|
|
|
|
|
|
- 不新增 `ai_allowed_roots`、`pi_allowed_roots`、`openhub_allowed_roots` 或任何同义表。
|
|
|
|
|
|
- 不允许 Pi Lab、OpenHub、AI 管理页或 session 设置单独写一份目录授权 JSON。
|
|
|
|
|
|
- 所有目录授权变更统一写入 `directory_grants`,沿用现有管理员/用户权限边界、审计和路径校验。
|
|
|
|
|
|
- AI effective config 按 user/workspace 读取 `directory_grants`,生成 `AiAccessScope.allowed_roots`。
|
|
|
|
|
|
- Pi Lab 创建 session/run 时记录 effective scope 快照,但每次工具执行仍按当前 `directory_grants` 重新校验。
|
|
|
|
|
|
- OpenHub `allowedRoots` 是 MNote 下发的下游投影,不能反向成为授权真相。
|
|
|
|
|
|
- `ai_policies.allowed_roots_json` 只能作为不可独立编辑的兼容快照、迁移输入或缓存;满足迁移条件后应删除或改名,避免误用和双写。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.3 新增或规范化表
|
|
|
|
|
|
|
|
|
|
|
|
第一阶段优先最小新增:
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
ai_tool_events(
|
|
|
|
|
|
id,
|
|
|
|
|
|
user_id,
|
|
|
|
|
|
workspace_id,
|
|
|
|
|
|
session_id,
|
|
|
|
|
|
run_id,
|
|
|
|
|
|
provider,
|
|
|
|
|
|
provider_session_id,
|
|
|
|
|
|
tool_name,
|
|
|
|
|
|
allowed,
|
|
|
|
|
|
deny_reason,
|
|
|
|
|
|
root_uri,
|
|
|
|
|
|
page_path,
|
|
|
|
|
|
normalized_file_path,
|
|
|
|
|
|
diff_summary,
|
|
|
|
|
|
citation_count,
|
|
|
|
|
|
before_file_version,
|
|
|
|
|
|
after_file_version,
|
|
|
|
|
|
payload_json,
|
|
|
|
|
|
created_at,
|
|
|
|
|
|
deleted_at
|
|
|
|
|
|
)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
ai_file_patches(
|
|
|
|
|
|
id,
|
|
|
|
|
|
user_id,
|
|
|
|
|
|
workspace_id,
|
|
|
|
|
|
session_id,
|
|
|
|
|
|
run_id,
|
|
|
|
|
|
tool_event_id,
|
|
|
|
|
|
root_uri,
|
|
|
|
|
|
relative_path,
|
|
|
|
|
|
before_file_version,
|
|
|
|
|
|
after_file_version,
|
|
|
|
|
|
patch_summary_json,
|
|
|
|
|
|
created_at
|
|
|
|
|
|
)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
第二阶段再规范化:
|
|
|
|
|
|
|
|
|
|
|
|
- `ai_provider_configs`
|
|
|
|
|
|
- `ai_model_catalog`
|
|
|
|
|
|
- `ai_model_grants`
|
|
|
|
|
|
- `ai_tool_policies`
|
|
|
|
|
|
- `ai_skill_registry`
|
|
|
|
|
|
- `ai_skill_grants`
|
|
|
|
|
|
- `ai_mcp_servers`
|
|
|
|
|
|
- `ai_mcp_grants`
|
|
|
|
|
|
- `ai_usage_logs`
|
|
|
|
|
|
- `ai_model_failover_chains`
|
|
|
|
|
|
|
|
|
|
|
|
说明:不要急着新增 `ai_provider_sessions`。MNote 已有 `ai_runtime_runs / ai_runtime_events`,Pi Lab history 可以先落这里;只有当 provider 原生 thread 与 MNote run/event journal 差异太大时,再加 provider-specific session detail 表。
|
|
|
|
|
|
|
|
|
|
|
|
## 6. API 合同
|
|
|
|
|
|
|
|
|
|
|
|
### 6.1 管理 API
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
GET /api/ai-admin/overview
|
|
|
|
|
|
GET /api/ai-admin/providers
|
|
|
|
|
|
PUT /api/ai-admin/providers/{provider_id}
|
|
|
|
|
|
GET /api/ai-admin/models
|
|
|
|
|
|
PUT /api/ai-admin/models/{provider_id}/{model_id}/policy
|
|
|
|
|
|
GET /api/ai-admin/access-scopes
|
|
|
|
|
|
GET /api/ai-admin/tools
|
|
|
|
|
|
PUT /api/ai-admin/tools/{tool_name}/policy
|
|
|
|
|
|
GET /api/ai-admin/skills
|
|
|
|
|
|
PUT /api/ai-admin/skills/{skill_id}/policy
|
|
|
|
|
|
GET /api/ai-admin/mcp
|
|
|
|
|
|
PUT /api/ai-admin/mcp/{server_id}/policy
|
|
|
|
|
|
GET /api/ai-admin/knowledge
|
|
|
|
|
|
GET /api/ai-admin/sessions
|
|
|
|
|
|
GET /api/ai-admin/receipts
|
|
|
|
|
|
GET /api/ai-admin/usage
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 6.2 用户有效配置 API
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
GET /api/ai-settings/effective
|
|
|
|
|
|
GET /api/ai-settings/models
|
|
|
|
|
|
PUT /api/ai-settings/models/{provider_id}/{model_id}
|
|
|
|
|
|
GET /api/ai-settings/tools
|
|
|
|
|
|
PUT /api/ai-settings/tools/{tool_name}
|
|
|
|
|
|
GET /api/ai-settings/skills
|
|
|
|
|
|
PUT /api/ai-settings/skills/{skill_id}
|
|
|
|
|
|
GET /api/ai-settings/mcp
|
|
|
|
|
|
GET /api/ai-settings/access-scopes
|
|
|
|
|
|
GET /api/ai-settings/usage
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`GET /api/ai-admin/access-scopes` 与 `GET /api/ai-settings/access-scopes` 只读返回由 `directory_grants` 计算的 effective scope,并返回现有授权管理页入口。授权写入继续使用现有 access-policy / `directory_grants` command/API;不在 AI admin route 中定义第二套 grants 写语义。
|
|
|
|
|
|
|
|
|
|
|
|
### 6.3 Pi Lab history API
|
|
|
|
|
|
|
|
|
|
|
|
可以做成 Pi-specific facade,但底层写 `ai_runtime_runs/events`:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
GET /api/page-ai/pi/sessions
|
|
|
|
|
|
GET /api/page-ai/pi/sessions/{session_id}
|
|
|
|
|
|
PUT /api/page-ai/pi/sessions/{session_id}/title
|
|
|
|
|
|
DELETE /api/page-ai/pi/sessions/{session_id}
|
|
|
|
|
|
GET /api/page-ai/pi/sessions/{session_id}/events
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
响应参考 Pi `SessionMetadata`:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "pi_lab_...",
|
|
|
|
|
|
"title": "当前页解释",
|
|
|
|
|
|
"model": "omniroute/freefirst",
|
|
|
|
|
|
"thinkingLevel": "medium",
|
|
|
|
|
|
"lastModified": "2026-07-04T14:20:00Z",
|
|
|
|
|
|
"messageCount": 8,
|
|
|
|
|
|
"usage": {"input": 1200, "output": 400, "totalTokens": 1600},
|
|
|
|
|
|
"preview": "帮我解释当前页面的逻辑..."
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 实施顺序
|
|
|
|
|
|
|
|
|
|
|
|
### P0:合同与只读聚合
|
|
|
|
|
|
|
|
|
|
|
|
- 新增设计和 smoke baseline。
|
|
|
|
|
|
- 增加 `/api/ai-settings/effective` 只读 API。
|
|
|
|
|
|
- 聚合已有 `directory_grants`、`ai_policies`、agent descriptors、Pi defaults。
|
|
|
|
|
|
- 明确 `effective.allowedRoots` 只从 `directory_grants` 派生;若 `ai_policies.allowed_roots_json` 存在,只作为兼容只读快照或迁移源,不参与新增写入。
|
|
|
|
|
|
- Pi Lab model selector 改为消费 effective models,但仍保留 `omniroute/freefirst` fallback。
|
|
|
|
|
|
|
|
|
|
|
|
验收:
|
|
|
|
|
|
|
|
|
|
|
|
- OpenHub 默认入口不变。
|
|
|
|
|
|
- Pi Lab 打开后能显示来自 MNote effective config 的模型、allowed roots、tool policy。
|
|
|
|
|
|
|
|
|
|
|
|
### P1:Pi Lab history 入库
|
|
|
|
|
|
|
|
|
|
|
|
- Pi Lab start/send/end 写 `ai_runtime_runs / ai_runtime_events`。
|
|
|
|
|
|
- 历史 drawer 读 MNote DB,不读 IndexedDB、不读内存 HashMap。
|
|
|
|
|
|
- 现有 JSONL receipt 保留为 debug fallback。
|
|
|
|
|
|
|
|
|
|
|
|
验收:
|
|
|
|
|
|
|
|
|
|
|
|
- 重启 mnote-web 后 Pi Lab 历史仍可见。
|
|
|
|
|
|
- 同一 user/workspace 隔离生效。
|
|
|
|
|
|
|
|
|
|
|
|
### P2:Receipt 与 patch 入库
|
|
|
|
|
|
|
|
|
|
|
|
- 新增 `ai_tool_events / ai_file_patches`。
|
|
|
|
|
|
- `mnote.local_file.read/patch`、LightRAG query、reference.open、tool_receipt.write 全部写入。
|
|
|
|
|
|
- Pi Lab receipt rail 改读 DB event stream。
|
|
|
|
|
|
|
|
|
|
|
|
验收:
|
|
|
|
|
|
|
|
|
|
|
|
- allowed roots deny、diff summary、file version、citation count 可在管理面板查询。
|
|
|
|
|
|
- patch 后 watcher refresh 仍不新增轮询。
|
|
|
|
|
|
|
|
|
|
|
|
### P3:MNote AI 管理中心首版
|
|
|
|
|
|
|
|
|
|
|
|
- `/admin/ai` 先做四个可用 tab:Overview、Providers & Models、Access Scopes、Sessions & Receipts。
|
|
|
|
|
|
- `/user/ai` 做 Models、Access、History、Usage。
|
|
|
|
|
|
- 复用 `/admin/access-policy` / `/user/access-policy` 逻辑,不拆第二套授权事实;AI 面板里的 Access Scopes 本质上是该授权页面的 AI 视角入口。
|
|
|
|
|
|
|
|
|
|
|
|
验收:
|
|
|
|
|
|
|
|
|
|
|
|
- 管理员可设置 Pi Lab 默认模型和可见模型。
|
|
|
|
|
|
- 用户只能选择管理员允许的模型。
|
|
|
|
|
|
- 文件夹授权仍同步 OpenHub,不破坏 OpenHub。
|
|
|
|
|
|
|
|
|
|
|
|
### P4:Skills / MCP / Tools / LightRAG 管理
|
|
|
|
|
|
|
|
|
|
|
|
- Skills registry 与 grants。
|
|
|
|
|
|
- MCP registry 与 sandbox policy。
|
|
|
|
|
|
- MNote-owned tools allow/ask/deny。
|
|
|
|
|
|
- LightRAG source/index/status 管理。
|
|
|
|
|
|
|
|
|
|
|
|
验收:
|
|
|
|
|
|
|
|
|
|
|
|
- Pi Lab settings 能显示 skills/MCP/tools effective 状态。
|
|
|
|
|
|
- Pi 仍不能直接启用 raw bash/read/write/edit。
|
|
|
|
|
|
- LightRAG 仍是唯一默认 knowledge provider。
|
|
|
|
|
|
|
|
|
|
|
|
## 8. 关键决策
|
|
|
|
|
|
|
|
|
|
|
|
1. **MNote 管理中心是必需的**,但第一步是 control-plane + effective API,不是先做完整 UI。
|
|
|
|
|
|
2. **OpenHub admin 只作为参考和下游同步对象**,不作为 MNote AI 真相层。
|
|
|
|
|
|
3. **文件夹授权只保留一套**:`directory_grants` 同时服务 MNote 工作区访问、OpenHub `allowedRoots` 和 Pi Lab `AiAccessScope.allowed_roots`;AI 管理页只提供同源视图和现有授权入口。
|
|
|
|
|
|
4. **Pi IndexedDB schema 可参考,不能作为 MNote 持久化方案**。
|
|
|
|
|
|
5. **Pi Lab history 先复用 `ai_runtime_runs/events`**,避免新增重复 session 表。
|
|
|
|
|
|
6. **receipt/patch 必须入 Turso/libSQL**,JSONL 只保留 debug/crash recovery。
|
|
|
|
|
|
7. **skills/MCP/tools 先管权限,再接 UI**;否则会把未受控工具暴露给 Pi。
|
|
|
|
|
|
8. **secrets 不进前端、不硬编码**;provider API key 应只存 secret reference/env key,后续再接正式 secret store。
|
|
|
|
|
|
|
|
|
|
|
|
## 9. 风险
|
|
|
|
|
|
|
|
|
|
|
|
- 直接把 OpenHub admin 嵌进 MNote 会形成第二个 iframe 管理系统,和 Pi Lab 原生化目标冲突。
|
|
|
|
|
|
- 先做 Pi UI settings 会把配置写进临时 DOM/内存,后续仍要重接 Turso。
|
|
|
|
|
|
- 如果不先统一 history,Pi Lab 与 OpenHub 会话会分裂,用户无法判断哪个入口产生了修改。
|
|
|
|
|
|
- MCP 管理若过早放开,容易绕过 AiAccessScope;必须默认只注册、只显示,不默认启用。
|
|
|
|
|
|
- Model/provider secret 管理不能复用 Codex auth 作为产品实现;Codex auth 只可作为 dev smoke 输入。
|
|
|
|
|
|
|
|
|
|
|
|
## 10. 下一步最小可执行设计稿
|
|
|
|
|
|
|
|
|
|
|
|
建议下一张执行稿拆成:
|
|
|
|
|
|
|
|
|
|
|
|
`7-72-page-ai-pi-lab-history-and-effective-config-control-plane-v1`
|
|
|
|
|
|
|
|
|
|
|
|
范围只做:
|
|
|
|
|
|
|
|
|
|
|
|
- `/api/ai-settings/effective`
|
|
|
|
|
|
- Pi Lab model options 读取 effective config
|
|
|
|
|
|
- Pi Lab session 写入 `ai_runtime_runs/events`
|
|
|
|
|
|
- Pi Lab history drawer 读 DB
|
|
|
|
|
|
- receipt 仍保留 JSONL,但设计 migration 到 `ai_tool_events`
|
|
|
|
|
|
- smoke 覆盖重启后历史存在、用户隔离、OpenHub 默认入口不变
|
|
|
|
|
|
|
|
|
|
|
|
做完 7-72 后,再做 `/admin/ai` 首版 UI。这样不会在 UI 上先行制造第二套事实源。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 11. 实施进度(2026-07-04)
|
|
|
|
|
|
|
|
|
|
|
|
### P0: 合同与只读聚合 — 进度
|
|
|
|
|
|
|
|
|
|
|
|
| 项 | 状态 | 证据 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| 新增设计和 smoke baseline | ✅ 已完成 | `design/07-ai/process/7-71-*` 设计文档、`scripts/task-ai-management-control-plane-static-smoke.js` 静态 smoke(27/27 通过) |
|
|
|
|
|
|
| `/api/ai-settings/effective` 只读 API | ✅ 已实现 | `routes/ai_settings.rs::effective_settings` — GET-only,读 `directory_grants` 和 `ai_policies.model_policy_json/quota_json` |
|
|
|
|
|
|
| `/api/ai-settings/access-scopes` 用户只读 API | ✅ 已实现 | `routes/ai_settings.rs::user_access_scopes` — GET-only |
|
|
|
|
|
|
| `/api/ai-admin/access-scopes` 管理员只读 API | ✅ 已实现 | `routes/ai_settings.rs::admin_access_scopes` — GET-only,管理员鉴权 |
|
|
|
|
|
|
| 聚合 `directory_grants`、`ai_policies`、agent descriptors、Pi defaults | ✅ 已实现 | effective 响应聚合 providers、models、tool_catalog、lightrag_provider、access_policy_links |
|
|
|
|
|
|
| `effective.allowedRoots` 只从 `directory_grants` 派生 | ✅ 已验证 | `load_active_directory_grants` 读取 `list_directory_grants_for_actor`;`ai_policies.allowed_roots_json` 不被读取 |
|
|
|
|
|
|
| Pi Lab model selector 消费 effective models | ✅ 已实现 | `effective_settings` 响应含 models、default_model;Pi Lab 前端消费 |
|
|
|
|
|
|
| 静态 smoke 覆盖:路由注册、source of truth、无写操作 | ✅ 27/27 通过 | `scripts/task-ai-management-control-plane-static-smoke.js` |
|
|
|
|
|
|
|
|
|
|
|
|
### P1: Pi Lab history 入库 — 进度
|
|
|
|
|
|
|
|
|
|
|
|
| 项 | 状态 | 证据 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| Pi Lab start/send/end 写 `ai_runtime_runs / ai_runtime_events` | ✅ 已实现 | `page_ai_pi.rs::persist_upsert_run` / `persist_append_event` |
|
|
|
|
|
|
| 历史 drawer 读 MNote DB | ✅ 已实现 | `list_sessions` 读 `control_plane.list_ai_runtime_runs`;`get_session_history` / `get_session_events` 分别读 run 和 events |
|
|
|
|
|
|
| 现有 JSONL receipt 保留为 debug fallback | ✅ 已保留 | `PI_LAB_RECEIPT_STORE` JSONL 静态存储仍在 |
|
|
|
|
|
|
| Pi Lab session 路由注册 | ✅ 已验证 | `GET /api/page-ai/pi/sessions`、`GET .../{session_id}`、`GET .../{session_id}/events` |
|
|
|
|
|
|
| Pi Lab session 按 pi_lab/pi profile/acp_runtime 过滤 | ✅ 已验证 | `list_sessions` 过滤 `r.profile == PI_LAB_PROFILE && r.acp_runtime == PI_LAB_ACP_RUNTIME` |
|
|
|
|
|
|
|
|
|
|
|
|
### P2: Receipt 与 patch 入库 — 已完成
|
|
|
|
|
|
|
|
|
|
|
|
| 项 | 状态 | 证据 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `ai_tool_events / ai_file_patches` migration | ✅ | `control-plane/migrations/009-ai-tool-events-file-patches.sql` |
|
|
|
|
|
|
| SQLite 与 Turso/libSQL store | ✅ | `append/list_ai_tool_event`、`append/list_ai_file_patch` |
|
|
|
|
|
|
| Pi tool receipt 入 control-plane | ✅ | `page_ai_pi.rs::write_receipt` |
|
|
|
|
|
|
| patch 关联写入 file patch journal | ✅ | receipt id 作为 `tool_event_id` |
|
|
|
|
|
|
| JSONL 降级为 debug fallback | ✅ | 仅 control-plane 写失败后追加 |
|
|
|
|
|
|
| 管理 API 查询 receipts / patches | ✅ | `/api/ai-settings/receipts`、`/api/ai-admin/receipts` |
|
|
|
|
|
|
|
|
|
|
|
|
### P3: MNote AI 管理中心首版 — 管理员写管理完成
|
|
|
|
|
|
|
|
|
|
|
|
| 项 | 状态 | 证据 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `/admin/ai` 路由与入口 | ✅ 已实现 | `gateway.rs::admin_ai_entry`,鉴权后跳转,管理员模式 |
|
|
|
|
|
|
| `/user/ai` 路由与入口 | ✅ 已实现 | `gateway.rs::user_ai_entry`,鉴权后跳转,用户模式 |
|
|
|
|
|
|
| 账户菜单独立 AI 管理入口 | ✅ 已实现 | `sidebar-workspace-runtime.js` `mnote-account-ai-management`,按角色跳 `/admin/ai` 或 `/user/ai` |
|
|
|
|
|
|
| AI 管理页面 SSR | ✅ 已实现 | `ssr/pages/ai_admin.rs::AiManagementPage` — 对齐 OpenHub Admin 左侧分页、白色 Card 壳、表格、抽屉与分组权限面板;管理 Overview、模型、服务、用量、工具、Skills/MCP、目录、知识库、会话与监控 |
|
|
|
|
|
|
| Access Scopes 只读展示 | ✅ 已验证 | 页面脚本只 GET access-scopes 数据,无 POST/PUT/DELETE,无写表单 |
|
|
|
|
|
|
| Sessions & Receipts 区域 | ✅ 已接真实数据 | 展示 Pi session、tool receipt、deny reason、diff summary、patch 数量 |
|
|
|
|
|
|
| `/admin/ai` 管理写操作(provider/model 编辑等) | ✅ 已实现 | `GET/PUT /api/ai-admin/settings`;模型配置浏览器保存与刷新持久化通过 |
|
|
|
|
|
|
| `/user/ai` 用户设置 | ❌ 未实现 | 当前 `/user/ai` 复用 `AiManagementPage` 用户模式,仅有只读视图;逐用户模型/工具/Skill/MCP override 已在管理员用户抽屉完成 |
|
|
|
|
|
|
|
|
|
|
|
|
### P4: Skills / MCP / Tools / LightRAG 管理 — 部分完成
|
|
|
|
|
|
|
|
|
|
|
|
- Skills、MCP 与工具策略已通过原子管理 API 和 SSR 管理 UI 写入 `ai_policies.model_policy_json`
|
|
|
|
|
|
- MCP 强制 `facadeOnly=true`、`sandbox=true`,secret 仅接受 `env://` / `secret://`
|
|
|
|
|
|
- MNote-owned tools 已支持 allow/ask/deny
|
|
|
|
|
|
- LightRAG source/index/status 管理 UI 未实现
|
|
|
|
|
|
- provider/skill/MCP 专用规范化表未实现;出现独立查询、授权或生命周期需求时再迁移
|
|
|
|
|
|
|
|
|
|
|
|
### OpenHub / Pi Lab 独立入口状态
|
|
|
|
|
|
|
|
|
|
|
|
| 项 | 状态 |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| OpenHub `/page-ai/openhub/ai` 未删除 | ✅ |
|
|
|
|
|
|
| OpenHub `/page-ai/openhub/admin` 未删除 | ✅ |
|
|
|
|
|
|
| OpenHub status API 未删除 | ✅ |
|
|
|
|
|
|
| Pi Lab shell `/page-ai/pi` 未删除 | ✅ |
|
|
|
|
|
|
| Pi Lab start/send/abort/events 路由未删除 | ✅ |
|
|
|
|
|
|
|
|
|
|
|
|
### 验证命令占位
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 静态 smoke(只读代码审计)
|
|
|
|
|
|
node scripts/task-ai-management-control-plane-static-smoke.js
|
|
|
|
|
|
|
|
|
|
|
|
# 运行时 smoke(需要 mnote-web 运行中)
|
|
|
|
|
|
# curl -s http://localhost:3000/api/ai-settings/effective | jq '.sourceOfTruth'
|
|
|
|
|
|
# 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}' http://localhost:3000/admin/ai
|
|
|
|
|
|
# curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/user/ai
|
|
|
|
|
|
# curl -s http://localhost:3000/api/page-ai/pi/sessions | jq '.schema'
|
|
|
|
|
|
# curl -s http://localhost:3000/api/ai-settings/receipts | jq '{receiptCount, patchCount}'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 运行时与浏览器证据
|
|
|
|
|
|
|
|
|
|
|
|
- 隔离运行端口:`127.0.0.1:33171`
|
|
|
|
|
|
- `task-pi-lab-mock-api-smoke.js`:通过
|
|
|
|
|
|
- `task-pi-lab-browser-smoke.js`:通过
|
|
|
|
|
|
- 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`
|
|
|
|
|
|
- OpenHub-like 逐用户配置抽屉截图:`tmp/7-71-ai-admin-openhub-like-ui-final/users.png`
|
|
|
|
|
|
- 管理页实测摘要:会话 1、回执 3、文件补丁 1
|
|
|
|
|
|
- OpenHub 仍为默认 Page AI,Pi Lab 继续使用独立按钮、独立抽屉与独立 session
|
|
|
|
|
|
- `mnote-e2e` 已通过 control-plane `role=admin` 验证管理员访问和写入;浏览器 smoke 使用 dev seed 仅为临时验收账号准备,不写第二套授权目录
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### P4: Skills / MCP / Tools 管理 — 验收结果
|
|
|
|
|
|
|
|
|
|
|
|
| 项 | 状态 | 证据 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| admin 原子策略 GET/PUT | ✅ 通过 | `/api/ai-admin/settings`,统一保存模型、工具、Skills、MCP |
|
|
|
|
|
|
| 浏览器保存与刷新持久化 | ✅ 通过 | `scripts/task-ai-management-browser-smoke.js` |
|
|
|
|
|
|
| secretRef-only 检查 | ✅ 通过 (3 项) | Section 9: 无硬编码 api_key/secret,仅 env 引用 |
|
|
|
|
|
|
| allowed roots 不可写检查 | ✅ 通过 (4 项) | Section 10: 无写路由、无写函数、无写表单 |
|
|
|
|
|
|
| MCP facade-only 检查 | ✅ 通过 (3 项) | Section 11: Pi 仅暴露 mnote. 工具,MCP 经 facade 管控 |
|
|
|
|
|
|
|
|
|
|
|
|
### P5: OpenHub 式逐用户 AI 配置 — 已完成
|
|
|
|
|
|
|
|
|
|
|
|
- OpenHub Admin 的真实用户管理入口为用户表格 + 模型/工具/Skill/目录权限操作;MCP 仅展示用户工作区 `.opencode/mcp` 文件,不存在 Admin per-user MCP 策略。
|
|
|
|
|
|
- MNote 新增用户列表与逐用户 AI 策略 API,用户 override 继续落 `ai_policies(user_id, workspace_id=NULL)`。
|
|
|
|
|
|
- 当前 `ai_policies` 没有系统全局行,因此暂以 `MNOTE_ADMIN_USER_IDS` 首个用户作为全局策略 owner;迁移到规范化 policy 表时移除此兼容约定。
|
|
|
|
|
|
- 本轮已把 MNote `/admin/ai` 用户配置抽屉改成 OpenHub-like 体验:模型按 provider 分组、工具按 risk level 分组、Skill/MCP 使用启停开关、目录权限只读并跳转统一授权管理页。
|
|
|
|
|
|
- effective 合并规则:
|
|
|
|
|
|
- 模型只能从管理员 allowed models 中选择;
|
|
|
|
|
|
- 工具只能降权,不能从 deny/ask 提升到 allow;
|
|
|
|
|
|
- Skill/MCP 只能关闭或启用全局已允许项;
|
|
|
|
|
|
- MCP 始终保持 facade-only + sandbox;
|
|
|
|
|
|
- allowed roots 完全不参与该合并,继续只读 `directory_grants`。
|
|
|
|
|
|
- 浏览器截图:`tmp/7-71-ai-admin-openhub-like-ui-final/users.png`。
|
|
|
|
|
|
- 浏览器 smoke 同时以普通用户 `ai-user` 登录,确认 effective API 不返回被禁用模型和 Skill。
|
|
|
|
|
|
|
|
|
|
|
|
### 本轮 smoke 结果
|
|
|
|
|
|
|
|
|
|
|
|
静态 smoke:**47 通过,0 失败**。浏览器 smoke 验证模型、工具、Skills/MCP 保存、OpenHub Admin 独立入口保留、OpenHub-like 用户抽屉、逐用户 override、刷新持久化及 effective 投影全部通过。
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
$ node scripts/task-ai-management-control-plane-static-smoke.js
|
|
|
|
|
|
通过: 47 失败: 0 跳过: 0
|
|
|
|
|
|
|
|
|
|
|
|
$ MNOTE_AI_ADMIN_OUTPUT_DIR=tmp/7-71-ai-admin-openhub-like-ui-final \
|
|
|
|
|
|
node scripts/task-ai-management-browser-smoke.js
|
|
|
|
|
|
ok: true
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 后续范围
|
|
|
|
|
|
|
|
|
|
|
|
- `/user/ai` 用户模型/Skills/MCP 偏好
|
|
|
|
|
|
- LightRAG source/index/status 写管理
|
|
|
|
|
|
- provider/skill/MCP 专用规范化表迁移
|