1use async_trait::async_trait;
7use serde_json::Value;
8use std::collections::HashMap;
9
10use super::base::{BaseMemory, ChatMessageHistory, MemoryError};
11use lc_schema::Message;
12
13#[derive(Debug)]
33pub struct ConversationBufferMemory {
34 chat_memory: ChatMessageHistory,
36
37 input_key: String,
39
40 output_key: String,
42
43 memory_key: String,
45
46 return_messages: bool,
48}
49
50impl ConversationBufferMemory {
51 pub fn new() -> Self {
53 Self {
54 chat_memory: ChatMessageHistory::new(),
55 input_key: "input".to_string(),
56 output_key: "output".to_string(),
57 memory_key: "history".to_string(),
58 return_messages: false,
59 }
60 }
61
62 pub fn with_input_key(mut self, key: String) -> Self {
64 self.input_key = key;
65 self
66 }
67
68 pub fn with_output_key(mut self, key: String) -> Self {
70 self.output_key = key;
71 self
72 }
73
74 pub fn with_memory_key(mut self, key: String) -> Self {
76 self.memory_key = key;
77 self
78 }
79
80 pub fn with_return_messages(mut self, return_messages: bool) -> Self {
82 self.return_messages = return_messages;
83 self
84 }
85
86 pub fn from_chat_memory(chat_memory: ChatMessageHistory) -> Self {
88 Self {
89 chat_memory,
90 ..Self::new()
91 }
92 }
93
94 pub fn chat_memory(&self) -> &ChatMessageHistory {
96 &self.chat_memory
97 }
98
99 pub fn chat_memory_mut(&mut self) -> &mut ChatMessageHistory {
101 &mut self.chat_memory
102 }
103
104 fn buffer_as_string(&self) -> String {
106 self.chat_memory.to_string()
107 }
108
109 fn buffer_as_messages(&self) -> Vec<Message> {
111 self.chat_memory.messages().to_vec()
112 }
113}
114
115impl Default for ConversationBufferMemory {
116 fn default() -> Self {
117 Self::new()
118 }
119}
120
121#[async_trait]
122impl BaseMemory for ConversationBufferMemory {
123 fn memory_variables(&self) -> Vec<&str> {
124 vec![&self.memory_key]
125 }
126
127 async fn load_memory_variables(
128 &self,
129 _inputs: &HashMap<String, String>,
130 ) -> Result<HashMap<String, Value>, MemoryError> {
131 let mut result = HashMap::new();
132
133 if self.return_messages {
134 let messages: Vec<Value> = self
136 .buffer_as_messages()
137 .into_iter()
138 .map(|msg| serde_json::to_value(&msg).unwrap_or(Value::Null))
139 .collect();
140 result.insert(self.memory_key.clone(), Value::Array(messages));
141 } else {
142 result.insert(
144 self.memory_key.clone(),
145 Value::String(self.buffer_as_string()),
146 );
147 }
148
149 Ok(result)
150 }
151
152 async fn save_context(
153 &mut self,
154 inputs: &HashMap<String, String>,
155 outputs: &HashMap<String, String>,
156 ) -> Result<(), MemoryError> {
157 let input = inputs.get(&self.input_key).ok_or_else(|| {
159 MemoryError::SaveError(format!("Missing input key '{}'", self.input_key))
160 })?;
161 self.chat_memory.add_user_message(input);
162
163 let output = outputs.get(&self.output_key).ok_or_else(|| {
164 MemoryError::SaveError(format!("Missing output key '{}'", self.output_key))
165 })?;
166 self.chat_memory.add_ai_message(output);
167
168 Ok(())
169 }
170
171 async fn clear(&mut self) -> Result<(), MemoryError> {
172 self.chat_memory.clear();
173 Ok(())
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180
181 #[tokio::test]
182 async fn test_conversation_buffer_memory() {
183 let mut memory = ConversationBufferMemory::new();
184
185 let inputs = HashMap::from([("input".to_string(), "Hello".to_string())]);
187 let outputs = HashMap::from([(
188 "output".to_string(),
189 "Hello! How can I help you?".to_string(),
190 )]);
191
192 memory.save_context(&inputs, &outputs).await.unwrap();
193
194 let memory_vars = memory.load_memory_variables(&HashMap::new()).await.unwrap();
196
197 assert!(memory_vars.contains_key("history"));
198 let history = memory_vars.get("history").unwrap();
199 assert!(history.as_str().unwrap().contains("Human: Hello"));
200 assert!(history.as_str().unwrap().contains("AI: Hello"));
201 }
202
203 #[tokio::test]
204 async fn test_conversation_buffer_memory_multiple() {
205 let mut memory = ConversationBufferMemory::new();
206
207 let inputs1 = HashMap::from([("input".to_string(), "My name is Zhang San".to_string())]);
209 let outputs1 = HashMap::from([("output".to_string(), "Hello Zhang San!".to_string())]);
210 memory.save_context(&inputs1, &outputs1).await.unwrap();
211
212 let inputs2 = HashMap::from([("input".to_string(), "What is my name?".to_string())]);
214 let outputs2 =
215 HashMap::from([("output".to_string(), "Your name is Zhang San".to_string())]);
216 memory.save_context(&inputs2, &outputs2).await.unwrap();
217
218 let memory_vars = memory.load_memory_variables(&HashMap::new()).await.unwrap();
220 let history = memory_vars.get("history").unwrap().as_str().unwrap();
221
222 assert!(history.contains("Zhang San"));
223 assert!(memory.chat_memory().len() == 4); }
225
226 #[tokio::test]
227 async fn test_conversation_buffer_memory_clear() {
228 let mut memory = ConversationBufferMemory::new();
229
230 let inputs = HashMap::from([("input".to_string(), "test".to_string())]);
232 let outputs = HashMap::from([("output".to_string(), "received".to_string())]);
233 memory.save_context(&inputs, &outputs).await.unwrap();
234
235 assert_eq!(memory.chat_memory().len(), 2);
236
237 memory.clear().await.unwrap();
239 assert_eq!(memory.chat_memory().len(), 0);
240 }
241
242 #[tokio::test]
243 async fn test_conversation_buffer_memory_return_messages() {
244 let mut memory = ConversationBufferMemory::new().with_return_messages(true);
245
246 let inputs = HashMap::from([("input".to_string(), "Hello".to_string())]);
247 let outputs = HashMap::from([("output".to_string(), "Hello!".to_string())]);
248 memory.save_context(&inputs, &outputs).await.unwrap();
249
250 let memory_vars = memory.load_memory_variables(&HashMap::new()).await.unwrap();
251 let history = memory_vars.get("history").unwrap();
252
253 assert!(history.is_array());
255 let messages = history.as_array().unwrap();
256 assert_eq!(messages.len(), 2);
257 }
258}