Fix tiptap selection sync and toolbar event loop

This commit is contained in:
lix-2026
2026-04-19 21:03:25 +08:00
parent 111a87d4fd
commit 394e2a155c
87 changed files with 17415 additions and 527 deletions
@@ -0,0 +1,143 @@
use crate::editor::model::{BlockProps, ContentNode, EditorBlock, EditorBlockType, ReferenceToken};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum EditorCommandKind {
ReplaceBlock,
InsertBlockAfter,
DeleteBlock,
SplitBlock,
MergeWithPrevious,
MoveBlock,
IndentBlock,
OutdentBlock,
ToggleHeadingCollapse,
AttachReferenceToken,
DetachReferenceToken,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct EditorReplaceBlock {
pub block_id: String,
pub block_type: Option<EditorBlockType>,
pub props: Option<BlockProps>,
pub content_nodes: Option<Vec<ContentNode>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct EditorInsertBlockAfter {
pub after_block_id: String,
pub block: EditorBlock,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorDeleteBlock {
pub block_id: String,
pub preserve_children: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorSplitBlock {
pub block_id: String,
pub content_node_index: u32,
pub text_offset: Option<u32>,
pub trailing_block_type: Option<EditorBlockType>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorMergeWithPrevious {
pub block_id: String,
pub previous_block_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorMoveBlock {
pub block_id: String,
pub parent_block_id: Option<String>,
pub after_block_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorIndentBlock {
pub block_id: String,
pub max_depth: Option<u16>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorOutdentBlock {
pub block_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorToggleHeadingCollapse {
pub block_id: String,
pub collapsed: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorAttachReferenceToken {
pub block_id: String,
pub content_node_index: u32,
pub token: ReferenceToken,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorDetachReferenceToken {
pub block_id: String,
pub content_node_index: u32,
pub target_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum EditorCommand {
ReplaceBlock(EditorReplaceBlock),
InsertBlockAfter(EditorInsertBlockAfter),
DeleteBlock(EditorDeleteBlock),
SplitBlock(EditorSplitBlock),
MergeWithPrevious(EditorMergeWithPrevious),
MoveBlock(EditorMoveBlock),
IndentBlock(EditorIndentBlock),
OutdentBlock(EditorOutdentBlock),
ToggleHeadingCollapse(EditorToggleHeadingCollapse),
AttachReferenceToken(EditorAttachReferenceToken),
DetachReferenceToken(EditorDetachReferenceToken),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorKernelCommandMapping {
pub editor_command: EditorCommandKind,
pub kernel_command_name: String,
pub lossy: bool,
pub notes: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorCommandDescriptor {
pub kind: EditorCommandKind,
pub label: String,
pub write_command: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct EditorCommandCatalog {
#[serde(default)]
pub commands: Vec<EditorCommandDescriptor>,
#[serde(default)]
pub kernel_command_mappings: Vec<EditorKernelCommandMapping>,
}
@@ -0,0 +1,91 @@
use crate::editor::model::{EditorBlockDocument, ReferenceTokenStrategy};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MarkdownFlavor {
Commonmark,
Gfm,
Mnote,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MarkdownImportMode {
ReplaceDocument,
ReplaceSelection,
MergeIntoDocument,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MarkdownExportMode {
FullDocument,
Selection,
SingleBlock,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "camelCase")]
pub struct MarkdownImportBoundary {
pub allow_front_matter: bool,
pub allow_html_blocks: bool,
pub allow_reference_tokens: bool,
pub unsupported_blocks_as_paragraph: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "camelCase")]
pub struct MarkdownExportBoundary {
pub preserve_heading_collapse: bool,
pub preserve_reference_tokens: bool,
pub allow_lossy_block_fallback: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct MarkdownImportOptions {
pub mode: MarkdownImportMode,
pub flavor: MarkdownFlavor,
pub reference_token_strategy: ReferenceTokenStrategy,
pub boundary: MarkdownImportBoundary,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct MarkdownExportOptions {
pub mode: MarkdownExportMode,
pub flavor: MarkdownFlavor,
pub reference_token_strategy: ReferenceTokenStrategy,
pub boundary: MarkdownExportBoundary,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct MarkdownImportRequest {
pub markdown: String,
pub options: MarkdownImportOptions,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct MarkdownImportResult {
pub document: EditorBlockDocument,
#[serde(default)]
pub warnings: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct MarkdownExportRequest {
pub document: EditorBlockDocument,
pub options: MarkdownExportOptions,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct MarkdownExportResult {
pub markdown: String,
#[serde(default)]
pub warnings: Vec<String>,
}
@@ -0,0 +1,56 @@
pub mod command;
pub mod markdown;
pub mod model;
pub use command::{
EditorAttachReferenceToken, EditorCommand, EditorCommandCatalog, EditorCommandDescriptor,
EditorCommandKind, EditorDeleteBlock, EditorDetachReferenceToken, EditorIndentBlock,
EditorInsertBlockAfter, EditorKernelCommandMapping, EditorMergeWithPrevious, EditorMoveBlock,
EditorOutdentBlock, EditorReplaceBlock, EditorSplitBlock, EditorToggleHeadingCollapse,
};
pub use markdown::{
MarkdownExportBoundary, MarkdownExportMode, MarkdownExportOptions, MarkdownExportRequest,
MarkdownExportResult, MarkdownFlavor, MarkdownImportBoundary, MarkdownImportMode,
MarkdownImportOptions, MarkdownImportRequest, MarkdownImportResult,
};
pub use model::{
BlockProps, ContentNode, ContentNodePayload, EditorBlock, EditorBlockDocument, EditorBlockType,
ReferenceToken, ReferenceTokenKind, ReferenceTokenStrategy, TextMark,
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn editor_command_kind_uses_phase_one_names() {
assert_eq!(
serde_json::to_string(&EditorCommandKind::InsertBlockAfter).unwrap(),
"\"insert_block_after\""
);
assert_eq!(
serde_json::to_string(&EditorCommandKind::MergeWithPrevious).unwrap(),
"\"merge_with_previous\""
);
assert_eq!(
serde_json::to_string(&EditorCommandKind::ToggleHeadingCollapse).unwrap(),
"\"toggle_heading_collapse\""
);
}
#[test]
fn editor_block_type_uses_expected_snake_case_names() {
assert_eq!(
serde_json::to_string(&EditorBlockType::BulletListItem).unwrap(),
"\"bullet_list_item\""
);
assert_eq!(
serde_json::to_string(&EditorBlockType::PageReference).unwrap(),
"\"page_reference\""
);
assert_eq!(
serde_json::to_string(&EditorBlockType::BlockReference).unwrap(),
"\"block_reference\""
);
}
}
@@ -0,0 +1,112 @@
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::BTreeMap;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum EditorBlockType {
Paragraph,
Heading,
BulletListItem,
NumberedListItem,
Quote,
Todo,
CodeBlock,
PageReference,
BlockReference,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReferenceTokenKind {
PageReference,
BlockReference,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReferenceTokenStrategy {
DoubleBracket,
DoubleParen,
InlineChip,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum TextMark {
Bold,
Italic,
Underline,
Strike,
Code,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ReferenceToken {
pub kind: ReferenceTokenKind,
pub strategy: ReferenceTokenStrategy,
pub target_id: String,
pub label: Option<String>,
pub raw_token: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ContentNodePayload {
Text {
text: String,
#[serde(default)]
marks: Vec<TextMark>,
},
HardBreak,
ReferenceToken {
token: ReferenceToken,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ContentNode {
pub payload: ContentNodePayload,
#[serde(default)]
pub attrs: BTreeMap<String, Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct BlockProps {
pub indent: Option<u16>,
pub heading_level: Option<u8>,
pub checked: Option<bool>,
pub collapsed: Option<bool>,
pub language: Option<String>,
pub reference_target_id: Option<String>,
pub reference_label: Option<String>,
pub reference_token_strategy: Option<ReferenceTokenStrategy>,
#[serde(default)]
pub extra: BTreeMap<String, Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct EditorBlock {
pub block_id: String,
pub block_type: EditorBlockType,
#[serde(default)]
pub props: BlockProps,
#[serde(default)]
pub content_nodes: Vec<ContentNode>,
#[serde(default)]
pub child_block_ids: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct EditorBlockDocument {
pub document_id: String,
#[serde(default)]
pub root_block_ids: Vec<String>,
#[serde(default)]
pub blocks: Vec<EditorBlock>,
}
+119 -1
View File
@@ -352,6 +352,121 @@ pub struct KernelProjectionResult {
pub edges: Vec<KernelEdge>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum DocumentReadNodeType {
Page,
Section,
ContentNode,
ReferenceAnchor,
Mindmap,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DocumentReadNodeMeta {
pub title: Option<String>,
pub text_snippet: Option<String>,
pub block_type: Option<String>,
pub heading_level: Option<u32>,
pub numbering: Option<String>,
pub child_count: u32,
pub order: u32,
#[serde(default)]
pub path: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DocumentReadNode {
pub id: String,
pub parent_node_id: Option<String>,
pub node_type: DocumentReadNodeType,
pub block_id: Option<String>,
pub anchor_block_id: Option<String>,
pub depth: u32,
pub metadata: DocumentReadNodeMeta,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DocumentReadSubtree {
pub root_node_id: String,
pub nodes: Vec<DocumentReadNode>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DocumentReadOutlineEntry {
pub id: String,
pub node_id: String,
pub anchor_block_id: Option<String>,
pub title: String,
pub level: u32,
pub numbering: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum DocumentReadEvidenceKind {
Page,
Heading,
Paragraph,
List,
Todo,
Quote,
Code,
Media,
Reference,
Table,
Mindmap,
Text,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DocumentReadEvidenceItem {
pub id: String,
pub node_id: String,
pub block_id: Option<String>,
pub kind: DocumentReadEvidenceKind,
pub snippet: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct DocumentReadStats {
pub block_count: u32,
pub heading_count: u32,
pub evidence_count: u32,
pub max_depth: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DocumentReadPageSubtree {
pub projection_id: String,
pub projection: String,
pub root_node_id: String,
pub root_node: DocumentReadNode,
pub subtree: DocumentReadSubtree,
#[serde(default)]
pub outline: Vec<DocumentReadOutlineEntry>,
#[serde(default)]
pub evidence: Vec<DocumentReadEvidenceItem>,
pub stats: DocumentReadStats,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DocumentContentResult {
pub content: Value,
pub revision: u64,
pub conflict_detection_key: String,
pub title: Option<String>,
pub page_subtree: DocumentReadPageSubtree,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct KernelCreateNode {
@@ -508,7 +623,10 @@ mod tests {
assert_eq!(value["rowId"], json!("asset:page_1"));
assert_eq!(value["rowKind"], json!("asset"));
assert_eq!(value["projectionKind"], json!("file_tree"));
assert_eq!(value["capabilities"], json!(["expand", "open", "create-child"]));
assert_eq!(
value["capabilities"],
json!(["expand", "open", "create-child"])
);
assert_eq!(value["resourceMeta"]["resourceKind"], json!("document"));
assert_eq!(value["iconHint"], json!("page"));
}
+44 -23
View File
@@ -1,5 +1,6 @@
pub mod command;
pub mod common;
pub mod editor;
pub mod governance;
pub mod kernel;
pub mod mindmap;
@@ -17,39 +18,49 @@ pub use common::{
ActorPayload, AffectedObject, ErrorDetail, ErrorPayload, OkPayload, RequestMeta, ResponseMeta,
SourcePayload, TargetRef,
};
pub use editor::{
BlockProps, ContentNode, ContentNodePayload, EditorAttachReferenceToken, EditorBlock,
EditorBlockDocument, EditorBlockType, EditorCommand, EditorCommandCatalog,
EditorCommandDescriptor, EditorCommandKind, EditorDeleteBlock, EditorDetachReferenceToken,
EditorIndentBlock, EditorInsertBlockAfter, EditorKernelCommandMapping, EditorMergeWithPrevious,
EditorMoveBlock, EditorOutdentBlock, EditorReplaceBlock, EditorSplitBlock,
EditorToggleHeadingCollapse, MarkdownExportBoundary, MarkdownExportMode, MarkdownExportOptions,
MarkdownExportRequest, MarkdownExportResult, MarkdownFlavor, MarkdownImportBoundary,
MarkdownImportMode, MarkdownImportOptions, MarkdownImportRequest, MarkdownImportResult,
ReferenceToken, ReferenceTokenKind, ReferenceTokenStrategy, TextMark,
};
pub use kernel::{
KernelAttachEdge, KernelAuditStamp, KernelContentPayload, KernelCreateNode,
KernelDetachEdge, KernelEdge, KernelEdgeListResult, KernelEdgeType, KernelGetNode,
KernelGetSubtree, KernelGraphDirection, KernelGraphTraversalResult, KernelGraphVisit,
KernelListChildren, KernelListEdges, KernelMoveSubtree, KernelNode, KernelNodeMetadata,
KernelNodeType, KernelProjectionAssetKind, KernelProjectionCapability,
KernelProjectionFilter, KernelProjectionItem, KernelProjectionKind,
DocumentContentResult, DocumentReadEvidenceItem, DocumentReadEvidenceKind, DocumentReadNode,
DocumentReadNodeMeta, DocumentReadNodeType, DocumentReadOutlineEntry, DocumentReadPageSubtree,
DocumentReadStats, DocumentReadSubtree, KernelAttachEdge, KernelAuditStamp,
KernelContentPayload, KernelCreateNode, KernelDetachEdge, KernelEdge, KernelEdgeListResult,
KernelEdgeType, KernelGetNode, KernelGetSubtree, KernelGraphDirection,
KernelGraphTraversalResult, KernelGraphVisit, KernelListChildren, KernelListEdges,
KernelMoveSubtree, KernelNode, KernelNodeMetadata, KernelNodeType, KernelProjectionAssetKind,
KernelProjectionCapability, KernelProjectionFilter, KernelProjectionItem, KernelProjectionKind,
KernelProjectionRequest, KernelProjectionResourceKind, KernelProjectionResourceMeta,
KernelProjectionResult, KernelProjectionRowKind, KernelRefsPayload, KernelSubtreeRef,
KernelSubtreeResult, KernelTraverseGraph, KernelUpdateNode,
};
pub use mindmap::{
MindmapNodeData, MindmapNodeInput, MindmapNodeRef, MindmapOp, MindmapTreeNode,
};
pub use mindmap::{MindmapNodeData, MindmapNodeInput, MindmapNodeRef, MindmapOp, MindmapTreeNode};
pub use query::{
GetBlock, GetBridgeCommand, GetBridgeRequest, GetBridgeTrace, GetMindmap, GetPage,
GetPageContent, GetPageMeta, ListBridgeWorkspaceOverview, ListPageBlocks,
ListSidebarDataset, QueryEnvelope, SearchBlocks, SearchDocuments, SearchPages, SearchRecent,
GetPageContent, GetPageMeta, ListBridgeWorkspaceOverview, ListPageBlocks, ListSidebarDataset,
QueryEnvelope, SearchBlocks, SearchDocuments, SearchPages, SearchRecent,
};
pub use tool::{
default_tool_registry, invocation_kind_label, tool_effect_label, tool_mode_label,
InvocationKind, ToolEffect, ToolExecutionMode, ToolInvocation, ToolRegistry, ToolSetSpec,
ToolSpec, BRIDGE_TOOL_COMMAND_GET, BRIDGE_TOOL_REQUEST_GET, BRIDGE_TOOL_TRACE_GET,
DOCS_TOOL_READ, DOCS_TOOL_SEARCH, DOCS_TOOLSET_READ, DOC_TOOL_FIND, DOC_TOOL_GET,
DOC_TOOL_INSERT_BLOCKS, DOC_TOOL_REPLACE_RANGE, DOC_TOOLSET_READ, DOC_TOOLSET_WRITE,
INDEX_TOOL_REBUILD, MINDMAP_TOOL_APPLY_OPS,
MINDMAP_TOOL_EMPTY_TRASH, MINDMAP_TOOL_EXPAND_NODE, MINDMAP_TOOL_GET,
MINDMAP_TOOL_GET_SUBTREE,
MINDMAP_TOOL_OUTLINE_TO_MINDMAP, MINDMAP_TOOL_PUT, MINDMAP_TOOLSET_READ,
MINDMAP_TOOLSET_WRITE, OBSERVE_TOOLSET_READ, ONLYOFFICE_TOOL_PREPARE_CALLBACK,
DOCS_TOOLSET_READ, DOCS_TOOL_READ, DOCS_TOOL_SEARCH, DOC_TOOLSET_READ, DOC_TOOLSET_WRITE,
DOC_TOOL_FIND, DOC_TOOL_GET, DOC_TOOL_INSERT_BLOCKS, DOC_TOOL_REPLACE_RANGE,
INDEX_TOOL_REBUILD, MINDMAP_TOOLSET_READ, MINDMAP_TOOLSET_WRITE, MINDMAP_TOOL_APPLY_OPS,
MINDMAP_TOOL_EMPTY_TRASH, MINDMAP_TOOL_EXPAND_NODE, MINDMAP_TOOL_GET, MINDMAP_TOOL_GET_SUBTREE,
MINDMAP_TOOL_OUTLINE_TO_MINDMAP, MINDMAP_TOOL_PUT, OBSERVE_TOOLSET_READ,
ONLYOFFICE_TOOLSET_SERVICE, ONLYOFFICE_TOOL_PREPARE_CALLBACK,
ONLYOFFICE_TOOL_PREPARE_FORCESAVE, ONLYOFFICE_TOOL_PREPARE_PROXY,
ONLYOFFICE_TOOL_SESSION_RESOLVE, ONLYOFFICE_TOOL_SIGN, ONLYOFFICE_TOOLSET_SERVICE,
RECOVERY_TOOLSET_JOB, REPLAY_TOOL_EVENTS,
ONLYOFFICE_TOOL_SESSION_RESOLVE, ONLYOFFICE_TOOL_SIGN, RECOVERY_TOOLSET_JOB,
REPLAY_TOOL_EVENTS,
};
#[cfg(test)]
@@ -164,9 +175,15 @@ mod tests {
.toolset("toolset.doc_write")
.expect("doc_write toolset should exist");
assert!(doc_write.write_toolset);
assert_eq!(doc_write.tool_names, &["doc_insert_blocks", "doc_replace_range"]);
assert_eq!(
registry.tool("doc_get").expect("doc_get should exist").toolset_id,
doc_write.tool_names,
&["doc_insert_blocks", "doc_replace_range"]
);
assert_eq!(
registry
.tool("doc_get")
.expect("doc_get should exist")
.toolset_id,
"toolset.doc_read"
);
let mindmap_write = registry
@@ -203,7 +220,11 @@ mod tests {
assert!(!observe.write_toolset);
assert_eq!(
observe.tool_names,
&["bridge_request_get", "bridge_trace_get", "bridge_command_get"]
&[
"bridge_request_get",
"bridge_trace_get",
"bridge_command_get"
]
);
let recovery = registry
.toolset("toolset.recovery_job")
+31 -55
View File
@@ -71,8 +71,7 @@ impl ToolRegistry {
}
pub fn tool_names_in_set(&self, id: &str) -> Option<Vec<&'static str>> {
self.toolset(id)
.map(|toolset| toolset.tool_names.to_vec())
self.toolset(id).map(|toolset| toolset.tool_names.to_vec())
}
pub fn tools_in_set(&self, id: &str) -> Option<Vec<&'static ToolSpec>> {
@@ -105,8 +104,7 @@ pub const SEARCH_WEB_TOOL: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":10}}}"#,
input_schema_json: r#"{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":10}}}"#,
};
pub const DOC_TOOL_FIND: ToolSpec = ToolSpec {
@@ -117,11 +115,9 @@ pub const DOC_TOOL_FIND: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"maxResults":{"type":"integer","minimum":1,"maximum":30}}}"#,
input_schema_json: r#"{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"maxResults":{"type":"integer","minimum":1,"maximum":30}}}"#,
};
pub const DOCS_TOOL_SEARCH: ToolSpec = ToolSpec {
name: "docs_search",
display_name: "跨页文档搜索",
@@ -130,8 +126,7 @@ pub const DOCS_TOOL_SEARCH: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"workspaceId":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":30},"includeDeleted":{"type":"boolean"},"pageId":{"type":"string"},"titleOnly":{"type":"boolean"},"exact":{"type":"boolean"},"includeOcr":{"type":"boolean"},"timeRange":{"type":"string"},"timeField":{"type":"string"},"customRangeFrom":{"type":"string"},"customRangeTo":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"workspaceId":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":30},"includeDeleted":{"type":"boolean"},"pageId":{"type":"string"},"titleOnly":{"type":"boolean"},"exact":{"type":"boolean"},"includeOcr":{"type":"boolean"},"timeRange":{"type":"string"},"timeField":{"type":"string"},"customRangeFrom":{"type":"string"},"customRangeTo":{"type":"string"}}}"#,
};
pub const DOCS_TOOL_READ: ToolSpec = ToolSpec {
@@ -142,8 +137,7 @@ pub const DOCS_TOOL_READ: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["documentId"],"properties":{"documentId":{"type":"string"},"maxChars":{"type":"integer","minimum":200,"maximum":20000},"includeContent":{"type":"boolean"}}}"#,
input_schema_json: r#"{"type":"object","required":["documentId"],"properties":{"documentId":{"type":"string"},"maxChars":{"type":"integer","minimum":200,"maximum":20000},"includeContent":{"type":"boolean"}}}"#,
};
pub const IMAGE_READ_TOOL: ToolSpec = ToolSpec {
@@ -154,8 +148,7 @@ pub const IMAGE_READ_TOOL: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","properties":{"assetId":{"type":"string"},"fileUrl":{"type":"string"},"attachmentRef":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","properties":{"assetId":{"type":"string"},"fileUrl":{"type":"string"},"attachmentRef":{"type":"string"}}}"#,
};
pub const DOC_TOOL_INSERT_BLOCKS: ToolSpec = ToolSpec {
@@ -166,8 +159,7 @@ pub const DOC_TOOL_INSERT_BLOCKS: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Command,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","required":["blocks"],"properties":{"afterBlockId":{"type":"string"},"beforeBlockId":{"type":"string"},"blocks":{"type":"array","minItems":1,"maxItems":20}}}"#,
input_schema_json: r#"{"type":"object","required":["blocks"],"properties":{"afterBlockId":{"type":"string"},"beforeBlockId":{"type":"string"},"blocks":{"type":"array","minItems":1,"maxItems":20}}}"#,
};
pub const DOC_TOOL_REPLACE_RANGE: ToolSpec = ToolSpec {
@@ -178,8 +170,7 @@ pub const DOC_TOOL_REPLACE_RANGE: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Command,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","required":["blockId","text"],"properties":{"blockId":{"type":"string"},"text":{"type":"string"},"mode":{"enum":["replace","append","prepend"]}}}"#,
input_schema_json: r#"{"type":"object","required":["blockId","text"],"properties":{"blockId":{"type":"string"},"text":{"type":"string"},"mode":{"enum":["replace","append","prepend"]}}}"#,
};
pub const SLASH_RUN_TOOL: ToolSpec = ToolSpec {
@@ -190,8 +181,7 @@ pub const SLASH_RUN_TOOL: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Command,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","properties":{"text":{"type":"string"},"command":{"enum":["new_doc","rename_doc"]},"params":{"type":"object"},"reason":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","properties":{"text":{"type":"string"},"command":{"enum":["new_doc","rename_doc"]},"params":{"type":"object"},"reason":{"type":"string"}}}"#,
};
pub const MINDMAP_TOOL_GET: ToolSpec = ToolSpec {
@@ -202,8 +192,7 @@ pub const MINDMAP_TOOL_GET: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","properties":{"maxNodes":{"type":"integer","minimum":10,"maximum":300}}}"#,
input_schema_json: r#"{"type":"object","properties":{"maxNodes":{"type":"integer","minimum":10,"maximum":300}}}"#,
};
pub const MINDMAP_TOOL_GET_SUBTREE: ToolSpec = ToolSpec {
@@ -214,8 +203,7 @@ pub const MINDMAP_TOOL_GET_SUBTREE: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["uid"],"properties":{"uid":{"type":"string"},"depth":{"type":"integer","minimum":0,"maximum":6},"maxNodes":{"type":"integer","minimum":5,"maximum":200}}}"#,
input_schema_json: r#"{"type":"object","required":["uid"],"properties":{"uid":{"type":"string"},"depth":{"type":"integer","minimum":0,"maximum":6},"maxNodes":{"type":"integer","minimum":5,"maximum":200}}}"#,
};
pub const MINDMAP_TOOL_PUT: ToolSpec = ToolSpec {
@@ -226,8 +214,7 @@ pub const MINDMAP_TOOL_PUT: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Command,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","required":["data"],"properties":{"data":{"type":"object"},"createOnly":{"type":"boolean"}}}"#,
input_schema_json: r#"{"type":"object","required":["data"],"properties":{"data":{"type":"object"},"createOnly":{"type":"boolean"}}}"#,
};
pub const MINDMAP_TOOL_APPLY_OPS: ToolSpec = ToolSpec {
@@ -238,8 +225,7 @@ pub const MINDMAP_TOOL_APPLY_OPS: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Command,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","required":["ops"],"properties":{"ops":{"type":"array","minItems":1,"maxItems":80},"reason":{"type":"string"},"targetUid":{"type":"string"},"searchResults":{"type":"array"}}}"#,
input_schema_json: r#"{"type":"object","required":["ops"],"properties":{"ops":{"type":"array","minItems":1,"maxItems":80},"reason":{"type":"string"},"targetUid":{"type":"string"},"searchResults":{"type":"array"}}}"#,
};
pub const MINDMAP_TOOL_EXPAND_NODE: ToolSpec = ToolSpec {
@@ -250,8 +236,7 @@ pub const MINDMAP_TOOL_EXPAND_NODE: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Command,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","required":["targetUid"],"properties":{"targetUid":{"type":"string"},"instruction":{"type":"string"},"ops":{"type":"array","maxItems":80},"searchResults":{"type":"array"},"reason":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["targetUid"],"properties":{"targetUid":{"type":"string"},"instruction":{"type":"string"},"ops":{"type":"array","maxItems":80},"searchResults":{"type":"array"},"reason":{"type":"string"}}}"#,
};
pub const MINDMAP_TOOL_EMPTY_TRASH: ToolSpec = ToolSpec {
@@ -262,8 +247,7 @@ pub const MINDMAP_TOOL_EMPTY_TRASH: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Command,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","required":["workspaceId"],"properties":{"workspaceId":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["workspaceId"],"properties":{"workspaceId":{"type":"string"}}}"#,
};
pub const MINDMAP_TOOL_OUTLINE_TO_MINDMAP: ToolSpec = ToolSpec {
@@ -274,8 +258,7 @@ pub const MINDMAP_TOOL_OUTLINE_TO_MINDMAP: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Command,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","required":["rootTitle","pageLinkPattern","outline"],"properties":{"rootTitle":{"type":"string"},"pageLinkPattern":{"type":"string"},"outline":{"type":"array","items":{"type":"object","required":["title","level","page"],"properties":{"title":{"type":"string"},"level":{"type":"integer","minimum":1,"maximum":6},"page":{"type":"integer","minimum":1}}}}}}"#,
input_schema_json: r#"{"type":"object","required":["rootTitle","pageLinkPattern","outline"],"properties":{"rootTitle":{"type":"string"},"pageLinkPattern":{"type":"string"},"outline":{"type":"array","items":{"type":"object","required":["title","level","page"],"properties":{"title":{"type":"string"},"level":{"type":"integer","minimum":1,"maximum":6},"page":{"type":"integer","minimum":1}}}}}}"#,
};
pub const BRIDGE_TOOL_REQUEST_GET: ToolSpec = ToolSpec {
@@ -286,8 +269,7 @@ pub const BRIDGE_TOOL_REQUEST_GET: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["workspaceId","requestId"],"properties":{"workspaceId":{"type":"string"},"requestId":{"type":"string"},"commandId":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["workspaceId","requestId"],"properties":{"workspaceId":{"type":"string"},"requestId":{"type":"string"},"commandId":{"type":"string"}}}"#,
};
pub const BRIDGE_TOOL_TRACE_GET: ToolSpec = ToolSpec {
@@ -298,8 +280,7 @@ pub const BRIDGE_TOOL_TRACE_GET: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["workspaceId","traceId"],"properties":{"workspaceId":{"type":"string"},"traceId":{"type":"string"},"commandId":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["workspaceId","traceId"],"properties":{"workspaceId":{"type":"string"},"traceId":{"type":"string"},"commandId":{"type":"string"}}}"#,
};
pub const BRIDGE_TOOL_COMMAND_GET: ToolSpec = ToolSpec {
@@ -310,8 +291,7 @@ pub const BRIDGE_TOOL_COMMAND_GET: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Query,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["workspaceId","commandId"],"properties":{"workspaceId":{"type":"string"},"commandId":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["workspaceId","commandId"],"properties":{"workspaceId":{"type":"string"},"commandId":{"type":"string"}}}"#,
};
pub const REPLAY_TOOL_EVENTS: ToolSpec = ToolSpec {
@@ -322,8 +302,7 @@ pub const REPLAY_TOOL_EVENTS: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Job,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","required":["workspaceId"],"properties":{"workspaceId":{"type":"string"},"lastProcessedEventId":{"type":"string"},"lastProcessedAt":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["workspaceId"],"properties":{"workspaceId":{"type":"string"},"lastProcessedEventId":{"type":"string"},"lastProcessedAt":{"type":"string"}}}"#,
};
pub const INDEX_TOOL_REBUILD: ToolSpec = ToolSpec {
@@ -334,8 +313,7 @@ pub const INDEX_TOOL_REBUILD: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Job,
effect: ToolEffect::Write,
requires_confirmation: true,
input_schema_json:
r#"{"type":"object","required":["workspaceId"],"properties":{"workspaceId":{"type":"string"},"lastProcessedEventId":{"type":"string"},"lastProcessedAt":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["workspaceId"],"properties":{"workspaceId":{"type":"string"},"lastProcessedEventId":{"type":"string"},"lastProcessedAt":{"type":"string"}}}"#,
};
pub const ONLYOFFICE_TOOL_SESSION_RESOLVE: ToolSpec = ToolSpec {
@@ -346,8 +324,7 @@ pub const ONLYOFFICE_TOOL_SESSION_RESOLVE: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Job,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["assetId"],"properties":{"assetId":{"type":"string"},"workspaceId":{"type":"string"},"documentId":{"type":"string"},"userId":{"type":"string"},"sessionId":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["assetId"],"properties":{"assetId":{"type":"string"},"workspaceId":{"type":"string"},"documentId":{"type":"string"},"userId":{"type":"string"},"sessionId":{"type":"string"}}}"#,
};
pub const ONLYOFFICE_TOOL_SIGN: ToolSpec = ToolSpec {
@@ -358,8 +335,7 @@ pub const ONLYOFFICE_TOOL_SIGN: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Job,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","properties":{"config":{"type":"object"},"secret":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","properties":{"config":{"type":"object"},"secret":{"type":"string"}}}"#,
};
pub const ONLYOFFICE_TOOL_PREPARE_PROXY: ToolSpec = ToolSpec {
@@ -370,8 +346,7 @@ pub const ONLYOFFICE_TOOL_PREPARE_PROXY: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Job,
effect: ToolEffect::Read,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["encodedUrl"],"properties":{"encodedUrl":{"type":"string"},"method":{"enum":["GET","HEAD"]},"range":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["encodedUrl"],"properties":{"encodedUrl":{"type":"string"},"method":{"enum":["GET","HEAD"]},"range":{"type":"string"}}}"#,
};
pub const ONLYOFFICE_TOOL_PREPARE_CALLBACK: ToolSpec = ToolSpec {
@@ -382,8 +357,7 @@ pub const ONLYOFFICE_TOOL_PREPARE_CALLBACK: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Job,
effect: ToolEffect::Write,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["assetId","status","onlyofficeInternalUrl"],"properties":{"assetId":{"type":"string"},"documentId":{"type":"string"},"workspaceId":{"type":"string"},"userId":{"type":"string"},"sessionId":{"type":"string"},"status":{"type":"integer"},"url":{"type":"string"},"key":{"type":"string"},"onlyofficeInternalUrl":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["assetId","status","onlyofficeInternalUrl"],"properties":{"assetId":{"type":"string"},"documentId":{"type":"string"},"workspaceId":{"type":"string"},"userId":{"type":"string"},"sessionId":{"type":"string"},"status":{"type":"integer"},"url":{"type":"string"},"key":{"type":"string"},"onlyofficeInternalUrl":{"type":"string"}}}"#,
};
pub const ONLYOFFICE_TOOL_PREPARE_FORCESAVE: ToolSpec = ToolSpec {
@@ -394,8 +368,7 @@ pub const ONLYOFFICE_TOOL_PREPARE_FORCESAVE: ToolSpec = ToolSpec {
invocation_kind: InvocationKind::Job,
effect: ToolEffect::Write,
requires_confirmation: false,
input_schema_json:
r#"{"type":"object","required":["assetId","key","onlyofficeInternalUrl"],"properties":{"assetId":{"type":"string"},"key":{"type":"string"},"onlyofficeInternalUrl":{"type":"string"},"secret":{"type":"string"}}}"#,
input_schema_json: r#"{"type":"object","required":["assetId","key","onlyofficeInternalUrl"],"properties":{"assetId":{"type":"string"},"key":{"type":"string"},"onlyofficeInternalUrl":{"type":"string"},"secret":{"type":"string"}}}"#,
};
pub const DOC_TOOLSET_READ: ToolSetSpec = ToolSetSpec {
@@ -406,7 +379,6 @@ pub const DOC_TOOLSET_READ: ToolSetSpec = ToolSetSpec {
tool_names: &["doc_get", "doc_find"],
};
pub const DOCS_TOOLSET_READ: ToolSetSpec = ToolSetSpec {
id: "toolset.docs_read",
display_name: "跨页文档读取",
@@ -466,7 +438,11 @@ pub const OBSERVE_TOOLSET_READ: ToolSetSpec = ToolSetSpec {
display_name: "统一观测",
description: "按 request、trace、command 回查统一日志与事件视图。",
write_toolset: false,
tool_names: &["bridge_request_get", "bridge_trace_get", "bridge_command_get"],
tool_names: &[
"bridge_request_get",
"bridge_trace_get",
"bridge_command_get",
],
};
pub const RECOVERY_TOOLSET_JOB: ToolSetSpec = ToolSetSpec {