Skip to main content

mentedb_core/
memory.rs

1//! MemoryNode: the fundamental unit of storage in MenteDB.
2
3use serde::{Deserialize, Serialize};
4
5use crate::types::*;
6use crate::types::{AgentId, MemoryId, SpaceId};
7
8/// The type classification of a memory.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum MemoryType {
11    /// A specific event or interaction.
12    Episodic,
13    /// A general fact or concept.
14    Semantic,
15    /// A learned skill or procedure.
16    Procedural,
17    /// What NOT to do: learned from failures.
18    AntiPattern,
19    /// A pre-computed reasoning chain or decision template.
20    Reasoning,
21    /// A correction record: "was X, actually Y because Z".
22    Correction,
23}
24
25/// A memory node: the atomic unit of knowledge in MenteDB.
26///
27/// Combines vector embeddings, graph connections, temporal properties,
28/// and flexible attributes in a single primitive.
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct MemoryNode {
31    /// Unique identifier.
32    pub id: MemoryId,
33    /// The agent that owns this memory.
34    pub agent_id: AgentId,
35    /// Memory type classification.
36    pub memory_type: MemoryType,
37    /// Embedding vector for semantic similarity search.
38    pub embedding: Embedding,
39    /// Human-readable content.
40    pub content: String,
41    /// When this memory was created.
42    pub created_at: Timestamp,
43    /// When this memory was last accessed.
44    pub accessed_at: Timestamp,
45    /// How many times this memory has been accessed.
46    pub access_count: u32,
47    /// Current salience score (decays over time).
48    pub salience: Salience,
49    /// Confidence in this memory's accuracy.
50    pub confidence: Confidence,
51    /// The memory space this belongs to.
52    pub space_id: SpaceId,
53    /// Flexible key-value attributes.
54    pub attributes: std::collections::HashMap<String, AttributeValue>,
55    /// Tags for bitmap indexing.
56    pub tags: Vec<String>,
57    /// When this fact became true in the real world.
58    /// None means valid since creation.
59    #[serde(default, skip_serializing_if = "Option::is_none")]
60    pub valid_from: Option<Timestamp>,
61    /// When this fact stopped being true.
62    /// None means still valid.
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub valid_until: Option<Timestamp>,
65}
66
67impl MemoryNode {
68    /// Create a new memory node with the given content and embedding.
69    pub fn new(
70        agent_id: AgentId,
71        memory_type: MemoryType,
72        content: String,
73        embedding: Embedding,
74    ) -> Self {
75        let now = std::time::SystemTime::now()
76            .duration_since(std::time::UNIX_EPOCH)
77            .unwrap_or_default()
78            .as_micros() as u64;
79
80        Self {
81            id: MemoryId::new(),
82            agent_id,
83            memory_type,
84            embedding,
85            content,
86            created_at: now,
87            accessed_at: now,
88            access_count: 0,
89            salience: 1.0,
90            confidence: 1.0,
91            space_id: SpaceId::nil(),
92            attributes: std::collections::HashMap::new(),
93            tags: Vec::new(),
94            valid_from: None,
95            valid_until: None,
96        }
97    }
98}
99
100impl MemoryNode {
101    /// Returns true if this memory is temporally valid at the given timestamp.
102    pub fn is_valid_at(&self, at: Timestamp) -> bool {
103        let from = self.valid_from.unwrap_or(0);
104        match self.valid_until {
105            Some(until) => at >= from && at < until,
106            None => at >= from,
107        }
108    }
109
110    /// Mark this memory as no longer valid.
111    pub fn invalidate(&mut self, at: Timestamp) {
112        self.valid_until = Some(at);
113    }
114
115    /// Returns true if this memory has been invalidated.
116    pub fn is_invalidated(&self) -> bool {
117        self.valid_until.is_some()
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124    use crate::types::AgentId;
125
126    #[test]
127    fn new_memory_has_no_temporal_bounds() {
128        let node = MemoryNode::new(
129            AgentId::new(),
130            MemoryType::Semantic,
131            "test".to_string(),
132            vec![1.0],
133        );
134        assert_eq!(node.valid_from, None);
135        assert_eq!(node.valid_until, None);
136        assert!(!node.is_invalidated());
137    }
138
139    #[test]
140    fn invalidate_memory() {
141        let mut node = MemoryNode::new(
142            AgentId::new(),
143            MemoryType::Semantic,
144            "Alice works at Acme".to_string(),
145            vec![1.0],
146        );
147        assert!(node.is_valid_at(node.created_at));
148
149        node.invalidate(node.created_at + 1_000_000);
150        assert!(node.is_invalidated());
151        assert!(node.is_valid_at(node.created_at));
152        assert!(!node.is_valid_at(node.created_at + 1_000_000));
153    }
154
155    #[test]
156    fn serde_backward_compatible() {
157        let json = r#"{"id":"00000000-0000-0000-0000-000000000001","agent_id":"00000000-0000-0000-0000-000000000002","memory_type":"Semantic","embedding":[1.0],"content":"test","created_at":1000,"accessed_at":1000,"access_count":0,"salience":1.0,"confidence":1.0,"space_id":"00000000-0000-0000-0000-000000000000","attributes":{},"tags":[]}"#;
158        let node: MemoryNode = serde_json::from_str(json).unwrap();
159        assert_eq!(node.valid_from, None);
160        assert_eq!(node.valid_until, None);
161        assert!(node.is_valid_at(5000));
162    }
163}
164
165/// Flexible attribute values for memory metadata.
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub enum AttributeValue {
168    /// A string value.
169    String(String),
170    /// An integer value.
171    Integer(i64),
172    /// A floating-point value.
173    Float(f64),
174    /// A boolean value.
175    Boolean(bool),
176    /// Raw bytes.
177    Bytes(Vec<u8>),
178}