stynx_code_compact/
session_memory_compact.rs1use stynx_code_types::{ContentBlock, Conversation};
2use regex::Regex;
3
4pub struct SessionMemoryCompactor;
5
6impl Default for SessionMemoryCompactor {
7 fn default() -> Self {
8 Self
9 }
10}
11
12impl SessionMemoryCompactor {
13 pub fn new() -> Self {
14 Self
15 }
16
17 pub fn extract_and_compact(
18 &self,
19 conversation: &Conversation,
20 ) -> (Vec<String>, Conversation) {
21 let mut memories = Vec::new();
22
23 for msg in &conversation.messages {
24 for block in &msg.content {
25 match block {
26 ContentBlock::Text { text } => {
27 self.extract_memories_from_text(text, &mut memories);
28 }
29 ContentBlock::ToolResult { content, is_error, .. } => {
30
31 if *is_error == Some(true) {
32 let preview = if content.len() > 200 {
33 format!("{}...", &content[..200])
34 } else {
35 content.clone()
36 };
37 memories.push(format!("Error encountered: {preview}"));
38 }
39
40 self.extract_file_paths(content, &mut memories);
41 }
42 _ => {}
43 }
44 }
45 }
46
47 memories.dedup();
48
49 (memories, conversation.clone())
50 }
51
52 fn extract_memories_from_text(&self, text: &str, memories: &mut Vec<String>) {
53
54 let decision_patterns = [
55 "I decided to",
56 "The solution is",
57 "We agreed to",
58 "The approach is",
59 "The fix is",
60 "The issue was",
61 "The problem was",
62 "The root cause",
63 ];
64
65 for line in text.lines() {
66 let trimmed = line.trim();
67 for pattern in &decision_patterns {
68 if trimmed.contains(pattern) {
69 let memory = if trimmed.len() > 200 {
70 format!("{}...", &trimmed[..200])
71 } else {
72 trimmed.to_string()
73 };
74 memories.push(memory);
75 break;
76 }
77 }
78 }
79
80 self.extract_file_paths(text, memories);
81 }
82
83 fn extract_file_paths(&self, text: &str, memories: &mut Vec<String>) {
84 let path_re = Regex::new(r#"(?:^|[\s"'`(])(/[\w./-]+\.\w+)"#).unwrap();
85 for cap in path_re.captures_iter(text) {
86 if let Some(path) = cap.get(1) {
87 let p = path.as_str();
88
89 if p.len() > 3 && !p.starts_with("//") {
90 memories.push(format!("File: {p}"));
91 }
92 }
93 }
94 }
95}