1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone)]
5pub enum StepResult {
6 Continue(String),
8 Final(String),
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Cell {
15 pub script: String,
16 pub output: String,
17}
18
19#[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 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}