ceylon_next/memory/
file_store.rs1use super::{Memory, MemoryEntry};
7use async_trait::async_trait;
8use std::collections::HashMap;
9use std::fs;
10use std::io::{Read, Write};
11use std::path::PathBuf;
12use std::sync::{Arc, RwLock};
13
14#[derive(Debug, Clone, Copy)]
16pub enum StorageFormat {
17 Json,
19 MessagePack,
21}
22
23pub struct FileStore {
48 file_path: PathBuf,
49 format: StorageFormat,
50 entries: Arc<RwLock<HashMap<String, MemoryEntry>>>,
51 agent_index: Arc<RwLock<HashMap<String, Vec<String>>>>,
52}
53
54impl FileStore {
55 pub async fn new<P: Into<PathBuf>>(file_path: P, format: StorageFormat) -> Result<Self, String> {
73 let file_path = file_path.into();
74 let mut entries: HashMap<String, MemoryEntry> = HashMap::new();
75 let mut agent_index: HashMap<String, Vec<String>> = HashMap::new();
76
77 if file_path.exists() {
79 let mut file = fs::File::open(&file_path)
80 .map_err(|e| format!("Failed to open file: {}", e))?;
81
82 let mut buffer = Vec::new();
83 file.read_to_end(&mut buffer)
84 .map_err(|e| format!("Failed to read file: {}", e))?;
85
86 if !buffer.is_empty() {
87 entries = match format {
88 StorageFormat::Json => serde_json::from_slice(&buffer)
89 .map_err(|e| format!("Failed to deserialize JSON: {}", e))?,
90 StorageFormat::MessagePack => rmp_serde::from_slice(&buffer)
91 .map_err(|e| format!("Failed to deserialize MessagePack: {}", e))?,
92 };
93
94 for (entry_id, entry) in &entries {
96 agent_index
97 .entry(entry.agent_id.clone())
98 .or_insert_with(Vec::new)
99 .push(entry_id.clone());
100 }
101 }
102 }
103
104 Ok(Self {
105 file_path,
106 format,
107 entries: Arc::new(RwLock::new(entries)),
108 agent_index: Arc::new(RwLock::new(agent_index)),
109 })
110 }
111
112 pub fn file_path(&self) -> &PathBuf {
114 &self.file_path
115 }
116
117 pub fn format(&self) -> StorageFormat {
119 self.format
120 }
121
122 fn save_to_disk(&self) -> Result<(), String> {
124 let entries = self.entries.read().unwrap();
125
126 let serialized = match self.format {
127 StorageFormat::Json => serde_json::to_vec_pretty(&*entries)
128 .map_err(|e| format!("Failed to serialize to JSON: {}", e))?,
129 StorageFormat::MessagePack => rmp_serde::to_vec(&*entries)
130 .map_err(|e| format!("Failed to serialize to MessagePack: {}", e))?,
131 };
132
133 let mut file = fs::File::create(&self.file_path)
134 .map_err(|e| format!("Failed to create file: {}", e))?;
135
136 file.write_all(&serialized)
137 .map_err(|e| format!("Failed to write to file: {}", e))?;
138
139 Ok(())
140 }
141}
142
143#[async_trait]
144impl Memory for FileStore {
145 async fn store(&self, entry: MemoryEntry) -> Result<String, String> {
146 let entry_id = entry.id.clone();
147 let agent_id = entry.agent_id.clone();
148
149 {
151 let mut entries = self.entries.write().unwrap();
152 entries.insert(entry_id.clone(), entry);
153 }
154
155 {
157 let mut index = self.agent_index.write().unwrap();
158 index
159 .entry(agent_id)
160 .or_insert_with(Vec::new)
161 .push(entry_id.clone());
162 }
163
164 self.save_to_disk()?;
166
167 Ok(entry_id)
168 }
169
170 async fn get(&self, id: &str) -> Result<Option<MemoryEntry>, String> {
171 let entries = self.entries.read().unwrap();
172 Ok(entries.get(id).cloned())
173 }
174
175 async fn get_agent_history(&self, agent_id: &str) -> Result<Vec<MemoryEntry>, String> {
176 let index = self.agent_index.read().unwrap();
177 let entries = self.entries.read().unwrap();
178
179 let entry_ids = index.get(agent_id);
180
181 if entry_ids.is_none() {
182 return Ok(Vec::new());
183 }
184
185 let mut result = Vec::new();
186 for entry_id in entry_ids.unwrap() {
187 if let Some(entry) = entries.get(entry_id) {
188 result.push(entry.clone());
189 }
190 }
191
192 result.sort_by(|a, b| b.created_at.cmp(&a.created_at));
194
195 Ok(result)
196 }
197
198 async fn get_recent(&self, agent_id: &str, limit: usize) -> Result<Vec<MemoryEntry>, String> {
199 let mut history = self.get_agent_history(agent_id).await?;
200 history.truncate(limit);
201 Ok(history)
202 }
203
204 async fn search(&self, agent_id: &str, query: &str) -> Result<Vec<MemoryEntry>, String> {
205 let history = self.get_agent_history(agent_id).await?;
206 let query_lower = query.to_lowercase();
207
208 let results: Vec<MemoryEntry> = history
209 .into_iter()
210 .filter(|entry| {
211 entry
212 .messages
213 .iter()
214 .any(|msg| msg.content.to_lowercase().contains(&query_lower))
215 })
216 .collect();
217
218 Ok(results)
219 }
220
221 async fn clear_agent_memory(&self, agent_id: &str) -> Result<(), String> {
222 let index = self.agent_index.read().unwrap();
223 let entry_ids = index.get(agent_id);
224
225 if let Some(ids) = entry_ids {
226 let mut entries = self.entries.write().unwrap();
227 for id in ids {
228 entries.remove(id);
229 }
230 }
231
232 let mut index = self.agent_index.write().unwrap();
233 index.remove(agent_id);
234
235 drop(index); self.save_to_disk()?;
238
239 Ok(())
240 }
241}