Skip to main content

matrixcode_core/command/handlers/
system.rs

1//! /system 命令处理器
2
3use std::future::Future;
4use std::pin::Pin;
5
6use crate::command::{Command, BackendContext};
7use crate::workflow::WorkflowRegistry;
8
9pub struct System;
10
11impl Command for System {
12    fn name(&self) -> &'static str {
13        "system"
14    }
15
16    fn help(&self) -> Option<&'static str> {
17        Some("显示系统信息和完整的系统提示词")
18    }
19
20    fn execute<'a>(&'a self, ctx: &'a mut BackendContext<'_>) 
21        -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> 
22    {
23        Box::pin(async move {
24            let msg = ctx.message.trim();
25            
26            // 解析子命令
27            if msg == "/system" || msg == "/system status" {
28                self.show_full(ctx).await
29            } else if msg == "/system prompt" {
30                self.show_prompt(ctx).await
31            } else if msg == "/system tools" {
32                self.show_tools(ctx).await
33            } else if msg == "/system stats" {
34                self.show_stats(ctx).await
35            } else if msg == "/system skills" {
36                self.show_skills(ctx).await
37            } else if msg == "/system workflows" {
38                self.show_workflows(ctx).await
39            } else if msg == "/system config" {
40                self.show_config(ctx).await
41            } else if msg == "/system env" {
42                self.show_env(ctx).await
43            } else if msg == "/system help" {
44                self.show_help(ctx).await
45            } else {
46                let _ = ctx.event_tx.send(crate::AgentEvent::progress(
47                    "用法:/system [status|prompt|tools|stats|skills|workflows|config|env|help]".to_string(),
48                    None,
49                )).await;
50                false
51            }
52        })
53    }
54}
55
56impl System {
57    /// 显示完整信息
58    async fn show_full(&self, ctx: &mut BackendContext<'_>) -> bool {
59        let mut output = String::new();
60        
61        // 1. 系统基本信息
62        output.push_str("🖥️  **系统环境**\n");
63        output.push_str(&format!("  • 操作系统: {} ({})\n", std::env::consts::OS, std::env::consts::ARCH));
64        output.push_str(&format!("  • 当前目录: {:?}\n", ctx.project_path.unwrap_or(&std::path::PathBuf::new())));
65        output.push_str(&format!("  • 当前模型: {}\n\n", ctx.model));
66        
67        // 2. Token 使用统计
68        let (input_tokens, output_tokens) = ctx.agent.get_token_counts();
69        output.push_str("📊 **Token 统计**\n");
70        output.push_str(&format!("  • 输入: {} tokens\n", input_tokens));
71        output.push_str(&format!("  • 输出: {} tokens\n", output_tokens));
72        output.push_str(&format!("  • 总计: {} tokens\n\n", input_tokens + output_tokens));
73        
74        // 3. 工具列表
75        let tools = ctx.agent.get_tools();
76        output.push_str(&format!("🔧 **可用工具** (共 {} 个)\n", tools.len()));
77        for (idx, tool) in tools.iter().enumerate() {
78            if idx < 10 || tools.len() <= 15 {
79                output.push_str(&format!("  • {}\n", tool.definition().name));
80            } else if idx == 10 {
81                output.push_str(&format!("  ... 还有 {} 个工具\n", tools.len() - 10));
82                break;
83            }
84        }
85        output.push('\n');
86        
87        // 4. 技能列表
88        if !ctx.skills.is_empty() {
89            output.push_str(&format!("📚 **可用技能** (共 {} 个)\n", ctx.skills.len()));
90            for skill in ctx.skills.iter() {
91                output.push_str(&format!("  • {}: {}\n", skill.name, skill.description));
92            }
93            output.push('\n');
94        }
95        
96        // 5. 工作流列表
97        if let Some(project_path) = ctx.project_path {
98            let registry = WorkflowRegistry::new(Some(project_path));
99            if !registry.is_empty() {
100                output.push_str(&format!("⚡ **可用工作流** (共 {} 个)\n", registry.list().len()));
101                for info in registry.list().iter().take(5) {
102                    output.push_str(&format!("  • {}: ", info.id));
103                    if let Some(ref desc) = info.description {
104                        output.push_str(desc);
105                    } else {
106                        output.push_str(&info.name);
107                    }
108                    output.push('\n');
109                }
110                if registry.list().len() > 5 {
111                    output.push_str(&format!("  ... 还有 {} 个工作流\n", registry.list().len() - 5));
112                }
113                output.push('\n');
114            }
115        }
116        
117        // 6. 完整 System Prompt
118        output.push_str("📜 **完整 System Prompt**\n");
119        output.push_str(&format!("长度: {} 字符\n\n", ctx.agent.get_system_prompt().len()));
120        output.push_str("```\n");
121        output.push_str(ctx.agent.get_system_prompt());
122        output.push_str("\n```\n");
123        
124        let _ = ctx.event_tx.send(crate::AgentEvent::progress(output, None)).await;
125        false
126    }
127    
128    /// 仅显示 System Prompt
129    async fn show_prompt(&self, ctx: &mut BackendContext<'_>) -> bool {
130        let prompt = ctx.agent.get_system_prompt();
131        let mut output = String::new();
132        
133        output.push_str("📜 **System Prompt**\n");
134        output.push_str(&format!("长度: {} 字符\n\n", prompt.len()));
135        output.push_str("```\n");
136        output.push_str(prompt);
137        output.push_str("\n```\n");
138        
139        let _ = ctx.event_tx.send(crate::AgentEvent::progress(output, None)).await;
140        false
141    }
142    
143    /// 仅显示工具列表
144    async fn show_tools(&self, ctx: &mut BackendContext<'_>) -> bool {
145        let tools = ctx.agent.get_tools();
146        let mut output = String::new();
147        
148        output.push_str(&format!("🔧 **可用工具** (共 {} 个)\n\n", tools.len()));
149        
150        for (idx, tool) in tools.iter().enumerate() {
151            let def = tool.definition();
152            output.push_str(&format!("{}. **{}**\n", idx + 1, def.name));
153            output.push_str(&format!("   {}\n\n", def.description));
154        }
155        
156        let _ = ctx.event_tx.send(crate::AgentEvent::progress(output, None)).await;
157        false
158    }
159    
160    /// 仅显示统计信息
161    async fn show_stats(&self, ctx: &mut BackendContext<'_>) -> bool {
162        let mut output = String::new();
163        
164        // 系统信息
165        output.push_str("🖥️  **系统环境**\n");
166        output.push_str(&format!("  • 操作系统: {} ({})\n", std::env::consts::OS, std::env::consts::ARCH));
167        output.push_str(&format!("  • 当前目录: {:?}\n", ctx.project_path.unwrap_or(&std::path::PathBuf::new())));
168        output.push_str(&format!("  • 当前模型: {}\n\n", ctx.model));
169        
170        // Token 统计
171        let (input_tokens, output_tokens) = ctx.agent.get_token_counts();
172        output.push_str("📊 **Token 统计**\n");
173        output.push_str(&format!("  • 输入: {} tokens\n", input_tokens));
174        output.push_str(&format!("  • 输出: {} tokens\n", output_tokens));
175        output.push_str(&format!("  • 总计: {} tokens\n\n", input_tokens + output_tokens));
176        
177        // 工具统计
178        let tools = ctx.agent.get_tools();
179        output.push_str("🔧 **资源统计**\n");
180        output.push_str(&format!("  • 可用工具: {} 个\n", tools.len()));
181        output.push_str(&format!("  • 可用技能: {} 个\n", ctx.skills.len()));
182        
183        // 工作流统计
184        if let Some(project_path) = ctx.project_path {
185            let registry = WorkflowRegistry::new(Some(project_path));
186            output.push_str(&format!("  • 可用工作流: {} 个\n", registry.list().len()));
187        } else {
188            output.push_str("  • 可用工作流: 0 个\n");
189        }
190        
191        output.push_str(&format!("  • System Prompt 长度: {} 字符\n", ctx.agent.get_system_prompt().len()));
192        
193        let _ = ctx.event_tx.send(crate::AgentEvent::progress(output, None)).await;
194        false
195    }
196    
197    /// 仅显示技能列表
198    async fn show_skills(&self, ctx: &mut BackendContext<'_>) -> bool {
199        let mut output = String::new();
200        
201        if ctx.skills.is_empty() {
202            output.push_str("📚 **可用技能**: 无\n");
203        } else {
204            output.push_str(&format!("📚 **可用技能** (共 {} 个)\n\n", ctx.skills.len()));
205            for (idx, skill) in ctx.skills.iter().enumerate() {
206                output.push_str(&format!("{}. **{}**\n", idx + 1, skill.name));
207                output.push_str(&format!("   {}\n\n", skill.description));
208            }
209        }
210        
211        let _ = ctx.event_tx.send(crate::AgentEvent::progress(output, None)).await;
212        false
213    }
214    
215    /// 显示工作流列表
216    async fn show_workflows(&self, ctx: &mut BackendContext<'_>) -> bool {
217        let mut output = String::new();
218        
219        if let Some(project_path) = ctx.project_path {
220            let registry = WorkflowRegistry::new(Some(project_path));
221            let workflows = registry.list();
222            
223            if workflows.is_empty() {
224                output.push_str("⚡ **可用工作流**: 无\n");
225                output.push_str("\n提示:在项目 .matrix/workflows/ 目录下创建 workflow.yaml 文件来添加自定义工作流。\n");
226            } else {
227                output.push_str(&format!("⚡ **可用工作流** (共 {} 个)\n\n", workflows.len()));
228                for (idx, info) in workflows.iter().enumerate() {
229                    output.push_str(&format!("{}. **{}** (`{}`)\n", idx + 1, info.name, info.id));
230                    if let Some(ref desc) = info.description {
231                        output.push_str(&format!("   {}\n", desc));
232                    }
233                    if !info.required_inputs.is_empty() {
234                        output.push_str(&format!("   需要输入: {}\n", info.required_inputs.join(", ")));
235                    }
236                    output.push('\n');
237                }
238                output.push_str("调用方式: 使用 workflow_run 工具,传入 workflow_id 和可选的 inputs 参数。\n");
239            }
240        } else {
241            output.push_str("⚡ **可用工作流**: 无项目路径\n");
242            output.push_str("\n提示:需要在项目目录下才能查看工作流。\n");
243        }
244        
245        let _ = ctx.event_tx.send(crate::AgentEvent::progress(output, None)).await;
246        false
247    }
248    
249    /// 显示配置信息(隐藏敏感信息)
250    async fn show_config(&self, ctx: &mut BackendContext<'_>) -> bool {
251        let mut output = String::new();
252        
253        output.push_str("⚙️  **配置信息**\n\n");
254        
255        // Provider 信息
256        if let Some(ref provider) = ctx.config.provider {
257            output.push_str(&format!("  • Provider: {}\n", provider));
258        } else {
259            output.push_str("  • Provider: anthropic (默认)\n");
260        }
261        
262        // Model 信息
263        if let Some(ref model) = ctx.config.model {
264            output.push_str(&format!("  • Model: {}\n", model));
265        } else {
266            output.push_str(&format!("  • Model: {} (默认)\n", ctx.model));
267        }
268        
269        // Base URL
270        if let Some(ref base_url) = ctx.config.base_url {
271            output.push_str(&format!("  • Base URL: {}\n", base_url));
272        }
273        
274        // API Key(隐藏)
275        if ctx.config.api_key.is_some() {
276            output.push_str("  • API Key: 已设置(已隐藏)\n");
277        } else {
278            output.push_str("  • API Key: 未设置\n");
279        }
280        
281        // 其他配置
282        output.push_str(&format!("  • Extended Thinking: {}\n", ctx.config.think));
283        output.push_str(&format!("  • Markdown Rendering: {}\n", ctx.config.markdown));
284        output.push_str(&format!("  • Max Tokens: {}\n", ctx.config.max_tokens));
285        
286        if let Some(ref context_size) = ctx.config.context_size {
287            output.push_str(&format!("  • Context Size: {}\n", context_size));
288        }
289        
290        // Approve Mode
291        if let Some(ref approve_mode) = ctx.config.approve_mode {
292            output.push_str(&format!("  • Approve Mode: {}\n", approve_mode));
293        }
294        
295        // Multi-model
296        if let Some(ref multi_model) = ctx.config.multi_model {
297            output.push_str(&format!("  • Multi-Model: {}\n", multi_model));
298        }
299        
300        if let Some(ref plan_model) = ctx.config.plan_model {
301            output.push_str(&format!("  • Plan Model: {}\n", plan_model));
302        }
303        
304        if let Some(ref compress_model) = ctx.config.compress_model {
305            output.push_str(&format!("  • Compress Model: {}\n", compress_model));
306        }
307        
308        if let Some(ref fast_model) = ctx.config.fast_model {
309            output.push_str(&format!("  • Fast Model: {}\n", fast_model));
310        }
311        
312        // MCP Servers
313        if let Some(ref mcp_servers) = ctx.config.mcp_servers {
314            if !mcp_servers.is_empty() {
315                output.push_str(&format!("\n  • MCP Servers: {} 个\n", mcp_servers.len()));
316                for (name, _config) in mcp_servers.iter().take(5) {
317                    output.push_str(&format!("    - {}\n", name));
318                }
319                if mcp_servers.len() > 5 {
320                    output.push_str(&format!("    ... 还有 {} 个\n", mcp_servers.len() - 5));
321                }
322            }
323        }
324        
325        // Config 路径
326        output.push_str("\n📁 **配置文件路径**\n");
327        if let Some(path) = crate::Config::matrix_config_path() {
328            output.push_str(&format!("  • Matrix Config: {:?}\n", path));
329        }
330        if let Some(path) = crate::Config::claude_settings_path() {
331            output.push_str(&format!("  • Claude Settings: {:?}\n", path));
332        }
333        
334        let _ = ctx.event_tx.send(crate::AgentEvent::progress(output, None)).await;
335        false
336    }
337    
338    /// 显示环境变量(隐藏敏感信息)
339    async fn show_env(&self, ctx: &mut BackendContext<'_>) -> bool {
340        let mut output = String::new();
341        
342        output.push_str("🌍 **环境变量**\n\n");
343        
344        // API 相关环境变量
345        let api_key = std::env::var("API_KEY").ok();
346        let anthropic_token = std::env::var("ANTHROPIC_AUTH_TOKEN").ok();
347        let base_url = std::env::var("BASE_URL").ok();
348        let anthropic_base = std::env::var("ANTHROPIC_BASE_URL").ok();
349        let model = std::env::var("MODEL").ok();
350        let anthropic_model = std::env::var("ANTHROPIC_MODEL").ok();
351        
352        // API Key(隐藏)
353        if api_key.is_some() || anthropic_token.is_some() {
354            output.push_str("  • API_KEY / ANTHROPIC_AUTH_TOKEN: 已设置(已隐藏)\n");
355        } else {
356            output.push_str("  • API_KEY / ANTHROPIC_AUTH_TOKEN: 未设置\n");
357        }
358        
359        // Base URL
360        if let Some(url) = base_url {
361            output.push_str(&format!("  • BASE_URL: {}\n", url));
362        } else if let Some(url) = anthropic_base {
363            output.push_str(&format!("  • ANTHROPIC_BASE_URL: {}\n", url));
364        } else {
365            output.push_str("  • BASE_URL: 未设置(使用默认)\n");
366        }
367        
368        // Model
369        if let Some(m) = model {
370            output.push_str(&format!("  • MODEL: {}\n", m));
371        } else if let Some(m) = anthropic_model {
372            output.push_str(&format!("  • ANTHROPIC_MODEL: {}\n", m));
373        } else {
374            output.push_str("  • MODEL: 未设置(使用配置或默认)\n");
375        }
376        
377        // 其他常用环境变量
378        let provider = std::env::var("PROVIDER").ok();
379        if let Some(p) = provider {
380            output.push_str(&format!("  • PROVIDER: {}\n", p));
381        }
382        
383        let max_tokens = std::env::var("MAX_TOKENS").ok();
384        if let Some(t) = max_tokens {
385            output.push_str(&format!("  • MAX_TOKENS: {}\n", t));
386        }
387        
388        let think = std::env::var("THINK").ok();
389        if let Some(t) = think {
390            output.push_str(&format!("  • THINK: {}\n", t));
391        }
392        
393        // 系统环境变量
394        output.push_str("\n💻 **系统环境**\n");
395        if let Ok(home) = std::env::var("HOME") {
396            output.push_str(&format!("  • HOME: {}\n", home));
397        } else if let Ok(userprofile) = std::env::var("USERPROFILE") {
398            output.push_str(&format!("  • USERPROFILE: {}\n", userprofile));
399        }
400        
401        if let Ok(pwd) = std::env::var("PWD") {
402            output.push_str(&format!("  • PWD: {}\n", pwd));
403        }
404        
405        if let Ok(path) = std::env::var("PATH") {
406            // 截断过长的 PATH
407            if path.len() > 100 {
408                output.push_str(&format!("  • PATH: {}... (已截断)\n", &path[..100]));
409            } else {
410                output.push_str(&format!("  • PATH: {}\n", path));
411            }
412        }
413        
414        // 优先级说明
415        output.push_str("\n📋 **配置优先级** (从高到低)\n");
416        output.push_str("  1. 环境变量 (API_KEY, BASE_URL, MODEL 等)\n");
417        output.push_str("  2. ~/.matrix/config.json (MatrixCode 配置)\n");
418        output.push_str("  3. ~/.claude/settings.json (Claude Code 配置)\n");
419        output.push_str("  4. 默认值\n");
420        
421        let _ = ctx.event_tx.send(crate::AgentEvent::progress(output, None)).await;
422        false
423    }
424    
425    /// 显示帮助
426    async fn show_help(&self, ctx: &mut BackendContext<'_>) -> bool {
427        let help = r#"🖥️  **/system 命令帮助**
428
429用法:
430  /system           显示完整系统信息(默认)
431  /system status    显示完整系统信息
432  /system prompt    仅显示 System Prompt
433  /system tools      仅显示工具列表(含描述)
434  /system stats      仅显示统计信息
435  /system skills     仅显示技能列表
436  /system workflows  仅显示工作流列表
437  /system config     仅显示配置信息(隐藏敏感信息)
438  /system env        仅显示环境变量(隐藏敏感信息)
439  /system help       显示此帮助信息
440
441说明:
442  - prompt: 查看发送给 LLM 的完整系统提示词
443  - tools: 查看所有可用工具及其描述
444  - stats: 查看运行时统计(Token、工具数、工作流数等)
445  - skills: 查看当前加载的技能
446  - workflows: 查看项目中的自动化工作流
447  - config: 查看当前配置(API Key 等敏感信息已隐藏)
448  - env: 查看环境变量(API Key 等敏感信息已隐藏)
449
450示例:
451  /system prompt    # 调试 Prompt 问题
452  /system config    # 检查配置是否正确
453  /system workflows # 查看可用的工作流
454"#;
455        
456        let _ = ctx.event_tx.send(crate::AgentEvent::progress(help.to_string(), None)).await;
457        false
458    }
459}