//! AI service binary - HTTP wrapper for AI capabilities including RAG, MCP tool //! invocation, and knowledge graphs use std::net::SocketAddr; use std::sync::Arc; use ai_service::{handlers, AiService, DEFAULT_PORT}; use axum::Router; use clap::Parser; #[derive(Parser, Debug)] #[command(name = "ai-service")] #[command(about = "HTTP service for AI capabilities including RAG, MCP tool invocation, DAG operations, and knowledge graphs", long_about = None)] struct Args { /// Configuration file path (highest priority) #[arg(short = 'c', long, env = "AI_SERVICE_CONFIG")] config: Option, /// Configuration directory (searches for ai-service.ncl|toml|json) #[arg(long, env = "PROVISIONING_CONFIG_DIR")] config_dir: Option, /// Deployment mode (solo, multiuser, cicd, enterprise) #[arg(short = 'm', long, env = "AI_SERVICE_MODE")] mode: Option, /// Service bind address #[arg(short = 'H', long, default_value = "127.0.0.1")] host: String, /// Service bind port #[arg(short = 'p', long, default_value_t = DEFAULT_PORT)] port: u16, /// Print all #[onto_api] registered routes as JSON and exit. /// Pipe to api-catalog-ai-service.json: `just export-api-catalog` #[arg(long)] dump_api_catalog: bool, } #[tokio::main] async fn main() -> anyhow::Result<()> { // Parse CLI arguments FIRST (so --help works before any other processing) let args = Args::parse(); if args.dump_api_catalog { println!("{}", ontoref_ontology::api::dump_catalog_json()); return Ok(()); } // Initialize centralized observability (logging, metrics, health checks) let _guard = observability::init_from_env("ai-service", env!("CARGO_PKG_VERSION"))?; // Check if ai-service is enabled in deployment-mode.ncl if let Ok(deployment) = platform_config::load_deployment_mode() { if let Ok(enabled) = deployment.is_service_enabled("ai_service") { if !enabled { tracing::warn!("⚠ AI Service is DISABLED in deployment-mode.ncl"); std::process::exit(1); } tracing::info!("✓ AI Service is ENABLED in deployment-mode.ncl"); } } // Try to load ai-service.ncl if let Ok(config) = platform_config::load_service_config_from_ncl("ai-service") { tracing::info!("✓ Loaded ai-service configuration from NCL"); tracing::debug!("Config: {:?}", config); } let addr: SocketAddr = format!("{}:{}", args.host, args.port).parse()?; // Create service let service = Arc::new(AiService::new(addr)); tracing::info!("Starting AI service on {}", addr); // Create router let app = Router::new() .merge(handlers::create_routes(service)) .fallback(|| async { (axum::http::StatusCode::NOT_FOUND, "Not found") }); // Start server let listener = tokio::net::TcpListener::bind(&addr).await?; axum::serve(listener, app).await?; Ok(()) }