fix(config): prevent default ModelList from overriding user config

When users provide a partial config (e.g., only model_name and api_key
without api_base), Go's JSON parser was reusing default ModelList values
at the same index position, causing wrong api_base to be used.

This fix:
1. Sets ModelList to nil in DefaultConfig() to avoid inheriting defaults
2. Adds GetDefaultModelList() function for first-time users
3. Applies default model list only when both ModelList and legacy providers
   are empty (new user scenario)

Closes #680
This commit is contained in:
opencode-assistant[bot] 2026-03-01 18:12:53 +08:00
parent f7136b6a5d
commit 63b8f97c0f
2 changed files with 170 additions and 154 deletions

View file

@ -617,6 +617,12 @@ func LoadConfig(path string) (*Config, error) {
cfg.ModelList = ConvertProvidersToModelList(cfg)
}
// If model_list is still empty and no legacy providers, use default model list
// This ensures new users get a working config template on first run
if len(cfg.ModelList) == 0 && !cfg.HasProvidersConfig() {
cfg.ModelList = GetDefaultModelList()
}
// Validate model_list for uniqueness and required fields
if err := cfg.ValidateModelList(); err != nil {
return nil, err

View file

@ -134,7 +134,73 @@ func DefaultConfig() *Config {
Providers: ProvidersConfig{
OpenAI: OpenAIProviderConfig{WebSearch: true},
},
ModelList: []ModelConfig{
// NOTE: ModelList is intentionally nil here to avoid inheriting default values
// when users provide partial config. The actual default model list is applied
// in LoadConfig when both ModelList and legacy providers are empty.
ModelList: nil,
Gateway: GatewayConfig{
Host: "127.0.0.1",
Port: 18790,
},
Tools: ToolsConfig{
MediaCleanup: MediaCleanupConfig{
Enabled: true,
MaxAge: 30,
Interval: 5,
},
Web: WebToolsConfig{
Proxy: "",
Brave: BraveConfig{
Enabled: false,
APIKey: "",
MaxResults: 5,
},
DuckDuckGo: DuckDuckGoConfig{
Enabled: true,
MaxResults: 5,
},
Perplexity: PerplexityConfig{
Enabled: false,
APIKey: "",
MaxResults: 5,
},
},
Cron: CronToolsConfig{
ExecTimeoutMinutes: 5,
},
Exec: ExecConfig{
EnableDenyPatterns: true,
},
Skills: SkillsToolsConfig{
Registries: SkillsRegistriesConfig{
ClawHub: ClawHubRegistryConfig{
Enabled: true,
BaseURL: "https://clawhub.ai",
},
},
MaxConcurrentSearches: 2,
SearchCache: SearchCacheConfig{
MaxSize: 50,
TTLSeconds: 300,
},
},
},
Heartbeat: HeartbeatConfig{
Enabled: true,
Interval: 30,
},
Devices: DevicesConfig{
Enabled: false,
MonitorUSB: true,
},
}
}
// GetDefaultModelList returns the default model list template for first-time users.
// This is separate from DefaultConfig to avoid the JSON parser inheriting default values
// when users provide partial configuration (issue #680).
func GetDefaultModelList() []ModelConfig {
return []ModelConfig{
// ============================================
// Add your API key to the model you want to use
// ============================================
@ -287,61 +353,5 @@ func DefaultConfig() *Config {
APIBase: "http://localhost:8000/v1",
APIKey: "",
},
},
Gateway: GatewayConfig{
Host: "127.0.0.1",
Port: 18790,
},
Tools: ToolsConfig{
MediaCleanup: MediaCleanupConfig{
Enabled: true,
MaxAge: 30,
Interval: 5,
},
Web: WebToolsConfig{
Proxy: "",
Brave: BraveConfig{
Enabled: false,
APIKey: "",
MaxResults: 5,
},
DuckDuckGo: DuckDuckGoConfig{
Enabled: true,
MaxResults: 5,
},
Perplexity: PerplexityConfig{
Enabled: false,
APIKey: "",
MaxResults: 5,
},
},
Cron: CronToolsConfig{
ExecTimeoutMinutes: 5,
},
Exec: ExecConfig{
EnableDenyPatterns: true,
},
Skills: SkillsToolsConfig{
Registries: SkillsRegistriesConfig{
ClawHub: ClawHubRegistryConfig{
Enabled: true,
BaseURL: "https://clawhub.ai",
},
},
MaxConcurrentSearches: 2,
SearchCache: SearchCacheConfig{
MaxSize: 50,
TTLSeconds: 300,
},
},
},
Heartbeat: HeartbeatConfig{
Enabled: true,
Interval: 30,
},
Devices: DevicesConfig{
Enabled: false,
MonitorUSB: true,
},
}
}