Skip to main content

openrouter_rust/
models.rs

1use crate::{
2    client::OpenRouterClient,
3    error::{OpenRouterError, Result},
4};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Model {
10    pub id: String,
11    pub canonical_slug: String,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub hugging_face_id: Option<String>,
14    pub name: String,
15    pub created: f64,
16    pub description: String,
17    pub pricing: PublicPricing,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub context_length: Option<f64>,
20    pub architecture: ModelArchitecture,
21    pub top_provider: TopProviderInfo,
22    pub per_request_limits: PerRequestLimits,
23    pub supported_parameters: Vec<String>,
24    pub default_parameters: DefaultParameters,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub expiration_date: Option<String>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct PublicPricing {
31    pub prompt: Value,
32    pub completion: Value,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub request: Option<Value>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub image: Option<Value>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub image_token: Option<Value>,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub image_output: Option<Value>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub audio: Option<Value>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub audio_output: Option<Value>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub input_audio_cache: Option<Value>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub web_search: Option<Value>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub internal_reasoning: Option<Value>,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub input_cache_read: Option<Value>,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub input_cache_write: Option<Value>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub discount: Option<f64>,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct ModelArchitecture {
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub tokenizer: Option<String>,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub instruct_type: Option<String>,
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub modality: Option<String>,
67    pub input_modalities: Vec<String>,
68    pub output_modalities: Vec<String>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct TopProviderInfo {
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub context_length: Option<f64>,
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub max_completion_tokens: Option<f64>,
77    pub is_moderated: bool,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct PerRequestLimits {
82    pub prompt_tokens: f64,
83    pub completion_tokens: f64,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct DefaultParameters {
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub temperature: Option<f64>,
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub top_p: Option<f64>,
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub frequency_penalty: Option<f64>,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct ModelsResponse {
98    pub data: Vec<Model>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct ModelsCountResponse {
103    pub data: ModelsCountData,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct ModelsCountData {
108    pub count: f64,
109}
110
111#[derive(Debug, Clone, Default)]
112pub struct ListModelsParams {
113    pub category: Option<String>,
114    pub supported_parameters: Option<String>,
115    pub use_rss: Option<String>,
116    pub use_rss_chat_links: Option<String>,
117}
118
119
120
121impl OpenRouterClient {
122    pub async fn list_models(&self, params: Option<ListModelsParams>) -> Result<ModelsResponse> {
123        let mut url = format!("{}/models", self.base_url);
124        
125        if let Some(p) = params {
126            let mut query_parts = Vec::new();
127            if let Some(cat) = p.category {
128                query_parts.push(format!("category={}", cat));
129            }
130            if let Some(sup) = p.supported_parameters {
131                query_parts.push(format!("supported_parameters={}", sup));
132            }
133            if let Some(rss) = p.use_rss {
134                query_parts.push(format!("use_rss={}", rss));
135            }
136            if let Some(links) = p.use_rss_chat_links {
137                query_parts.push(format!("use_rss_chat_links={}", links));
138            }
139            if !query_parts.is_empty() {
140                url = format!("{}?{}", url, query_parts.join("&"));
141            }
142        }
143
144        let headers = self.build_headers()?;
145
146        let response = self
147            .client
148            .get(&url)
149            .headers(headers)
150            .send()
151            .await
152            .map_err(OpenRouterError::HttpError)?;
153
154        let status = response.status();
155        
156        if !status.is_success() {
157            let error_text = response.text().await.unwrap_or_default();
158            return Err(OpenRouterError::ApiError {
159                code: status.as_u16(),
160                message: error_text,
161            });
162        }
163
164        let result = response
165            .json::<ModelsResponse>()
166            .await
167            .map_err(OpenRouterError::HttpError)?;
168
169        Ok(result)
170    }
171
172    pub async fn get_models_count(&self) -> Result<ModelsCountResponse> {
173        let url = format!("{}/models/count", self.base_url);
174        let headers = self.build_headers()?;
175
176        let response = self
177            .client
178            .get(&url)
179            .headers(headers)
180            .send()
181            .await
182            .map_err(OpenRouterError::HttpError)?;
183
184        let status = response.status();
185        
186        if !status.is_success() {
187            let error_text = response.text().await.unwrap_or_default();
188            return Err(OpenRouterError::ApiError {
189                code: status.as_u16(),
190                message: error_text,
191            });
192        }
193
194        let result = response
195            .json::<ModelsCountResponse>()
196            .await
197            .map_err(OpenRouterError::HttpError)?;
198
199        Ok(result)
200    }
201
202    pub async fn list_models_user(&self) -> Result<ModelsResponse> {
203        let url = format!("{}/models/user", self.base_url);
204        let headers = self.build_headers()?;
205
206        let response = self
207            .client
208            .get(&url)
209            .headers(headers)
210            .send()
211            .await
212            .map_err(OpenRouterError::HttpError)?;
213
214        let status = response.status();
215        
216        if !status.is_success() {
217            let error_text = response.text().await.unwrap_or_default();
218            return Err(OpenRouterError::ApiError {
219                code: status.as_u16(),
220                message: error_text,
221            });
222        }
223
224        let result = response
225            .json::<ModelsResponse>()
226            .await
227            .map_err(OpenRouterError::HttpError)?;
228
229        Ok(result)
230    }
231}