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