Skip to main content

kowalski_cli/
interactive.rs

1use colored::*;
2use kowalski_core::agent::Agent;
3use rustyline::error::ReadlineError;
4use rustyline::{DefaultEditor, Result};
5
6pub struct InteractiveSession {
7    agent: Box<dyn Agent + Send + Sync>,
8    conversation_id: String,
9}
10
11impl InteractiveSession {
12    pub fn new(mut agent: Box<dyn Agent + Send + Sync>, model: &str) -> Self {
13        let conversation_id = agent.start_conversation(model);
14        Self {
15            agent,
16            conversation_id,
17        }
18    }
19
20    pub async fn run(&mut self) -> Result<()> {
21        let mut rl = DefaultEditor::new()?;
22        let history_path = "history.txt";
23
24        if rl.load_history(history_path).is_err() {
25            println!("No previous history.");
26        }
27
28        println!("{}", "Welcome to Kowalski Interactive Mode!".green().bold());
29        println!("{}", "Type your message or use /help for commands.".cyan());
30
31        loop {
32            let readline = rl.readline(">> ");
33            match readline {
34                Ok(line) => {
35                    let trim_line = line.trim();
36                    if trim_line.is_empty() {
37                        continue;
38                    }
39
40                    rl.add_history_entry(trim_line)?;
41
42                    if trim_line.starts_with('/') {
43                        let cmd = trim_line.to_lowercase();
44                        match cmd.as_str() {
45                            "/exit" | "/quit" => {
46                                println!("{}", "Goodbye!".yellow());
47                                break;
48                            }
49                            "/help" => {
50                                self.print_help();
51                                continue;
52                            }
53                            "/clear" => {
54                                // Simplified clear
55                                print!("\x1B[2J\x1B[1;1H");
56                                continue;
57                            }
58                            _ => {
59                                println!("{} {}", "Unknown command:".red(), cmd);
60                                continue;
61                            }
62                        }
63                    }
64
65                    // Process with agent
66                    println!("{}", "Processing...".italic().dimmed());
67                    match self
68                        .agent
69                        .chat_with_tools(&self.conversation_id, trim_line)
70                        .await
71                    {
72                        Ok(response) => {
73                            println!("\n{}\n", response.blue());
74                        }
75                        Err(e) => {
76                            println!("{} {}", "Error:".red().bold(), e);
77                        }
78                    }
79                }
80                Err(ReadlineError::Interrupted) => {
81                    println!("Interrupted");
82                    break;
83                }
84                Err(ReadlineError::Eof) => {
85                    println!("EOF");
86                    break;
87                }
88                Err(err) => {
89                    println!("Error: {:?}", err);
90                    break;
91                }
92            }
93        }
94
95        rl.save_history(history_path)?;
96        Ok(())
97    }
98
99    fn print_help(&self) {
100        println!("{}", "\nAvailable Commands:".bold());
101        println!("  {} - Display this help message", "/help".cyan());
102        println!("  {} - Clear the screen", "/clear".cyan());
103        println!("  {} - Exit the interactive session", "/exit".cyan());
104        println!("  {} - Exit the interactive session", "/quit".cyan());
105        println!();
106    }
107}