Overview
Providers implement theProvider trait, which defines a simple contract:
Step-by-Step Guide
use anyhow::Result;
use async_trait::async_trait;
use crate::providers::traits::Provider;
/// Custom provider for Ollama (local LLM server)
pub struct OllamaProvider {
base_url: String,
client: reqwest::Client,
}
impl OllamaProvider {
pub fn new(base_url: Option<&str>) -> Self {
Self {
base_url: base_url.unwrap_or("http://localhost:11434").to_string(),
client: reqwest::Client::new(),
}
}
}
#[async_trait]
impl Provider for OllamaProvider {
async fn chat(&self, message: &str, model: &str, temperature: f64) -> Result<String> {
let url = format!("{}/api/generate", self.base_url);
let body = serde_json::json!({
"model": model,
"prompt": message,
"temperature": temperature,
"stream": false,
});
let resp = self
.client
.post(&url)
.json(&body)
.send()
.await?
.json::<serde_json::Value>()
.await?;
resp["response"]
.as_str()
.map(|s| s.to_string())
.ok_or_else(|| anyhow::anyhow!("No response field in Ollama reply"))
}
}
pub fn create_provider(name: &str, api_key: Option<&str>) -> Result<Box<dyn Provider>> {
match name {
"openai" => Ok(Box::new(openai::OpenAIProvider::new(api_key)?)),
"anthropic" => Ok(Box::new(anthropic::AnthropicProvider::new(api_key)?)),
"ollama" => Ok(Box::new(ollama::OllamaProvider::new(None))),
_ => anyhow::bail!("Unknown provider: {}", name),
}
}
default_provider = "ollama"
default_model = "llama3.2"
default_temperature = 0.7
# Ollama doesn't need an API key for local use
api_key = ""
Complete Example
Here’s the full implementation fromexamples/custom_provider.rs:
Advanced Features
Error Handling
Providers should return descriptive errors:Streaming Support
For streaming responses, implementchat_stream:
Authentication
Handle API keys securely:Best Practices
Keep implementations simple and focused
Keep implementations simple and focused
Focus on API communication. Don’t add business logic — that belongs in the agent orchestration layer.
Handle rate limits gracefully
Handle rate limits gracefully
Implement exponential backoff for rate-limited APIs:
Never log API keys or sensitive data
Never log API keys or sensitive data
Use masked logging for credentials:
Test against provider's actual API
Test against provider's actual API
Use integration tests with real (or mocked) API calls:
Next Steps
Creating Channels
Learn how to add messaging platform support
Creating Tools
Give your agent new capabilities