use crate::kota_code::agent::{AgentBuilder, AgentInstance};
use crate::kota_code::context::ContextManager;
use crate::kota_code::skills::SkillManager;
use anyhow::Result;
use colored::*;
use rustyline::error::ReadlineError;
use rustyline::Editor;
mod command;
pub mod command_registry;
mod render;
mod tab;
pub use command_registry::{parse_command_input, CommandRegistry};
use tab::KotaHelper;
const LOGO: &str = r#"
██╗░░██╗░█████╗░████████╗░█████╗░
██║░██╔╝██╔══██╗╚══██╔══╝██╔══██╗
█████═╝░██║░░██║░░░██║░░░███████║
██╔═██╗░██║░░██║░░░██║░░░██╔══██║
██║░╚██╗╚█████╔╝░░░██║░░░██║░░██║
╚═╝░░╚═╝░╚════╝░░░░╚═╝░░░╚═╝░░╚═╝
"#;
pub struct KotaCli {
pub agent_instance: AgentInstance,
pub api_base: String,
pub model_name: String,
pub api_key: String,
pub command_registry: Option<CommandRegistry>,
}
impl KotaCli {
pub fn new(
api_key: String,
api_base: String,
model_name: String,
context: ContextManager,
skill_manager: SkillManager,
command_registry: Option<CommandRegistry>,
) -> Result<Self> {
let agent_instance = AgentBuilder::new(api_key.clone(), model_name.clone())?
.with_context(context)
.with_skill_manager(skill_manager)
.build()?;
Ok(Self {
agent_instance,
api_base,
model_name,
api_key,
command_registry,
})
}
pub async fn run(&mut self) -> Result<()> {
println!("{}", LOGO);
self.show_welcome()?;
self.show_tips()?;
let result = self.run_input_loop().await;
match result {
Ok(_) => println!("\n{}", "👋 Goodbye!".bright_cyan()),
Err(e) => {
println!("\n{} {}", "❌ Error:".red(), e);
return Err(e);
}
}
Ok(())
}
async fn run_input_loop(&mut self) -> Result<()> {
let mut rl = Editor::new()?;
rl.set_helper(Some(KotaHelper::default()));
loop {
self.print_separator()?;
let readline = rl.readline("❯ ");
match readline {
Ok(line) => {
let input = line.trim();
if input.is_empty() {
continue;
}
let _ = rl.add_history_entry(input);
self.print_separator()?;
let should_continue = self.handle_command(input).await?;
if !should_continue {
break;
}
}
Err(ReadlineError::Interrupted) => {
println!("{}", "^C".dimmed());
break;
}
Err(ReadlineError::Eof) => {
break;
}
Err(err) => {
println!("{} {:?}", "Error:".red(), err);
break;
}
}
}
Ok(())
}
fn print_separator(&self) -> Result<()> {
let width = 80; let separator = "-".repeat(width);
println!("{}", separator.dimmed());
Ok(())
}
}