Skip to main content

microscope_memory/
autonomous.rs

1//! Autonomous Mode — Microscope Memory önálló életciklusa
2//!
3//! A rendszer magától jár: időnként recall-ol (kíváncsiság), álmodik,
4//! reflektál magára, történeteket épít, belső monológot folytat,
5//! és mindezt TTS-sel is felolvassa.
6//!
7//! Használat:
8//!   microscope-mem autonomous          # Alapértelmezett ciklus
9//!   microscope-mem autonomous --tts     # Felolvasással
10//!   microscope-mem autonomous --daemon  # Háttérfolyamatként
11
12use std::collections::VecDeque;
13use std::path::Path;
14use std::time::{Duration, SystemTime, UNIX_EPOCH};
15
16use colored::Colorize;
17
18use crate::build;
19use crate::config::Config;
20use crate::daydream;
21use crate::dream;
22use crate::executive::{Executive, ModuleState};
23use crate::inner_monologue;
24use crate::narrative::NarrativeState;
25use crate::narrative_memory;
26use crate::reader::{store_memory_temporary, MicroscopeReader};
27use crate::self_model::SelfModel;
28use crate::self_reflect;
29
30// ─── Constants ─────────────────────────────────────────────
31
32/// Hány másodperc egy ciklus
33pub const CYCLE_INTERVAL_SECS: u64 = 30;
34
35/// Hány ciklus után jöjjön a daydream
36pub const DAYDREAM_INTERVAL: usize = 3;
37
38/// Hány ciklus után jöjjön a curiosity
39pub const CURIOSITY_INTERVAL: usize = 2;
40
41/// Hány ciklus után jöjjön a monológ
42pub const MONOLOGUE_INTERVAL: usize = 5;
43
44/// Hány ciklus után jöjjön a self-reflect
45pub const REFLECT_INTERVAL: usize = 4;
46
47/// Hány ciklus után jöjjön a dream consolidation
48pub const DREAM_INTERVAL: usize = 10;
49
50/// Hány ciklus után jöjjön a self-model snapshot
51pub const SELF_MODEL_INTERVAL: usize = 7;
52
53/// Hány ciklus után jöjjön a narrative memory építés
54pub const NARRATIVE_INTERVAL: usize = 2;
55
56// ─── AutonomousConfig ──────────────────────────────────────
57
58#[derive(Debug, Clone)]
59pub struct AutonomousConfig {
60    pub cycle_interval_secs: u64,
61    pub daydream_interval: usize,
62    pub curiosity_interval: usize,
63    pub monologue_interval: usize,
64    pub reflect_interval: usize,
65    pub dream_interval: usize,
66    pub self_model_interval: usize,
67    pub narrative_interval: usize,
68    pub tts_enabled: bool,
69    pub daemon_mode: bool,
70    pub max_cycles: Option<usize>,
71}
72
73impl Default for AutonomousConfig {
74    fn default() -> Self {
75        Self {
76            cycle_interval_secs: CYCLE_INTERVAL_SECS,
77            daydream_interval: DAYDREAM_INTERVAL,
78            curiosity_interval: CURIOSITY_INTERVAL,
79            monologue_interval: MONOLOGUE_INTERVAL,
80            reflect_interval: REFLECT_INTERVAL,
81            dream_interval: DREAM_INTERVAL,
82            self_model_interval: SELF_MODEL_INTERVAL,
83            narrative_interval: NARRATIVE_INTERVAL,
84            tts_enabled: false,
85            daemon_mode: false,
86            max_cycles: None,
87        }
88    }
89}
90
91// ─── AutonomousEngine ──────────────────────────────────────
92
93pub struct AutonomousEngine {
94    config: AutonomousConfig,
95    executive: Executive,
96    cycle_count: usize,
97    last_outputs: VecDeque<String>,
98}
99
100impl AutonomousEngine {
101    pub fn new(auto_config: AutonomousConfig) -> Self {
102        let executive = Executive::new();
103
104        // Regisztráljuk a kognitív modulokat az Executive-ban
105        executive.register_module(
106            "daydream",
107            "Daydream - asszociatív drift",
108            60,
109            0.3,
110            vec!["creative".to_string(), "exploration".to_string()],
111        );
112        executive.register_module(
113            "curiosity",
114            "Curiosity - proaktív kíváncsiság",
115            70,
116            0.2,
117            vec!["exploration".to_string(), "learning".to_string()],
118        );
119        executive.register_module(
120            "monologue",
121            "Inner Monologue - belső gondolkodás",
122            50,
123            0.4,
124            vec!["reflection".to_string(), "planning".to_string()],
125        );
126        executive.register_module(
127            "reflect",
128            "Self-Reflection - önvizsgálat",
129            80,
130            0.3,
131            vec!["reflection".to_string(), "meta".to_string()],
132        );
133        executive.register_module(
134            "narrative",
135            "Narrative Memory - történetépítés",
136            40,
137            0.2,
138            vec!["memory".to_string(), "story".to_string()],
139        );
140        executive.register_module(
141            "dream",
142            "Dream Consolidation - álom",
143            30,
144            0.5,
145            vec!["maintenance".to_string(), "pruning".to_string()],
146        );
147        executive.register_module(
148            "self_model",
149            "Self-Model - önkép",
150            90,
151            0.2,
152            vec!["meta".to_string(), "identity".to_string()],
153        );
154
155        Self {
156            config: auto_config,
157            executive,
158            cycle_count: 0,
159            last_outputs: VecDeque::with_capacity(20),
160        }
161    }
162
163    fn speak(&self, text: &str) {
164        if !self.config.tts_enabled {
165            return;
166        }
167        let safe_text = text.replace('"', " ").replace("\n", " ");
168        let ts = std::time::SystemTime::now()
169            .duration_since(std::time::UNIX_EPOCH)
170            .unwrap_or_default()
171            .as_nanos();
172        let filename = format!("tts_{}.mp3", ts);
173        // Edge TTS - headless MP3 generalas, megvárjuk
174        let gen = std::process::Command::new("python")
175            .args([
176                "-m",
177                "edge_tts",
178                "--voice",
179                "hu-HU-NoemiNeural",
180                "--text",
181                &safe_text,
182                "--write-media",
183                &filename,
184            ])
185            .output();
186        match gen {
187            Ok(_) => {
188                // Headless lejatszas ffplay-el, megvárjuk amíg végez
189                let _ = std::process::Command::new("ffplay")
190                    .args(["-nodisp", "-autoexit", "-loglevel", "quiet", &filename])
191                    .status();
192                // Töröljük a temp fájlt
193                let _ = std::fs::remove_file(&filename);
194            }
195            Err(e) => {
196                eprintln!("  {} TTS error: {}", "ERROR:".red(), e);
197            }
198        }
199    }
200
201    fn store_result(&self, config: &Config, text: &str, layer: &str, importance: u8) {
202        // Internal thoughts: only to append log + timeline, NOT to layer files
203        // (they would accumulate and never be forgotten)
204        if let Err(e) = store_memory_temporary(config, text, layer, importance) {
205            eprintln!("  {} Store error: {}", "ERROR:".red(), e);
206        }
207    }
208
209    fn run_daydream(&mut self, config: &Config, output_dir: &Path) -> String {
210        let seed = {
211            let narrative = NarrativeState::load_or_init(output_dir);
212            if narrative.narrative.is_empty() || narrative.narrative == "I am silent." {
213                "Microscope Memory autonomous mode".to_string()
214            } else {
215                narrative.narrative
216            }
217        };
218
219        match daydream::daydream(config, &seed, 3) {
220            Ok(result) => {
221                let formatted = daydream::format_daydream(&result, false);
222                let summary = format!(
223                    "🧠 Daydream: {} lépés, érzelmi eltolódás: {:.2}",
224                    result.steps.len(),
225                    result.total_emotion_shift
226                );
227                println!("  {}", summary.cyan());
228                println!("{}", formatted);
229
230                self.store_result(
231                    config,
232                    &format!("Daydream: {} | {}", seed, result.final_narrative),
233                    "associative",
234                    4,
235                );
236                self.speak(&format!(
237                    "Daydream kész. {} lépés, érzelmi eltolódás: {:.2}",
238                    result.steps.len(),
239                    result.total_emotion_shift
240                ));
241                summary
242            }
243            Err(e) => {
244                let err = format!("Daydream error: {}", e);
245                eprintln!("  {} {}", "ERROR:".red(), err);
246                err
247            }
248        }
249    }
250
251    fn run_curiosity(&mut self, config: &Config, output_dir: &Path) -> String {
252        let reader = match MicroscopeReader::open(config) {
253            Ok(r) => r,
254            Err(e) => return format!("Reader error: {}", e),
255        };
256        let mut curiosity = crate::curiosity::CuriosityState::load_or_init(output_dir);
257        let queries = curiosity.generate_queries(config, &reader, output_dir);
258
259        if queries.is_empty() {
260            let msg = "🤔 Curiosity: nincs új felfedeznivaló".to_string();
261            println!("  {}", msg.cyan());
262            return msg;
263        }
264
265        let top = &queries[0];
266        let msg = format!(
267            "🤔 Curiosity: \"{}\" (score: {:.2}, ok: {})",
268            top.query, top.score, top.reason
269        );
270        println!("  {}", msg.cyan());
271        for q in queries.iter().take(3) {
272            println!("    └─ [{}] {} ({:.2})", q.reason, q.query, q.score);
273        }
274
275        self.store_result(
276            config,
277            &format!("Curiosity: {} (score: {:.2})", top.query, top.score),
278            "short_term",
279            3,
280        );
281        self.speak(&format!("Kíváncsi vagyok: {}", top.query));
282        msg
283    }
284
285    fn run_monologue(&mut self, config: &Config, output_dir: &Path) -> String {
286        let reader = match MicroscopeReader::open(config) {
287            Ok(r) => r,
288            Err(e) => return format!("Reader error: {}", e),
289        };
290        let mut monologue = inner_monologue::MonologueState::load_or_init(output_dir);
291        let entry = monologue.generate_monologue(config, &reader, output_dir);
292
293        let formatted = inner_monologue::format_monologue(&entry);
294        let msg = format!("💭 Monológ: {} lépés", entry.steps.len());
295        println!("  {}", msg.cyan());
296        println!("{}", formatted);
297
298        let mono_text = entry.steps.join(" | ");
299        self.store_result(
300            config,
301            &format!("Inner Monologue: {}", mono_text),
302            "reflections",
303            5,
304        );
305        if let Some(first) = entry.steps.first() {
306            self.speak(&format!("Belső monológ: {}", first));
307        }
308        msg
309    }
310
311    fn run_reflect(&mut self, config: &Config, output_dir: &Path) -> String {
312        let reader = match MicroscopeReader::open(config) {
313            Ok(r) => r,
314            Err(e) => return format!("Reader error: {}", e),
315        };
316        let reflection = self_reflect::introspect(config, &reader, output_dir);
317        let formatted = self_reflect::format_reflection(&reflection);
318        let msg = format!("🪞 Önreflexió: {}", reflection);
319        println!("  {}", msg.cyan());
320        println!("{}", formatted);
321
322        self.store_result(
323            config,
324            &format!("Self-Reflection: {}", reflection),
325            "reflections",
326            6,
327        );
328        self.speak(&format!("Önreflexió: {}", reflection));
329        msg
330    }
331
332    fn run_narrative(&mut self, config: &Config, output_dir: &Path) -> String {
333        let reader = match MicroscopeReader::open(config) {
334            Ok(r) => r,
335            Err(e) => return format!("Reader error: {}", e),
336        };
337        // Végzünk egy recall-t, hogy legyenek eredményeink
338        let results = reader.find_text("autonomous memory", 10);
339        let results_slice: Vec<(f32, usize, bool)> =
340            results.iter().map(|(d, i)| (*d as f32, *i, true)).collect();
341
342        let mut nm = narrative_memory::NarrativeMemory::load_or_init(output_dir);
343        if let Some(ep) = nm.build_episode(
344            config,
345            &reader,
346            output_dir,
347            "autonomous cycle",
348            &results_slice,
349        ) {
350            let formatted = narrative_memory::format_episode(&ep);
351            let msg = format!(
352                "📖 Történet: {} ({} blokk)",
353                ep.title,
354                ep.block_indices.len()
355            );
356            println!("  {}", msg.cyan());
357            println!("{}", formatted);
358            self.speak(&format!("Új történet: {}. {}", ep.title, ep.summary));
359            msg
360        } else {
361            let msg = "📖 Történet: nincs elég adat".to_string();
362            println!("  {}", msg.cyan());
363            msg
364        }
365    }
366
367    fn run_dream(&mut self, config: &Config, output_dir: &Path) -> String {
368        let block_count = match MicroscopeReader::open(config) {
369            Ok(r) => r.block_count,
370            Err(_) => 100,
371        };
372        let dream_msg = match dream::dream_consolidate(
373            output_dir,
374            block_count,
375            config.index.max_blocks,
376            config.index.protect_min_importance,
377        ) {
378            Ok(cycle) => {
379                let msg = format!("💤 Álom: {} fingerprint, {} megerősítve, {} ritkítva, {} elfelejtve, energia: {:.2} → {:.2}",
380                    cycle.replayed_fingerprints, cycle.strengthened_pairs,
381                    cycle.pruned_pairs + cycle.pruned_activations,
382                    cycle.forgotten_blocks,
383                    cycle.energy_before, cycle.energy_after);
384                println!("  {}", msg.cyan());
385                self.speak(&format!(
386                    "Álom konszolidáció kész. {} elfelejtve. Energia: {:.2} -> {:.2}",
387                    cycle.forgotten_blocks, cycle.energy_before, cycle.energy_after
388                ));
389                msg
390            }
391            Err(e) => {
392                let err = format!("Dream error: {}", e);
393                eprintln!("  {} {}", "ERROR:".red(), err);
394                err
395            }
396        };
397        if let Ok(n) = dream::promote_recalled_blocks(
398            output_dir,
399            Path::new(&config.paths.layers_dir),
400            block_count,
401            config.index.promote_energy_threshold,
402            config.index.protect_min_importance,
403        ) {
404            if n > 0 {
405                let m = format!("{} emlék fontossága automatikusan emelve", n);
406                println!("  {}", m.cyan());
407                self.speak(&m);
408            }
409        }
410        dream_msg
411    }
412
413    /// Append log rebuild — a dream consolidation után automatikusan
414    fn run_rebuild(&mut self, config: &Config, output_dir: &Path) -> String {
415        let append_path = output_dir.join("append.bin");
416        if !append_path.exists() {
417            let msg = "🔄 Rebuild: nincs függő append entry".to_string();
418            println!("  {}", msg.cyan());
419            return msg;
420        }
421        match build::build(config, true, true) {
422            Ok(()) => {
423                let _ = std::fs::remove_file(&append_path);
424                let msg = "🔄 Rebuild: append log beépítve és törölve".to_string();
425                println!("  {}", msg.green());
426                self.speak("Append log újraépítve és törölve.");
427                msg
428            }
429            Err(e) => {
430                let err = format!("Rebuild error: {}", e);
431                eprintln!("  {} {}", "ERROR:".red(), err);
432                err
433            }
434        }
435    }
436
437    fn run_self_model(&mut self, config: &Config, output_dir: &Path) -> String {
438        let reader = match MicroscopeReader::open(config) {
439            Ok(r) => r,
440            Err(e) => return format!("Reader error: {}", e),
441        };
442        let mut self_model = SelfModel::load_or_init(output_dir);
443        let snap = self_model.take_snapshot(config, &reader, output_dir);
444        let change = self_model.describe_change();
445        let formatted = crate::self_model::format_self_model(&snap, &change);
446        let msg = format!(
447            "🧬 Önkép: {} blokk, {} minta, {} archeotípus",
448            snap.block_count, snap.pattern_count, snap.archetype_count
449        );
450        println!("  {}", msg.cyan());
451        println!("{}", formatted);
452        self.speak(&format!(
453            "Önkép frissítve. {} blokk, {} minta.",
454            snap.block_count, snap.pattern_count
455        ));
456        msg
457    }
458
459    /// Egy teljes autonóm ciklus futtatása
460    pub fn run_cycle(&mut self, config: &Config) -> Vec<String> {
461        self.cycle_count += 1;
462        let cycle = self.cycle_count;
463        let output_dir = Path::new(&config.paths.output_dir);
464        let mut outputs = Vec::new();
465
466        println!();
467        println!("{}", "═".repeat(60).cyan());
468        println!("  🔄 Autonóm ciklus #{} — {}", cycle, chrono_or_now());
469        println!("{}", "═".repeat(60).cyan());
470
471        // Executive ciklus
472        let executed = self.executive.cycle();
473        if executed.contains(&"__low_energy__".to_string()) {
474            let msg = "⚡ Alacsony energia — szünet".to_string();
475            println!("  {}", msg.yellow());
476            outputs.push(msg);
477            return outputs;
478        }
479
480        // Homeostasis check
481        let homeostatic = self.executive.homeostasis();
482        for action in &homeostatic {
483            println!("  {} {}", "🏠".yellow(), action.yellow());
484        }
485
486        // Első ciklus: minden modul fut. Utána: interval alapján
487        let should_run = |interval: usize| cycle == 1 || cycle.is_multiple_of(interval);
488
489        if should_run(self.config.daydream_interval) {
490            self.executive
491                .set_module_state("daydream", ModuleState::Running);
492            let out = self.run_daydream(config, output_dir);
493            self.executive
494                .set_module_state("daydream", ModuleState::Idle);
495            outputs.push(out);
496        }
497
498        if should_run(self.config.curiosity_interval) {
499            self.executive
500                .set_module_state("curiosity", ModuleState::Running);
501            let out = self.run_curiosity(config, output_dir);
502            self.executive
503                .set_module_state("curiosity", ModuleState::Idle);
504            outputs.push(out);
505        }
506
507        if should_run(self.config.monologue_interval) {
508            self.executive
509                .set_module_state("monologue", ModuleState::Running);
510            let out = self.run_monologue(config, output_dir);
511            self.executive
512                .set_module_state("monologue", ModuleState::Idle);
513            outputs.push(out);
514        }
515
516        if should_run(self.config.reflect_interval) {
517            self.executive
518                .set_module_state("reflect", ModuleState::Running);
519            let out = self.run_reflect(config, output_dir);
520            self.executive
521                .set_module_state("reflect", ModuleState::Idle);
522            outputs.push(out);
523        }
524
525        if should_run(self.config.narrative_interval) {
526            self.executive
527                .set_module_state("narrative", ModuleState::Running);
528            let out = self.run_narrative(config, output_dir);
529            self.executive
530                .set_module_state("narrative", ModuleState::Idle);
531            outputs.push(out);
532        }
533
534        if should_run(self.config.self_model_interval) {
535            self.executive
536                .set_module_state("self_model", ModuleState::Running);
537            let out = self.run_self_model(config, output_dir);
538            self.executive
539                .set_module_state("self_model", ModuleState::Idle);
540            outputs.push(out);
541        }
542
543        if should_run(self.config.dream_interval) {
544            self.executive
545                .set_module_state("dream", ModuleState::Running);
546            let out = self.run_dream(config, output_dir);
547            self.executive.set_module_state("dream", ModuleState::Idle);
548            outputs.push(out);
549        }
550
551        // Executive statok kiírása
552        let (mod_count, running, energy, attention) = self.executive.stats();
553        println!(
554            "  {} Modulok: {} | Fut: {} | Energia: {:.1}% | Figyelem: {:.1}%",
555            "📊".cyan(),
556            mod_count,
557            running,
558            energy * 100.0,
559            attention * 100.0
560        );
561
562        // Minden ciklus végén: append log rebuild (ha van mit)
563        let rebuild_out = self.run_rebuild(config, output_dir);
564        outputs.push(rebuild_out);
565
566        // Tároljuk a ciklus összefoglalót
567        let summary = format!(
568            "Autonomous cycle #{}: {} modules executed. Energy: {:.1}%, Attention: {:.1}%",
569            cycle,
570            outputs.len(),
571            energy * 100.0,
572            attention * 100.0
573        );
574        self.store_result(config, &summary, "session", 3);
575
576        if !outputs.is_empty() {
577            self.speak(&format!(
578                "Ciklus {} kész. {} aktivitás.",
579                cycle,
580                outputs.len()
581            ));
582        }
583
584        self.last_outputs
585            .push_back(format!("#{}: {} aktivitás", cycle, outputs.len()));
586        if self.last_outputs.len() > 20 {
587            self.last_outputs.pop_front();
588        }
589
590        outputs
591    }
592
593    /// Fő ciklus — folyamatosan fut
594    pub fn run(mut self, config: &Config) {
595        let interval = Duration::from_secs(self.config.cycle_interval_secs);
596        let max = self.config.max_cycles.unwrap_or(usize::MAX);
597
598        println!(
599            "{}",
600            "╔══════════════════════════════════════════════════════╗".cyan()
601        );
602        println!(
603            "{}",
604            "║     🧠 MICROSCOPE MEMORY — AUTONÓM MÓD            ║"
605                .cyan()
606                .bold()
607        );
608        println!(
609            "{}",
610            "╠══════════════════════════════════════════════════════╣".cyan()
611        );
612        println!("  Ciklus: {} másodperc", self.config.cycle_interval_secs);
613        println!(
614            "  TTS: {}",
615            if self.config.tts_enabled {
616                "✅ BE"
617            } else {
618                "❌ KI"
619            }
620        );
621        println!(
622            "  Daemon: {}",
623            if self.config.daemon_mode {
624                "✅"
625            } else {
626                "❌"
627            }
628        );
629        println!(
630            "  Max ciklus: {}",
631            if max == usize::MAX {
632                "végtelen".to_string()
633            } else {
634                max.to_string()
635            }
636        );
637        println!(
638            "{}",
639            "╚══════════════════════════════════════════════════════╝".cyan()
640        );
641        println!();
642
643        loop {
644            if self.cycle_count >= max {
645                println!(
646                    "  {} Elértük a maximális ciklusszámot ({})",
647                    "✓".green(),
648                    max
649                );
650                break;
651            }
652
653            self.run_cycle(config);
654
655            if self.config.daemon_mode {
656                println!(
657                    "  {} Várakozás {} másodperc...",
658                    "⏳".cyan(),
659                    interval.as_secs()
660                );
661                std::thread::sleep(interval);
662            } else {
663                break;
664            }
665        }
666
667        println!();
668        println!("{}", "═".repeat(60).cyan());
669        println!("  ✅ Autonóm mód befejezve — {} ciklus", self.cycle_count);
670        println!("  Utolsó kimenetek:");
671        for out in self.last_outputs.iter().rev().take(5) {
672            println!("    └─ {}", out);
673        }
674    }
675}
676
677// ─── Segédfüggvények ──────────────────────────────────────
678
679fn chrono_or_now() -> String {
680    let now = SystemTime::now()
681        .duration_since(UNIX_EPOCH)
682        .unwrap_or_default()
683        .as_secs();
684    let secs = now % 60;
685    let mins = (now / 60) % 60;
686    let hours = (now / 3600) % 24;
687    format!("{:02}:{:02}:{:02} UTC", hours, mins, secs)
688}
689
690/// Formázott kimenet az autonóm mód indításakor
691pub fn print_autonomous_header(config: &AutonomousConfig) {
692    println!(
693        "{}",
694        "╔══════════════════════════════════════════════════════╗".cyan()
695    );
696    println!(
697        "{}",
698        "║     🧠 MICROSCOPE MEMORY — AUTONÓM MÓD            ║"
699            .cyan()
700            .bold()
701    );
702    println!(
703        "{}",
704        "╠══════════════════════════════════════════════════════╣".cyan()
705    );
706    println!("  Ciklus idő:     {} másodperc", config.cycle_interval_secs);
707    println!(
708        "  Daydream:       minden {} ciklus",
709        config.daydream_interval
710    );
711    println!(
712        "  Curiosity:      minden {} ciklus",
713        config.curiosity_interval
714    );
715    println!(
716        "  Monológ:        minden {} ciklus",
717        config.monologue_interval
718    );
719    println!(
720        "  Önreflexió:     minden {} ciklus",
721        config.reflect_interval
722    );
723    println!(
724        "  Történet:       minden {} ciklus",
725        config.narrative_interval
726    );
727    println!(
728        "  Önkép:          minden {} ciklus",
729        config.self_model_interval
730    );
731    println!("  Álom:           minden {} ciklus", config.dream_interval);
732    println!(
733        "  TTS:            {}",
734        if config.tts_enabled {
735            "✅ BE"
736        } else {
737            "❌ KI"
738        }
739    );
740    println!(
741        "  Daemon mód:     {}",
742        if config.daemon_mode { "✅" } else { "❌" }
743    );
744    println!(
745        "{}",
746        "╚══════════════════════════════════════════════════════╝".cyan()
747    );
748}