use anyhow::Context;
use do_memory_core::{Error, MemoryConfig, SelfLearningMemory};
use do_memory_storage_redb::{CacheConfig, RedbStorage};
use do_memory_storage_turso::{TursoConfig, TursoStorage};
use std::path::Path;
use std::sync::Arc;
use tracing::{info, warn};
pub async fn initialize_memory_system() -> anyhow::Result<Arc<SelfLearningMemory>> {
if let Ok(memory) = initialize_turso_local().await {
info!("Memory system initialized with Turso local database (default)");
return Ok(memory);
}
if let Ok(memory) = initialize_dual_storage().await {
info!("Memory system initialized with persistent storage (Turso cloud + redb)");
return Ok(memory);
}
if let Ok(memory) = initialize_redb_only_storage().await {
info!("Memory system initialized with redb cache storage (Turso unavailable)");
return Ok(memory);
}
warn!("Failed to initialize any persistent storage, falling back to in-memory");
info!("To enable persistence:");
info!(" - Default: Turso local database (no configuration needed)");
info!(" - Cloud: set TURSO_DATABASE_URL and TURSO_AUTH_TOKEN");
info!(" - Cache-only: ensure REDB_CACHE_PATH is accessible");
Ok(Arc::new(SelfLearningMemory::new()))
}
pub async fn initialize_redb_only_storage() -> anyhow::Result<Arc<SelfLearningMemory>> {
info!("Attempting to initialize redb-only storage...");
let cache_path_str =
std::env::var("REDB_CACHE_PATH").unwrap_or_else(|_| "./data/cache.redb".to_string());
let cache_path = Path::new(&cache_path_str);
if let Some(parent) = cache_path.parent() {
std::fs::create_dir_all(parent)
.map_err(|e| Error::Storage(format!("Failed to create data directory: {}", e)))?;
}
let cache_config = CacheConfig {
max_size: std::env::var("REDB_MAX_CACHE_SIZE")
.unwrap_or_else(|_| "1000".to_string())
.parse()
.unwrap_or(1000),
default_ttl_secs: 1800, cleanup_interval_secs: 600, enable_background_cleanup: true,
};
let redb_storage = RedbStorage::new_with_cache_config(cache_path, cache_config).await?;
info!(
"Successfully initialized redb storage at {}",
cache_path.display()
);
let memory_config = MemoryConfig::default();
let redb_arc: Arc<dyn do_memory_core::StorageBackend> = Arc::new(redb_storage);
let memory = SelfLearningMemory::with_storage(memory_config, Arc::clone(&redb_arc), redb_arc);
Ok(Arc::new(memory))
}
pub async fn initialize_dual_storage() -> anyhow::Result<Arc<SelfLearningMemory>> {
let turso_url = std::env::var("TURSO_DATABASE_URL")
.context("TURSO_DATABASE_URL environment variable not set")?;
let turso_token = std::env::var("TURSO_AUTH_TOKEN")
.context("TURSO_AUTH_TOKEN environment variable not set")?;
info!("Connecting to Turso database at {}", turso_url);
#[allow(clippy::field_reassign_with_default)]
let turso_config = TursoConfig {
max_retries: 3,
retry_base_delay_ms: 100,
retry_max_delay_ms: 5000,
enable_pooling: true,
compression_threshold: 1024,
compress_episodes: true,
compress_patterns: true,
compress_embeddings: true,
..Default::default()
};
let turso_storage = TursoStorage::with_config(&turso_url, &turso_token, turso_config).await?;
turso_storage.initialize_schema().await?;
let cache_path_str =
std::env::var("REDB_CACHE_PATH").unwrap_or_else(|_| "./data/cache.redb".to_string());
let cache_path = Path::new(&cache_path_str);
let cache_config = CacheConfig {
max_size: std::env::var("REDB_MAX_CACHE_SIZE")
.unwrap_or_else(|_| "1000".to_string())
.parse()
.unwrap_or(1000),
default_ttl_secs: 1800, cleanup_interval_secs: 600, enable_background_cleanup: true,
};
let redb_storage = RedbStorage::new_with_cache_config(cache_path, cache_config).await?;
let memory_config = MemoryConfig::default();
let memory = SelfLearningMemory::with_storage(
memory_config,
Arc::new(turso_storage),
Arc::new(redb_storage),
);
Ok(Arc::new(memory))
}
pub async fn initialize_turso_local() -> anyhow::Result<Arc<SelfLearningMemory>> {
info!("Attempting to initialize Turso local database (default)...");
let turso_url =
std::env::var("TURSO_DATABASE_URL").unwrap_or_else(|_| "file:./data/memory.db".to_string());
let turso_token = if turso_url.starts_with("file:") {
"".to_string()
} else {
std::env::var("TURSO_AUTH_TOKEN").unwrap_or_default()
};
info!("Connecting to Turso database at {}", turso_url);
#[allow(clippy::field_reassign_with_default)]
let turso_config = TursoConfig {
max_retries: 1, retry_base_delay_ms: 50,
retry_max_delay_ms: 1000,
enable_pooling: false, compression_threshold: 1024,
compress_episodes: true,
compress_patterns: true,
compress_embeddings: true,
..Default::default()
};
let turso_storage = TursoStorage::with_config(&turso_url, &turso_token, turso_config).await?;
turso_storage.initialize_schema().await?;
let cache_path_str =
std::env::var("REDB_CACHE_PATH").unwrap_or_else(|_| "./data/cache.redb".to_string());
let cache_path = Path::new(&cache_path_str);
let cache_config = CacheConfig {
max_size: std::env::var("REDB_MAX_CACHE_SIZE")
.unwrap_or_else(|_| "1000".to_string())
.parse()
.unwrap_or(1000),
default_ttl_secs: 1800, cleanup_interval_secs: 600, enable_background_cleanup: true,
};
let redb_storage = RedbStorage::new_with_cache_config(cache_path, cache_config).await?;
let memory_config = MemoryConfig::default();
let memory = SelfLearningMemory::with_storage(
memory_config,
Arc::new(turso_storage),
Arc::new(redb_storage),
);
info!("Successfully initialized Turso local + redb cache storage");
Ok(Arc::new(memory))
}