use std::io::{self, Write};
use bitrouter_config::BitrouterConfig;
use serde::Serialize;
use super::OutputFormat;
#[derive(Debug, Serialize)]
pub struct ProviderEntry {
pub name: String,
pub api_base: Option<String>,
pub auth_kind: String,
}
#[derive(Debug, Serialize)]
pub struct ProviderListData {
pub providers: Vec<ProviderEntry>,
}
pub fn query_list(config: &BitrouterConfig) -> ProviderListData {
let mut names: Vec<&String> = config.providers.keys().collect();
names.sort();
let providers = names
.into_iter()
.map(|name| {
let p = &config.providers[name];
let auth_kind = if p.api_key.is_some() {
"api_key".to_owned()
} else if p.auth.is_some() {
"oauth".to_owned()
} else {
"none".to_owned()
};
ProviderEntry {
name: name.clone(),
api_base: p.api_base.clone(),
auth_kind,
}
})
.collect();
ProviderListData { providers }
}
pub fn render_list_text(data: &ProviderListData, w: &mut impl Write) -> io::Result<()> {
if data.providers.is_empty() {
writeln!(w, " (no providers configured)")?;
return Ok(());
}
eprintln!();
eprintln!(" Providers");
eprintln!(" ─────────");
eprintln!();
for entry in &data.providers {
let api_base = entry.api_base.as_deref().unwrap_or("(derives from base)");
let key_status = match entry.auth_kind.as_str() {
"api_key" => "\u{2713} key set",
"oauth" => "\u{2713} OAuth",
_ => "\u{2717} no credentials",
};
writeln!(w, " {:<20} {:<40} {key_status}", entry.name, api_base)?;
}
writeln!(w)?;
Ok(())
}
pub fn run_list(
config: &BitrouterConfig,
output: OutputFormat,
) -> Result<(), Box<dyn std::error::Error>> {
let data = query_list(config);
match output {
OutputFormat::Text => render_list_text(&data, &mut io::stdout())?,
OutputFormat::Json => serde_json::to_writer(io::stdout(), &data)?,
}
Ok(())
}
pub fn run_use(mode: &str, config: &BitrouterConfig) -> Result<(), Box<dyn std::error::Error>> {
let mode = mode.trim().to_lowercase();
let byok_configured = config
.providers
.iter()
.any(|(name, p)| name != "bitrouter" && (p.api_key.is_some() || p.auth.is_some()));
match mode.as_str() {
"default" => {
println!();
println!(" BitRouter Cloud is the default provider — models in");
println!(" bitrouter-config/providers/models/bitrouter.yaml are billed");
println!(" through your wallet.");
if byok_configured {
println!();
println!(" You also have BYOK providers configured. To make BitRouter");
println!(" Cloud the *sole* provider, run:");
println!(" bitrouter init");
println!(" and choose 'BitRouter Cloud' at the models step.");
}
}
"byok" => {
println!();
if byok_configured {
println!(" BYOK providers already configured:");
for (name, p) in &config.providers {
if name == "bitrouter" {
continue;
}
if p.api_key.is_some() || p.auth.is_some() {
println!(" \u{2713} {name}");
}
}
} else {
println!(" No BYOK providers configured yet. Run:");
println!(" bitrouter init");
println!(" and choose 'Bring Your Own Keys' at the models step.");
}
}
other => {
return Err(format!("unknown mode '{other}' (expected 'default' or 'byok')").into());
}
}
println!();
Ok(())
}