Skip to main content

haki_core/
session.rs

1//! Session — a single conversation context.
2
3use uuid::Uuid;
4use chrono::Utc;
5use haki_llm::Message;
6use haki_config::Config;
7
8#[derive(Debug, Clone)]
9pub struct Session {
10    pub id: String,
11    pub created_at: String,
12    pub model: String,
13    pub history: Vec<Message>,
14    pub config: Config,
15}
16
17impl Session {
18    pub fn new(config: Config) -> Self {
19        Self {
20            id: Uuid::new_v4().to_string(),
21            created_at: Utc::now().to_rfc3339(),
22            model: config.model.clone(),
23            history: Vec::new(),
24            config,
25        }
26    }
27
28    pub fn push(&mut self, msg: Message) {
29        self.history.push(msg);
30    }
31
32    pub fn history(&self) -> &[Message] {
33        &self.history
34    }
35
36    pub fn last_assistant_message(&self) -> Option<&str> {
37        self.history
38            .iter()
39            .rev()
40            .find(|m| m.role == haki_llm::Role::Assistant)
41            .map(|m| m.content.as_str())
42    }
43}
44
45// ─── Tests ────────────────────────────────────────────────────────────────────
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use haki_llm::Message;
51
52    fn test_config() -> Config {
53        Config::default()
54    }
55
56    #[test]
57    fn session_has_unique_id() {
58        let s1 = Session::new(test_config());
59        let s2 = Session::new(test_config());
60        assert_ne!(s1.id, s2.id);
61    }
62
63    #[test]
64    fn push_and_history() {
65        let mut s = Session::new(test_config());
66        s.push(Message::user("hello"));
67        s.push(Message::assistant("hi"));
68        assert_eq!(s.history().len(), 2);
69    }
70
71    #[test]
72    fn last_assistant_message() {
73        let mut s = Session::new(test_config());
74        s.push(Message::user("ping"));
75        s.push(Message::assistant("pong"));
76        assert_eq!(s.last_assistant_message(), Some("pong"));
77    }
78
79    #[test]
80    fn last_assistant_message_none_when_empty() {
81        let s = Session::new(test_config());
82        assert!(s.last_assistant_message().is_none());
83    }
84}