Skip to main content

hematite/agent/
transcript.rs

1use std::fs::{create_dir_all, OpenOptions};
2use std::io::Write;
3use std::path::PathBuf;
4
5/// Persistent transcript logger for the DeepReflect engine.
6/// Writes append-only session logs to `.hematite_logs/` so the
7/// memory consolidation pass has real signal to synthesize from.
8#[allow(dead_code)]
9pub struct TranscriptLogger {
10    log_dir: PathBuf,
11    session_file: PathBuf,
12}
13
14#[allow(dead_code)]
15impl TranscriptLogger {
16    pub fn new() -> Self {
17        let log_dir = crate::tools::file_ops::hematite_dir().join("logs");
18        let _ = create_dir_all(&log_dir);
19
20        // One file per calendar day — DeepReflect reads these during Phase 2 (Gather)
21        let today = chrono_lite_date();
22        let session_file = log_dir.join(format!("{}.log", today));
23
24        Self {
25            log_dir,
26            session_file,
27        }
28    }
29
30    /// Appends a timestamped user turn to the daily log.
31    pub fn log_user(&self, input: &str) {
32        self.append(&format!("[USER] {}", input));
33    }
34
35    /// Appends a timestamped AI response to the daily log.
36    pub fn log_agent(&self, output: &str) {
37        // Truncate long responses to keep logs scannable for DeepReflect
38        let truncated = if output.len() > 500 {
39            format!("{}... [TRUNCATED {} bytes]", &output[..500], output.len())
40        } else {
41            output.to_string()
42        };
43        self.append(&format!("[AGENT] {}", truncated));
44    }
45
46    /// Appends a system event (Vigil tick, Swarm dispatch, etc.)
47    pub fn log_system(&self, event: &str) {
48        self.append(&format!("[SYSTEM] {}", event));
49    }
50
51    fn append(&self, line: &str) {
52        if let Ok(mut file) = OpenOptions::new()
53            .create(true)
54            .append(true)
55            .open(&self.session_file)
56        {
57            let _ = writeln!(file, "{}", line);
58        }
59    }
60}
61
62/// Lightweight date string without pulling in the full chrono crate.
63/// Returns YYYY-MM-DD using the system clock.
64#[allow(dead_code)]
65fn chrono_lite_date() -> String {
66    let now = std::time::SystemTime::now()
67        .duration_since(std::time::UNIX_EPOCH)
68        .unwrap_or_default()
69        .as_secs();
70
71    // Simple epoch-to-date conversion
72    let days = now / 86400;
73    let years = (days * 4 + 2) / 1461; // Approximate Gregorian
74    let year = 1970 + years;
75    let day_of_year = days - (years * 365 + years / 4);
76    let month = day_of_year / 30 + 1;
77    let day = day_of_year % 30 + 1;
78
79    format!("{:04}-{:02}-{:02}", year, month.min(12), day.min(31))
80}