ricecoder_cli/
chat.rs

1// Interactive chat mode
2
3use crate::error::CliResult;
4use rustyline::DefaultEditor;
5
6/// Chat session manager
7pub struct ChatSession {
8    pub provider: String,
9    pub model: String,
10    pub history: Vec<ChatMessage>,
11}
12
13/// A single chat message
14#[derive(Debug, Clone)]
15pub struct ChatMessage {
16    pub role: String,
17    pub content: String,
18}
19
20impl ChatSession {
21    /// Create a new chat session
22    pub fn new(provider: String, model: String) -> Self {
23        Self {
24            provider,
25            model,
26            history: Vec::new(),
27        }
28    }
29
30    /// Start interactive chat mode
31    pub fn start(&mut self) -> CliResult<()> {
32        let mut rl =
33            DefaultEditor::new().map_err(|e| crate::error::CliError::Internal(e.to_string()))?;
34
35        println!("Entering chat mode. Type 'exit' to quit.");
36        println!("Provider: {}, Model: {}", self.provider, self.model);
37
38        loop {
39            let readline = rl.readline("r[ > ");
40            match readline {
41                Ok(line) => {
42                    if line.trim() == "exit" {
43                        println!("Goodbye!");
44                        break;
45                    }
46
47                    if !line.trim().is_empty() {
48                        // Add to history
49                        self.history.push(ChatMessage {
50                            role: "user".to_string(),
51                            content: line.clone(),
52                        });
53
54                        // Process message
55                        println!("Processing: {}", line);
56                    }
57                }
58                Err(_) => {
59                    println!("Goodbye!");
60                    break;
61                }
62            }
63        }
64
65        Ok(())
66    }
67
68    /// Add a message to history
69    pub fn add_message(&mut self, role: String, content: String) {
70        self.history.push(ChatMessage { role, content });
71    }
72
73    /// Get chat history
74    pub fn get_history(&self) -> &[ChatMessage] {
75        &self.history
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_chat_session_creation() {
85        let session = ChatSession::new("openai".to_string(), "gpt-4".to_string());
86        assert_eq!(session.provider, "openai");
87        assert_eq!(session.model, "gpt-4");
88        assert!(session.history.is_empty());
89    }
90
91    #[test]
92    fn test_add_message() {
93        let mut session = ChatSession::new("openai".to_string(), "gpt-4".to_string());
94        session.add_message("user".to_string(), "Hello".to_string());
95        assert_eq!(session.history.len(), 1);
96        assert_eq!(session.history[0].role, "user");
97        assert_eq!(session.history[0].content, "Hello");
98    }
99
100    #[test]
101    fn test_get_history() {
102        let mut session = ChatSession::new("openai".to_string(), "gpt-4".to_string());
103        session.add_message("user".to_string(), "Hello".to_string());
104        session.add_message("assistant".to_string(), "Hi there!".to_string());
105
106        let history = session.get_history();
107        assert_eq!(history.len(), 2);
108    }
109}