- Exclude problematic markdown files from linting (existing legacy issues) - Make clippy check less aggressive (warnings only, not -D warnings) - Move cargo test to manual stage (too slow for pre-commit) - Exclude SVG files from end-of-file-fixer and trailing-whitespace - Add markdown linting exclusions for existing documentation This allows pre-commit hooks to run successfully on new code without blocking commits due to existing issues in legacy documentation files.
133 lines
4.1 KiB
Rust
133 lines
4.1 KiB
Rust
//! VAPORA Agent Server Binary
|
|
//! Provides HTTP server for agent coordination and health checks
|
|
|
|
use anyhow::Result;
|
|
use axum::{extract::State, routing::get, Json, Router};
|
|
use serde_json::json;
|
|
use std::sync::Arc;
|
|
use tokio::net::TcpListener;
|
|
use tracing::{error, info};
|
|
use vapora_agents::{config::AgentConfig, coordinator::AgentCoordinator, registry::AgentRegistry};
|
|
use vapora_llm_router::{BudgetConfig, BudgetManager};
|
|
|
|
#[derive(Clone)]
|
|
struct AppState {
|
|
coordinator: Arc<AgentCoordinator>,
|
|
#[allow(dead_code)]
|
|
budget_manager: Option<Arc<BudgetManager>>,
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<()> {
|
|
// Initialize tracing
|
|
tracing_subscriber::fmt()
|
|
.with_env_filter(
|
|
tracing_subscriber::EnvFilter::from_default_env()
|
|
.add_directive("vapora_agents=debug".parse()?),
|
|
)
|
|
.init();
|
|
|
|
info!("Starting VAPORA Agent Server");
|
|
|
|
// Load configuration
|
|
let config = AgentConfig::from_env()?;
|
|
info!("Loaded configuration from environment");
|
|
|
|
// Load budget configuration
|
|
let budget_config_path = std::env::var("BUDGET_CONFIG_PATH")
|
|
.unwrap_or_else(|_| "config/agent-budgets.toml".to_string());
|
|
let budget_manager = match BudgetConfig::load_or_default(&budget_config_path) {
|
|
Ok(budget_config) => {
|
|
if budget_config.budgets.is_empty() {
|
|
info!(
|
|
"No budget configuration found at {}, running without budget enforcement",
|
|
budget_config_path
|
|
);
|
|
None
|
|
} else {
|
|
let manager = Arc::new(BudgetManager::new(budget_config.budgets));
|
|
info!(
|
|
"Loaded budget configuration for {} roles",
|
|
manager.list_budgets().await.len()
|
|
);
|
|
Some(manager)
|
|
}
|
|
}
|
|
Err(e) => {
|
|
error!("Failed to load budget configuration: {}", e);
|
|
return Err(e.into());
|
|
}
|
|
};
|
|
|
|
// Initialize agent registry and coordinator
|
|
// Max 10 agents per role (can be configured via environment)
|
|
let max_agents_per_role = std::env::var("MAX_AGENTS_PER_ROLE")
|
|
.ok()
|
|
.and_then(|v| v.parse().ok())
|
|
.unwrap_or(10);
|
|
let registry = Arc::new(AgentRegistry::new(max_agents_per_role));
|
|
let mut coordinator = AgentCoordinator::new(config, registry).await?;
|
|
|
|
// Attach budget manager to coordinator if available
|
|
if let Some(ref bm) = budget_manager {
|
|
coordinator = coordinator.with_budget_manager(bm.clone());
|
|
info!("Budget enforcement enabled for agent coordinator");
|
|
}
|
|
|
|
let coordinator = Arc::new(coordinator);
|
|
|
|
// Start coordinator
|
|
let _coordinator_handle = {
|
|
let coordinator = coordinator.clone();
|
|
tokio::spawn(async move {
|
|
if let Err(e) = coordinator.start().await {
|
|
error!("Coordinator error: {}", e);
|
|
}
|
|
})
|
|
};
|
|
|
|
// Build application state
|
|
let state = AppState {
|
|
coordinator,
|
|
budget_manager,
|
|
};
|
|
|
|
// Build HTTP router
|
|
let app = Router::new()
|
|
.route("/health", get(health_handler))
|
|
.route("/ready", get(readiness_handler))
|
|
.with_state(state);
|
|
|
|
// Start HTTP server
|
|
let addr = std::env::var("BIND_ADDR").unwrap_or_else(|_| "0.0.0.0:9000".to_string());
|
|
info!("Agent server listening on {}", addr);
|
|
|
|
let listener = TcpListener::bind(&addr).await?;
|
|
|
|
axum::serve(listener, app).await?;
|
|
|
|
// Note: coordinator_handle would be awaited here if needed,
|
|
// but axum::serve blocks until server shutdown
|
|
Ok(())
|
|
}
|
|
|
|
/// Health check endpoint
|
|
async fn health_handler() -> Json<serde_json::Value> {
|
|
Json(json!({
|
|
"status": "healthy",
|
|
"service": "vapora-agents",
|
|
"version": env!("CARGO_PKG_VERSION")
|
|
}))
|
|
}
|
|
|
|
/// Readiness check endpoint
|
|
async fn readiness_handler(State(state): State<AppState>) -> Json<serde_json::Value> {
|
|
let is_ready = state.coordinator.is_ready().await;
|
|
|
|
Json(json!({
|
|
"ready": is_ready,
|
|
"service": "vapora-agents",
|
|
"agents": state.coordinator.get_agent_count().await
|
|
}))
|
|
}
|