openrouter_rs/types/mod.rs
1//! # Core Types and Data Structures
2//!
3//! This module contains all the core types, enums, and data structures used
4//! throughout the OpenRouter SDK. These types provide type-safe representations
5//! of API requests, responses, and configuration options.
6//!
7//! ## 📋 Type Categories
8//!
9//! ### Request/Response Types ([`completion`])
10//! - **Chat Completions**: Modern conversational AI request/response structures
11//! - **Text Completions**: Legacy prompt-based completion types
12//! - **Streaming**: Types for handling real-time response streams
13//! - **Reasoning**: Advanced reasoning and chain-of-thought structures
14//!
15//! ### Provider Information ([`provider`])
16//! - **Model Metadata**: Provider-specific model information
17//! - **Capabilities**: Model feature and parameter support
18//! - **Pricing**: Cost information and token usage
19//!
20//! ### Response Formatting ([`response_format`])
21//! - **JSON Schema**: Structured output formatting
22//! - **Content Types**: Different response content formats
23//! - **Validation**: Response format validation rules
24//!
25//! ### Tool Support ([`tool`])
26//! - **Tool Definitions**: Function calling definitions and schemas
27//! - **Tool Choice**: Control over tool usage behavior
28//! - **Function Parameters**: JSON Schema for tool parameters
29//!
30//! ### Typed Tools ([`typed_tool`])
31//! - **TypedTool Trait**: Strongly-typed tool definitions using Rust structs
32//! - **Automatic Schema Generation**: JSON Schema generation from Rust types
33//! - **Type Safety**: Compile-time validation of tool parameters
34//!
35//! ## 🎯 Core Enums
36//!
37//! ### Role
38//! Defines the role of a message in a conversation:
39//!
40//! ```rust
41//! use openrouter_rs::types::Role;
42//!
43//! let system_role = Role::System; // System instructions
44//! let user_role = Role::User; // User input
45//! let assistant_role = Role::Assistant; // AI response
46//! let tool_role = Role::Tool; // Tool/function results
47//! let developer_role = Role::Developer; // Developer context
48//! ```
49//!
50//! ### Effort
51//! Specifies reasoning effort levels for chain-of-thought models:
52//!
53//! ```rust
54//! use openrouter_rs::types::Effort;
55//!
56//! let xhigh_effort = Effort::Xhigh; // Extra high reasoning depth
57//! let max_effort = Effort::Max; // Maximum reasoning depth
58//! let high_effort = Effort::High; // High reasoning depth
59//! let medium_effort = Effort::Medium; // Balanced reasoning
60//! let low_effort = Effort::Low; // Quick reasoning
61//! let minimal_effort = Effort::Minimal; // Minimal reasoning
62//! let no_effort = Effort::None; // Disable reasoning
63//! ```
64//!
65//! ## 🔧 Configuration Types
66//!
67//! ### ReasoningConfig
68//! Configuration for advanced reasoning capabilities:
69//!
70//! ```rust
71//! use openrouter_rs::types::{ReasoningConfig, Effort};
72//!
73//! let reasoning = ReasoningConfig::enabled()
74//! .effort(Effort::High)
75//! .max_tokens(1000)
76//! .exclude(false);
77//! ```
78//!
79//! ### ProviderPreferences
80//! Specify preferences for model provider selection:
81//!
82//! ```rust
83//! use openrouter_rs::types::{DataCollectionPolicy, ProviderPreferences};
84//!
85//! let mut prefs = ProviderPreferences::default();
86//! prefs.allow_fallbacks = Some(true);
87//! prefs.require_parameters = Some(true);
88//! prefs.data_collection = Some(DataCollectionPolicy::Deny);
89//! ```
90//!
91//! ## 📊 Model Categories
92//!
93//! Categories for filtering and organizing models:
94//!
95//! ```rust
96//! use openrouter_rs::types::ModelCategory;
97//!
98//! // Filter models by use case
99//! let programming_models = ModelCategory::Programming;
100//! let roleplay_models = ModelCategory::Roleplay;
101//! let science_models = ModelCategory::Science;
102//! ```
103//!
104//! ## 🏗️ Builder Patterns
105//!
106//! Most complex types support the builder pattern for ergonomic construction:
107//!
108//! ```rust
109//! use openrouter_rs::types::{ReasoningConfig, Effort};
110//!
111//! let config = ReasoningConfig::enabled()
112//! .effort(Effort::High)
113//! .max_tokens(2000)
114//! .exclude(false);
115//! ```
116//!
117//! ## 🔄 Serialization Support
118//!
119//! All types implement `Serialize` and `Deserialize` for JSON compatibility:
120//!
121//! ```rust
122//! use openrouter_rs::types::Role;
123//! use serde_json;
124//!
125//! let role = Role::Assistant;
126//! let json = serde_json::to_string(&role)?;
127//! let parsed: Role = serde_json::from_str(&json)?;
128//! # Ok::<(), Box<dyn std::error::Error>>(())
129//! ```
130//!
131//! ## 🎨 Display Formatting
132//!
133//! Common enums implement `Display` for human-readable output:
134//!
135//! ```rust
136//! use openrouter_rs::types::{Role, Effort};
137//!
138//! println!("Role: {}", Role::User); // "user"
139//! println!("Effort: {}", Effort::High); // "high"
140//! ```
141
142pub mod completion;
143pub mod pagination;
144pub mod provider;
145pub mod response_format;
146pub mod stream;
147pub mod tool;
148pub mod typed_tool;
149
150use std::fmt::Display;
151
152use serde::{Deserialize, Deserializer, Serialize, Serializer};
153
154pub use {
155 completion::*, pagination::*, provider::*, response_format::*, stream::*, tool::*,
156 typed_tool::*,
157};
158
159#[derive(Serialize, Deserialize, Debug)]
160#[non_exhaustive]
161pub struct ApiResponse<T> {
162 pub data: T,
163}
164
165/// Opt-in level for OpenRouter's experimental response metadata header.
166#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
167#[non_exhaustive]
168#[serde(rename_all = "lowercase")]
169pub enum OpenRouterExperimentalMetadata {
170 Disabled,
171 Enabled,
172}
173
174impl OpenRouterExperimentalMetadata {
175 pub(crate) fn as_header_value(self) -> &'static str {
176 match self {
177 Self::Disabled => "disabled",
178 Self::Enabled => "enabled",
179 }
180 }
181}
182
183/// Message role in a conversation
184///
185/// Specifies who or what is sending a message in a chat completion.
186/// Different roles have different behaviors and restrictions.
187///
188/// # Examples
189///
190/// ```rust
191/// use openrouter_rs::types::Role;
192/// use openrouter_rs::api::chat::Message;
193///
194/// let system_msg = Message::new(Role::System, "You are a helpful assistant");
195/// let user_msg = Message::new(Role::User, "Hello, world!");
196/// let assistant_msg = Message::new(Role::Assistant, "Hello! How can I help?");
197/// ```
198#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
199#[non_exhaustive]
200#[serde(rename_all = "lowercase")]
201pub enum Role {
202 /// System instructions that guide the AI's behavior
203 System,
204 /// Developer/admin context (provider-specific)
205 Developer,
206 /// User input or questions
207 User,
208 /// AI assistant responses
209 Assistant,
210 /// Results from tool/function calls
211 Tool,
212}
213
214impl Display for Role {
215 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216 match self {
217 Role::System => write!(f, "system"),
218 Role::Developer => write!(f, "developer"),
219 Role::User => write!(f, "user"),
220 Role::Assistant => write!(f, "assistant"),
221 Role::Tool => write!(f, "tool"),
222 }
223 }
224}
225
226/// Reasoning effort level for chain-of-thought models
227///
228/// Controls how much computational effort the model should put into
229/// reasoning through problems. Higher effort levels typically produce
230/// more detailed reasoning but take longer and cost more.
231///
232/// # Examples
233///
234/// ```rust
235/// use openrouter_rs::types::Effort;
236/// use openrouter_rs::api::chat::{ChatCompletionRequest, Message};
237/// use openrouter_rs::types::Role;
238///
239/// let request = ChatCompletionRequest::builder()
240/// .model("deepseek/deepseek-r1")
241/// .messages(vec![Message::new(Role::User, "Solve 2x + 5 = 13")])
242/// .reasoning_effort(Effort::High)
243/// .build()?;
244/// # Ok::<(), Box<dyn std::error::Error>>(())
245/// ```
246#[derive(Debug, Clone, PartialEq, Eq)]
247#[non_exhaustive]
248pub enum Effort {
249 /// Extra high reasoning depth and thoroughness
250 Xhigh,
251 /// Maximum reasoning depth and thoroughness
252 Max,
253 /// High reasoning depth and thoroughness
254 High,
255 /// Balanced reasoning effort
256 Medium,
257 /// Quick, lightweight reasoning
258 Low,
259 /// Minimal reasoning effort
260 Minimal,
261 /// Disable reasoning effort
262 None,
263 /// Provider-defined reasoning effort not yet known by this SDK.
264 Other(String),
265}
266
267impl Effort {
268 pub fn as_str(&self) -> &str {
269 match self {
270 Effort::Xhigh => "xhigh",
271 Effort::Max => "max",
272 Effort::High => "high",
273 Effort::Medium => "medium",
274 Effort::Low => "low",
275 Effort::Minimal => "minimal",
276 Effort::None => "none",
277 Effort::Other(value) => value.as_str(),
278 }
279 }
280}
281
282impl Serialize for Effort {
283 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
284 where
285 S: Serializer,
286 {
287 serializer.serialize_str(self.as_str())
288 }
289}
290
291impl<'de> Deserialize<'de> for Effort {
292 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
293 where
294 D: Deserializer<'de>,
295 {
296 let value = String::deserialize(deserializer)?;
297 Ok(match value.as_str() {
298 "xhigh" => Effort::Xhigh,
299 "max" => Effort::Max,
300 "high" => Effort::High,
301 "medium" => Effort::Medium,
302 "low" => Effort::Low,
303 "minimal" => Effort::Minimal,
304 "none" => Effort::None,
305 _ => Effort::Other(value),
306 })
307 }
308}
309
310impl Display for Effort {
311 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 f.write_str(self.as_str())
313 }
314}
315
316#[derive(Serialize, Deserialize, Debug, Clone)]
317#[non_exhaustive]
318pub struct ReasoningConfig {
319 #[serde(skip_serializing_if = "Option::is_none")]
320 pub effort: Option<Effort>,
321 #[serde(skip_serializing_if = "Option::is_none")]
322 pub max_tokens: Option<u32>,
323 #[serde(skip_serializing_if = "Option::is_none")]
324 pub exclude: Option<bool>,
325 #[serde(skip_serializing_if = "Option::is_none")]
326 pub enabled: Option<bool>,
327}
328
329impl ReasoningConfig {
330 /// Create a new ReasoningConfig with default enabled settings (medium effort)
331 pub fn enabled() -> Self {
332 Self {
333 effort: None,
334 max_tokens: None,
335 exclude: None,
336 enabled: Some(true),
337 }
338 }
339
340 /// Create a ReasoningConfig with specific effort level
341 pub fn with_effort(effort: Effort) -> Self {
342 Self {
343 effort: Some(effort),
344 max_tokens: None,
345 exclude: None,
346 enabled: None,
347 }
348 }
349
350 /// Create a ReasoningConfig with max tokens limit
351 pub fn with_max_tokens(max_tokens: u32) -> Self {
352 Self {
353 effort: None,
354 max_tokens: Some(max_tokens),
355 exclude: None,
356 enabled: None,
357 }
358 }
359
360 /// Create a ReasoningConfig that excludes reasoning from response
361 pub fn excluded() -> Self {
362 Self {
363 effort: None,
364 max_tokens: None,
365 exclude: Some(true),
366 enabled: None,
367 }
368 }
369
370 /// Set effort level
371 pub fn effort(mut self, effort: Effort) -> Self {
372 self.effort = Some(effort);
373 self
374 }
375
376 /// Set max tokens
377 pub fn max_tokens(mut self, max_tokens: u32) -> Self {
378 self.max_tokens = Some(max_tokens);
379 self
380 }
381
382 /// Set exclude flag
383 pub fn exclude(mut self, exclude: bool) -> Self {
384 self.exclude = Some(exclude);
385 self
386 }
387}
388
389#[derive(Serialize, Deserialize, Debug, Clone)]
390#[non_exhaustive]
391#[serde(rename_all = "lowercase")]
392pub enum ModelCategory {
393 Roleplay,
394 Programming,
395 Marketing,
396 #[serde(rename = "marketing/seo")]
397 MarketingSeo,
398 Technology,
399 Science,
400 Translation,
401 Legal,
402 Finance,
403 Health,
404 Trivia,
405 Academia,
406}
407
408impl Display for ModelCategory {
409 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
410 match self {
411 ModelCategory::Roleplay => write!(f, "roleplay"),
412 ModelCategory::Programming => write!(f, "programming"),
413 ModelCategory::Marketing => write!(f, "marketing"),
414 ModelCategory::MarketingSeo => write!(f, "marketing/seo"),
415 ModelCategory::Technology => write!(f, "technology"),
416 ModelCategory::Science => write!(f, "science"),
417 ModelCategory::Translation => write!(f, "translation"),
418 ModelCategory::Legal => write!(f, "legal"),
419 ModelCategory::Finance => write!(f, "finance"),
420 ModelCategory::Health => write!(f, "health"),
421 ModelCategory::Trivia => write!(f, "trivia"),
422 ModelCategory::Academia => write!(f, "academia"),
423 }
424 }
425}
426
427impl ModelCategory {
428 pub fn all() -> Vec<ModelCategory> {
429 vec![
430 ModelCategory::Roleplay,
431 ModelCategory::Programming,
432 ModelCategory::Marketing,
433 ModelCategory::MarketingSeo,
434 ModelCategory::Technology,
435 ModelCategory::Science,
436 ModelCategory::Translation,
437 ModelCategory::Legal,
438 ModelCategory::Finance,
439 ModelCategory::Health,
440 ModelCategory::Trivia,
441 ModelCategory::Academia,
442 ]
443 }
444}
445
446#[derive(Serialize, Deserialize, Debug, Clone)]
447#[non_exhaustive]
448#[serde(rename_all = "snake_case")]
449pub enum SupportedParameters {
450 Tools,
451 Temperature,
452 TopP,
453 TopK,
454 MinP,
455 TopA,
456 FrequencyPenalty,
457 PresencePenalty,
458 RepetitionPenalty,
459 MaxTokens,
460 LogitBias,
461 Logprobs,
462 TopLogprobs,
463 Seed,
464 ResponseFormat,
465 StructuredOutputs,
466 Stop,
467 IncludeReasoning,
468 Reasoning,
469 WebSearchOptions,
470}
471
472impl Display for SupportedParameters {
473 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
474 match self {
475 SupportedParameters::Tools => write!(f, "tools"),
476 SupportedParameters::Temperature => write!(f, "temperature"),
477 SupportedParameters::TopP => write!(f, "top_p"),
478 SupportedParameters::TopK => write!(f, "top_k"),
479 SupportedParameters::MinP => write!(f, "min_p"),
480 SupportedParameters::TopA => write!(f, "top_a"),
481 SupportedParameters::FrequencyPenalty => write!(f, "frequency_penalty"),
482 SupportedParameters::PresencePenalty => write!(f, "presence_penalty"),
483 SupportedParameters::RepetitionPenalty => write!(f, "repetition_penalty"),
484 SupportedParameters::MaxTokens => write!(f, "max_tokens"),
485 SupportedParameters::LogitBias => write!(f, "logit_bias"),
486 SupportedParameters::Logprobs => write!(f, "logprobs"),
487 SupportedParameters::TopLogprobs => write!(f, "top_logprobs"),
488 SupportedParameters::Seed => write!(f, "seed"),
489 SupportedParameters::ResponseFormat => write!(f, "response_format"),
490 SupportedParameters::StructuredOutputs => write!(f, "structured_outputs"),
491 SupportedParameters::Stop => write!(f, "stop"),
492 SupportedParameters::IncludeReasoning => write!(f, "include_reasoning"),
493 SupportedParameters::Reasoning => write!(f, "reasoning"),
494 SupportedParameters::WebSearchOptions => write!(f, "web_search_options"),
495 }
496 }
497}
498
499impl SupportedParameters {
500 pub fn all() -> Vec<SupportedParameters> {
501 vec![
502 SupportedParameters::Tools,
503 SupportedParameters::Temperature,
504 SupportedParameters::TopP,
505 SupportedParameters::TopK,
506 SupportedParameters::MinP,
507 SupportedParameters::TopA,
508 SupportedParameters::FrequencyPenalty,
509 SupportedParameters::PresencePenalty,
510 SupportedParameters::RepetitionPenalty,
511 SupportedParameters::MaxTokens,
512 SupportedParameters::LogitBias,
513 SupportedParameters::Logprobs,
514 SupportedParameters::TopLogprobs,
515 SupportedParameters::Seed,
516 SupportedParameters::ResponseFormat,
517 SupportedParameters::StructuredOutputs,
518 SupportedParameters::Stop,
519 SupportedParameters::IncludeReasoning,
520 SupportedParameters::Reasoning,
521 SupportedParameters::WebSearchOptions,
522 ]
523 }
524}