# 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` 请求。