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}