Persist PageTree expand state via control-plane view-state and align chevron/DOM with restored expansion; keep Sidex-style shallow page-tree scan and drop the unused recursive scanner that only added cargo noise. Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi into a module package, and retire Hermes/ACP/OpenHub recycle + root harness evidence from the index while gitignoring recycle and local diag dumps. Archive superseded design/bugs docs under old/, point architecture at ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor regressions so the working tree can stay clean.
623 lines
28 KiB
Markdown
623 lines
28 KiB
Markdown
# [recycle] 7-59 Page AI Reasonix Desktop / Hermes Web 控制面借鉴设计 v1
|
||
|
||
> 创建时间:2026-06-10
|
||
>
|
||
> 当前状态:`DONE`
|
||
>
|
||
> Owner:07-ai / Page AI / ACP runtime / Session dashboard / Runtime control surface
|
||
>
|
||
> 前置完成项:`design/07-ai/done/7-58-page-ai-reasonix-official-desktop-session-alignment-v1.md`
|
||
>
|
||
> 参考代码:
|
||
> - Reasonix 官方 desktop:`reference-code/DeepSeek-Reasonix-main/desktop/`
|
||
> - Reasonix desktop runtime:`reference-code/DeepSeek-Reasonix-main/desktop/src/App.tsx`、`desktop/src/protocol.ts`、`desktop/src/ui/*`
|
||
> - Hermes Web UI:`reference-code/hermes-web-ui-0.5.18/README.md`、`packages/client/src/api/hermes/*`、`packages/client/src/stores/hermes/*`、`packages/server/src/routes/hermes/*`
|
||
> - Hermes VSCode ACP host:`reference-code/hermes-vscode-main/src/sessionManager.ts`
|
||
> - MNote 当前 Page AI:`rust/crates/mnote-web/src/routes/hermes_client.rs`、`rust/crates/mnote-web/browser/sidebar-page-ai-*.js`
|
||
|
||
## 1. 第一结论
|
||
|
||
`7-58` 已经解决了 Reasonix / Hermes 的底层会话连续性分歧:Reasonix 走 live binding,Hermes ACP 走 `session/load`。
|
||
|
||
本稿继续处理下一层问题:**Page AI 不应该只是一个聊天抽屉,而应该收敛成“对话 + agent 运行态 + 会话资产 + 配置/权限/工具状态”的轻量控制面。**
|
||
|
||
Reasonix Desktop 和 Hermes Web 各自值得借鉴的部分不同:
|
||
|
||
| 参考 | 值得借鉴 | 不应照搬 |
|
||
| --- | --- | --- |
|
||
| Reasonix Desktop | 运行态事件 reducer、busy/turn complete、queued send、plan/checkpoint/path permission/job/MCP/statusbar | Tauri/Wails 壳、完整桌面布局、Reasonix 专用设置结构 |
|
||
| Hermes Web UI | session dashboard、usage/cost、profiles/models/providers、gateway/jobs/logs/config/status、search/export/delete 资产面 | 独立 Web UI IA、Hermes DB 真相、平台 channel 全量管理 |
|
||
|
||
MNote 的正确方向是:
|
||
|
||
```text
|
||
Page AI drawer = 当前页上下文里的工作面
|
||
Page AI session dashboard = MNote 自己的会话资产面
|
||
Runtime control surface = Hermes/Reasonix/ChatOnly/API Chat 的统一状态面
|
||
External provider/Hermes DB/Reasonix live loop = 外部或进程内 runtime,不是 MNote 长期真相
|
||
```
|
||
|
||
## 2. Reasonix Desktop 对 MNote 的启发
|
||
|
||
### 2.1 事件不是纯文本流,而是 UI reducer 输入
|
||
|
||
Reasonix desktop `App.tsx` 将 incoming event 映射为明确状态:
|
||
|
||
- `$turn_complete`:解除 busy、清 active skill、驱动 queued send。
|
||
- `$path_access_required` / `$confirm_required` / `$choice_required`:进入前端待决策队列。
|
||
- `$plan_required` / `$checkpoint_required` / `$revision_required` / `$step_completed`:进入 plan/checkpoint UI。
|
||
- `$mcp_specs`:显示 MCP 配置/握手/连接/失败/工具数。
|
||
- `$jobs`:显示后台 job 列表、运行/退出状态、stop/stop all。
|
||
- `$ctx_breakdown` / `$balance` / usage:进入 statusbar / context panel。
|
||
- `$session_loaded`:恢复消息、清队列、恢复 carryover usage。
|
||
|
||
MNote 当前 Page AI 已有 message/tool/permission/session/run 的事件基础,但仍偏“聊天消息优先”。后续应把 Page AI event projection 正式拆成:
|
||
|
||
| Projection | UI owner | 事件来源 |
|
||
| --- | --- | --- |
|
||
| final assistant | chat transcript | `message.delta` / final output |
|
||
| thought/reasoning | folded reasoning panel | `thought.delta` |
|
||
| tool card | tool timeline | `tool.started/completed/failed` |
|
||
| permission queue | permission panel/dialog | `permission.*` / ACP decision request |
|
||
| plan/checkpoint | plan panel | `plan.updated` / future `checkpoint.*` |
|
||
| runtime status | header/statusbar | `session.info.updated` / `run.*` / `usage.updated` |
|
||
| MCP/status | runtime control panel | runtime manifest / MCP bridge health |
|
||
| background jobs | jobs popover/panel | future `job.*` / tool long-running receipt |
|
||
|
||
### 2.2 busy 后输入应排队,而不是丢弃或再开 session
|
||
|
||
Reasonix Desktop 有 `queuedSends`:busy 时用户继续发送,不直接开新底层 session;turn complete 后 FIFO 自动发送。
|
||
|
||
MNote 对 Reasonix 尤其需要这个模型,因为同一 live binding 内必须串行 prompt。当前 `7-58` 对 busy binding 会返回 `acp_reasonix_session_busy`。后续应该升级为:
|
||
|
||
```text
|
||
Reasonix binding running
|
||
-> 新输入进入 MNote Page AI session queue
|
||
-> UI 显示 queued count / 可取消
|
||
-> 当前 run terminal 后自动启动下一条 run
|
||
-> 仍复用同一 live binding / acpSessionId
|
||
```
|
||
|
||
验收不应只是“不报 busy”,而是验证两条快速输入仍同一 `acpSessionId` 且顺序正确。
|
||
|
||
### 2.3 Stop 语义必须拆三层
|
||
|
||
Reasonix Desktop 的 stop 更接近“停止当前 turn/job”,不是删除 session。MNote 后续 UI 应明确三个按钮/动作:
|
||
|
||
| 动作 | 含义 | 默认影响 |
|
||
| --- | --- | --- |
|
||
| Stop turn | 取消当前 prompt | 保留 MNote session 与 live binding |
|
||
| Reset runtime | 关闭 Reasonix live binding / Hermes ACP manager | 保留 MNote history,下一轮 cold/new |
|
||
| Delete session | 删除 MNote session history/audit | 不默认删除外部 Hermes DB / provider 会话 |
|
||
|
||
这能避免用户点击“停止”后误以为历史或底层 session 被删。
|
||
|
||
### 2.4 MCP / jobs / usage 要进状态条,不进 assistant 正文
|
||
|
||
Reasonix Desktop 把 MCP specs、jobs、usage、balance 放到 sidebar/statusbar/settings,而不是让模型自然语言解释。
|
||
|
||
MNote 后续应在 Page AI header 下增加 compact status strip:
|
||
|
||
```text
|
||
runtime: Reasonix native-live | Hermes loadable | ChatOnly provider
|
||
session: mnoteSessionId / acpSessionId / mode
|
||
model/profile: profile id + resolved model
|
||
roots: write/read-only grant count
|
||
MCP: connected/failed/tool count
|
||
tools: enabled/disabled count
|
||
jobs: running count
|
||
usage: last run tokens/cost/cache if available
|
||
```
|
||
|
||
## 3. Hermes Web 对 MNote 的启发
|
||
|
||
Hermes Web UI 的 README 将能力分成 Chat、Platform Channels、Usage、Jobs、Model Management、Multi-Profile/Gateway、File Browser、Group Chat、Skills/Memory、Logs、Auth、Settings、Web Terminal。
|
||
|
||
MNote 不能照搬完整 dashboard,但可以抽取控制面能力:
|
||
|
||
### 3.1 Session asset dashboard
|
||
|
||
Hermes Web 的 session 管理包含:多会话、rename/delete/switch、SQLite session DB、按来源分组、active session pin、搜索、模型 badge、context token usage。
|
||
|
||
MNote 已有最小 list/detail/search/export/rename/delete。后续应补:
|
||
|
||
- active session pin:正在 run 的 session 固定到历史列表顶部。
|
||
- runtime grouping:Reasonix / Hermes ACP / ChatOnly / API Chat 分组。
|
||
- status filters:active / completed / failed / cold_resumed / native_live / replay_seen。
|
||
- search fields:user question、assistant final、tool name、citation path、changed file、error code。
|
||
- export profile:JSON / Markdown / audit JSONL 三种导出。
|
||
- delete semantics badge:仅删 MNote history,外部 provider/Hermes DB 不默认删除。
|
||
|
||
### 3.2 Usage / cost / context panel
|
||
|
||
Hermes Web 有 usage analytics:token breakdown、daily trend、model distribution、cost/cache。
|
||
|
||
MNote 不需要先做全局财务面板,但 Page AI 应先做 session/run 级 usage:
|
||
|
||
- 当前 run:prompt/completion/reasoning/cache tokens。
|
||
- 当前 session:累计 tokens/cost/cache hit。
|
||
- 当前 runtime:reserved tool/system/context tokens。
|
||
- fallback/cold resume:显示 packet 大小和截断原因。
|
||
|
||
Reasonix Desktop 的 `ctx_breakdown` 与 Hermes Web 的 usage store 可以合并成 MNote 的 `page_ai_usage_projection.v1`。
|
||
|
||
### 3.3 Profiles / models / providers
|
||
|
||
Hermes Web 将 providers/models/profiles 拆成独立设置面,并支持 credential pool、provider presets、default model switching。
|
||
|
||
MNote 当前 Page AI profile selector 已可用,但缺少“解析后的真实模型与凭据状态”。后续应显示:
|
||
|
||
| 字段 | 示例 |
|
||
| --- | --- |
|
||
| profileId | `mnoteai` / `shared_api_deepseek_flash_chat` |
|
||
| providerKind | `hermes-acp` / `api-chat` / `web-provider` |
|
||
| resolvedModel | `deepseek-v4-flash` / `gpt-5.5` |
|
||
| credentialStatus | configured / missing / inherited / masked |
|
||
| runtimeBinary | `hermes` / `node scripts/reasonix-acp-wrapper.mjs` |
|
||
| configSource | control-plane / env / profile file |
|
||
|
||
### 3.4 Gateway / logs / jobs
|
||
|
||
Hermes Web 把 gateway、logs、jobs 作为运维一等公民。MNote 后续应只引入轻量版:
|
||
|
||
- Runtime health:Hermes ACP process、Reasonix wrapper、MNote MCP bridge、LightRAG MCP/HTTP。
|
||
- Logs tail:最近 N 条 ACP stderr、tool failed、permission denied、MCP failed。
|
||
- Jobs:长任务工具的 running/completed/failed,不把后台进度塞进 assistant final。
|
||
|
||
### 3.5 Skills / memory
|
||
|
||
Hermes Web 有 skills/memory 浏览。Reasonix Desktop 也有 skills、memory、MCP specs。
|
||
|
||
MNote Page AI 后续应把 skill/memory 作为 runtime capability,而不是继续分散在设置页:
|
||
|
||
- 当前 runtime 可用 skills。
|
||
- enabled/disabled user preference。
|
||
- inline/subagent 模式。
|
||
- project/global/builtin scope。
|
||
- memory source:Reasonix native memory / Hermes memory / MNote profile note。
|
||
- 对 Reasonix native-live,不把 MNote memory 强塞到每轮 prompt;只作为 capability manifest 或 cold resume fallback 输入。
|
||
|
||
## 4. 目标信息架构
|
||
|
||
### 4.1 Page AI drawer 分区
|
||
|
||
```text
|
||
Header
|
||
runtime badge / profile / model / session mode / active-run status
|
||
|
||
Chat
|
||
user / assistant final
|
||
folded thought
|
||
tool cards
|
||
citations
|
||
changed files receipt
|
||
|
||
Runtime
|
||
live binding / acpSessionId / load/replay / cold resume
|
||
MCP status
|
||
allowed roots
|
||
tool enablement
|
||
permission queue
|
||
jobs
|
||
usage/context
|
||
|
||
History
|
||
list / search / filters / export / rename / delete
|
||
|
||
Settings
|
||
profile/model/provider
|
||
skills/memory
|
||
runtime health/logs
|
||
```
|
||
|
||
### 4.2 不同 runtime 的展示差异
|
||
|
||
| Runtime | Header mode | Runtime panel 必显 | 不显示/禁用 |
|
||
| --- | --- | --- | --- |
|
||
| Reasonix ACP | `native-live` / `cold-resumed` / `new-session` | live binding、MCP specs、jobs、allowed roots、queued sends | `session/load` 成功率、provider conversation |
|
||
| Hermes ACP | `loaded` / `load-failed-new` / `replay-seen` | acpSessionId、load/replay、profile/model、tool locations | Reasonix live binding status |
|
||
| ChatOnly Web | `provider-conversation` | providerConversationId、remote delete status | ACP session/load/live binding |
|
||
| API Chat | `server-transcript` | model/provider/usage、MNote transcript | provider web conversation binding |
|
||
|
||
## 5. 后端合同
|
||
|
||
### 5.1 Runtime status snapshot
|
||
|
||
新增或收口一个 Page AI runtime status API:
|
||
|
||
```text
|
||
GET /api/page-ai/runtime/status?sessionId=...&workspaceId=...&documentId=...
|
||
```
|
||
|
||
返回:
|
||
|
||
```json
|
||
{
|
||
"schema": "mnote.page_ai_runtime_status.v1",
|
||
"mnoteSessionId": "...",
|
||
"runtime": "reasonix",
|
||
"profile": "reasonix",
|
||
"mode": "native_live",
|
||
"activeRun": { "runId": "...", "status": "running" },
|
||
"acp": {
|
||
"acpSessionId": "...",
|
||
"supportsSessionLoad": false,
|
||
"replaySeen": false,
|
||
"liveBinding": { "status": "idle", "workspaceKey": "file://..." }
|
||
},
|
||
"model": { "resolvedModel": "...", "providerKind": "..." },
|
||
"roots": { "write": 1, "readOnly": 0 },
|
||
"mcp": { "status": "connected", "toolCount": 8, "failed": [] },
|
||
"tools": { "enabled": 12, "disabled": 2 },
|
||
"jobs": { "running": 0 },
|
||
"usage": { "sessionTokens": 0, "lastRunTokens": 0 }
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- `acpSessionId` 只作为 runtime reference,不是 MNote 长期真相。
|
||
- Reasonix `supportsSessionLoad=false` 必须明确展示。
|
||
- Hermes replay 只能影响 `replaySeen/replaySeq`,不能当当前 answer。
|
||
- ChatOnly/API Chat 不返回 ACP binding。
|
||
|
||
### 5.2 Session search/export 升级
|
||
|
||
现有 `/api/hermes/client/sessions/search` 与 `/export` 后续收口为 Page AI 命名:
|
||
|
||
```text
|
||
GET /api/page-ai/sessions
|
||
GET /api/page-ai/sessions/search?q=...
|
||
GET /api/page-ai/sessions/{id}
|
||
GET /api/page-ai/sessions/{id}/export?format=json|markdown|jsonl
|
||
POST /api/page-ai/sessions/{id}/rename
|
||
DELETE /api/page-ai/sessions/{id}
|
||
```
|
||
|
||
`/api/hermes/client/sessions/*` 保留 compat,但前端新代码优先走 `/api/page-ai/*`。
|
||
|
||
### 5.3 Queued sends
|
||
|
||
新增队列表:
|
||
|
||
```text
|
||
page_ai_queued_runs
|
||
id
|
||
user_id
|
||
workspace_id
|
||
document_id
|
||
session_id
|
||
run_id
|
||
runtime
|
||
profile
|
||
payload_json
|
||
status: queued | started | cancelled | failed
|
||
created_at / updated_at
|
||
```
|
||
|
||
Reasonix live binding busy 时不返回 failed,而是入队。
|
||
|
||
## 6. 前端实现边界
|
||
|
||
### 6.1 文件 owner
|
||
|
||
| 文件 | 改动边界 |
|
||
| --- | --- |
|
||
| `sidebar-page-ai-runtime.js` | 只保留 orchestration;不要继续塞 dashboard 渲染细节 |
|
||
| `sidebar-page-ai-session-runtime.js` | session list/detail/search/export/rename/delete/filters |
|
||
| `sidebar-page-ai-render-runtime.js` | Page AI 面板渲染,新增 Runtime / Dashboard 分区 |
|
||
| `sidebar-page-ai-profile-runtime.js` | profile/model/provider 解析展示 |
|
||
| `sidebar-page-ai-skill-runtime.js` | skill/memory/MCP capability 偏好 |
|
||
| `sidebar-page-ai-permission-runtime.js` | permission decision queue |
|
||
| 新建议:`sidebar-page-ai-runtime-status-runtime.js` | runtime status polling/event apply,不和 chat streaming 混写 |
|
||
|
||
### 6.2 UI 原则
|
||
|
||
- Runtime 状态只做 compact status strip + detail panel,不占 assistant 正文。
|
||
- thought/tool/plan/permission/citation 分区渲染,不拼进 final answer。
|
||
- history action 永远可点击,不靠 hover 才能完成核心操作。
|
||
- stop/reset/delete 三类危险程度不同,按钮必须分开。
|
||
- 短回复“可以/继续”在 `new-session` 且无 history 时显示缺上下文提示。
|
||
|
||
## 7. 执行顺序
|
||
|
||
### Phase A:Runtime status surface
|
||
|
||
- [x] 后端新增 `/api/page-ai/runtime/status`,返回 runtime/profile/model/session/acp/mcp/tools/jobs/usage。
|
||
- [x] 前端 header 显示 runtime badge、session mode、active-run status。
|
||
- [x] Runtime panel 展示 `acpSessionId`、Reasonix live binding、Hermes load/replay、allowed roots。
|
||
- [x] 浏览器 smoke:Reasonix / Hermes / API Chat 三种 runtime 切换时 status 不串线。
|
||
|
||
### Phase B:Reasonix Desktop 运行态对齐
|
||
|
||
- [x] Reasonix busy binding 改为 queued send,不再直接 failed。
|
||
- [x] 队列 UI 显示 queued count、queued text preview、cancel。
|
||
- [x] 当前 run terminal 后自动启动下一条 queued run,仍复用同一 live binding。
|
||
- [x] Stop turn 不关闭 binding;Reset runtime 才关闭 binding。
|
||
- [x] MCP specs/status/toolCount 进入 runtime panel。
|
||
- [x] Jobs popover 支持 long-running tool receipt / stop all。(当前无真实后台 job registry 时展示空态和 no-op stop-all,后续长任务接入只需填充 `jobs.items`。)
|
||
- [x] Smoke:快速发送两条消息,验证 FIFO、同一 `acpSessionId`、无输出中残留。
|
||
|
||
### Phase C:Hermes Web 控制面最小引入
|
||
|
||
- [x] Page AI session API 命名从 `/api/hermes/client/sessions` 收口到 `/api/page-ai/sessions`。
|
||
- [x] session list 支持 runtime grouping、active pin、status filters。
|
||
- [x] search 支持 message/tool/citation/changed file/error code。
|
||
- [x] export 支持 json/markdown/jsonl 三格式。
|
||
- [x] usage panel 展示 session/run/model/cache/cost。
|
||
- [x] profile/model/provider panel 展示 resolved model、credential status、config source。
|
||
- [x] Smoke:search/filter/export/usage/profile status 在真实浏览器可见。
|
||
|
||
### Phase D:权限/配置/外部删除边界
|
||
|
||
- [x] permission decision loop 做成持久 pending queue,刷新后不丢。
|
||
- [x] delete session 明确只删除 MNote history;外部 Hermes/provider 删除必须二次确认。
|
||
- [x] reset runtime 只关闭 live binding/ACP manager,不删除 MNote history。
|
||
- [x] logs tail 显示 ACP stderr、tool failed、MCP failed 最近 N 条。
|
||
- [x] Smoke:delete/reset/stop 三类动作互不误伤。
|
||
|
||
## 8. 验收矩阵
|
||
|
||
### 8.1 Reasonix
|
||
|
||
- [x] `native-live` 状态清晰可见。
|
||
- [x] busy 时第二条输入进入 queue,不开新 session。
|
||
- [x] queued send 自动执行后仍同一 `acpSessionId`。
|
||
- [x] Stop turn 后下一轮仍可 native-live。
|
||
- [x] Reset runtime 后下一轮显示 `cold_resumed` 或 `new_session`。
|
||
- [x] MCP failed 显示为 status/tool card,不污染 assistant final。
|
||
|
||
### 8.2 Hermes ACP
|
||
|
||
- [x] stored `acpSessionId` 先 `session/load`。
|
||
- [x] replay 显示为 replay evidence / history restore,不混入当前回答。
|
||
- [x] load failed 明确显示 `load-failed-new`。
|
||
- [x] session dashboard 可按 Hermes profile/model 过滤。
|
||
|
||
### 8.3 ChatOnly / API Chat
|
||
|
||
- [x] providerConversationId 与 acpSessionId 不混用。
|
||
- [x] API Chat 不写 web provider binding。
|
||
- [x] session dashboard 仍可展示/search/export。
|
||
- [x] delete MNote history 不默认删除远端 provider 会话。
|
||
|
||
### 8.4 通用 UI
|
||
|
||
- [x] 回答完成后无 `AI · 输出中`。
|
||
- [x] history actions 在桌面/移动都可点击。
|
||
- [x] runtime status 与当前 session 一致,切 session 后不显示旧 acpSessionId。
|
||
- [x] tool/citation/permission/plan/job 不进入 assistant final。
|
||
|
||
## 9. 不做事项
|
||
|
||
- 不把 Reasonix Desktop 的 Tauri shell 或完整布局搬进 MNote。
|
||
- 不把 Hermes Web UI 作为 MNote 的独立 dashboard 复刻。
|
||
- 不把 Hermes DB 当成 MNote session 真相。
|
||
- 不把 Reasonix native memory 改造成 MNote 每轮 transcript 注入。
|
||
- 不自动删除外部 Hermes/provider session store。
|
||
- 不在 Page AI 主路径继续叠加无界轮询;runtime status 优先事件/command result 驱动,短期 fallback 必须有退出条件。
|
||
|
||
## 10. 首批可执行切片
|
||
|
||
### 10.1 Slice A1:runtime status 后端只读快照
|
||
|
||
目标:先让 Page AI 能回答“当前 agent 是谁、是否还在运行、底层 session 是否连续、MCP/工具是否可用”。
|
||
|
||
范围:
|
||
|
||
- 新增 `/api/page-ai/runtime/status` 只读 route。
|
||
- 数据先从现有 `PageAiSessionStore` / `AcpSessionManager` / profile resolver / tool registry 组合,不新增长期表。
|
||
- Reasonix 返回 `mode=native_live|cold_resumed|new_session`,Hermes 返回 `mode=loaded|load_failed_new|replay_seen|new_session`,ChatOnly/API Chat 返回非 ACP mode。
|
||
- active run 状态必须来自 event store / terminal reconciliation 后的最终状态,不能只看前端 streaming flag。
|
||
|
||
验收:
|
||
|
||
```bash
|
||
cargo test -p mnote-web page_ai_runtime_status
|
||
```
|
||
|
||
若 Rust route 暂时没有专名测试,至少补一个 fake store/unit test 覆盖 Reasonix、Hermes、API Chat 三类 snapshot。
|
||
|
||
### 10.2 Slice A2:Page AI header/status strip
|
||
|
||
目标:把 runtime status 放到聊天抽屉顶部,而不是让 assistant 正文解释。
|
||
|
||
范围:
|
||
|
||
- `sidebar-page-ai-render-runtime.js` 增加 compact status strip。
|
||
- `sidebar-page-ai-runtime.js` 只负责加载/应用 status,不塞具体 DOM 细节。
|
||
- 回答终止后 status strip 必须同步清理 active-run,避免 `AI · 输出中` 残留。
|
||
- 切换 session/document 后先清空旧 status,再加载新 status,避免旧 `acpSessionId` 短暂串线。
|
||
|
||
验收:
|
||
|
||
```bash
|
||
node scripts/task559-page-ai-terminal-status-reconciliation-smoke.js
|
||
```
|
||
|
||
并补一条真实浏览器 smoke:Reasonix/Hermes/API Chat 切换后 header badge 与当前 profile 一致。
|
||
|
||
### 10.3 Slice B1:Reasonix queued send 最小版
|
||
|
||
目标:busy binding 不再直接失败,先支持同一 Page AI session 内 FIFO 串行发送。
|
||
|
||
范围:
|
||
|
||
- 先实现内存队列或 event-store backed queue;如果实现跨刷新不稳定,再升级 `page_ai_queued_runs` 表。
|
||
- queue item 必须记录 `sessionId`、`runId`、`runtime`、`profile`、`acpSessionId`、原始 prompt payload。
|
||
- 当前 run terminal 后自动 dequeue 下一条,仍复用 Reasonix live binding。
|
||
- cancel queued item 只取消队列项,不 stop 当前 run。
|
||
|
||
验收:
|
||
|
||
```bash
|
||
node scripts/task558-page-ai-reasonix-live-session-context-smoke.js
|
||
```
|
||
|
||
新增/扩展浏览器断言:
|
||
|
||
- 快速发送两条消息。
|
||
- 第二条先显示 queued。
|
||
- 两轮完成后 `acpSessionId` 一致。
|
||
- 第二轮短回复能引用第一轮上下文。
|
||
- 最终无 `AI · 输出中`。
|
||
|
||
### 10.4 Slice C1:Page AI sessions 命名兼容层
|
||
|
||
目标:前端新主路径不再把 Page AI session dashboard 命名成 Hermes client。
|
||
|
||
范围:
|
||
|
||
- 新增 `/api/page-ai/sessions/*` wrapper。
|
||
- 复用现有 `/api/hermes/client/sessions/*` handler 或 store,不重复实现。
|
||
- 老路由继续保留 compat;测试必须证明老路由仍可用。
|
||
- 前端 session runtime 优先请求 `/api/page-ai/sessions/*`。
|
||
|
||
验收:
|
||
|
||
```bash
|
||
cargo test -p mnote-web page_ai_sessions
|
||
node scripts/task561-page-ai-session-dashboard-smoke.js
|
||
```
|
||
|
||
### 10.5 Slice C2:Hermes load/replay 可见化
|
||
|
||
目标:把 Hermes ACP `session/load` 与 replay 作为 runtime evidence 展示,而不是混入当前回答。
|
||
|
||
范围:
|
||
|
||
- status snapshot 增加 `loadAttempted`、`loadStatus`、`replaySeen`、`replaySeq`、`replayMessageCount`。
|
||
- UI 显示为 runtime panel evidence。
|
||
- 当前 assistant final 只来自当前 run final,不消费 replay 作为回答。
|
||
|
||
验收:
|
||
|
||
```bash
|
||
node scripts/task560-page-ai-hermes-load-replay-smoke.js
|
||
```
|
||
|
||
覆盖无 replay / 有 replay 两种 fake Hermes ACP fixture。
|
||
|
||
## 11. Event projection 合同
|
||
|
||
Page AI 后续统一把 runtime events 规整成下面几类 projection。前端只能消费 projection,不直接按 provider 原始事件猜 UI 状态。
|
||
|
||
| Projection | 关键字段 | terminal 规则 |
|
||
| --- | --- | --- |
|
||
| `runProjection` | `runId/status/startedAt/endedAt/errorCode` | `completed/failed/cancelled` 必须清 active-run |
|
||
| `messageProjection` | `role/final/thought/toolCalls/citations` | final 与 thought 分离 |
|
||
| `sessionProjection` | `mnoteSessionId/runtime/acpSessionId/mode` | 切 session 后旧 projection 不可复用 |
|
||
| `runtimeProjection` | `profile/model/provider/binary/configSource` | profile 切换后立即 invalidated |
|
||
| `capabilityProjection` | `mcp/tools/skills/memory/roots` | failed capability 不污染 assistant final |
|
||
| `decisionProjection` | `permission/choice/confirm/pathAccess` | pending 决策可刷新恢复 |
|
||
| `queueProjection` | `queuedCount/items/cancellable` | current terminal 后 FIFO dequeue |
|
||
| `usageProjection` | `tokens/cost/cache/contextBreakdown` | usage 缺失时显示 unknown,不伪造 0 |
|
||
|
||
最低要求:
|
||
|
||
- `AI · 输出中` 只能绑定 `runProjection.status=running|streaming`。
|
||
- `acpSessionId` 只能来自 `sessionProjection`。
|
||
- replay、load、MCP、job、permission 都不能写进 assistant final。
|
||
- provider 原始 event 增加新字段时,未识别字段进入 `rawEvidence`,不直接影响 UI。
|
||
|
||
## 12. 风险与边界
|
||
|
||
### 12.1 上下文连续性的误判风险
|
||
|
||
短回复“可以/继续”天然依赖历史。UI 必须区分:
|
||
|
||
| 状态 | 用户提示 |
|
||
| --- | --- |
|
||
| `native_live` / `loaded` | 显示连续会话 |
|
||
| `cold_resumed` | 显示已用 MNote history fallback 恢复 |
|
||
| `new_session` 且 history 为空 | 提示当前没有可用上下文 |
|
||
| `load_failed_new` | 提示底层 ACP load 失败,已新建 runtime session |
|
||
|
||
这比单纯把 transcript 拼进 prompt 更重要,因为 Reasonix native-live 与 Hermes load/replay 的真实连续机制不同。
|
||
|
||
### 12.2 删除与重置边界
|
||
|
||
删除、重置、停止必须保持三套语义:
|
||
|
||
- `Stop turn`:只影响当前 run。
|
||
- `Reset runtime`:只影响 Reasonix live binding / Hermes ACP process 或 manager。
|
||
- `Delete session`:只影响 MNote session history;外部 Hermes DB / provider 会话删除必须另设显式二次确认。
|
||
|
||
### 12.3 轮询边界
|
||
|
||
runtime status 首选 event apply / command result refresh。短期允许有界 fallback,但必须满足:
|
||
|
||
- 仅在 Page AI drawer 可见且当前 session active 时启用。
|
||
- interval 有最大时长和 stop 条件。
|
||
- run terminal、session switch、drawer close 都必须停止。
|
||
- 后续进入 done 前,要记录是否已替换为 event-driven。
|
||
|
||
## 13. 设计归档规则
|
||
|
||
本稿进入 `done/` 前必须满足:
|
||
|
||
- Phase A-D checklist 至少按 slice 完成,并记录每个 slice 的测试命令。
|
||
- 浏览器 smoke 证明 Reasonix、Hermes ACP、ChatOnly/API Chat 不串状态。
|
||
- 用户最初两个问题已有可见验收:短回复能继承上下文,回答完成不残留 `AI · 输出中`。
|
||
- 若某项因为外部 provider 权限、Hermes DB 删除策略或 Reasonix 官方行为无法完成,必须在本稿末尾追加“归档说明”,不能只留 unchecked TODO。
|
||
|
||
## 14. 本稿完成条件
|
||
|
||
- Phase A-D checklist 有真实代码、单测或 browser smoke。
|
||
- Reasonix queued send / stop / reset 语义明确可见。
|
||
- Hermes-style session dashboard 不再挂在 `/api/hermes/client/*` 命名主路径上。
|
||
- Runtime status 能解释用户最关心的四件事:当前 agent 是谁、上下文是否连续、工具/MCP 是否可用、为什么还在输出中或已经结束。
|
||
- ChatOnly / API Chat 回归不受 ACP runtime status 改动影响。
|
||
|
||
## 15. 实施记录
|
||
|
||
### 2026-06-10 Slice A-D 完成记录
|
||
|
||
已完成:
|
||
|
||
- 后端新增 `/api/page-ai/runtime/status`,返回 `runtime/profile/model/session/acp/mcp/tools/jobs/usage/logs`。
|
||
- 前端 Page AI header 增加 runtime status strip,runtime panel 增加 status detail。
|
||
- `AI · 输出中` / active-run 清理继续走 terminal reconciliation;`session.created` 不再被判定为 active run。
|
||
- Reasonix 前端 busy/queued/running 发送改为 client FIFO queue:当前 run 结束后自动发送下一条,仍复用当前 MNote session 和已保存的 `acpSessionId`。
|
||
- Reasonix live binding 的 direct busy fallback 不再立即返回 `acp_reasonix_session_busy` failed;stream 侧等待 binding idle 后继续同一 live binding。
|
||
- 队列 UI 显示 queued count、preview、cancel;client queued item 可本地取消。
|
||
- 新增 `/api/page-ai/sessions/*` 主命名 route,旧 `/api/hermes/client/sessions/*` 保留 compat。
|
||
- 前端 session runtime 已切到 `/api/page-ai/sessions/*`。
|
||
- Hermes replay 继续作为 `adapter_replay` evidence;runtime status 展示 `replaySeen/replaySeq/replayMessageCount`。
|
||
- permission pending queue 增加 localStorage 恢复,刷新后可恢复未决 permission。
|
||
- 新增 `/api/page-ai/runtime/reset`,只关闭 Reasonix live binding / runtime binding,不删除 MNote history 或外部 provider session。
|
||
- session delete 默认只删除 MNote history / 本地 provider binding 标记;外部 provider 远端删除需要 `deleteExternalProviderSession=1`。
|
||
- session dashboard 增加 runtime/status filter、active pin、可见 action,前端主路径使用 `/api/page-ai/sessions/*`。
|
||
- session export 增加 `json/markdown/jsonl` 三格式。
|
||
- runtime panel 增加 jobs/logs tail;当前无真实长任务 registry 时显示空态,`Stop all` 不删除 history / runtime,只在无 job 时提示无可停止项。
|
||
|
||
验证:
|
||
|
||
```bash
|
||
cargo test -p mnote-web page_ai_runtime_status -- --nocapture
|
||
cargo test -p mnote-web page_ai_session_active_run -- --nocapture
|
||
cargo test -p mnote-web delete_session -- --nocapture
|
||
cargo test -p mnote-web hermes_client -- --nocapture
|
||
node --check rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js
|
||
node --check rust/crates/mnote-web/browser/sidebar-page-ai-render-runtime.js
|
||
node --check rust/crates/mnote-web/browser/sidebar-page-ai-session-runtime.js
|
||
node --check rust/crates/mnote-web/browser/sidebar-page-ai-permission-runtime.js
|
||
node scripts/task559-page-ai-terminal-status-reconciliation-smoke.js
|
||
node scripts/task558-page-ai-reasonix-live-session-context-smoke.js
|
||
node scripts/task560-page-ai-hermes-load-replay-smoke.js
|
||
node scripts/task561-page-ai-session-dashboard-smoke.js
|
||
```
|
||
|
||
最新验证输出:
|
||
|
||
- `cargo test -p mnote-web hermes_client -- --nocapture`:87 passed。
|
||
- `node scripts/task558-page-ai-reasonix-live-session-context-smoke.js`:通过,验证快速连续发送、queued preview、同一 `acpSessionId`、第二轮“可以”继承上下文、无输出中残留。
|
||
- `node scripts/task559-page-ai-terminal-status-reconciliation-smoke.js`:通过,验证 terminal reconciliation、runtime strip、runtime panel jobs/logs/status 可见。
|
||
- `node scripts/task560-page-ai-hermes-load-replay-smoke.js`:通过,覆盖 no replay / with replay。
|
||
- `node scripts/task561-page-ai-session-dashboard-smoke.js`:通过,验证 `/api/page-ai/sessions/*`、search、status filter、export `json/markdown/jsonl`、rename/delete。
|
||
|
||
归档说明:
|
||
|
||
- 当前 jobs 面板已经有 `jobs.running/items` 合同、空态和 Stop all 控件;由于 Page AI 还没有真实 long-running job registry,本稿不伪造 job receipt,不接外部 provider job 删除。后续长任务工具接入时只扩充 `jobs.items` 和 stop handler。
|
||
- 外部 Hermes/provider 远端删除仍不提供默认 UI 动作;后端只接受显式 `deleteExternalProviderSession=1`,前端普通 Delete session 只删 MNote history。
|