@@ -9,6 +9,7 @@ import (
11 "github.com/charmbracelet/catwalk/pkg/catwalk"
11 "github.com/charmbracelet/catwalk/pkg/catwalk"
12+ "github.com/charmbracelet/crush/internal/csync"
12 "github.com/charmbracelet/crush/internal/env"
13 "github.com/charmbracelet/crush/internal/env"
13 "github.com/stretchr/testify/assert"
14 "github.com/stretchr/testify/assert"
@@ -29,9 +30,10 @@ func TestConfig_LoadFromReaders(t *testing.T) {
30 assert.NoError(t, err)
31 assert.NoError(t, err)
31 assert.NotNil(t, loadedConfig)
32 assert.NotNil(t, loadedConfig)
33+ assert.Equal(t, 1, loadedConfig.Providers.Len())
32− assert.Len(t, loadedConfig.Providers, 1)
34+ pc, _ := loadedConfig.Providers.Get("openai")
33− assert.Equal(t, "key2", loadedConfig.Providers["openai"].APIKey)
35+ assert.Equal(t, "key2", pc.APIKey)
34− assert.Equal(t, "https://api.openai.com/v2", loadedConfig.Providers["openai"].BaseURL)
36+ assert.Equal(t, "https://api.openai.com/v2", pc.BaseURL)
37func TestConfig_setDefaults(t *testing.T) {
39func TestConfig_setDefaults(t *testing.T) {
@@ -73,10 +75,11 @@ func TestConfig_configureProviders(t *testing.T) {
73 resolver := NewEnvironmentVariableResolver(env)
75 resolver := NewEnvironmentVariableResolver(env)
74 err := cfg.configureProviders(env, resolver, knownProviders)
76 err := cfg.configureProviders(env, resolver, knownProviders)
75 assert.NoError(t, err)
77 assert.NoError(t, err)
76− assert.Len(t, cfg.Providers, 1)
78+ assert.Equal(t, 1, cfg.Providers.Len())
78 // We want to make sure that we keep the configured API key as a placeholder
80 // We want to make sure that we keep the configured API key as a placeholder
81+ pc, _ := cfg.Providers.Get("openai")
79− assert.Equal(t, "$OPENAI_API_KEY", cfg.Providers["openai"].APIKey)
82+ assert.Equal(t, "$OPENAI_API_KEY", pc.APIKey)
82func TestConfig_configureProvidersWithOverride(t *testing.T) {
85func TestConfig_configureProvidersWithOverride(t *testing.T) {
@@ -92,22 +95,21 @@ func TestConfig_configureProvidersWithOverride(t *testing.T) {
94 cfg := &Config{
97 cfg := &Config{
95− Providers: map[string]ProviderConfig{
98+ Providers: csync.NewMap[string, ProviderConfig](),
100+ cfg.Providers.Set("openai", ProviderConfig{
97− APIKey: "xyz",
101+ APIKey: "xyz",
98− BaseURL: "https://api.openai.com/v2",
102+ BaseURL: "https://api.openai.com/v2",
99− Models: []catwalk.Model{
103+ Models: []catwalk.Model{
101− ID: "test-model",
105+ ID: "test-model",
102− Name: "Updated",
106+ Name: "Updated",
105− ID: "another-model",
109+ ID: "another-model",
111 cfg.setDefaults("/tmp")
113 cfg.setDefaults("/tmp")
113 env := env.NewFromMap(map[string]string{
115 env := env.NewFromMap(map[string]string{
@@ -116,13 +118,14 @@ func TestConfig_configureProvidersWithOverride(t *testing.T) {
116 resolver := NewEnvironmentVariableResolver(env)
118 resolver := NewEnvironmentVariableResolver(env)
117 err := cfg.configureProviders(env, resolver, knownProviders)
119 err := cfg.configureProviders(env, resolver, knownProviders)
118 assert.NoError(t, err)
120 assert.NoError(t, err)
119− assert.Len(t, cfg.Providers, 1)
121+ assert.Equal(t, 1, cfg.Providers.Len())
121 // We want to make sure that we keep the configured API key as a placeholder
123 // We want to make sure that we keep the configured API key as a placeholder
124+ pc, _ := cfg.Providers.Get("openai")
122− assert.Equal(t, "xyz", cfg.Providers["openai"].APIKey)
125+ assert.Equal(t, "xyz", pc.APIKey)
123− assert.Equal(t, "https://api.openai.com/v2", cfg.Providers["openai"].BaseURL)
126+ assert.Equal(t, "https://api.openai.com/v2", pc.BaseURL)
124− assert.Len(t, cfg.Providers["openai"].Models, 2)
127+ assert.Len(t, pc.Models, 2)
125− assert.Equal(t, "Updated", cfg.Providers["openai"].Models[0].Name)
128+ assert.Equal(t, "Updated", pc.Models[0].Name)
128func TestConfig_configureProvidersWithNewProvider(t *testing.T) {
131func TestConfig_configureProvidersWithNewProvider(t *testing.T) {
@@ -138,7 +141,7 @@ func TestConfig_configureProvidersWithNewProvider(t *testing.T) {
140 cfg := &Config{
143 cfg := &Config{
141− Providers: map[string]ProviderConfig{
144+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
142 "custom": {
145 "custom": {
143 APIKey: "xyz",
146 APIKey: "xyz",
144 BaseURL: "https://api.someendpoint.com/v2",
147 BaseURL: "https://api.someendpoint.com/v2",
@@ -148,7 +151,7 @@ func TestConfig_configureProvidersWithNewProvider(t *testing.T) {
153 cfg.setDefaults("/tmp")
156 cfg.setDefaults("/tmp")
154 env := env.NewFromMap(map[string]string{
157 env := env.NewFromMap(map[string]string{
@@ -158,16 +161,17 @@ func TestConfig_configureProvidersWithNewProvider(t *testing.T) {
158 err := cfg.configureProviders(env, resolver, knownProviders)
161 err := cfg.configureProviders(env, resolver, knownProviders)
159 assert.NoError(t, err)
162 assert.NoError(t, err)
160 // Should be to because of the env variable
163 // Should be to because of the env variable
161− assert.Len(t, cfg.Providers, 2)
164+ assert.Equal(t, cfg.Providers.Len(), 2)
163 // We want to make sure that we keep the configured API key as a placeholder
166 // We want to make sure that we keep the configured API key as a placeholder
167+ pc, _ := cfg.Providers.Get("custom")
164− assert.Equal(t, "xyz", cfg.Providers["custom"].APIKey)
168+ assert.Equal(t, "xyz", pc.APIKey)
165 // Make sure we set the ID correctly
169 // Make sure we set the ID correctly
166− assert.Equal(t, "custom", cfg.Providers["custom"].ID)
170+ assert.Equal(t, "custom", pc.ID)
167− assert.Equal(t, "https://api.someendpoint.com/v2", cfg.Providers["custom"].BaseURL)
171+ assert.Equal(t, "https://api.someendpoint.com/v2", pc.BaseURL)
168− assert.Len(t, cfg.Providers["custom"].Models, 1)
172+ assert.Len(t, pc.Models, 1)
170− _, ok := cfg.Providers["openai"]
174+ _, ok := cfg.Providers.Get("openai")
171 assert.True(t, ok, "OpenAI provider should still be present")
175 assert.True(t, ok, "OpenAI provider should still be present")
@@ -192,9 +196,9 @@ func TestConfig_configureProvidersBedrockWithCredentials(t *testing.T) {
192 resolver := NewEnvironmentVariableResolver(env)
196 resolver := NewEnvironmentVariableResolver(env)
193 err := cfg.configureProviders(env, resolver, knownProviders)
197 err := cfg.configureProviders(env, resolver, knownProviders)
194 assert.NoError(t, err)
198 assert.NoError(t, err)
195− assert.Len(t, cfg.Providers, 1)
199+ assert.Equal(t, cfg.Providers.Len(), 1)
197− bedrockProvider, ok := cfg.Providers["bedrock"]
201+ bedrockProvider, ok := cfg.Providers.Get("bedrock")
198 assert.True(t, ok, "Bedrock provider should be present")
202 assert.True(t, ok, "Bedrock provider should be present")
199 assert.Len(t, bedrockProvider.Models, 1)
203 assert.Len(t, bedrockProvider.Models, 1)
200 assert.Equal(t, "anthropic.claude-sonnet-4-20250514-v1:0", bedrockProvider.Models[0].ID)
204 assert.Equal(t, "anthropic.claude-sonnet-4-20250514-v1:0", bedrockProvider.Models[0].ID)
@@ -219,7 +223,7 @@ func TestConfig_configureProvidersBedrockWithoutCredentials(t *testing.T) {
219 err := cfg.configureProviders(env, resolver, knownProviders)
223 err := cfg.configureProviders(env, resolver, knownProviders)
220 assert.NoError(t, err)
224 assert.NoError(t, err)
221 // Provider should not be configured without credentials
225 // Provider should not be configured without credentials
222− assert.Len(t, cfg.Providers, 0)
226+ assert.Equal(t, cfg.Providers.Len(), 0)
225func TestConfig_configureProvidersBedrockWithoutUnsupportedModel(t *testing.T) {
229func TestConfig_configureProvidersBedrockWithoutUnsupportedModel(t *testing.T) {
@@ -267,9 +271,9 @@ func TestConfig_configureProvidersVertexAIWithCredentials(t *testing.T) {
267 resolver := NewEnvironmentVariableResolver(env)
271 resolver := NewEnvironmentVariableResolver(env)
268 err := cfg.configureProviders(env, resolver, knownProviders)
272 err := cfg.configureProviders(env, resolver, knownProviders)
269 assert.NoError(t, err)
273 assert.NoError(t, err)
270− assert.Len(t, cfg.Providers, 1)
274+ assert.Equal(t, cfg.Providers.Len(), 1)
272− vertexProvider, ok := cfg.Providers["vertexai"]
276+ vertexProvider, ok := cfg.Providers.Get("vertexai")
273 assert.True(t, ok, "VertexAI provider should be present")
277 assert.True(t, ok, "VertexAI provider should be present")
274 assert.Len(t, vertexProvider.Models, 1)
278 assert.Len(t, vertexProvider.Models, 1)
275 assert.Equal(t, "gemini-pro", vertexProvider.Models[0].ID)
279 assert.Equal(t, "gemini-pro", vertexProvider.Models[0].ID)
@@ -300,7 +304,7 @@ func TestConfig_configureProvidersVertexAIWithoutCredentials(t *testing.T) {
300 err := cfg.configureProviders(env, resolver, knownProviders)
304 err := cfg.configureProviders(env, resolver, knownProviders)
301 assert.NoError(t, err)
305 assert.NoError(t, err)
302 // Provider should not be configured without proper credentials
306 // Provider should not be configured without proper credentials
303− assert.Len(t, cfg.Providers, 0)
307+ assert.Equal(t, cfg.Providers.Len(), 0)
306func TestConfig_configureProvidersVertexAIMissingProject(t *testing.T) {
310func TestConfig_configureProvidersVertexAIMissingProject(t *testing.T) {
@@ -325,7 +329,7 @@ func TestConfig_configureProvidersVertexAIMissingProject(t *testing.T) {
325 err := cfg.configureProviders(env, resolver, knownProviders)
329 err := cfg.configureProviders(env, resolver, knownProviders)
326 assert.NoError(t, err)
330 assert.NoError(t, err)
327 // Provider should not be configured without project
331 // Provider should not be configured without project
328− assert.Len(t, cfg.Providers, 0)
332+ assert.Equal(t, cfg.Providers.Len(), 0)
331func TestConfig_configureProvidersSetProviderID(t *testing.T) {
335func TestConfig_configureProvidersSetProviderID(t *testing.T) {
@@ -348,16 +352,17 @@ func TestConfig_configureProvidersSetProviderID(t *testing.T) {
348 resolver := NewEnvironmentVariableResolver(env)
352 resolver := NewEnvironmentVariableResolver(env)
349 err := cfg.configureProviders(env, resolver, knownProviders)
353 err := cfg.configureProviders(env, resolver, knownProviders)
350 assert.NoError(t, err)
354 assert.NoError(t, err)
351− assert.Len(t, cfg.Providers, 1)
355+ assert.Equal(t, cfg.Providers.Len(), 1)
353 // Provider ID should be set
357 // Provider ID should be set
358+ pc, _ := cfg.Providers.Get("openai")
354− assert.Equal(t, "openai", cfg.Providers["openai"].ID)
359+ assert.Equal(t, "openai", pc.ID)
357func TestConfig_EnabledProviders(t *testing.T) {
362func TestConfig_EnabledProviders(t *testing.T) {
358 t.Run("all providers enabled", func(t *testing.T) {
363 t.Run("all providers enabled", func(t *testing.T) {
359 cfg := &Config{
364 cfg := &Config{
360− Providers: map[string]ProviderConfig{
365+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
361 "openai": {
366 "openai": {
362 ID: "openai",
367 ID: "openai",
363 APIKey: "key1",
368 APIKey: "key1",
@@ -368,7 +373,7 @@ func TestConfig_EnabledProviders(t *testing.T) {
368 APIKey: "key2",
373 APIKey: "key2",
369 Disable: false,
374 Disable: false,
374 enabled := cfg.EnabledProviders()
379 enabled := cfg.EnabledProviders()
@@ -377,7 +382,7 @@ func TestConfig_EnabledProviders(t *testing.T) {
378 t.Run("some providers disabled", func(t *testing.T) {
383 t.Run("some providers disabled", func(t *testing.T) {
379 cfg := &Config{
384 cfg := &Config{
380− Providers: map[string]ProviderConfig{
385+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
381 "openai": {
386 "openai": {
382 ID: "openai",
387 ID: "openai",
383 APIKey: "key1",
388 APIKey: "key1",
@@ -388,7 +393,7 @@ func TestConfig_EnabledProviders(t *testing.T) {
388 APIKey: "key2",
393 APIKey: "key2",
389 Disable: true,
394 Disable: true,
394 enabled := cfg.EnabledProviders()
399 enabled := cfg.EnabledProviders()
@@ -398,7 +403,7 @@ func TestConfig_EnabledProviders(t *testing.T) {
399 t.Run("empty providers map", func(t *testing.T) {
404 t.Run("empty providers map", func(t *testing.T) {
400 cfg := &Config{
405 cfg := &Config{
401− Providers: map[string]ProviderConfig{},
406+ Providers: csync.NewMap[string, ProviderConfig](),
404 enabled := cfg.EnabledProviders()
409 enabled := cfg.EnabledProviders()
@@ -409,13 +414,13 @@ func TestConfig_EnabledProviders(t *testing.T) {
409func TestConfig_IsConfigured(t *testing.T) {
414func TestConfig_IsConfigured(t *testing.T) {
410 t.Run("returns true when at least one provider is enabled", func(t *testing.T) {
415 t.Run("returns true when at least one provider is enabled", func(t *testing.T) {
411 cfg := &Config{
416 cfg := &Config{
412− Providers: map[string]ProviderConfig{
417+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
413 "openai": {
418 "openai": {
414 ID: "openai",
419 ID: "openai",
415 APIKey: "key1",
420 APIKey: "key1",
416 Disable: false,
421 Disable: false,
421 assert.True(t, cfg.IsConfigured())
426 assert.True(t, cfg.IsConfigured())
@@ -423,7 +428,7 @@ func TestConfig_IsConfigured(t *testing.T) {
424 t.Run("returns false when no providers are configured", func(t *testing.T) {
429 t.Run("returns false when no providers are configured", func(t *testing.T) {
425 cfg := &Config{
430 cfg := &Config{
426− Providers: map[string]ProviderConfig{},
431+ Providers: csync.NewMap[string, ProviderConfig](),
429 assert.False(t, cfg.IsConfigured())
434 assert.False(t, cfg.IsConfigured())
@@ -431,7 +436,7 @@ func TestConfig_IsConfigured(t *testing.T) {
432 t.Run("returns false when all providers are disabled", func(t *testing.T) {
437 t.Run("returns false when all providers are disabled", func(t *testing.T) {
433 cfg := &Config{
438 cfg := &Config{
434− Providers: map[string]ProviderConfig{
439+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
435 "openai": {
440 "openai": {
436 ID: "openai",
441 ID: "openai",
437 APIKey: "key1",
442 APIKey: "key1",
@@ -442,7 +447,7 @@ func TestConfig_IsConfigured(t *testing.T) {
442 APIKey: "key2",
447 APIKey: "key2",
443 Disable: true,
448 Disable: true,
448 assert.False(t, cfg.IsConfigured())
453 assert.False(t, cfg.IsConfigured())
@@ -462,11 +467,11 @@ func TestConfig_configureProvidersWithDisabledProvider(t *testing.T) {
464 cfg := &Config{
469 cfg := &Config{
465− Providers: map[string]ProviderConfig{
470+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
466 "openai": {
471 "openai": {
467 Disable: true,
472 Disable: true,
471 cfg.setDefaults("/tmp")
476 cfg.setDefaults("/tmp")
@@ -478,15 +483,15 @@ func TestConfig_configureProvidersWithDisabledProvider(t *testing.T) {
478 assert.NoError(t, err)
483 assert.NoError(t, err)
480 // Provider should be removed from config when disabled
485 // Provider should be removed from config when disabled
481− assert.Len(t, cfg.Providers, 0)
486+ assert.Equal(t, cfg.Providers.Len(), 0)
482− _, exists := cfg.Providers["openai"]
487+ _, exists := cfg.Providers.Get("openai")
483 assert.False(t, exists)
488 assert.False(t, exists)
486func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
491func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
487 t.Run("custom provider with missing API key is allowed, but not known providers", func(t *testing.T) {
492 t.Run("custom provider with missing API key is allowed, but not known providers", func(t *testing.T) {
488 cfg := &Config{
493 cfg := &Config{
489− Providers: map[string]ProviderConfig{
494+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
490 "custom": {
495 "custom": {
491 BaseURL: "https://api.custom.com/v1",
496 BaseURL: "https://api.custom.com/v1",
492 Models: []catwalk.Model{{
497 Models: []catwalk.Model{{
@@ -496,7 +501,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
496 "openai": {
501 "openai": {
497 APIKey: "$MISSING",
502 APIKey: "$MISSING",
501 cfg.setDefaults("/tmp")
506 cfg.setDefaults("/tmp")
@@ -505,21 +510,21 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
505 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
510 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
506 assert.NoError(t, err)
511 assert.NoError(t, err)
508− assert.Len(t, cfg.Providers, 1)
513+ assert.Equal(t, cfg.Providers.Len(), 1)
509− _, exists := cfg.Providers["custom"]
514+ _, exists := cfg.Providers.Get("custom")
510 assert.True(t, exists)
515 assert.True(t, exists)
513 t.Run("custom provider with missing BaseURL is removed", func(t *testing.T) {
518 t.Run("custom provider with missing BaseURL is removed", func(t *testing.T) {
514 cfg := &Config{
519 cfg := &Config{
515− Providers: map[string]ProviderConfig{
520+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
516 "custom": {
521 "custom": {
517 APIKey: "test-key",
522 APIKey: "test-key",
518 Models: []catwalk.Model{{
523 Models: []catwalk.Model{{
519 ID: "test-model",
524 ID: "test-model",
524 cfg.setDefaults("/tmp")
529 cfg.setDefaults("/tmp")
@@ -528,20 +533,20 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
528 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
533 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
529 assert.NoError(t, err)
534 assert.NoError(t, err)
531− assert.Len(t, cfg.Providers, 0)
536+ assert.Equal(t, cfg.Providers.Len(), 0)
532− _, exists := cfg.Providers["custom"]
537+ _, exists := cfg.Providers.Get("custom")
533 assert.False(t, exists)
538 assert.False(t, exists)
536 t.Run("custom provider with no models is removed", func(t *testing.T) {
541 t.Run("custom provider with no models is removed", func(t *testing.T) {
537 cfg := &Config{
542 cfg := &Config{
538− Providers: map[string]ProviderConfig{
543+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
539 "custom": {
544 "custom": {
540 APIKey: "test-key",
545 APIKey: "test-key",
541 BaseURL: "https://api.custom.com/v1",
546 BaseURL: "https://api.custom.com/v1",
542 Models: []catwalk.Model{},
547 Models: []catwalk.Model{},
546 cfg.setDefaults("/tmp")
551 cfg.setDefaults("/tmp")
@@ -550,14 +555,14 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
550 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
555 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
551 assert.NoError(t, err)
556 assert.NoError(t, err)
553− assert.Len(t, cfg.Providers, 0)
558+ assert.Equal(t, cfg.Providers.Len(), 0)
554− _, exists := cfg.Providers["custom"]
559+ _, exists := cfg.Providers.Get("custom")
555 assert.False(t, exists)
560 assert.False(t, exists)
558 t.Run("custom provider with unsupported type is removed", func(t *testing.T) {
563 t.Run("custom provider with unsupported type is removed", func(t *testing.T) {
559 cfg := &Config{
564 cfg := &Config{
560− Providers: map[string]ProviderConfig{
565+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
561 "custom": {
566 "custom": {
562 APIKey: "test-key",
567 APIKey: "test-key",
563 BaseURL: "https://api.custom.com/v1",
568 BaseURL: "https://api.custom.com/v1",
@@ -566,7 +571,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
566 ID: "test-model",
571 ID: "test-model",
571 cfg.setDefaults("/tmp")
576 cfg.setDefaults("/tmp")
@@ -575,14 +580,14 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
575 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
580 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
576 assert.NoError(t, err)
581 assert.NoError(t, err)
578− assert.Len(t, cfg.Providers, 0)
583+ assert.Equal(t, cfg.Providers.Len(), 0)
579− _, exists := cfg.Providers["custom"]
584+ _, exists := cfg.Providers.Get("custom")
580 assert.False(t, exists)
585 assert.False(t, exists)
583 t.Run("valid custom provider is kept and ID is set", func(t *testing.T) {
588 t.Run("valid custom provider is kept and ID is set", func(t *testing.T) {
584 cfg := &Config{
589 cfg := &Config{
585− Providers: map[string]ProviderConfig{
590+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
586 "custom": {
591 "custom": {
587 APIKey: "test-key",
592 APIKey: "test-key",
588 BaseURL: "https://api.custom.com/v1",
593 BaseURL: "https://api.custom.com/v1",
@@ -591,7 +596,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
591 ID: "test-model",
596 ID: "test-model",
596 cfg.setDefaults("/tmp")
601 cfg.setDefaults("/tmp")
@@ -600,8 +605,8 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
600 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
605 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
601 assert.NoError(t, err)
606 assert.NoError(t, err)
603− assert.Len(t, cfg.Providers, 1)
608+ assert.Equal(t, cfg.Providers.Len(), 1)
604− customProvider, exists := cfg.Providers["custom"]
609+ customProvider, exists := cfg.Providers.Get("custom")
605 assert.True(t, exists)
610 assert.True(t, exists)
606 assert.Equal(t, "custom", customProvider.ID)
611 assert.Equal(t, "custom", customProvider.ID)
607 assert.Equal(t, "test-key", customProvider.APIKey)
612 assert.Equal(t, "test-key", customProvider.APIKey)
@@ -610,7 +615,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
611 t.Run("disabled custom provider is removed", func(t *testing.T) {
616 t.Run("disabled custom provider is removed", func(t *testing.T) {
612 cfg := &Config{
617 cfg := &Config{
613− Providers: map[string]ProviderConfig{
618+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
614 "custom": {
619 "custom": {
615 APIKey: "test-key",
620 APIKey: "test-key",
616 BaseURL: "https://api.custom.com/v1",
621 BaseURL: "https://api.custom.com/v1",
@@ -620,7 +625,7 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
620 ID: "test-model",
625 ID: "test-model",
625 cfg.setDefaults("/tmp")
630 cfg.setDefaults("/tmp")
@@ -629,8 +634,8 @@ func TestConfig_configureProvidersCustomProviderValidation(t *testing.T) {
629 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
634 err := cfg.configureProviders(env, resolver, []catwalk.Provider{})
630 assert.NoError(t, err)
635 assert.NoError(t, err)
632− assert.Len(t, cfg.Providers, 0)
637+ assert.Equal(t, cfg.Providers.Len(), 0)
633− _, exists := cfg.Providers["custom"]
638+ _, exists := cfg.Providers.Get("custom")
634 assert.False(t, exists)
639 assert.False(t, exists)
@@ -649,11 +654,11 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
651 cfg := &Config{
656 cfg := &Config{
652− Providers: map[string]ProviderConfig{
657+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
653 "vertexai": {
658 "vertexai": {
654 BaseURL: "custom-url",
659 BaseURL: "custom-url",
658 cfg.setDefaults("/tmp")
663 cfg.setDefaults("/tmp")
@@ -664,8 +669,8 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
664 err := cfg.configureProviders(env, resolver, knownProviders)
669 err := cfg.configureProviders(env, resolver, knownProviders)
665 assert.NoError(t, err)
670 assert.NoError(t, err)
667− assert.Len(t, cfg.Providers, 0)
672+ assert.Equal(t, cfg.Providers.Len(), 0)
668− _, exists := cfg.Providers["vertexai"]
673+ _, exists := cfg.Providers.Get("vertexai")
669 assert.False(t, exists)
674 assert.False(t, exists)
@@ -682,11 +687,11 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
684 cfg := &Config{
689 cfg := &Config{
685− Providers: map[string]ProviderConfig{
690+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
686 "bedrock": {
691 "bedrock": {
687 BaseURL: "custom-url",
692 BaseURL: "custom-url",
691 cfg.setDefaults("/tmp")
696 cfg.setDefaults("/tmp")
@@ -695,8 +700,8 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
695 err := cfg.configureProviders(env, resolver, knownProviders)
700 err := cfg.configureProviders(env, resolver, knownProviders)
696 assert.NoError(t, err)
701 assert.NoError(t, err)
698− assert.Len(t, cfg.Providers, 0)
703+ assert.Equal(t, cfg.Providers.Len(), 0)
699− _, exists := cfg.Providers["bedrock"]
704+ _, exists := cfg.Providers.Get("bedrock")
700 assert.False(t, exists)
705 assert.False(t, exists)
@@ -713,11 +718,11 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
715 cfg := &Config{
720 cfg := &Config{
716− Providers: map[string]ProviderConfig{
721+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
717 "openai": {
722 "openai": {
718 BaseURL: "custom-url",
723 BaseURL: "custom-url",
722 cfg.setDefaults("/tmp")
727 cfg.setDefaults("/tmp")
@@ -726,8 +731,8 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
726 err := cfg.configureProviders(env, resolver, knownProviders)
731 err := cfg.configureProviders(env, resolver, knownProviders)
727 assert.NoError(t, err)
732 assert.NoError(t, err)
729− assert.Len(t, cfg.Providers, 0)
734+ assert.Equal(t, cfg.Providers.Len(), 0)
730− _, exists := cfg.Providers["openai"]
735+ _, exists := cfg.Providers.Get("openai")
731 assert.False(t, exists)
736 assert.False(t, exists)
@@ -744,11 +749,11 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
746 cfg := &Config{
751 cfg := &Config{
747− Providers: map[string]ProviderConfig{
752+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
748 "openai": {
753 "openai": {
749 APIKey: "test-key",
754 APIKey: "test-key",
753 cfg.setDefaults("/tmp")
758 cfg.setDefaults("/tmp")
@@ -759,8 +764,8 @@ func TestConfig_configureProvidersEnhancedCredentialValidation(t *testing.T) {
759 err := cfg.configureProviders(env, resolver, knownProviders)
764 err := cfg.configureProviders(env, resolver, knownProviders)
760 assert.NoError(t, err)
765 assert.NoError(t, err)
762− assert.Len(t, cfg.Providers, 1)
767+ assert.Equal(t, cfg.Providers.Len(), 1)
763− _, exists := cfg.Providers["openai"]
768+ _, exists := cfg.Providers.Get("openai")
764 assert.True(t, exists)
769 assert.True(t, exists)
@@ -883,7 +888,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
885 cfg := &Config{
890 cfg := &Config{
886− Providers: map[string]ProviderConfig{
891+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
887 "custom": {
892 "custom": {
888 APIKey: "test-key",
893 APIKey: "test-key",
889 BaseURL: "https://api.custom.com/v1",
894 BaseURL: "https://api.custom.com/v1",
@@ -894,7 +899,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
899 cfg.setDefaults("/tmp")
904 cfg.setDefaults("/tmp")
900 env := env.NewFromMap(map[string]string{})
905 env := env.NewFromMap(map[string]string{})
@@ -932,13 +937,13 @@ func TestConfig_defaultModelSelection(t *testing.T) {
934 cfg := &Config{
939 cfg := &Config{
935− Providers: map[string]ProviderConfig{
940+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
936 "custom": {
941 "custom": {
937 APIKey: "test-key",
942 APIKey: "test-key",
938 BaseURL: "https://api.custom.com/v1",
943 BaseURL: "https://api.custom.com/v1",
939 Models: []catwalk.Model{},
944 Models: []catwalk.Model{},
943 cfg.setDefaults("/tmp")
948 cfg.setDefaults("/tmp")
944 env := env.NewFromMap(map[string]string{})
949 env := env.NewFromMap(map[string]string{})
@@ -969,7 +974,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
971 cfg := &Config{
976 cfg := &Config{
972− Providers: map[string]ProviderConfig{
977+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
973 "custom": {
978 "custom": {
974 APIKey: "test-key",
979 APIKey: "test-key",
975 BaseURL: "https://api.custom.com/v1",
980 BaseURL: "https://api.custom.com/v1",
@@ -980,7 +985,7 @@ func TestConfig_defaultModelSelection(t *testing.T) {
985 cfg.setDefaults("/tmp")
990 cfg.setDefaults("/tmp")
986 env := env.NewFromMap(map[string]string{})
991 env := env.NewFromMap(map[string]string{})