openrouter-rs 0.5.0

A type-safe OpenRouter Rust SDK
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
//! # Core Types and Data Structures
//!
//! This module contains all the core types, enums, and data structures used
//! throughout the OpenRouter SDK. These types provide type-safe representations
//! of API requests, responses, and configuration options.
//!
//! ## 📋 Type Categories
//!
//! ### Request/Response Types ([`completion`])
//! - **Chat Completions**: Modern conversational AI request/response structures
//! - **Text Completions**: Legacy prompt-based completion types
//! - **Streaming**: Types for handling real-time response streams
//! - **Reasoning**: Advanced reasoning and chain-of-thought structures
//!
//! ### Provider Information ([`provider`])
//! - **Model Metadata**: Provider-specific model information
//! - **Capabilities**: Model feature and parameter support
//! - **Pricing**: Cost information and token usage
//!
//! ### Response Formatting ([`response_format`])
//! - **JSON Schema**: Structured output formatting
//! - **Content Types**: Different response content formats
//! - **Validation**: Response format validation rules
//!
//! ### Tool Support ([`tool`])
//! - **Tool Definitions**: Function calling definitions and schemas
//! - **Tool Choice**: Control over tool usage behavior
//! - **Function Parameters**: JSON Schema for tool parameters
//!
//! ### Typed Tools ([`typed_tool`])
//! - **TypedTool Trait**: Strongly-typed tool definitions using Rust structs
//! - **Automatic Schema Generation**: JSON Schema generation from Rust types
//! - **Type Safety**: Compile-time validation of tool parameters
//!
//! ## 🎯 Core Enums
//!
//! ### Role
//! Defines the role of a message in a conversation:
//!
//! ```rust
//! use openrouter_rs::types::Role;
//!
//! let system_role = Role::System;    // System instructions
//! let user_role = Role::User;        // User input
//! let assistant_role = Role::Assistant; // AI response
//! let tool_role = Role::Tool;        // Tool/function results
//! let developer_role = Role::Developer; // Developer context
//! ```
//!
//! ### Effort
//! Specifies reasoning effort levels for chain-of-thought models:
//!
//! ```rust
//! use openrouter_rs::types::Effort;
//!
//! let high_effort = Effort::High;    // Maximum reasoning depth
//! let medium_effort = Effort::Medium; // Balanced reasoning
//! let low_effort = Effort::Low;      // Quick reasoning
//! ```
//!
//! ## 🔧 Configuration Types
//!
//! ### ReasoningConfig
//! Configuration for advanced reasoning capabilities:
//!
//! ```rust
//! use openrouter_rs::types::{ReasoningConfig, Effort};
//!
//! let reasoning = ReasoningConfig::builder()
//!     .enabled(true)
//!     .effort(Effort::High)
//!     .max_tokens(1000)
//!     .build()?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ### ProviderPreferences
//! Specify preferences for model provider selection:
//!
//! ```rust
//! use openrouter_rs::types::ProviderPreferences;
//!
//! let prefs = ProviderPreferences {
//!     allow_fallbacks: true,
//!     require_parameters: Some(vec!["tools".to_string()]),
//!     data_collection: Some("deny".to_string()),
//! };
//! ```
//!
//! ## 📊 Model Categories
//!
//! Categories for filtering and organizing models:
//!
//! ```rust
//! use openrouter_rs::types::ModelCategory;
//!
//! // Filter models by use case
//! let programming_models = ModelCategory::Programming;
//! let reasoning_models = ModelCategory::Reasoning;
//! let image_models = ModelCategory::Image;
//! ```
//!
//! ## 🏗️ Builder Patterns
//!
//! Most complex types support the builder pattern for ergonomic construction:
//!
//! ```rust
//! use openrouter_rs::types::{ReasoningConfig, Effort};
//!
//! let config = ReasoningConfig::builder()
//!     .enabled(true)
//!     .effort(Effort::High)
//!     .max_tokens(2000)
//!     .exclude(false)
//!     .build()?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ## 🔄 Serialization Support
//!
//! All types implement `Serialize` and `Deserialize` for JSON compatibility:
//!
//! ```rust
//! use openrouter_rs::types::Role;
//! use serde_json;
//!
//! let role = Role::Assistant;
//! let json = serde_json::to_string(&role)?;
//! let parsed: Role = serde_json::from_str(&json)?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ## 🎨 Display Formatting
//!
//! Common enums implement `Display` for human-readable output:
//!
//! ```rust
//! use openrouter_rs::types::{Role, Effort};
//!
//! println!("Role: {}", Role::User);        // "user"
//! println!("Effort: {}", Effort::High);    // "high"
//! ```

pub mod completion;
pub mod provider;
pub mod response_format;
pub mod stream;
pub mod tool;
pub mod typed_tool;

use std::fmt::Display;

use serde::{Deserialize, Serialize};

pub use {completion::*, provider::*, response_format::*, stream::*, tool::*, typed_tool::*};

#[derive(Serialize, Deserialize, Debug)]
pub struct ApiResponse<T> {
    pub data: T,
}

/// Message role in a conversation
///
/// Specifies who or what is sending a message in a chat completion.
/// Different roles have different behaviors and restrictions.
///
/// # Examples
///
/// ```rust
/// use openrouter_rs::types::Role;
/// use openrouter_rs::api::chat::Message;
///
/// let system_msg = Message::new(Role::System, "You are a helpful assistant");
/// let user_msg = Message::new(Role::User, "Hello, world!");
/// let assistant_msg = Message::new(Role::Assistant, "Hello! How can I help?");
/// ```
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Role {
    /// System instructions that guide the AI's behavior
    System,
    /// Developer/admin context (provider-specific)
    Developer,
    /// User input or questions
    User,
    /// AI assistant responses
    Assistant,
    /// Results from tool/function calls
    Tool,
}

impl Display for Role {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Role::System => write!(f, "system"),
            Role::Developer => write!(f, "developer"),
            Role::User => write!(f, "user"),
            Role::Assistant => write!(f, "assistant"),
            Role::Tool => write!(f, "tool"),
        }
    }
}

/// Reasoning effort level for chain-of-thought models
///
/// Controls how much computational effort the model should put into
/// reasoning through problems. Higher effort levels typically produce
/// more detailed reasoning but take longer and cost more.
///
/// # Examples
///
/// ```rust
/// use openrouter_rs::types::Effort;
/// use openrouter_rs::api::chat::ChatCompletionRequest;
///
/// let request = ChatCompletionRequest::builder()
///     .model("deepseek/deepseek-r1")
///     .reasoning_effort(Effort::High)  // Maximum reasoning depth
///     // ... other fields
///     .build()?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum Effort {
    /// Maximum reasoning depth and thoroughness
    High,
    /// Balanced reasoning effort
    Medium,
    /// Quick, lightweight reasoning
    Low,
}

impl Display for Effort {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Effort::High => write!(f, "high"),
            Effort::Medium => write!(f, "medium"),
            Effort::Low => write!(f, "low"),
        }
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ReasoningConfig {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub effort: Option<Effort>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_tokens: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub exclude: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub enabled: Option<bool>,
}

impl ReasoningConfig {
    /// Create a new ReasoningConfig with default enabled settings (medium effort)
    pub fn enabled() -> Self {
        Self {
            effort: None,
            max_tokens: None,
            exclude: None,
            enabled: Some(true),
        }
    }

    /// Create a ReasoningConfig with specific effort level
    pub fn with_effort(effort: Effort) -> Self {
        Self {
            effort: Some(effort),
            max_tokens: None,
            exclude: None,
            enabled: None,
        }
    }

    /// Create a ReasoningConfig with max tokens limit
    pub fn with_max_tokens(max_tokens: u32) -> Self {
        Self {
            effort: None,
            max_tokens: Some(max_tokens),
            exclude: None,
            enabled: None,
        }
    }

    /// Create a ReasoningConfig that excludes reasoning from response
    pub fn excluded() -> Self {
        Self {
            effort: None,
            max_tokens: None,
            exclude: Some(true),
            enabled: None,
        }
    }

    /// Set effort level
    pub fn effort(mut self, effort: Effort) -> Self {
        self.effort = Some(effort);
        self
    }

    /// Set max tokens
    pub fn max_tokens(mut self, max_tokens: u32) -> Self {
        self.max_tokens = Some(max_tokens);
        self
    }

    /// Set exclude flag
    pub fn exclude(mut self, exclude: bool) -> Self {
        self.exclude = Some(exclude);
        self
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum ModelCategory {
    Roleplay,
    Programming,
    Marketing,
    #[serde(rename = "marketing/seo")]
    MarketingSeo,
    Technology,
    Science,
    Translation,
    Legal,
    Finance,
    Health,
    Trivia,
    Academia,
}

impl Display for ModelCategory {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ModelCategory::Roleplay => write!(f, "roleplay"),
            ModelCategory::Programming => write!(f, "programming"),
            ModelCategory::Marketing => write!(f, "marketing"),
            ModelCategory::MarketingSeo => write!(f, "marketing/seo"),
            ModelCategory::Technology => write!(f, "technology"),
            ModelCategory::Science => write!(f, "science"),
            ModelCategory::Translation => write!(f, "translation"),
            ModelCategory::Legal => write!(f, "legal"),
            ModelCategory::Finance => write!(f, "finance"),
            ModelCategory::Health => write!(f, "health"),
            ModelCategory::Trivia => write!(f, "trivia"),
            ModelCategory::Academia => write!(f, "academia"),
        }
    }
}

impl ModelCategory {
    pub fn all() -> Vec<ModelCategory> {
        vec![
            ModelCategory::Roleplay,
            ModelCategory::Programming,
            ModelCategory::Marketing,
            ModelCategory::MarketingSeo,
            ModelCategory::Technology,
            ModelCategory::Science,
            ModelCategory::Translation,
            ModelCategory::Legal,
            ModelCategory::Finance,
            ModelCategory::Health,
            ModelCategory::Trivia,
            ModelCategory::Academia,
        ]
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub enum SupportedParameters {
    Tools,
    Temperature,
    TopP,
    TopK,
    MinP,
    TopA,
    FrequencyPenalty,
    PresencePenalty,
    RepetitionPenalty,
    MaxTokens,
    LogitBias,
    Logprobs,
    TopLogprobs,
    Seed,
    ResponseFormat,
    StructuredOutputs,
    Stop,
    IncludeReasoning,
    Reasoning,
    WebSearchOptions,
}

impl Display for SupportedParameters {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            SupportedParameters::Tools => write!(f, "tools"),
            SupportedParameters::Temperature => write!(f, "temperature"),
            SupportedParameters::TopP => write!(f, "top_p"),
            SupportedParameters::TopK => write!(f, "top_k"),
            SupportedParameters::MinP => write!(f, "min_p"),
            SupportedParameters::TopA => write!(f, "top_a"),
            SupportedParameters::FrequencyPenalty => write!(f, "frequency_penalty"),
            SupportedParameters::PresencePenalty => write!(f, "presence_penalty"),
            SupportedParameters::RepetitionPenalty => write!(f, "repetition_penalty"),
            SupportedParameters::MaxTokens => write!(f, "max_tokens"),
            SupportedParameters::LogitBias => write!(f, "logit_bias"),
            SupportedParameters::Logprobs => write!(f, "logprobs"),
            SupportedParameters::TopLogprobs => write!(f, "top_logprobs"),
            SupportedParameters::Seed => write!(f, "seed"),
            SupportedParameters::ResponseFormat => write!(f, "response_format"),
            SupportedParameters::StructuredOutputs => write!(f, "structured_outputs"),
            SupportedParameters::Stop => write!(f, "stop"),
            SupportedParameters::IncludeReasoning => write!(f, "include_reasoning"),
            SupportedParameters::Reasoning => write!(f, "reasoning"),
            SupportedParameters::WebSearchOptions => write!(f, "web_search_options"),
        }
    }
}

impl SupportedParameters {
    pub fn all() -> Vec<SupportedParameters> {
        vec![
            SupportedParameters::Tools,
            SupportedParameters::Temperature,
            SupportedParameters::TopP,
            SupportedParameters::TopK,
            SupportedParameters::MinP,
            SupportedParameters::TopA,
            SupportedParameters::FrequencyPenalty,
            SupportedParameters::PresencePenalty,
            SupportedParameters::RepetitionPenalty,
            SupportedParameters::MaxTokens,
            SupportedParameters::LogitBias,
            SupportedParameters::Logprobs,
            SupportedParameters::TopLogprobs,
            SupportedParameters::Seed,
            SupportedParameters::ResponseFormat,
            SupportedParameters::StructuredOutputs,
            SupportedParameters::Stop,
            SupportedParameters::IncludeReasoning,
            SupportedParameters::Reasoning,
            SupportedParameters::WebSearchOptions,
        ]
    }
}