use crate::config::RouterCfg;
use crate::model::RouteDecision;
pub struct RouterClient {
http: reqwest::Client,
url: String,
api_key: Option<String>,
taxonomy_id: Option<String>,
}
impl RouterClient {
pub fn new(cfg: &RouterCfg) -> anyhow::Result<Self> {
let mut builder =
reqwest::Client::builder().timeout(std::time::Duration::from_millis(cfg.timeout_ms));
if !cfg.verify_tls {
builder = builder
.danger_accept_invalid_certs(true)
.danger_accept_invalid_hostnames(true);
}
let http = builder.build()?;
let api_key = cfg
.api_key_env
.as_ref()
.and_then(|name| std::env::var(name).ok());
Ok(Self {
http,
url: cfg.url.trim_end_matches('/').to_string(),
api_key,
taxonomy_id: cfg.taxonomy_id.clone(),
})
}
pub async fn route(&self, text: &str, profile: &str) -> anyhow::Result<Option<RouteDecision>> {
let mut body = serde_json::json!({
"input": { "text": text },
"options": { "policy_profile": profile, "allow_oracle": true }
});
if let Some(tax) = &self.taxonomy_id {
body["taxonomy_id"] = serde_json::Value::String(tax.clone());
}
let mut req = self.http.post(format!("{}/v1/route", self.url)).json(&body);
if let Some(key) = &self.api_key {
req = req.bearer_auth(key);
}
let resp = match req.send().await {
Ok(r) => r,
Err(_) => return Ok(None), };
if !resp.status().is_success() {
return Ok(None);
}
let v: serde_json::Value = resp.json().await?;
let d = &v["decision"];
Ok(Some(RouteDecision {
task_label: d["task_label"]
.as_str()
.unwrap_or("__unknown__")
.to_string(),
complexity_score: d["complexity"]["score"].as_f64().unwrap_or(0.5) as f32,
complexity_tier: d["complexity"]["tier"]
.as_str()
.unwrap_or("medium")
.to_string(),
router_request_id: v["request_id"].as_str().map(|s| s.to_string()),
source: "router".into(),
}))
}
}