use std::sync::Arc;
use agentcore::{
AgenticError, AnthropicProvider, CompletionRequest, ContentBlock, HttpTransport,
LiteLlmProvider, LlmProvider, Message, MistralProvider,
};
fn build_transport() -> HttpTransport {
Box::new(|url, headers, body| {
let url = url.to_string();
let headers: Vec<(String, String)> = headers
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect();
Box::pin(async move {
let client = reqwest::Client::new();
let mut req = client.post(&url).json(&body);
for (k, v) in &headers {
req = req.header(k.as_str(), v.as_str());
}
let resp = req.send().await.map_err(|e| AgenticError::Other(e.to_string()))?;
resp.json().await.map_err(|e| AgenticError::Other(e.to_string()))
})
})
}
fn build_provider() -> Option<(Arc<dyn LlmProvider>, String)> {
let transport = build_transport();
if let Ok(url) = std::env::var("LITELLM_API_URL") {
let key = std::env::var("LITELLM_API_KEY").unwrap_or_else(|_| "unused".into());
let model = std::env::var("LITELLM_MODEL").unwrap_or_else(|_| "claude-sonnet-4-20250514".into());
return Some((Arc::new(LiteLlmProvider::new(key, transport).base_url(url)), model));
}
if let Some(key) = std::env::var("MISTRAL_API_KEY").ok().filter(|k| !k.is_empty()) {
let mut p = MistralProvider::new(key, transport);
if let Ok(url) = std::env::var("MISTRAL_BASE_URL") {
p = p.base_url(url);
}
let model =
std::env::var("MISTRAL_MODEL").unwrap_or_else(|_| "mistral-medium-2508".into());
return Some((Arc::new(p), model));
}
if let Ok(key) = std::env::var("ANTHROPIC_API_KEY") {
let mut p = AnthropicProvider::new(key, transport);
if let Ok(url) = std::env::var("ANTHROPIC_BASE_URL") {
p = p.base_url(url);
}
let model = std::env::var("ANTHROPIC_MODEL").unwrap_or_else(|_| "claude-sonnet-4-20250514".into());
return Some((Arc::new(p), model));
}
if std::net::TcpStream::connect("127.0.0.1:4000").is_ok() {
let key = std::env::var("LITELLM_API_KEY").unwrap_or_else(|_| "unused".into());
let model = std::env::var("LITELLM_MODEL").unwrap_or_else(|_| "claude-sonnet-4-20250514".into());
return Some((Arc::new(LiteLlmProvider::new(key, transport).base_url("http://localhost:4000".into())), model));
}
return None;
}
#[tokio::test]
async fn test() -> std::result::Result<(), Box<dyn std::error::Error>> {
let Some((provider, model)) = build_provider() else { eprintln!("SKIPPED: no provider"); return Ok(()); };
let request = CompletionRequest {
model: model.clone(),
system_prompt: "You are a helpful assistant. Be concise.".into(),
messages: vec![Message::User {
content: vec![ContentBlock::Text {
text: "Say hello in one sentence.".into(),
}],
}],
tools: vec![],
max_tokens: 256,
tool_choice: None,
};
println!("Sending request...");
let response = provider.complete(request).await?;
for block in &response.content {
if let ContentBlock::Text { text } = block {
println!("Response: {text}");
}
}
println!("Model: {}", response.model);
println!(
"Usage: {} input, {} output tokens",
response.usage.input_tokens, response.usage.output_tokens
);
println!("\nTokens: {} in, {} out",
response.usage.input_tokens, response.usage.output_tokens);
Ok(())
}