Skip to main content

lean_agent_core/
writer.rs

1//! Trace artifact writers.
2
3use crate::{Result, TraceRecord};
4use camino::Utf8Path;
5use serde::Serialize;
6use std::fs::File;
7use std::io::{BufWriter, Write};
8
9/// Streaming JSONL trace writer.
10pub struct TraceWriter {
11    inner: BufWriter<File>,
12}
13
14impl TraceWriter {
15    /// Create a new writer at `path`.
16    pub fn create(path: &Utf8Path) -> Result<Self> {
17        let file = File::create(path)?;
18        Ok(Self {
19            inner: BufWriter::new(file),
20        })
21    }
22
23    /// Write one trace record as one JSON line.
24    pub fn write_record(&mut self, record: &TraceRecord) -> Result<()> {
25        serde_json::to_writer(&mut self.inner, record)?;
26        self.inner.write_all(b"\n")?;
27        Ok(())
28    }
29
30    /// Flush buffered output.
31    pub fn flush(&mut self) -> Result<()> {
32        self.inner.flush()?;
33        Ok(())
34    }
35}
36
37/// Convenience writer for small record batches.
38pub fn write_jsonl(path: &Utf8Path, records: &[TraceRecord]) -> Result<()> {
39    let mut writer = TraceWriter::create(path)?;
40    for record in records {
41        writer.write_record(record)?;
42    }
43    writer.flush()
44}
45
46/// Streaming JSONL writer for any serializable record type.
47///
48/// Trace records carry a `record_type` tag; mined task records do not, so this
49/// writer stays generic over the record type instead of taking [`TraceRecord`].
50pub struct JsonlWriter {
51    inner: BufWriter<File>,
52}
53
54impl JsonlWriter {
55    /// Create a new writer at `path`, truncating any existing file.
56    pub fn create(path: &Utf8Path) -> Result<Self> {
57        let file = File::create(path)?;
58        Ok(Self {
59            inner: BufWriter::new(file),
60        })
61    }
62
63    /// Write one record as a single JSON line.
64    pub fn write_record<T: Serialize>(&mut self, record: &T) -> Result<()> {
65        serde_json::to_writer(&mut self.inner, record)?;
66        self.inner.write_all(b"\n")?;
67        Ok(())
68    }
69
70    /// Flush buffered output to disk.
71    pub fn flush(&mut self) -> Result<()> {
72        self.inner.flush()?;
73        Ok(())
74    }
75}