Skip to main content

deepseek_rust_cli/agent/
ops.rs

1use 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}