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}