use llmr::providers::openai;
use llmr::{
transport::Reqwest, Message, Provider, Reach, Registry, Requirements, Route, Router, Secret,
};
use std::sync::Arc;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let transport = Arc::new(Reqwest::new(Duration::from_secs(5))?);
let local = Arc::new(openai::api::at(
"ollama",
"http://localhost:11434/v1",
Arc::clone(&transport) as Arc<dyn llmr::transport::HttpTransport>,
Secret::new("ollama", "not-needed"),
Reach::SelfHosted,
Arc::new(shelf("llama3", Reach::SelfHosted)),
));
let hosted = Arc::new(openai::api::at(
"vendor",
"https://api.example.invalid/v1",
transport,
Secret::new("vendor", "sk-not-real"),
Reach::FirstPartyApi,
Arc::new(shelf("some-hosted-model", Reach::FirstPartyApi)),
));
let router = Router::new(vec![
Route::new(local as Arc<dyn Provider>, "llama3"),
Route::new(hosted as Arc<dyn Provider>, "some-hosted-model"),
]);
for (name, capabilities) in router.routes() {
println!("route {name:<28} {:?}", capabilities.map(|c| c.reach));
}
println!("unusable routes: {:?}\n", router.unusable());
let request = llmr::ChatRequest::new("", vec![Message::user("Summarise this.")]);
println!("--- no privacy floor");
match router.chat(request.clone(), Requirements::default()).await {
Ok(routed) => println!(
"answered by {} after {:?}",
routed.route, routed.fell_through
),
Err(e) => println!("both were unreachable: {e}"),
}
println!("\n--- data must stay on this machine");
match router
.chat(request, Requirements::default().on_device())
.await
{
Ok(routed) => println!("answered by {}", routed.route),
Err(e) => println!("refused rather than sent away: {e}"),
}
Ok(())
}
fn shelf(model: &str, reach: Reach) -> Registry {
let toml = format!(
"provider = \"example\"\nreach = \"{reach:?}\"\n\n\
[[model]]\nid = \"{model}\"\ncontext_window = 128000\nmax_output = 4096\n\
source = \"an example\"\nverified_at = \"2026-08-28\"\n"
);
Registry::parse(&toml).unwrap_or_else(|_| Registry::empty("example", reach))
}