Skip to main content

openrouter_rust/
lib.rs

1//! # OpenRouter Rust Client
2//!
3//! A comprehensive, type-safe Rust client library for the [OpenRouter API](https://openrouter.ai/).
4//!
5//! ## Features
6//!
7//! - **Chat Completions API**: Full support for `/v1/chat/completions` endpoint
8//! - **Responses API (Beta)**: Support for the new `/v1/responses` endpoint
9//! - **Anthropic Messages API**: Support for `/v1/messages` endpoint
10//! - **Embeddings API**: Text and image embeddings support
11//! - **Streaming**: Real-time streaming responses using Server-Sent Events
12//! - **Models API**: List and filter available models
13//! - **Providers API**: List available providers
14//! - **Generation API**: Retrieve generation metadata
15//! - **Type-Safe**: Comprehensive types for all API requests and responses
16//! - **Builder Pattern**: Ergonomic builder APIs for constructing requests
17//! - **Error Handling**: Detailed error types for different failure scenarios
18//!
19//! ## Quick Start
20//!
21//! ```rust,no_run
22//! use openrouter_rust::{OpenRouterClient, ChatCompletionBuilder};
23//!
24//! #[tokio::main]
25//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
26//!     // Create a client
27//!     let client = OpenRouterClient::builder()
28//!         .api_key("your-api-key")
29//!         .build()?;
30//!
31//!     // Build a request
32//!     let request = ChatCompletionBuilder::new("openai/gpt-3.5-turbo")
33//!         .user_message("What is the meaning of life?")
34//!         .build();
35//!
36//!     // Send the request
37//!     let response = client.chat_completion(request).await?;
38//!     
39//!     if let Some(ref content) = response.choices[0].message.content {
40//!         println!("Response: {}", content);
41//!     }
42//!     
43//!     Ok(())
44//! }
45//! ```
46//!
47//! ## Feature Flags
48//!
49//! - `chat` (default): Enable chat completions API
50//! - `responses`: Enable Responses API (Beta)
51//! - `streaming` (default): Enable streaming support
52//! - `embeddings`: Enable embeddings API
53//! - `anthropic`: Enable Anthropic Messages API
54//! - `providers`: Enable providers API
55//! - `models`: Enable models API
56//! - `generations`: Enable generation metadata API
57//!
58//! ## Examples
59//!
60//! See the `examples/` directory for more comprehensive examples.
61
62pub mod client;
63pub mod error;
64pub mod types;
65
66#[cfg(feature = "chat")]
67pub mod chat;
68
69#[cfg(feature = "responses")]
70pub mod responses;
71
72#[cfg(feature = "streaming")]
73pub mod streaming;
74
75#[cfg(feature = "embeddings")]
76pub mod embeddings;
77
78#[cfg(feature = "anthropic")]
79pub mod anthropic;
80
81#[cfg(feature = "providers")]
82pub mod providers;
83
84#[cfg(feature = "models")]
85pub mod models;
86
87#[cfg(feature = "generations")]
88pub mod generations;
89
90// Re-export commonly used items
91pub use client::{OpenRouterClient, OpenRouterClientBuilder};
92pub use error::{OpenRouterError, Result};
93
94#[cfg(feature = "chat")]
95pub use chat::{
96    ChatCompletionBuilder,
97    ChatCompletionRequest,
98    ChatCompletionResponse,
99    ChatCompletionBuilder as ChatRequestBuilder,
100    Choice,
101};
102
103#[cfg(feature = "responses")]
104pub use responses::{
105    ResponsesRequestBuilder,
106    ResponsesRequest,
107    ResponsesResponse,
108    ResponsesRequestBuilder as ResponseBuilder,
109    InputItem, InputRole, InputContent, OutputItem, OutputContent,
110    ReasoningSummary, ReasoningConfig,
111};
112
113#[cfg(feature = "streaming")]
114pub use streaming::{
115    ChatCompletionStream,
116    ChatCompletionChunk,
117    StreamingChoice,
118    DeltaMessage,
119    collect_stream,
120};
121
122#[cfg(feature = "embeddings")]
123pub use embeddings::{
124    EmbeddingBuilder,
125    EmbeddingRequest,
126    EmbeddingResponse,
127    EmbeddingData,
128    EmbeddingDataItem,
129    EmbeddingUsage,
130    EmbeddingModel,
131    EmbeddingInput,
132    EmbeddingEncodingFormat,
133};
134
135#[cfg(feature = "anthropic")]
136pub use anthropic::{
137    AnthropicMessageBuilder,
138    AnthropicMessageRequest,
139    AnthropicMessageResponse,
140    AnthropicMessageParam,
141    AnthropicRole,
142    AnthropicContentItem,
143    AnthropicResponseContent,
144    AnthropicUsage,
145    AnthropicTool,
146    AnthropicToolChoice,
147    AnthropicThinking,
148};
149
150#[cfg(feature = "providers")]
151pub use providers::{
152    Provider,
153    ProvidersResponse,
154};
155
156#[cfg(feature = "models")]
157pub use models::{
158    Model,
159    ModelsResponse,
160    ModelsCountResponse,
161    PublicPricing,
162    ModelArchitecture,
163    TopProviderInfo,
164    PerRequestLimits,
165    DefaultParameters,
166    ListModelsParams,
167};
168
169#[cfg(feature = "generations")]
170pub use generations::{
171    GenerationResponse,
172    GenerationData,
173    ProviderResponse,
174};
175
176pub use types::{
177    Message,
178    Role,
179    Function,
180    Tool,
181    ToolChoice,
182    ResponseFormat,
183    Usage,
184    Plugin,
185    ProviderPreferences,
186};
187
188#[cfg(test)]
189mod tests {
190    use super::*;
191
192    #[test]
193    fn test_error_display() {
194        let err = OpenRouterError::ConfigError("test error".to_string());
195        assert_eq!(err.to_string(), "Configuration error: test error");
196    }
197
198    #[test]
199    fn test_role_serialization() {
200        let role = Role::User;
201        let json = serde_json::to_string(&role).unwrap();
202        assert_eq!(json, "\"user\"");
203
204        let role = Role::Assistant;
205        let json = serde_json::to_string(&role).unwrap();
206        assert_eq!(json, "\"assistant\"");
207    }
208
209    #[test]
210    fn test_role_deserialization() {
211        let role: Role = serde_json::from_str("\"system\"").unwrap();
212        assert!(matches!(role, Role::System));
213    }
214
215    #[test]
216    fn test_usage_default() {
217        let usage = Usage {
218            prompt_tokens: 10,
219            completion_tokens: 20,
220            total_tokens: 30,
221            prompt_tokens_details: None,
222            completion_tokens_details: None,
223            cost: None,
224        };
225
226        assert_eq!(usage.prompt_tokens, 10);
227        assert_eq!(usage.completion_tokens, 20);
228        assert_eq!(usage.total_tokens, 30);
229    }
230
231    #[test]
232    fn test_message_builder_pattern() {
233        let msg = Message {
234            role: Role::User,
235            content: Some("Hello".to_string()),
236            name: None,
237            tool_calls: None,
238        };
239
240        assert!(matches!(msg.role, Role::User));
241        assert_eq!(msg.content, Some("Hello".to_string()));
242    }
243}