atman_runtime/event_log/
reader.rs1use std::path::Path;
2
3use crate::session::{ContextSnapshot, SessionOpenError};
4use serde_json;
5
6pub fn read_event_envelopes(
7 path: &Path,
8) -> Result<Vec<crate::event::EventEnvelope>, SessionOpenError> {
9 let text = match std::fs::read_to_string(path) {
10 Ok(t) => t,
11 Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()),
12 Err(e) => {
13 return Err(SessionOpenError::Replay {
14 path: path.to_path_buf(),
15 source: e,
16 });
17 }
18 };
19 let mut out = Vec::new();
20 for line in text.lines() {
21 if line.trim().is_empty() {
22 continue;
23 }
24 if let Ok(env) = serde_json::from_str::<crate::event::EventEnvelope>(line) {
25 out.push(env);
26 }
27 }
28 Ok(out)
29}
30
31pub fn parse_json_lines(text: &str) -> Vec<serde_json::Value> {
32 text.lines()
33 .filter_map(|line| {
34 let t = line.trim();
35 if t.is_empty() {
36 None
37 } else {
38 serde_json::from_str::<serde_json::Value>(t).ok()
39 }
40 })
41 .collect()
42}
43
44pub fn find_last_seq(path: &Path) -> Result<Option<u64>, SessionOpenError> {
45 let envelopes = read_event_envelopes(path)?;
46 Ok(envelopes.last().map(|env| env.seq))
47}
48
49pub fn replay_context_snapshot_from(path: &Path) -> ContextSnapshot {
50 let mut snap = ContextSnapshot::default();
51 let text = match std::fs::read_to_string(path) {
52 Ok(t) => t,
53 Err(_) => return snap,
54 };
55 for value in parse_json_lines(&text) {
56 if value["type"].as_str() != Some("llm_call") {
57 continue;
58 }
59 if value["run_id"].is_null() {
61 continue;
62 }
63 if let Some(model) = value["model"].as_str() {
64 snap.model = model.to_string();
65 }
66 let usage = &value["usage"];
67 let input = usage["input"].as_u64().unwrap_or(0);
68 let cached = usage["cached_input"].as_u64().unwrap_or(0);
69 let output = usage["output"].as_u64().unwrap_or(0);
70 snap.tokens_in = snap.tokens_in.saturating_add(input).saturating_add(cached);
71 snap.tokens_out = snap.tokens_out.saturating_add(output);
72 }
73 snap
74}