use anyhow::Result;
use chrono::{DateTime, Utc};
use log::error;
use serde::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Write;
use uuid::Uuid;
use super::types::{AgentState, ChatMessage};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ChatSession {
pub id: Uuid,
pub name: String,
pub created_at: DateTime<Utc>,
pub messages: Vec<ChatMessage>,
pub agent_state: AgentState,
pub recording: bool,
pub recording_file: Option<String>,
}
impl ChatSession {
pub fn new(name: String) -> Self {
Self {
id: Uuid::new_v4(),
name,
created_at: Utc::now(),
messages: Vec::new(),
agent_state: AgentState::Idle,
recording: false,
recording_file: None,
}
}
pub fn add_message(&mut self, message: ChatMessage) {
self.messages.push(message);
if self.messages.len() > 1000 {
self.messages.drain(0..100); }
if self.recording {
if let Some(last_message) = self.messages.last() {
if let Err(e) = self.save_message_to_recording(last_message) {
error!("Failed to save message to recording: {}", e);
}
}
}
}
fn save_message_to_recording(&self, message: &ChatMessage) -> Result<()> {
if let Some(file_path) = &self.recording_file {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(file_path)?;
let timestamp = Utc::now().format("%Y-%m-%d %H:%M:%S UTC");
let message_json = serde_json::to_string(message)?;
writeln!(file, "[{}] {}", timestamp, message_json)?;
}
Ok(())
}
pub fn start_recording(&mut self, file_path: String) -> Result<()> {
use std::fs::File;
let mut file = File::create(&file_path)?;
writeln!(file, "# OSVM Agent Chat Session Recording")?;
writeln!(file, "# Session: {} ({})", self.name, self.id)?;
writeln!(
file,
"# Started: {}",
Utc::now().format("%Y-%m-%d %H:%M:%S UTC")
)?;
writeln!(file, "# Format: [timestamp] {{message_json}}")?;
writeln!(file, "")?;
self.recording = true;
self.recording_file = Some(file_path.clone());
self.add_message(ChatMessage::System(format!(
"Recording started: {}",
file_path
)));
Ok(())
}
pub fn stop_recording(&mut self) {
if self.recording {
self.add_message(ChatMessage::System("Recording stopped".to_string()));
self.recording = false;
self.recording_file = None;
}
}
}