ubl_office/
memory.rs

1//! Memory system for the Office runtime.
2//!
3//! Manages short-term scratchpad and (future) long-term LLLV storage.
4
5use std::collections::VecDeque;
6
7/// Maximum items in short-term memory.
8const MAX_SHORT_TERM: usize = 100;
9
10/// Memory system for agent state.
11#[derive(Debug, Default)]
12pub struct MemorySystem {
13    /// Short-term buffer (ephemeral notes).
14    short_buffer: VecDeque<String>,
15}
16
17impl MemorySystem {
18    /// Create a new memory system.
19    #[must_use]
20    pub fn new() -> Self {
21        Self {
22            short_buffer: VecDeque::with_capacity(MAX_SHORT_TERM),
23        }
24    }
25
26    /// Add a note to short-term memory.
27    pub fn remember(&mut self, note: impl Into<String>) {
28        if self.short_buffer.len() >= MAX_SHORT_TERM {
29            self.short_buffer.pop_front();
30        }
31        self.short_buffer.push_back(note.into());
32    }
33
34    /// Get recent memories (for recall).
35    #[must_use]
36    pub fn recent(&self, n: usize) -> Vec<String> {
37        self.short_buffer
38            .iter()
39            .rev()
40            .take(n)
41            .cloned()
42            .collect()
43    }
44
45    /// Recall relevant memories for a signal.
46    ///
47    /// Currently returns recent memories; future: semantic search via LLLV.
48    #[must_use]
49    pub fn recall(&self, _signal: &str) -> Vec<String> {
50        self.recent(10)
51    }
52
53    /// Clear short-term memory.
54    pub fn clear_short_term(&mut self) {
55        self.short_buffer.clear();
56    }
57
58    /// Consolidate recent events into long-term storage.
59    ///
60    /// Stub for now; future: embed → pack → commit proof to LLLV.
61    pub fn consolidate(&mut self, _events: &[String]) {
62        // TODO: Implement LLLV consolidation
63        // For now, just trim the short buffer
64        while self.short_buffer.len() > MAX_SHORT_TERM / 2 {
65            self.short_buffer.pop_front();
66        }
67    }
68
69    /// Get the number of items in short-term memory.
70    #[must_use]
71    pub fn short_term_len(&self) -> usize {
72        self.short_buffer.len()
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    #[test]
81    fn remember_and_recall() {
82        let mut mem = MemorySystem::new();
83        mem.remember("event 1");
84        mem.remember("event 2");
85        mem.remember("event 3");
86
87        let recent = mem.recent(2);
88        assert_eq!(recent.len(), 2);
89        assert_eq!(recent[0], "event 3");
90        assert_eq!(recent[1], "event 2");
91    }
92
93    #[test]
94    fn memory_cap() {
95        let mut mem = MemorySystem::new();
96        for i in 0..150 {
97            mem.remember(format!("event {i}"));
98        }
99        assert_eq!(mem.short_term_len(), MAX_SHORT_TERM);
100    }
101
102    #[test]
103    fn consolidate_trims() {
104        let mut mem = MemorySystem::new();
105        for i in 0..80 {
106            mem.remember(format!("event {i}"));
107        }
108        mem.consolidate(&[]);
109        assert!(mem.short_term_len() <= MAX_SHORT_TERM / 2);
110    }
111}