@@ -2,11 +2,54 @@ package config
22
33import (
44 "context"
5+ "fmt"
6+ "strings"
57
68 "github.com/docker/cagent/pkg/config/latest"
79 "github.com/docker/cagent/pkg/environment"
810)
911
12+ // providerConfig defines a cloud provider and how to detect/describe its API keys.
13+ type providerConfig struct {
14+ name string // provider name (e.g., "anthropic")
15+ envVars []string // env vars to check - provider is available if ANY is set
16+ hint string // description for error messages
17+ }
18+
19+ // cloudProviders defines the available cloud providers in priority order.
20+ // The first provider with a configured API key will be selected by AutoModelConfig.
21+ // DMR is always appended as the final fallback (not listed here).
22+ var cloudProviders = []providerConfig {
23+ {"anthropic" , []string {"ANTHROPIC_API_KEY" }, "ANTHROPIC_API_KEY" },
24+ {"openai" , []string {"OPENAI_API_KEY" }, "OPENAI_API_KEY" },
25+ {"google" , []string {"GOOGLE_API_KEY" }, "GOOGLE_API_KEY" },
26+ {"mistral" , []string {"MISTRAL_API_KEY" }, "MISTRAL_API_KEY" },
27+ {"amazon-bedrock" , []string {
28+ "AWS_BEARER_TOKEN_BEDROCK" ,
29+ "AWS_ACCESS_KEY_ID" ,
30+ "AWS_PROFILE" ,
31+ "AWS_ROLE_ARN" ,
32+ }, "AWS_ACCESS_KEY_ID (or AWS_PROFILE, AWS_ROLE_ARN, AWS_BEARER_TOKEN_BEDROCK)" },
33+ }
34+
35+ // ErrAutoModelFallback is returned when auto model selection fails because
36+ // no providers are available (no API keys configured and DMR not installed).
37+ type ErrAutoModelFallback struct {}
38+
39+ func (e * ErrAutoModelFallback ) Error () string {
40+ var hints []string
41+ for _ , p := range cloudProviders {
42+ hints = append (hints , fmt .Sprintf (" - %s: %s" , p .name , p .hint ))
43+ }
44+
45+ return fmt .Sprintf (`No model providers available.
46+
47+ To fix this, you can:
48+ - Install Docker Model Runner: https://docs.docker.com/ai/model-runner/get-started/
49+ - Configure an API key for a cloud provider:
50+ %s` , strings .Join (hints , "\n " ))
51+ }
52+
1053var DefaultModels = map [string ]string {
1154 "openai" : "gpt-5-mini" ,
1255 "anthropic" : "claude-sonnet-4-0" ,
@@ -24,29 +67,16 @@ func AvailableProviders(ctx context.Context, modelsGateway string, env environme
2467
2568 var providers []string
2669
27- if key , _ := env .Get (ctx , "ANTHROPIC_API_KEY" ); key != "" {
28- providers = append (providers , "anthropic" )
29- }
30- if key , _ := env .Get (ctx , "OPENAI_API_KEY" ); key != "" {
31- providers = append (providers , "openai" )
32- }
33- if key , _ := env .Get (ctx , "GOOGLE_API_KEY" ); key != "" {
34- providers = append (providers , "google" )
35- }
36- if key , _ := env .Get (ctx , "MISTRAL_API_KEY" ); key != "" {
37- providers = append (providers , "mistral" )
38- }
39- // AWS Bedrock supports multiple authentication methods (API key, IAM credentials, profile, role)
40- if key , _ := env .Get (ctx , "AWS_BEARER_TOKEN_BEDROCK" ); key != "" {
41- providers = append (providers , "amazon-bedrock" )
42- } else if key , _ := env .Get (ctx , "AWS_ACCESS_KEY_ID" ); key != "" {
43- providers = append (providers , "amazon-bedrock" )
44- } else if key , _ := env .Get (ctx , "AWS_PROFILE" ); key != "" {
45- providers = append (providers , "amazon-bedrock" )
46- } else if key , _ := env .Get (ctx , "AWS_ROLE_ARN" ); key != "" {
47- providers = append (providers , "amazon-bedrock" )
70+ for _ , p := range cloudProviders {
71+ for _ , envVar := range p .envVars {
72+ if key , _ := env .Get (ctx , envVar ); key != "" {
73+ providers = append (providers , p .name )
74+ break // found one, no need to check other env vars for this provider
75+ }
76+ }
4877 }
4978
79+ // DMR is always the final fallback
5080 providers = append (providers , "dmr" )
5181
5282 return providers
0 commit comments