llm_latency_lens_providers/
lib.rs

1//! Provider adapters for LLM Latency Lens
2//!
3//! This crate provides production-ready adapters for various LLM providers,
4//! enabling high-precision latency measurements and streaming token analysis.
5//!
6//! # Features
7//!
8//! - **OpenAI**: Full implementation with GPT-4, GPT-4o, and GPT-3.5 support
9//! - **Anthropic**: Complete Claude integration with extended thinking support
10//! - **Google**: Stub implementation for Gemini (coming soon)
11//! - **Streaming**: Server-Sent Events (SSE) with fine-grained token timing
12//! - **Retries**: Automatic retry logic with exponential backoff
13//! - **Cost Calculation**: Accurate pricing for all supported models
14//!
15//! # Example
16//!
17//! ```no_run
18//! use llm_latency_lens_providers::{
19//!     openai::OpenAIProvider,
20//!     traits::{Provider, StreamingRequest, MessageRole},
21//! };
22//! use llm_latency_lens_core::TimingEngine;
23//!
24//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
25//! // Create provider
26//! let provider = OpenAIProvider::new("sk-...");
27//!
28//! // Create timing engine
29//! let timing = TimingEngine::new();
30//!
31//! // Build request
32//! let request = StreamingRequest::builder()
33//!     .model("gpt-4o")
34//!     .message(MessageRole::User, "Explain quantum computing")
35//!     .max_tokens(500)
36//!     .temperature(0.7)
37//!     .build();
38//!
39//! // Stream response
40//! let mut response = provider.stream(request, &timing).await?;
41//!
42//! // Process tokens
43//! use futures::StreamExt;
44//! while let Some(token) = response.token_stream.next().await {
45//!     let event = token?;
46//!     println!("Token {}: {:?} (latency: {:?})",
47//!         event.sequence,
48//!         event.content,
49//!         event.inter_token_latency
50//!     );
51//! }
52//! # Ok(())
53//! # }
54//! ```
55//!
56//! # Provider Implementations
57//!
58//! ## OpenAI
59//!
60//! The OpenAI provider supports all GPT models with comprehensive streaming
61//! and timing capabilities:
62//!
63//! ```no_run
64//! use llm_latency_lens_providers::openai::OpenAIProvider;
65//!
66//! let provider = OpenAIProvider::builder()
67//!     .api_key("sk-...")
68//!     .organization("org-...")  // Optional
69//!     .max_retries(3)
70//!     .build();
71//! ```
72//!
73//! ## Anthropic
74//!
75//! The Anthropic provider supports all Claude models including extended
76//! thinking mode:
77//!
78//! ```no_run
79//! use llm_latency_lens_providers::anthropic::AnthropicProvider;
80//!
81//! let provider = AnthropicProvider::builder()
82//!     .api_key("sk-ant-...")
83//!     .api_version("2023-06-01")
84//!     .max_retries(3)
85//!     .build();
86//! ```
87//!
88//! ## Google
89//!
90//! The Google provider is currently a stub. Full implementation coming soon:
91//!
92//! ```no_run
93//! use llm_latency_lens_providers::google::GoogleProvider;
94//!
95//! let provider = GoogleProvider::new("AIza...");
96//! // Note: stream() will return an error until implemented
97//! ```
98//!
99//! # Error Handling
100//!
101//! All providers use a comprehensive error type that distinguishes between
102//! retryable and non-retryable errors:
103//!
104//! ```no_run
105//! use llm_latency_lens_providers::error::ProviderError;
106//!
107//! # async fn example() -> Result<(), ProviderError> {
108//! # use llm_latency_lens_providers::openai::OpenAIProvider;
109//! # use llm_latency_lens_providers::traits::{Provider, StreamingRequest, MessageRole};
110//! # use llm_latency_lens_core::TimingEngine;
111//! # let provider = OpenAIProvider::new("sk-...");
112//! # let timing = TimingEngine::new();
113//! # let request = StreamingRequest::builder()
114//! #     .model("gpt-4o")
115//! #     .message(MessageRole::User, "test")
116//! #     .build();
117//! match provider.stream(request, &timing).await {
118//!     Ok(response) => {
119//!         // Process response
120//!     }
121//!     Err(e) => {
122//!         if e.is_retryable() {
123//!             eprintln!("Retryable error: {}", e);
124//!             if let Some(delay) = e.retry_delay() {
125//!                 eprintln!("Retry after {} seconds", delay);
126//!             }
127//!         } else {
128//!             eprintln!("Fatal error: {}", e);
129//!         }
130//!     }
131//! }
132//! # Ok(())
133//! # }
134//! ```
135//!
136//! # Timing Measurements
137//!
138//! All providers integrate with the core timing engine to provide
139//! nanosecond-precision measurements:
140//!
141//! - **TTFT** (Time to First Token): Critical for perceived responsiveness
142//! - **Inter-token latency**: Consistency of token generation
143//! - **Total generation time**: Overall performance
144//! - **Network timing**: DNS, TLS, connection establishment
145//!
146//! # Cost Calculation
147//!
148//! Each provider implements accurate cost calculation based on current
149//! pricing (as of 2024):
150//!
151//! ```no_run
152//! use llm_latency_lens_providers::openai::OpenAIProvider;
153//! use llm_latency_lens_providers::traits::Provider;
154//!
155//! let provider = OpenAIProvider::new("sk-...");
156//!
157//! // Calculate cost for GPT-4o
158//! let cost = provider.calculate_cost("gpt-4o", 1000, 2000);
159//! if let Some(usd) = cost {
160//!     println!("Estimated cost: ${:.6}", usd);
161//! }
162//! ```
163
164pub mod anthropic;
165pub mod error;
166pub mod google;
167pub mod openai;
168pub mod traits;
169
170// Re-export commonly used types
171pub use error::{ProviderError, Result};
172pub use traits::{
173    CompletionResult, Message, MessageRole, Provider, ResponseMetadata, StreamingRequest,
174    StreamingResponse,
175};
176
177// Re-export provider implementations
178pub use anthropic::AnthropicProvider;
179pub use google::GoogleProvider;
180pub use openai::OpenAIProvider;
181
182/// Version of the providers crate
183pub const VERSION: &str = env!("CARGO_PKG_VERSION");
184
185/// Create a provider from a string identifier
186///
187/// This is a convenience function for dynamically selecting providers.
188///
189/// # Arguments
190///
191/// * `provider` - Provider identifier ("openai", "anthropic", "google")
192/// * `api_key` - API key for the provider
193///
194/// # Example
195///
196/// ```no_run
197/// use llm_latency_lens_providers::create_provider;
198///
199/// let provider = create_provider("openai", "sk-...").unwrap();
200/// ```
201pub fn create_provider(
202    provider: &str,
203    api_key: impl Into<String>,
204) -> Result<Box<dyn Provider>> {
205    match provider.to_lowercase().as_str() {
206        "openai" => Ok(Box::new(OpenAIProvider::new(api_key))),
207        "anthropic" => Ok(Box::new(AnthropicProvider::new(api_key))),
208        "google" => Ok(Box::new(GoogleProvider::new(api_key))),
209        _ => Err(ProviderError::ConfigError(format!(
210            "Unknown provider: {}. Supported providers: openai, anthropic, google",
211            provider
212        ))),
213    }
214}
215
216/// List all supported providers
217pub fn supported_providers() -> Vec<&'static str> {
218    vec!["openai", "anthropic", "google"]
219}
220
221#[cfg(test)]
222mod tests {
223    use super::*;
224
225    #[test]
226    fn test_create_provider_openai() {
227        let provider = create_provider("openai", "test-key");
228        assert!(provider.is_ok());
229        let provider = provider.unwrap();
230        assert_eq!(provider.name(), "openai");
231    }
232
233    #[test]
234    fn test_create_provider_anthropic() {
235        let provider = create_provider("anthropic", "test-key");
236        assert!(provider.is_ok());
237        let provider = provider.unwrap();
238        assert_eq!(provider.name(), "anthropic");
239    }
240
241    #[test]
242    fn test_create_provider_google() {
243        let provider = create_provider("google", "test-key");
244        assert!(provider.is_ok());
245        let provider = provider.unwrap();
246        assert_eq!(provider.name(), "google");
247    }
248
249    #[test]
250    fn test_create_provider_unknown() {
251        let provider = create_provider("unknown", "test-key");
252        assert!(provider.is_err());
253    }
254
255    #[test]
256    fn test_create_provider_case_insensitive() {
257        assert!(create_provider("OpenAI", "test-key").is_ok());
258        assert!(create_provider("ANTHROPIC", "test-key").is_ok());
259        assert!(create_provider("Google", "test-key").is_ok());
260    }
261
262    #[test]
263    fn test_supported_providers() {
264        let providers = supported_providers();
265        assert_eq!(providers.len(), 3);
266        assert!(providers.contains(&"openai"));
267        assert!(providers.contains(&"anthropic"));
268        assert!(providers.contains(&"google"));
269    }
270
271    #[test]
272    fn test_version() {
273        assert!(!VERSION.is_empty());
274    }
275}