gemini_adk_rs/memory/
mod.rs1mod in_memory;
7mod vertex_ai_memory_bank;
8#[cfg(feature = "vertex-ai-rag")]
9mod vertex_ai_rag;
10
11pub use in_memory::InMemoryMemoryService;
12pub use vertex_ai_memory_bank::{VertexAiMemoryBankConfig, VertexAiMemoryBankService};
13#[cfg(feature = "vertex-ai-rag")]
14pub use vertex_ai_rag::{VertexAiRagMemoryConfig, VertexAiRagMemoryService};
15
16use async_trait::async_trait;
17use serde::{Deserialize, Serialize};
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct MemoryEntry {
22 pub key: String,
24 pub value: serde_json::Value,
26 pub created_at: u64,
28 pub updated_at: u64,
30}
31
32impl MemoryEntry {
33 pub fn new(key: impl Into<String>, value: serde_json::Value) -> Self {
35 let now = now_secs();
36 Self {
37 key: key.into(),
38 value,
39 created_at: now,
40 updated_at: now,
41 }
42 }
43}
44
45#[derive(Debug, thiserror::Error)]
47pub enum MemoryError {
48 #[error("Memory key not found: {0}")]
50 NotFound(String),
51 #[error("Storage error: {0}")]
53 Storage(String),
54 #[error("Unsupported operation: {0}")]
56 Unsupported(String),
57}
58
59#[async_trait]
63pub trait MemoryService: Send + Sync {
64 async fn store(&self, session_id: &str, entry: MemoryEntry) -> Result<(), MemoryError>;
66
67 async fn get(&self, session_id: &str, key: &str) -> Result<Option<MemoryEntry>, MemoryError>;
69
70 async fn list(&self, session_id: &str) -> Result<Vec<MemoryEntry>, MemoryError>;
72
73 async fn search(&self, session_id: &str, query: &str) -> Result<Vec<MemoryEntry>, MemoryError>;
75
76 async fn delete(&self, session_id: &str, key: &str) -> Result<(), MemoryError>;
78
79 async fn clear(&self, session_id: &str) -> Result<(), MemoryError>;
81}
82
83fn now_secs() -> u64 {
84 std::time::SystemTime::now()
85 .duration_since(std::time::UNIX_EPOCH)
86 .unwrap_or_default()
87 .as_secs()
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn memory_entry_new() {
96 let entry = MemoryEntry::new("topic", serde_json::json!("Rust"));
97 assert_eq!(entry.key, "topic");
98 assert_eq!(entry.value, serde_json::json!("Rust"));
99 assert!(entry.created_at > 0);
100 }
101
102 #[test]
103 fn memory_service_is_object_safe() {
104 fn _assert(_: &dyn MemoryService) {}
105 }
106
107 #[tokio::test]
108 async fn store_and_get() {
109 let svc = InMemoryMemoryService::new();
110 let entry = MemoryEntry::new("topic", serde_json::json!("AI"));
111 svc.store("s1", entry).await.unwrap();
112
113 let fetched = svc.get("s1", "topic").await.unwrap();
114 assert!(fetched.is_some());
115 assert_eq!(fetched.unwrap().value, serde_json::json!("AI"));
116 }
117
118 #[tokio::test]
119 async fn get_nonexistent_returns_none() {
120 let svc = InMemoryMemoryService::new();
121 let fetched = svc.get("s1", "missing").await.unwrap();
122 assert!(fetched.is_none());
123 }
124
125 #[tokio::test]
126 async fn list_entries() {
127 let svc = InMemoryMemoryService::new();
128 svc.store("s1", MemoryEntry::new("a", serde_json::json!(1)))
129 .await
130 .unwrap();
131 svc.store("s1", MemoryEntry::new("b", serde_json::json!(2)))
132 .await
133 .unwrap();
134 svc.store("s2", MemoryEntry::new("c", serde_json::json!(3)))
135 .await
136 .unwrap();
137
138 let entries = svc.list("s1").await.unwrap();
139 assert_eq!(entries.len(), 2);
140 }
141
142 #[tokio::test]
143 async fn search_entries() {
144 let svc = InMemoryMemoryService::new();
145 svc.store(
146 "s1",
147 MemoryEntry::new("rust_topic", serde_json::json!("Rust programming")),
148 )
149 .await
150 .unwrap();
151 svc.store(
152 "s1",
153 MemoryEntry::new("python_topic", serde_json::json!("Python scripting")),
154 )
155 .await
156 .unwrap();
157
158 let results = svc.search("s1", "rust").await.unwrap();
159 assert_eq!(results.len(), 1);
160 assert_eq!(results[0].key, "rust_topic");
161 }
162
163 #[tokio::test]
164 async fn delete_entry() {
165 let svc = InMemoryMemoryService::new();
166 svc.store("s1", MemoryEntry::new("k", serde_json::json!(1)))
167 .await
168 .unwrap();
169 svc.delete("s1", "k").await.unwrap();
170 let fetched = svc.get("s1", "k").await.unwrap();
171 assert!(fetched.is_none());
172 }
173
174 #[tokio::test]
175 async fn clear_session() {
176 let svc = InMemoryMemoryService::new();
177 svc.store("s1", MemoryEntry::new("a", serde_json::json!(1)))
178 .await
179 .unwrap();
180 svc.store("s1", MemoryEntry::new("b", serde_json::json!(2)))
181 .await
182 .unwrap();
183 svc.clear("s1").await.unwrap();
184 let entries = svc.list("s1").await.unwrap();
185 assert!(entries.is_empty());
186 }
187}