ceylon_next/memory/migration.rs
1//! Memory migration utilities for transferring data between backends.
2//!
3//! This module provides functions to migrate, export, and import memory entries
4//! between different storage backends.
5
6use super::{Memory, MemoryEntry};
7use std::fs;
8use std::path::PathBuf;
9
10/// Migrates memory entries from one backend to another.
11///
12/// # Arguments
13///
14/// * `source` - The source memory backend to read from
15/// * `target` - The target memory backend to write to
16/// * `agent_id` - Agent ID to migrate memories for
17///
18/// # Returns
19///
20/// The number of entries migrated, or an error message
21///
22/// # Examples
23///
24/// ```rust,no_run
25/// use ceylon_next::memory::{InMemoryStore, FileStore, StorageFormat, migrate_memory};
26/// use std::sync::Arc;
27///
28/// #[tokio::main]
29/// async fn main() {
30/// let source = Arc::new(InMemoryStore::new());
31/// let target = Arc::new(
32/// FileStore::new("backup.json", StorageFormat::Json).await.unwrap()
33/// );
34///
35/// // Migrate specific agent's memories
36/// let count = migrate_memory(&*source, &*target, "agent-123").await.unwrap();
37/// println!("Migrated {} entries for agent-123", count);
38/// }
39/// ```
40pub async fn migrate_memory(
41 source: &dyn Memory,
42 target: &dyn Memory,
43 agent_id: &str,
44) -> Result<usize, String> {
45 let entries = source.get_agent_history(agent_id).await?;
46
47 let mut count = 0;
48 for entry in entries {
49 target.store(entry).await?;
50 count += 1;
51 }
52
53 Ok(count)
54}
55
56/// Exports all memory entries to a JSON file.
57///
58/// # Arguments
59///
60/// * `source` - The source memory backend to read from
61/// * `agent_id` - The agent ID whose memories to export
62/// * `file_path` - Path to the output JSON file
63///
64/// # Examples
65///
66/// ```rust,no_run
67/// use ceylon_next::memory::{InMemoryStore, export_to_json};
68/// use std::sync::Arc;
69///
70/// #[tokio::main]
71/// async fn main() {
72/// let memory = Arc::new(InMemoryStore::new());
73/// export_to_json(&*memory, "agent-123", "backup.json").await.unwrap();
74/// }
75/// ```
76pub async fn export_to_json<P: Into<PathBuf>>(
77 source: &dyn Memory,
78 agent_id: &str,
79 file_path: P,
80) -> Result<usize, String> {
81 let entries = source.get_agent_history(agent_id).await?;
82 let count = entries.len();
83
84 let json = serde_json::to_string_pretty(&entries)
85 .map_err(|e| format!("Failed to serialize to JSON: {}", e))?;
86
87 fs::write(file_path.into(), json)
88 .map_err(|e| format!("Failed to write file: {}", e))?;
89
90 Ok(count)
91}
92
93/// Imports memory entries from a JSON file.
94///
95/// # Arguments
96///
97/// * `target` - The target memory backend to write to
98/// * `file_path` - Path to the input JSON file
99///
100/// # Examples
101///
102/// ```rust,no_run
103/// use ceylon_next::memory::{SqliteStore, import_from_json};
104/// use std::sync::Arc;
105///
106/// #[tokio::main]
107/// async fn main() {
108/// let memory = Arc::new(SqliteStore::new("memory.db").await.unwrap());
109/// let count = import_from_json(&*memory, "backup.json").await.unwrap();
110/// println!("Imported {} entries", count);
111/// }
112/// ```
113pub async fn import_from_json<P: Into<PathBuf>>(
114 target: &dyn Memory,
115 file_path: P,
116) -> Result<usize, String> {
117 let json = fs::read_to_string(file_path.into())
118 .map_err(|e| format!("Failed to read file: {}", e))?;
119
120 let entries: Vec<MemoryEntry> = serde_json::from_str(&json)
121 .map_err(|e| format!("Failed to deserialize JSON: {}", e))?;
122
123 let mut count = 0;
124 for entry in entries {
125 target.store(entry).await?;
126 count += 1;
127 }
128
129 Ok(count)
130}
131
132/// Exports all memory entries to a MessagePack file.
133///
134/// # Arguments
135///
136/// * `source` - The source memory backend to read from
137/// * `agent_id` - The agent ID whose memories to export
138/// * `file_path` - Path to the output MessagePack file
139///
140/// # Examples
141///
142/// ```rust,no_run
143/// use ceylon_next::memory::{InMemoryStore, export_to_msgpack};
144/// use std::sync::Arc;
145///
146/// #[tokio::main]
147/// async fn main() {
148/// let memory = Arc::new(InMemoryStore::new());
149/// export_to_msgpack(&*memory, "agent-123", "backup.msgpack").await.unwrap();
150/// }
151/// ```
152pub async fn export_to_msgpack<P: Into<PathBuf>>(
153 source: &dyn Memory,
154 agent_id: &str,
155 file_path: P,
156) -> Result<usize, String> {
157 let entries = source.get_agent_history(agent_id).await?;
158 let count = entries.len();
159
160 let msgpack = rmp_serde::to_vec(&entries)
161 .map_err(|e| format!("Failed to serialize to MessagePack: {}", e))?;
162
163 fs::write(file_path.into(), msgpack)
164 .map_err(|e| format!("Failed to write file: {}", e))?;
165
166 Ok(count)
167}
168
169/// Imports memory entries from a MessagePack file.
170///
171/// # Arguments
172///
173/// * `target` - The target memory backend to write to
174/// * `file_path` - Path to the input MessagePack file
175///
176/// # Examples
177///
178/// ```rust,no_run
179/// use ceylon_next::memory::{SqliteStore, import_from_msgpack};
180/// use std::sync::Arc;
181///
182/// #[tokio::main]
183/// async fn main() {
184/// let memory = Arc::new(SqliteStore::new("memory.db").await.unwrap());
185/// let count = import_from_msgpack(&*memory, "backup.msgpack").await.unwrap();
186/// println!("Imported {} entries", count);
187/// }
188/// ```
189pub async fn import_from_msgpack<P: Into<PathBuf>>(
190 target: &dyn Memory,
191 file_path: P,
192) -> Result<usize, String> {
193 let msgpack = fs::read(file_path.into())
194 .map_err(|e| format!("Failed to read file: {}", e))?;
195
196 let entries: Vec<MemoryEntry> = rmp_serde::from_slice(&msgpack)
197 .map_err(|e| format!("Failed to deserialize MessagePack: {}", e))?;
198
199 let mut count = 0;
200 for entry in entries {
201 target.store(entry).await?;
202 count += 1;
203 }
204
205 Ok(count)
206}