1pub mod store;
2pub use store::SessionStore;
3
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Session {
9 pub id: String,
10 pub title: Option<String>,
11 pub created_at: DateTime<Utc>,
12 pub updated_at: DateTime<Utc>,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct StoredMessage {
17 pub id: String,
18 pub session_id: String,
19 pub role: String,
20 pub content: Option<String>,
21 pub tool_calls: Option<String>, pub tool_call_id: Option<String>,
23 pub created_at: DateTime<Utc>,
24}
25
26pub fn auto_title(message: &str) -> String {
28 let trimmed = message.trim();
29 if trimmed.chars().count() <= 50 {
30 return trimmed.to_string();
31 }
32 let byte_end = trimmed.char_indices().nth(50).map(|(i, _)| i).unwrap_or(trimmed.len());
34 let cut = &trimmed[..byte_end];
35 if let Some(pos) = cut.rfind(' ') {
36 trimmed[..pos].to_string()
37 } else {
38 cut.to_string()
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn test_auto_title_short() {
48 assert_eq!(auto_title("hello"), "hello");
49 }
50
51 #[test]
52 fn test_auto_title_truncates_at_word() {
53 let msg = "implement a function to read files from the filesystem efficiently";
54 let title = auto_title(msg);
55 assert!(title.len() <= 50);
56 assert!(!title.ends_with(' '));
57 }
58
59 #[test]
60 fn test_auto_title_no_spaces() {
61 let msg = "a".repeat(60);
62 let title = auto_title(&msg);
63 assert_eq!(title.len(), 50);
64 }
65
66 #[test]
67 fn test_auto_title_cjk() {
68 let msg = "我要在老家建房,需要一个设计软件,最好是多agent 可以出设计效果的那种";
70 let title = auto_title(msg); assert!(title.chars().count() <= 50);
72 assert!(title.is_char_boundary(title.len()));
74 }
75
76 #[test]
77 fn test_auto_title_cjk_short() {
78 let msg = "你好世界";
79 assert_eq!(auto_title(msg), "你好世界");
80 }
81}