Skip to main content

hematite/agent/
transcript.rs

1use chrono::Local;
2use std::fs::{create_dir_all, OpenOptions};
3use std::io::Write;
4use std::path::PathBuf;
5
6use crate::agent::truncation::safe_head;
7
8/// Persistent transcript logger for the DeepReflect engine.
9/// Writes append-only session logs to `.hematite_logs/` so the
10/// memory consolidation pass has real signal to synthesize from.
11#[allow(dead_code)]
12pub struct TranscriptLogger {
13    log_dir: PathBuf,
14    session_file: PathBuf,
15}
16
17#[allow(dead_code)]
18impl Default for TranscriptLogger {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl TranscriptLogger {
25    pub fn new() -> Self {
26        let log_dir = crate::tools::file_ops::hematite_dir().join("logs");
27        let _ = create_dir_all(&log_dir);
28
29        // One file per calendar day — DeepReflect reads these during Phase 2 (Gather)
30        let today = Local::now().format("%Y-%m-%d").to_string();
31        let session_file = log_dir.join(format!("{}.log", today));
32
33        Self {
34            log_dir,
35            session_file,
36        }
37    }
38
39    /// Appends a timestamped user turn to the daily log.
40    pub fn log_user(&self, input: &str) {
41        self.append_two("[USER] ", input);
42    }
43
44    /// Appends a timestamped AI response to the daily log.
45    pub fn log_agent(&self, output: &str) {
46        if let Ok(mut file) = OpenOptions::new()
47            .create(true)
48            .append(true)
49            .open(&self.session_file)
50        {
51            if output.len() > 500 {
52                let _ = writeln!(
53                    file,
54                    "[AGENT] {}... [TRUNCATED {} bytes]",
55                    safe_head(output, 500),
56                    output.len()
57                );
58            } else {
59                let _ = writeln!(file, "[AGENT] {}", output);
60            }
61        }
62    }
63
64    /// Appends a system event (Vigil tick, Swarm dispatch, etc.)
65    pub fn log_system(&self, event: &str) {
66        self.append_two("[SYSTEM] ", event);
67    }
68
69    fn append_two(&self, prefix: &str, body: &str) {
70        if let Ok(mut file) = OpenOptions::new()
71            .create(true)
72            .append(true)
73            .open(&self.session_file)
74        {
75            let _ = writeln!(file, "{}{}", prefix, body);
76        }
77    }
78}