rig/providers/anthropic/
client.rs

1//! Anthropic client api implementation
2use http::{HeaderName, HeaderValue};
3
4use super::completion::{ANTHROPIC_VERSION_LATEST, CompletionModel};
5use crate::{
6    client::{
7        self, ApiKey, Capabilities, Capable, DebugExt, Nothing, Provider, ProviderBuilder,
8        ProviderClient,
9    },
10    http_client,
11};
12
13// ================================================================
14// Main Anthropic Client
15// ================================================================
16#[derive(Debug, Default, Clone)]
17pub struct AnthropicExt;
18
19impl Provider for AnthropicExt {
20    type Builder = AnthropicBuilder;
21
22    const VERIFY_PATH: &'static str = "/v1/models";
23
24    fn build<H>(
25        _builder: &client::ClientBuilder<Self::Builder, AnthropicKey, H>,
26    ) -> http_client::Result<Self> {
27        Ok(Self)
28    }
29}
30
31impl<H> Capabilities<H> for AnthropicExt {
32    type Completion = Capable<CompletionModel<H>>;
33
34    type Embeddings = Nothing;
35    type Transcription = Nothing;
36    #[cfg(feature = "image")]
37    type ImageGeneration = Nothing;
38    #[cfg(feature = "audio")]
39    type AudioGeneration = Nothing;
40}
41
42#[derive(Debug, Clone)]
43pub struct AnthropicBuilder {
44    anthropic_version: String,
45    anthropic_betas: Vec<String>,
46}
47
48#[derive(Debug, Clone)]
49pub struct AnthropicKey(String);
50
51impl<S> From<S> for AnthropicKey
52where
53    S: Into<String>,
54{
55    fn from(value: S) -> Self {
56        Self(value.into())
57    }
58}
59
60impl ApiKey for AnthropicKey {
61    fn into_header(self) -> Option<http_client::Result<(http::HeaderName, HeaderValue)>> {
62        Some(
63            HeaderValue::from_str(&self.0)
64                .map(|val| (HeaderName::from_static("x-api-key"), val))
65                .map_err(Into::into),
66        )
67    }
68}
69
70pub type Client<H = reqwest::Client> = client::Client<AnthropicExt, H>;
71pub type ClientBuilder<H = reqwest::Client> =
72    client::ClientBuilder<AnthropicBuilder, AnthropicKey, H>;
73
74impl Default for AnthropicBuilder {
75    fn default() -> Self {
76        Self {
77            anthropic_version: ANTHROPIC_VERSION_LATEST.into(),
78            anthropic_betas: Vec::new(),
79        }
80    }
81}
82
83impl ProviderBuilder for AnthropicBuilder {
84    type Output = AnthropicExt;
85    type ApiKey = AnthropicKey;
86
87    const BASE_URL: &'static str = "https://api.anthropic.com";
88
89    fn finish<H>(
90        &self,
91        mut builder: client::ClientBuilder<Self, AnthropicKey, H>,
92    ) -> http_client::Result<client::ClientBuilder<Self, AnthropicKey, H>> {
93        builder.headers_mut().insert(
94            "anthropic-version",
95            HeaderValue::from_str(&self.anthropic_version)?,
96        );
97
98        if !self.anthropic_betas.is_empty() {
99            builder.headers_mut().insert(
100                "anthropic-beta",
101                HeaderValue::from_str(&self.anthropic_betas.join(","))?,
102            );
103        }
104
105        Ok(builder)
106    }
107}
108
109impl DebugExt for AnthropicExt {}
110
111impl ProviderClient for Client {
112    type Input = String;
113
114    fn from_env() -> Self
115    where
116        Self: Sized,
117    {
118        let key = std::env::var("ANTHROPIC_API_KEY").expect("ANTHROPIC_API_KEY not set");
119
120        Self::builder().api_key(key).build().unwrap()
121    }
122
123    fn from_val(input: Self::Input) -> Self
124    where
125        Self: Sized,
126    {
127        Self::builder().api_key(input).build().unwrap()
128    }
129}
130
131/// Create a new anthropic client using the builder
132///
133/// # Example
134/// ```
135/// use rig::providers::anthropic::{ClientBuilder, self};
136///
137/// // Initialize the Anthropic client
138/// let anthropic_client = ClientBuilder::new("your-claude-api-key")
139///    .anthropic_version(ANTHROPIC_VERSION_LATEST)
140///    .anthropic_beta("prompt-caching-2024-07-31")
141///    .build()
142/// ```
143impl<H> ClientBuilder<H> {
144    pub fn anthropic_version(self, anthropic_version: &str) -> Self {
145        self.over_ext(|ext| AnthropicBuilder {
146            anthropic_version: anthropic_version.into(),
147            ..ext
148        })
149    }
150
151    pub fn anthropic_betas(self, anthropic_betas: &[&str]) -> Self {
152        self.over_ext(|mut ext| {
153            ext.anthropic_betas
154                .extend(anthropic_betas.iter().copied().map(String::from));
155
156            ext
157        })
158    }
159
160    pub fn anthropic_beta(self, anthropic_beta: &str) -> Self {
161        self.over_ext(|mut ext| {
162            ext.anthropic_betas.push(anthropic_beta.into());
163
164            ext
165        })
166    }
167}