matrixcode_core/command/handlers/
system.rs1use 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 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 async fn show_full(&self, ctx: &mut BackendContext<'_>) -> bool {
59 let mut output = String::new();
60
61 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 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 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 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 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 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 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 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 async fn show_stats(&self, ctx: &mut BackendContext<'_>) -> bool {
162 let mut output = String::new();
163
164 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 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 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 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 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 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 async fn show_config(&self, ctx: &mut BackendContext<'_>) -> bool {
251 let mut output = String::new();
252
253 output.push_str("⚙️ **配置信息**\n\n");
254
255 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 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 if let Some(ref base_url) = ctx.config.base_url {
271 output.push_str(&format!(" • Base URL: {}\n", base_url));
272 }
273
274 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 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 if let Some(ref approve_mode) = ctx.config.approve_mode {
292 output.push_str(&format!(" • Approve Mode: {}\n", approve_mode));
293 }
294
295 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 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 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 async fn show_env(&self, ctx: &mut BackendContext<'_>) -> bool {
340 let mut output = String::new();
341
342 output.push_str("🌍 **环境变量**\n\n");
343
344 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 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 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 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 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 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 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 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 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}