Skip to main content

memrec_common/types/
memory.rs

1use serde::{Deserialize, Serialize};
2use chrono::{DateTime, Utc};
3use std::collections::HashMap;
4use uuid::Uuid;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "lowercase")]
8#[derive(Default)]
9pub enum MemoryType {
10    #[default]
11    Conversation,
12    Knowledge,
13    Decision,
14    Preference,
15    Context,
16}
17
18
19impl std::fmt::Display for MemoryType {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        match self {
22            MemoryType::Conversation => write!(f, "conversation"),
23            MemoryType::Knowledge => write!(f, "knowledge"),
24            MemoryType::Decision => write!(f, "decision"),
25            MemoryType::Preference => write!(f, "preference"),
26            MemoryType::Context => write!(f, "context"),
27        }
28    }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct Memory {
33    pub id: Uuid,
34    pub memory_type: MemoryType,
35    pub content: String,
36    pub summary: Option<String>,
37    pub embedding: Option<Vec<f32>>,
38    pub importance: f32,
39    pub created_at: DateTime<Utc>,
40    pub last_accessed: DateTime<Utc>,
41    pub access_count: u32,
42    pub tags: Vec<String>,
43    pub metadata: HashMap<String, String>,
44    pub project_id: Option<Uuid>,
45    pub is_deleted: bool,
46    pub deleted_at: Option<DateTime<Utc>>,
47    
48    pub chunk_group_id: Option<Uuid>,
49    pub chunk_index: Option<u32>,
50    pub chunk_total: Option<u32>,
51}
52
53impl Memory {
54    pub fn new(content: String, memory_type: MemoryType) -> Self {
55        let now = Utc::now();
56        Self {
57            id: Uuid::new_v4(),
58            memory_type,
59            content,
60            summary: None,
61            embedding: None,
62            importance: 0.8,
63            created_at: now,
64            last_accessed: now,
65            access_count: 0,
66            tags: Vec::new(),
67            metadata: HashMap::new(),
68            project_id: None,
69            is_deleted: false,
70            deleted_at: None,
71            chunk_group_id: None,
72            chunk_index: None,
73            chunk_total: None,
74        }
75    }
76    
77    pub fn with_tags(mut self, tags: Vec<String>) -> Self {
78        self.tags = tags;
79        self
80    }
81    
82    pub fn with_project(mut self, project_id: Uuid) -> Self {
83        self.project_id = Some(project_id);
84        self
85    }
86    
87    pub fn with_chunk_info(mut self, group_id: Uuid, index: u32, total: u32) -> Self {
88        self.chunk_group_id = Some(group_id);
89        self.chunk_index = Some(index);
90        self.chunk_total = Some(total);
91        self
92    }
93    
94    pub fn access(&mut self) {
95        self.last_accessed = Utc::now();
96        self.access_count += 1;
97    }
98    
99    pub fn is_chunked(&self) -> bool {
100        self.chunk_group_id.is_some()
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    
108    #[test]
109    fn test_memory_type_serde() {
110        let types = [
111            MemoryType::Conversation,
112            MemoryType::Knowledge,
113            MemoryType::Decision,
114            MemoryType::Preference,
115            MemoryType::Context,
116        ];
117        
118        for t in types {
119            let json = serde_json::to_string(&t).unwrap();
120            let parsed: MemoryType = serde_json::from_str(&json).unwrap();
121            assert_eq!(t, parsed);
122        }
123    }
124    
125    #[test]
126    fn test_memory_type_json_values() {
127        assert_eq!(serde_json::to_string(&MemoryType::Conversation).unwrap(), "\"conversation\"");
128        assert_eq!(serde_json::to_string(&MemoryType::Knowledge).unwrap(), "\"knowledge\"");
129    }
130    
131    #[test]
132    fn test_memory_creation() {
133        let memory = Memory::new("test content".to_string(), MemoryType::Knowledge);
134        
135        assert!(!memory.id.to_string().is_empty());
136        assert_eq!(memory.memory_type, MemoryType::Knowledge);
137        assert_eq!(memory.content, "test content");
138        assert!(memory.embedding.is_none());
139        assert_eq!(memory.importance, 0.8);
140        assert_eq!(memory.access_count, 0);
141        assert!(memory.tags.is_empty());
142        assert!(!memory.is_deleted);
143    }
144    
145    #[test]
146    fn test_memory_with_tags() {
147        let memory = Memory::new("test".to_string(), MemoryType::Decision)
148            .with_tags(vec!["important".to_string(), "project-x".to_string()]);
149        
150        assert_eq!(memory.tags.len(), 2);
151        assert!(memory.tags.contains(&"important".to_string()));
152    }
153    
154    #[test]
155    fn test_memory_access() {
156        let mut memory = Memory::new("test".to_string(), MemoryType::Conversation);
157        let initial_accessed = memory.last_accessed;
158        
159        memory.access();
160        
161        assert!(memory.last_accessed > initial_accessed);
162        assert_eq!(memory.access_count, 1);
163    }
164    
165    #[test]
166    fn test_memory_serde() {
167        let memory = Memory::new("test content".to_string(), MemoryType::Knowledge)
168            .with_tags(vec!["tag1".to_string()]);
169        
170        let json = serde_json::to_string(&memory).unwrap();
171        let parsed: Memory = serde_json::from_str(&json).unwrap();
172        
173        assert_eq!(memory.id, parsed.id);
174        assert_eq!(memory.content, parsed.content);
175        assert_eq!(memory.tags, parsed.tags);
176    }
177    
178    #[test]
179    fn test_memory_chunk_fields() {
180        let group_id = Uuid::new_v4();
181        let memory = Memory::new("test".to_string(), MemoryType::Knowledge)
182            .with_chunk_info(group_id, 0, 3);
183        
184        assert_eq!(memory.chunk_group_id, Some(group_id));
185        assert_eq!(memory.chunk_index, Some(0));
186        assert_eq!(memory.chunk_total, Some(3));
187        assert!(memory.is_chunked());
188    }
189    
190    #[test]
191    fn test_memory_chunk_serde() {
192        let group_id = Uuid::new_v4();
193        let memory = Memory::new("test".to_string(), MemoryType::Knowledge)
194            .with_chunk_info(group_id, 1, 5);
195        
196        let json = serde_json::to_string(&memory).unwrap();
197        let parsed: Memory = serde_json::from_str(&json).unwrap();
198        
199        assert_eq!(memory.chunk_group_id, parsed.chunk_group_id);
200        assert_eq!(memory.chunk_index, parsed.chunk_index);
201        assert_eq!(memory.chunk_total, parsed.chunk_total);
202    }
203}