#![doc = include_str!("../README.md")]
pub mod derive;
pub mod error;
pub mod io;
pub mod paths;
pub mod provider;
pub mod reader;
pub mod types;
pub use derive::{derive_graph, derive_path, derive_project};
pub use error::{PiError, Result};
pub use paths::PathResolver;
pub use provider::session_to_view;
pub use reader::{PiSession, SessionMeta};
pub use toolpath_convo::DeriveConfig;
pub use types::{
AgentMessage, ContentBlock, CostBreakdown, Entry, EntryBase, SessionHeader, Usage,
};
use toolpath_convo::ConversationView;
#[derive(Debug, Clone, Default)]
pub struct PiConvo {
resolver: PathResolver,
}
impl PiConvo {
pub fn new() -> Self {
Self {
resolver: PathResolver::new(),
}
}
pub fn with_resolver(resolver: PathResolver) -> Self {
Self { resolver }
}
pub fn resolver(&self) -> &PathResolver {
&self.resolver
}
pub fn exists(&self) -> bool {
self.resolver.sessions_dir().exists()
}
pub fn list_projects(&self) -> Result<Vec<String>> {
io::list_projects(&self.resolver)
}
pub fn list_sessions(&self, project: &str) -> Result<Vec<SessionMeta>> {
io::list_sessions(&self.resolver, project)
}
pub fn read_session(&self, project: &str, session_id: &str) -> Result<PiSession> {
reader::read_session(&self.resolver, project, session_id)
}
pub fn most_recent_session(&self, project: &str) -> Result<Option<PiSession>> {
let mut metas = self.list_sessions(project)?;
if let Some(meta) = metas.drain(..).next() {
let session = self.read_session(project, &meta.id)?;
Ok(Some(session))
} else {
Ok(None)
}
}
pub fn to_view(&self, session: &PiSession) -> ConversationView {
provider::session_to_view(session)
}
pub fn read_all_sessions(&self, project: &str) -> Result<Vec<PiSession>> {
let metas = self.list_sessions(project)?;
let mut sessions = Vec::new();
for meta in metas {
match self.read_session(project, &meta.id) {
Ok(s) => sessions.push(s),
Err(e) => {
eprintln!("Warning: failed to read Pi session {}: {}", meta.id, e);
}
}
}
Ok(sessions)
}
}