Skip to main content

synaptic_memory/
history.rs

1use std::sync::Arc;
2
3use async_trait::async_trait;
4use synaptic_core::{MemoryStore, Message, RunnableConfig, SynapticError};
5use synaptic_runnables::{BoxRunnable, Runnable};
6
7/// Wraps a `Runnable<Vec<Message>, String>` with automatic message history
8/// load/save from a `MemoryStore`.
9///
10/// On each invocation:
11/// 1. Extracts `session_id` from `config.metadata["session_id"]` (defaults to `"default"`)
12/// 2. Loads conversation history from memory
13/// 3. Appends `Message::human(input)` to the history
14/// 4. Calls the inner runnable with the full message list
15/// 5. Appends `Message::ai(output)` to memory
16/// 6. Returns the output string
17pub struct RunnableWithMessageHistory {
18    inner: BoxRunnable<Vec<Message>, String>,
19    memory: Arc<dyn MemoryStore>,
20}
21
22impl RunnableWithMessageHistory {
23    /// Create a new history-aware runnable wrapper.
24    pub fn new(inner: BoxRunnable<Vec<Message>, String>, memory: Arc<dyn MemoryStore>) -> Self {
25        Self { inner, memory }
26    }
27}
28
29#[async_trait]
30impl Runnable<String, String> for RunnableWithMessageHistory {
31    async fn invoke(
32        &self,
33        input: String,
34        config: &RunnableConfig,
35    ) -> Result<String, SynapticError> {
36        // Extract session_id from config metadata
37        let session_id = config
38            .metadata
39            .get("session_id")
40            .and_then(|v| v.as_str())
41            .unwrap_or("default")
42            .to_string();
43
44        // Load existing history
45        let mut messages = self.memory.load(&session_id).await?;
46
47        // Append the new human message
48        let human_msg = Message::human(&input);
49        messages.push(human_msg.clone());
50        self.memory.append(&session_id, human_msg).await?;
51
52        // Call the inner runnable with the full message list
53        let output = self.inner.invoke(messages, config).await?;
54
55        // Save the AI response to memory
56        let ai_msg = Message::ai(&output);
57        self.memory.append(&session_id, ai_msg).await?;
58
59        Ok(output)
60    }
61}