mem0_rust/
models.rs

1//! Data models for mem0-rust.
2//!
3//! This module provides all the core data structures used throughout the library.
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use sha2::{Digest, Sha256};
8use std::collections::HashMap;
9use uuid::Uuid;
10
11/// A stored memory record
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct MemoryRecord {
14    /// Unique identifier
15    pub id: Uuid,
16
17    /// Memory content
18    pub content: String,
19
20    /// Associated metadata
21    pub metadata: HashMap<String, serde_json::Value>,
22
23    /// User ID scope
24    pub user_id: Option<String>,
25
26    /// Agent ID scope
27    pub agent_id: Option<String>,
28
29    /// Run ID scope
30    pub run_id: Option<String>,
31
32    /// Content hash for deduplication
33    pub hash: String,
34
35    /// Creation timestamp
36    pub created_at: DateTime<Utc>,
37
38    /// Last update timestamp
39    pub updated_at: DateTime<Utc>,
40}
41
42impl MemoryRecord {
43    /// Create a new memory record
44    pub fn new(content: impl Into<String>, metadata: serde_json::Value) -> Self {
45        let content = content.into();
46        let hash = Self::compute_hash(&content);
47        let now = Utc::now();
48
49        let metadata_map = match metadata {
50            serde_json::Value::Object(map) => map.into_iter().collect(),
51            _ => HashMap::new(),
52        };
53
54        Self {
55            id: Uuid::new_v4(),
56            content,
57            metadata: metadata_map,
58            user_id: None,
59            agent_id: None,
60            run_id: None,
61            hash,
62            created_at: now,
63            updated_at: now,
64        }
65    }
66
67    /// Create with scoping
68    pub fn with_scoping(
69        content: impl Into<String>,
70        metadata: serde_json::Value,
71        user_id: Option<String>,
72        agent_id: Option<String>,
73        run_id: Option<String>,
74    ) -> Self {
75        let mut record = Self::new(content, metadata);
76        record.user_id = user_id;
77        record.agent_id = agent_id;
78        record.run_id = run_id;
79        record
80    }
81
82    /// Compute content hash
83    fn compute_hash(content: &str) -> String {
84        let mut hasher = Sha256::new();
85        hasher.update(content.as_bytes());
86        hex::encode(hasher.finalize())
87    }
88
89    /// Update the content and hash
90    pub fn update_content(&mut self, content: impl Into<String>) {
91        self.content = content.into();
92        self.hash = Self::compute_hash(&self.content);
93        self.updated_at = Utc::now();
94    }
95}
96
97/// A memory with its similarity score
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct ScoredMemory {
100    /// The memory record
101    pub record: MemoryRecord,
102
103    /// Similarity score
104    pub score: f32,
105}
106
107/// Message role for chat-style input
108#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
109#[serde(rename_all = "lowercase")]
110pub enum Role {
111    /// System message
112    System,
113    /// User message
114    User,
115    /// Assistant message
116    Assistant,
117}
118
119/// A chat message
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct Message {
122    /// Message role
123    pub role: Role,
124
125    /// Message content
126    pub content: String,
127
128    /// Optional actor name
129    pub name: Option<String>,
130}
131
132impl Message {
133    /// Create a user message
134    pub fn user(content: impl Into<String>) -> Self {
135        Self {
136            role: Role::User,
137            content: content.into(),
138            name: None,
139        }
140    }
141
142    /// Create an assistant message
143    pub fn assistant(content: impl Into<String>) -> Self {
144        Self {
145            role: Role::Assistant,
146            content: content.into(),
147            name: None,
148        }
149    }
150
151    /// Create a system message
152    pub fn system(content: impl Into<String>) -> Self {
153        Self {
154            role: Role::System,
155            content: content.into(),
156            name: None,
157        }
158    }
159
160    /// Set the actor name
161    pub fn with_name(mut self, name: impl Into<String>) -> Self {
162        self.name = Some(name.into());
163        self
164    }
165}
166
167/// Input that can be converted to messages
168#[derive(Debug, Clone)]
169pub enum Messages {
170    /// Plain text input
171    Text(String),
172    /// Single message
173    Single(Message),
174    /// Multiple messages
175    Multiple(Vec<Message>),
176}
177
178impl From<&str> for Messages {
179    fn from(s: &str) -> Self {
180        Messages::Text(s.to_string())
181    }
182}
183
184impl From<String> for Messages {
185    fn from(s: String) -> Self {
186        Messages::Text(s)
187    }
188}
189
190impl From<Message> for Messages {
191    fn from(m: Message) -> Self {
192        Messages::Single(m)
193    }
194}
195
196impl From<Vec<Message>> for Messages {
197    fn from(v: Vec<Message>) -> Self {
198        Messages::Multiple(v)
199    }
200}
201
202impl Messages {
203    /// Convert to a list of messages
204    pub fn into_messages(self) -> Vec<Message> {
205        match self {
206            Messages::Text(s) => vec![Message::user(s)],
207            Messages::Single(m) => vec![m],
208            Messages::Multiple(v) => v,
209        }
210    }
211}
212
213/// Options for adding memories
214#[derive(Debug, Clone, Default, Serialize, Deserialize)]
215pub struct AddOptions {
216    /// User ID scope
217    pub user_id: Option<String>,
218
219    /// Agent ID scope
220    pub agent_id: Option<String>,
221
222    /// Run ID scope
223    pub run_id: Option<String>,
224
225    /// Additional metadata
226    pub metadata: Option<HashMap<String, serde_json::Value>>,
227
228    /// Whether to use LLM for inference (default: true)
229    pub infer: bool,
230}
231
232impl AddOptions {
233    /// Create options with user scope
234    pub fn for_user(user_id: impl Into<String>) -> Self {
235        Self {
236            user_id: Some(user_id.into()),
237            infer: true,
238            ..Default::default()
239        }
240    }
241
242    /// Create options with agent scope
243    pub fn for_agent(agent_id: impl Into<String>) -> Self {
244        Self {
245            agent_id: Some(agent_id.into()),
246            infer: true,
247            ..Default::default()
248        }
249    }
250
251    /// Disable LLM inference
252    pub fn raw(mut self) -> Self {
253        self.infer = false;
254        self
255    }
256}
257
258/// Result of adding memories
259#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct AddResult {
261    /// List of memory operations performed
262    pub results: Vec<MemoryEvent>,
263}
264
265/// A memory operation event
266#[derive(Debug, Clone, Serialize, Deserialize)]
267pub struct MemoryEvent {
268    /// Memory ID
269    pub id: Uuid,
270
271    /// Memory content
272    pub memory: String,
273
274    /// Event type
275    pub event: EventType,
276}
277
278/// Type of memory event
279#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
280#[serde(rename_all = "UPPERCASE")]
281pub enum EventType {
282    /// Memory was added
283    Add,
284    /// Memory was updated
285    Update,
286    /// Memory was deleted
287    Delete,
288    /// No change
289    Noop,
290}
291
292/// Options for searching memories
293#[derive(Debug, Clone, Default, Serialize, Deserialize)]
294pub struct SearchOptions {
295    /// User ID filter
296    pub user_id: Option<String>,
297
298    /// Agent ID filter
299    pub agent_id: Option<String>,
300
301    /// Run ID filter
302    pub run_id: Option<String>,
303
304    /// Maximum number of results
305    pub limit: Option<usize>,
306
307    /// Minimum similarity threshold
308    pub threshold: Option<f32>,
309
310    /// Additional metadata filters
311    pub filters: Option<Filters>,
312
313    /// Whether to rerank results
314    pub rerank: bool,
315}
316
317impl SearchOptions {
318    /// Create options with user filter
319    pub fn for_user(user_id: impl Into<String>) -> Self {
320        Self {
321            user_id: Some(user_id.into()),
322            limit: Some(10),
323            ..Default::default()
324        }
325    }
326
327    /// Set the result limit
328    pub fn with_limit(mut self, limit: usize) -> Self {
329        self.limit = Some(limit);
330        self
331    }
332
333    /// Set the similarity threshold
334    pub fn with_threshold(mut self, threshold: f32) -> Self {
335        self.threshold = Some(threshold);
336        self
337    }
338}
339
340/// Search result
341#[derive(Debug, Clone, Serialize, Deserialize)]
342pub struct SearchResult {
343    /// Found memories with scores
344    pub results: Vec<ScoredMemory>,
345}
346
347/// Metadata filters
348#[derive(Debug, Clone, Default, Serialize, Deserialize)]
349pub struct Filters {
350    /// Filter conditions
351    pub conditions: Vec<FilterCondition>,
352
353    /// Logic operator between conditions
354    pub logic: FilterLogic,
355}
356
357/// A filter condition
358#[derive(Debug, Clone, Serialize, Deserialize)]
359pub struct FilterCondition {
360    /// Field name
361    pub field: String,
362
363    /// Operator
364    pub operator: FilterOperator,
365
366    /// Value to compare
367    pub value: serde_json::Value,
368}
369
370/// Filter operators
371#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
372#[serde(rename_all = "lowercase")]
373pub enum FilterOperator {
374    /// Equal
375    Eq,
376    /// Not equal
377    Ne,
378    /// Greater than
379    Gt,
380    /// Greater than or equal
381    Gte,
382    /// Less than
383    Lt,
384    /// Less than or equal
385    Lte,
386    /// In list
387    In,
388    /// Not in list
389    Nin,
390    /// Contains (for strings)
391    Contains,
392    /// Contains (case-insensitive)
393    IContains,
394}
395
396/// Logic for combining filter conditions
397#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
398#[serde(rename_all = "UPPERCASE")]
399pub enum FilterLogic {
400    #[default]
401    And,
402    Or,
403}
404
405/// Options for listing all memories
406#[derive(Debug, Clone, Default, Serialize, Deserialize)]
407pub struct GetAllOptions {
408    /// User ID filter
409    pub user_id: Option<String>,
410
411    /// Agent ID filter
412    pub agent_id: Option<String>,
413
414    /// Run ID filter
415    pub run_id: Option<String>,
416
417    /// Maximum number of results
418    pub limit: Option<usize>,
419}
420
421/// A history entry for a memory
422#[derive(Debug, Clone, Serialize, Deserialize)]
423pub struct HistoryEntry {
424    /// History entry ID
425    pub id: Uuid,
426
427    /// Memory ID this history belongs to
428    pub memory_id: Uuid,
429
430    /// Previous content
431    pub previous_content: Option<String>,
432
433    /// New content
434    pub new_content: String,
435
436    /// Event type
437    pub event: EventType,
438
439    /// Timestamp
440    pub timestamp: DateTime<Utc>,
441}
442
443/// Options for resetting memories
444#[derive(Debug, Clone, Default, Serialize, Deserialize)]
445pub struct ResetOptions {
446    /// User ID scope (if set, only reset this user's memories)
447    pub user_id: Option<String>,
448
449    /// Agent ID scope
450    pub agent_id: Option<String>,
451}
452
453/// Payload for vector store operations
454#[derive(Debug, Clone, Serialize, Deserialize)]
455pub struct Payload {
456    /// Memory content
457    pub data: String,
458
459    /// Memory hash
460    pub hash: String,
461
462    /// Creation timestamp
463    pub created_at: DateTime<Utc>,
464
465    /// User ID
466    pub user_id: Option<String>,
467
468    /// Agent ID
469    pub agent_id: Option<String>,
470
471    /// Run ID
472    pub run_id: Option<String>,
473
474    /// Additional metadata
475    #[serde(flatten)]
476    pub metadata: HashMap<String, serde_json::Value>,
477}
478
479impl From<&MemoryRecord> for Payload {
480    fn from(record: &MemoryRecord) -> Self {
481        Self {
482            data: record.content.clone(),
483            hash: record.hash.clone(),
484            created_at: record.created_at,
485            user_id: record.user_id.clone(),
486            agent_id: record.agent_id.clone(),
487            run_id: record.run_id.clone(),
488            metadata: record.metadata.clone(),
489        }
490    }
491}