anthropic_api/
models.rs

1//! # Models API
2//!
3//! This module provides a Rust interface to Anthropic's Models API, which allows you to
4//! [list available models](https://docs.anthropic.com/en/api/models-list) and [get information about specific models](https://docs.anthropic.com/en/api/models-get).
5//!
6//! ## Key Features
7//!
8//! - List all available models with pagination support
9//! - Get detailed information about a specific model
10//! - Resolve model aliases to model IDs
11//!
12//! ## Basic Usage
13//!
14//! ```no_run
15//! use anthropic_api::{models::*, Credentials};
16//!
17//! #[tokio::main]
18//! async fn main() {
19//!     let credentials = Credentials::from_env();
20//!
21//!     // List available models
22//!     let models = ModelList::builder()
23//!         .credentials(credentials.clone())
24//!         .create()
25//!         .await
26//!         .unwrap();
27//!
28//!     println!("Available models: {:?}", models.data);
29//!
30//!     // Get a specific model
31//!     let model = Model::builder("claude-3-7-sonnet-20250219")
32//!         .credentials(credentials)
33//!         .create()
34//!         .await
35//!         .unwrap();
36//!
37//!     println!("Model details: {:?}", model);
38//! }
39//! ```
40
41use crate::{anthropic_request_json, ApiResponseOrError, Credentials};
42use derive_builder::Builder;
43use reqwest::Method;
44use serde::{Deserialize, Serialize};
45
46/// A model available through the Anthropic API.
47#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
48pub struct Model {
49    /// Unique model identifier
50    pub id: String,
51    /// A human-readable name for the model
52    pub display_name: String,
53    /// RFC 3339 datetime string representing the time at which the model was released
54    pub created_at: String,
55    /// Object type (always "model" for Models)
56    #[serde(rename = "type")]
57    pub model_type: String,
58}
59
60/// Response from the List Models API.
61#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
62pub struct ModelList {
63    /// List of available models
64    pub data: Vec<Model>,
65    /// First ID in the data list (for pagination)
66    pub first_id: Option<String>,
67    /// Last ID in the data list (for pagination)
68    pub last_id: Option<String>,
69    /// Indicates if there are more results in the requested page direction
70    pub has_more: bool,
71}
72
73/// Request parameters for listing models.
74#[derive(Serialize, Builder, Debug, Clone)]
75#[builder(derive(Clone, Debug, PartialEq))]
76#[builder(pattern = "owned")]
77#[builder(name = "ModelListBuilder")]
78#[builder(setter(strip_option, into))]
79pub struct ModelListRequest {
80    /// ID of the object to use as a cursor for pagination (previous page)
81    #[builder(default)]
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub before_id: Option<String>,
84
85    /// ID of the object to use as a cursor for pagination (next page)
86    #[builder(default)]
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub after_id: Option<String>,
89
90    /// Number of items to return per page (1-1000)
91    #[builder(default)]
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub limit: Option<u32>,
94
95    /// Credentials for authentication (not serialized)
96    #[serde(skip_serializing)]
97    #[builder(default)]
98    pub credentials: Option<Credentials>,
99}
100
101/// Request parameters for getting a specific model.
102#[derive(Serialize, Builder, Debug, Clone)]
103#[builder(derive(Clone, Debug, PartialEq))]
104#[builder(pattern = "owned")]
105#[builder(name = "ModelBuilder")]
106#[builder(setter(strip_option, into))]
107pub struct ModelRequest {
108    /// Model identifier or alias
109    pub model_id: String,
110
111    /// Credentials for authentication (not serialized)
112    #[serde(skip_serializing)]
113    #[builder(default)]
114    pub credentials: Option<Credentials>,
115}
116
117impl ModelList {
118    /// Creates a builder for listing models.
119    ///
120    /// # Example
121    ///
122    /// ```no_run
123    /// # use anthropic_api::{models::*, Credentials};
124    /// # #[tokio::main]
125    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
126    /// let credentials = Credentials::from_env();
127    ///
128    /// let models = ModelList::builder()
129    ///     .credentials(credentials)
130    ///     .limit(10u32)
131    ///     .create()
132    ///     .await?;
133    /// # Ok(())
134    /// # }
135    /// ```
136    pub fn builder() -> ModelListBuilder {
137        ModelListBuilder::create_empty()
138    }
139
140    /// Lists available models with the given request parameters.
141    ///
142    /// # Example
143    ///
144    /// ```no_run
145    /// # use anthropic_api::{models::*, Credentials};
146    /// # #[tokio::main]
147    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
148    /// let credentials = Credentials::from_env();
149    /// let request = ModelListRequest {
150    ///     before_id: None,
151    ///     after_id: None,
152    ///     limit: Some(20),
153    ///     credentials: Some(credentials),
154    /// };
155    ///
156    /// let models = ModelList::create(request).await?;
157    /// # Ok(())
158    /// # }
159    /// ```
160    pub async fn create(request: ModelListRequest) -> ApiResponseOrError<Self> {
161        let credentials_opt = request.credentials.clone();
162
163        // Build query parameters
164        let mut query_params = Vec::new();
165        if let Some(before_id) = &request.before_id {
166            query_params.push(("before_id", before_id.clone()));
167        }
168        if let Some(after_id) = &request.after_id {
169            query_params.push(("after_id", after_id.clone()));
170        }
171        if let Some(limit) = request.limit {
172            query_params.push(("limit", limit.to_string()));
173        }
174
175        anthropic_request_json(
176            Method::GET,
177            "models",
178            |r| r.query(&query_params),
179            credentials_opt,
180        )
181        .await
182    }
183}
184
185impl Model {
186    /// Creates a builder for getting a specific model.
187    ///
188    /// # Example
189    ///
190    /// ```no_run
191    /// # use anthropic_api::{models::*, Credentials};
192    /// # #[tokio::main]
193    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
194    /// let credentials = Credentials::from_env();
195    ///
196    /// let model = Model::builder("claude-3-7-sonnet-20250219")
197    ///     .credentials(credentials)
198    ///     .create()
199    ///     .await?;
200    /// # Ok(())
201    /// # }
202    /// ```
203    pub fn builder(model_id: impl Into<String>) -> ModelBuilder {
204        ModelBuilder::create_empty().model_id(model_id)
205    }
206
207    /// Gets information about a specific model.
208    ///
209    /// # Example
210    ///
211    /// ```no_run
212    /// # use anthropic_api::{models::*, Credentials};
213    /// # #[tokio::main]
214    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
215    /// let credentials = Credentials::from_env();
216    /// let request = ModelRequest {
217    ///     model_id: "claude-3-7-sonnet-20250219".to_string(),
218    ///     credentials: Some(credentials),
219    /// };
220    ///
221    /// let model = Model::create(request).await?;
222    /// # Ok(())
223    /// # }
224    /// ```
225    pub async fn create(request: ModelRequest) -> ApiResponseOrError<Self> {
226        let credentials_opt = request.credentials.clone();
227        let route = format!("models/{}", request.model_id);
228
229        anthropic_request_json(Method::GET, &route, |r| r, credentials_opt).await
230    }
231}
232
233// Builder convenience methods
234impl ModelListBuilder {
235    /// Creates a new model list request and returns the response.
236    ///
237    /// This is a convenience method that builds the request from the builder
238    /// and sends it to the Models API.
239    ///
240    /// # Example
241    ///
242    /// ```no_run
243    /// # use anthropic_api::{models::*, Credentials};
244    /// # #[tokio::main]
245    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
246    /// let credentials = Credentials::from_env();
247    ///
248    /// let models = ModelList::builder()
249    ///     .credentials(credentials)
250    ///     .limit(10u32)
251    ///     .create()
252    ///     .await?;
253    /// # Ok(())
254    /// # }
255    /// ```
256    pub async fn create(self) -> ApiResponseOrError<ModelList> {
257        let request = self.build().unwrap();
258        ModelList::create(request).await
259    }
260}
261
262impl ModelBuilder {
263    /// Creates a new model request and returns the response.
264    ///
265    /// This is a convenience method that builds the request from the builder
266    /// and sends it to the Models API.
267    ///
268    /// # Example
269    ///
270    /// ```no_run
271    /// # use anthropic_api::{models::*, Credentials};
272    /// # #[tokio::main]
273    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
274    /// let credentials = Credentials::from_env();
275    ///
276    /// let model = Model::builder("claude-3-7-sonnet-20250219")
277    ///     .credentials(credentials)
278    ///     .create()
279    ///     .await?;
280    /// # Ok(())
281    /// # }
282    /// ```
283    pub async fn create(self) -> ApiResponseOrError<Model> {
284        let request = self.build().unwrap();
285        Model::create(request).await
286    }
287}
288
289#[cfg(test)]
290mod tests {
291    use super::*;
292    use crate::Credentials;
293
294    #[tokio::test]
295    async fn test_list_models() {
296        let credentials = Credentials::from_env();
297
298        let models = ModelList::builder()
299            .credentials(credentials)
300            .create()
301            .await
302            .unwrap();
303
304        assert!(!models.data.is_empty());
305    }
306
307    #[tokio::test]
308    async fn test_get_model() {
309        let credentials = Credentials::from_env();
310
311        // First get a model ID from the list
312        let models = ModelList::builder()
313            .credentials(credentials.clone())
314            .create()
315            .await
316            .unwrap();
317
318        let model_id = &models.data[0].id;
319
320        // Then get that specific model
321        let model = Model::builder(model_id)
322            .credentials(credentials)
323            .create()
324            .await
325            .unwrap();
326
327        assert_eq!(model.id, *model_id);
328    }
329}