use std::env;
use std::time::Instant;
use serde_json::{json, Value};
pub type TurnTuple = (String, u32, u32, u32);
pub fn call_ollama(user_msg: &str) -> Result<TurnTuple, String> {
let url = env::var("NOUS_OLLAMA_URL")
.unwrap_or_else(|_| "http://localhost:11434/api/chat".into());
let model = env::var("NOUS_OLLAMA_MODEL").unwrap_or_else(|_| "phi3:mini".into());
let body = json!({
"model": model,
"messages": [{"role": "user", "content": user_msg}],
"stream": false
});
let t0 = Instant::now();
let resp = ureq::post(&url)
.send_json(&body)
.map_err(|e| format!("HTTP request failed: {e}"))?;
let data: Value = resp
.into_json()
.map_err(|e| format!("JSON parse failed: {e}"))?;
let content = data["message"]["content"]
.as_str()
.ok_or("response missing message.content")?
.to_string();
let tokens_in = data["prompt_eval_count"].as_u64().unwrap_or(0) as u32;
let tokens_out = data["eval_count"].as_u64().unwrap_or(0) as u32;
let wallclock_ms = t0.elapsed().as_millis() as u32;
Ok((content, tokens_in, tokens_out, wallclock_ms))
}
pub fn call_anthropic(user_msg: &str) -> Result<TurnTuple, String> {
let key = env::var("ANTHROPIC_API_KEY")
.map_err(|_| "ANTHROPIC_API_KEY env var unset".to_string())?;
let model = env::var("NOUS_ANTHROPIC_MODEL")
.unwrap_or_else(|_| "claude-haiku-4-5-20251001".into());
let body = json!({
"model": model,
"max_tokens": 512,
"messages": [{"role": "user", "content": user_msg}]
});
let t0 = Instant::now();
let resp = ureq::post("https://api.anthropic.com/v1/messages")
.set("x-api-key", &key)
.set("anthropic-version", "2023-06-01")
.set("content-type", "application/json")
.send_json(&body)
.map_err(|e| format!("HTTP request failed: {e}"))?;
let data: Value = resp
.into_json()
.map_err(|e| format!("JSON parse failed: {e}"))?;
let content = data["content"]
.as_array()
.and_then(|blocks| {
let joined: String = blocks
.iter()
.filter_map(|b| b["text"].as_str())
.collect::<Vec<_>>()
.join("");
if joined.is_empty() {
None
} else {
Some(joined)
}
})
.ok_or_else(|| format!("response missing content[].text: {data}"))?;
let tokens_in = data["usage"]["input_tokens"].as_u64().unwrap_or(0) as u32;
let tokens_out = data["usage"]["output_tokens"].as_u64().unwrap_or(0) as u32;
let wallclock_ms = t0.elapsed().as_millis() as u32;
Ok((content, tokens_in, tokens_out, wallclock_ms))
}