2026-05-14 15:10:33 +08:00
|
|
|
|
use serde_json::{json, Value};
|
|
|
|
|
|
|
|
|
|
|
|
pub const MANIFEST_SCHEMA_VERSION: &str = "mnote.hermes_tool_manifest.v1";
|
|
|
|
|
|
pub const TOOL_SCHEMA_VERSION: &str = "mnote.hermes_tool.v1";
|
|
|
|
|
|
|
|
|
|
|
|
pub fn manifest() -> Value {
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"schemaVersion": MANIFEST_SCHEMA_VERSION,
|
|
|
|
|
|
"plugin": {
|
|
|
|
|
|
"name": "mnote",
|
|
|
|
|
|
"description": "mnote 页面、树、artifact 与 edge 工具",
|
|
|
|
|
|
"runtimeOwner": "mnote-web",
|
|
|
|
|
|
"writeOwner": "rust-runtime-kernel"
|
|
|
|
|
|
},
|
|
|
|
|
|
"tools": [
|
2026-05-16 22:03:14 +08:00
|
|
|
|
doc_fetch_tool(),
|
|
|
|
|
|
doc_find_tool(),
|
|
|
|
|
|
block_fetch_tool(),
|
|
|
|
|
|
doc_plan_update_tool(),
|
|
|
|
|
|
block_replace_tool(),
|
|
|
|
|
|
block_insert_after_tool(),
|
|
|
|
|
|
block_delete_tool(),
|
|
|
|
|
|
block_move_after_tool(),
|
|
|
|
|
|
doc_apply_block_ops_tool(),
|
2026-05-17 12:58:27 +08:00
|
|
|
|
doc_markdown_edit_tool(),
|
2026-05-14 15:10:33 +08:00
|
|
|
|
page_get_tool(),
|
2026-05-16 12:34:48 +08:00
|
|
|
|
page_save_tool(),
|
|
|
|
|
|
available_tool("mnote.page.update_title", "更新当前页面标题", ["page.write"]),
|
|
|
|
|
|
available_tool("mnote.page.update_options", "更新当前页面设置", ["page.write"]),
|
2026-05-19 12:03:43 +08:00
|
|
|
|
mindmap_fetch_tool(),
|
|
|
|
|
|
mindmap_apply_ops_tool(),
|
|
|
|
|
|
office_fetch_summary_tool(),
|
|
|
|
|
|
office_propose_changes_tool(),
|
2026-05-16 12:34:48 +08:00
|
|
|
|
available_tool("mnote.artifact.create_summary", "为当前页面创建或更新 AI Summary", ["artifact.write"]),
|
|
|
|
|
|
available_tool("mnote.artifact.create_ai_note", "基于当前页面创建新的 AI Note", ["artifact.write"])
|
2026-05-14 15:10:33 +08:00
|
|
|
|
]
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-16 22:03:14 +08:00
|
|
|
|
fn base_identity_properties() -> Value {
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"workspaceId": { "type": "string" },
|
|
|
|
|
|
"documentId": { "type": "string" },
|
|
|
|
|
|
"sessionId": { "type": "string" },
|
|
|
|
|
|
"runId": { "type": "string" },
|
|
|
|
|
|
"toolCallId": { "type": "string" },
|
|
|
|
|
|
"traceId": { "type": "string" },
|
|
|
|
|
|
"actorId": { "type": "string" },
|
|
|
|
|
|
"actorType": { "type": "string" }
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn doc_fetch_tool() -> Value {
|
|
|
|
|
|
let mut properties = base_identity_properties();
|
|
|
|
|
|
if let Value::Object(map) = &mut properties {
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"scope".into(),
|
|
|
|
|
|
json!({ "type": "string", "default": "full" }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"detail".into(),
|
|
|
|
|
|
json!({ "type": "string", "default": "with_ids" }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"format".into(),
|
|
|
|
|
|
json!({ "type": "string", "enum": ["json", "markdown", "text", "page_xml"], "default": "json" }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert("blockId".into(), json!({ "type": "string" }));
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"selectedBlockIds".into(),
|
|
|
|
|
|
json!({ "type": "array", "items": { "type": "string" } }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"allowedTargetBlockIds".into(),
|
|
|
|
|
|
json!({ "type": "array", "items": { "type": "string" } }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert("query".into(), json!({ "type": "string" }));
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"maxBlocks".into(),
|
|
|
|
|
|
json!({ "type": "integer", "default": 120 }),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"name": "mnote.doc.fetch",
|
|
|
|
|
|
"description": "读取当前页面的 canonical block projection,支持 full/outline/block/keyword 范围",
|
|
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
|
|
|
|
|
"capabilityScope": ["page.read"],
|
|
|
|
|
|
"status": "available",
|
|
|
|
|
|
"annotations": tool_annotations(true, false, true, false),
|
|
|
|
|
|
"inputSchema": {
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"required": ["workspaceId", "documentId", "sessionId", "runId", "toolCallId", "traceId", "actorId"],
|
|
|
|
|
|
"properties": properties
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn doc_find_tool() -> Value {
|
|
|
|
|
|
let mut properties = base_identity_properties();
|
|
|
|
|
|
if let Value::Object(map) = &mut properties {
|
|
|
|
|
|
map.insert("query".into(), json!({ "type": "string" }));
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"match".into(),
|
|
|
|
|
|
json!({ "type": "string", "default": "text" }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert("limit".into(), json!({ "type": "integer", "default": 20 }));
|
|
|
|
|
|
}
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"name": "mnote.doc.find",
|
|
|
|
|
|
"description": "在 Page Aggregate block projection 中按文本、类型或 blockId 查找块",
|
|
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
|
|
|
|
|
"capabilityScope": ["page.read"],
|
|
|
|
|
|
"status": "available",
|
|
|
|
|
|
"annotations": tool_annotations(true, false, true, false),
|
|
|
|
|
|
"inputSchema": {
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"required": ["workspaceId", "documentId", "sessionId", "runId", "toolCallId", "traceId", "actorId", "query"],
|
|
|
|
|
|
"properties": properties
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn block_fetch_tool() -> Value {
|
|
|
|
|
|
let mut properties = base_identity_properties();
|
|
|
|
|
|
if let Value::Object(map) = &mut properties {
|
|
|
|
|
|
map.insert("blockId".into(), json!({ "type": "string" }));
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"includeChildren".into(),
|
|
|
|
|
|
json!({ "type": "boolean", "default": true }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"contextBefore".into(),
|
|
|
|
|
|
json!({ "type": "integer", "default": 1 }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"contextAfter".into(),
|
|
|
|
|
|
json!({ "type": "integer", "default": 1 }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"format".into(),
|
|
|
|
|
|
json!({ "type": "string", "enum": ["json", "markdown", "text", "page_xml"], "default": "json" }),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"name": "mnote.block.fetch",
|
|
|
|
|
|
"description": "读取单个块及同父级上下文",
|
|
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
|
|
|
|
|
"capabilityScope": ["block.read", "page.read"],
|
|
|
|
|
|
"status": "available",
|
|
|
|
|
|
"annotations": tool_annotations(true, false, true, false),
|
|
|
|
|
|
"inputSchema": {
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"required": ["workspaceId", "documentId", "sessionId", "runId", "toolCallId", "traceId", "actorId", "blockId"],
|
|
|
|
|
|
"properties": properties
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn doc_plan_update_tool() -> Value {
|
|
|
|
|
|
write_tool(
|
|
|
|
|
|
"mnote.doc.plan_update",
|
|
|
|
|
|
"生成页面块更新 dry-run 计划,不直接写入",
|
|
|
|
|
|
["page.write", "block.write"],
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"command": { "type": "string" },
|
|
|
|
|
|
"blockId": { "type": "string" },
|
|
|
|
|
|
"anchorBlockId": { "type": "string" },
|
|
|
|
|
|
"content": { "type": ["string", "object", "array"] },
|
|
|
|
|
|
"query": { "type": "string" },
|
|
|
|
|
|
"revision": { "type": ["number", "string"] },
|
|
|
|
|
|
"conflictDetectionKey": { "type": "string" }
|
|
|
|
|
|
}),
|
|
|
|
|
|
[],
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn block_replace_tool() -> Value {
|
|
|
|
|
|
write_tool(
|
|
|
|
|
|
"mnote.block.replace",
|
2026-05-19 08:07:17 +08:00
|
|
|
|
"兼容块写工具:替换指定块内容;本地 Markdown 普通编辑优先使用 agent 原生 patch/diff,必要时再走 Rust page.body.write 兼容链路",
|
2026-05-16 22:03:14 +08:00
|
|
|
|
["block.write", "page.write"],
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"blockId": { "type": "string" },
|
|
|
|
|
|
"content": { "type": ["string", "object", "array"] },
|
|
|
|
|
|
"revision": { "type": ["number", "string"] },
|
|
|
|
|
|
"conflictDetectionKey": { "type": "string" },
|
2026-05-18 17:01:35 +08:00
|
|
|
|
"blockRevisionRef": { "type": "string" },
|
|
|
|
|
|
"allowedTargetBlockIds": {
|
|
|
|
|
|
"type": "array",
|
|
|
|
|
|
"items": { "type": "string" }
|
|
|
|
|
|
}
|
2026-05-16 22:03:14 +08:00
|
|
|
|
}),
|
|
|
|
|
|
[
|
|
|
|
|
|
"blockId",
|
|
|
|
|
|
"content",
|
|
|
|
|
|
"revision",
|
|
|
|
|
|
"conflictDetectionKey",
|
|
|
|
|
|
"blockRevisionRef",
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn block_insert_after_tool() -> Value {
|
2026-05-18 17:01:35 +08:00
|
|
|
|
let mut tool = write_tool(
|
2026-05-16 22:03:14 +08:00
|
|
|
|
"mnote.block.insert_after",
|
|
|
|
|
|
"在指定块后插入新块;真实写入走 Rust page.body.save 链路",
|
|
|
|
|
|
["block.write", "page.write"],
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"anchorBlockId": { "type": "string" },
|
|
|
|
|
|
"content": { "type": ["string", "object", "array"] },
|
|
|
|
|
|
"block": { "type": "object" },
|
2026-05-18 17:01:35 +08:00
|
|
|
|
"blocks": {
|
|
|
|
|
|
"type": "array",
|
|
|
|
|
|
"minItems": 1,
|
|
|
|
|
|
"maxItems": 20,
|
|
|
|
|
|
"items": { "type": ["string", "object", "array"] }
|
|
|
|
|
|
},
|
2026-05-16 22:03:14 +08:00
|
|
|
|
"revision": { "type": ["number", "string"] },
|
|
|
|
|
|
"conflictDetectionKey": { "type": "string" },
|
2026-05-18 17:01:35 +08:00
|
|
|
|
"anchorRevisionRef": { "type": "string" },
|
|
|
|
|
|
"allowedTargetBlockIds": {
|
|
|
|
|
|
"type": "array",
|
|
|
|
|
|
"items": { "type": "string" }
|
|
|
|
|
|
}
|
2026-05-16 22:03:14 +08:00
|
|
|
|
}),
|
|
|
|
|
|
[
|
|
|
|
|
|
"anchorBlockId",
|
|
|
|
|
|
"revision",
|
|
|
|
|
|
"conflictDetectionKey",
|
|
|
|
|
|
"anchorRevisionRef",
|
|
|
|
|
|
],
|
2026-05-18 17:01:35 +08:00
|
|
|
|
);
|
|
|
|
|
|
if let Some(schema) = tool.get_mut("inputSchema").and_then(Value::as_object_mut) {
|
|
|
|
|
|
schema.insert(
|
|
|
|
|
|
"anyOf".into(),
|
|
|
|
|
|
json!([
|
|
|
|
|
|
{ "required": ["content"] },
|
|
|
|
|
|
{ "required": ["block"] },
|
|
|
|
|
|
{ "required": ["blocks"] }
|
|
|
|
|
|
]),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
tool
|
2026-05-16 22:03:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn block_move_after_tool() -> Value {
|
|
|
|
|
|
write_tool(
|
|
|
|
|
|
"mnote.block.move_after",
|
|
|
|
|
|
"受限同父级普通叶子块移动;真实写入走 Rust page.body.save 链路",
|
|
|
|
|
|
["block.write", "page.write"],
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"blockId": { "type": "string" },
|
|
|
|
|
|
"anchorBlockId": { "type": "string" },
|
|
|
|
|
|
"revision": { "type": ["number", "string"] },
|
|
|
|
|
|
"conflictDetectionKey": { "type": "string" },
|
|
|
|
|
|
"blockRevisionRef": { "type": "string" },
|
2026-05-18 17:01:35 +08:00
|
|
|
|
"anchorRevisionRef": { "type": "string" },
|
|
|
|
|
|
"allowedTargetBlockIds": {
|
|
|
|
|
|
"type": "array",
|
|
|
|
|
|
"items": { "type": "string" }
|
|
|
|
|
|
}
|
2026-05-16 22:03:14 +08:00
|
|
|
|
}),
|
|
|
|
|
|
[
|
|
|
|
|
|
"blockId",
|
|
|
|
|
|
"anchorBlockId",
|
|
|
|
|
|
"revision",
|
|
|
|
|
|
"conflictDetectionKey",
|
|
|
|
|
|
"blockRevisionRef",
|
|
|
|
|
|
"anchorRevisionRef",
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn block_delete_tool() -> Value {
|
|
|
|
|
|
write_tool(
|
|
|
|
|
|
"mnote.block.delete",
|
|
|
|
|
|
"删除指定无子块普通块;真实写入走 Rust page.body.save 链路",
|
|
|
|
|
|
["block.write", "page.write"],
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"blockId": { "type": "string" },
|
|
|
|
|
|
"revision": { "type": ["number", "string"] },
|
|
|
|
|
|
"conflictDetectionKey": { "type": "string" },
|
2026-05-18 17:01:35 +08:00
|
|
|
|
"blockRevisionRef": { "type": "string" },
|
|
|
|
|
|
"allowedTargetBlockIds": {
|
|
|
|
|
|
"type": "array",
|
|
|
|
|
|
"items": { "type": "string" }
|
|
|
|
|
|
}
|
2026-05-16 22:03:14 +08:00
|
|
|
|
}),
|
|
|
|
|
|
[
|
|
|
|
|
|
"blockId",
|
|
|
|
|
|
"revision",
|
|
|
|
|
|
"conflictDetectionKey",
|
|
|
|
|
|
"blockRevisionRef",
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn doc_apply_block_ops_tool() -> Value {
|
|
|
|
|
|
write_tool(
|
|
|
|
|
|
"mnote.doc.apply_block_ops",
|
|
|
|
|
|
"一次性应用多个块级操作;Rust 侧统一读取最新 projection、生成 canonical content 并一次保存,适合页面 AI 小段落增删改移动快路径",
|
|
|
|
|
|
["block.write", "page.write"],
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"operations": {
|
|
|
|
|
|
"type": "array",
|
|
|
|
|
|
"items": {
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"properties": {
|
|
|
|
|
|
"op": { "type": "string" },
|
|
|
|
|
|
"blockId": { "type": "string" },
|
|
|
|
|
|
"anchorBlockId": { "type": "string" },
|
|
|
|
|
|
"matchText": { "type": "string" },
|
|
|
|
|
|
"anchorText": { "type": "string" },
|
|
|
|
|
|
"afterText": { "type": "string" },
|
|
|
|
|
|
"allowedTargetBlockIds": {
|
|
|
|
|
|
"type": "array",
|
|
|
|
|
|
"items": { "type": "string" }
|
|
|
|
|
|
},
|
|
|
|
|
|
"content": { "type": ["string", "object", "array"] }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}),
|
|
|
|
|
|
["operations"],
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn write_tool(
|
|
|
|
|
|
name: &str,
|
|
|
|
|
|
description: &str,
|
|
|
|
|
|
scope: impl IntoIterator<Item = &'static str>,
|
|
|
|
|
|
extra_properties: Value,
|
|
|
|
|
|
extra_required: impl IntoIterator<Item = &'static str>,
|
|
|
|
|
|
) -> Value {
|
|
|
|
|
|
let mut properties = base_identity_properties();
|
|
|
|
|
|
if let Value::Object(map) = &mut properties {
|
|
|
|
|
|
map.insert("dryRun".into(), json!({ "type": "boolean" }));
|
|
|
|
|
|
map.insert("idempotencyKey".into(), json!({ "type": "string" }));
|
|
|
|
|
|
if let Value::Object(extra) = extra_properties {
|
|
|
|
|
|
for (key, value) in extra {
|
|
|
|
|
|
map.insert(key, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
let mut required = vec![
|
|
|
|
|
|
"workspaceId",
|
|
|
|
|
|
"documentId",
|
|
|
|
|
|
"sessionId",
|
|
|
|
|
|
"runId",
|
|
|
|
|
|
"toolCallId",
|
|
|
|
|
|
"traceId",
|
|
|
|
|
|
"actorId",
|
|
|
|
|
|
"dryRun",
|
|
|
|
|
|
"idempotencyKey",
|
|
|
|
|
|
];
|
|
|
|
|
|
required.extend(extra_required);
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"name": name,
|
|
|
|
|
|
"description": description,
|
|
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
|
|
|
|
|
"capabilityScope": scope.into_iter().collect::<Vec<_>>(),
|
|
|
|
|
|
"status": "available",
|
|
|
|
|
|
"annotations": tool_annotations(false, false, false, false),
|
|
|
|
|
|
"inputSchema": {
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"required": required,
|
|
|
|
|
|
"properties": properties
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-14 15:10:33 +08:00
|
|
|
|
fn page_get_tool() -> Value {
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"name": "mnote.page.get",
|
|
|
|
|
|
"description": "读取当前页面 Page Aggregate 摘要",
|
|
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
|
|
|
|
|
"capabilityScope": ["page.read"],
|
|
|
|
|
|
"inputSchema": {
|
|
|
|
|
|
"type": "object",
|
2026-05-16 22:03:14 +08:00
|
|
|
|
"required": ["workspaceId", "documentId", "sessionId", "runId", "toolCallId", "traceId", "actorId"],
|
2026-05-14 15:10:33 +08:00
|
|
|
|
"properties": {
|
|
|
|
|
|
"workspaceId": { "type": "string" },
|
|
|
|
|
|
"documentId": { "type": "string" },
|
|
|
|
|
|
"sessionId": { "type": "string" },
|
|
|
|
|
|
"runId": { "type": "string" },
|
|
|
|
|
|
"toolCallId": { "type": "string" },
|
|
|
|
|
|
"traceId": { "type": "string" },
|
2026-05-16 22:03:14 +08:00
|
|
|
|
"actorId": { "type": "string" },
|
|
|
|
|
|
"actorType": { "type": "string" },
|
2026-05-14 15:10:33 +08:00
|
|
|
|
"includeBody": { "type": "boolean", "default": true },
|
|
|
|
|
|
"includeOptions": { "type": "boolean", "default": true },
|
|
|
|
|
|
"includeBlocks": { "type": "boolean", "default": true }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-16 12:34:48 +08:00
|
|
|
|
fn page_save_tool() -> Value {
|
2026-05-14 15:10:33 +08:00
|
|
|
|
json!({
|
2026-05-16 12:34:48 +08:00
|
|
|
|
"name": "mnote.page.save",
|
2026-05-19 08:07:17 +08:00
|
|
|
|
"description": "粗粒度兼容兜底:保存当前页面正文;本地 Markdown 普通编辑优先使用 agent 原生 patch/diff,只有整页覆盖/追加且其它工具无法表达时使用",
|
2026-05-14 15:10:33 +08:00
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
2026-05-16 12:34:48 +08:00
|
|
|
|
"capabilityScope": ["page.write"],
|
|
|
|
|
|
"status": "available",
|
2026-05-16 22:03:14 +08:00
|
|
|
|
"annotations": tool_annotations(false, true, false, false),
|
2026-05-16 12:34:48 +08:00
|
|
|
|
"inputSchema": {
|
|
|
|
|
|
"type": "object",
|
2026-05-16 22:03:14 +08:00
|
|
|
|
"required": ["workspaceId", "documentId", "sessionId", "runId", "toolCallId", "traceId", "actorId", "content", "dryRun", "idempotencyKey"],
|
2026-05-16 12:34:48 +08:00
|
|
|
|
"properties": {
|
|
|
|
|
|
"workspaceId": { "type": "string" },
|
|
|
|
|
|
"documentId": { "type": "string" },
|
|
|
|
|
|
"sessionId": { "type": "string" },
|
|
|
|
|
|
"runId": { "type": "string" },
|
|
|
|
|
|
"toolCallId": { "type": "string" },
|
|
|
|
|
|
"traceId": { "type": "string" },
|
2026-05-16 22:03:14 +08:00
|
|
|
|
"actorId": { "type": "string" },
|
|
|
|
|
|
"actorType": { "type": "string" },
|
2026-05-16 12:34:48 +08:00
|
|
|
|
"content": {
|
|
|
|
|
|
"description": "要写入的正文块数组、{blocks:[...]}、TipTap content 数组或纯文本",
|
|
|
|
|
|
"type": ["array", "object", "string"]
|
|
|
|
|
|
},
|
|
|
|
|
|
"mode": {
|
|
|
|
|
|
"type": "string",
|
|
|
|
|
|
"enum": ["replace", "append", "prepend"],
|
|
|
|
|
|
"default": "replace"
|
|
|
|
|
|
},
|
|
|
|
|
|
"dryRun": { "type": "boolean" },
|
|
|
|
|
|
"idempotencyKey": { "type": "string" }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn available_tool(
|
|
|
|
|
|
name: &str,
|
|
|
|
|
|
description: &str,
|
|
|
|
|
|
scope: impl IntoIterator<Item = &'static str>,
|
|
|
|
|
|
) -> Value {
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"name": name,
|
|
|
|
|
|
"description": description,
|
|
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
2026-05-14 15:10:33 +08:00
|
|
|
|
"capabilityScope": scope.into_iter().collect::<Vec<_>>(),
|
2026-05-16 22:03:14 +08:00
|
|
|
|
"status": "available",
|
|
|
|
|
|
"annotations": tool_annotations(false, false, false, false)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-17 12:58:27 +08:00
|
|
|
|
fn doc_markdown_edit_tool() -> Value {
|
2026-05-18 17:01:35 +08:00
|
|
|
|
let mut tool = write_tool(
|
|
|
|
|
|
"mnote.doc.markdown_edit",
|
2026-05-19 08:07:17 +08:00
|
|
|
|
"兼容 / 远端代理 fallback:通过文本级搜索替换编辑 markdown 内容。local-first 本地 workspace 默认优先让 agent 原生 patch/diff 直接编辑授权文件;仅在需要 MNote 兼容工具、远端代理或结构校验时使用。",
|
2026-05-18 17:01:35 +08:00
|
|
|
|
["block.write", "page.write"],
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"operations": {
|
2026-05-17 12:58:27 +08:00
|
|
|
|
"type": "array",
|
|
|
|
|
|
"description": "搜索替换操作列表",
|
|
|
|
|
|
"items": {
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"properties": {
|
|
|
|
|
|
"search": { "type": "string", "description": "要搜索的原文片段" },
|
|
|
|
|
|
"replace": { "type": "string", "description": "替换后的新文本" }
|
|
|
|
|
|
},
|
|
|
|
|
|
"required": ["search", "replace"]
|
|
|
|
|
|
}
|
2026-05-18 17:01:35 +08:00
|
|
|
|
},
|
|
|
|
|
|
"full_content": {
|
2026-05-17 12:58:27 +08:00
|
|
|
|
"type": "string",
|
|
|
|
|
|
"description": "完整修改后的 markdown 文本(替代 operations)"
|
2026-05-18 17:01:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}),
|
|
|
|
|
|
[],
|
|
|
|
|
|
);
|
|
|
|
|
|
if let Some(schema) = tool.get_mut("inputSchema").and_then(Value::as_object_mut) {
|
|
|
|
|
|
schema.insert(
|
|
|
|
|
|
"anyOf".into(),
|
|
|
|
|
|
json!([
|
|
|
|
|
|
{ "required": ["operations"] },
|
|
|
|
|
|
{ "required": ["full_content"] }
|
|
|
|
|
|
]),
|
2026-05-17 12:58:27 +08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
2026-05-18 17:01:35 +08:00
|
|
|
|
tool
|
2026-05-17 12:58:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-19 12:03:43 +08:00
|
|
|
|
fn resource_identity_properties(resource_id_name: &str) -> Value {
|
|
|
|
|
|
let mut properties = base_identity_properties();
|
|
|
|
|
|
if let Value::Object(map) = &mut properties {
|
|
|
|
|
|
map.insert("rootUri".into(), json!({ "type": "string" }));
|
|
|
|
|
|
map.insert("sourceKind".into(), json!({ "type": "string" }));
|
|
|
|
|
|
map.insert(resource_id_name.into(), json!({ "type": "string" }));
|
|
|
|
|
|
map.insert("resourcePath".into(), json!({ "type": "string" }));
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"aiAccessScope".into(),
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"properties": {
|
|
|
|
|
|
"permissionLevel": { "type": "string" },
|
|
|
|
|
|
"allowedResourceIds": { "type": "array", "items": { "type": "string" } },
|
|
|
|
|
|
"allowedRoots": { "type": "array" }
|
|
|
|
|
|
}
|
|
|
|
|
|
}),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
properties
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn mindmap_fetch_tool() -> Value {
|
|
|
|
|
|
let mut properties = resource_identity_properties("mindmapId");
|
|
|
|
|
|
if let Value::Object(map) = &mut properties {
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"scope".into(),
|
|
|
|
|
|
json!({ "type": "string", "enum": ["tree", "subtree", "markdown_summary"], "default": "tree" }),
|
|
|
|
|
|
);
|
|
|
|
|
|
map.insert("nodeId".into(), json!({ "type": "string" }));
|
|
|
|
|
|
}
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"name": "mnote.mindmap.fetch",
|
|
|
|
|
|
"description": "读取授权 root 内的 mindmap resource 结构或 markdown summary",
|
|
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
|
|
|
|
|
"capabilityScope": ["resource.read", "mindmap.read"],
|
|
|
|
|
|
"status": "available",
|
|
|
|
|
|
"annotations": tool_annotations(true, false, true, false),
|
|
|
|
|
|
"inputSchema": {
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"required": ["workspaceId", "documentId", "mindmapId", "sessionId", "runId", "toolCallId", "traceId", "actorId"],
|
|
|
|
|
|
"properties": properties
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn mindmap_apply_ops_tool() -> Value {
|
|
|
|
|
|
write_tool(
|
|
|
|
|
|
"mnote.mindmap.apply_ops",
|
|
|
|
|
|
"对授权 mindmap resource 生成或执行结构操作;本地 workspace 默认建议 agent 直接编辑授权文件,必要时才走该工具",
|
|
|
|
|
|
["resource.write", "mindmap.write"],
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"mindmapId": { "type": "string" },
|
|
|
|
|
|
"rootUri": { "type": "string" },
|
|
|
|
|
|
"sourceKind": { "type": "string" },
|
|
|
|
|
|
"resourcePath": { "type": "string" },
|
|
|
|
|
|
"expectedRevision": { "type": ["number", "string"] },
|
|
|
|
|
|
"ops": {
|
|
|
|
|
|
"type": "array",
|
|
|
|
|
|
"items": { "type": "object" }
|
|
|
|
|
|
},
|
|
|
|
|
|
"aiAccessScope": { "type": "object" }
|
|
|
|
|
|
}),
|
|
|
|
|
|
["mindmapId", "ops"],
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn office_fetch_summary_tool() -> Value {
|
|
|
|
|
|
let mut properties = resource_identity_properties("assetId");
|
|
|
|
|
|
if let Value::Object(map) = &mut properties {
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"extractMode".into(),
|
|
|
|
|
|
json!({ "type": "string", "enum": ["text", "outline", "metadata"], "default": "metadata" }),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"name": "mnote.office.fetch_summary",
|
|
|
|
|
|
"description": "读取授权 Office resource 的元数据和轻量文本摘要;不直接写二进制文件",
|
|
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
|
|
|
|
|
"capabilityScope": ["resource.read", "office.read"],
|
|
|
|
|
|
"status": "available",
|
|
|
|
|
|
"annotations": tool_annotations(true, false, true, false),
|
|
|
|
|
|
"inputSchema": {
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"required": ["workspaceId", "documentId", "assetId", "sessionId", "runId", "toolCallId", "traceId", "actorId"],
|
|
|
|
|
|
"properties": properties
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn office_propose_changes_tool() -> Value {
|
|
|
|
|
|
let mut properties = resource_identity_properties("assetId");
|
|
|
|
|
|
if let Value::Object(map) = &mut properties {
|
|
|
|
|
|
map.insert("instructions".into(), json!({ "type": "string" }));
|
|
|
|
|
|
map.insert(
|
|
|
|
|
|
"basisRevision".into(),
|
|
|
|
|
|
json!({ "type": ["number", "string"] }),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"name": "mnote.office.propose_changes",
|
|
|
|
|
|
"description": "基于授权 Office resource 生成修改建议;真实写入仍由 OnlyOffice / officecli 完成",
|
|
|
|
|
|
"schemaVersion": TOOL_SCHEMA_VERSION,
|
|
|
|
|
|
"capabilityScope": ["resource.read", "office.read"],
|
|
|
|
|
|
"status": "available",
|
|
|
|
|
|
"annotations": tool_annotations(true, false, true, false),
|
|
|
|
|
|
"inputSchema": {
|
|
|
|
|
|
"type": "object",
|
|
|
|
|
|
"required": ["workspaceId", "documentId", "assetId", "sessionId", "runId", "toolCallId", "traceId", "actorId", "instructions"],
|
|
|
|
|
|
"properties": properties
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-16 22:03:14 +08:00
|
|
|
|
fn tool_annotations(
|
|
|
|
|
|
readonly: bool,
|
|
|
|
|
|
destructive: bool,
|
|
|
|
|
|
idempotent: bool,
|
|
|
|
|
|
requires_approval: bool,
|
|
|
|
|
|
) -> Value {
|
|
|
|
|
|
json!({
|
|
|
|
|
|
"readonly": readonly,
|
|
|
|
|
|
"destructive": destructive,
|
|
|
|
|
|
"idempotent": idempotent,
|
2026-05-19 08:07:17 +08:00
|
|
|
|
"readOnly": readonly,
|
|
|
|
|
|
"requiresWritePermission": !readonly,
|
2026-05-16 22:03:14 +08:00
|
|
|
|
"requiresApproval": requires_approval,
|
|
|
|
|
|
"approvalMode": if requires_approval { "review" } else { "yolo" },
|
|
|
|
|
|
"runtimeOwner": "mnote-web",
|
|
|
|
|
|
"writeOwner": "rust-runtime-kernel",
|
|
|
|
|
|
"selectionEffect": if readonly { "preserve" } else { "may_change" }
|
2026-05-14 15:10:33 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|