ai_agents_core/traits/
memory.rs1use async_trait::async_trait;
4
5use crate::error::Result;
6use crate::message::ChatMessage;
7
8#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
10pub struct MemorySnapshot {
11 #[serde(default)]
12 pub messages: Vec<ChatMessage>,
13 #[serde(default)]
14 pub summary: Option<String>,
15 #[serde(default)]
16 pub summarized_count: usize,
17}
18
19impl MemorySnapshot {
20 pub fn new(messages: Vec<ChatMessage>) -> Self {
21 Self {
22 messages,
23 summary: None,
24 summarized_count: 0,
25 }
26 }
27
28 pub fn with_summary(mut self, summary: String) -> Self {
29 self.summary = Some(summary);
30 self
31 }
32
33 pub fn with_summarized_count(mut self, summarized_count: usize) -> Self {
34 self.summarized_count = summarized_count;
35 self
36 }
37}
38
39#[async_trait]
44pub trait Memory: Send + Sync {
45 async fn add_message(&self, message: ChatMessage) -> Result<()>;
47 async fn get_messages(&self, limit: Option<usize>) -> Result<Vec<ChatMessage>>;
49 async fn clear(&self) -> Result<()>;
51 fn len(&self) -> usize;
53
54 fn is_empty(&self) -> bool {
56 self.len() == 0
57 }
58
59 async fn snapshot(&self) -> Result<MemorySnapshot> {
61 Ok(MemorySnapshot::new(self.get_messages(None).await?))
62 }
63
64 async fn restore(&self, snapshot: MemorySnapshot) -> Result<()>;
66
67 async fn evict_oldest(&self, _count: usize) -> Result<Vec<ChatMessage>> {
69 Ok(vec![])
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn old_snapshot_defaults_summarized_count() {
79 let json = r#"{"messages":[],"summary":"existing"}"#;
80 let snapshot: MemorySnapshot = serde_json::from_str(json).unwrap();
81 assert_eq!(snapshot.summary.as_deref(), Some("existing"));
82 assert_eq!(snapshot.summarized_count, 0);
83 }
84
85 #[test]
86 fn snapshot_roundtrip_preserves_summarized_count() {
87 let snapshot = MemorySnapshot::new(Vec::new())
88 .with_summary("existing".to_string())
89 .with_summarized_count(12);
90 let json = serde_json::to_string(&snapshot).unwrap();
91 let restored: MemorySnapshot = serde_json::from_str(&json).unwrap();
92 assert_eq!(restored.summary.as_deref(), Some("existing"));
93 assert_eq!(restored.summarized_count, 12);
94 }
95}