batuta/agent/memory/
mod.rs1pub mod in_memory;
11#[cfg(feature = "rag")]
12pub mod trueno;
13
14pub use in_memory::InMemorySubstrate;
15#[cfg(feature = "rag")]
16pub use trueno::TruenoMemory;
17
18use async_trait::async_trait;
19use serde::{Deserialize, Serialize};
20
21use crate::agent::result::AgentError;
22
23pub type MemoryId = String;
25
26#[derive(Debug, Clone, Default)]
28pub struct MemoryFilter {
29 pub agent_id: Option<String>,
31 pub source: Option<MemorySource>,
33 pub since: Option<chrono::DateTime<chrono::Utc>>,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
39pub enum MemorySource {
40 Conversation,
42 ToolResult,
44 System,
46 User,
48}
49
50#[derive(Debug, Clone)]
52pub struct MemoryFragment {
53 pub id: MemoryId,
55 pub content: String,
57 pub source: MemorySource,
59 pub relevance_score: f32,
61 pub created_at: chrono::DateTime<chrono::Utc>,
63}
64
65#[async_trait]
67pub trait MemorySubstrate: Send + Sync {
68 async fn remember(
70 &self,
71 agent_id: &str,
72 content: &str,
73 source: MemorySource,
74 embedding: Option<&[f32]>,
75 ) -> Result<MemoryId, AgentError>;
76
77 async fn recall(
79 &self,
80 query: &str,
81 limit: usize,
82 filter: Option<MemoryFilter>,
83 query_embedding: Option<&[f32]>,
84 ) -> Result<Vec<MemoryFragment>, AgentError>;
85
86 async fn set(
88 &self,
89 agent_id: &str,
90 key: &str,
91 value: serde_json::Value,
92 ) -> Result<(), AgentError>;
93
94 async fn get(&self, agent_id: &str, key: &str)
96 -> Result<Option<serde_json::Value>, AgentError>;
97
98 async fn forget(&self, id: MemoryId) -> Result<(), AgentError>;
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_memory_source_serialization() {
108 let sources = vec![
109 MemorySource::Conversation,
110 MemorySource::ToolResult,
111 MemorySource::System,
112 MemorySource::User,
113 ];
114 for source in &sources {
115 let json = serde_json::to_string(source).expect("serialize failed");
116 let back: MemorySource = serde_json::from_str(&json).expect("deserialize failed");
117 assert_eq!(*source, back);
118 }
119 }
120
121 #[test]
122 fn test_memory_filter_default() {
123 let filter = MemoryFilter::default();
124 assert!(filter.agent_id.is_none());
125 assert!(filter.source.is_none());
126 assert!(filter.since.is_none());
127 }
128}