feat(ai): switch page ai to hermes panel

This commit is contained in:
lix-2026
2026-05-14 15:10:33 +08:00
parent e9188716e6
commit 9816035491
48 changed files with 6353 additions and 412 deletions
@@ -11,7 +11,7 @@
> - 本稿对应 `Phase 7 v2` 的“文档页 AI 最小闭环”已完成,故迁入 `done/`
> - 本稿完成不等于整个 `Phase 7 v2` 已完成;结构化知识写链仍以后续阶段继续推进
> - 2026-05-05 追加说明:本稿记录的是 `openai-agents-python` sidecar 作为过渡主链的完成状态,不代表当前长期方向;当时长期口径曾由 `/mnt/Data1T/mnote/design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md` 收口为 `mnote-cli` 是唯一长期 agent 执行面
> - 2026-05-13 追加说明:`mnote-cli` 唯一长期 agent 执行面口径已被 `/mnt/Data1T/mnote/design/07-ai/process/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md` 覆盖;新的长期方向是页面 AI 面板仅作为 Hermes 页面内客户端,Hermes 持有 AI 会话真相,mnote 通过 Hermes skill/plugin 暴露业务工具
> - 2026-05-13 追加说明:`mnote-cli` 唯一长期 agent 执行面口径已被 `/mnt/Data1T/mnote/design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md` 覆盖;新的长期方向是页面 AI 面板仅作为 Hermes 页面内客户端,Hermes 持有 AI 会话真相,mnote 通过 Hermes skill/plugin 暴露业务工具
---
@@ -1,4 +1,4 @@
# 7-2 [process] Phase 7 结构化 Artifact 写链最小落地方案 v1
# 7-2 [done] Phase 7 结构化 Artifact 写链最小落地方案 v1
> 更新时间:2026-04-23
>
@@ -7,7 +7,7 @@
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-tree-first-graph-kernel-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md`
> - `/mnt/Data1T/mnote/design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-1-phase7-document-ai-minimum-loop-checklist-v1.md`
>
> 2026-05-05 追加说明:
@@ -17,7 +17,7 @@
>
> 2026-05-13 追加说明:
> - 本稿的对象模型、artifact 写链、projection-only `AI Artifacts` 分组与 kernel 边界继续有效
> - 触发与执行口径改由 `/mnt/Data1T/mnote/design/07-ai/process/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md` 覆盖
> - 触发与执行口径改由 `/mnt/Data1T/mnote/design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md` 覆盖
> - 当前凡是提到“页面 AI 面板触发”或“页面 AI host 固定动作”的位置,都应理解为:
> 页面 AI 面板作为 Hermes 页面内客户端发起意图,Hermes 通过 mnote skill/plugin 调用正式 artifact 工具,最终写入仍回到 Rust runtime / kernel
@@ -1,4 +1,4 @@
# 7-3 [process] 页面 AI Hermes 面板与 mnote Plugin 主线方案 v1
# 7-3 [done] 页面 AI Hermes 面板与 mnote Plugin 主线方案 v1
> 更新时间:2026-05-13
>
@@ -10,7 +10,8 @@
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-10-wolai-page-settings-and-ai-surface-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-2-phase7-structured-artifact-write-chain-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-2-phase7-structured-artifact-write-chain-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md`
>
> 覆盖关系:
> - 覆盖 `/mnt/Data1T/mnote/design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md`
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,243 @@
# 7-5 [done] Hermes client proxy 合同 v1
> 更新时间:2026-05-14
>
> 上位依据:`design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`、`design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md`
>
> Hermes Web UI 参考:`packages/client/src/api/hermes/chat.ts`、`packages/client/src/api/hermes/sessions.ts`、`packages/server/src/routes/hermes/proxy-handler.ts`、`packages/server/src/services/hermes/chat-run-socket.ts`
## 1. 边界
- [x] 浏览器只访问 mnote-web 同源 `/api/hermes/client/*`
- [x] Hermes API key / gateway token 只存在 mnote-web 服务端环境变量。
- [x] mnote-web proxy 只做 auth、同源安全、页面上下文注入、trace 注入和错误码标准化。
- [x] mnote-web proxy 不保存 Hermes session、message、tool event、usage、model 真相。
- [x] `pageContext` 是 run 输入上下文,不是 Hermes session 的长期事实源。
- [x]`/api/ai-agent/run` 在并存期只作为 legacy endpoint,不是新 Hermes 面板主代理。
## 2. 路由
### `GET /api/hermes/client/sessions`
请求:
```http
GET /api/hermes/client/sessions?workspaceId=ws_1&documentId=doc_1&limit=20
```
响应:
```json
{
"ok": true,
"traceId": "trace_1",
"sessions": [
{
"sessionId": "mnote_doc_1_20260514",
"title": "当前页问答",
"preview": "请总结当前页面",
"messageCount": 2,
"toolCallCount": 1,
"updatedAt": 1778712000,
"model": "hermes-agent"
}
]
}
```
### `POST /api/hermes/client/sessions`
请求:
```json
{
"workspaceId": "ws_1",
"documentId": "doc_1",
"traceId": "trace_1",
"title": "当前页问答"
}
```
响应:
```json
{
"ok": true,
"sessionId": "mnote_doc_1_trace_1",
"traceId": "trace_1",
"persistence": "hermes_on_first_run"
}
```
说明:Hermes Web UI 参考实现没有独立 session create HTTP route,客户端生成 session id,首次 run 时由 Hermes 持久化。mnote 保留本 route 是为了同源客户端合同稳定,但不得在 mnote 保存聊天历史。
### `GET /api/hermes/client/sessions/{session_id}`
请求:
```http
GET /api/hermes/client/sessions/mnote_doc_1_trace_1?workspaceId=ws_1&documentId=doc_1
```
响应:
```json
{
"ok": true,
"sessionId": "mnote_doc_1_trace_1",
"traceId": "trace_1",
"messages": [
{
"messageId": "42",
"role": "assistant",
"content": "当前页标题是...",
"toolCallId": null,
"toolName": null,
"timestamp": 1778712000,
"reasoning": null
}
],
"usage": {
"inputTokens": 120,
"outputTokens": 30,
"totalTokens": 150
}
}
```
### `POST /api/hermes/client/runs`
请求:
```json
{
"workspaceId": "ws_1",
"documentId": "doc_1",
"sessionId": "mnote_doc_1_trace_1",
"message": "概括当前页面标题和第一段",
"model": "hermes-agent",
"pageContext": {
"title": "项目计划",
"outline": [],
"pageOptions": { "wideLayout": true }
},
"selectedBlockId": null,
"selectedText": null,
"traceId": "trace_1"
}
```
响应:
```json
{
"ok": true,
"sessionId": "mnote_doc_1_trace_1",
"runId": "run_123",
"messageId": null,
"events": [],
"traceId": "trace_1"
}
```
### `GET /api/hermes/client/events/{run_id}`
请求:
```http
GET /api/hermes/client/events/run_123?sessionId=mnote_doc_1_trace_1
```
响应:`text/event-stream`
```text
data: {"event":"message.delta","run_id":"run_123","session_id":"mnote_doc_1_trace_1","delta":"当前页"}
data: {"event":"run.completed","run_id":"run_123","session_id":"mnote_doc_1_trace_1","output":"当前页...","usage":{"input_tokens":120,"output_tokens":30,"total_tokens":150}}
```
### `POST /api/hermes/client/runs/{run_id}/abort`
请求:
```json
{
"workspaceId": "ws_1",
"documentId": "doc_1",
"sessionId": "mnote_doc_1_trace_1",
"traceId": "trace_1"
}
```
响应:
```json
{
"ok": true,
"runId": "run_123",
"sessionId": "mnote_doc_1_trace_1",
"traceId": "trace_1",
"events": [
{ "event": "abort.started", "run_id": "run_123" }
]
}
```
### `GET /api/hermes/client/models`
响应:
```json
{
"ok": true,
"traceId": "trace_1",
"defaultModel": "hermes-agent",
"models": [
{ "id": "hermes-agent", "label": "Hermes Agent", "provider": "hermes" }
]
}
```
### `GET /api/hermes/client/tools`
响应:
```json
{
"ok": true,
"traceId": "trace_1",
"tools": [
{ "name": "mnote.page.get", "scope": "page.read", "schemaVersion": "mnote.hermes_tool.v1" }
]
}
```
## 3. 错误响应
统一错误体:
```json
{
"ok": false,
"code": "hermes_client_unconfigured",
"message": "Hermes client proxy 未配置 upstream",
"traceId": "trace_1",
"requestId": "req_1"
}
```
稳定错误码:
- [x] `hermes_client_unauthorized`:未登录或缺少有效 mnote 会话。
- [x] `hermes_client_unconfigured`:未配置 `MNOTE_WEB_HERMES_UPSTREAM_URL`
- [x] `hermes_client_bad_request`:请求 JSON 或必要字段错误。
- [x] `hermes_client_upstream_unauthorized`Hermes upstream 拒绝服务端 token。
- [x] `hermes_client_upstream_rate_limited`Hermes upstream 429。
- [x] `hermes_client_upstream_unavailable`Hermes upstream 连接失败或 5xx。
## 4. 并存期规则
- [x] 新页面 AI 面板只允许请求 `/api/hermes/client/*`
- [x] `/api/ai-agent/run` 保留为 legacy guard,不再承载 Hermes 页面 AI 主链。
- [x] `provider=hermes` 不再通过旧 `/api/ai-agent/run` 表达。
- [x] 所有新 smoke 应断言页面 AI 主链没有 `/api/ai-agent/run` 请求。
@@ -0,0 +1,304 @@
# 7-6 [done] mnote Hermes plugin tool 合同 v1
> 更新时间:2026-05-14
>
> 上位依据:`design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`、`design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md`
>
> Hermes Web UI 参考:`packages/client/src/api/hermes/plugins.ts`、`packages/client/src/api/hermes/skills.ts`、`packages/server/src/services/hermes/plugins.ts`、`packages/server/src/services/hermes/chat-run-socket.ts`
## 1. 总边界
- [x] Hermes 看到的工具名必须是 `mnote.*`,不是 `mnote-cli`、Next route 或前端私有函数。
- [x] plugin 内部可以临时调用 `mnote-cli` JSON adapter,但这只是内部 adapter,不是长期 tool 名称。
- [x] Hermes plugin 不直接写 Convex;所有写入必须回到 Rust runtime / kernel。
- [x] mnote 只保存业务事实、audit、artifact、edge、page/body/title/options 结果,不保存 Hermes 聊天历史。
- [x] 所有 tool call 必须携带 `sessionId/runId/toolCallId/traceId` 便于串联 Hermes run 与 Rust command。
## 2. 统一入参
```json
{
"toolName": "mnote.page.get",
"workspaceId": "ws_1",
"documentId": "doc_1",
"actorId": "user_1",
"sessionId": "mnote_doc_1_trace_1",
"runId": "run_123",
"toolCallId": "call_123",
"traceId": "trace_1",
"idempotencyKey": "idem_123",
"dryRun": false,
"capabilityScope": ["page.read"],
"args": {}
}
```
## 3. 统一出参
```json
{
"ok": true,
"toolName": "mnote.page.get",
"toolCallId": "call_123",
"traceId": "trace_1",
"result": {},
"audit": {
"effect": "read",
"commandId": null,
"workspaceId": "ws_1",
"documentId": "doc_1"
},
"error": null
}
```
失败:
```json
{
"ok": false,
"toolName": "mnote.page.save",
"toolCallId": "call_123",
"traceId": "trace_1",
"result": null,
"audit": {
"effect": "none",
"workspaceId": "ws_1",
"documentId": "doc_1"
},
"error": {
"code": "mnote_tool_permission_denied",
"message": "当前用户没有页面写权限"
}
}
```
## 4. 第一批工具 schema
### `mnote.page.get`
入参:
```json
{
"type": "object",
"required": ["workspaceId", "documentId", "sessionId", "runId", "toolCallId", "traceId"],
"properties": {
"workspaceId": { "type": "string" },
"documentId": { "type": "string" },
"includeBody": { "type": "boolean", "default": true },
"includeOptions": { "type": "boolean", "default": true },
"includeBlocks": { "type": "boolean", "default": true }
}
}
```
成功:
```json
{
"ok": true,
"toolName": "mnote.page.get",
"toolCallId": "call_get_1",
"traceId": "trace_1",
"result": {
"documentId": "doc_1",
"workspaceId": "ws_1",
"title": "项目计划",
"bodySummary": "第一段...",
"pageOptions": { "wideLayout": true },
"blocks": [{ "id": "heading_1", "type": "heading", "text": "章节一" }]
},
"audit": { "effect": "read", "commandId": null }
}
```
失败:
```json
{
"ok": false,
"toolName": "mnote.page.get",
"toolCallId": "call_get_1",
"traceId": "trace_1",
"error": { "code": "mnote_tool_permission_denied", "message": "无页面读取权限" }
}
```
### `mnote.page.save`
入参:
```json
{
"type": "object",
"required": ["workspaceId", "documentId", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun", "content"],
"properties": {
"workspaceId": { "type": "string" },
"documentId": { "type": "string" },
"content": { "type": "array" },
"mode": { "type": "string", "enum": ["replace", "append"] },
"idempotencyKey": { "type": "string" },
"dryRun": { "type": "boolean" }
}
}
```
成功:
```json
{
"ok": true,
"toolName": "mnote.page.save",
"toolCallId": "call_save_1",
"traceId": "trace_1",
"result": { "commandName": "page.body.save", "revision": 8 },
"audit": { "effect": "write", "commandId": "page_body_save_trace_1" }
}
```
dryRun
```json
{
"ok": true,
"toolName": "mnote.page.save",
"toolCallId": "call_save_1",
"traceId": "trace_1",
"result": { "dryRun": true, "diff": [{ "op": "append", "blocks": 1 }] },
"audit": { "effect": "dry_run", "commandId": null }
}
```
权限失败:
```json
{
"ok": false,
"toolName": "mnote.page.save",
"toolCallId": "call_save_1",
"traceId": "trace_1",
"error": { "code": "mnote_tool_permission_denied", "message": "无页面写权限" }
}
```
业务失败:
```json
{
"ok": false,
"toolName": "mnote.page.save",
"toolCallId": "call_save_1",
"traceId": "trace_1",
"error": { "code": "mnote_tool_conflict", "message": "页面版本冲突,需要刷新后重试" }
}
```
### `mnote.page.update_title`
入参:
```json
{
"type": "object",
"required": ["workspaceId", "documentId", "title", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun"],
"properties": {
"workspaceId": { "type": "string" },
"documentId": { "type": "string" },
"title": { "type": "string", "minLength": 1 },
"idempotencyKey": { "type": "string" },
"dryRun": { "type": "boolean" }
}
}
```
成功、dryRun、权限失败、业务失败响应形状同 `mnote.page.save`,成功 command 为 `page.head.updateTitle`
### `mnote.page.update_options`
入参:
```json
{
"type": "object",
"required": ["workspaceId", "documentId", "options", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun"],
"properties": {
"workspaceId": { "type": "string" },
"documentId": { "type": "string" },
"options": {
"type": "object",
"properties": {
"wideLayout": { "type": "boolean" },
"smallText": { "type": "boolean" },
"showToc": { "type": "boolean" },
"protectEditing": { "type": "boolean" }
},
"additionalProperties": false
},
"idempotencyKey": { "type": "string" },
"dryRun": { "type": "boolean" }
}
}
```
成功、dryRun、权限失败、业务失败响应形状同 `mnote.page.save`,成功 command 为 `page.layout.updateOptions``runtimeSupport !== "wired"` 的字段必须返回 dryRun 警告或业务失败。
### `mnote.artifact.create_summary`
入参:
```json
{
"type": "object",
"required": ["workspaceId", "documentId", "summary", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun"],
"properties": {
"workspaceId": { "type": "string" },
"documentId": { "type": "string" },
"summary": { "type": "string" },
"idempotencyKey": { "type": "string" },
"dryRun": { "type": "boolean" }
}
}
```
成功:创建或更新当前页面唯一 summary node,并创建或确认 reference edge。
失败示例:
```json
{
"ok": false,
"toolName": "mnote.artifact.create_summary",
"toolCallId": "call_summary_1",
"traceId": "trace_1",
"error": { "code": "mnote_tool_idempotency_conflict", "message": "同一幂等键已用于不同 summary 内容" }
}
```
### `mnote.artifact.create_ai_note`
入参:
```json
{
"type": "object",
"required": ["workspaceId", "documentId", "content", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun"],
"properties": {
"workspaceId": { "type": "string" },
"documentId": { "type": "string" },
"content": { "type": "string" },
"idempotencyKey": { "type": "string" },
"dryRun": { "type": "boolean" }
}
}
```
成功:每次创建独立 ai_note node,并创建 reference edge。
## 5. 权限、幂等与 dryRun
- [x] 权限校验点:登录、workspace member、页面读、页面写、artifact 写。
- [x] 同一 `idempotencyKey` 重试不得重复创建 artifact 或重复写正文。
- [x] `dryRun=true` 只能返回计划和 diff,不得写入。
- [x] 所有失败响应不得泄露无权限页面标题、正文或 artifact 内容。
- [x] 写工具返回的 `audit.commandId` 必须能追踪到 Rust runtime / kernel command。
@@ -0,0 +1,277 @@
# 7-7 [process] 页面 AI Mini Hermes 控制面设计与执行 checklist v1
> 更新时间:2026-05-14
>
> 当前状态:`PROCESS`。当前实现已经可以通过 Hermes 返回回复,并已完成 `7-4` 的 session/run/tool/writeback/audit 主链;本稿只承接下一阶段体验与设置面的收口。
>
> 上位依据:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md`
---
## 1. 方向判断
当前截图和实现状态说明:页面 AI 已经能回复,但它还更像“能发消息的 Hermes run 面板”,缺少用户自然期待的 Hermes 运行态控制与设置入口。
下一阶段不要把 mnote 做成第二个 Hermes 管理台,也不要把 Hermes 的 Settings / Profiles / Usage / Logs 全部搬进页面抽屉。正确方向是:
> **页面 AI 面板成为 Mini Hermes control surface:只展示和当前 mnote 页面会话直接相关的 session、run、model、profile、tool、context scope 与错误恢复;所有全局配置真相仍归 Hermes。**
边界继续保持:
- Hermes 持有 session/message/tool event/usage/model/profile 真相。
- mnote 只持有页面、树、正文、artifact、edge、Page Aggregate 和 audit 真相。
- 页面 AI 面板只调用 Hermes,不保存聊天历史,不维护 provider/API key,不重建 plugin registry。
- 需要深层设置时跳转或 deep link 到 Hermes 自己的设置页。
---
## 2. Hermes Web UI 参考索引
参考根目录固定为:
```text
/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18
```
只参考下表列出的具体位置。目标是复用 Hermes 的语义与行为边界,仍然用 Leptos 实现 mnote 页面内面板。
| mnote 下一步任务 | 参考文件 | 搜索点 / 具体位置 | 参考目的 | 不采用内容 |
| --- | --- | --- | --- | --- |
| run 发起、恢复和事件语义 | `packages/client/src/api/hermes/chat.ts` | `StartRunRequest``RunEvent``registerSessionHandlers``resumeSession``startRunViaSocket` | 对齐 run 创建、session room 恢复、事件类型和浏览器端分发语义 | 不直接复用 Vue/TS client,不让浏览器绕过 mnote-web proxy |
| 前端消息归并 | `packages/client/src/stores/hermes/chat.ts` | `mapHermesMessages``case 'tool.started'``case 'tool.completed'``refreshActiveSession``switchSession` | 对齐 message/tool event 在前端归并成消息列表的规则 | 不把归并结果保存到 mnote local/session storage 作为真相 |
| 面板分层 | `packages/client/src/components/hermes/chat/ChatPanel.vue` | `activeSessionTitle``showSessions``handleNewChat``MessageList``ChatInput``SessionListItem` | 对齐 session list / message list / input 的最小层次 | 不复制 Hermes 全屏布局、Vue 组件结构或 Naive UI |
| tool 消息展示 | `packages/client/src/components/hermes/chat/MessageItem.vue` | `message.role === 'tool'``formatToolPayload``tool-preview``tool-details``tool-error-badge` | 对齐 tool 结果默认折叠、摘要、错误 badge、详情展开 | 不把 tool result 当正文写入,不扩大为审计详情管理台 |
| session 列表项 | `packages/client/src/components/hermes/chat/SessionListItem.vue` | `session-item-title``session.title``session-item-model` | 对齐 session 标题、模型和时间的展示语义 | 不把 Hermes session title 同步为 mnote page title |
| model 选择展示 | `packages/client/src/components/layout/ModelSelector.vue` | `selectedDisplayName``handleSelect``model-name``model-item` | 对齐模型显示名称、选择行为和禁用态 | 不在 mnote 保存 model/provider/API key 真相 |
| run 生命周期与持久化 | `packages/server/src/services/hermes/chat-run-socket.ts` | `handleRun``emit``applyResponseStreamEvent``flushResponseRunToDb``markCompleted` | 对齐 queued/running/tool_calling/completed/failed 与 flush 到 Hermes DB 的时机 | 不在 mnote 里重写 Hermes 编排器 |
| session 存储真相 | `packages/server/src/db/hermes/session-store.ts` | `HermesSessionRow``HermesMessageRow``getSessionDetail``addMessage``renameSession` | 明确 session/message/tool call 真相字段来自 Hermes | 不在 mnote 建第二份 chat/session 表 |
| plugin/tool 发现 | `packages/server/src/services/hermes/plugins.ts` | `PluginManager``providesTools``listHermesPlugins``requiresEnv` | 对齐 mnote tools 作为 Hermes plugin/tool registry 的一部分被发现 | 不把 mnote-web 私有 route 当成最终 plugin registry |
| skill/plugin API 外观 | `packages/client/src/api/hermes/plugins.ts``packages/client/src/api/hermes/skills.ts` | `list``get``enable``disable` 类方法 | 仅用于面板显示 mnote plugin/tool 可用性和缺失状态 | 不实现完整 Hermes plugin/skill 管理页 |
| 不进入 mnote 面板第一阶段 | `packages/client/src/views/hermes/SettingsView.vue``ProfilesView.vue``UsageView.vue``LogsView.vue``JobsView.vue``FilesView.vue``ChannelsView.vue``TerminalView.vue``GroupChatView.vue` | 页面级管理视图入口 | 用来明确边界:这些属于 Hermes 管理台 | 不搬进 mnote 页面 AI 抽屉 |
快速定位命令:
```bash
cd /mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18
rg -n "StartRunRequest|RunEvent|registerSessionHandlers|resumeSession|startRunViaSocket|mapHermesMessages|tool\\.started|tool\\.completed|activeSessionTitle|formatToolPayload|selectedDisplayName|handleRun|flushResponseRunToDb|PluginManager|providesTools" packages/client/src packages/server/src
```
---
## 3. 产品边界
### 3.1 必须进入 mnote 页面 AI 面板
- 当前 Hermes session 标题、session id、模型名、profile 名和恢复状态。
- 当前 run 状态:`idle``queued``running``tool_calling``completed``failed``aborted`
- 当前页面上下文范围:当前页、当前选区、当前块、全文、页面设置。
- 当前 mnote tools 可用性:`mnote.page.get``mnote.page.save``mnote.page.update_title``mnote.page.update_options``mnote.artifact.create_summary``mnote.artifact.create_ai_note`
- 最近 tool call 摘要、参数摘要、结果摘要、失败原因和 trace/audit id。
- 停止、重试、继续、重新读取当前页上下文的最小操作。
- 跳转 Hermes 设置的入口,说明缺失项应在 Hermes 中配置。
### 3.2 不进入 mnote 页面 AI 面板
- provider/API key 密钥管理。
- 全局 profile 创建、删除、复杂编辑。
- Hermes plugin marketplace / skill marketplace 管理。
- usage 报表、日志中心、任务中心、文件中心、频道、终端、群聊。
- Hermes session 数据库迁移、导入导出、conversation 管理台。
- 独立 mnote 聊天历史存储。
### 3.3 可选但不阻塞第一阶段
- 当前页面最近 sessions 搜索。
- session 重命名与删除。
- profile/model 下拉切换。
- tool event JSON 详情复制。
- session deep link 到 Hermes 管理台。
---
## 4. 目标信息架构
页面 AI 抽屉保持 Wolai 对齐后的壳层,内部按四层组织:
1. 顶部状态条:session 标题、模型/profile、连接状态、设置跳转。
2. 消息区:Hermes message list、streaming 回复、tool event 折叠项。
3. 上下文与工具条:当前 context scope、可用 mnote tools、最近 audit/trace。
4. 输入区:prompt 输入、发送、停止、重试、继续。
验收时不要只看 DOM,应以截图和交互为准:
- 顶部状态在窄屏不挤压输入区。
- tool event 折叠项不会撑破抽屉宽度。
- 失败态能看到可执行动作,不只是一段错误文本。
- 设置入口不会暗示 mnote 自己持有 API key。
---
## 5. 数据与 API 边界
### 5.1 mnote-web proxy 需要补齐的读接口
- `GET /api/hermes/client/session/current?documentId=...`
- `GET /api/hermes/client/sessions?documentId=...&limit=...`
- `GET /api/hermes/client/session/:sessionId`
- `GET /api/hermes/client/models`
- `GET /api/hermes/client/tools?scope=mnote`
- `GET /api/hermes/client/runtime/status`
这些接口只透传或规整 Hermes 状态,不在 mnote 保存真相。
### 5.2 mnote-web proxy 需要补齐的操作接口
- `POST /api/hermes/client/run`
- `POST /api/hermes/client/run/:runId/stop`
- `POST /api/hermes/client/run/:runId/retry`
- `POST /api/hermes/client/session/:sessionId/resume`
- `POST /api/hermes/client/session/:sessionId/rename`
- `DELETE /api/hermes/client/session/:sessionId`
第一阶段可以只完成 `run/stop/resume``retry/rename/delete` 可以排到 P2,但 UI 文案不能让用户误以为已经支持。
### 5.3 mnote tool manifest
页面 AI 面板展示 tool 可用性时应优先从 Hermes plugin/tool registry 来,而不是硬编码前端列表。允许 mnote-web 在过渡期提供同源聚合:
- tool name
- description
- read/write 分类
- required scope
- permission 状态
- last call summary
- last audit id
- unavailable reason
---
## 6. 顺序执行 checklist
### A. 设计与现状审计
- [ ] A1. 打开当前 `3000` 页面 AI 抽屉,记录“能回复但缺设置/运行态控制”的截图到 `tmp/`
- 验收标准:截图能看到回复链路、顶部或设置区域缺失点、当前 session/run 状态展示缺口。
- [ ] A2. 用 `rg` 确认活跃设计稿中页面 AI 主线已经指向 Hermes session/run/events。
- 验收标准:`design/07-ai/process` 只剩本 `7-7` 作为 AI 活跃稿;`7-2``7-6` 位于 `done/`
- [ ] A3. 对照 Hermes Web UI 参考索引打开精确文件,不整目录通读。
- 验收标准:实现任务说明中写明参考了哪个 `packages/...` 文件和哪个搜索点。
### B. 面板状态模型
- [ ] B1. 定义 Leptos 侧 `HermesPanelState`
- 验收标准:状态至少包含 `sessionId``sessionTitle``modelName``profileName``runStatus``connectionStatus``contextScope``toolAvailability``lastAudit`
- [ ] B2. 明确哪些字段来自 Hermes,哪些字段来自 mnote。
- 验收标准:session/message/model/profile/run/tool event 来自 Hermespage title/context/audit 来自 mnote;没有字段把 Hermes session title 当作页面标题。
- [ ] B3. 增加空态、连接失败态、tool 不可用态。
- 验收标准:Hermes 未启动、未配置模型、mnote plugin 缺失、权限不足分别有不同 UI 状态。
### C. 顶部 Mini Hermes 状态条
- [ ] C1. 展示当前 session 标题和恢复状态。
- 验收标准:刷新页面后能从 Hermes session detail 恢复标题和消息,不从 mnote 本地 state 恢复聊天真相。
- [ ] C2. 展示 model/profile 摘要。
- 验收标准:能看到当前模型与 profile;缺失时显示“去 Hermes 配置”的动作,而不是在 mnote 内要求填写 API key。
- [ ] C3. 增加设置跳转入口。
- 验收标准:入口跳到 Hermes 设置或 profile 页面;mnote 页面内不出现 provider/API key 编辑表单。
### D. Run 控制与恢复
- [ ] D1. 显示 run 状态。
- 验收标准:发送后能依次看到 running/tool_calling/completed 或 failed;状态来自 Hermes run event。
- [ ] D2. 支持停止当前 run。
- 验收标准:点击停止后 Hermes run 进入 aborted/failed 的明确终止态,输入框恢复可用。
- [ ] D3. 支持失败后重试或继续。
- 验收标准:失败态有明确按钮;重试不会创建 mnote 本地聊天副本。
- [ ] D4. 刷新后恢复进行中或已完成 session。
- 验收标准:刷新页面不丢失 Hermes 消息;若 run 已结束,状态显示 completed/failed 而不是一直 loading。
### E. Context Scope
- [ ] E1. 增加 context scope 控件。
- 验收标准:至少支持当前页、当前选区、当前块、页面设置四类;无选区时选区项禁用。
- [ ] E2. run input 只携带当前 scope 的上下文摘要。
- 验收标准:正文大对象不长期写进 Hermes sessionHermes 需要最新正文时通过 `mnote.page.get` 回读。
- [ ] E3. tool call audit 记录 context scope。
- 验收标准:`mnote.page.save`、artifact 写入等 audit 能看到本次来源是 page/selection/block/options 哪种 scope。
### F. Tool 可用性与最近调用
- [ ] F1. 展示 mnote tools 清单。
- 验收标准:清单来源于 Hermes plugin/tool registry 或 mnote-web 过渡聚合,不能只写死在前端。
- [ ] F2. 区分只读工具和写入工具。
- 验收标准:`mnote.page.get` 明确为只读;`mnote.page.save``mnote.page.update_title``mnote.artifact.*` 明确为写入。
- [ ] F3. tool event 默认折叠,支持展开详情。
- 验收标准:交互参考 `MessageItem.vue``tool-preview` / `tool-details`,但使用 Leptos 实现;长 JSON 不撑破布局。
- [ ] F4. 最近 tool call 关联 audit。
- 验收标准:能从 UI 或测试输出看到 `sessionId/runId/toolCallId/traceId/auditId` 的串联。
### G. Session 列表最小面
- [ ] G1. 支持当前页面最近 Hermes sessions 列表。
- 验收标准:列表来自 Hermes session API;只过滤/标注当前 document context,不复制 session 到 mnote。
- [ ] G2. 支持切换 session。
- 验收标准:切换后 message list 从 Hermes detail 恢复;页面正文不因切换 session 被自动修改。
- [ ] G3. P2 支持 rename/delete/search。
- 验收标准:若未实现,UI 不出现可点击假按钮;若实现,操作调用 Hermes session API。
### H. 错误与权限
- [ ] H1. Hermes 未启动或 proxy 502 时显示可诊断状态。
- 验收标准:错误能区分 upstream unavailable、auth/permission、model missing、tool unavailable。
- [ ] H2. 写入工具权限失败不泄露正文。
- 验收标准:tool error 展示摘要、trace/audit id 和恢复动作,不展示不必要的正文 payload。
- [ ] H3. 旧 `/api/ai-agent/run` 继续保持退场 guard。
- 验收标准:新页面 AI 主链不会调用旧入口;retirement smoke 继续通过。
### I. 自动化验收
- [ ] I1. 新增或扩展 browser smokesession 状态条。
- 验收标准:断言 session title/model/run status 可见。
- [ ] I2. 新增或扩展 browser smokerun stop/retry。
- 验收标准:至少覆盖 stop;retry 若未实现则断言按钮不存在或禁用。
- [ ] I3. 新增或扩展 browser smokecontext scope。
- 验收标准:选区/当前页上下文能进入 run payload 或 tool audit。
- [ ] I4. 新增或扩展 browser smoketool 可用性与 audit。
- 验收标准:能看到 mnote tool 列表、一次 tool call、对应 audit id。
- [ ] I5. 移动端 smoke。
- 验收标准:状态条、tool 折叠、输入区在窄屏不重叠。
---
## 7. Done Gate
本稿移入 `done/` 前必须同时满足:
- [ ] 页面 AI 抽屉具备 Mini Hermes 状态条,用户能看见当前 session、model/profile、run 状态。
- [ ] 页面 AI 抽屉具备 context scope 控件,run input 和 tool audit 能反映 scope。
- [ ] 页面 AI 抽屉能展示 mnote tool 可用性、最近 tool call 和 audit/trace 串联。
- [ ] stop 至少可用;retry/rename/delete 若未实现,必须明确标为 P2 且 UI 不出现假可用按钮。
- [ ] Hermes 未启动、模型缺失、plugin/tool 不可用、权限失败至少四类错误有可区分展示。
- [ ] 页面刷新后仍以 Hermes session detail/resume 为会话真相。
- [ ] mnote 不保存聊天消息真相,不保存 provider/API key,不创建第二套 plugin registry。
- [ ] `git diff --check` 通过。
- [ ] Rust 侧相关测试通过:`cargo test -p mnote-web hermes_client -- --nocapture``cargo test -p mnote-web hermes_tools_ -- --nocapture`
- [ ] 正式 `3000` smoke 覆盖 session/run/tool/audit/mobile,且证据写回本文。
---
## 8. 当前建议的下一步
优先顺序:
1. 先补顶部 Mini Hermes 状态条和错误态,因为这是当前“能回复但缺 Hermes 设置感”的直接缺口。
2. 再补 context scope 和 tool 可用性,让用户明确 Hermes 正在调用 mnote 的哪些能力。
3. 最后补 session 列表、rename/delete/search 等历史管理能力。
不要先做 Hermes 全局设置页复刻。API key、provider、全局 profile、usage/logs/jobs/files/channels 仍应留在 Hermes 自己的管理台。