Skip to main content

agentik_sdk/
client.rs

1use crate::config::ClientConfig;
2use crate::http::HttpClient;
3use crate::resources::{BatchesResource, FilesResource, MessagesResource, ModelsResource};
4use crate::types::errors::Result;
5use crate::utils::init_logging;
6
7/// Main Anthropic API client
8pub struct Anthropic {
9    config: ClientConfig,
10    http_client: HttpClient,
11}
12
13impl Anthropic {
14    /// Create a new Anthropic client with the provided API key
15    pub fn new(api_key: impl Into<String>) -> Result<Self> {
16        let config = ClientConfig::new(api_key);
17        let http_client = HttpClient::new(config.clone())?;
18
19        // Initialize logging
20        init_logging(&config.log_level);
21
22        Ok(Self {
23            config,
24            http_client,
25        })
26    }
27
28    /// Create a new Anthropic client from environment variables
29    pub fn from_env() -> Result<Self> {
30        let config = ClientConfig::from_env()?;
31        let http_client = HttpClient::new(config.clone())?;
32
33        // Initialize logging
34        init_logging(&config.log_level);
35
36        Ok(Self {
37            config,
38            http_client,
39        })
40    }
41
42    /// Create a new Anthropic client with custom configuration
43    pub fn with_config(config: ClientConfig) -> Result<Self> {
44        let http_client = HttpClient::new(config.clone())?;
45
46        // Initialize logging
47        init_logging(&config.log_level);
48
49        Ok(Self {
50            config,
51            http_client,
52        })
53    }
54
55    /// Get the current configuration
56    pub fn config(&self) -> &ClientConfig {
57        &self.config
58    }
59
60    /// Get a reference to the HTTP client for internal use
61    pub(crate) fn http_client(&self) -> &HttpClient {
62        &self.http_client
63    }
64
65    /// Test the connection by making a simple API call
66    pub async fn test_connection(&self) -> Result<()> {
67        // This will be implemented once we have the messages API
68        // For now, we'll just validate the configuration
69        self.config.validate()?;
70        tracing::info!("Anthropic client initialized successfully");
71        Ok(())
72    }
73
74    /// Access to the Messages API
75    ///
76    /// # Example
77    ///
78    /// ```rust,no_run
79    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
80    /// use agentik_sdk::{Anthropic, types::MessageCreateBuilder};
81    ///
82    /// let client = Anthropic::from_env()?;
83    ///
84    /// let message = client.messages().create(
85    ///     MessageCreateBuilder::new("claude-3-5-sonnet-latest", 1024)
86    ///         .user("Hello, Claude!")
87    ///         .build()
88    /// ).await?;
89    ///
90    /// println!("Claude responded: {:?}", message.content);
91    /// # Ok(())
92    /// # }
93    /// ```
94    pub fn messages(&self) -> MessagesResource<'_> {
95        MessagesResource::new(self)
96    }
97
98    /// Access to the Message Batches API (Beta)
99    ///
100    /// # Example
101    ///
102    /// ```rust,no_run
103    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
104    /// use agentik_sdk::{Anthropic, types::{BatchRequest, BatchCreateParams}};
105    ///
106    /// let client = Anthropic::from_env()?;
107    ///
108    /// let requests = vec![
109    ///     BatchRequest::new("req1", "claude-3-5-sonnet-latest", 1024)
110    ///         .user("Hello, world!")
111    ///         .build(),
112    /// ];
113    ///
114    /// let batch = client.batches().create(
115    ///     BatchCreateParams::new(requests)
116    /// ).await?;
117    ///
118    /// println!("Created batch: {}", batch.id);
119    /// # Ok(())
120    /// # }
121    /// ```
122    pub fn batches(&self) -> BatchesResource {
123        BatchesResource::new(std::sync::Arc::new(self.http_client.clone()))
124    }
125
126    /// Access to the Files API (Beta)
127    ///
128    /// # Example
129    ///
130    /// ```rust,no_run
131    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
132    /// use agentik_sdk::{Anthropic, FileUploadParams, FilePurpose};
133    ///
134    /// let client = Anthropic::from_env()?;
135    ///
136    /// let upload_params = FileUploadParams::new(
137    ///     std::fs::read("document.pdf")?,
138    ///     "document.pdf",
139    ///     "application/pdf",
140    ///     FilePurpose::Document,
141    /// );
142    ///
143    /// let file_object = client.files().upload(upload_params).await?;
144    /// println!("Uploaded file: {}", file_object.id);
145    /// # Ok(())
146    /// # }
147    /// ```
148    pub fn files(&self) -> FilesResource {
149        FilesResource::new(std::sync::Arc::new(self.http_client.clone()))
150    }
151
152    /// Access to the Models API
153    ///
154    /// # Example
155    ///
156    /// ```rust,no_run
157    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
158    /// use agentik_sdk::{Anthropic, ModelListParams, ModelRequirements, ModelCapability};
159    ///
160    /// let client = Anthropic::from_env()?;
161    ///
162    /// // List all models
163    /// let models = client.models().list(None).await?;
164    /// println!("Found {} models", models.data.len());
165    ///
166    /// // Get specific model
167    /// let model = client.models().get("claude-3-5-sonnet-latest").await?;
168    /// println!("Model: {} ({})", model.display_name, model.id);
169    ///
170    /// // Find best model for requirements
171    /// let requirements = ModelRequirements::new()
172    ///     .require_vision()
173    ///     .min_context_length(100000);
174    /// let best_model = client.models().find_best_model(&requirements).await?;
175    ///
176    /// // Compare models
177    /// let comparison = client.models().compare_models(&[
178    ///     "claude-3-5-sonnet-latest",
179    ///     "claude-3-5-haiku-latest"
180    /// ]).await?;
181    ///
182    /// // Estimate costs
183    /// let cost = client.models().estimate_cost("claude-3-5-sonnet-latest", 1000, 500).await?;
184    /// println!("Estimated cost: ${:.4}", cost.final_cost_usd);
185    /// # Ok(())
186    /// # }
187    /// ```
188    pub fn models(&self) -> ModelsResource<'_> {
189        ModelsResource::new(self)
190    }
191}
192
193impl std::fmt::Debug for Anthropic {
194    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195        f.debug_struct("Anthropic")
196            .field("base_url", &self.config.base_url)
197            .field("timeout", &self.config.timeout)
198            .field("max_retries", &self.config.max_retries)
199            .field("log_level", &self.config.log_level)
200            .finish_non_exhaustive()
201    }
202}
203