Skip to main content

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}