FileStore

Struct FileStore 

Source
pub struct FileStore { /* private fields */ }
Expand description

A file-based implementation of the Memory trait.

This provides persistent storage of conversation history using files. Supports both JSON (human-readable) and MessagePack (compact binary) formats.

§Examples

use ceylon_next::memory::{FileStore, StorageFormat};
use std::sync::Arc;

#[tokio::main]
async fn main() {
    // JSON format
    let memory = Arc::new(
        FileStore::new("memory.json", StorageFormat::Json).await.unwrap()
    );

    // MessagePack format
    let memory_mp = Arc::new(
        FileStore::new("memory.msgpack", StorageFormat::MessagePack).await.unwrap()
    );
}

Implementations§

Source§

impl FileStore

Source

pub async fn new<P: Into<PathBuf>>( file_path: P, format: StorageFormat, ) -> Result<Self, String>

Creates a new file-based store with the given file path and format.

§Arguments
  • file_path - Path to the storage file
  • format - Serialization format (JSON or MessagePack)
§Examples
use ceylon_next::memory::{FileStore, StorageFormat};

#[tokio::main]
async fn main() {
    let store = FileStore::new("memory.json", StorageFormat::Json).await.unwrap();
}
Examples found in repository?
examples/11_persistent_memory.rs (line 64)
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 file_path(&self) -> &PathBuf

Returns the path to the storage file.

Source

pub fn format(&self) -> StorageFormat

Returns the storage format being used.

Trait Implementations§

Source§

impl Memory for FileStore

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,