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,
11};
12
13#[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
131impl<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}