rig/providers/anthropic/
client.rs1use 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::{self, HttpClientExt},
11};
12
13#[derive(Debug, Default, Clone)]
17pub struct AnthropicExt;
18
19impl Provider for AnthropicExt {
20 type Builder = AnthropicBuilder;
21 const VERIFY_PATH: &'static str = "/v1/models";
22}
23
24impl<H> Capabilities<H> for AnthropicExt {
25 type Completion = Capable<CompletionModel<H>>;
26
27 type Embeddings = Nothing;
28 type Transcription = Nothing;
29 type ModelListing = Nothing;
30 #[cfg(feature = "image")]
31 type ImageGeneration = Nothing;
32 #[cfg(feature = "audio")]
33 type AudioGeneration = Nothing;
34}
35
36#[derive(Debug, Clone)]
37pub struct AnthropicBuilder {
38 anthropic_version: String,
39 anthropic_betas: Vec<String>,
40}
41
42#[derive(Debug, Clone)]
43pub struct AnthropicKey(String);
44
45impl<S> From<S> for AnthropicKey
46where
47 S: Into<String>,
48{
49 fn from(value: S) -> Self {
50 Self(value.into())
51 }
52}
53
54impl ApiKey for AnthropicKey {
55 fn into_header(self) -> Option<http_client::Result<(http::HeaderName, HeaderValue)>> {
56 Some(
57 HeaderValue::from_str(&self.0)
58 .map(|val| (HeaderName::from_static("x-api-key"), val))
59 .map_err(Into::into),
60 )
61 }
62}
63
64pub type Client<H = reqwest::Client> = client::Client<AnthropicExt, H>;
65pub type ClientBuilder<H = reqwest::Client> =
66 client::ClientBuilder<AnthropicBuilder, AnthropicKey, H>;
67
68impl Default for AnthropicBuilder {
69 fn default() -> Self {
70 Self {
71 anthropic_version: ANTHROPIC_VERSION_LATEST.into(),
72 anthropic_betas: Vec::new(),
73 }
74 }
75}
76
77impl ProviderBuilder for AnthropicBuilder {
78 type Extension<H>
79 = AnthropicExt
80 where
81 H: HttpClientExt;
82 type ApiKey = AnthropicKey;
83
84 const BASE_URL: &'static str = "https://api.anthropic.com";
85
86 fn build<H>(
87 _builder: &client::ClientBuilder<Self, Self::ApiKey, H>,
88 ) -> http_client::Result<Self::Extension<H>>
89 where
90 H: HttpClientExt,
91 {
92 Ok(AnthropicExt)
93 }
94
95 fn finish<H>(
96 &self,
97 mut builder: client::ClientBuilder<Self, AnthropicKey, H>,
98 ) -> http_client::Result<client::ClientBuilder<Self, AnthropicKey, H>> {
99 builder.headers_mut().insert(
100 "anthropic-version",
101 HeaderValue::from_str(&self.anthropic_version)?,
102 );
103
104 if !self.anthropic_betas.is_empty() {
105 builder.headers_mut().insert(
106 "anthropic-beta",
107 HeaderValue::from_str(&self.anthropic_betas.join(","))?,
108 );
109 }
110
111 Ok(builder)
112 }
113}
114
115impl DebugExt for AnthropicExt {}
116
117impl ProviderClient for Client {
118 type Input = String;
119
120 fn from_env() -> Self
121 where
122 Self: Sized,
123 {
124 let key = std::env::var("ANTHROPIC_API_KEY").expect("ANTHROPIC_API_KEY not set");
125
126 Self::builder().api_key(key).build().unwrap()
127 }
128
129 fn from_val(input: Self::Input) -> Self
130 where
131 Self: Sized,
132 {
133 Self::builder().api_key(input).build().unwrap()
134 }
135}
136
137impl<H> ClientBuilder<H> {
150 pub fn anthropic_version(self, anthropic_version: &str) -> Self {
151 self.over_ext(|ext| AnthropicBuilder {
152 anthropic_version: anthropic_version.into(),
153 ..ext
154 })
155 }
156
157 pub fn anthropic_betas(self, anthropic_betas: &[&str]) -> Self {
158 self.over_ext(|mut ext| {
159 ext.anthropic_betas
160 .extend(anthropic_betas.iter().copied().map(String::from));
161
162 ext
163 })
164 }
165
166 pub fn anthropic_beta(self, anthropic_beta: &str) -> Self {
167 self.over_ext(|mut ext| {
168 ext.anthropic_betas.push(anthropic_beta.into());
169
170 ext
171 })
172 }
173}
174#[cfg(test)]
175mod tests {
176 #[test]
177 fn test_client_initialization() {
178 let _client =
179 crate::providers::anthropic::Client::new("dummy-key").expect("Client::new() failed");
180 let _client_from_builder = crate::providers::anthropic::Client::builder()
181 .api_key("dummy-key")
182 .build()
183 .expect("Client::builder() failed");
184 }
185}