diff --git a/app/components/settings/providers/ProvidersTab.tsx b/app/components/settings/providers/ProvidersTab.tsx
index 20e66ef..58c8dac 100644
--- a/app/components/settings/providers/ProvidersTab.tsx
+++ b/app/components/settings/providers/ProvidersTab.tsx
@@ -34,9 +34,87 @@ export default function ProvidersTab() {
newFilteredProviders.sort((a, b) => a.name.localeCompare(b.name));
- setFilteredProviders(newFilteredProviders);
+ // Split providers into regular and URL-configurable
+ const regular = newFilteredProviders.filter(p => !URL_CONFIGURABLE_PROVIDERS.includes(p.name));
+ const urlConfigurable = newFilteredProviders.filter(p => URL_CONFIGURABLE_PROVIDERS.includes(p.name));
+
+ setFilteredProviders([...regular, ...urlConfigurable]);
}, [providers, searchTerm, isLocalModel]);
+ const renderProviderCard = (provider: IProviderConfig) => {
+ const envBaseUrlKey = providerBaseUrlEnvKeys[provider.name].baseUrlKey;
+ const envBaseUrl = envBaseUrlKey ? import.meta.env[envBaseUrlKey] : undefined;
+ const isUrlConfigurable = URL_CONFIGURABLE_PROVIDERS.includes(provider.name);
+
+ return (
+
+
+
+
{
+ e.currentTarget.src = DefaultIcon;
+ }}
+ alt={`${provider.name} icon`}
+ className="w-6 h-6 dark:invert"
+ />
+
{provider.name}
+
+
{
+ updateProviderSettings(provider.name, { ...provider.settings, enabled });
+
+ if (enabled) {
+ logStore.logProvider(`Provider ${provider.name} enabled`, { provider: provider.name });
+ } else {
+ logStore.logProvider(`Provider ${provider.name} disabled`, { provider: provider.name });
+ }
+ }}
+ />
+
+ {isUrlConfigurable && provider.settings.enabled && (
+
+ {envBaseUrl && (
+
+ Set On (.env) : {envBaseUrl}
+
+ )}
+
+ {envBaseUrl ? 'Override Base Url' : 'Base URL '}:{' '}
+
+ {
+ let newBaseUrl: string | undefined = e.target.value;
+
+ if (newBaseUrl && newBaseUrl.trim().length === 0) {
+ newBaseUrl = undefined;
+ }
+
+ updateProviderSettings(provider.name, { ...provider.settings, baseUrl: newBaseUrl });
+ logStore.logProvider(`Base URL updated for ${provider.name}`, {
+ provider: provider.name,
+ baseUrl: newBaseUrl,
+ });
+ }}
+ placeholder={`Enter ${provider.name} base URL`}
+ className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
+ />
+
+ )}
+
+ );
+ };
+
+ const regularProviders = filteredProviders.filter(p => !URL_CONFIGURABLE_PROVIDERS.includes(p.name));
+ const urlConfigurableProviders = filteredProviders.filter(p => URL_CONFIGURABLE_PROVIDERS.includes(p.name));
+
return (
@@ -48,77 +126,24 @@ export default function ProvidersTab() {
className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
/>
- {filteredProviders.map((provider) => {
- const envBaseUrlKey = providerBaseUrlEnvKeys[provider.name].baseUrlKey;
- const envBaseUrl = envBaseUrlKey ? import.meta.env[envBaseUrlKey] : undefined;
- return (
-
-
-
-
{
- // Fallback to default icon on error
- e.currentTarget.src = DefaultIcon;
- }}
- alt={`${provider.name} icon`}
- className="w-6 h-6 dark:invert"
- />
-
{provider.name}
-
-
{
- updateProviderSettings(provider.name, { ...provider.settings, enabled });
+ {/* Regular Providers Grid */}
+
+ {regularProviders.map(renderProviderCard)}
+
- if (enabled) {
- logStore.logProvider(`Provider ${provider.name} enabled`, { provider: provider.name });
- } else {
- logStore.logProvider(`Provider ${provider.name} disabled`, { provider: provider.name });
- }
- }}
- />
-
- {/* Base URL input for configurable providers */}
- {URL_CONFIGURABLE_PROVIDERS.includes(provider.name) && provider.settings.enabled && (
-
- {envBaseUrl && (
-
- Set On (.env) : {envBaseUrl}
-
- )}
-
- {envBaseUrl ? 'Override Base Url' : 'Base URL '}:{' '}
-
- {
- let newBaseUrl: string | undefined = e.target.value;
-
- if (newBaseUrl && newBaseUrl.trim().length === 0) {
- newBaseUrl = undefined;
- }
-
- updateProviderSettings(provider.name, { ...provider.settings, baseUrl: newBaseUrl });
- logStore.logProvider(`Base URL updated for ${provider.name}`, {
- provider: provider.name,
- baseUrl: newBaseUrl,
- });
- }}
- placeholder={`Enter ${provider.name} base URL`}
- className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
- />
-
- )}
+ {/* URL Configurable Providers Section */}
+ {urlConfigurableProviders.length > 0 && (
+
+
Experimental Providers
+
+ These providers are experimental and allow you to run AI models locally or connect to your own infrastructure. They require additional setup but offer more flexibility.
+
+
+ {urlConfigurableProviders.map(renderProviderCard)}
- );
- })}
+
+ )}
);
-}
+}
\ No newline at end of file