SqliteStore

Struct SqliteStore 

Source
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

Source

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
Hide additional 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}
Source

pub fn db_path(&self) -> &PathBuf

Returns the path to the database file.

Trait Implementations§

Source§

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,

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,

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,

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,

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,

Searches conversations for a query string.
Source§

fn clear_agent_memory<'life0, 'life1, 'async_trait>( &'life0 self, agent_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Clears all memory for an agent.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

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
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,