use std::collections::HashMap;
use std::env;
use axum::extract::State;
use axum::http::StatusCode;
use axum::response::IntoResponse;
use axum::Json;
use embacle::discovery::resolve_binary;
use tracing::debug;
use crate::openai_types::HealthResponse;
use crate::runner::ALL_PROVIDERS;
use crate::state::SharedState;
pub async fn handle(State(state): State<SharedState>) -> impl IntoResponse {
let mut providers = HashMap::new();
let mut any_ready = false;
for &provider in ALL_PROVIDERS {
let binary_name = provider.binary_name();
let env_key = provider.env_override_key();
let env_override = env::var(env_key).ok();
if resolve_binary(binary_name, env_override.as_deref()).is_err() {
providers.insert(provider.to_string(), "not_found".to_owned());
continue;
}
match state.get_runner(provider).await {
Ok(runner) => match runner.health_check().await {
Ok(true) => {
providers.insert(provider.to_string(), "ready".to_owned());
any_ready = true;
}
Ok(false) => {
providers.insert(provider.to_string(), "not_ready".to_owned());
}
Err(e) => {
debug!(provider = %provider, error = %e, "Health check failed");
providers.insert(provider.to_string(), format!("error: {e}"));
}
},
Err(e) => {
debug!(provider = %provider, error = %e, "Failed to create runner");
providers.insert(provider.to_string(), format!("error: {e}"));
}
}
}
let status_str = if any_ready { "ok" } else { "degraded" };
let http_status = if any_ready {
StatusCode::OK
} else {
StatusCode::SERVICE_UNAVAILABLE
};
let resp = HealthResponse {
status: status_str,
providers,
};
(http_status, Json(resp))
}