#![forbid(unsafe_code)]
mod error;
#[cfg(feature = "file")]
mod file;
#[cfg(feature = "sqlite")]
mod sqlite;
#[cfg(feature = "postgres")]
mod postgres;
pub use error::{PersistenceError, Result};
#[cfg(feature = "file")]
pub use file::FileStore;
#[cfg(feature = "sqlite")]
pub use sqlite::SqliteStore;
#[cfg(feature = "postgres")]
pub use postgres::PostgresStore;
use async_trait::async_trait;
use serde_json::Value;
#[async_trait]
pub trait CheckpointStore: Send + Sync {
async fn save(&self, agent_key: &str, field: &str, value: Value) -> Result<()>;
async fn load(&self, agent_key: &str, field: &str) -> Result<Option<Value>>;
async fn load_all(&self, agent_key: &str) -> Result<std::collections::HashMap<String, Value>>;
async fn save_all(
&self,
agent_key: &str,
fields: &std::collections::HashMap<String, Value>,
) -> Result<()>;
async fn delete(&self, agent_key: &str) -> Result<()>;
async fn exists(&self, agent_key: &str) -> Result<bool>;
}
#[derive(Debug, Clone)]
pub struct PersistenceConfig {
pub backend: Backend,
pub path: Option<String>,
pub url: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Backend {
Sqlite,
Postgres,
File,
}
impl Default for PersistenceConfig {
fn default() -> Self {
Self {
backend: Backend::Sqlite,
path: Some(".sage/checkpoints.db".to_string()),
url: None,
}
}
}
pub fn agent_checkpoint_key(agent_name: &str, initial_beliefs: &Value) -> String {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
agent_name.hash(&mut hasher);
initial_beliefs.to_string().hash(&mut hasher);
format!("{}_{:016x}", agent_name, hasher.finish())
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn checkpoint_key_different_for_different_beliefs() {
let key1 = agent_checkpoint_key("Agent", &json!({"x": 1}));
let key2 = agent_checkpoint_key("Agent", &json!({"x": 2}));
assert_ne!(key1, key2);
}
#[test]
fn checkpoint_key_same_for_same_beliefs() {
let key1 = agent_checkpoint_key("Agent", &json!({"x": 1}));
let key2 = agent_checkpoint_key("Agent", &json!({"x": 1}));
assert_eq!(key1, key2);
}
#[test]
fn checkpoint_key_different_for_different_agents() {
let key1 = agent_checkpoint_key("Agent1", &json!({"x": 1}));
let key2 = agent_checkpoint_key("Agent2", &json!({"x": 1}));
assert_ne!(key1, key2);
}
}