fix: respect disable_default_providers (#2177)

Carlos Alexandro Becker created

* fix: respect disable_default_providers

closes #1949

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: use x/slice

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: fail if no providers

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* test: fix

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

Change summary

go.mod                       |  2 +-
go.sum                       |  4 ++--
internal/config/load.go      |  5 +++++
internal/config/load_test.go |  6 +++---
internal/ui/dialog/models.go | 37 +++++++++----------------------------
5 files changed, 20 insertions(+), 34 deletions(-)

Detailed changes

go.mod 🔗

@@ -29,7 +29,7 @@ require (
 	github.com/charmbracelet/x/exp/charmtone v0.0.0-20260109001716-2fbdffcb221f
 	github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f
 	github.com/charmbracelet/x/exp/ordered v0.1.0
-	github.com/charmbracelet/x/exp/slice v0.0.0-20251201173703-9f73bfd934ff
+	github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759
 	github.com/charmbracelet/x/exp/strings v0.1.0
 	github.com/charmbracelet/x/powernap v0.0.0-20260209132835-6b065b8ba62c
 	github.com/charmbracelet/x/term v0.2.2

go.sum 🔗

@@ -116,8 +116,8 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6g
 github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
 github.com/charmbracelet/x/exp/ordered v0.1.0 h1:55/qLwjIh0gL0Vni+QAWk7T/qRVP6sBf+2agPBgnOFE=
 github.com/charmbracelet/x/exp/ordered v0.1.0/go.mod h1:5UHwmG+is5THxMyCJHNPCn2/ecI07aKNrW+LcResjJ8=
-github.com/charmbracelet/x/exp/slice v0.0.0-20251201173703-9f73bfd934ff h1:Uwr+/JS+qnRcO/++xjYEDtW7x+P5E4+4cBiOHTt2Xfk=
-github.com/charmbracelet/x/exp/slice v0.0.0-20251201173703-9f73bfd934ff/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA=
+github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759 h1:96wFGlst+IDv3dIf5q29nw470wJYB3YAgemiciLZcG0=
+github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA=
 github.com/charmbracelet/x/exp/strings v0.1.0 h1:i69S2XI7uG1u4NLGeJPSYU++Nmjvpo9nwd6aoEm7gkA=
 github.com/charmbracelet/x/exp/strings v0.1.0/go.mod h1:/ehtMPNh9K4odGFkqYJKpIYyePhdp1hLBRvyY4bWkH8=
 github.com/charmbracelet/x/json v0.2.0 h1:DqB+ZGx2h+Z+1s98HOuOyli+i97wsFQIxP2ZQANTPrQ=

internal/config/load.go 🔗

@@ -331,6 +331,11 @@ func (c *Config) configureProviders(env env.Env, resolver VariableResolver, know
 
 		c.Providers.Set(id, providerConfig)
 	}
+
+	if c.Providers.Len() == 0 && c.Options.DisableDefaultProviders {
+		return fmt.Errorf("default providers are disabled and there are no custom providers are configured")
+	}
+
 	return nil
 }
 

internal/config/load_test.go 🔗

@@ -1127,7 +1127,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
 		})
 		resolver := NewEnvironmentVariableResolver(env)
 		err := cfg.configureProviders(env, resolver, knownProviders)
-		require.NoError(t, err)
+		require.ErrorContains(t, err, "no custom providers")
 
 		// openai should NOT be present because it lacks base_url and models.
 		require.Equal(t, 0, cfg.Providers.Len())
@@ -1252,7 +1252,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
 		env := env.NewFromMap(map[string]string{})
 		resolver := NewEnvironmentVariableResolver(env)
 		err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
-		require.NoError(t, err)
+		require.ErrorContains(t, err, "no custom providers")
 
 		// Provider should be rejected for missing models.
 		require.Equal(t, 0, cfg.Providers.Len())
@@ -1276,7 +1276,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
 		env := env.NewFromMap(map[string]string{})
 		resolver := NewEnvironmentVariableResolver(env)
 		err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
-		require.NoError(t, err)
+		require.ErrorContains(t, err, "no custom providers")
 
 		// Provider should be rejected for missing base_url.
 		require.Equal(t, 0, cfg.Providers.Len())

internal/ui/dialog/models.go 🔗

@@ -4,7 +4,6 @@ import (
 	"cmp"
 	"fmt"
 	"slices"
-	"strings"
 
 	"charm.land/bubbles/v2/help"
 	"charm.land/bubbles/v2/key"
@@ -15,6 +14,7 @@ import (
 	"github.com/charmbracelet/crush/internal/ui/common"
 	"github.com/charmbracelet/crush/internal/ui/util"
 	uv "github.com/charmbracelet/ultraviolet"
+	xslice "github.com/charmbracelet/x/exp/slice"
 )
 
 // ModelType represents the type of model to select.
@@ -143,12 +143,14 @@ func NewModels(com *common.Common, isOnboarding bool) (*Models, error) {
 	)
 	m.keyMap.Close = CloseKey
 
-	providers, err := getFilteredProviders(com.Config())
-	if err != nil {
-		return nil, fmt.Errorf("failed to get providers: %w", err)
-	}
-
-	m.providers = providers
+	m.providers = slices.Collect(
+		xslice.Map(
+			com.Config().Providers.Seq(),
+			func(pc config.ProviderConfig) catwalk.Provider {
+				return pc.ToProvider()
+			},
+		),
+	)
 	if err := m.setProviderItems(); err != nil {
 		return nil, fmt.Errorf("failed to set provider items: %w", err)
 	}
@@ -521,27 +523,6 @@ func (m *Models) setProviderItems() error {
 	return nil
 }
 
-func getFilteredProviders(cfg *config.Config) ([]catwalk.Provider, error) {
-	providers, err := config.Providers(cfg)
-	if err != nil {
-		return nil, fmt.Errorf("failed to get providers: %w", err)
-	}
-	var filteredProviders []catwalk.Provider
-	for _, p := range providers {
-		var (
-			isAzure         = p.ID == catwalk.InferenceProviderAzure
-			isCopilot       = p.ID == catwalk.InferenceProviderCopilot
-			isHyper         = string(p.ID) == "hyper"
-			hasAPIKeyEnv    = strings.HasPrefix(p.APIKey, "$")
-			_, isConfigured = cfg.Providers.Get(string(p.ID))
-		)
-		if isAzure || isCopilot || isHyper || hasAPIKeyEnv || isConfigured {
-			filteredProviders = append(filteredProviders, p)
-		}
-	}
-	return filteredProviders, nil
-}
-
 func modelKey(providerID, modelID string) string {
 	if providerID == "" || modelID == "" {
 		return ""