1use async_trait::async_trait;
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::HashMap;
6
7use crate::error::Result;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct MemoryEntry {
12 pub id: String,
14
15 pub content: String,
17
18 pub metadata: HashMap<String, Value>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub embedding: Option<Vec<f32>>,
24
25 pub created_at: DateTime<Utc>,
27
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub expires_at: Option<DateTime<Utc>>,
31}
32
33impl MemoryEntry {
34 pub fn new(content: impl Into<String>) -> Self {
36 Self {
37 id: uuid::Uuid::new_v4().to_string(),
38 content: content.into(),
39 metadata: HashMap::new(),
40 embedding: None,
41 created_at: Utc::now(),
42 expires_at: None,
43 }
44 }
45
46 pub fn with_id(id: impl Into<String>, content: impl Into<String>) -> Self {
48 Self {
49 id: id.into(),
50 content: content.into(),
51 metadata: HashMap::new(),
52 embedding: None,
53 created_at: Utc::now(),
54 expires_at: None,
55 }
56 }
57
58 pub fn with_metadata(mut self, key: impl Into<String>, value: Value) -> Self {
60 self.metadata.insert(key.into(), value);
61 self
62 }
63
64 pub fn with_embedding(mut self, embedding: Vec<f32>) -> Self {
66 self.embedding = Some(embedding);
67 self
68 }
69
70 pub fn with_expiration(mut self, expires_at: DateTime<Utc>) -> Self {
72 self.expires_at = Some(expires_at);
73 self
74 }
75
76 pub fn with_ttl_seconds(mut self, seconds: i64) -> Self {
78 self.expires_at = Some(Utc::now() + chrono::Duration::seconds(seconds));
79 self
80 }
81
82 pub fn is_expired(&self) -> bool {
84 if let Some(expires_at) = self.expires_at {
85 expires_at < Utc::now()
86 } else {
87 false
88 }
89 }
90}
91
92#[derive(Debug, Clone, Default)]
94pub struct MemoryQuery {
95 pub filters: HashMap<String, Value>,
97
98 pub limit: Option<usize>,
100
101 pub semantic_query: Option<String>,
103
104 pub similarity_threshold: Option<f32>,
106}
107
108impl MemoryQuery {
109 pub fn new() -> Self {
111 Self::default()
112 }
113
114 pub fn with_filter(mut self, key: impl Into<String>, value: Value) -> Self {
116 self.filters.insert(key.into(), value);
117 self
118 }
119
120 pub fn with_limit(mut self, limit: usize) -> Self {
122 self.limit = Some(limit);
123 self
124 }
125
126 pub fn with_semantic_query(mut self, query: impl Into<String>) -> Self {
128 self.semantic_query = Some(query.into());
129 self
130 }
131
132 pub fn with_threshold(mut self, threshold: f32) -> Self {
134 self.similarity_threshold = Some(threshold);
135 self
136 }
137}
138
139#[async_trait]
141pub trait Memory: Send + Sync {
142 async fn store(&self, entry: MemoryEntry) -> Result<String>;
144
145 async fn get(&self, id: &str) -> Result<Option<MemoryEntry>>;
147
148 async fn search(&self, query: MemoryQuery) -> Result<Vec<MemoryEntry>>;
150
151 async fn delete(&self, id: &str) -> Result<bool>;
153
154 async fn clear(&self) -> Result<()>;
156
157 async fn count(&self) -> Result<usize>;
159}
160
161#[async_trait]
163pub trait VectorMemory: Memory {
164 async fn embed(&self, text: &str) -> Result<Vec<f32>>;
166
167 async fn similarity_search(
170 &self,
171 query: &str,
172 limit: Option<usize>,
173 threshold: Option<f32>,
174 ) -> Result<Vec<(MemoryEntry, f32)>>;
175}