fix(config): resolve nvidia provider model lookup failure for custom model names
When a user configured provider=nvidia with a model like kimi-k2.5 (or moonshotai/kimi-k2.5), ConvertProvidersToModelList updated mc.Model but left mc.ModelName as "nvidia". GetModelConfig then searched for ModelName=="kimi-k2.5" and found nothing, producing the "no API key configured for model" error. Two issues fixed: - mc.ModelName is now set to userModel so GetModelConfig(userModel) finds the migrated entry. - The protocol prefix is added with a strict HasPrefix check, so model IDs that already contain "/" but are NOT protocol-prefixed (e.g. Nvidia's "moonshotai/kimi-k2.5") are correctly wrapped as "nvidia/moonshotai/kimi-k2.5" instead of being passed through with the wrong protocol. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6e1deb8945
commit
338c7dc528
2 changed files with 109 additions and 4 deletions
|
|
@ -335,8 +335,16 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig {
|
|||
|
||||
// Check if this is the user's configured provider
|
||||
if slices.Contains(m.providerNames, userProvider) && userModel != "" {
|
||||
// Use the user's configured model instead of default
|
||||
mc.Model = buildModelWithProtocol(m.protocol, userModel)
|
||||
// Use the user's configured model instead of default.
|
||||
// Add protocol prefix unless the model already starts with it.
|
||||
// This handles API-specific model IDs that contain "/" (e.g. "moonshotai/kimi-k2.5" on Nvidia).
|
||||
if strings.HasPrefix(strings.ToLower(userModel), m.protocol+"/") {
|
||||
mc.Model = userModel
|
||||
} else {
|
||||
mc.Model = m.protocol + "/" + userModel
|
||||
}
|
||||
// Update ModelName so GetModelConfig(userModel) can find this entry.
|
||||
mc.ModelName = userModel
|
||||
} else if userProvider == "" && userModel != "" && !legacyModelNameApplied {
|
||||
// Legacy config: no explicit provider field but model is specified
|
||||
// Use userModel as ModelName for the FIRST provider so GetModelConfig(model) can find it
|
||||
|
|
|
|||
|
|
@ -327,14 +327,16 @@ func TestConvertProvidersToModelList_MultipleProviders_PreservesUserModel(t *tes
|
|||
t.Fatalf("len(result) = %d, want 2", len(result))
|
||||
}
|
||||
|
||||
// Find each provider and verify model
|
||||
// Find each provider and verify model.
|
||||
// After migration, user-selected provider ModelName becomes the user's model name.
|
||||
for _, mc := range result {
|
||||
switch mc.ModelName {
|
||||
case "openai":
|
||||
if mc.Model != "openai/gpt-5.2" {
|
||||
t.Errorf("OpenAI Model = %q, want %q (default)", mc.Model, "openai/gpt-5.2")
|
||||
}
|
||||
case "deepseek":
|
||||
case "deepseek-reasoner":
|
||||
// The user's explicit provider (deepseek) now uses the user's model as ModelName
|
||||
if mc.Model != "deepseek/deepseek-reasoner" {
|
||||
t.Errorf("DeepSeek Model = %q, want %q (user's)", mc.Model, "deepseek/deepseek-reasoner")
|
||||
}
|
||||
|
|
@ -549,3 +551,98 @@ func TestConvertProvidersToModelList_LegacyModelWithProtocolPrefix(t *testing.T)
|
|||
t.Errorf("Model = %q, want %q (should not duplicate prefix)", result[0].Model, "openrouter/auto")
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for nvidia provider with custom (third-party) model names.
|
||||
// Nvidia's API hosts models from various vendors using identifiers like "moonshotai/kimi-k2.5".
|
||||
|
||||
func TestConvertProvidersToModelList_Nvidia_SimpleModel(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Agents: AgentsConfig{
|
||||
Defaults: AgentDefaults{
|
||||
Provider: "nvidia",
|
||||
Model: "kimi-k2.5",
|
||||
},
|
||||
},
|
||||
Providers: ProvidersConfig{
|
||||
Nvidia: ProviderConfig{APIKey: "nvapi-xxx", APIBase: "https://integrate.api.nvidia.com/v1"},
|
||||
},
|
||||
}
|
||||
|
||||
result := ConvertProvidersToModelList(cfg)
|
||||
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("len(result) = %d, want 1", len(result))
|
||||
}
|
||||
|
||||
// ModelName must match the user's model so GetModelConfig("kimi-k2.5") can find it
|
||||
if result[0].ModelName != "kimi-k2.5" {
|
||||
t.Errorf("ModelName = %q, want %q", result[0].ModelName, "kimi-k2.5")
|
||||
}
|
||||
|
||||
// Model should be prefixed with the nvidia protocol
|
||||
if result[0].Model != "nvidia/kimi-k2.5" {
|
||||
t.Errorf("Model = %q, want %q", result[0].Model, "nvidia/kimi-k2.5")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertProvidersToModelList_Nvidia_VendorPrefixedModel(t *testing.T) {
|
||||
// Nvidia hosts third-party models like "moonshotai/kimi-k2.5".
|
||||
// The "/" is part of the model ID, not a protocol separator.
|
||||
cfg := &Config{
|
||||
Agents: AgentsConfig{
|
||||
Defaults: AgentDefaults{
|
||||
Provider: "nvidia",
|
||||
Model: "moonshotai/kimi-k2.5",
|
||||
},
|
||||
},
|
||||
Providers: ProvidersConfig{
|
||||
Nvidia: ProviderConfig{APIKey: "nvapi-xxx", APIBase: "https://integrate.api.nvidia.com/v1"},
|
||||
},
|
||||
}
|
||||
|
||||
result := ConvertProvidersToModelList(cfg)
|
||||
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("len(result) = %d, want 1", len(result))
|
||||
}
|
||||
|
||||
// ModelName must match the user's model so GetModelConfig("moonshotai/kimi-k2.5") can find it
|
||||
if result[0].ModelName != "moonshotai/kimi-k2.5" {
|
||||
t.Errorf("ModelName = %q, want %q", result[0].ModelName, "moonshotai/kimi-k2.5")
|
||||
}
|
||||
|
||||
// Model should be wrapped with nvidia/ protocol prefix so the provider is resolved correctly
|
||||
if result[0].Model != "nvidia/moonshotai/kimi-k2.5" {
|
||||
t.Errorf("Model = %q, want %q", result[0].Model, "nvidia/moonshotai/kimi-k2.5")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertProvidersToModelList_Nvidia_ExplicitNvidiaPrefix(t *testing.T) {
|
||||
// User specifies nvidia/kimi-k2.5 - should not double-prefix.
|
||||
cfg := &Config{
|
||||
Agents: AgentsConfig{
|
||||
Defaults: AgentDefaults{
|
||||
Provider: "nvidia",
|
||||
Model: "nvidia/kimi-k2.5",
|
||||
},
|
||||
},
|
||||
Providers: ProvidersConfig{
|
||||
Nvidia: ProviderConfig{APIKey: "nvapi-xxx"},
|
||||
},
|
||||
}
|
||||
|
||||
result := ConvertProvidersToModelList(cfg)
|
||||
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("len(result) = %d, want 1", len(result))
|
||||
}
|
||||
|
||||
if result[0].ModelName != "nvidia/kimi-k2.5" {
|
||||
t.Errorf("ModelName = %q, want %q", result[0].ModelName, "nvidia/kimi-k2.5")
|
||||
}
|
||||
|
||||
// Should NOT produce nvidia/nvidia/kimi-k2.5
|
||||
if result[0].Model != "nvidia/kimi-k2.5" {
|
||||
t.Errorf("Model = %q, want %q (should not double-prefix)", result[0].Model, "nvidia/kimi-k2.5")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue