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::{ModelObject, ModelsResponse};
use crate::runner::ALL_PROVIDERS;
use crate::state::SharedState;
pub async fn handle(State(state): State<SharedState>) -> impl IntoResponse {
let mut data = Vec::new();
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() {
debug!(provider = %provider, "Binary not found, skipping");
continue;
}
match state.get_runner(provider).await {
Ok(runner) => {
let provider_name = runner.name();
let models = runner.available_models();
if models.is_empty() {
data.push(ModelObject {
id: provider_name.to_owned(),
object: "model",
owned_by: provider_name.to_owned(),
});
} else {
for model in models {
data.push(ModelObject {
id: format!("{provider_name}:{model}"),
object: "model",
owned_by: provider_name.to_owned(),
});
}
}
}
Err(e) => {
debug!(provider = %provider, error = %e, "Failed to create runner");
}
}
}
let resp = ModelsResponse {
object: "list",
data,
};
(StatusCode::OK, Json(resp))
}