1use super::base::{BaseMemory, MemoryError};
8use async_trait::async_trait;
9
10#[async_trait]
29pub trait PersistentMemory: BaseMemory {
30 async fn load_from_store(&mut self, session_id: &str) -> Result<(), MemoryError>;
38
39 async fn save_to_store(&mut self, session_id: &str) -> Result<(), MemoryError>;
46
47 async fn delete_session(&self, session_id: &str) -> Result<(), MemoryError>;
52
53 async fn session_exists(&self, session_id: &str) -> Result<bool, MemoryError>;
58
59 fn current_session_id(&self) -> Option<String>;
64
65 fn set_session_id(&mut self, session_id: String);
67}
68
69#[derive(Debug, Clone)]
75pub struct PersistenceConfig {
76 pub auto_save: bool,
78
79 pub auto_load: bool,
81
82 pub token_limit: usize,
84}
85
86impl Default for PersistenceConfig {
87 fn default() -> Self {
88 Self {
89 auto_save: true,
90 auto_load: true,
91 token_limit: 4000,
92 }
93 }
94}
95
96impl PersistenceConfig {
97 pub fn new() -> Self {
99 Self::default()
100 }
101
102 pub fn with_auto_save(mut self, auto_save: bool) -> Self {
104 self.auto_save = auto_save;
105 self
106 }
107
108 pub fn with_auto_load(mut self, auto_load: bool) -> Self {
110 self.auto_load = auto_load;
111 self
112 }
113
114 pub fn with_token_limit(mut self, token_limit: usize) -> Self {
116 self.token_limit = token_limit;
117 self
118 }
119}
120
121#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
123pub struct MemoryData {
124 pub session_id: String,
126
127 pub messages: Vec<lc_schema::Message>,
129
130 pub summary: Option<String>,
132
133 pub metadata: std::collections::HashMap<String, String>,
135
136 pub created_at: String,
138
139 pub updated_at: String,
141
142 #[serde(default)]
145 pub version: u64,
146}
147
148impl MemoryData {
149 pub fn new(session_id: impl Into<String>) -> Self {
151 let now = chrono::Utc::now().to_rfc3339();
152 Self {
153 session_id: session_id.into(),
154 messages: Vec::new(),
155 summary: None,
156 metadata: std::collections::HashMap::new(),
157 created_at: now.clone(),
158 updated_at: now,
159 version: 0,
160 }
161 }
162
163 pub fn with_messages(mut self, messages: Vec<lc_schema::Message>) -> Self {
165 self.messages = messages;
166 self.updated_at = chrono::Utc::now().to_rfc3339();
167 self
168 }
169
170 pub fn with_summary(mut self, summary: impl Into<String>) -> Self {
172 self.summary = Some(summary.into());
173 self.updated_at = chrono::Utc::now().to_rfc3339();
174 self
175 }
176
177 pub fn add_message(&mut self, message: lc_schema::Message) {
179 self.messages.push(message);
180 self.updated_at = chrono::Utc::now().to_rfc3339();
181 }
182
183 pub fn set_summary(&mut self, summary: impl Into<String>) {
185 self.summary = Some(summary.into());
186 self.updated_at = chrono::Utc::now().to_rfc3339();
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn test_persistence_config_default() {
196 let config = PersistenceConfig::default();
197 assert!(config.auto_save);
198 assert!(config.auto_load);
199 assert_eq!(config.token_limit, 4000);
200 }
201
202 #[test]
203 fn test_persistence_config_custom() {
204 let config = PersistenceConfig::new()
205 .with_auto_save(false)
206 .with_token_limit(2000);
207
208 assert!(!config.auto_save);
209 assert_eq!(config.token_limit, 2000);
210 }
211
212 #[test]
213 fn test_memory_data_new() {
214 let data = MemoryData::new("session_123".to_string());
215 assert_eq!(data.session_id, "session_123");
216 assert!(data.messages.is_empty());
217 assert!(data.summary.is_none());
218 }
219
220 #[test]
221 fn test_memory_data_with_messages() {
222 let messages = vec![
223 lc_schema::Message::human("Hello"),
224 lc_schema::Message::ai("Hi!"),
225 ];
226
227 let data = MemoryData::new("session_123".to_string()).with_messages(messages);
228
229 assert_eq!(data.messages.len(), 2);
230 }
231}