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> where Self: Sized;
96}
97
98// ============================================================================
99// Legacy types for backward compatibility
100// ============================================================================
101
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
103pub struct ProxyMetadata {
104    pub tool_type: String,
105    pub endpoint: Option<String>,
106    pub timeout_ms: u64,
107    pub custom: Option<Value>,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct ProxyToolRequest {
112    pub request_id: String,
113    pub tool_name: String,
114    pub tool_input: Value,
115    pub metadata: ProxyMetadata,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct ProxyToolResponse {
120    pub request_id: String,
121    pub result: String,
122    pub is_error: bool,
123}
124
125#[derive(Debug)]
126pub struct ProxyTool {
127    definition: ToolDefinition,
128    metadata: ProxyMetadata,
129}
130
131impl ProxyTool {
132    pub fn new(definition: ToolDefinition, metadata: ProxyMetadata) -> Self {
133        Self { definition, metadata }
134    }
135
136    pub fn metadata(&self) -> &ProxyMetadata {
137        &self.metadata
138    }
139
140    pub fn definition(&self) -> ToolDefinition {
141        self.definition.clone()
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn test_proxy_tool_def_creation() {
151        let def = ProxyToolDef::new("test", "测试工具", serde_json::json!({}))
152            .with_priority(true)
153            .with_timeout(60000);
154
155        assert_eq!(def.definition.name, "test");
156        assert!(def.definition.is_priority);
157        assert_eq!(def.timeout_ms, 60000);
158    }
159}