1use std::collections::HashMap;
5use std::fs;
6use std::path::Path;
7
8#[derive(Clone, Debug)]
9pub struct Fact {
10 pub statement: String,
11 pub confidence: f32, pub source: String,
13 pub timestamp_ms: u64,
14 pub access_count: u32,
15 pub verified: bool,
16}
17
18#[derive(Clone, Debug)]
19pub struct Concept {
20 pub name: String,
21 pub definition: String,
22 pub examples: Vec<String>,
23 pub related_concepts: Vec<String>,
24 pub abstraction_level: f32, }
26
27#[derive(Clone, Debug)]
28pub struct Event {
29 pub description: String,
30 pub timestamp_ms: u64,
31 pub participants: Vec<String>,
32 pub location: String,
33 pub emotional_significance: f32,
34 pub detail_level: f32, }
36
37pub struct ExplicitMemory {
38 pub facts: HashMap<String, Fact>,
39 pub concepts: HashMap<String, Concept>,
40 pub events: Vec<Event>,
41 pub relationships: HashMap<String, Vec<String>>, }
43
44impl Default for ExplicitMemory {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl ExplicitMemory {
51 pub fn new() -> Self {
52 Self {
53 facts: HashMap::new(),
54 concepts: HashMap::new(),
55 events: Vec::new(),
56 relationships: HashMap::new(),
57 }
58 }
59
60 pub fn store_fact(&mut self, statement: &str, source: &str, confidence: f32) {
62 let key = statement.to_lowercase();
63 self.facts
64 .entry(key.clone())
65 .and_modify(|f| {
66 f.access_count += 1;
67 f.confidence = (f.confidence + confidence) / 2.0;
68 })
69 .or_insert_with(|| Fact {
70 statement: statement.to_string(),
71 confidence: confidence.clamp(0.0, 1.0),
72 source: source.to_string(),
73 timestamp_ms: Self::now_ms(),
74 access_count: 1,
75 verified: confidence > 0.8,
76 });
77 }
78
79 pub fn define_concept(&mut self, name: &str, definition: &str, abstraction: f32) {
81 self.concepts.insert(
82 name.to_lowercase(),
83 Concept {
84 name: name.to_string(),
85 definition: definition.to_string(),
86 examples: Vec::new(),
87 related_concepts: Vec::new(),
88 abstraction_level: abstraction.clamp(0.0, 1.0),
89 },
90 );
91 }
92
93 pub fn add_example(&mut self, concept: &str, example: &str) {
95 if let Some(c) = self.concepts.get_mut(&concept.to_lowercase()) {
96 c.examples.push(example.to_string());
97 }
98 }
99
100 pub fn record_event(&mut self, description: &str, location: &str, emotional_sig: f32) {
102 self.events.push(Event {
103 description: description.to_string(),
104 timestamp_ms: Self::now_ms(),
105 participants: Vec::new(),
106 location: location.to_string(),
107 emotional_significance: emotional_sig.clamp(0.0, 1.0),
108 detail_level: 0.5,
109 });
110 }
111
112 pub fn relate_concepts(&mut self, concept1: &str, concept2: &str) {
114 let key1 = concept1.to_lowercase();
115 let key2 = concept2.to_lowercase();
116
117 self.relationships
118 .entry(key1.clone())
119 .or_default()
120 .push(key2.clone());
121
122 self.relationships.entry(key2).or_default().push(key1);
123 }
124
125 pub fn recall_fact(&mut self, statement: &str) -> Option<(String, f32)> {
127 let key = statement.to_lowercase();
128 if let Some(fact) = self.facts.get_mut(&key) {
129 fact.access_count += 1;
130 return Some((fact.statement.clone(), fact.confidence));
131 }
132 None
133 }
134
135 pub fn get_concept(&self, name: &str) -> Option<&Concept> {
137 self.concepts.get(&name.to_lowercase())
138 }
139
140 pub fn high_confidence_facts(&self, min_confidence: f32) -> Vec<&Fact> {
142 let mut facts: Vec<_> = self
143 .facts
144 .values()
145 .filter(|f| f.confidence >= min_confidence)
146 .collect();
147 facts.sort_by(|a, b| b.confidence.total_cmp(&a.confidence));
148 facts
149 }
150
151 pub fn recent_events(&self, count: usize) -> Vec<&Event> {
153 let mut events = self.events.iter().collect::<Vec<_>>();
154 events.sort_by_key(|b| std::cmp::Reverse(b.timestamp_ms));
155 events.into_iter().take(count).collect()
156 }
157
158 pub fn save(&self, dir: &Path) -> Result<(), String> {
159 let path = dir.join("explicit_memory.bin");
160 let mut data = Vec::new();
161
162 data.extend_from_slice(b"EXPL");
163 data.push(1);
164
165 let fact_count = self.facts.len() as u32;
167 data.extend_from_slice(&fact_count.to_le_bytes());
168 for fact in self.facts.values() {
169 let stmt_bytes = fact.statement.as_bytes();
170 data.extend_from_slice(&(stmt_bytes.len() as u16).to_le_bytes());
171 data.extend_from_slice(stmt_bytes);
172 data.extend_from_slice(&fact.confidence.to_le_bytes());
173 let src_bytes = fact.source.as_bytes();
174 data.push(src_bytes.len() as u8);
175 data.extend_from_slice(src_bytes);
176 data.extend_from_slice(&fact.timestamp_ms.to_le_bytes());
177 data.extend_from_slice(&fact.access_count.to_le_bytes());
178 data.push(fact.verified as u8);
179 }
180
181 let concept_count = self.concepts.len() as u32;
183 data.extend_from_slice(&concept_count.to_le_bytes());
184 for concept in self.concepts.values() {
185 let name_bytes = concept.name.as_bytes();
186 data.push(name_bytes.len() as u8);
187 data.extend_from_slice(name_bytes);
188 let def_bytes = concept.definition.as_bytes();
189 data.extend_from_slice(&(def_bytes.len() as u16).to_le_bytes());
190 data.extend_from_slice(def_bytes);
191 data.extend_from_slice(&concept.abstraction_level.to_le_bytes());
192
193 let ex_count = concept.examples.len() as u8;
194 data.push(ex_count);
195 for example in &concept.examples {
196 let ex_bytes = example.as_bytes();
197 data.extend_from_slice(&(ex_bytes.len() as u16).to_le_bytes());
198 data.extend_from_slice(ex_bytes);
199 }
200 }
201
202 let event_count = self.events.len() as u32;
204 data.extend_from_slice(&event_count.to_le_bytes());
205 for event in &self.events {
206 let desc_bytes = event.description.as_bytes();
207 data.extend_from_slice(&(desc_bytes.len() as u16).to_le_bytes());
208 data.extend_from_slice(desc_bytes);
209 data.extend_from_slice(&event.timestamp_ms.to_le_bytes());
210 let loc_bytes = event.location.as_bytes();
211 data.push(loc_bytes.len() as u8);
212 data.extend_from_slice(loc_bytes);
213 data.extend_from_slice(&event.emotional_significance.to_le_bytes());
214 data.extend_from_slice(&event.detail_level.to_le_bytes());
215 }
216
217 let tmp_path = dir.join("explicit_memory.bin.tmp");
218 fs::write(&tmp_path, data).map_err(|e| e.to_string())?;
219 fs::rename(&tmp_path, &path).map_err(|e| e.to_string())
220 }
221
222 pub fn load(dir: &Path) -> Result<Self, String> {
223 let path = dir.join("explicit_memory.bin");
224 if !path.exists() {
225 return Ok(Self::new());
226 }
227
228 let data = fs::read(&path).map_err(|e| e.to_string())?;
229 if data.len() < 5 || &data[0..4] != b"EXPL" {
230 return Ok(Self::new());
231 }
232
233 let mut idx = 5;
234 let mut facts = HashMap::new();
235 let mut concepts = HashMap::new();
236 let events = Vec::new();
237
238 if idx + 4 <= data.len() {
240 let fact_count =
241 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]])
242 as usize;
243 idx += 4;
244
245 for _ in 0..fact_count {
246 if idx + 2 > data.len() {
247 break;
248 }
249 let stmt_len = u16::from_le_bytes([data[idx], data[idx + 1]]) as usize;
250 idx += 2;
251
252 if idx + stmt_len > data.len() {
253 break;
254 }
255 let statement = String::from_utf8_lossy(&data[idx..idx + stmt_len]).to_string();
256 idx += stmt_len;
257
258 if idx + 4 > data.len() {
259 break;
260 }
261 let confidence =
262 f32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
263 idx += 4;
264
265 if idx >= data.len() {
266 break;
267 }
268 let src_len = data[idx] as usize;
269 idx += 1;
270
271 if idx + src_len > data.len() {
272 break;
273 }
274 let source = String::from_utf8_lossy(&data[idx..idx + src_len]).to_string();
275 idx += src_len;
276
277 if idx + 13 > data.len() {
278 break;
279 }
280 let timestamp_ms = u64::from_le_bytes([
281 data[idx],
282 data[idx + 1],
283 data[idx + 2],
284 data[idx + 3],
285 data[idx + 4],
286 data[idx + 5],
287 data[idx + 6],
288 data[idx + 7],
289 ]);
290 idx += 8;
291
292 let access_count =
293 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
294 idx += 4;
295
296 let verified = data[idx] != 0;
297 idx += 1;
298
299 facts.insert(
300 statement.to_lowercase(),
301 Fact {
302 statement,
303 confidence,
304 source,
305 timestamp_ms,
306 access_count,
307 verified,
308 },
309 );
310 }
311 }
312
313 if idx + 4 <= data.len() {
315 let concept_count =
316 u32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]])
317 as usize;
318 idx += 4;
319
320 for _ in 0..concept_count {
321 if idx >= data.len() {
322 break;
323 }
324 let name_len = data[idx] as usize;
325 idx += 1;
326
327 if idx + name_len + 6 > data.len() {
328 break;
329 }
330 let name = String::from_utf8_lossy(&data[idx..idx + name_len]).to_string();
331 idx += name_len;
332
333 let def_len = u16::from_le_bytes([data[idx], data[idx + 1]]) as usize;
334 idx += 2;
335
336 if idx + def_len > data.len() {
337 break;
338 }
339 let definition = String::from_utf8_lossy(&data[idx..idx + def_len]).to_string();
340 idx += def_len;
341
342 if idx + 4 > data.len() {
343 break;
344 }
345 let abstraction_level =
346 f32::from_le_bytes([data[idx], data[idx + 1], data[idx + 2], data[idx + 3]]);
347 idx += 4;
348
349 concepts.insert(
350 name.clone(),
351 Concept {
352 name,
353 definition,
354 examples: Vec::new(),
355 related_concepts: Vec::new(),
356 abstraction_level,
357 },
358 );
359 }
360 }
361
362 Ok(Self {
363 facts,
364 concepts,
365 events,
366 relationships: HashMap::new(),
367 })
368 }
369
370 pub fn load_or_init(dir: &Path) -> Self {
371 Self::load(dir).unwrap_or_else(|_| Self::new())
372 }
373
374 fn now_ms() -> u64 {
375 std::time::SystemTime::now()
376 .duration_since(std::time::UNIX_EPOCH)
377 .unwrap_or_default()
378 .as_millis() as u64
379 }
380}