use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionState {
pub last_provider: String,
pub last_model: String,
pub last_session_turns: u64,
pub last_session_tokens: u64,
pub last_session_duration_secs: u64,
}
impl Default for SessionState {
fn default() -> Self {
Self {
last_provider: String::new(),
last_model: String::new(),
last_session_turns: 0,
last_session_tokens: 0,
last_session_duration_secs: 0,
}
}
}
fn session_path() -> String {
let home = std::env::var("HOME").unwrap_or_else(|_| ".".into());
format!("{}/.cortex/session.json", home)
}
pub fn save_session_state(state: &SessionState) {
let path = session_path();
if let Some(parent) = Path::new(&path).parent() {
let _ = std::fs::create_dir_all(parent);
}
if let Ok(json) = serde_json::to_string_pretty(state) {
let _ = std::fs::write(&path, &json);
}
}
pub fn load_session_state() -> SessionState {
let path = session_path();
std::fs::read_to_string(&path)
.ok()
.and_then(|s| serde_json::from_str(&s).ok())
.unwrap_or_default()
}
pub async fn health_check(base_url: &str, api_key: &str) -> (bool, String) {
let url = format!("{}/models", base_url.trim_end_matches('/'));
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(5))
.build()
.unwrap_or_default();
if api_key.is_empty() || api_key.contains("${") {
return (false, "API key not configured".into());
}
match client
.get(&url)
.header("Authorization", format!("Bearer {}", api_key))
.header("Content-Type", "application/json")
.send()
.await
{
Ok(resp) if resp.status().is_success() => {
match resp.json::<serde_json::Value>().await {
Ok(data) => {
let count = data["data"].as_array().map(|a| a.len()).unwrap_or(0);
(true, format!("{} models available", count))
}
Err(_) => (false, "Failed to parse model list".into()),
}
}
Ok(resp) => (false, format!("HTTP {}", resp.status())),
Err(e) => (false, format!("Connection failed: {}", e)),
}
}