bep/providers/anthropic/
client.rs1use crate::{agent::AgentBuilder, extractor::ExtractorBuilder};
4
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7
8use super::completion::{CompletionModel, ANTHROPIC_VERSION_LATEST};
9
10const ANTHROPIC_API_BASE_URL: &str = "https://api.anthropic.com";
14
15#[derive(Clone)]
16pub struct ClientBuilder<'a> {
17 api_key: &'a str,
18 base_url: &'a str,
19 anthropic_version: &'a str,
20 anthropic_betas: Option<Vec<&'a str>>,
21}
22
23impl<'a> ClientBuilder<'a> {
36 pub fn new(api_key: &'a str) -> Self {
37 Self {
38 api_key,
39 base_url: ANTHROPIC_API_BASE_URL,
40 anthropic_version: ANTHROPIC_VERSION_LATEST,
41 anthropic_betas: None,
42 }
43 }
44
45 pub fn base_url(mut self, base_url: &'a str) -> Self {
46 self.base_url = base_url;
47 self
48 }
49
50 pub fn anthropic_version(mut self, anthropic_version: &'a str) -> Self {
51 self.anthropic_version = anthropic_version;
52 self
53 }
54
55 pub fn anthropic_beta(mut self, anthropic_beta: &'a str) -> Self {
56 if let Some(mut betas) = self.anthropic_betas {
57 betas.push(anthropic_beta);
58 self.anthropic_betas = Some(betas);
59 } else {
60 self.anthropic_betas = Some(vec![anthropic_beta]);
61 }
62 self
63 }
64
65 pub fn build(self) -> Client {
66 Client::new(
67 self.api_key,
68 self.base_url,
69 self.anthropic_betas,
70 self.anthropic_version,
71 )
72 }
73}
74
75#[derive(Clone)]
76pub struct Client {
77 base_url: String,
78 http_client: reqwest::Client,
79}
80
81impl Client {
82 pub fn new(api_key: &str, base_url: &str, betas: Option<Vec<&str>>, version: &str) -> Self {
90 Self {
91 base_url: base_url.to_string(),
92 http_client: reqwest::Client::builder()
93 .default_headers({
94 let mut headers = reqwest::header::HeaderMap::new();
95 headers.insert("x-api-key", api_key.parse().expect("API key should parse"));
96 headers.insert(
97 "anthropic-version",
98 version.parse().expect("Anthropic version should parse"),
99 );
100 if let Some(betas) = betas {
101 headers.insert(
102 "anthropic-beta",
103 betas
104 .join(",")
105 .parse()
106 .expect("Anthropic betas should parse"),
107 );
108 }
109 headers
110 })
111 .build()
112 .expect("Anthropic reqwest client should build"),
113 }
114 }
115
116 pub fn from_env() -> Self {
119 let api_key = std::env::var("ANTHROPIC_API_KEY").expect("ANTHROPIC_API_KEY not set");
120 ClientBuilder::new(&api_key).build()
121 }
122
123 pub fn post(&self, path: &str) -> reqwest::RequestBuilder {
124 let url = format!("{}/{}", self.base_url, path).replace("//", "/");
125 self.http_client.post(url)
126 }
127
128 pub fn completion_model(&self, model: &str) -> CompletionModel {
129 CompletionModel::new(self.clone(), model)
130 }
131
132 pub fn agent(&self, model: &str) -> AgentBuilder<CompletionModel> {
147 AgentBuilder::new(self.completion_model(model))
148 }
149
150 pub fn extractor<T: JsonSchema + for<'a> Deserialize<'a> + Serialize + Send + Sync>(
151 &self,
152 model: &str,
153 ) -> ExtractorBuilder<T, CompletionModel> {
154 ExtractorBuilder::new(self.completion_model(model))
155 }
156}