Browse Source

make new settings backward compatible

alexchenzl 5 months ago
parent
commit
b5081f2e55

+ 46 - 45
chrome-extension/src/background/agent/helper.ts

@@ -5,37 +5,57 @@ import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
 import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
 import { ChatOllama } from '@langchain/ollama';
 
+const maxTokens = 1024 * 4;
+
+function isOpenAIOModel(modelName: string): boolean {
+  return modelName.startsWith('openai/o') || modelName.startsWith('o');
+}
+
+function createOpenAIChatModel(providerConfig: ProviderConfig, modelConfig: ModelConfig): BaseChatModel {
+  const args: {
+    model: string;
+    apiKey?: string;
+    configuration?: Record<string, unknown>;
+    modelKwargs?: { max_completion_tokens: number };
+    topP?: number;
+    temperature?: number;
+    maxTokens?: number;
+  } = {
+    model: modelConfig.modelName,
+    apiKey: providerConfig.apiKey,
+  };
+
+  if (providerConfig.baseUrl) {
+    args.configuration = {
+      baseURL: providerConfig.baseUrl,
+    };
+  }
+  // custom provider may have no api key
+  if (providerConfig.apiKey) {
+    args.apiKey = providerConfig.apiKey;
+  }
+
+  // O series models have different parameters
+  if (isOpenAIOModel(modelConfig.modelName)) {
+    args.modelKwargs = {
+      max_completion_tokens: maxTokens,
+    };
+  } else {
+    args.topP = (modelConfig.parameters?.topP ?? 0.1) as number;
+    args.temperature = (modelConfig.parameters?.temperature ?? 0.1) as number;
+    args.maxTokens = maxTokens;
+  }
+  return new ChatOpenAI(args);
+}
+
 // create a chat model based on the agent name, the model name and provider
 export function createChatModel(providerConfig: ProviderConfig, modelConfig: ModelConfig): BaseChatModel {
-  const maxTokens = 1024 * 4;
-  const maxCompletionTokens = 1024 * 4;
   const temperature = (modelConfig.parameters?.temperature ?? 0.1) as number;
   const topP = (modelConfig.parameters?.topP ?? 0.1) as number;
 
-  switch (providerConfig.type) {
+  switch (modelConfig.provider) {
     case ProviderTypeEnum.OpenAI: {
-      const args: {
-        model: string;
-        apiKey: string;
-        modelKwargs?: { max_completion_tokens: number };
-        topP?: number;
-        temperature?: number;
-        maxTokens?: number;
-      } = {
-        model: modelConfig.modelName,
-        apiKey: providerConfig.apiKey,
-      };
-      // O series models have different parameters
-      if (modelConfig.modelName.startsWith('o')) {
-        args.modelKwargs = {
-          max_completion_tokens: maxCompletionTokens,
-        };
-      } else {
-        args.topP = topP;
-        args.temperature = temperature;
-        args.maxTokens = maxTokens;
-      }
-      return new ChatOpenAI(args);
+      return createOpenAIChatModel(providerConfig, modelConfig);
     }
     case ProviderTypeEnum.Anthropic: {
       const args = {
@@ -86,26 +106,7 @@ export function createChatModel(providerConfig: ProviderConfig, modelConfig: Mod
     }
     default: {
       // by default, we think it's a openai-compatible provider
-      const args: {
-        model: string;
-        apiKey?: string;
-        configuration: Record<string, unknown>;
-        topP?: number;
-        temperature?: number;
-        maxTokens?: number;
-      } = {
-        model: modelConfig.modelName,
-        configuration: {
-          baseURL: providerConfig.baseUrl,
-        },
-        topP,
-        temperature,
-        maxTokens,
-      };
-      if (providerConfig.apiKey) {
-        args.apiKey = providerConfig.apiKey;
-      }
-      return new ChatOpenAI(args);
+      return createOpenAIChatModel(providerConfig, modelConfig);
     }
   }
 }

+ 61 - 69
packages/storage/lib/settings/llmProviders.ts

@@ -1,14 +1,7 @@
 import { StorageEnum } from '../base/enums';
 import { createStorage } from '../base/base';
 import type { BaseStorage } from '../base/types';
-import {
-  llmProviderModelNames,
-  ProviderTypeEnum,
-  OPENAI_PROVIDER,
-  ANTHROPIC_PROVIDER,
-  GEMINI_PROVIDER,
-  OLLAMA_PROVIDER,
-} from './types';
+import { llmProviderModelNames, ProviderTypeEnum } from './types';
 
 // Interface for a single provider configuration
 export interface ProviderConfig {
@@ -21,19 +14,21 @@ export interface ProviderConfig {
 }
 
 // Interface for storing multiple LLM provider configurations
+// The key is the provider id, which is the same as the provider type for built-in providers, but is custom for custom providers
 export interface LLMKeyRecord {
   providers: Record<string, ProviderConfig>;
 }
 
 export type LLMProviderStorage = BaseStorage<LLMKeyRecord> & {
-  setProvider: (provider: string, config: ProviderConfig) => Promise<void>;
-  getProvider: (provider: string) => Promise<ProviderConfig | undefined>;
-  removeProvider: (provider: string) => Promise<void>;
-  hasProvider: (provider: string) => Promise<boolean>;
-  getConfiguredProviders: () => Promise<string[]>;
+  setProvider: (providerId: string, config: ProviderConfig) => Promise<void>;
+  getProvider: (providerId: string) => Promise<ProviderConfig | undefined>;
+  removeProvider: (providerId: string) => Promise<void>;
+  hasProvider: (providerId: string) => Promise<boolean>;
   getAllProviders: () => Promise<Record<string, ProviderConfig>>;
 };
 
+// Storage for LLM provider configurations
+// use "llm-api-keys" as the key for the storage, for backward compatibility
 const storage = createStorage<LLMKeyRecord>(
   'llm-api-keys',
   { providers: {} },
@@ -44,42 +39,61 @@ const storage = createStorage<LLMKeyRecord>(
 );
 
 // Helper function to determine provider type from provider name
-function getProviderTypeFromName(provider: string): ProviderTypeEnum {
-  switch (provider) {
-    case OPENAI_PROVIDER:
+function getProviderTypeByProviderId(providerId: string): ProviderTypeEnum {
+  switch (providerId) {
+    case ProviderTypeEnum.OpenAI:
       return ProviderTypeEnum.OpenAI;
-    case ANTHROPIC_PROVIDER:
+    case ProviderTypeEnum.Anthropic:
       return ProviderTypeEnum.Anthropic;
-    case GEMINI_PROVIDER:
+    case ProviderTypeEnum.Gemini:
       return ProviderTypeEnum.Gemini;
-    case OLLAMA_PROVIDER:
+    case ProviderTypeEnum.Ollama:
       return ProviderTypeEnum.Ollama;
     default:
       return ProviderTypeEnum.CustomOpenAI;
   }
 }
 
-// Helper function to get display name from provider name
-function getDisplayNameFromProvider(provider: string): string {
-  switch (provider) {
-    case OPENAI_PROVIDER:
+// Helper function to get display name from provider id
+function getDisplayNameFromProviderId(providerId: string): string {
+  switch (providerId) {
+    case ProviderTypeEnum.OpenAI:
       return 'OpenAI';
-    case ANTHROPIC_PROVIDER:
+    case ProviderTypeEnum.Anthropic:
       return 'Anthropic';
-    case GEMINI_PROVIDER:
+    case ProviderTypeEnum.Gemini:
       return 'Gemini';
-    case OLLAMA_PROVIDER:
+    case ProviderTypeEnum.Ollama:
       return 'Ollama';
     default:
-      return provider; // Use the provider string as display name for custom providers
+      return providerId; // Use the provider id as display name for custom providers by default
   }
 }
 
+// Helper function to ensure backward compatibility for provider configs
+function ensureBackwardCompatibility(providerId: string, config: ProviderConfig): ProviderConfig {
+  const updatedConfig = { ...config };
+  if (!updatedConfig.name) {
+    updatedConfig.name = getDisplayNameFromProviderId(providerId);
+  }
+  if (!updatedConfig.type) {
+    updatedConfig.type = getProviderTypeByProviderId(providerId);
+  }
+  if (!updatedConfig.modelNames) {
+    updatedConfig.modelNames = llmProviderModelNames[providerId as keyof typeof llmProviderModelNames] || [];
+  }
+  if (!updatedConfig.createdAt) {
+    // if createdAt is not set, set it to "03/04/2025" for backward compatibility
+    updatedConfig.createdAt = new Date('03/04/2025').getTime();
+  }
+  return updatedConfig;
+}
+
 export const llmProviderStore: LLMProviderStorage = {
   ...storage,
-  async setProvider(provider: string, config: ProviderConfig) {
-    if (!provider) {
-      throw new Error('Provider name cannot be empty');
+  async setProvider(providerId: string, config: ProviderConfig) {
+    if (!providerId) {
+      throw new Error('Provider id cannot be empty');
     }
 
     if (config.apiKey === undefined) {
@@ -93,8 +107,8 @@ export const llmProviderStore: LLMProviderStorage = {
     // Ensure backward compatibility by filling in missing fields
     const completeConfig: ProviderConfig = {
       ...config,
-      name: config.name || getDisplayNameFromProvider(provider),
-      type: config.type || getProviderTypeFromName(provider),
+      name: config.name || getDisplayNameFromProviderId(providerId),
+      type: config.type || getProviderTypeByProviderId(providerId),
       modelNames: config.modelNames,
       createdAt: config.createdAt || Date.now(),
     };
@@ -103,57 +117,35 @@ export const llmProviderStore: LLMProviderStorage = {
     await storage.set({
       providers: {
         ...current.providers,
-        [provider]: completeConfig,
+        [providerId]: completeConfig,
       },
     });
   },
-  async getProvider(provider: string) {
+  async getProvider(providerId: string) {
     const data = (await storage.get()) || { providers: {} };
-    const config = data.providers[provider];
-
-    // If we have a config but it's missing some fields, fill them in
-    if (config) {
-      if (!config.name) {
-        config.name = getDisplayNameFromProvider(provider);
-      }
-      if (!config.type) {
-        config.type = getProviderTypeFromName(provider);
-      }
-      if (!config.modelNames) {
-        config.modelNames = llmProviderModelNames[provider as keyof typeof llmProviderModelNames] || [];
-      }
-      if (!config.createdAt) {
-        config.createdAt = Date.now();
-      }
-    }
-
-    return config;
+    const config = data.providers[providerId];
+    return config ? ensureBackwardCompatibility(providerId, config) : undefined;
   },
-  async removeProvider(provider: string) {
+  async removeProvider(providerId: string) {
     const current = (await storage.get()) || { providers: {} };
     const newProviders = { ...current.providers };
-    delete newProviders[provider];
+    delete newProviders[providerId];
     await storage.set({ providers: newProviders });
   },
-  async hasProvider(provider: string) {
+  async hasProvider(providerId: string) {
     const data = (await storage.get()) || { providers: {} };
-    return provider in data.providers;
+    return providerId in data.providers;
   },
-  async getConfiguredProviders() {
-    console.log('Getting configured providers');
+
+  async getAllProviders() {
     const data = await storage.get();
-    console.log('Raw storage data:', data); // Debug the entire data object
+    const providers = { ...data.providers };
 
-    if (!data || !data.providers) {
-      console.log('No data found, returning empty array');
-      return [];
+    // Add backward compatibility for all providers
+    for (const [providerId, config] of Object.entries(providers)) {
+      providers[providerId] = ensureBackwardCompatibility(providerId, config);
     }
 
-    console.log('Configured providers:', data.providers);
-    return Object.keys(data.providers);
-  },
-  async getAllProviders() {
-    const data = await storage.get();
-    return data.providers;
+    return providers;
   },
 };

+ 14 - 17
packages/storage/lib/settings/types.ts

@@ -1,16 +1,13 @@
+// Agent name, used to identify the agent in the settings
 export enum AgentNameEnum {
   Planner = 'planner',
   Navigator = 'navigator',
   Validator = 'validator',
 }
 
-// String literal constants for supported LLM providers
-export const OPENAI_PROVIDER = 'openai';
-export const ANTHROPIC_PROVIDER = 'anthropic';
-export const GEMINI_PROVIDER = 'gemini';
-export const OLLAMA_PROVIDER = 'ollama';
-
-// Provider type for determining which LangChain ChatModel package to use
+// Provider type, types before CustomOpenAI are built-in providers, CustomOpenAI is a custom provider
+// For built-in providers, we will create ChatModel instances with its respective LangChain ChatModel classes
+// For custom providers, we will create ChatModel instances with the ChatOpenAI class
 export enum ProviderTypeEnum {
   OpenAI = 'openai',
   Anthropic = 'anthropic',
@@ -19,23 +16,23 @@ export enum ProviderTypeEnum {
   CustomOpenAI = 'custom_openai',
 }
 
-// Default model names for each built-in provider
+// Default supported models for each built-in provider
 export const llmProviderModelNames = {
-  [OPENAI_PROVIDER]: ['gpt-4o', 'gpt-4o-mini', 'o1', 'o1-mini', 'o3-mini'],
-  [ANTHROPIC_PROVIDER]: ['claude-3-7-sonnet-latest', 'claude-3-5-sonnet-latest', 'claude-3-5-haiku-latest'],
-  [GEMINI_PROVIDER]: [
+  [ProviderTypeEnum.OpenAI]: ['gpt-4o', 'gpt-4o-mini', 'o1', 'o1-mini', 'o3-mini'],
+  [ProviderTypeEnum.Anthropic]: ['claude-3-7-sonnet-latest', 'claude-3-5-sonnet-latest', 'claude-3-5-haiku-latest'],
+  [ProviderTypeEnum.Gemini]: [
     'gemini-2.0-flash',
     'gemini-2.0-flash-lite',
     'gemini-2.0-pro-exp-02-05',
     // 'gemini-2.0-flash-thinking-exp-01-21', // TODO: not support function calling for now
   ],
-  [OLLAMA_PROVIDER]: [],
+  [ProviderTypeEnum.Ollama]: [],
   // Custom OpenAI providers don't have predefined models as they are user-defined
 };
 
-// Default parameters for each agent per provider
+// Default parameters for each agent per provider, for providers not specified, use OpenAI parameters
 export const llmProviderParameters = {
-  [OPENAI_PROVIDER]: {
+  [ProviderTypeEnum.OpenAI]: {
     [AgentNameEnum.Planner]: {
       temperature: 0.01,
       topP: 0.001,
@@ -49,7 +46,7 @@ export const llmProviderParameters = {
       topP: 0.001,
     },
   },
-  [ANTHROPIC_PROVIDER]: {
+  [ProviderTypeEnum.Anthropic]: {
     [AgentNameEnum.Planner]: {
       temperature: 0.1,
       topP: 0.1,
@@ -63,7 +60,7 @@ export const llmProviderParameters = {
       topP: 0.1,
     },
   },
-  [GEMINI_PROVIDER]: {
+  [ProviderTypeEnum.Gemini]: {
     [AgentNameEnum.Planner]: {
       temperature: 0.01,
       topP: 0.1,
@@ -77,7 +74,7 @@ export const llmProviderParameters = {
       topP: 0.1,
     },
   },
-  [OLLAMA_PROVIDER]: {
+  [ProviderTypeEnum.Ollama]: {
     [AgentNameEnum.Planner]: {
       temperature: 0,
       topP: 0.001,

+ 4 - 4
pages/options/src/components/GeneralSettings.tsx

@@ -46,7 +46,7 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
               min={1}
               max={100}
               value={settings.maxSteps}
-              onChange={e => updateSetting('maxSteps', parseInt(e.target.value, 10))}
+              onChange={e => updateSetting('maxSteps', Number.parseInt(e.target.value, 10))}
               className={`w-20 rounded-md border ${isDarkMode ? 'border-slate-600 bg-slate-700 text-gray-200' : 'border-gray-300 bg-white text-gray-700'} px-3 py-2`}
             />
           </div>
@@ -69,7 +69,7 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
               min={1}
               max={100}
               value={settings.maxActionsPerStep}
-              onChange={e => updateSetting('maxActionsPerStep', parseInt(e.target.value, 10))}
+              onChange={e => updateSetting('maxActionsPerStep', Number.parseInt(e.target.value, 10))}
               className={`w-20 rounded-md border ${isDarkMode ? 'border-slate-600 bg-slate-700 text-gray-200' : 'border-gray-300 bg-white text-gray-700'} px-3 py-2`}
             />
           </div>
@@ -92,7 +92,7 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
               min={1}
               max={10}
               value={settings.maxFailures}
-              onChange={e => updateSetting('maxFailures', parseInt(e.target.value, 10))}
+              onChange={e => updateSetting('maxFailures', Number.parseInt(e.target.value, 10))}
               className={`w-20 rounded-md border ${isDarkMode ? 'border-slate-600 bg-slate-700 text-gray-200' : 'border-gray-300 bg-white text-gray-700'} px-3 py-2`}
             />
           </div>
@@ -163,7 +163,7 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
               min={1}
               max={20}
               value={settings.planningInterval}
-              onChange={e => updateSetting('planningInterval', parseInt(e.target.value, 10))}
+              onChange={e => updateSetting('planningInterval', Number.parseInt(e.target.value, 10))}
               className={`w-20 rounded-md border ${isDarkMode ? 'border-slate-600 bg-slate-700 text-gray-200' : 'border-gray-300 bg-white text-gray-700'} px-3 py-2`}
             />
           </div>

+ 76 - 72
pages/options/src/components/ModelSettings.tsx

@@ -7,10 +7,6 @@ import {
   AgentNameEnum,
   llmProviderModelNames,
   ProviderTypeEnum,
-  OPENAI_PROVIDER,
-  ANTHROPIC_PROVIDER,
-  GEMINI_PROVIDER,
-  OLLAMA_PROVIDER,
   llmProviderParameters,
 } from '@extension/storage';
 
@@ -552,7 +548,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
               style={{
                 background: `linear-gradient(to right, ${isDarkMode ? '#3b82f6' : '#60a5fa'} 0%, ${isDarkMode ? '#3b82f6' : '#60a5fa'} ${(modelParameters[agentName].temperature / 2) * 100}%, ${isDarkMode ? '#475569' : '#cbd5e1'} ${(modelParameters[agentName].temperature / 2) * 100}%, ${isDarkMode ? '#475569' : '#cbd5e1'} 100%)`,
               }}
-              className={`flex-1 ${isDarkMode ? 'accent-blue-500' : 'accent-blue-400'} appearance-none h-1 rounded-full`}
+              className={`flex-1 ${isDarkMode ? 'accent-blue-500' : 'accent-blue-400'} h-1 appearance-none rounded-full`}
             />
             <div className="flex items-center space-x-2">
               <span className={`w-12 text-sm ${isDarkMode ? 'text-gray-300' : 'text-gray-600'}`}>
@@ -596,7 +592,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
               style={{
                 background: `linear-gradient(to right, ${isDarkMode ? '#3b82f6' : '#60a5fa'} 0%, ${isDarkMode ? '#3b82f6' : '#60a5fa'} ${modelParameters[agentName].topP * 100}%, ${isDarkMode ? '#475569' : '#cbd5e1'} ${modelParameters[agentName].topP * 100}%, ${isDarkMode ? '#475569' : '#cbd5e1'} 100%)`,
               }}
-              className={`flex-1 ${isDarkMode ? 'accent-blue-500' : 'accent-blue-400'} appearance-none h-1 rounded-full`}
+              className={`flex-1 ${isDarkMode ? 'accent-blue-500' : 'accent-blue-400'} h-1 appearance-none rounded-full`}
             />
             <div className="flex items-center space-x-2">
               <span className={`w-12 text-sm ${isDarkMode ? 'text-gray-300' : 'text-gray-600'}`}>
@@ -693,34 +689,34 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
     };
 
     switch (provider) {
-      case OPENAI_PROVIDER:
+      case ProviderTypeEnum.OpenAI:
         config = {
           apiKey: '',
           name: 'OpenAI',
           type: ProviderTypeEnum.OpenAI,
-          modelNames: [...(llmProviderModelNames[OPENAI_PROVIDER] || [])],
+          modelNames: [...(llmProviderModelNames[ProviderTypeEnum.OpenAI] || [])],
           createdAt: Date.now(),
         };
         break;
-      case ANTHROPIC_PROVIDER:
+      case ProviderTypeEnum.Anthropic:
         config = {
           apiKey: '',
           name: 'Anthropic',
           type: ProviderTypeEnum.Anthropic,
-          modelNames: [...(llmProviderModelNames[ANTHROPIC_PROVIDER] || [])],
+          modelNames: [...(llmProviderModelNames[ProviderTypeEnum.Anthropic] || [])],
           createdAt: Date.now(),
         };
         break;
-      case GEMINI_PROVIDER:
+      case ProviderTypeEnum.Gemini:
         config = {
           apiKey: '',
           name: 'Gemini',
           type: ProviderTypeEnum.Gemini,
-          modelNames: [...(llmProviderModelNames[GEMINI_PROVIDER] || [])],
+          modelNames: [...(llmProviderModelNames[ProviderTypeEnum.Gemini] || [])],
           createdAt: Date.now(),
         };
         break;
-      case OLLAMA_PROVIDER:
+      case ProviderTypeEnum.Ollama:
         config = {
           apiKey: 'ollama', // Set default API key for Ollama
           name: 'Ollama',
@@ -820,10 +816,10 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
 
     // Handle default providers
     switch (providerType) {
-      case OPENAI_PROVIDER:
-      case ANTHROPIC_PROVIDER:
-      case GEMINI_PROVIDER:
-      case OLLAMA_PROVIDER:
+      case ProviderTypeEnum.OpenAI:
+      case ProviderTypeEnum.Anthropic:
+      case ProviderTypeEnum.Gemini:
+      case ProviderTypeEnum.Ollama:
         addDefaultProvider(providerType);
         break;
       default:
@@ -1068,14 +1064,14 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
           )}
 
           {/* Add Provider button and dropdown */}
-          <div className="provider-selector-container relative pt-4">
+          <div className="provider-selector-container pt-4 relative">
             <Button
               variant="secondary"
               onClick={() => setIsProviderSelectorOpen(prev => !prev)}
               className={`flex w-full items-center justify-center font-medium ${
                 isDarkMode
-                  ? 'bg-blue-600 hover:bg-blue-500 border-blue-700 text-white'
-                  : 'bg-blue-100 hover:bg-blue-200 border-blue-200 text-blue-800'
+                  ? 'border-blue-700 bg-blue-600 text-white hover:bg-blue-500'
+                  : 'border-blue-200 bg-blue-100 text-blue-800 hover:bg-blue-200'
               }`}>
               <span className="mr-2">+</span> Add Provider
             </Button>
@@ -1089,67 +1085,75 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
                 }`}>
                 <div className="py-1">
                   {/* Check if all default providers are already added */}
-                  {(providersFromStorage.has(OPENAI_PROVIDER) || modifiedProviders.has(OPENAI_PROVIDER)) &&
-                    (providersFromStorage.has(ANTHROPIC_PROVIDER) || modifiedProviders.has(ANTHROPIC_PROVIDER)) &&
-                    (providersFromStorage.has(GEMINI_PROVIDER) || modifiedProviders.has(GEMINI_PROVIDER)) &&
-                    (providersFromStorage.has(OLLAMA_PROVIDER) || modifiedProviders.has(OLLAMA_PROVIDER)) && (
+                  {(providersFromStorage.has(ProviderTypeEnum.OpenAI) ||
+                    modifiedProviders.has(ProviderTypeEnum.OpenAI)) &&
+                    (providersFromStorage.has(ProviderTypeEnum.Anthropic) ||
+                      modifiedProviders.has(ProviderTypeEnum.Anthropic)) &&
+                    (providersFromStorage.has(ProviderTypeEnum.Gemini) ||
+                      modifiedProviders.has(ProviderTypeEnum.Gemini)) &&
+                    (providersFromStorage.has(ProviderTypeEnum.Ollama) ||
+                      modifiedProviders.has(ProviderTypeEnum.Ollama)) && (
                       <div
                         className={`px-4 py-3 text-sm font-medium ${isDarkMode ? 'text-blue-300' : 'text-blue-600'}`}>
                         All default providers already added. You can still add a custom provider.
                       </div>
                     )}
 
-                  {!providersFromStorage.has(OPENAI_PROVIDER) && !modifiedProviders.has(OPENAI_PROVIDER) && (
-                    <button
-                      type="button"
-                      className={`flex w-full items-center px-4 py-3 text-left text-sm ${
-                        isDarkMode
-                          ? 'text-blue-200 hover:bg-blue-600/30 hover:text-white'
-                          : 'text-blue-700 hover:bg-blue-100 hover:text-blue-800'
-                      } transition-colors duration-150`}
-                      onClick={() => handleProviderSelection(OPENAI_PROVIDER)}>
-                      <span className="font-medium">OpenAI</span>
-                    </button>
-                  )}
+                  {!providersFromStorage.has(ProviderTypeEnum.OpenAI) &&
+                    !modifiedProviders.has(ProviderTypeEnum.OpenAI) && (
+                      <button
+                        type="button"
+                        className={`flex w-full items-center px-4 py-3 text-left text-sm ${
+                          isDarkMode
+                            ? 'text-blue-200 hover:bg-blue-600/30 hover:text-white'
+                            : 'text-blue-700 hover:bg-blue-100 hover:text-blue-800'
+                        } transition-colors duration-150`}
+                        onClick={() => handleProviderSelection(ProviderTypeEnum.OpenAI)}>
+                        <span className="font-medium">OpenAI</span>
+                      </button>
+                    )}
 
-                  {!providersFromStorage.has(ANTHROPIC_PROVIDER) && !modifiedProviders.has(ANTHROPIC_PROVIDER) && (
-                    <button
-                      type="button"
-                      className={`flex w-full items-center px-4 py-3 text-left text-sm ${
-                        isDarkMode
-                          ? 'text-blue-200 hover:bg-blue-600/30 hover:text-white'
-                          : 'text-blue-700 hover:bg-blue-100 hover:text-blue-800'
-                      } transition-colors duration-150`}
-                      onClick={() => handleProviderSelection(ANTHROPIC_PROVIDER)}>
-                      <span className="font-medium">Anthropic</span>
-                    </button>
-                  )}
+                  {!providersFromStorage.has(ProviderTypeEnum.Anthropic) &&
+                    !modifiedProviders.has(ProviderTypeEnum.Anthropic) && (
+                      <button
+                        type="button"
+                        className={`flex w-full items-center px-4 py-3 text-left text-sm ${
+                          isDarkMode
+                            ? 'text-blue-200 hover:bg-blue-600/30 hover:text-white'
+                            : 'text-blue-700 hover:bg-blue-100 hover:text-blue-800'
+                        } transition-colors duration-150`}
+                        onClick={() => handleProviderSelection(ProviderTypeEnum.Anthropic)}>
+                        <span className="font-medium">Anthropic</span>
+                      </button>
+                    )}
 
-                  {!providersFromStorage.has(GEMINI_PROVIDER) && !modifiedProviders.has(GEMINI_PROVIDER) && (
-                    <button
-                      type="button"
-                      className={`flex w-full items-center px-4 py-3 text-left text-sm ${
-                        isDarkMode
-                          ? 'text-blue-200 hover:bg-blue-600/30 hover:text-white'
-                          : 'text-blue-700 hover:bg-blue-100 hover:text-blue-800'
-                      } transition-colors duration-150`}
-                      onClick={() => handleProviderSelection(GEMINI_PROVIDER)}>
-                      <span className="font-medium">Gemini</span>
-                    </button>
-                  )}
+                  {!providersFromStorage.has(ProviderTypeEnum.Gemini) &&
+                    !modifiedProviders.has(ProviderTypeEnum.Gemini) && (
+                      <button
+                        type="button"
+                        className={`flex w-full items-center px-4 py-3 text-left text-sm ${
+                          isDarkMode
+                            ? 'text-blue-200 hover:bg-blue-600/30 hover:text-white'
+                            : 'text-blue-700 hover:bg-blue-100 hover:text-blue-800'
+                        } transition-colors duration-150`}
+                        onClick={() => handleProviderSelection(ProviderTypeEnum.Gemini)}>
+                        <span className="font-medium">Gemini</span>
+                      </button>
+                    )}
 
-                  {!providersFromStorage.has(OLLAMA_PROVIDER) && !modifiedProviders.has(OLLAMA_PROVIDER) && (
-                    <button
-                      type="button"
-                      className={`flex w-full items-center px-4 py-3 text-left text-sm ${
-                        isDarkMode
-                          ? 'text-blue-200 hover:bg-blue-600/30 hover:text-white'
-                          : 'text-blue-700 hover:bg-blue-100 hover:text-blue-800'
-                      } transition-colors duration-150`}
-                      onClick={() => handleProviderSelection(OLLAMA_PROVIDER)}>
-                      <span className="font-medium">Ollama</span>
-                    </button>
-                  )}
+                  {!providersFromStorage.has(ProviderTypeEnum.Ollama) &&
+                    !modifiedProviders.has(ProviderTypeEnum.Ollama) && (
+                      <button
+                        type="button"
+                        className={`flex w-full items-center px-4 py-3 text-left text-sm ${
+                          isDarkMode
+                            ? 'text-blue-200 hover:bg-blue-600/30 hover:text-white'
+                            : 'text-blue-700 hover:bg-blue-100 hover:text-blue-800'
+                        } transition-colors duration-150`}
+                        onClick={() => handleProviderSelection(ProviderTypeEnum.Ollama)}>
+                        <span className="font-medium">Ollama</span>
+                      </button>
+                    )}
 
                   <button
                     type="button"