Skip to main content

microscope_memory/
sequential_thinking.rs

1//! Sequential Thinking — Chain-of-Thought layer for Microscope Memory.
2//! This module organizes memory retrievals into logical sequences (Steps).
3
4use crate::config::Config;
5use crate::reader::MicroscopeReader;
6use std::time::Instant;
7
8#[derive(Debug, Clone)]
9pub struct ThoughtStep {
10    pub thought_number: usize,
11    pub total_thoughts: usize,
12    pub content: String,
13    pub is_revision: bool,
14    pub revises_thought: Option<usize>,
15    pub timestamp: Instant,
16}
17
18pub struct ThinkingChain {
19    pub steps: Vec<ThoughtStep>,
20    pub max_steps: usize,
21    pub next_thought_needed: bool,
22}
23
24impl ThinkingChain {
25    pub fn new(max_steps: usize) -> Self {
26        Self {
27            steps: Vec::new(),
28            max_steps,
29            next_thought_needed: true,
30        }
31    }
32
33    /// Appends a new thought to the sequence.
34    pub fn add_step(&mut self, content: String, is_revision: bool, revises: Option<usize>) {
35        let step_num = self.steps.len() + 1;
36        self.steps.push(ThoughtStep {
37            thought_number: step_num,
38            total_thoughts: self.max_steps,
39            content,
40            is_revision,
41            revises_thought: revises,
42            timestamp: Instant::now(),
43        });
44
45        if step_num >= self.max_steps {
46            self.next_thought_needed = false;
47        }
48    }
49
50    /// Evaluates the Hebbian field to determine the next logical memory block.
51    pub fn brainstorm(&mut self, reader: &MicroscopeReader, config: &Config, initial_query: &str) {
52        println!("🧠 Sequential Thinking: Processing '{}'...", initial_query);
53
54        // Step 1: Initial search (text-based fallback for the seed)
55        let results = reader.find_text(initial_query, 5);
56        if let Some(&(_depth, idx)) = results.first() {
57            self.add_step(reader.text(idx).to_string(), false, None);
58        }
59
60        // Step 2-N: Iterative refinement based on previous step using spatial radial search
61        while self.next_thought_needed && self.steps.len() < self.max_steps {
62            let last_idx = if let Some(last) = self.steps.last() {
63                // We'd ideally need the index, but let's re-search for now
64                let text = &last.content;
65                reader
66                    .find_text(text, 1)
67                    .first()
68                    .map(|&(_, i)| i)
69                    .unwrap_or(0)
70            } else {
71                break;
72            };
73
74            let h = reader.header(last_idx);
75
76            // Radial search to find similar/nearby memories in the Hebbian field (spatial mmap)
77            let result_set = reader.radial_search(
78                config,
79                h.x,
80                h.y,
81                h.z,
82                h.depth,
83                config.search.zoom_weight * 0.5, // radius
84                10,                              // k
85            );
86
87            let retrieved: Vec<String> = result_set
88                .all()
89                .iter()
90                .map(|r| reader.text(r.block_idx).to_string())
91                .collect();
92
93            if let Some(next_text) = retrieved.get(1) {
94                // 2nd best as a "new branch/association"
95                self.add_step(next_text.clone(), false, None);
96            } else {
97                self.next_thought_needed = false;
98            }
99        }
100    }
101
102    pub fn display(&self) {
103        for step in &self.steps {
104            let prefix = if step.is_revision {
105                "🔄 REVISION"
106            } else {
107                "💭 THOUGHT"
108            };
109            println!(
110                "[{}/{}] {} ({}): {}",
111                step.thought_number,
112                step.total_thoughts,
113                prefix,
114                step.revises_thought
115                    .map(|n| n.to_string())
116                    .unwrap_or_else(|| "new".to_string()),
117                step.content
118            );
119        }
120    }
121}