use systemprompt_models::services::{GatewayConfig, ModelPricing, ProviderRegistry};
#[derive(Debug, thiserror::Error)]
#[error("No configured pricing for provider {provider} and models {models:?}")]
pub struct MissingPricing {
pub provider: String,
pub models: Vec<String>,
}
pub fn resolve(
provider: &str,
candidates: &[&str],
gateway: Option<&GatewayConfig>,
registry: &ProviderRegistry,
) -> Result<ModelPricing, MissingPricing> {
for model in candidates.iter().filter(|m| !m.is_empty()) {
if let Some(p) = lookup(model, gateway, registry) {
return Ok(p);
}
}
Err(MissingPricing {
provider: provider.to_owned(),
models: candidates.iter().map(|model| (*model).to_owned()).collect(),
})
}
fn lookup(
model: &str,
gateway: Option<&GatewayConfig>,
registry: &ProviderRegistry,
) -> Option<ModelPricing> {
if let Some(gw) = gateway
&& let Some(route) = gw.find_route(model)
&& let Some(p) = route.pricing
{
return Some(p);
}
registry_pricing(registry, gateway, model)
}
fn registry_pricing(
registry: &ProviderRegistry,
gateway: Option<&GatewayConfig>,
model: &str,
) -> Option<ModelPricing> {
if let Some(route) = gateway.and_then(|gw| gw.find_route(model))
&& let Some(m) = route
.resolve(registry)
.and_then(|entry| entry.find_model(model))
{
return Some(m.pricing);
}
registry
.providers
.iter()
.find_map(|entry| entry.find_model(model))
.map(|m| m.pricing)
}
pub fn resolve_selected(
route: &systemprompt_models::services::GatewayRoute,
provider: &systemprompt_models::services::ProviderEntry,
requested_model: &str,
) -> Result<ModelPricing, MissingPricing> {
let model = route.upstream_model.as_deref().unwrap_or(requested_model);
route
.pricing
.or_else(|| provider.find_model(model).map(|entry| entry.pricing))
.ok_or_else(|| MissingPricing {
provider: route.provider.to_string(),
models: vec![model.to_owned()],
})
}