matrixcode_core/command/handlers/
tools.rs1use std::future::Future;
4use std::pin::Pin;
5
6use crate::command::{BackendContext, Command};
7
8pub struct Tools;
9
10impl Command for Tools {
11 fn name(&self) -> &'static str {
12 "tools"
13 }
14
15 fn help(&self) -> Option<&'static str> {
16 Some("列出可用工具")
17 }
18
19 fn execute<'a>(
20 &'a self,
21 ctx: &'a mut BackendContext<'_>,
22 ) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
23 Box::pin(async move {
24 let tools = ctx.agent.get_tools();
25 let mut info = format!("🔧 可用工具:{}\n\n", tools.len());
26
27 let mut core_tools: Vec<_> = Vec::new();
29 let mut file_tools: Vec<_> = Vec::new();
30 let mut search_tools: Vec<_> = Vec::new();
31 let mut web_tools: Vec<_> = Vec::new();
32 let mut code_tools: Vec<_> = Vec::new();
33 let mut mcp_tools: Vec<_> = Vec::new();
34 let mut workflow_tools: Vec<_> = Vec::new();
35 let mut other_tools: Vec<_> = Vec::new();
36
37 for tool in tools.iter() {
38 let def = tool.definition();
39 let name = def.name.as_str();
40 let desc = def.description.as_str();
41
42 if name.starts_with("mcp_") || name.starts_with("mcp__") {
43 mcp_tools.push(tool);
44 } else if name.starts_with("workflow_") || name.contains("workflow") {
45 workflow_tools.push(tool);
46 } else if name.starts_with("code_") || desc.contains("CodeGraph") {
47 code_tools.push(tool);
48 } else if name.starts_with("proxy_") || desc.contains("代理") {
49 other_tools.push(tool);
50 } else {
51 match name {
52 "read" | "write" | "edit" | "multi_edit" | "ls" => file_tools.push(tool),
53 "grep" | "glob" | "search" => search_tools.push(tool),
54 "websearch" | "webfetch" => web_tools.push(tool),
55 "bash" | "task" | "todo_write" | "notebook_edit" | "task_create"
56 | "task_get" | "task_list" | "task_stop" => core_tools.push(tool),
57 "ask" | "enter_plan_mode" | "exit_plan_mode" | "monitor" => {
58 core_tools.push(tool)
59 }
60 _ => other_tools.push(tool),
61 }
62 }
63 }
64
65 if !core_tools.is_empty() {
66 info.push_str("📁 核心:\n");
67 for tool in core_tools.iter().take(12) {
68 let def = tool.definition();
69 info.push_str(&format!(
70 " {} - {}\n",
71 def.name,
72 truncate_description(&def.description, 35)
73 ));
74 }
75 }
76
77 if !file_tools.is_empty() {
78 info.push_str("\n📄 文件:\n");
79 for tool in file_tools.iter() {
80 let def = tool.definition();
81 info.push_str(&format!(
82 " {} - {}\n",
83 def.name,
84 truncate_description(&def.description, 35)
85 ));
86 }
87 }
88
89 if !search_tools.is_empty() {
90 info.push_str("\n🔍 搜索:\n");
91 for tool in search_tools.iter() {
92 let def = tool.definition();
93 info.push_str(&format!(
94 " {} - {}\n",
95 def.name,
96 truncate_description(&def.description, 35)
97 ));
98 }
99 }
100
101 if !code_tools.is_empty() {
102 info.push_str("\n📊 CodeGraph:\n");
103 for tool in code_tools.iter() {
104 let def = tool.definition();
105 info.push_str(&format!(
106 " {} - {}\n",
107 def.name,
108 truncate_description(&def.description, 35)
109 ));
110 }
111 }
112
113 if !web_tools.is_empty() {
114 info.push_str("\n🌐 网络:\n");
115 for tool in web_tools.iter() {
116 let def = tool.definition();
117 info.push_str(&format!(
118 " {} - {}\n",
119 def.name,
120 truncate_description(&def.description, 35)
121 ));
122 }
123 }
124
125 if !workflow_tools.is_empty() {
126 info.push_str("\n🔄 工作流:\n");
127 for tool in workflow_tools.iter().take(10) {
128 let def = tool.definition();
129 info.push_str(&format!(
130 " {} - {}\n",
131 def.name,
132 truncate_description(&def.description, 35)
133 ));
134 }
135 }
136
137 if !mcp_tools.is_empty() {
138 info.push_str("\n🔌 MCP:\n");
139 for tool in mcp_tools.iter().take(15) {
140 let def = tool.definition();
141 info.push_str(&format!(
142 " {} - {}\n",
143 def.name,
144 truncate_description(&def.description, 35)
145 ));
146 }
147 if mcp_tools.len() > 15 {
148 info.push_str(&format!(" (+ {} 个更多)\n", mcp_tools.len() - 15));
149 }
150 }
151
152 if !other_tools.is_empty() {
153 info.push_str("\n🔧 其他:\n");
154 for tool in other_tools.iter().take(10) {
155 let def = tool.definition();
156 info.push_str(&format!(
157 " {} - {}\n",
158 def.name,
159 truncate_description(&def.description, 35)
160 ));
161 }
162 if other_tools.len() > 10 {
163 info.push_str(&format!(" (+ {} 个更多)\n", other_tools.len() - 10));
164 }
165 }
166
167 let _ = ctx
168 .event_tx
169 .send(crate::AgentEvent::progress(info, None))
170 .await;
171 false
172 })
173 }
174}
175
176fn truncate_description(desc: &str, max_len: usize) -> String {
177 let first_line = desc.lines().next().unwrap_or(desc);
178 let chars: Vec<char> = first_line.chars().collect();
179 if chars.len() > max_len {
180 chars[..max_len.saturating_sub(3)]
181 .iter()
182 .collect::<String>()
183 + "..."
184 } else {
185 first_line.to_string()
186 }
187}