22 * Utility functions for AI provider detection and model management
33 */
44
5- export type AIProvider = "openai" | "anthropic" | "gemini" | "ollama" | "groq" | "cohere" | "unknown" ;
5+ export type AIProvider = "openai" | "anthropic" | "gemini" | "ollama" | "groq" | "cohere" | "xai" | " unknown";
66
77/**
88 * Detects the AI provider based on the API key format
@@ -44,6 +44,11 @@ export function detectProviderFromApiKey(apiKey: string | undefined): AIProvider
4444 return "groq" ;
4545 }
4646
47+ // xAI: starts with "xai-"
48+ if ( trimmedKey . startsWith ( "xai-" ) ) {
49+ return "xai" ;
50+ }
51+
4752 // Cohere: typically a long alphanumeric string starting with specific patterns
4853 // No reliable prefix detection for Cohere, handled by model selection
4954
@@ -70,6 +75,8 @@ export function getProviderDisplayName(provider: AIProvider): string {
7075 return "Groq" ;
7176 case "cohere" :
7277 return "Cohere" ;
78+ case "xai" :
79+ return "xAI" ;
7380 default :
7481 return "Unknown" ;
7582 }
@@ -120,6 +127,11 @@ export function getProviderApiKeyInfo(provider: AIProvider): {
120127 url : "https://dashboard.cohere.com/api-keys" ,
121128 description : "Get your Cohere API key from the Cohere Dashboard" ,
122129 } ;
130+ case "xai" :
131+ return {
132+ url : "https://console.x.ai/" ,
133+ description : "Get your xAI API key from the xAI Console" ,
134+ } ;
123135 default :
124136 return null ;
125137 }
@@ -140,7 +152,7 @@ export function detectProviderFromModel(model: string): AIProvider {
140152 const doubleSeparatorIndex = model . indexOf ( "::" ) ;
141153 if ( doubleSeparatorIndex !== - 1 ) {
142154 const prefix = model . substring ( 0 , doubleSeparatorIndex ) ;
143- const knownProviders : AIProvider [ ] = [ "openai" , "anthropic" , "gemini" , "ollama" , "groq" , "cohere" ] ;
155+ const knownProviders : AIProvider [ ] = [ "openai" , "anthropic" , "gemini" , "ollama" , "groq" , "cohere" , "xai" ] ;
144156 const matched = knownProviders . find ( p => p === prefix ) ;
145157 if ( matched ) return matched ;
146158 }
@@ -149,7 +161,7 @@ export function detectProviderFromModel(model: string): AIProvider {
149161 const singleSeparatorIndex = model . indexOf ( ":" ) ;
150162 if ( singleSeparatorIndex !== - 1 ) {
151163 const prefix = model . substring ( 0 , singleSeparatorIndex ) ;
152- const knownProviders : AIProvider [ ] = [ "openai" , "anthropic" , "gemini" , "ollama" , "groq" , "cohere" ] ;
164+ const knownProviders : AIProvider [ ] = [ "openai" , "anthropic" , "gemini" , "ollama" , "groq" , "cohere" , "xai" ] ;
153165 const matched = knownProviders . find ( p => p === prefix ) ;
154166 if ( matched ) return matched ;
155167 }
@@ -161,6 +173,7 @@ export function detectProviderFromModel(model: string): AIProvider {
161173 if ( model . includes ( "llama" ) || model . includes ( "mixtral" ) || model . includes ( "phi" ) || model . includes ( "deepseek" ) ) return "ollama" ;
162174 if ( model . includes ( "groq" ) ) return "groq" ;
163175 if ( model . includes ( "command" ) || model . includes ( "cohere" ) ) return "cohere" ;
176+ if ( model . includes ( "grok" ) ) return "xai" ;
164177
165178 return "unknown" ;
166179}
@@ -185,7 +198,7 @@ export function formatModelDisplayName(modelValue: string): string {
185198 withoutPrefix = modelValue . substring ( doubleSepIndex + 2 ) ;
186199 } else {
187200 // Remove legacy single-colon provider prefix (e.g., "anthropic:claude-3-5-sonnet")
188- const knownPrefixes = [ "openai" , "anthropic" , "gemini" , "ollama" , "groq" , "cohere" ] ;
201+ const knownPrefixes = [ "openai" , "anthropic" , "gemini" , "ollama" , "groq" , "cohere" , "xai" ] ;
189202 const singleSepIndex = modelValue . indexOf ( ":" ) ;
190203 if ( singleSepIndex !== - 1 ) {
191204 const prefix = modelValue . substring ( 0 , singleSepIndex ) ;
0 commit comments