acp_cli/session/
history.rs1use serde::{Deserialize, Serialize};
2use std::fs::{self, OpenOptions};
3use std::io::{self, BufRead, Write};
4
5use super::scoping::session_dir;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct ConversationEntry {
9 pub role: String,
10 pub content: String,
11 pub timestamp: u64,
12}
13
14fn log_path(session_key: &str) -> std::path::PathBuf {
16 session_dir().join(format!("{session_key}.log.jsonl"))
17}
18
19pub fn append_entry(session_key: &str, entry: &ConversationEntry) -> io::Result<()> {
21 let path = log_path(session_key);
22 if let Some(parent) = path.parent() {
23 fs::create_dir_all(parent)?;
24 }
25 let mut file = OpenOptions::new().create(true).append(true).open(&path)?;
26 let json =
27 serde_json::to_string(entry).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
28 writeln!(file, "{json}")?;
29 Ok(())
30}
31
32pub fn load_history(session_key: &str) -> io::Result<Vec<ConversationEntry>> {
34 let path = log_path(session_key);
35 let file = match fs::File::open(&path) {
36 Ok(f) => f,
37 Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(Vec::new()),
38 Err(e) => return Err(e),
39 };
40 let reader = io::BufReader::new(file);
41 let mut entries = Vec::new();
42 for line in reader.lines() {
43 let line = line?;
44 if line.trim().is_empty() {
45 continue;
46 }
47 let entry: ConversationEntry = serde_json::from_str(&line)
48 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
49 entries.push(entry);
50 }
51 Ok(entries)
52}