1use std::collections::hash_map::DefaultHasher;
2use std::fs;
3use std::hash::{Hash, Hasher};
4use std::path::PathBuf;
5
6use crate::providers::Message;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct SessionCache {
11 pub conversation: Vec<Message>,
12 pub provider: Option<String>,
13 pub model: Option<String>,
14}
15
16pub fn load() -> Option<SessionCache> {
17 let path = session_path();
18 let raw = fs::read_to_string(path).ok()?;
19 serde_json::from_str(&raw).ok()
20}
21
22pub fn save(cache: &SessionCache) {
23 let path = session_path();
24 if let Some(dir) = path.parent() {
25 let _ = fs::create_dir_all(dir);
26 }
27 let filtered = SessionCache {
29 conversation: cache
30 .conversation
31 .iter()
32 .filter(|m| m.role != crate::providers::Role::System)
33 .cloned()
34 .collect(),
35 provider: cache.provider.clone(),
36 model: cache.model.clone(),
37 };
38 if let Ok(raw) = serde_json::to_string_pretty(&filtered) {
39 let _ = fs::write(path, raw);
40 }
41}
42
43fn session_path() -> PathBuf {
44 let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
45 let dir = PathBuf::from(home).join(".ripl").join("sessions");
46 let hash = project_hash();
47 dir.join(format!("{}.json", hash))
48}
49
50fn project_hash() -> u64 {
51 let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
52 let mut hasher = DefaultHasher::new();
53 cwd.to_string_lossy().hash(&mut hasher);
54 hasher.finish()
55}