1use serde::{Deserialize, Serialize};
4
5use crate::types::*;
6use crate::types::{AgentId, MemoryId, SpaceId};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum MemoryType {
11 Episodic,
13 Semantic,
15 Procedural,
17 AntiPattern,
19 Reasoning,
21 Correction,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct MemoryNode {
31 pub id: MemoryId,
33 pub agent_id: AgentId,
35 pub memory_type: MemoryType,
37 pub embedding: Embedding,
39 pub content: String,
41 pub created_at: Timestamp,
43 pub accessed_at: Timestamp,
45 pub access_count: u32,
47 pub salience: Salience,
49 pub confidence: Confidence,
51 pub space_id: SpaceId,
53 pub attributes: std::collections::HashMap<String, AttributeValue>,
55 pub tags: Vec<String>,
57 #[serde(default, skip_serializing_if = "Option::is_none")]
60 pub valid_from: Option<Timestamp>,
61 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub valid_until: Option<Timestamp>,
65}
66
67impl MemoryNode {
68 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 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 pub fn invalidate(&mut self, at: Timestamp) {
112 self.valid_until = Some(at);
113 }
114
115 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#[derive(Debug, Clone, Serialize, Deserialize)]
167pub enum AttributeValue {
168 String(String),
170 Integer(i64),
172 Float(f64),
174 Boolean(bool),
176 Bytes(Vec<u8>),
178}