@@ -1,8 +1,11 @@
1package config
1package config
8 "path/filepath"
11 "path/filepath"
@@ -317,7 +320,7 @@ func TestConfig_configureProviders(t *testing.T) {
317 "OPENAI_API_KEY": "test-key",
320 "OPENAI_API_KEY": "test-key",
319 resolver := NewShellVariableResolver(env)
322 resolver := NewShellVariableResolver(env)
320− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
323+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
321 require.NoError(t, err)
324 require.NoError(t, err)
322 require.Equal(t, 1, cfg.Providers.Len())
325 require.Equal(t, 1, cfg.Providers.Len())
@@ -360,7 +363,7 @@ func TestConfig_configureProvidersWithOverride(t *testing.T) {
360 "OPENAI_API_KEY": "test-key",
363 "OPENAI_API_KEY": "test-key",
362 resolver := NewShellVariableResolver(env)
365 resolver := NewShellVariableResolver(env)
363− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
366+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
364 require.NoError(t, err)
367 require.NoError(t, err)
365 require.Equal(t, 1, cfg.Providers.Len())
368 require.Equal(t, 1, cfg.Providers.Len())
@@ -402,7 +405,7 @@ func TestConfig_configureProvidersWithNewProvider(t *testing.T) {
402 "OPENAI_API_KEY": "test-key",
405 "OPENAI_API_KEY": "test-key",
404 resolver := NewShellVariableResolver(env)
407 resolver := NewShellVariableResolver(env)
405− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
408+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
406 require.NoError(t, err)
409 require.NoError(t, err)
407 // Should be to because of the env variable
410 // Should be to because of the env variable
408 require.Equal(t, cfg.Providers.Len(), 2)
411 require.Equal(t, cfg.Providers.Len(), 2)
@@ -438,7 +441,7 @@ func TestConfig_configureProvidersBedrockWithCredentials(t *testing.T) {
438 "AWS_SECRET_ACCESS_KEY": "test-secret-key",
441 "AWS_SECRET_ACCESS_KEY": "test-secret-key",
440 resolver := NewShellVariableResolver(env)
443 resolver := NewShellVariableResolver(env)
441− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
444+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
442 require.NoError(t, err)
445 require.NoError(t, err)
443 require.Equal(t, cfg.Providers.Len(), 1)
446 require.Equal(t, cfg.Providers.Len(), 1)
@@ -464,7 +467,7 @@ func TestConfig_configureProvidersBedrockWithoutCredentials(t *testing.T) {
464 cfg.setDefaults("/tmp", "")
467 cfg.setDefaults("/tmp", "")
465 env := env.NewFromMap(map[string]string{})
468 env := env.NewFromMap(map[string]string{})
466 resolver := NewShellVariableResolver(env)
469 resolver := NewShellVariableResolver(env)
467− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
470+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
468 require.NoError(t, err)
471 require.NoError(t, err)
469 // Provider should not be configured without credentials
472 // Provider should not be configured without credentials
470 require.Equal(t, cfg.Providers.Len(), 0)
473 require.Equal(t, cfg.Providers.Len(), 0)
@@ -489,7 +492,7 @@ func TestConfig_configureProvidersVertexAIWithCredentials(t *testing.T) {
489 "VERTEXAI_LOCATION": "us-central1",
492 "VERTEXAI_LOCATION": "us-central1",
491 resolver := NewShellVariableResolver(env)
494 resolver := NewShellVariableResolver(env)
492− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
495+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
493 require.NoError(t, err)
496 require.NoError(t, err)
494 require.Equal(t, cfg.Providers.Len(), 1)
497 require.Equal(t, cfg.Providers.Len(), 1)
@@ -521,7 +524,7 @@ func TestConfig_configureProvidersVertexAIWithoutCredentials(t *testing.T) {
521 "GOOGLE_CLOUD_LOCATION": "us-central1",
524 "GOOGLE_CLOUD_LOCATION": "us-central1",
523 resolver := NewShellVariableResolver(env)
526 resolver := NewShellVariableResolver(env)
524− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
527+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
525 require.NoError(t, err)
528 require.NoError(t, err)
526 // Provider should not be configured without proper credentials
529 // Provider should not be configured without proper credentials
527 require.Equal(t, cfg.Providers.Len(), 0)
530 require.Equal(t, cfg.Providers.Len(), 0)
@@ -546,7 +549,7 @@ func TestConfig_configureProvidersVertexAIMissingProject(t *testing.T) {
546 "GOOGLE_CLOUD_LOCATION": "us-central1",
549 "GOOGLE_CLOUD_LOCATION": "us-central1",
548 resolver := NewShellVariableResolver(env)
551 resolver := NewShellVariableResolver(env)
549− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
552+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
550 require.NoError(t, err)
553 require.NoError(t, err)
551 // Provider should not be configured without project
554 // Provider should not be configured without project
552 require.Equal(t, cfg.Providers.Len(), 0)
555 require.Equal(t, cfg.Providers.Len(), 0)
@@ -570,7 +573,7 @@ func TestConfig_configureProvidersSetProviderID(t *testing.T) {
570 "OPENAI_API_KEY": "test-key",
573 "OPENAI_API_KEY": "test-key",
572 resolver := NewShellVariableResolver(env)
575 resolver := NewShellVariableResolver(env)
573− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
576+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
574 require.NoError(t, err)
577 require.NoError(t, err)
575 require.Equal(t, cfg.Providers.Len(), 1)
578 require.Equal(t, cfg.Providers.Len(), 1)
@@ -761,7 +764,7 @@ func TestConfig_configureProvidersWithDisabledProvider(t *testing.T) {
761 "OPENAI_API_KEY": "test-key",
764 "OPENAI_API_KEY": "test-key",
763 resolver := NewShellVariableResolver(env)
766 resolver := NewShellVariableResolver(env)
764− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
767+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
765 require.NoError(t, err)
768 require.NoError(t, err)
767 require.Equal(t, cfg.Providers.Len(), 1)
770 require.Equal(t, cfg.Providers.Len(), 1)
@@ -789,7 +792,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
790 env := env.NewFromMap(map[string]string{})
793 env := env.NewFromMap(map[string]string{})
791 resolver := NewShellVariableResolver(env)
794 resolver := NewShellVariableResolver(env)
792− err := cfg.configureProviders(testStore(cfg), env, resolver, []catwalk.Provider{})
795+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
793 require.NoError(t, err)
796 require.NoError(t, err)
795 require.Equal(t, cfg.Providers.Len(), 1)
798 require.Equal(t, cfg.Providers.Len(), 1)
@@ -812,7 +815,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
813 env := env.NewFromMap(map[string]string{})
816 env := env.NewFromMap(map[string]string{})
814 resolver := NewShellVariableResolver(env)
817 resolver := NewShellVariableResolver(env)
815− err := cfg.configureProviders(testStore(cfg), env, resolver, []catwalk.Provider{})
818+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
816 require.NoError(t, err)
819 require.NoError(t, err)
818 require.Equal(t, cfg.Providers.Len(), 0)
821 require.Equal(t, cfg.Providers.Len(), 0)
@@ -820,7 +823,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
820 require.False(t, exists)
823 require.False(t, exists)
823− t.Run("custom provider with no models is removed", func(t *testing.T) {
826+ t.Run("custom provider with no models attempts discovery and is removed on failure", func(t *testing.T) {
824 cfg := &Config{
827 cfg := &Config{
825 Providers: csync.NewMapFrom(map[string]ProviderConfig{
828 Providers: csync.NewMapFrom(map[string]ProviderConfig{
826 "custom": {
829 "custom": {
@@ -834,14 +837,142 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
835 env := env.NewFromMap(map[string]string{})
838 env := env.NewFromMap(map[string]string{})
836 resolver := NewShellVariableResolver(env)
839 resolver := NewShellVariableResolver(env)
837− err := cfg.configureProviders(testStore(cfg), env, resolver, []catwalk.Provider{})
840+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
838 require.NoError(t, err)
841 require.NoError(t, err)
843+ // Discovery fails (unreachable URL) so provider is removed.
840− require.Equal(t, cfg.Providers.Len(), 0)
844+ require.Equal(t, 0, cfg.Providers.Len())
845+ _, exists := cfg.Providers.Get("custom")
846+ require.False(t, exists)
849+ t.Run("custom provider with no models and discover_models:false is removed", func(t *testing.T) {
850+ discoverFalse := false
852+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
855+ BaseURL: "https://api.custom.com/v1",
856+ Models: []catwalk.Model{},
857+ AutoDiscoverModels: &discoverFalse,
861+ cfg.setDefaults("/tmp", "")
863+ env := env.NewFromMap(map[string]string{})
864+ resolver := NewShellVariableResolver(env)
865+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
866+ require.NoError(t, err)
868+ require.Equal(t, 0, cfg.Providers.Len())
841 _, exists := cfg.Providers.Get("custom")
869 _, exists := cfg.Providers.Get("custom")
842 require.False(t, exists)
870 require.False(t, exists)
873+ t.Run("custom provider with models and discover_models:true merges discovered models", func(t *testing.T) {
874+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
875+ w.Header().Set("Content-Type", "application/json")
876+ _, _ = w.Write([]byte(`{"data": [
877+ {"id": "existing-model", "object": "model"},
878+ {"id": "discovered-model", "object": "model"}
881+ defer server.Close()
883+ discoverTrue := true
885+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
888+ BaseURL: server.URL + "/v1",
889+ Models: []catwalk.Model{
890+ {ID: "existing-model", Name: "My Custom Name", ContextWindow: 200000},
892+ AutoDiscoverModels: &discoverTrue,
896+ cfg.setDefaults("/tmp", "")
898+ env := env.NewFromMap(map[string]string{})
899+ resolver := NewShellVariableResolver(env)
900+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
901+ require.NoError(t, err)
903+ require.Equal(t, 1, cfg.Providers.Len())
904+ p, exists := cfg.Providers.Get("custom")
905+ require.True(t, exists)
906+ require.Len(t, p.Models, 2)
908+ // User-specified model keeps its custom fields.
909+ require.Equal(t, "existing-model", p.Models[0].ID)
910+ require.Equal(t, "My Custom Name", p.Models[0].Name)
911+ require.Equal(t, int64(200000), p.Models[0].ContextWindow)
913+ // Discovered model is appended.
914+ require.Equal(t, "discovered-model", p.Models[1].ID)
917+ t.Run("custom provider with models and no discover_models uses only listed models", func(t *testing.T) {
919+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
922+ BaseURL: "https://api.custom.com/v1",
923+ Models: []catwalk.Model{
924+ {ID: "my-model", Name: "My Model"},
929+ cfg.setDefaults("/tmp", "")
931+ env := env.NewFromMap(map[string]string{})
932+ resolver := NewShellVariableResolver(env)
933+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
934+ require.NoError(t, err)
936+ require.Equal(t, 1, cfg.Providers.Len())
937+ p, exists := cfg.Providers.Get("custom")
938+ require.True(t, exists)
939+ require.Len(t, p.Models, 1)
940+ require.Equal(t, "my-model", p.Models[0].ID)
943+ t.Run("custom provider with no models auto-discovers successfully", func(t *testing.T) {
944+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
945+ w.Header().Set("Content-Type", "application/json")
946+ _, _ = w.Write([]byte(`{"data": [
947+ {"id": "auto-model-a", "object": "model"},
948+ {"id": "auto-model-b", "object": "model"}
951+ defer server.Close()
954+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
957+ BaseURL: server.URL + "/v1",
961+ cfg.setDefaults("/tmp", "")
963+ env := env.NewFromMap(map[string]string{})
964+ resolver := NewShellVariableResolver(env)
965+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
966+ require.NoError(t, err)
968+ require.Equal(t, 1, cfg.Providers.Len())
969+ p, exists := cfg.Providers.Get("custom")
970+ require.True(t, exists)
971+ require.Len(t, p.Models, 2)
972+ require.Equal(t, "auto-model-a", p.Models[0].ID)
973+ require.Equal(t, "auto-model-b", p.Models[1].ID)
845 t.Run("custom provider with unsupported type is removed", func(t *testing.T) {
976 t.Run("custom provider with unsupported type is removed", func(t *testing.T) {
846 cfg := &Config{
977 cfg := &Config{
847 Providers: csync.NewMapFrom(map[string]ProviderConfig{
978 Providers: csync.NewMapFrom(map[string]ProviderConfig{
@@ -859,7 +990,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
860 env := env.NewFromMap(map[string]string{})
991 env := env.NewFromMap(map[string]string{})
861 resolver := NewShellVariableResolver(env)
992 resolver := NewShellVariableResolver(env)
862− err := cfg.configureProviders(testStore(cfg), env, resolver, []catwalk.Provider{})
993+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
863 require.NoError(t, err)
994 require.NoError(t, err)
865 require.Equal(t, cfg.Providers.Len(), 0)
996 require.Equal(t, cfg.Providers.Len(), 0)
@@ -884,7 +1015,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
885 env := env.NewFromMap(map[string]string{})
1016 env := env.NewFromMap(map[string]string{})
886 resolver := NewShellVariableResolver(env)
1017 resolver := NewShellVariableResolver(env)
887− err := cfg.configureProviders(testStore(cfg), env, resolver, []catwalk.Provider{})
1018+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
888 require.NoError(t, err)
1019 require.NoError(t, err)
890 require.Equal(t, cfg.Providers.Len(), 1)
1021 require.Equal(t, cfg.Providers.Len(), 1)
@@ -912,7 +1043,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
913 env := env.NewFromMap(map[string]string{})
1044 env := env.NewFromMap(map[string]string{})
914 resolver := NewShellVariableResolver(env)
1045 resolver := NewShellVariableResolver(env)
915− err := cfg.configureProviders(testStore(cfg), env, resolver, []catwalk.Provider{})
1046+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
916 require.NoError(t, err)
1047 require.NoError(t, err)
918 require.Equal(t, cfg.Providers.Len(), 1)
1049 require.Equal(t, cfg.Providers.Len(), 1)
@@ -942,7 +1073,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
943 env := env.NewFromMap(map[string]string{})
1074 env := env.NewFromMap(map[string]string{})
944 resolver := NewShellVariableResolver(env)
1075 resolver := NewShellVariableResolver(env)
945− err := cfg.configureProviders(testStore(cfg), env, resolver, []catwalk.Provider{})
1076+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
946 require.NoError(t, err)
1077 require.NoError(t, err)
948 require.Equal(t, cfg.Providers.Len(), 0)
1079 require.Equal(t, cfg.Providers.Len(), 0)
@@ -977,7 +1108,7 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
977 "GOOGLE_GENAI_USE_VERTEXAI": "false",
1108 "GOOGLE_GENAI_USE_VERTEXAI": "false",
979 resolver := NewShellVariableResolver(env)
1110 resolver := NewShellVariableResolver(env)
980− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1111+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
981 require.NoError(t, err)
1112 require.NoError(t, err)
983 require.Equal(t, cfg.Providers.Len(), 0)
1114 require.Equal(t, cfg.Providers.Len(), 0)
@@ -1008,7 +1139,7 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
1009 env := env.NewFromMap(map[string]string{})
1140 env := env.NewFromMap(map[string]string{})
1010 resolver := NewShellVariableResolver(env)
1141 resolver := NewShellVariableResolver(env)
1011− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1142+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1012 require.NoError(t, err)
1143 require.NoError(t, err)
1014 require.Equal(t, cfg.Providers.Len(), 0)
1145 require.Equal(t, cfg.Providers.Len(), 0)
@@ -1039,7 +1170,7 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
1040 env := env.NewFromMap(map[string]string{})
1171 env := env.NewFromMap(map[string]string{})
1041 resolver := NewShellVariableResolver(env)
1172 resolver := NewShellVariableResolver(env)
1042− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1173+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1043 require.NoError(t, err)
1174 require.NoError(t, err)
1045 require.Equal(t, cfg.Providers.Len(), 0)
1176 require.Equal(t, cfg.Providers.Len(), 0)
@@ -1072,7 +1203,7 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
1072 "OPENAI_API_KEY": "test-key",
1203 "OPENAI_API_KEY": "test-key",
1074 resolver := NewShellVariableResolver(env)
1205 resolver := NewShellVariableResolver(env)
1075− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1206+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1076 require.NoError(t, err)
1207 require.NoError(t, err)
1078 require.Equal(t, cfg.Providers.Len(), 1)
1209 require.Equal(t, cfg.Providers.Len(), 1)
@@ -1106,7 +1237,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
1106 cfg.setDefaults("/tmp", "")
1237 cfg.setDefaults("/tmp", "")
1107 env := env.NewFromMap(map[string]string{})
1238 env := env.NewFromMap(map[string]string{})
1108 resolver := NewShellVariableResolver(env)
1239 resolver := NewShellVariableResolver(env)
1109− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1240+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1110 require.NoError(t, err)
1241 require.NoError(t, err)
1112 large, small, err := cfg.defaultModelSelection(knownProviders)
1243 large, small, err := cfg.defaultModelSelection(knownProviders)
@@ -1142,7 +1273,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
1142 cfg.setDefaults("/tmp", "")
1273 cfg.setDefaults("/tmp", "")
1143 env := env.NewFromMap(map[string]string{})
1274 env := env.NewFromMap(map[string]string{})
1144 resolver := NewShellVariableResolver(env)
1275 resolver := NewShellVariableResolver(env)
1145− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1276+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1146 require.NoError(t, err)
1277 require.NoError(t, err)
1148 _, _, err = cfg.defaultModelSelection(knownProviders)
1279 _, _, err = cfg.defaultModelSelection(knownProviders)
@@ -1172,7 +1303,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
1172 cfg.setDefaults("/tmp", "")
1303 cfg.setDefaults("/tmp", "")
1173 env := env.NewFromMap(map[string]string{})
1304 env := env.NewFromMap(map[string]string{})
1174 resolver := NewShellVariableResolver(env)
1305 resolver := NewShellVariableResolver(env)
1175− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1306+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1176 require.NoError(t, err)
1307 require.NoError(t, err)
1177 _, _, err = cfg.defaultModelSelection(knownProviders)
1308 _, _, err = cfg.defaultModelSelection(knownProviders)
1178 require.NoError(t, err)
1309 require.NoError(t, err)
@@ -1215,7 +1346,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
1215 cfg.setDefaults("/tmp", "")
1346 cfg.setDefaults("/tmp", "")
1216 env := env.NewFromMap(map[string]string{})
1347 env := env.NewFromMap(map[string]string{})
1217 resolver := NewShellVariableResolver(env)
1348 resolver := NewShellVariableResolver(env)
1218− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1349+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1219 require.NoError(t, err)
1350 require.NoError(t, err)
1220 large, small, err := cfg.defaultModelSelection(knownProviders)
1351 large, small, err := cfg.defaultModelSelection(knownProviders)
1221 require.NoError(t, err)
1352 require.NoError(t, err)
@@ -1259,7 +1390,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
1259 cfg.setDefaults("/tmp", "")
1390 cfg.setDefaults("/tmp", "")
1260 env := env.NewFromMap(map[string]string{})
1391 env := env.NewFromMap(map[string]string{})
1261 resolver := NewShellVariableResolver(env)
1392 resolver := NewShellVariableResolver(env)
1262− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1393+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1263 require.NoError(t, err)
1394 require.NoError(t, err)
1264 _, _, err = cfg.defaultModelSelection(knownProviders)
1395 _, _, err = cfg.defaultModelSelection(knownProviders)
1265 require.Error(t, err)
1396 require.Error(t, err)
@@ -1301,7 +1432,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
1301 cfg.setDefaults("/tmp", "")
1432 cfg.setDefaults("/tmp", "")
1302 env := env.NewFromMap(map[string]string{})
1433 env := env.NewFromMap(map[string]string{})
1303 resolver := NewShellVariableResolver(env)
1434 resolver := NewShellVariableResolver(env)
1304− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1435+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1305 require.NoError(t, err)
1436 require.NoError(t, err)
1306 large, small, err := cfg.defaultModelSelection(knownProviders)
1437 large, small, err := cfg.defaultModelSelection(knownProviders)
1307 require.NoError(t, err)
1438 require.NoError(t, err)
@@ -1346,7 +1477,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1346 "OPENAI_API_KEY": "test-key",
1477 "OPENAI_API_KEY": "test-key",
1348 resolver := NewShellVariableResolver(env)
1479 resolver := NewShellVariableResolver(env)
1349− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1480+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1350 require.ErrorContains(t, err, "no custom providers")
1481 require.ErrorContains(t, err, "no custom providers")
1352 // openai should NOT be present because it lacks base_url and models.
1483 // openai should NOT be present because it lacks base_url and models.
@@ -1389,7 +1520,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1389 "OPENAI_API_KEY": "test-key",
1520 "OPENAI_API_KEY": "test-key",
1391 resolver := NewShellVariableResolver(env)
1522 resolver := NewShellVariableResolver(env)
1392− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1523+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1393 require.NoError(t, err)
1524 require.NoError(t, err)
1395 // Only fully specified provider should be present.
1526 // Only fully specified provider should be present.
@@ -1443,7 +1574,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1443 "ANTHROPIC_API_KEY": "test-key",
1574 "ANTHROPIC_API_KEY": "test-key",
1445 resolver := NewShellVariableResolver(env)
1576 resolver := NewShellVariableResolver(env)
1446− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1577+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1447 require.NoError(t, err)
1578 require.NoError(t, err)
1449 // Both providers should be present.
1580 // Both providers should be present.
@@ -1454,7 +1585,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1454 require.True(t, exists, "anthropic should be present")
1585 require.True(t, exists, "anthropic should be present")
1457− t.Run("when enabled, provider missing models is rejected", func(t *testing.T) {
1588+ t.Run("when enabled, provider missing models attempts discovery but still triggers no-custom-providers error", func(t *testing.T) {
1458 cfg := &Config{
1589 cfg := &Config{
1459 Options: &Options{
1590 Options: &Options{
1460 DisableDefaultProviders: true,
1591 DisableDefaultProviders: true,
@@ -1471,10 +1602,10 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1472 env := env.NewFromMap(map[string]string{})
1603 env := env.NewFromMap(map[string]string{})
1473 resolver := NewShellVariableResolver(env)
1604 resolver := NewShellVariableResolver(env)
1474− err := cfg.configureProviders(testStore(cfg), env, resolver, []catwalk.Provider{})
1605+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
1475 require.ErrorContains(t, err, "no custom providers")
1606 require.ErrorContains(t, err, "no custom providers")
1477− // Provider should be rejected for missing models.
1608+ // Discovery fails (unreachable URL) so provider is removed.
1478 require.Equal(t, 0, cfg.Providers.Len())
1609 require.Equal(t, 0, cfg.Providers.Len())
@@ -1495,7 +1626,7 @@ func TestConfig_configureProvidersDisableDefaultProviders(t *testing.T) {
1496 env := env.NewFromMap(map[string]string{})
1627 env := env.NewFromMap(map[string]string{})
1497 resolver := NewShellVariableResolver(env)
1628 resolver := NewShellVariableResolver(env)
1498− err := cfg.configureProviders(testStore(cfg), env, resolver, []catwalk.Provider{})
1629+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, []catwalk.Provider{})
1499 require.ErrorContains(t, err, "no custom providers")
1630 require.ErrorContains(t, err, "no custom providers")
1501 // Provider should be rejected for missing base_url.
1632 // Provider should be rejected for missing base_url.
@@ -1553,7 +1684,7 @@ func TestConfig_configureSelectedModels(t *testing.T) {
1553 store := &ConfigStore{config: cfg, globalDataPath: globalPath}
1684 store := &ConfigStore{config: cfg, globalDataPath: globalPath}
1554 env := env.NewFromMap(map[string]string{})
1685 env := env.NewFromMap(map[string]string{})
1555 resolver := NewShellVariableResolver(env)
1686 resolver := NewShellVariableResolver(env)
1556− err := cfg.configureProviders(store, env, resolver, knownProviders)
1687+ err := cfg.configureProviders(context.Background(), store, env, resolver, knownProviders)
1557 require.NoError(t, err)
1688 require.NoError(t, err)
1559 err = configureSelectedModels(store, knownProviders, false)
1690 err = configureSelectedModels(store, knownProviders, false)
@@ -1603,7 +1734,7 @@ func TestConfig_configureSelectedModels(t *testing.T) {
1603 cfg.setDefaults("/tmp", "")
1734 cfg.setDefaults("/tmp", "")
1604 env := env.NewFromMap(map[string]string{})
1735 env := env.NewFromMap(map[string]string{})
1605 resolver := NewShellVariableResolver(env)
1736 resolver := NewShellVariableResolver(env)
1606− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1737+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1607 require.NoError(t, err)
1738 require.NoError(t, err)
1609 err = configureSelectedModels(testStore(cfg), knownProviders, true)
1740 err = configureSelectedModels(testStore(cfg), knownProviders, true)
@@ -1665,7 +1796,7 @@ func TestConfig_configureSelectedModels(t *testing.T) {
1665 cfg.setDefaults("/tmp", "")
1796 cfg.setDefaults("/tmp", "")
1666 env := env.NewFromMap(map[string]string{})
1797 env := env.NewFromMap(map[string]string{})
1667 resolver := NewShellVariableResolver(env)
1798 resolver := NewShellVariableResolver(env)
1668− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1799+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1669 require.NoError(t, err)
1800 require.NoError(t, err)
1671 err = configureSelectedModels(testStore(cfg), knownProviders, true)
1802 err = configureSelectedModels(testStore(cfg), knownProviders, true)
@@ -1710,7 +1841,7 @@ func TestConfig_configureSelectedModels(t *testing.T) {
1710 cfg.setDefaults("/tmp", "")
1841 cfg.setDefaults("/tmp", "")
1711 env := env.NewFromMap(map[string]string{})
1842 env := env.NewFromMap(map[string]string{})
1712 resolver := NewShellVariableResolver(env)
1843 resolver := NewShellVariableResolver(env)
1713− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1844+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1714 require.NoError(t, err)
1845 require.NoError(t, err)
1716 err = configureSelectedModels(testStore(cfg), knownProviders, true)
1847 err = configureSelectedModels(testStore(cfg), knownProviders, true)
@@ -1749,7 +1880,7 @@ func TestConfig_configureProviders_HyperAPIKeyFromEnv(t *testing.T) {
1749 "HYPER_API_KEY": "env-api-key",
1880 "HYPER_API_KEY": "env-api-key",
1751 resolver := NewShellVariableResolver(env)
1882 resolver := NewShellVariableResolver(env)
1752− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1883+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1753 require.NoError(t, err)
1884 require.NoError(t, err)
1754 require.Equal(t, 1, cfg.Providers.Len())
1885 require.Equal(t, 1, cfg.Providers.Len())
@@ -1796,7 +1927,7 @@ func TestConfig_configureProviders_HyperAPIKeyFromConfigOverrides(t *testing.T)
1796 "HYPER_API_KEY": "env-api-key",
1927 "HYPER_API_KEY": "env-api-key",
1798 resolver := NewShellVariableResolver(env)
1929 resolver := NewShellVariableResolver(env)
1799− err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1930+ err := cfg.configureProviders(context.Background(), testStore(cfg), env, resolver, knownProviders)
1800 require.NoError(t, err)
1931 require.NoError(t, err)
1801 require.Equal(t, 1, cfg.Providers.Len())
1932 require.Equal(t, 1, cfg.Providers.Len())
@@ -1839,7 +1970,7 @@ func TestConfig_configureProviders_ProviderHeaderResolveError(t *testing.T) {
1840 resolver := NewShellVariableResolver(testEnv)
1971 resolver := NewShellVariableResolver(testEnv)
1842− err := cfg.configureProviders(testStore(cfg), testEnv, resolver, knownProviders)
1973+ err := cfg.configureProviders(context.Background(), testStore(cfg), testEnv, resolver, knownProviders)
1843 require.Error(t, err, "failing $(cmd) in a header must fail the provider load")
1974 require.Error(t, err, "failing $(cmd) in a header must fail the provider load")
1844 require.Contains(t, err.Error(), "X-Broken", "error must name the offending header")
1975 require.Contains(t, err.Error(), "X-Broken", "error must name the offending header")
@@ -1871,7 +2002,7 @@ func TestConfig_configureProviders_CatwalkDefaultWithUnsetVarLoads(t *testing.T)
1872 resolver := NewShellVariableResolver(testEnv)
2003 resolver := NewShellVariableResolver(testEnv)
1874− err := cfg.configureProviders(testStore(cfg), testEnv, resolver, knownProviders)
2005+ err := cfg.configureProviders(context.Background(), testStore(cfg), testEnv, resolver, knownProviders)
1875 require.NoError(t, err, "optional env-gated header must not fail the load")
2006 require.NoError(t, err, "optional env-gated header must not fail the load")
1877 pc, ok := cfg.Providers.Get("openai")
2008 pc, ok := cfg.Providers.Get("openai")
@@ -1907,7 +2038,7 @@ func TestConfig_configureProviders_LiteralEmptyHeaderDropped(t *testing.T) {
1908 resolver := NewShellVariableResolver(testEnv)
2039 resolver := NewShellVariableResolver(testEnv)
1910− err := cfg.configureProviders(testStore(cfg), testEnv, resolver, []catwalk.Provider{})
2041+ err := cfg.configureProviders(context.Background(), testStore(cfg), testEnv, resolver, []catwalk.Provider{})
1911 require.NoError(t, err)
2042 require.NoError(t, err)
1913 pc, ok := cfg.Providers.Get("my-llm")
2044 pc, ok := cfg.Providers.Get("my-llm")
@@ -1944,7 +2075,7 @@ func TestConfig_configureProviders_EchoEmptyHeaderDropped(t *testing.T) {
1945 resolver := NewShellVariableResolver(testEnv)
2076 resolver := NewShellVariableResolver(testEnv)
1947− err := cfg.configureProviders(testStore(cfg), testEnv, resolver, knownProviders)
2078+ err := cfg.configureProviders(context.Background(), testStore(cfg), testEnv, resolver, knownProviders)
1948 require.NoError(t, err)
2079 require.NoError(t, err)
1950 pc, ok := cfg.Providers.Get("openai")
2081 pc, ok := cfg.Providers.Get("openai")
@@ -1992,7 +2123,7 @@ func TestConfig_configureProviders_UnsetAPIKeySkipsProvider(t *testing.T) {
1993 resolver := NewShellVariableResolver(testEnv)
2124 resolver := NewShellVariableResolver(testEnv)
1995− err := cfg.configureProviders(testStore(cfg), testEnv, resolver, knownProviders)
2126+ err := cfg.configureProviders(context.Background(), testStore(cfg), testEnv, resolver, knownProviders)
1996 require.NoError(t, err, "skip path must not surface as a load error")
2127 require.NoError(t, err, "skip path must not surface as a load error")
1998 require.Equal(t, 0, cfg.Providers.Len(), "provider with unset API key must be skipped")
2129 require.Equal(t, 0, cfg.Providers.Len(), "provider with unset API key must be skipped")
@@ -2030,7 +2161,7 @@ func TestConfig_configureProviders_FailingAPIKeyCmdSkipsProvider(t *testing.T) {
2031 resolver := NewShellVariableResolver(testEnv)
2162 resolver := NewShellVariableResolver(testEnv)
2033− err := cfg.configureProviders(testStore(cfg), testEnv, resolver, knownProviders)
2164+ err := cfg.configureProviders(context.Background(), testStore(cfg), testEnv, resolver, knownProviders)
2034 require.NoError(t, err, "failing $(cmd) in API key must skip provider, not fail load")
2165 require.NoError(t, err, "failing $(cmd) in API key must skip provider, not fail load")
2036 require.Equal(t, 0, cfg.Providers.Len(), "provider with failing $(cmd) API key must be skipped")
2167 require.Equal(t, 0, cfg.Providers.Len(), "provider with failing $(cmd) API key must be skipped")
@@ -2067,7 +2198,7 @@ func TestConfig_configureProviders_UnsetAzureEndpointSkipsProvider(t *testing.T)
2068 resolver := NewShellVariableResolver(testEnv)
2199 resolver := NewShellVariableResolver(testEnv)
2070− err := cfg.configureProviders(testStore(cfg), testEnv, resolver, knownProviders)
2201+ err := cfg.configureProviders(context.Background(), testStore(cfg), testEnv, resolver, knownProviders)
2071 require.NoError(t, err)
2202 require.NoError(t, err)
2073 require.Equal(t, 0, cfg.Providers.Len(), "azure provider with unset endpoint must be skipped")
2204 require.Equal(t, 0, cfg.Providers.Len(), "azure provider with unset endpoint must be skipped")