use serde::{Deserialize, Serialize};
use crate::profile::{ApiSurface, ProviderRegistry};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BridgeProfileResponse {
pub inference_gateway_base_url: String,
pub auth_scheme: String,
#[serde(default)]
pub models: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub default_model: Option<String>,
#[serde(default)]
pub organization_uuid: Option<String>,
#[serde(default)]
pub providers: Vec<ProviderHealth>,
}
pub const KNOWN_HOSTS: &[&str] = &[
"claude-code",
"claude-desktop",
"codex-cli",
"hermes",
"opencode",
];
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderHealth {
pub name: String,
pub surface: ApiSurface,
pub configured: bool,
#[serde(default)]
pub models: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub config_issue: Option<String>,
}
pub fn provider_health(
registry: &ProviderRegistry,
secret_present: impl Fn(&str) -> bool,
) -> Vec<ProviderHealth> {
registry
.advertised_providers()
.map(|entry| {
let secret = entry.api_key_secret.as_str();
let configured = secret_present(secret);
ProviderHealth {
name: entry.name.as_str().to_owned(),
surface: entry.surface,
configured,
models: entry
.models
.iter()
.flat_map(|m| {
std::iter::once(m.id.as_str().to_owned())
.chain(m.aliases.iter().map(|a| a.as_str().to_owned()))
})
.collect(),
config_issue: (!configured)
.then(|| format!("API key secret '{secret}' is not configured")),
}
})
.collect()
}
#[derive(Debug, Clone)]
pub struct BridgeProfileParams<'a> {
pub inference_gateway_base_url: String,
pub auth_scheme: String,
pub organization_uuid: Option<String>,
pub default_model: Option<String>,
pub registry: &'a ProviderRegistry,
}
#[must_use]
pub fn build(
params: BridgeProfileParams<'_>,
secret_present: impl Fn(&str) -> bool,
) -> BridgeProfileResponse {
let BridgeProfileParams {
inference_gateway_base_url,
auth_scheme,
organization_uuid,
default_model,
registry,
} = params;
BridgeProfileResponse {
inference_gateway_base_url,
auth_scheme,
models: registry.advertised_model_ids(&[ApiSurface::Anthropic]),
default_model,
organization_uuid,
providers: provider_health(registry, secret_present),
}
}