use std::sync::Arc;
use anyhow::Result;
use imitatort::{
start_web_server, Agent, AppConfig, CompanyBuilder, CompanyConfig, VirtualCompany,
};
use tokio::sync::broadcast;
use tracing::{info, warn};
use dotenv::dotenv;
#[tokio::main]
async fn main() -> Result<()> {
dotenv().ok();
tracing_subscriber::fmt::init();
info!("🚀 Starting ImitatorT - Multi-Agent Company Framework...");
let app_config = AppConfig::from_env();
info!(
"Using configuration: output_mode={}, web_bind={}",
app_config.output_mode, app_config.web_bind
);
let company = initialize_framework(&app_config).await?;
start_services(company, &app_config).await?;
Ok(())
}
async fn initialize_framework(app_config: &AppConfig) -> Result<VirtualCompany> {
info!("🔧 Initializing multi-agent framework...");
if let Ok(config) = load_config() {
info!("📋 Loaded company configuration from company_config.yaml");
let company = CompanyBuilder::from_config(config)?
.build_and_save()
.await?;
info!("✅ Multi-agent system initialized with configuration");
return Ok(company);
}
info!("🔍 No config file found, attempting to load from database...");
match VirtualCompany::from_sqlite(&app_config.db_path).await {
Ok(company) => {
info!(
"✅ Loaded existing company from database: {}",
app_config.db_path
);
Ok(company)
}
Err(_) => {
warn!("⚠️ No existing database found, initializing with default configuration");
let config = CompanyConfig::test_config();
let company = CompanyBuilder::from_config(config)?
.build_and_save()
.await?;
info!("✅ Initialized default multi-agent system");
Ok(company)
}
}
}
fn load_config() -> Result<CompanyConfig> {
if let Ok(content) = std::fs::read_to_string("company_config.yaml") {
let config: CompanyConfig = serde_yaml::from_str(&content)?;
return Ok(config);
}
Err(anyhow::anyhow!("Config file not found"))
}
async fn start_services(company: VirtualCompany, app_config: &AppConfig) -> Result<()> {
info!("⚡ Starting framework services...");
let agents: Vec<Agent> = company.get_agents().await?;
info!("👥 Loaded {} agents", agents.len());
let (message_tx, _) = broadcast::channel::<imitatort::Message>(1000);
let company_arc = Arc::new(company);
if app_config.run_agent_loops {
info!("🔄 Starting agent autonomous loops...");
let company_for_agents = company_arc.clone();
let message_tx_for_agents = message_tx.clone();
tokio::spawn(async move {
start_agent_loops(company_for_agents, message_tx_for_agents).await;
});
} else {
info!("⏸️ Agent loops disabled by configuration");
}
if app_config.output_mode == "web" {
info!("🌐 Starting web server on {}", app_config.web_bind);
start_web_server(
&app_config.web_bind,
agents,
message_tx,
company_arc.store().clone(),
)
.await?;
info!("✅ Web server started successfully");
} else {
info!("ℹ️ Running in console mode (no web interface)");
tokio::signal::ctrl_c()
.await
.expect("Failed to listen for ctrl+c");
info!("🛑 Received shutdown signal");
}
Ok(())
}
async fn start_agent_loops(
company: Arc<VirtualCompany>,
_message_tx: broadcast::Sender<imitatort::Message>,
) {
info!("🤖 Starting agent autonomous operations...");
match company.run().await {
Ok(_) => info!("Agent operations completed"),
Err(e) => {
tracing::error!("Agent operations error: {}", e);
}
}
}