Skip to main content

matrixcode_core/command/handlers/
context.rs

1//! /context 命令处理器
2//!
3//! 显示当前上下文信息,包括即将发送给大模型的完整内容预览。
4
5use std::future::Future;
6use std::pin::Pin;
7
8use crate::command::{BackendContext, Command};
9use crate::AgentEvent;
10
11pub struct Context;
12
13impl Command for Context {
14    fn name(&self) -> &'static str {
15        "context"
16    }
17
18    fn aliases(&self) -> &[&'static str] {
19        &["ctx"]
20    }
21
22    fn help(&self) -> Option<&'static str> {
23        Some("显示当前上下文信息(消息、记忆、焦点等)")
24    }
25
26    fn execute<'a>(
27        &'a self,
28        ctx: &'a mut BackendContext<'_>,
29    ) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
30        Box::pin(async move {
31            let msg = ctx.message.trim();
32
33            if msg == "/context" || msg == "/context status" || msg == "/ctx" {
34                self.show_status(ctx).await
35            } else if msg == "/context full" || msg == "/ctx full" {
36                self.show_full_preview(ctx).await
37            } else if msg == "/context messages" || msg == "/ctx messages" {
38                self.show_messages(ctx).await
39            } else if msg == "/context memory" || msg == "/ctx memory" {
40                self.show_memory(ctx).await
41            } else if msg == "/context focus" || msg == "/ctx focus" {
42                self.show_focus(ctx).await
43            } else {
44                let _ = ctx
45                    .event_tx
46                    .send(AgentEvent::progress(
47                        "用法:/context [status|full|messages|memory|focus]\n\
48                         别名:/ctx\n\
49                         - status: 显示上下文状态概览\n\
50                         - full: 显示完整上下文预览\n\
51                         - messages: 显示消息列表\n\
52                         - memory: 显示记忆信息\n\
53                         - focus: 显示焦点信息".to_string(),
54                        None,
55                    ))
56                    .await;
57                false
58            }
59        })
60    }
61}
62
63impl Context {
64    /// Show context status overview
65    async fn show_status(&self, ctx: &mut BackendContext<'_>) -> bool {
66        let info = ctx.agent.get_context_info();
67
68        let mut output = String::new();
69        output.push_str("📊 **上下文状态**\n\n");
70
71        // Basic stats
72        output.push_str(&format!("**模型**: {}\n", info.model_name));
73        output.push_str(&format!("**消息数量**: {}\n", info.message_count));
74        output.push_str(&format!("**估算输入 tokens**: ~{}\n", info.estimated_input_tokens));
75        output.push_str(&format!("**累计输入 tokens**: {}\n", info.total_input_tokens));
76        output.push_str(&format!("**累计输出 tokens**: {}\n", info.total_output_tokens));
77        output.push_str(&format!("**最大 tokens 设置**: {}\n\n", info.max_tokens));
78
79        // System prompt preview
80        output.push_str("**系统提示预览**:\n");
81        output.push_str(&format!("> {}...\n\n",
82            truncate_string(&info.system_prompt_preview, 200)));
83
84        // Memory
85        if let Some(memory) = &info.memory_summary {
86            output.push_str("**记忆摘要**: ✅ 已加载\n");
87            output.push_str(&format!("> {}...\n\n", truncate_string(memory, 100)));
88        } else {
89            output.push_str("**记忆摘要**: ❌ 未加载\n\n");
90        }
91
92        // Project overview
93        if let Some(overview) = &info.project_overview_preview {
94            output.push_str("**项目概述**: ✅ 已加载\n");
95            output.push_str(&format!("> {}...\n\n", truncate_string(overview, 100)));
96        } else {
97            output.push_str("**项目概述**: ❌ 未加载\n\n");
98        }
99
100        // Recent messages
101        output.push_str("**最近 5 条消息**:\n");
102        for msg_preview in &info.recent_messages_preview {
103            output.push_str(&format!("  {}\n", msg_preview));
104        }
105
106        // Memory storage status
107        if let Some(storage) = &ctx.memory_storage {
108            output.push_str("\n**记忆存储**: ✅ 已初始化\n");
109        } else {
110            output.push_str("\n**记忆存储**: ❌ 未初始化\n");
111        }
112
113        // Session info
114        if let Some(session_mgr) = &ctx.session_mgr {
115            if session_mgr.has_current() {
116                if let Some(current) = session_mgr.current_id() {
117                    output.push_str(&format!("\n**当前会话**: {}\n",
118                        truncate_string(current, 20)));
119                }
120            } else {
121                output.push_str("\n**当前会话**: 新会话\n");
122            }
123        }
124
125        let _ = ctx
126            .event_tx
127            .send(AgentEvent::progress(output, None))
128            .await;
129
130        false
131    }
132
133    /// Show full context preview (everything sent to LLM)
134    async fn show_full_preview(&self, ctx: &mut BackendContext<'_>) -> bool {
135        let preview = ctx.agent.get_full_context_preview();
136
137        // Calculate total length
138        let total_chars = preview.chars().count();
139        let estimated_tokens = total_chars / 3; // rough estimate
140
141        let output = format!(
142            "📄 **完整上下文预览** ({} 字符, ~{} tokens)\n\n```text\n{}\n```",
143            total_chars,
144            estimated_tokens,
145            preview
146        );
147
148        let _ = ctx
149            .event_tx
150            .send(AgentEvent::progress(output, None))
151            .await;
152
153        false
154    }
155
156    /// Show message list
157    async fn show_messages(&self, ctx: &mut BackendContext<'_>) -> bool {
158        let info = ctx.agent.get_context_info();
159
160        let mut output = String::new();
161        output.push_str(&format!("📨 **消息列表** (共 {} 条)\n\n", info.message_count));
162
163        for msg_preview in &info.recent_messages_preview {
164            output.push_str(&format!("{}\n", msg_preview));
165        }
166
167        if info.message_count > 5 {
168            output.push_str(&format!("\n... 还有 {} 条较早消息", info.message_count - 5));
169        }
170
171        let _ = ctx
172            .event_tx
173            .send(AgentEvent::progress(output, None))
174            .await;
175
176        false
177    }
178
179    /// Show memory information
180    async fn show_memory(&self, ctx: &mut BackendContext<'_>) -> bool {
181        let info = ctx.agent.get_context_info();
182
183        let mut output = String::new();
184        output.push_str("🧠 **记忆信息**\n\n");
185
186        if let Some(memory) = &info.memory_summary {
187            output.push_str("**已加载记忆摘要**:\n");
188            output.push_str(&format!("{}\n", memory));
189        } else {
190            output.push_str("**未加载记忆摘要**\n");
191        }
192
193        // Memory storage details
194        if let Some(storage) = &ctx.memory_storage {
195            output.push_str("\n**记忆存储状态**:\n");
196            output.push_str("  ✅ 已初始化\n");
197            // Could add more details here if needed
198        } else {
199            output.push_str("\n**记忆存储状态**: ❌ 未初始化\n");
200        }
201
202        let _ = ctx
203            .event_tx
204            .send(AgentEvent::progress(output, None))
205            .await;
206
207        false
208    }
209
210    /// Show focus information
211    async fn show_focus(&self, ctx: &mut BackendContext<'_>) -> bool {
212        let mut output = String::new();
213        output.push_str("🎯 **焦点信息**\n\n");
214
215        // Check if agent has focus manager (via memory storage)
216        // Focus information is typically in the memory summary
217        let info = ctx.agent.get_context_info();
218
219        if let Some(memory) = &info.memory_summary {
220            // Extract focus-related info from memory
221            if memory.contains("焦点") || memory.contains("focus") {
222                output.push_str("**焦点状态**: ✅ 已跟踪\n");
223                output.push_str(&format!("{}\n", memory));
224            } else {
225                output.push_str("**焦点状态**: 信息在记忆摘要中\n");
226                output.push_str(&format!("{}\n", memory));
227            }
228        } else {
229            output.push_str("**焦点状态**: ❌ 无焦点信息\n");
230        }
231
232        // Note: FocusManager is not directly accessible from BackendContext
233        // This shows what's available through the memory system
234
235        output.push_str("\n**提示**: 焦点信息会随记忆一起发送给大模型\n");
236        output.push_str("使用 `/context full` 可查看完整上下文\n");
237
238        let _ = ctx
239            .event_tx
240            .send(AgentEvent::progress(output, None))
241            .await;
242
243        false
244    }
245}
246
247/// Helper function to truncate string
248fn truncate_string(s: &str, max: usize) -> String {
249    if s.chars().count() <= max {
250        s.to_string()
251    } else {
252        let truncated: String = s.chars().take(max).collect();
253        format!("{}...", truncated)
254    }
255}