deepseek_rust_cli/agent/
ops.rs1use crate::agent::{agent::DeepSeekAgent, history::save_history};
2
3impl DeepSeekAgent {
4 pub fn save(&self) {
5 save_history(&self.session_id, &self.messages);
6 }
7
8 pub fn manage_context(&mut self) {
9 let max_chars = self.config.max_context_chars;
10 let mut current_chars: usize = self
11 .messages
12 .iter()
13 .map(|m| {
14 m.content.as_deref().unwrap_or("").len()
15 + m.reasoning_content.as_deref().unwrap_or("").len()
16 })
17 .sum();
18
19 while current_chars > max_chars && self.messages.len() > 1 {
20 let mut remove_count = 1;
21 let idx = 1;
22
23 if idx >= self.messages.len() {
24 break;
25 }
26
27 match self.messages[idx].role.as_str() {
28 "assistant" if self.messages[idx].tool_calls.is_some() => {
29 let mut j = idx + 1;
30 while j < self.messages.len() && self.messages[j].role == "tool" {
31 j += 1;
32 }
33 remove_count = j - idx;
34 }
35 "assistant" => {}
36 "tool" => {
37 let mut j = idx + 1;
38 while j < self.messages.len() && self.messages[j].role == "tool" {
39 j += 1;
40 }
41 let start = idx - 1;
42 remove_count = j - start;
43 let mut chars_removed = 0;
44 for _ in 0..remove_count {
45 if start < self.messages.len() {
46 let removed = self.messages.remove(start);
47 chars_removed += removed.content.as_deref().unwrap_or("").len()
48 + removed.reasoning_content.as_deref().unwrap_or("").len();
49 }
50 }
51 current_chars -= chars_removed;
52 continue;
53 }
54 _ => {}
55 }
56
57 let mut chars_removed = 0;
58 for _ in 0..remove_count {
59 if idx < self.messages.len() {
60 let removed = self.messages.remove(idx);
61 chars_removed += removed.content.as_deref().unwrap_or("").len()
62 + removed.reasoning_content.as_deref().unwrap_or("").len();
63 }
64 }
65 current_chars -= chars_removed;
66 }
67 }
68
69 pub fn undo(&mut self) -> String {
70 if let Some(action) = self.undo_stack.pop() {
71 while self.messages.len() > 1
72 && (self
73 .messages
74 .last()
75 .map(|m| m.role == "tool" || m.role == "assistant")
76 .unwrap_or(false))
77 {
78 self.messages.pop();
79 }
80
81 match action.r#type.as_str() {
82 "write" | "replace" | "delete" => {
83 if let Some(backup) = action.backup {
84 let _ = std::fs::write(&action.path, backup);
85 format!("✅ Undone {}: Restored {}", action.r#type, action.path)
86 } else if action.r#type == "write" || action.r#type == "replace" {
87 let _ = std::fs::remove_file(&action.path);
88 format!(
89 "✅ Undone {}: Deleted new file {}",
90 action.r#type, action.path
91 )
92 } else {
93 "❌ Undo failed: No backup available.".to_string()
94 }
95 }
96 "rename" => {
97 if let Some(backup) = action.backup {
98 let original_path = String::from_utf8_lossy(&backup).to_string();
99 let _ = std::fs::rename(&action.path, &original_path);
100 format!(
101 "✅ Undone rename: Moved {} back to {}",
102 action.path, original_path
103 )
104 } else {
105 "❌ Undo failed: No backup path available.".to_string()
106 }
107 }
108 _ => "❌ Undo failed: Unknown action type".to_string(),
109 }
110 } else {
111 "ℹ️ Undo stack is empty.".to_string()
112 }
113 }
114
115 pub fn cleanup_aborted_messages(&mut self) {
116 while self.messages.last().is_some_and(|m| m.role == "tool") {
117 self.messages.pop();
118 }
119 if self
120 .messages
121 .last()
122 .is_some_and(|m| m.role == "assistant" && m.tool_calls.is_some())
123 {
124 self.messages.pop();
125 }
126 }
127}