@@ -1094,6 +1094,217 @@ func TestConfig_defaultModelSelection(t *testing.T) {
1097+func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1098+ t.Run("when enabled, ignores all default providers and requires full specification", func(t *testing.T) {
1099+ knownProviders := []catwalk.Provider{
1102+ APIKey: "$OPENAI_API_KEY",
1103+ APIEndpoint: "https://api.openai.com/v1",
1104+ Models: []catwalk.Model{{
1110+ // User references openai but doesn't fully specify it (no base_url, no
1111+ // models). This should be rejected because disable_default_providers
1112+ // treats all providers as custom.
1115+ DisableDefaultProviders: true,
1117+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
1119+ APIKey: "$OPENAI_API_KEY",
1123+ cfg.setDefaults("/tmp", "")
1125+ env := env.NewFromMap(map[string]string{
1126+ "OPENAI_API_KEY": "test-key",
1128+ resolver := NewEnvironmentVariableResolver(env)
1129+ err := cfg.configureProviders(env, resolver, knownProviders)
1130+ require.NoError(t, err)
1132+ // openai should NOT be present because it lacks base_url and models.
1133+ require.Equal(t, 0, cfg.Providers.Len())
1134+ _, exists := cfg.Providers.Get("openai")
1135+ require.False(t, exists, "openai should not be present without full specification")
1138+ t.Run("when enabled, fully specified providers work", func(t *testing.T) {
1139+ knownProviders := []catwalk.Provider{
1142+ APIKey: "$OPENAI_API_KEY",
1143+ APIEndpoint: "https://api.openai.com/v1",
1144+ Models: []catwalk.Model{{
1150+ // User fully specifies their provider.
1153+ DisableDefaultProviders: true,
1155+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
1157+ APIKey: "$MY_API_KEY",
1158+ BaseURL: "https://my-llm.example.com/v1",
1159+ Models: []catwalk.Model{{
1165+ cfg.setDefaults("/tmp", "")
1167+ env := env.NewFromMap(map[string]string{
1168+ "MY_API_KEY": "test-key",
1169+ "OPENAI_API_KEY": "test-key",
1171+ resolver := NewEnvironmentVariableResolver(env)
1172+ err := cfg.configureProviders(env, resolver, knownProviders)
1173+ require.NoError(t, err)
1175+ // Only fully specified provider should be present.
1176+ require.Equal(t, 1, cfg.Providers.Len())
1177+ provider, exists := cfg.Providers.Get("my-llm")
1178+ require.True(t, exists, "my-llm should be present")
1179+ require.Equal(t, "https://my-llm.example.com/v1", provider.BaseURL)
1180+ require.Len(t, provider.Models, 1)
1182+ // Default openai should NOT be present.
1183+ _, exists = cfg.Providers.Get("openai")
1184+ require.False(t, exists, "openai should not be present")
1187+ t.Run("when disabled, includes all known providers with valid credentials", func(t *testing.T) {
1188+ knownProviders := []catwalk.Provider{
1191+ APIKey: "$OPENAI_API_KEY",
1192+ APIEndpoint: "https://api.openai.com/v1",
1193+ Models: []catwalk.Model{{
1199+ APIKey: "$ANTHROPIC_API_KEY",
1200+ APIEndpoint: "https://api.anthropic.com/v1",
1201+ Models: []catwalk.Model{{
1207+ // User only configures openai, both API keys are available, but option
1211+ DisableDefaultProviders: false,
1213+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
1215+ APIKey: "$OPENAI_API_KEY",
1219+ cfg.setDefaults("/tmp", "")
1221+ env := env.NewFromMap(map[string]string{
1222+ "OPENAI_API_KEY": "test-key",
1223+ "ANTHROPIC_API_KEY": "test-key",
1225+ resolver := NewEnvironmentVariableResolver(env)
1226+ err := cfg.configureProviders(env, resolver, knownProviders)
1227+ require.NoError(t, err)
1229+ // Both providers should be present.
1230+ require.Equal(t, 2, cfg.Providers.Len())
1231+ _, exists := cfg.Providers.Get("openai")
1232+ require.True(t, exists, "openai should be present")
1233+ _, exists = cfg.Providers.Get("anthropic")
1234+ require.True(t, exists, "anthropic should be present")
1237+ t.Run("when enabled, provider missing models is rejected", func(t *testing.T) {
1240+ DisableDefaultProviders: true,
1242+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
1244+ APIKey: "test-key",
1245+ BaseURL: "https://my-llm.example.com/v1",
1246+ Models: []catwalk.Model{}, // No models.
1250+ cfg.setDefaults("/tmp", "")
1252+ env := env.NewFromMap(map[string]string{})
1253+ resolver := NewEnvironmentVariableResolver(env)
1254+ err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
1255+ require.NoError(t, err)
1257+ // Provider should be rejected for missing models.
1258+ require.Equal(t, 0, cfg.Providers.Len())
1261+ t.Run("when enabled, provider missing base_url is rejected", func(t *testing.T) {
1264+ DisableDefaultProviders: true,
1266+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
1268+ APIKey: "test-key",
1269+ Models: []catwalk.Model{{ID: "model"}},
1274+ cfg.setDefaults("/tmp", "")
1276+ env := env.NewFromMap(map[string]string{})
1277+ resolver := NewEnvironmentVariableResolver(env)
1278+ err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
1279+ require.NoError(t, err)
1281+ // Provider should be rejected for missing base_url.
1282+ require.Equal(t, 0, cfg.Providers.Len())
1286+func TestConfig_setDefaultsDisableDefaultProvidersEnvVar(t *testing.T) {
1287+ t.Run("sets option from environment variable", func(t *testing.T) {
1288+ t.Setenv("CRUSH_DISABLE_DEFAULT_PROVIDERS", "true")
1291+ cfg.setDefaults("/tmp", "")
1293+ require.True(t, cfg.Options.DisableDefaultProviders)
1296+ t.Run("does not override when env var is not set", func(t *testing.T) {
1299+ DisableDefaultProviders: true,
1302+ cfg.setDefaults("/tmp", "")
1304+ require.True(t, cfg.Options.DisableDefaultProviders)
1097func TestConfig_configureSelectedModels(t *testing.T) {
1308func TestConfig_configureSelectedModels(t *testing.T) {
1098 t.Run("should override defaults", func(t *testing.T) {
1309 t.Run("should override defaults", func(t *testing.T) {
1099 knownProviders := []catwalk.Provider{
1310 knownProviders := []catwalk.Provider{