Skip to main content

lc_memory/
base.rs

1// lc-memory/src/base.rs
2//! Memory base trait
3
4use async_trait::async_trait;
5use lc_schema::Message;
6use std::collections::HashMap;
7
8/// Memory error type
9#[derive(Debug, thiserror::Error)]
10pub enum MemoryError {
11    /// Load error
12    #[error("Failed to load memory: {0}")]
13    LoadError(String),
14
15    /// Save error
16    #[error("Failed to save memory: {0}")]
17    SaveError(String),
18
19    /// Clear error
20    #[error("Failed to clear memory: {0}")]
21    ClearError(String),
22
23    /// Other error
24    #[error("Memory error: {0}")]
25    Other(String),
26}
27
28/// Base Memory trait
29///
30/// The base interface for all Memory types.
31#[async_trait]
32pub trait BaseMemory: Send + Sync {
33    /// Get memory variable names
34    ///
35    /// Returns all variable keys stored in memory.
36    fn memory_variables(&self) -> Vec<&str>;
37
38    /// Load memory variables
39    ///
40    /// # Arguments
41    /// * `inputs` - Current input
42    ///
43    /// # Returns
44    /// Memory variable dictionary
45    async fn load_memory_variables(
46        &self,
47        inputs: &HashMap<String, String>,
48    ) -> Result<HashMap<String, serde_json::Value>, MemoryError>;
49
50    /// Save context
51    ///
52    /// # Arguments
53    /// * `inputs` - User input
54    /// * `outputs` - System output
55    async fn save_context(
56        &mut self,
57        inputs: &HashMap<String, String>,
58        outputs: &HashMap<String, String>,
59    ) -> Result<(), MemoryError>;
60
61    /// Clear memory
62    async fn clear(&mut self) -> Result<(), MemoryError>;
63}
64
65/// Base Chat Memory trait
66///
67/// Memory specifically for chat scenarios.
68pub trait BaseChatMemory: BaseMemory {
69    /// Get chat message list
70    fn messages(&self) -> &Vec<Message>;
71
72    /// Add message
73    fn add_message(&mut self, message: Message);
74
75    /// Add user message
76    fn add_user_message(&mut self, content: &str) {
77        self.add_message(Message::human(content));
78    }
79
80    /// Add AI message
81    fn add_ai_message(&mut self, content: &str) {
82        self.add_message(Message::ai(content));
83    }
84}
85
86/// Chat message buffer
87///
88/// Simple message storage for ConversationBufferMemory.
89#[derive(Debug, Clone)]
90pub struct ChatMessageHistory {
91    /// Message list
92    messages: Vec<Message>,
93}
94
95impl ChatMessageHistory {
96    /// Create empty history
97    pub fn new() -> Self {
98        Self {
99            messages: Vec::new(),
100        }
101    }
102
103    /// Create from existing messages
104    pub fn from_messages(messages: Vec<Message>) -> Self {
105        Self { messages }
106    }
107
108    /// Add message
109    pub fn add_message(&mut self, message: Message) {
110        self.messages.push(message);
111    }
112
113    /// Add user message
114    pub fn add_user_message(&mut self, content: &str) {
115        self.add_message(Message::human(content));
116    }
117
118    /// Add AI message
119    pub fn add_ai_message(&mut self, content: &str) {
120        self.add_message(Message::ai(content));
121    }
122
123    /// Add system message
124    pub fn add_system_message(&mut self, content: &str) {
125        self.add_message(Message::system(content));
126    }
127
128    /// Get all messages
129    pub fn messages(&self) -> &[Message] {
130        &self.messages
131    }
132
133    /// Clear messages
134    pub fn clear(&mut self) {
135        self.messages.clear();
136    }
137
138    /// Message count
139    pub fn len(&self) -> usize {
140        self.messages.len()
141    }
142
143    /// Is empty
144    pub fn is_empty(&self) -> bool {
145        self.messages.is_empty()
146    }
147}
148
149impl std::fmt::Display for ChatMessageHistory {
150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151        let formatted: String = self
152            .messages
153            .iter()
154            .map(|msg| {
155                let role = match msg.message_type {
156                    lc_schema::MessageType::Human => "Human",
157                    lc_schema::MessageType::AI => "AI",
158                    lc_schema::MessageType::System => "System",
159                    lc_schema::MessageType::Tool { .. } => "Tool",
160                };
161                format!("{}: {}", role, msg.content)
162            })
163            .collect::<Vec<_>>()
164            .join("\n");
165        write!(f, "{}", formatted)
166    }
167}
168
169impl Default for ChatMessageHistory {
170    fn default() -> Self {
171        Self::new()
172    }
173}
174
175#[cfg(test)]
176mod tests {
177    use super::*;
178
179    #[test]
180    fn test_chat_message_history() {
181        let mut history = ChatMessageHistory::new();
182
183        history.add_user_message("hello");
184        history.add_ai_message("Hello! How can I help you?");
185        history.add_user_message("introduce yourself");
186
187        assert_eq!(history.len(), 3);
188        assert!(!history.is_empty());
189    }
190
191    #[test]
192    fn test_chat_message_history_to_string() {
193        let mut history = ChatMessageHistory::new();
194
195        history.add_user_message("hello");
196        history.add_ai_message("Hello!");
197
198        let str = history.to_string();
199        assert!(str.contains("Human: hello"));
200        assert!(str.contains("AI: Hello!"));
201    }
202
203    #[test]
204    fn test_chat_message_history_clear() {
205        let mut history = ChatMessageHistory::new();
206
207        history.add_user_message("test");
208        assert_eq!(history.len(), 1);
209
210        history.clear();
211        assert_eq!(history.len(), 0);
212        assert!(history.is_empty());
213    }
214}