1use 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#[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}