Files
mnote/design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md
T
2026-05-16 12:34:48 +08:00

307 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`
>
> 2026-05-16 口径补充:本文定义的是页面 AI 最小可用工具合同。`mnote.page.save` 只作为页面级兜底写入工具,不再代表长期精确块编辑方案;页面/块级 AI 工具体系以 `design/07-ai/process/7-9-page-block-ai-tooling-roadmap-v1.md` 为后续规划依据。
## 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。