use std::{fs, path::PathBuf};
use crate::api::types::Message;
fn repair_history(mut messages: Vec<Message>) -> Vec<Message> {
while messages.last().is_some_and(|m| m.role == "tool") {
messages.pop();
}
if messages
.last()
.is_some_and(|m| m.role == "assistant" && m.tool_calls.is_some())
{
messages.pop();
}
let mut i = 0;
while i < messages.len() {
if messages[i].role == "tool" {
let tool_id = messages[i].tool_call_id.as_deref().unwrap_or("");
let mut found = false;
for j in (0..i).rev() {
if messages[j].role == "assistant" {
if let Some(ref tcs) = messages[j].tool_calls {
if tcs.iter().any(|tc| tc.id == tool_id) {
found = true;
}
}
break; }
}
if !found {
messages.remove(i);
continue;
}
} else if messages[i].role == "assistant" && messages[i].tool_calls.is_some() {
let mut has_tool_response = false;
for msg in messages.iter().skip(i + 1) {
match msg.role.as_str() {
"tool" => {
has_tool_response = true;
}
"user" | "assistant" => {
break;
}
_ => {}
}
}
if !has_tool_response {
messages.remove(i);
continue;
}
}
i += 1;
}
messages
}
pub fn load_history(session_id: &str) -> Vec<Message> {
let path = get_history_path(session_id);
if let Some(msgs) = fs::read_to_string(path)
.ok()
.and_then(|c| serde_json::from_str::<Vec<Message>>(&c).ok())
{
let original_len = msgs.len();
let repaired = repair_history(msgs);
if repaired.len() != original_len {
save_history(session_id, &repaired);
}
return repaired;
}
Vec::new()
}
pub fn save_history(session_id: &str, messages: &[Message]) {
let path = get_history_path(session_id);
let _ = fs::create_dir_all(path.parent().unwrap());
if let Ok(json) = serde_json::to_string_pretty(messages) {
let _ = fs::write(path, json);
}
}
pub fn get_history_path(session_id: &str) -> PathBuf {
let safe_id: String = session_id
.chars()
.filter(|c| c.is_alphanumeric() || *c == '-' || *c == '_')
.collect();
let mut path = PathBuf::from(".deep/history");
path.push(format!("{}.json", safe_id));
path
}