agent_sessions/reader/
mod.rs1pub(crate) mod input;
2mod options;
3mod stream;
4use crate::parser::State;
5use crate::{Agent, Event, FileKind, Located, ReadError, SessionFile};
6pub use options::*;
7use std::{
8 collections::VecDeque,
9 fs::File,
10 io::{BufRead, BufReader},
11};
12
13pub struct SessionReader<R = BufReader<File>> {
15 source: R,
16 agent: Agent,
17 opts: ReadOptions,
18 state: State,
19 summary: ReadSummary,
20 pending: VecDeque<Located<Event>>,
21 ended: bool,
22 checkpoint: Option<u64>,
23 file_sidechain: bool,
24 scratch: Vec<u8>,
25}
26
27pub fn read(file: &SessionFile, opts: &ReadOptions) -> Result<SessionReader, ReadError> {
28 opts.validate()?;
29 let source = File::open(&file.path).map_err(ReadError::Io)?;
30 let metadata = source.metadata().map_err(ReadError::Io)?;
31 if let Some(limit) = opts.max_file_bytes
32 && opts.stop_at_byte.unwrap_or(metadata.len()) > limit
33 {
34 return Err(ReadError::TooLarge { limit });
35 }
36 let mut reader = read_from(file.agent, BufReader::new(source), opts)?;
37 reader.file_sidechain = file.kind == FileKind::Subagent;
38 Ok(reader)
39}
40
41pub fn read_from<R: BufRead>(
44 agent: Agent,
45 source: R,
46 opts: &ReadOptions,
47) -> Result<SessionReader<R>, ReadError> {
48 opts.validate()?;
49 if !agent.streaming() {
50 return Err(ReadError::InvalidOptions(
51 "use import_session for this source format",
52 ));
53 }
54 Ok(SessionReader {
55 source,
56 agent,
57 opts: opts.clone(),
58 state: State {
59 codex_content: opts.codex_content,
60 ..Default::default()
61 },
62 summary: ReadSummary::default(),
63 pending: VecDeque::new(),
64 ended: false,
65 checkpoint: None,
66 file_sidechain: false,
67 scratch: Vec::new(),
68 })
69}
70
71impl<R: BufRead> SessionReader<R> {
72 pub fn finish(self) -> ReadSummary {
75 self.summary
76 }
77 pub fn summary(&self) -> &ReadSummary {
78 &self.summary
79 }
80 fn deliver(&mut self) -> Option<Located<Event>> {
81 let event = self.pending.pop_front();
82 if self.pending.is_empty()
83 && let Some(end) = self.checkpoint.take()
84 {
85 self.summary.last_complete_byte = end;
86 }
87 event
88 }
89}