55 "testing"
66
77 "github.com/stretchr/testify/assert"
8+
9+ "github.com/docker/cagent/pkg/config/latest"
810)
911
1012type mockEnvProvider struct {
@@ -175,7 +177,7 @@ func TestAutoModelConfig(t *testing.T) {
175177 "ANTHROPIC_API_KEY" : "test-key" ,
176178 },
177179 expectedProvider : "anthropic" ,
178- expectedModel : "claude-sonnet-4-0 " ,
180+ expectedModel : "claude-sonnet-4-5 " ,
179181 expectedMaxTokens : 32000 ,
180182 },
181183 {
@@ -217,7 +219,7 @@ func TestAutoModelConfig(t *testing.T) {
217219 envVars : map [string ]string {},
218220 gateway : "gateway:8080" ,
219221 expectedProvider : "anthropic" ,
220- expectedModel : "claude-sonnet-4-0 " ,
222+ expectedModel : "claude-sonnet-4-5 " ,
221223 expectedMaxTokens : 32000 ,
222224 },
223225 }
@@ -226,7 +228,7 @@ func TestAutoModelConfig(t *testing.T) {
226228 t .Run (tt .name , func (t * testing.T ) {
227229 t .Parallel ()
228230
229- modelConfig := AutoModelConfig (t .Context (), tt .gateway , & mockEnvProvider {envVars : tt .envVars })
231+ modelConfig := AutoModelConfig (t .Context (), tt .gateway , & mockEnvProvider {envVars : tt .envVars }, nil )
230232
231233 assert .Equal (t , tt .expectedProvider , modelConfig .Provider )
232234 assert .Equal (t , tt .expectedModel , modelConfig .Model )
@@ -295,7 +297,7 @@ func TestDefaultModels(t *testing.T) {
295297
296298 // Test specific model values
297299 assert .Equal (t , "gpt-5-mini" , DefaultModels ["openai" ])
298- assert .Equal (t , "claude-sonnet-4-0 " , DefaultModels ["anthropic" ])
300+ assert .Equal (t , "claude-sonnet-4-5 " , DefaultModels ["anthropic" ])
299301 assert .Equal (t , "gemini-2.5-flash" , DefaultModels ["google" ])
300302 assert .Equal (t , "ai/qwen3:latest" , DefaultModels ["dmr" ])
301303 assert .Equal (t , "mistral-small-latest" , DefaultModels ["mistral" ])
@@ -326,7 +328,7 @@ func TestAutoModelConfig_IntegrationWithDefaultModels(t *testing.T) {
326328 envVars ["MISTRAL_API_KEY" ] = "test-key"
327329 }
328330
329- modelConfig := AutoModelConfig (t .Context (), "" , & mockEnvProvider {envVars : envVars })
331+ modelConfig := AutoModelConfig (t .Context (), "" , & mockEnvProvider {envVars : envVars }, nil )
330332
331333 // Verify the returned model matches the DefaultModels entry
332334 expectedModel := DefaultModels [provider ]
@@ -339,7 +341,7 @@ func TestAutoModelConfig_IntegrationWithDefaultModels(t *testing.T) {
339341 t .Run ("dmr" , func (t * testing.T ) {
340342 t .Parallel ()
341343
342- modelConfig := AutoModelConfig (t .Context (), "" , & mockEnvProvider {envVars : map [string ]string {}})
344+ modelConfig := AutoModelConfig (t .Context (), "" , & mockEnvProvider {envVars : map [string ]string {}}, nil )
343345
344346 assert .Equal (t , "dmr" , modelConfig .Provider )
345347 assert .Equal (t , DefaultModels ["dmr" ], modelConfig .Model )
@@ -399,3 +401,100 @@ func TestAvailableProviders_PrecedenceOrder(t *testing.T) {
399401 providers = AvailableProviders (t .Context (), "" , env )
400402 assert .Equal (t , "dmr" , providers [0 ])
401403}
404+
405+ func TestAutoModelConfig_UserDefaultModel (t * testing.T ) {
406+ t .Parallel ()
407+
408+ tests := []struct {
409+ name string
410+ defaultModel * latest.ModelConfig
411+ envVars map [string ]string
412+ expectedProvider string
413+ expectedModel string
414+ expectedMaxTokens int64
415+ }{
416+ {
417+ name : "user default model overrides auto detection" ,
418+ defaultModel : & latest.ModelConfig {Provider : "openai" , Model : "gpt-4o" },
419+ envVars : map [string ]string {"ANTHROPIC_API_KEY" : "test-key" },
420+ expectedProvider : "openai" ,
421+ expectedModel : "gpt-4o" ,
422+ expectedMaxTokens : 32000 ,
423+ },
424+ {
425+ name : "user default model with dmr provider" ,
426+ defaultModel : & latest.ModelConfig {Provider : "dmr" , Model : "ai/llama3.2" },
427+ envVars : map [string ]string {"OPENAI_API_KEY" : "test-key" },
428+ expectedProvider : "dmr" ,
429+ expectedModel : "ai/llama3.2" ,
430+ expectedMaxTokens : 16000 ,
431+ },
432+ {
433+ name : "user default model with anthropic provider" ,
434+ defaultModel : & latest.ModelConfig {Provider : "anthropic" , Model : "claude-sonnet-4-0" },
435+ envVars : map [string ]string {},
436+ expectedProvider : "anthropic" ,
437+ expectedModel : "claude-sonnet-4-0" ,
438+ expectedMaxTokens : 32000 ,
439+ },
440+ {
441+ name : "nil default model falls back to auto detection" ,
442+ defaultModel : nil ,
443+ envVars : map [string ]string {"GOOGLE_API_KEY" : "test-key" },
444+ expectedProvider : "google" ,
445+ expectedModel : "gemini-2.5-flash" ,
446+ expectedMaxTokens : 32000 ,
447+ },
448+ {
449+ name : "empty provider falls back to auto detection" ,
450+ defaultModel : & latest.ModelConfig {Provider : "" , Model : "model-only" },
451+ envVars : map [string ]string {"MISTRAL_API_KEY" : "test-key" },
452+ expectedProvider : "mistral" ,
453+ expectedModel : "mistral-small-latest" ,
454+ expectedMaxTokens : 32000 ,
455+ },
456+ {
457+ name : "empty model falls back to auto detection" ,
458+ defaultModel : & latest.ModelConfig {Provider : "openai" , Model : "" },
459+ envVars : map [string ]string {"ANTHROPIC_API_KEY" : "test-key" },
460+ expectedProvider : "anthropic" ,
461+ expectedModel : "claude-sonnet-4-5" ,
462+ expectedMaxTokens : 32000 ,
463+ },
464+ }
465+
466+ for _ , tt := range tests {
467+ t .Run (tt .name , func (t * testing.T ) {
468+ t .Parallel ()
469+
470+ modelConfig := AutoModelConfig (t .Context (), "" , & mockEnvProvider {envVars : tt .envVars }, tt .defaultModel )
471+
472+ assert .Equal (t , tt .expectedProvider , modelConfig .Provider )
473+ assert .Equal (t , tt .expectedModel , modelConfig .Model )
474+ assert .Equal (t , tt .expectedMaxTokens , * modelConfig .MaxTokens )
475+ })
476+ }
477+ }
478+
479+ func TestAutoModelConfig_UserDefaultModelWithOptions (t * testing.T ) {
480+ t .Parallel ()
481+
482+ // Test that user-provided options like max_tokens, thinking_budget are preserved
483+ customMaxTokens := int64 (64000 )
484+ thinkingBudget := & latest.ThinkingBudget {Tokens : 10000 }
485+
486+ defaultModel := & latest.ModelConfig {
487+ Provider : "anthropic" ,
488+ Model : "claude-sonnet-4-5" ,
489+ MaxTokens : & customMaxTokens ,
490+ ThinkingBudget : thinkingBudget ,
491+ }
492+
493+ modelConfig := AutoModelConfig (t .Context (), "" , & mockEnvProvider {envVars : map [string ]string {}}, defaultModel )
494+
495+ assert .Equal (t , "anthropic" , modelConfig .Provider )
496+ assert .Equal (t , "claude-sonnet-4-5" , modelConfig .Model )
497+ assert .Equal (t , int64 (64000 ), * modelConfig .MaxTokens )
498+ assert .NotNil (t , modelConfig .ThinkingBudget )
499+ assert .Equal (t , 10000 , modelConfig .ThinkingBudget .Tokens )
500+ }
0 commit comments