Skip to main content

matrixcode_core/tools/
toolproxy.rs

1//! Proxy Tool Executor Trait
2//!
3//! 简化的代理工具接口 - 外部只需实现一个 trait
4//!
5//! ## 设计原则
6//!
7//! 实现者必须同时提供:
8//! 1. `exec()` - 执行逻辑
9//! 2. `tool_definitions()` - 工具定义(LLM 看到的)
10//!
11//! 这样每个 Executor 都知道自己的工具定义,紧密绑定。
12
13use anyhow::Result;
14use async_trait::async_trait;
15use serde::{Deserialize, Serialize};
16use serde_json::Value;
17
18use super::ToolDefinition;
19
20/// 代理工具定义(发送给 LLM)
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ProxyToolDef {
23    pub definition: ToolDefinition,
24    pub timeout_ms: u64,
25}
26
27impl ProxyToolDef {
28    pub fn new(name: impl Into<String>, description: impl Into<String>, parameters: Value) -> Self {
29        Self {
30            definition: ToolDefinition {
31                name: name.into(),
32                description: description.into(),
33                parameters,
34                is_priority: false,
35            },
36            timeout_ms: 30000,
37        }
38    }
39
40    pub fn with_priority(mut self, is_priority: bool) -> Self {
41        self.definition.is_priority = is_priority;
42        self
43    }
44
45    pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
46        self.timeout_ms = timeout_ms;
47        self
48    }
49}
50
51/// 代理工具执行器 trait
52///
53/// **必须实现两个方法:**
54/// - `exec()` - 执行逻辑
55/// - `tool_definitions()` - 工具定义列表
56///
57/// # Example
58///
59/// ```ignore
60/// use async_trait::async_trait;
61/// use serde_json::json;
62/// use std::sync::Arc;
63/// use matrixcode_core::tools::toolproxy::{ProxyToolExecutor, ProxyToolDef};
64/// use anyhow::Result;
65/// use serde_json::Value;
66///
67/// struct ImageSearchExecutor;
68///
69/// #[async_trait]
70/// impl ProxyToolExecutor for ImageSearchExecutor {
71///     async fn exec(&self, tool_name: &str, input: Value) -> Result<String> {
72///         // 执行逻辑...
73///         Ok("result".to_string())
74///     }
75///
76///     fn tool_definitions() -> Vec<ProxyToolDef> {
77///         vec![
78///             ProxyToolDef::new("image_search", "搜索图片", json!({...}))
79///                 .with_priority(true)
80///         ]
81///     }
82/// }
83///
84/// // 使用
85/// let executor = Arc::new(ImageSearchExecutor);
86/// let tool_defs = ImageSearchExecutor::tool_definitions();
87/// // builder.proxy_executor(executor, tool_defs)
88/// ```
89#[async_trait]
90pub trait ProxyToolExecutor: Send + Sync {
91    /// 执行代理工具(必需)
92    async fn exec(&self, tool_name: &str, input: Value) -> Result<String>;
93
94    /// 返回工具定义列表(必需 - LLM 看到的)
95    fn tool_definitions() -> Vec<ProxyToolDef>
96    where
97        Self: Sized;
98}
99
100// ============================================================================
101// Legacy types for backward compatibility
102// ============================================================================
103
104#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
105pub struct ProxyMetadata {
106    pub tool_type: String,
107    pub endpoint: Option<String>,
108    pub timeout_ms: u64,
109    pub custom: Option<Value>,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct ProxyToolRequest {
114    pub request_id: String,
115    pub tool_name: String,
116    pub tool_input: Value,
117    pub metadata: ProxyMetadata,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct ProxyToolResponse {
122    pub request_id: String,
123    pub result: String,
124    pub is_error: bool,
125}
126
127#[derive(Debug)]
128pub struct ProxyTool {
129    definition: ToolDefinition,
130    metadata: ProxyMetadata,
131}
132
133impl ProxyTool {
134    pub fn new(definition: ToolDefinition, metadata: ProxyMetadata) -> Self {
135        Self {
136            definition,
137            metadata,
138        }
139    }
140
141    pub fn metadata(&self) -> &ProxyMetadata {
142        &self.metadata
143    }
144
145    pub fn definition(&self) -> ToolDefinition {
146        self.definition.clone()
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153
154    #[test]
155    fn test_proxy_tool_def_creation() {
156        let def = ProxyToolDef::new("test", "测试工具", serde_json::json!({}))
157            .with_priority(true)
158            .with_timeout(60000);
159
160        assert_eq!(def.definition.name, "test");
161        assert!(def.definition.is_priority);
162        assert_eq!(def.timeout_ms, 60000);
163    }
164}