@@ -165,7 +165,8 @@ impl ResponseOptions {
165165pub enum ModelVendor {
166166 Anthropic ,
167167 OpenAI ,
168- Gemini , // Google's Gemini models
168+ OpenRouter , // OpenRouter - routes to multiple providers via OpenAI-compatible API
169+ Gemini , // Google's Gemini models
169170 Cohere ,
170171 Groq ,
171172 Ollama ,
@@ -176,7 +177,12 @@ impl ModelVendor {
176177 /// Check if this vendor uses OpenAI-compatible API
177178 pub fn is_openai_compatible ( & self ) -> bool {
178179 match self {
179- Self :: OpenAI | Self :: Cohere | Self :: Groq | Self :: Ollama | Self :: Other => true ,
180+ Self :: OpenAI
181+ | Self :: OpenRouter
182+ | Self :: Cohere
183+ | Self :: Groq
184+ | Self :: Ollama
185+ | Self :: Other => true ,
180186 Self :: Anthropic | Self :: Gemini => false ,
181187 }
182188 }
@@ -186,6 +192,7 @@ impl ModelVendor {
186192 match provider. to_lowercase ( ) . as_str ( ) {
187193 "anthropic" => Self :: Anthropic ,
188194 "openai" => Self :: OpenAI ,
195+ "openrouter" => Self :: OpenRouter ,
189196 "gemini" | "google" => Self :: Gemini ,
190197 "cohere" => Self :: Cohere ,
191198 "groq" => Self :: Groq ,
@@ -282,6 +289,9 @@ impl GenAiClient {
282289 if std:: env:: var ( "COHERE_API_KEY" ) . is_ok ( ) {
283290 available_endpoints. push ( AdapterKind :: Cohere ) ;
284291 }
292+ if std:: env:: var ( "OPENROUTER_API_KEY" ) . is_ok ( ) {
293+ available_endpoints. push ( AdapterKind :: OpenRouter ) ;
294+ }
285295
286296 Ok ( Self {
287297 client,
@@ -317,23 +327,32 @@ impl ModelProvider for GenAiClient {
317327 } ;
318328
319329 for model in models {
330+ // For OpenRouter, we need to prefix model IDs with "openrouter::" so genai
331+ // can resolve them to the correct adapter. OpenRouter models use "/" as separator
332+ // (e.g., "anthropic/claude-opus-4.5") but genai uses "::" for namespacing.
333+ let model_id = if * endpoint == AdapterKind :: OpenRouter {
334+ format ! ( "openrouter::{}" , model)
335+ } else {
336+ model. clone ( )
337+ } ;
338+
320339 // Try to resolve the service target - this validates authentication
321- match self . client . resolve_service_target ( & model ) . await {
340+ match self . client . resolve_service_target ( & model_id ) . await {
322341 Ok ( _) => {
323342 // Model is accessible, continue
324343 }
325344 Err ( e) => {
326345 // Authentication failed for this model, skip it
327- tracing:: debug!( "Skipping model {} due to auth error: {}" , model , e) ;
346+ tracing:: debug!( "Skipping model {} due to auth error: {}" , model_id , e) ;
328347 continue ;
329348 }
330349 }
331350
332351 // Create basic ModelInfo from provider
333352 let model_info = ModelInfo {
334353 provider : endpoint. to_string ( ) ,
335- id : model . clone ( ) ,
336- name : model,
354+ id : model_id . clone ( ) ,
355+ name : model, // Keep original name for display
337356 capabilities : vec ! [ ] ,
338357 max_output_tokens : None ,
339358 cost_per_1k_completion_tokens : None ,
0 commit comments