mod causal;
mod meta;
mod online;
mod reflexion;
mod sessions;
mod skills;
mod temporal;
pub use causal::{CausalEdge, CausalMemory, CausalNode, Hyperedge};
pub use meta::{FewShotLearner, LearningStrategy, MetaLearner, TaskFeatures};
pub use online::{DriftDetector, Experience, ExperienceWindow, OnlineLearner, ParameterSnapshot};
pub use reflexion::{Critique, CritiqueType, ReflexionEpisode, ReflexionMemory};
pub use sessions::{LearningSession, Reward, SessionTurn};
pub use skills::{Skill, SkillLibrary, SkillPattern};
pub use temporal::{TemporalMemory, TemporalOccurrence, TemporalPeriod, TimeCrystal};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;
pub struct AgenticDB {
pub reflexion: Arc<RwLock<ReflexionMemory>>,
pub skills: Arc<RwLock<SkillLibrary>>,
pub causal: Arc<RwLock<CausalMemory>>,
pub sessions: Arc<RwLock<Vec<LearningSession>>>,
pub temporal: Arc<RwLock<TemporalMemory>>,
pub meta: Arc<RwLock<MetaLearner>>,
pub experiences: Arc<RwLock<ExperienceWindow>>,
pub drift_detector: Arc<RwLock<DriftDetector>>,
#[allow(dead_code)]
path: Option<String>,
}
impl AgenticDB {
pub fn new() -> Self {
Self::with_dimensions(64, 64)
}
pub fn with_dimensions(meta_param_dim: usize, drift_feature_dim: usize) -> Self {
Self {
reflexion: Arc::new(RwLock::new(ReflexionMemory::new())),
skills: Arc::new(RwLock::new(SkillLibrary::new())),
causal: Arc::new(RwLock::new(CausalMemory::new())),
sessions: Arc::new(RwLock::new(Vec::new())),
temporal: Arc::new(RwLock::new(TemporalMemory::new())),
meta: Arc::new(RwLock::new(MetaLearner::new("agent_meta", meta_param_dim))),
experiences: Arc::new(RwLock::new(ExperienceWindow::new(1000))),
drift_detector: Arc::new(RwLock::new(DriftDetector::new(drift_feature_dim))),
path: None,
}
}
pub fn with_path(path: impl Into<String>) -> Self {
Self {
reflexion: Arc::new(RwLock::new(ReflexionMemory::new())),
skills: Arc::new(RwLock::new(SkillLibrary::new())),
causal: Arc::new(RwLock::new(CausalMemory::new())),
sessions: Arc::new(RwLock::new(Vec::new())),
temporal: Arc::new(RwLock::new(TemporalMemory::new())),
meta: Arc::new(RwLock::new(MetaLearner::new("agent_meta", 64))),
experiences: Arc::new(RwLock::new(ExperienceWindow::new(1000))),
drift_detector: Arc::new(RwLock::new(DriftDetector::new(64))),
path: Some(path.into()),
}
}
pub async fn add_reflexion(&self, episode: ReflexionEpisode) {
let mut reflexion = self.reflexion.write().await;
reflexion.add_episode(episode);
}
pub async fn query_similar_failures(&self, task: &str, limit: usize) -> Vec<ReflexionEpisode> {
let reflexion = self.reflexion.read().await;
reflexion.find_similar_failures(task, limit)
}
pub async fn register_skill(&self, skill: Skill) {
let mut skills = self.skills.write().await;
skills.add_skill(skill);
}
#[allow(clippy::unused_async)]
pub async fn find_skills(&self, _task_description: &str) -> Vec<&Skill> {
Vec::new()
}
pub async fn add_causal_link(
&self,
cause: Uuid,
effect: Uuid,
relationship: impl Into<String>,
strength: f32,
) {
let mut causal = self.causal.write().await;
causal.add_edge(CausalEdge {
id: Uuid::new_v4(),
cause,
effect,
relationship: relationship.into(),
strength,
evidence_count: 1,
});
}
pub async fn start_session(&self, goal: impl Into<String>) -> Uuid {
let session = LearningSession::new(goal);
let id = session.id;
let mut sessions = self.sessions.write().await;
sessions.push(session);
id
}
pub async fn record_turn(
&self,
session_id: Uuid,
action: impl Into<String>,
observation: impl Into<String>,
reward: Reward,
) {
let mut sessions = self.sessions.write().await;
if let Some(session) = sessions.iter_mut().find(|s| s.id == session_id) {
session.add_turn(SessionTurn {
action: action.into(),
observation: observation.into(),
reward,
timestamp: chrono::Utc::now(),
});
}
}
pub async fn stats(&self) -> AgenticStats {
let reflexion = self.reflexion.read().await;
let skills = self.skills.read().await;
let causal = self.causal.read().await;
let sessions = self.sessions.read().await;
let temporal = self.temporal.read().await;
let meta = self.meta.read().await;
let experiences = self.experiences.read().await;
AgenticStats {
reflexion_episodes: reflexion.len(),
failed_episodes: reflexion.failure_count(),
skills_count: skills.len(),
causal_nodes: causal.node_count(),
causal_edges: causal.edge_count(),
total_sessions: sessions.len(),
total_turns: sessions.iter().map(|s| s.turns.len()).sum(),
temporal_patterns: temporal.len(),
meta_tasks_learned: meta.num_tasks() as usize,
learning_strategies: meta.num_strategies(),
experience_buffer_size: experiences.len(),
}
}
pub async fn record_temporal(&self, pattern_name: &str, period: TemporalPeriod, value: f32) {
let mut temporal = self.temporal.write().await;
temporal.record(pattern_name, period, value);
}
pub async fn predict_temporal(&self, pattern_name: &str) -> Option<f32> {
let temporal = self.temporal.read().await;
temporal.predict(pattern_name)
}
pub async fn add_experience(
&mut self,
features: Vec<f32>,
target: f32,
task_id: Option<String>,
) {
let mut experiences = self.experiences.write().await;
experiences.add(features, target, task_id);
}
pub async fn check_drift(&self, features: &[f32]) -> bool {
let mut detector = self.drift_detector.write().await;
detector.update(features)
}
pub async fn meta_update(
&self,
task_id: &str,
final_params: &[f32],
task_embedding: Option<Vec<f32>>,
) {
let mut meta = self.meta.write().await;
meta.meta_update(task_id, final_params, task_embedding);
}
pub async fn get_task_initialization(&self, task_embedding: Option<&[f32]>) -> Vec<f32> {
let meta = self.meta.read().await;
meta.initialize_for_task(task_embedding)
}
pub async fn register_strategy(&self, strategy: LearningStrategy) {
let mut meta = self.meta.write().await;
meta.register_strategy(strategy);
}
pub async fn select_strategy(&self, task_features: &TaskFeatures) -> Option<String> {
let meta = self.meta.read().await;
meta.select_strategy(task_features).map(|s| s.name.clone())
}
}
impl Default for AgenticDB {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgenticStats {
pub reflexion_episodes: usize,
pub failed_episodes: usize,
pub skills_count: usize,
pub causal_nodes: usize,
pub causal_edges: usize,
pub total_sessions: usize,
pub total_turns: usize,
pub temporal_patterns: usize,
pub meta_tasks_learned: usize,
pub learning_strategies: usize,
pub experience_buffer_size: usize,
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_reflexion_workflow() {
let db = AgenticDB::new();
let episode = ReflexionEpisode::new(
"code_generation", "Write a function to calculate factorial", "fn factorial(n: i32) -> i32 { n * factorial(n-1) }", false, )
.with_critique(Critique::new(
CritiqueType::LogicError,
"Missing base case causes infinite recursion", "Add: if n <= 1 { return 1; }", ))
.with_critique(Critique::new(
CritiqueType::MissingStep,
"No handling for negative numbers",
"Add input validation or use unsigned type",
));
db.add_reflexion(episode).await;
let stats = db.stats().await;
assert_eq!(stats.reflexion_episodes, 1);
assert_eq!(stats.failed_episodes, 1);
let similar = db.query_similar_failures("factorial function", 5).await;
assert_eq!(similar.len(), 1);
let past_mistake = &similar[0];
assert!(!past_mistake.succeeded);
assert_eq!(past_mistake.critiques.len(), 2);
}
#[tokio::test]
async fn test_skill_library() {
let db = AgenticDB::new();
let skill = Skill::new(
"error_handling",
"Rust Error Handling Pattern",
vec![
SkillPattern::new("result_type", "fn do_thing() -> Result<T, Error> { ... }"),
SkillPattern::new("question_mark", "let value = risky_op()?;"),
],
)
.with_success_rate(0.95)
.with_usage_count(42);
db.register_skill(skill).await;
let stats = db.stats().await;
assert_eq!(stats.skills_count, 1);
}
#[tokio::test]
async fn test_causal_memory() {
let db = AgenticDB::new();
let cause_id = Uuid::new_v4();
let effect_id = Uuid::new_v4();
db.add_causal_link(
cause_id, effect_id, "causes", 0.8, )
.await;
let stats = db.stats().await;
assert_eq!(stats.causal_edges, 1);
}
#[tokio::test]
async fn test_learning_session() {
let db = AgenticDB::new();
let session_id = db.start_session("Fix the bug in auth module").await;
db.record_turn(
session_id,
"read_file auth.rs",
"Found potential null check issue on line 42",
Reward::Neutral,
)
.await;
db.record_turn(
session_id,
"edit auth.rs: add None check",
"File updated successfully",
Reward::Positive(0.5),
)
.await;
db.record_turn(
session_id,
"run tests",
"All 15 tests passing",
Reward::Positive(1.0), )
.await;
let stats = db.stats().await;
assert_eq!(stats.total_sessions, 1);
assert_eq!(stats.total_turns, 3);
}
#[tokio::test]
async fn test_integrated_workflow() {
let db = AgenticDB::new();
let past_failure = ReflexionEpisode::new(
"api_design",
"Design REST API endpoint",
"POST /users with no validation",
false,
)
.with_critique(Critique::new(
CritiqueType::DesignFlaw,
"No input validation leads to security issues",
"Always validate and sanitize inputs",
));
db.add_reflexion(past_failure).await;
let skill = Skill::new(
"api_validation",
"Input Validation Pattern",
vec![SkillPattern::new("validate_first", "validate(&input)?;")],
);
db.register_skill(skill).await;
let validation_id = Uuid::new_v4();
let security_id = Uuid::new_v4();
db.add_causal_link(validation_id, security_id, "improves", 0.9)
.await;
let session_id = db
.start_session("Implement user registration endpoint")
.await;
let failures = db.query_similar_failures("api endpoint", 5).await;
assert!(!failures.is_empty(), "Should find past API failure");
db.record_turn(
session_id,
"apply validation skill",
"Added input validation with proper error handling",
Reward::Positive(0.8),
)
.await;
let stats = db.stats().await;
assert_eq!(stats.reflexion_episodes, 1);
assert_eq!(stats.skills_count, 1);
assert_eq!(stats.causal_edges, 1);
assert_eq!(stats.total_sessions, 1);
assert_eq!(stats.total_turns, 1);
println!("AgenticDB Stats: {:?}", stats);
}
}