on main help sign in
fix: respect disable_default_providers (#2177)
d1032baCarlos Alexandro Becker
go.mod+1−1
@@ -29,7 +29,7 @@ require (
29 github.com/charmbracelet/x/exp/charmtone v0.0.0-20260109001716-2fbdffcb221f
29 github.com/charmbracelet/x/exp/charmtone v0.0.0-20260109001716-2fbdffcb221f
30 github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f
30 github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f
31 github.com/charmbracelet/x/exp/ordered v0.1.0
31 github.com/charmbracelet/x/exp/ordered v0.1.0
32− github.com/charmbracelet/x/exp/slice v0.0.0-20251201173703-9f73bfd934ff
32+ github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759
33 github.com/charmbracelet/x/exp/strings v0.1.0
33 github.com/charmbracelet/x/exp/strings v0.1.0
34 github.com/charmbracelet/x/powernap v0.0.0-20260209132835-6b065b8ba62c
34 github.com/charmbracelet/x/powernap v0.0.0-20260209132835-6b065b8ba62c
35 github.com/charmbracelet/x/term v0.2.2
35 github.com/charmbracelet/x/term v0.2.2
go.sum+2−2
@@ -116,8 +116,8 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6g
116github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
116github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
117github.com/charmbracelet/x/exp/ordered v0.1.0 h1:55/qLwjIh0gL0Vni+QAWk7T/qRVP6sBf+2agPBgnOFE=
117github.com/charmbracelet/x/exp/ordered v0.1.0 h1:55/qLwjIh0gL0Vni+QAWk7T/qRVP6sBf+2agPBgnOFE=
118github.com/charmbracelet/x/exp/ordered v0.1.0/go.mod h1:5UHwmG+is5THxMyCJHNPCn2/ecI07aKNrW+LcResjJ8=
118github.com/charmbracelet/x/exp/ordered v0.1.0/go.mod h1:5UHwmG+is5THxMyCJHNPCn2/ecI07aKNrW+LcResjJ8=
119−github.com/charmbracelet/x/exp/slice v0.0.0-20251201173703-9f73bfd934ff h1:Uwr+/JS+qnRcO/++xjYEDtW7x+P5E4+4cBiOHTt2Xfk=
119+github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759 h1:96wFGlst+IDv3dIf5q29nw470wJYB3YAgemiciLZcG0=
120−github.com/charmbracelet/x/exp/slice v0.0.0-20251201173703-9f73bfd934ff/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA=
120+github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA=
121github.com/charmbracelet/x/exp/strings v0.1.0 h1:i69S2XI7uG1u4NLGeJPSYU++Nmjvpo9nwd6aoEm7gkA=
121github.com/charmbracelet/x/exp/strings v0.1.0 h1:i69S2XI7uG1u4NLGeJPSYU++Nmjvpo9nwd6aoEm7gkA=
122github.com/charmbracelet/x/exp/strings v0.1.0/go.mod h1:/ehtMPNh9K4odGFkqYJKpIYyePhdp1hLBRvyY4bWkH8=
122github.com/charmbracelet/x/exp/strings v0.1.0/go.mod h1:/ehtMPNh9K4odGFkqYJKpIYyePhdp1hLBRvyY4bWkH8=
123github.com/charmbracelet/x/json v0.2.0 h1:DqB+ZGx2h+Z+1s98HOuOyli+i97wsFQIxP2ZQANTPrQ=
123github.com/charmbracelet/x/json v0.2.0 h1:DqB+ZGx2h+Z+1s98HOuOyli+i97wsFQIxP2ZQANTPrQ=
internal/config/load.go+5
@@ -331,6 +331,11 @@ func (c *Config) configureProviders(env env.Env, resolver VariableResolver, know
331
331
332 c.Providers.Set(id, providerConfig)
332 c.Providers.Set(id, providerConfig)
333 }
333 }
334+
335+ if c.Providers.Len() == 0 && c.Options.DisableDefaultProviders {
336+ return fmt.Errorf("default providers are disabled and there are no custom providers are configured")
337+ }
338+
334 return nil
339 return nil
335}
340}
336
341
internal/config/load_test.go+3−3
@@ -1127,7 +1127,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1127 })
1127 })
1128 resolver := NewEnvironmentVariableResolver(env)
1128 resolver := NewEnvironmentVariableResolver(env)
1129 err := cfg.configureProviders(env, resolver, knownProviders)
1129 err := cfg.configureProviders(env, resolver, knownProviders)
1130− require.NoError(t, err)
1130+ require.ErrorContains(t, err, "no custom providers")
1131
1131
1132 // openai should NOT be present because it lacks base_url and models.
1132 // openai should NOT be present because it lacks base_url and models.
1133 require.Equal(t, 0, cfg.Providers.Len())
1133 require.Equal(t, 0, cfg.Providers.Len())
@@ -1252,7 +1252,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1252 env := env.NewFromMap(map[string]string{})
1252 env := env.NewFromMap(map[string]string{})
1253 resolver := NewEnvironmentVariableResolver(env)
1253 resolver := NewEnvironmentVariableResolver(env)
1254 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
1254 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
1255− require.NoError(t, err)
1255+ require.ErrorContains(t, err, "no custom providers")
1256
1256
1257 // Provider should be rejected for missing models.
1257 // Provider should be rejected for missing models.
1258 require.Equal(t, 0, cfg.Providers.Len())
1258 require.Equal(t, 0, cfg.Providers.Len())
@@ -1276,7 +1276,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1276 env := env.NewFromMap(map[string]string{})
1276 env := env.NewFromMap(map[string]string{})
1277 resolver := NewEnvironmentVariableResolver(env)
1277 resolver := NewEnvironmentVariableResolver(env)
1278 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
1278 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
1279− require.NoError(t, err)
1279+ require.ErrorContains(t, err, "no custom providers")
1280
1280
1281 // Provider should be rejected for missing base_url.
1281 // Provider should be rejected for missing base_url.
1282 require.Equal(t, 0, cfg.Providers.Len())
1282 require.Equal(t, 0, cfg.Providers.Len())
internal/ui/dialog/models.go+9−28
@@ -4,7 +4,6 @@ import (
4 "cmp"
4 "cmp"
5 "fmt"
5 "fmt"
6 "slices"
6 "slices"
7− "strings"
8
7
9 "charm.land/bubbles/v2/help"
8 "charm.land/bubbles/v2/help"
10 "charm.land/bubbles/v2/key"
9 "charm.land/bubbles/v2/key"
@@ -15,6 +14,7 @@ import (
15 "github.com/charmbracelet/crush/internal/ui/common"
14 "github.com/charmbracelet/crush/internal/ui/common"
16 "github.com/charmbracelet/crush/internal/ui/util"
15 "github.com/charmbracelet/crush/internal/ui/util"
17 uv "github.com/charmbracelet/ultraviolet"
16 uv "github.com/charmbracelet/ultraviolet"
17+ xslice "github.com/charmbracelet/x/exp/slice"
18)
18)
19
19
20// ModelType represents the type of model to select.
20// ModelType represents the type of model to select.
@@ -143,12 +143,14 @@ func NewModels(com *common.Common, isOnboarding bool) (*Models, error) {
143 )
143 )
144 m.keyMap.Close = CloseKey
144 m.keyMap.Close = CloseKey
145
145
146− providers, err := getFilteredProviders(com.Config())
146+ m.providers = slices.Collect(
147− if err != nil {
147+ xslice.Map(
148− return nil, fmt.Errorf("failed to get providers: %w", err)
148+ com.Config().Providers.Seq(),
149+ func(pc config.ProviderConfig) catwalk.Provider {
150+ return pc.ToProvider()
149− }
151+ },
150−
152+ ),
151− m.providers = providers
153+ )
152 if err := m.setProviderItems(); err != nil {
154 if err := m.setProviderItems(); err != nil {
153 return nil, fmt.Errorf("failed to set provider items: %w", err)
155 return nil, fmt.Errorf("failed to set provider items: %w", err)
154 }
156 }
@@ -521,27 +523,6 @@ func (m *Models) setProviderItems() error {
521 return nil
523 return nil
522}
524}
523
525
524−func getFilteredProviders(cfg *config.Config) ([]catwalk.Provider, error) {
525− providers, err := config.Providers(cfg)
526− if err != nil {
527− return nil, fmt.Errorf("failed to get providers: %w", err)
528− }
529− var filteredProviders []catwalk.Provider
530− for _, p := range providers {
531− var (
532− isAzure = p.ID == catwalk.InferenceProviderAzure
533− isCopilot = p.ID == catwalk.InferenceProviderCopilot
534− isHyper = string(p.ID) == "hyper"
535− hasAPIKeyEnv = strings.HasPrefix(p.APIKey, "$")
536− _, isConfigured = cfg.Providers.Get(string(p.ID))
537− )
538− if isAzure || isCopilot || isHyper || hasAPIKeyEnv || isConfigured {
539− filteredProviders = append(filteredProviders, p)
540− }
541− }
542− return filteredProviders, nil
543−}
544−
545func modelKey(providerID, modelID string) string {
526func modelKey(providerID, modelID string) string {
546 if providerID == "" || modelID == "" {
527 if providerID == "" || modelID == "" {
547 return ""
528 return ""