Skip to main content

mlrs_core/
protocol.rs

1use serde::{Deserialize, Serialize};
2
3/// The result of executing one Rhai cell in the RLM loop.
4#[derive(Debug, Clone)]
5pub enum StepResult {
6    /// Script ran, produced output — loop continues with this output appended to the notebook.
7    Continue(String),
8    /// Model called `final(answer)` — loop exits, answer is returned to caller.
9    Final(String),
10}
11
12/// A single executed cell: the script the model wrote and its output.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Cell {
15    pub script: String,
16    pub output: String,
17}
18
19/// Accumulated history of all cells executed in one RLM run.
20#[derive(Debug, Clone, Default, Serialize, Deserialize)]
21pub struct Notebook {
22    pub cells: Vec<Cell>,
23}
24
25impl Notebook {
26    pub fn push(&mut self, script: String, output: String) {
27        self.cells.push(Cell { script, output });
28    }
29
30    /// Render cells as a message history string for the LLM.
31    pub fn as_history(&self) -> String {
32        self.cells
33            .iter()
34            .enumerate()
35            .map(|(i, c)| {
36                format!(
37                    "# Cell {}\n```\n{}\n```\nOutput:\n{}",
38                    i, c.script, c.output
39                )
40            })
41            .collect::<Vec<_>>()
42            .join("\n\n")
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn notebook_push_and_history() {
52        let mut nb = Notebook::default();
53        assert!(nb.as_history().is_empty());
54        nb.push("ctx_len()".into(), "42".into());
55        let h = nb.as_history();
56        assert!(h.contains("Cell 0"));
57        assert!(h.contains("ctx_len()"));
58        assert!(h.contains("42"));
59    }
60
61    #[test]
62    fn step_result_variants() {
63        let c = StepResult::Continue("out".into());
64        let f = StepResult::Final("answer".into());
65        assert!(matches!(c, StepResult::Continue(_)));
66        assert!(matches!(f, StepResult::Final(_)));
67    }
68}