use std::time::Duration;
use crate::api::batches::Batches;
use crate::api::messages::Messages;
use crate::api::models::Models;
use crate::error::{Error, Result};
use crate::http::HttpClient;
const DEFAULT_BASE_URL: &str = "https://api.anthropic.com";
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(600);
const DEFAULT_MAX_RETRIES: u32 = 2;
#[derive(Clone, Debug)]
pub struct Client {
http: HttpClient,
}
impl Client {
pub fn builder() -> ClientBuilder {
ClientBuilder::default()
}
pub fn from_env() -> Result<Self> {
let api_key = std::env::var("ANTHROPIC_API_KEY").map_err(|_| {
Error::Config("environment variable ANTHROPIC_API_KEY is not set".to_string())
})?;
Self::builder().api_key(api_key).build()
}
pub fn messages(&self) -> Messages<'_> {
Messages::new(self)
}
pub fn models(&self) -> Models<'_> {
Models::new(self)
}
pub fn batches(&self) -> Batches<'_> {
Batches::new(self)
}
pub(crate) fn http(&self) -> &HttpClient {
&self.http
}
}
#[derive(Clone)]
pub struct ClientBuilder {
api_key: Option<String>,
base_url: String,
timeout: Duration,
max_retries: u32,
}
impl std::fmt::Debug for ClientBuilder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ClientBuilder")
.field("api_key", &self.api_key.as_ref().map(|_| "[redacted]"))
.field("base_url", &self.base_url)
.field("timeout", &self.timeout)
.field("max_retries", &self.max_retries)
.finish()
}
}
impl Default for ClientBuilder {
fn default() -> Self {
Self {
api_key: None,
base_url: DEFAULT_BASE_URL.to_string(),
timeout: DEFAULT_TIMEOUT,
max_retries: DEFAULT_MAX_RETRIES,
}
}
}
impl ClientBuilder {
pub fn api_key(mut self, api_key: impl Into<String>) -> Self {
self.api_key = Some(api_key.into());
self
}
pub fn base_url(mut self, base_url: impl Into<String>) -> Self {
self.base_url = base_url.into();
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn max_retries(mut self, max_retries: u32) -> Self {
self.max_retries = max_retries;
self
}
pub fn build(self) -> Result<Client> {
let api_key = self.api_key.filter(|key| !key.is_empty()).ok_or_else(|| {
Error::Config(
"`api_key` is required (set it explicitly or via ANTHROPIC_API_KEY)".to_string(),
)
})?;
let builder = reqwest::Client::builder();
#[cfg(not(target_arch = "wasm32"))]
let builder = builder.read_timeout(self.timeout);
let http_client = builder.build()?;
let http = HttpClient::new(
http_client,
self.base_url,
api_key,
self.max_retries,
self.timeout,
);
Ok(Client { http })
}
}