1use std::io;
5
6use rig_core::conversation::Conversation;
7
8use crate::format::SESSION;
9use crate::session::{Fold, Folded, fold, log_lines, read_header};
10use crate::{SessionError, Store, main_order};
11
12pub fn read_conversation(
21 store: &dyn Store,
22 agent: Option<&str>,
23) -> Result<(String, Conversation), SessionError> {
24 let how = Fold::WHOLE;
25 let folded = match agent {
26 Some(agent) => fold(store, agent, how)?,
27 None => main_log(store, how)?,
28 };
29 let Some(folded) = folded.filter(|folded| folded.name != SESSION) else {
30 let why = format!("the session has no agent {}", agent.unwrap_or("to talk to"));
31 return Err(io::Error::new(io::ErrorKind::NotFound, why).into());
32 };
33 Ok((folded.name, folded.conversation))
34}
35
36fn main_log(store: &dyn Store, how: Fold) -> Result<Option<Folded>, SessionError> {
41 let mut candidates = Vec::new();
42 for name in store.logs()? {
43 if name == SESSION {
44 continue;
45 }
46 let Some(lines) = log_lines(store, &name)? else {
47 continue;
48 };
49 if let Some((_, _, first)) = lines.iter().next() {
50 let (_, header) = read_header(&name, first)?;
51 if header.parent.is_none() {
52 candidates.push(name);
53 }
54 }
55 }
56 candidates.sort_by(|a, b| main_order(false, a).cmp(&main_order(false, b)));
57 for name in candidates {
58 if let Some(folded) = fold(store, &name, how)?.filter(|folded| !folded.retired) {
59 return Ok(Some(folded));
60 }
61 }
62 Ok(None)
63}
64
65#[cfg(test)]
66mod tests;