use std::sync::Arc;
use clap::Parser;
use robit_agent::{create_tools_from_config, filter_skills_by_config, load_all_skills, log_skill_errors};
use robit_agent::skill::SkillRegistry;
use robit_ai::{init_logging, load_config, LlmClient};
use robit_chatbot::tool::SendFileTool;
use robit_chatbot::ChatbotManager;
use robit_qq::{QqConfig, QqPlatformAdapter};
#[derive(Debug, Parser)]
#[command(name = "robit-qq")]
#[command(about = "Robit AI Agent - QQ Bot")]
#[command(version)]
struct Cli {
#[arg(long, short = 'w')]
workdir: Option<std::path::PathBuf>,
#[arg(long)]
global_storage: bool,
}
#[tokio::main]
async fn main() {
let cli = Cli::parse();
let working_dir = cli
.workdir
.clone()
.unwrap_or_else(|| std::env::current_dir().expect("Failed to get current directory"));
let _lock = match robit_agent::DirectoryLock::acquire(&working_dir, "robit-qq") {
Ok(lock) => lock,
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
};
let config = load_config(Some(&working_dir)).expect("Failed to load config.toml");
init_logging(config.app.as_ref(), "robit_qq", &working_dir, &[]);
let llm_client = Arc::new(
LlmClient::from_config(&config, None).expect("Failed to initialize LLM client"),
);
let base_tool_names = ["read", "bash", "write", "edit"];
let (skills, skill_load_errors) = load_all_skills(&working_dir);
let filtered_skills = filter_skills_by_config(skills, &config);
let skill_registry = Arc::new(SkillRegistry::new(filtered_skills, &base_tool_names));
let mut tool_registry = create_tools_from_config(&config, Arc::clone(&skill_registry));
tool_registry.register(SendFileTool);
let tool_registry = Arc::new(tool_registry);
log_skill_errors(&skill_load_errors);
let qq_config = QqConfig::from_config(&config).expect("QQ Bot config not found");
let shutdown = Arc::new(tokio::sync::Notify::new());
let platform = QqPlatformAdapter::connect(qq_config, shutdown.clone())
.await
.expect("Failed to connect to QQ gateway");
let manager = ChatbotManager::new(
platform,
config,
working_dir,
llm_client,
tool_registry,
skill_registry,
)
.expect("Failed to create ChatbotManager");
tracing::info!("robit-qq bot is running");
let shutdown_clone = shutdown.clone();
tokio::select! {
result = manager.run(shutdown_clone) => {
if let Err(e) = result {
tracing::error!("ChatbotManager error: {}", e);
}
}
_ = tokio::signal::ctrl_c() => {
tracing::info!("Received Ctrl+C, shutting down gracefully...");
shutdown.notify_waiters();
}
}
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
tracing::info!("robit-qq bot has stopped");
}