pub struct SqliteStore { /* private fields */ }Expand description
A SQLite-backed implementation of the Memory trait.
This provides persistent storage of conversation history using SQLite. All conversations are stored in a local SQLite database file.
§Examples
use ceylon_next::memory::SqliteStore;
use std::sync::Arc;
#[tokio::main]
async fn main() {
let memory = Arc::new(
SqliteStore::new("agent_memory.db").await.unwrap()
);
}Implementations§
Source§impl SqliteStore
impl SqliteStore
Sourcepub async fn new<P: Into<PathBuf>>(db_path: P) -> Result<Self, String>
pub async fn new<P: Into<PathBuf>>(db_path: P) -> Result<Self, String>
Creates a new SQLite store with the given database path.
§Arguments
db_path- Path to the SQLite database file (will be created if it doesn’t exist)
§Examples
use ceylon_next::memory::SqliteStore;
#[tokio::main]
async fn main() {
let store = SqliteStore::new("memory.db").await.unwrap();
}Examples found in repository?
examples/advanced_memory.rs (line 23)
18async fn main() -> Result<(), String> {
19 println!("🧠 Ceylon AI Framework - Advanced Memory Management Demo\n");
20
21 // 1. Setup Advanced Memory Manager
22 println!("1️⃣ Setting up Advanced Memory Manager...");
23 let backend = Arc::new(SqliteStore::new("advanced_memory_demo.db").await?);
24
25 let config = MemoryConfig {
26 working_memory_limit: 5,
27 episodic_memory_limit: 100,
28 auto_summarize: true,
29 min_summary_length: 2,
30 auto_consolidate: false, // Manual for demo
31 consolidation_interval: 3600,
32 duplicate_threshold: 0.85,
33 enable_decay: true,
34 decay_rate: 0.05,
35 ..Default::default()
36 };
37
38 let memory = AdvancedMemoryManager::new(backend, config).await?;
39 println!(" ✓ Memory manager initialized\n");
40
41 // 2. Store Multiple Conversations
42 println!("2️⃣ Storing conversations...");
43
44 let conversations = vec![
45 (
46 "What is Rust?",
47 "Rust is a systems programming language focused on safety, concurrency, and performance.",
48 ),
49 (
50 "Tell me about Alice",
51 "Alice is a software engineer who works at Google on cloud infrastructure projects.",
52 ),
53 (
54 "What projects is Alice working on?",
55 "Alice is currently working on Kubernetes optimization and distributed systems.",
56 ),
57 (
58 "How does Rust ensure memory safety?",
59 "Rust ensures memory safety through its ownership system, borrowing rules, and lifetimes.",
60 ),
61 (
62 "What is the capital of France?",
63 "The capital of France is Paris, a major European city known for art and culture.",
64 ),
65 ];
66
67 for (i, (user_msg, assistant_msg)) in conversations.iter().enumerate() {
68 let messages = vec![
69 Message {
70 role: "user".to_string(),
71 content: user_msg.to_string(),
72 },
73 Message {
74 role: "assistant".to_string(),
75 content: assistant_msg.to_string(),
76 },
77 ];
78
79 let entry = MemoryEntry::new(
80 "demo-agent".to_string(),
81 format!("task-{}", i),
82 messages,
83 );
84
85 let id = memory.store_conversation(entry).await?;
86 println!(" ✓ Stored conversation {} (ID: {})", i + 1, &id[..8]);
87 }
88 println!();
89
90 // 3. Query Working Memory
91 println!("3️⃣ Querying Working Memory (recent context)...");
92 let working = memory.get_working_memory(None).await;
93 println!(" Working memory contains {} conversations", working.len());
94 for (i, mem) in working.iter().enumerate() {
95 if let Some(summary) = &mem.summary {
96 println!(" {}. {}", i + 1, summary);
97 } else {
98 println!(" {}. {} messages", i + 1, mem.entry.messages.len());
99 }
100 }
101 println!();
102
103 // 4. Query Episodic Memory by Time Range
104 println!("4️⃣ Querying Episodic Memory...");
105 let recent = memory
106 .get_episodic_by_time("demo-agent", TimeRange::LastDays(7))
107 .await?;
108 println!(" Found {} conversations in the last 7 days", recent.len());
109
110 let all = memory
111 .get_episodic_by_time("demo-agent", TimeRange::All)
112 .await?;
113 println!(" Total conversations: {}", all.len());
114 println!();
115
116 // 5. Search Memories
117 println!("5️⃣ Searching memories for 'Alice'...");
118 let search_results = memory.search("demo-agent", "Alice").await?;
119 println!(" Found {} results:", search_results.len());
120 for (i, mem) in search_results.iter().enumerate() {
121 if let Some(summary) = &mem.summary {
122 println!(" {}. {}", i + 1, summary);
123 }
124 }
125 println!();
126
127 // 6. Query Semantic Memory
128 println!("6️⃣ Querying Semantic Memory...");
129 let stats = memory.get_semantic_stats().await;
130 println!(" Entities tracked: {}", stats.total_entities);
131 println!(" Facts stored: {}", stats.total_facts);
132 println!(" Relationships: {}", stats.total_relationships);
133
134 // Query facts about Alice (if extracted)
135 if stats.total_facts > 0 {
136 println!("\n Facts about 'Alice':");
137 let alice_facts = memory.get_facts_about("Alice").await;
138 for fact in alice_facts {
139 println!(
140 " - {} {} {} (confidence: {:.2})",
141 fact.subject, fact.predicate, fact.object, fact.confidence
142 );
143 }
144 }
145 println!();
146
147 // 7. Generate Agent Context
148 println!("7️⃣ Generating comprehensive agent context...");
149 let context = memory
150 .create_agent_context("demo-agent", Some(1000), true)
151 .await?;
152 println!(" Context length: {} characters", context.len());
153 println!(" Preview:");
154 let preview: String = context.lines().take(10).collect::<Vec<_>>().join("\n");
155 println!("{}\n", preview);
156
157 // 8. Get Relevant Memories
158 println!("8️⃣ Getting most relevant memories...");
159 let relevant = memory
160 .get_relevant_memories("demo-agent", 0.0, 3)
161 .await?;
162 println!(" Top 3 most relevant memories:");
163 for (i, mem) in relevant.iter().enumerate() {
164 println!(
165 " {}. Relevance: {:.2} - {} messages",
166 i + 1,
167 mem.relevance_score(),
168 mem.entry.messages.len()
169 );
170 }
171 println!();
172
173 // 9. Run Consolidation
174 println!("9️⃣ Running memory consolidation...");
175 let result = memory.consolidate(ConsolidationTask::All).await?;
176 println!(" Consolidation results:");
177 println!(" - Memories processed: {}", result.memories_processed);
178 println!(" - Memories merged: {}", result.memories_merged);
179 println!(" - Memories deleted: {}", result.memories_deleted);
180 println!(" - Duration: {}ms", result.duration_ms);
181 println!();
182
183 // 10. Memory Statistics
184 println!("🔟 Overall Memory Statistics:");
185 let final_stats = memory.get_statistics().await;
186 println!(" Working memory:");
187 println!(" - Count: {}", final_stats.working_memory_count);
188 println!(" - Tokens: {}", final_stats.working_memory_tokens);
189 println!(" Semantic memory:");
190 println!(" - Entities: {}", final_stats.semantic_entities);
191 println!(" - Facts: {}", final_stats.semantic_facts);
192 println!(" - Relationships: {}", final_stats.semantic_relationships);
193 println!();
194
195 println!("✅ Advanced Memory Management Demo Complete!");
196 println!("\n💡 Key Features Demonstrated:");
197 println!(" • Working memory for recent context");
198 println!(" • Episodic memory for past conversations");
199 println!(" • Semantic memory for facts and knowledge");
200 println!(" • Automatic summarization");
201 println!(" • Time-based and relevance-based retrieval");
202 println!(" • Memory consolidation and optimization");
203 println!(" • Comprehensive context generation");
204
205 Ok(())
206}More examples
examples/11_persistent_memory.rs (line 27)
16async fn main() {
17 println!("🤖 Ceylon Agent - Persistent Memory Example\n");
18
19 // ============================================
20 // Part 1: SQLite Backend
21 // ============================================
22 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
23 println!("📦 Part 1: SQLite Backend");
24 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
25
26 let sqlite_path = "agent_memory.db";
27 let sqlite_store = SqliteStore::new(sqlite_path).await
28 .expect("Failed to create SQLite store");
29
30 let mut agent = Agent::new("PersistentAssistant", "ollama::gemma3:latest");
31 agent.with_memory(Arc::new(sqlite_store))
32 .with_system_prompt("You are a helpful assistant with persistent memory across sessions.");
33
34 println!("✅ Created agent with SQLite backend at {}\n", sqlite_path);
35
36 // Run some tasks to populate memory
37 let tasks = vec![
38 "My name is Alice and I love programming in Rust",
39 "What programming language do I like?",
40 ];
41
42 for prompt in tasks {
43 println!("📋 Task: {}", prompt);
44 let mut task = TaskRequest::new(prompt);
45 task.with_priority(5);
46
47 let response = agent.run(task).await;
48 if let OutputData::Text(_) = response.result() {
49 println!("✓ Task completed\n");
50 }
51 }
52
53 println!("📊 SQLite database now contains conversation history");
54 println!(" This data persists even after the program exits!\n");
55
56 // ============================================
57 // Part 2: File-based Backend (JSON)
58 // ============================================
59 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
60 println!("📄 Part 2: File-based Backend (JSON)");
61 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
62
63 let json_path = "agent_memory.json";
64 let file_store = FileStore::new(json_path, StorageFormat::Json).await
65 .expect("Failed to create File store");
66
67 let mut agent2 = Agent::new("FileAssistant", "ollama::gemma3:latest");
68 agent2.with_memory(Arc::new(file_store))
69 .with_system_prompt("You are a helpful assistant storing memories in JSON files.");
70
71 println!("✅ Created agent with JSON file backend at {}\n", json_path);
72
73 let task = TaskRequest::new("Remember: My favorite color is blue");
74 let response = agent2.run(task).await;
75
76 if let OutputData::Text(_) = response.result() {
77 println!("✓ Memory saved to JSON file");
78 println!(" You can open {} to view the human-readable data!\n", json_path);
79 }
80
81 // ============================================
82 // Part 3: MessagePack Backend
83 // ============================================
84 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
85 println!("📦 Part 3: MessagePack Backend (Compact Binary)");
86 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
87
88 let msgpack_path = "agent_memory.msgpack";
89 let msgpack_store = FileStore::new(msgpack_path, StorageFormat::MessagePack).await
90 .expect("Failed to create MessagePack store");
91
92 let mut agent3 = Agent::new("BinaryAssistant", "ollama::gemma3:latest");
93 agent3.with_memory(Arc::new(msgpack_store))
94 .with_system_prompt("You are a helpful assistant using compact binary storage.");
95
96 println!("✅ Created agent with MessagePack backend at {}\n", msgpack_path);
97
98 let task = TaskRequest::new("Store this efficiently: The quick brown fox jumps over the lazy dog");
99 let response = agent3.run(task).await;
100
101 if let OutputData::Text(_) = response.result() {
102 println!("✓ Memory saved to MessagePack file");
103 println!(" Binary format is more compact than JSON!\n");
104 }
105
106 // ============================================
107 // Part 4: Memory Migration
108 // ============================================
109 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
110 println!("🔄 Part 4: Memory Migration Between Backends");
111 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
112
113 // Create source and destination stores
114 let source_db = SqliteStore::new("source.db").await.unwrap();
115
116 // Create an agent with source backend and add some data
117 let mut temp_agent = Agent::new("MigrationAgent", "ollama::gemma3:latest");
118 temp_agent.with_memory(Arc::new(source_db));
119
120 let task = TaskRequest::new("Migration test: This data will be migrated!");
121 temp_agent.run(task).await;
122
123 // Note: You would normally track your agent IDs. For this demo, we'll use
124 // a known pattern - the agent creates entries with its own ID
125 println!("💡 Tip: To migrate data, you need to know the agent's ID");
126 println!(" In production, track agent IDs when creating agents\n");
127
128 println!("✓ Migration between backends is available via migrate_memory()\n");
129 println!(" Example: migrate_memory(&source, &target, \"agent-id\").await\n");
130
131 // ============================================
132 // Part 5: Export/Import Utilities
133 // ============================================
134 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
135 println!("💾 Part 5: Export/Import Utilities");
136 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
137
138 // Demonstrate export/import with the existing SQLite database
139 println!("💡 Export and import utilities are available:\n");
140 println!(" • export_to_json(store, agent_id, path)");
141 println!(" • export_to_msgpack(store, agent_id, path)");
142 println!(" • import_from_json(store, path)");
143 println!(" • import_from_msgpack(store, path)\n");
144
145 println!("✓ These functions allow you to backup and restore agent memories\n");
146
147 // ============================================
148 // Summary
149 // ============================================
150 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
151 println!("📊 Summary: Available Backends");
152 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
153
154 println!("1. InMemoryStore (default)");
155 println!(" • Fast, but data lost on restart");
156 println!(" • Best for: Development, testing\n");
157
158 println!("2. SqliteStore");
159 println!(" • Persistent, efficient queries");
160 println!(" • Best for: Production apps, large datasets\n");
161
162 println!("3. FileStore (JSON)");
163 println!(" • Human-readable, easy to inspect");
164 println!(" • Best for: Debugging, data sharing\n");
165
166 println!("4. FileStore (MessagePack)");
167 println!(" • Compact binary format");
168 println!(" • Best for: Large datasets, bandwidth constraints\n");
169
170 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
171 println!("📝 Files Created:");
172 println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
173
174 println!("• agent_memory.db - SQLite database");
175 println!("• agent_memory.json - JSON storage");
176 println!("• agent_memory.msgpack - MessagePack storage");
177 println!("• backup.json - Migrated data");
178 println!("• exported_memory.json - Exported snapshot");
179 println!("• exported_memory.msgpack - Exported snapshot (binary)\n");
180
181 println!("✅ Example completed successfully!");
182 println!("\n💡 Tip: Check the created files to see your persisted data!");
183 println!(" Try running this example again - your SQLite data will persist!");
184}Trait Implementations§
Source§impl Memory for SqliteStore
impl Memory for SqliteStore
Source§fn store<'life0, 'async_trait>(
&'life0 self,
entry: MemoryEntry,
) -> Pin<Box<dyn Future<Output = Result<String, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn store<'life0, 'async_trait>(
&'life0 self,
entry: MemoryEntry,
) -> Pin<Box<dyn Future<Output = Result<String, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Stores a conversation in memory.
Source§fn get<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<MemoryEntry>, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<MemoryEntry>, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Retrieves a specific conversation by ID.
Source§fn get_agent_history<'life0, 'life1, 'async_trait>(
&'life0 self,
agent_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_agent_history<'life0, 'life1, 'async_trait>(
&'life0 self,
agent_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Retrieves all conversations for an agent.
Source§fn get_recent<'life0, 'life1, 'async_trait>(
&'life0 self,
agent_id: &'life1 str,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_recent<'life0, 'life1, 'async_trait>(
&'life0 self,
agent_id: &'life1 str,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Retrieves the most recent N conversations for an agent.
Source§fn search<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
agent_id: &'life1 str,
query: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn search<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
agent_id: &'life1 str,
query: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Searches conversations for a query string.
Auto Trait Implementations§
impl Freeze for SqliteStore
impl RefUnwindSafe for SqliteStore
impl Send for SqliteStore
impl Sync for SqliteStore
impl Unpin for SqliteStore
impl UnwindSafe for SqliteStore
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more