ricecoder_tui/
session_integration.rs1use crate::sessions::{Session as TuiSession, SessionStatus as TuiSessionStatus, SessionWidget};
8use ricecoder_sessions::{Session, SessionManager, SessionStatus as CoreSessionStatus};
9
10pub struct SessionIntegration {
12 pub manager: SessionManager,
14 pub widget: SessionWidget,
16}
17
18impl SessionIntegration {
19 pub fn new(session_limit: usize) -> Self {
21 Self {
22 manager: SessionManager::new(session_limit),
23 widget: SessionWidget::new(),
24 }
25 }
26
27 pub fn sync_to_widget(&mut self) {
30 let sessions = self.manager.list_sessions();
32
33 self.widget.clear();
35
36 for session in sessions {
37 let tui_session = self.convert_to_tui_session(&session);
38 self.widget.add_session(tui_session);
39 }
40
41 if let Some(active_id) = self.manager.active_session_id() {
43 if let Some(index) = self.widget.find_session_index(active_id) {
44 self.widget.switch_to_session(index);
45 }
46 }
47 }
48
49 fn convert_to_tui_session(&self, session: &Session) -> TuiSession {
51 let tui_status = match session.status {
52 CoreSessionStatus::Active => TuiSessionStatus::Active,
53 CoreSessionStatus::Paused => TuiSessionStatus::Idle,
54 CoreSessionStatus::Archived => TuiSessionStatus::Idle,
55 };
56
57 let mut tui_session = TuiSession::new(session.id.clone(), session.name.clone());
58 tui_session.set_status(tui_status);
59 tui_session.message_count = session.history.len();
60 tui_session.last_activity = session.updated_at.timestamp().max(0) as u64;
61
62 tui_session
63 }
64
65 pub fn handle_session_switch(&mut self, session_id: &str) -> Result<(), String> {
68 self.manager
70 .switch_session(session_id)
71 .map_err(|e| e.to_string())?;
72
73 self.sync_to_widget();
75
76 Ok(())
77 }
78
79 pub fn create_session(
81 &mut self,
82 name: String,
83 context: ricecoder_sessions::SessionContext,
84 ) -> Result<String, String> {
85 let session = self
87 .manager
88 .create_session(name.clone(), context.clone())
89 .map_err(|e| e.to_string())?;
90
91 let session_id = session.id.clone();
92
93 self.sync_to_widget();
95
96 Ok(session_id)
97 }
98
99 pub fn delete_session(&mut self, session_id: &str) -> Result<(), String> {
101 self.manager
103 .delete_session(session_id)
104 .map_err(|e| e.to_string())?;
105
106 self.sync_to_widget();
108
109 Ok(())
110 }
111
112 pub fn active_session_id(&self) -> Option<&str> {
114 self.manager.active_session_id()
115 }
116
117 pub fn session_count(&self) -> usize {
119 self.manager.session_count()
120 }
121
122 pub fn is_limit_reached(&self) -> bool {
124 self.manager.is_limit_reached()
125 }
126
127 pub fn list_sessions(&self) -> Vec<Session> {
129 self.manager.list_sessions()
130 }
131
132 pub fn get_session(&self, session_id: &str) -> Result<Session, String> {
134 self.manager
135 .get_session(session_id)
136 .map_err(|e| e.to_string())
137 }
138
139 pub fn get_active_session(&self) -> Result<Session, String> {
141 self.manager.get_active_session().map_err(|e| e.to_string())
142 }
143
144 pub fn add_message_to_active(&mut self, message_content: &str) -> Result<String, String> {
146 let mut session = self
148 .manager
149 .get_active_session()
150 .map_err(|e| e.to_string())?;
151
152 let session_id = session.id.clone();
153
154 let message = ricecoder_sessions::Message::new(
156 ricecoder_sessions::MessageRole::User,
157 message_content.to_string(),
158 );
159 session.history.push(message);
160 session.updated_at = chrono::Utc::now();
161
162 self.manager
164 .update_session(session)
165 .map_err(|e| e.to_string())?;
166
167 Ok(session_id)
168 }
169
170 pub fn add_message_to_session(
172 &mut self,
173 session_id: &str,
174 message_content: &str,
175 ) -> Result<String, String> {
176 let mut session = self
178 .manager
179 .get_session(session_id)
180 .map_err(|e| e.to_string())?;
181
182 let message = ricecoder_sessions::Message::new(
184 ricecoder_sessions::MessageRole::User,
185 message_content.to_string(),
186 );
187 session.history.push(message);
188 session.updated_at = chrono::Utc::now();
189
190 self.manager
192 .update_session(session)
193 .map_err(|e| e.to_string())?;
194
195 Ok(session_id.to_string())
196 }
197
198 pub fn widget(&self) -> &SessionWidget {
200 &self.widget
201 }
202
203 pub fn widget_mut(&mut self) -> &mut SessionWidget {
205 &mut self.widget
206 }
207}
208
209impl Default for SessionIntegration {
210 fn default() -> Self {
211 Self::new(10) }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218 use ricecoder_sessions::SessionMode;
219
220 fn create_test_context() -> ricecoder_sessions::SessionContext {
221 ricecoder_sessions::SessionContext::new(
222 "openai".to_string(),
223 "gpt-4".to_string(),
224 SessionMode::Chat,
225 )
226 }
227
228 #[test]
229 fn test_create_session_integration() {
230 let mut integration = SessionIntegration::new(5);
231 let context = create_test_context();
232
233 let session_id = integration
234 .create_session("Test Session".to_string(), context)
235 .unwrap();
236
237 assert_eq!(integration.session_count(), 1);
238 assert_eq!(integration.active_session_id(), Some(session_id.as_str()));
239 assert_eq!(integration.widget.session_count(), 1);
240 }
241
242 #[test]
243 fn test_sync_to_widget() {
244 let mut integration = SessionIntegration::new(5);
245 let context = create_test_context();
246
247 integration
248 .create_session("Session 1".to_string(), context.clone())
249 .unwrap();
250 integration
251 .create_session("Session 2".to_string(), context)
252 .unwrap();
253
254 assert_eq!(integration.widget.session_count(), 2);
255
256 let widget_sessions = integration.widget.session_names();
257 assert!(widget_sessions.contains(&"Session 1"));
258 assert!(widget_sessions.contains(&"Session 2"));
259 }
260
261 #[test]
262 fn test_session_switch_integration() {
263 let mut integration = SessionIntegration::new(5);
264 let context = create_test_context();
265
266 let session1_id = integration
267 .create_session("Session 1".to_string(), context.clone())
268 .unwrap();
269 let session2_id = integration
270 .create_session("Session 2".to_string(), context)
271 .unwrap();
272
273 integration.handle_session_switch(&session1_id).unwrap();
275
276 assert_eq!(integration.active_session_id(), Some(session1_id.as_str()));
277 assert_eq!(
278 integration.widget.current_session().unwrap().id,
279 session1_id
280 );
281
282 integration.handle_session_switch(&session2_id).unwrap();
284
285 assert_eq!(integration.active_session_id(), Some(session2_id.as_str()));
286 assert_eq!(
287 integration.widget.current_session().unwrap().id,
288 session2_id
289 );
290 }
291
292 #[test]
293 fn test_delete_session_integration() {
294 let mut integration = SessionIntegration::new(5);
295 let context = create_test_context();
296
297 let session_id = integration
298 .create_session("Test Session".to_string(), context)
299 .unwrap();
300
301 assert_eq!(integration.session_count(), 1);
302
303 integration.delete_session(&session_id).unwrap();
304
305 assert_eq!(integration.session_count(), 0);
306 assert_eq!(integration.widget.session_count(), 0);
307 }
308
309 #[test]
310 fn test_session_status_display() {
311 let mut integration = SessionIntegration::new(5);
312 let context = create_test_context();
313
314 integration
315 .create_session("Test Session".to_string(), context)
316 .unwrap();
317
318 let tui_session = integration.widget.current_session().unwrap();
319 assert_eq!(tui_session.status, TuiSessionStatus::Active);
320 }
321
322 #[test]
323 fn test_message_routing() {
324 let mut integration = SessionIntegration::new(5);
325 let context = create_test_context();
326
327 let session_id = integration
328 .create_session("Test Session".to_string(), context)
329 .unwrap();
330
331 let routed_id = integration.add_message_to_active("Hello").unwrap();
332
333 assert_eq!(routed_id, session_id);
334
335 let session = integration.get_session(&session_id).unwrap();
336 assert_eq!(session.history.len(), 1);
337 assert_eq!(session.history[0].content, "Hello");
338 }
339
340 #[test]
341 fn test_session_limit_enforcement() {
342 let mut integration = SessionIntegration::new(2);
343 let context = create_test_context();
344
345 integration
346 .create_session("Session 1".to_string(), context.clone())
347 .unwrap();
348 integration
349 .create_session("Session 2".to_string(), context.clone())
350 .unwrap();
351
352 assert!(integration.is_limit_reached());
353
354 let result = integration.create_session("Session 3".to_string(), context);
355 assert!(result.is_err());
356 }
357}