Skip to main content

lmm_agent/cognition/learning/
store.rs

1// Copyright 2026 Mahmoud Harmouch.
2//
3// Licensed under the MIT license
4// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
5// option. This file may not be copied, modified, or distributed
6// except according to those terms.
7
8//! # `LearningStore` - persistent serialisation of HELM learning state.
9//!
10//! `LearningStore` serialises and deserialises the complete `LearningEngine`
11//! state (Q-table, meta-prototypes, distiller fingerprints, elastic guard
12//! activation counts, PMI pair counts) to/from a JSON file on disk.
13//!
14//! This provides **long-term persistence** across process restarts: an agent
15//! that has been saved can be restored and continue learning from where it
16//! left off, fulfilling the *smart lifelong learning* requirement.
17//!
18//! ## Examples
19//!
20//! ```rust
21//! use lmm_agent::cognition::learning::store::LearningStore;
22//! use lmm_agent::cognition::learning::engine::LearningEngine;
23//! use lmm_agent::cognition::learning::config::LearningConfig;
24//!
25//! let engine = LearningEngine::new(LearningConfig::default());
26//! let path = std::env::temp_dir().join(format!("test_helm_store_{}.json", uuid::Uuid::new_v4()));
27//!
28//! LearningStore::save(&engine, &path).unwrap();
29//! let loaded = LearningStore::load(&path).unwrap();
30//! assert_eq!(loaded.q_table().state_count(), engine.q_table().state_count());
31//! ```
32
33use crate::cognition::learning::engine::LearningEngine;
34use anyhow::{Result, anyhow};
35use std::fs;
36use std::path::Path;
37
38/// Round-trip serialisation helper for [`LearningEngine`].
39pub struct LearningStore;
40
41impl LearningStore {
42    /// Serialises `engine` to a JSON file at `path`.
43    ///
44    /// Creates the file (and all parent directories) if they do not exist.
45    ///
46    /// # Errors
47    ///
48    /// Returns an error if serialisation fails or the file cannot be created.
49    ///
50    /// # Examples
51    ///
52    /// ```rust
53    /// use lmm_agent::cognition::learning::store::LearningStore;
54    /// use lmm_agent::cognition::learning::engine::LearningEngine;
55    /// use lmm_agent::cognition::learning::config::LearningConfig;
56    ///
57    /// let engine = LearningEngine::new(LearningConfig::default());
58    /// let path = std::env::temp_dir().join(format!("helm_doctest_{}.json", uuid::Uuid::new_v4()));
59    /// LearningStore::save(&engine, &path).unwrap();
60    /// ```
61    pub fn save(engine: &LearningEngine, path: &Path) -> Result<()> {
62        if let Some(parent) = path.parent()
63            && !parent.as_os_str().is_empty()
64        {
65            fs::create_dir_all(parent)
66                .map_err(|e| anyhow!("Cannot create dir {:?}: {e}", parent))?;
67        }
68        let json = serde_json::to_string_pretty(engine)
69            .map_err(|e| anyhow!("Serialisation error: {e}"))?;
70        fs::write(path, &json).map_err(|e| anyhow!("Cannot write {:?}: {e}", path))
71    }
72
73    /// Deserialises a [`LearningEngine`] from the JSON file at `path`.
74    ///
75    /// # Errors
76    ///
77    /// Returns an error if the file cannot be read or if the JSON is malformed.
78    ///
79    /// # Examples
80    ///
81    /// ```rust
82    /// use lmm_agent::cognition::learning::store::LearningStore;
83    /// use lmm_agent::cognition::learning::engine::LearningEngine;
84    /// use lmm_agent::cognition::learning::config::LearningConfig;
85    ///
86    /// let engine = LearningEngine::new(LearningConfig::default());
87    /// let path = std::env::temp_dir().join(format!("helm_load_doctest_{}.json", uuid::Uuid::new_v4()));
88    /// LearningStore::save(&engine, &path).unwrap();
89    /// let loaded = LearningStore::load(&path).unwrap();
90    /// assert_eq!(loaded.config().alpha, engine.config().alpha);
91    /// ```
92    pub fn load(path: &Path) -> Result<LearningEngine> {
93        let json = fs::read_to_string(path).map_err(|e| anyhow!("Cannot read {:?}: {e}", path))?;
94        serde_json::from_str(&json).map_err(|e| anyhow!("Deserialisation error in {:?}: {e}", path))
95    }
96}
97
98// Copyright 2026 Mahmoud Harmouch.
99//
100// Licensed under the MIT license
101// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
102// option. This file may not be copied, modified, or distributed
103// except according to those terms.