Skip to main content

tycode_core/persistence/
session.rs

1use std::collections::HashMap;
2use std::path::PathBuf;
3
4use chrono::Utc;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8use crate::ai::types::{Message, MessageRole};
9use crate::chat::events::ChatEvent;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct SessionData {
13    pub id: String,
14    pub created_at: u64,
15    pub last_modified: u64,
16    pub messages: Vec<Message>,
17    pub tracked_files: Vec<PathBuf>,
18    pub events: Vec<ChatEvent>,
19
20    /// Module state is flattened into the JSON root.
21    /// This provides backwards compatibility: old sessions with top-level
22    /// `task_list` are collected here, and new sessions serialize identically.
23    #[serde(flatten)]
24    pub module_state: HashMap<String, Value>,
25}
26
27impl SessionData {
28    pub fn new(id: String, messages: Vec<Message>, tracked_files: Vec<PathBuf>) -> Self {
29        let now = Utc::now().timestamp_millis() as u64;
30        Self {
31            id,
32            created_at: now,
33            last_modified: now,
34            messages,
35            tracked_files,
36            events: Vec::new(),
37            module_state: HashMap::new(),
38        }
39    }
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct SessionMetadata {
44    pub id: String,
45    pub title: String,
46    pub last_modified: u64,
47}
48
49impl SessionMetadata {
50    pub fn from_session_data(data: &SessionData) -> Self {
51        let title = data
52            .messages
53            .iter()
54            .find(|msg| msg.role == MessageRole::User)
55            .map(|msg| Self::truncate_text(&msg.content.text()))
56            .unwrap_or_else(|| "New Session".to_string());
57
58        Self {
59            id: data.id.clone(),
60            title,
61            last_modified: data.last_modified,
62        }
63    }
64
65    fn truncate_text(text: &str) -> String {
66        let truncated: String = text.chars().take(50).collect();
67        if text.chars().count() > 50 {
68            format!("{}...", truncated)
69        } else {
70            truncated
71        }
72    }
73}