Fix deepseek model max_tokens validation error
This commit is contained in:
parent
028605cfd0
commit
1abcc95ed6
4 changed files with 127 additions and 7 deletions
|
|
@ -217,7 +217,9 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
|
||||||
strings.HasPrefix(model, "openai/") ||
|
strings.HasPrefix(model, "openai/") ||
|
||||||
strings.HasPrefix(model, "meta-llama/") ||
|
strings.HasPrefix(model, "meta-llama/") ||
|
||||||
strings.HasPrefix(model, "deepseek/") ||
|
strings.HasPrefix(model, "deepseek/") ||
|
||||||
|
strings.HasPrefix(model, "deepseek-ai/") ||
|
||||||
strings.HasPrefix(model, "google/"):
|
strings.HasPrefix(model, "google/"):
|
||||||
|
|
||||||
sel.apiKey = cfg.Providers.OpenRouter.APIKey
|
sel.apiKey = cfg.Providers.OpenRouter.APIKey
|
||||||
sel.proxy = cfg.Providers.OpenRouter.Proxy
|
sel.proxy = cfg.Providers.OpenRouter.Proxy
|
||||||
if cfg.Providers.OpenRouter.APIBase != "" {
|
if cfg.Providers.OpenRouter.APIBase != "" {
|
||||||
|
|
@ -279,7 +281,35 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
|
||||||
if sel.apiBase == "" {
|
if sel.apiBase == "" {
|
||||||
sel.apiBase = "https://api.groq.com/openai/v1"
|
sel.apiBase = "https://api.groq.com/openai/v1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case (strings.Contains(lowerModel, "deepseek") || strings.HasPrefix(model, "deepseek/") || strings.HasPrefix(model, "deepseek-ai/")) && cfg.Providers.DeepSeek.APIKey != "":
|
||||||
|
|
||||||
|
sel.apiKey = cfg.Providers.DeepSeek.APIKey
|
||||||
|
|
||||||
|
sel.apiBase = cfg.Providers.DeepSeek.APIBase
|
||||||
|
|
||||||
|
sel.proxy = cfg.Providers.DeepSeek.Proxy
|
||||||
|
|
||||||
|
if sel.apiBase == "" {
|
||||||
|
|
||||||
|
sel.apiBase = "https://api.deepseek.com/v1"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep original model name logic for backward compatibility
|
||||||
|
|
||||||
|
if !strings.HasPrefix(model, "deepseek/") && !strings.HasPrefix(model, "deepseek-ai/") {
|
||||||
|
|
||||||
|
if model != "deepseek-chat" && model != "deepseek-reasoner" {
|
||||||
|
|
||||||
|
sel.model = "deepseek-chat"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
case (strings.Contains(lowerModel, "nvidia") || strings.HasPrefix(model, "nvidia/")) && cfg.Providers.Nvidia.APIKey != "":
|
case (strings.Contains(lowerModel, "nvidia") || strings.HasPrefix(model, "nvidia/")) && cfg.Providers.Nvidia.APIKey != "":
|
||||||
|
|
||||||
sel.apiKey = cfg.Providers.Nvidia.APIKey
|
sel.apiKey = cfg.Providers.Nvidia.APIKey
|
||||||
sel.apiBase = cfg.Providers.Nvidia.APIBase
|
sel.apiBase = cfg.Providers.Nvidia.APIBase
|
||||||
sel.proxy = cfg.Providers.Nvidia.Proxy
|
sel.proxy = cfg.Providers.Nvidia.Proxy
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,13 @@ func ExtractProtocol(model string) (protocol, modelID string) {
|
||||||
// It uses the protocol prefix in the Model field to determine which provider to create.
|
// It uses the protocol prefix in the Model field to determine which provider to create.
|
||||||
// Supported protocols: openai, litellm, anthropic, antigravity, claude-cli, codex-cli, github-copilot
|
// Supported protocols: openai, litellm, anthropic, antigravity, claude-cli, codex-cli, github-copilot
|
||||||
// Returns the provider, the model ID (without protocol prefix), and any error.
|
// Returns the provider, the model ID (without protocol prefix), and any error.
|
||||||
|
// ExtractProtocol extracts the protocol prefix and model identifier from a model string.
|
||||||
|
// If no prefix is specified, it defaults to "openai".
|
||||||
|
// Examples:
|
||||||
|
// - "openai/gpt-4o" -> ("openai", "gpt-4o")
|
||||||
|
// - "anthropic/claude-sonnet-4.6" -> ("anthropic", "claude-sonnet-4.6")
|
||||||
|
// - "gpt-4o" -> ("openai", "gpt-4o") // default protocol
|
||||||
|
func ExtractProtocol(model string) (protocol, modelID string) {
|
||||||
func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, error) {
|
func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil, "", fmt.Errorf("config is nil")
|
return nil, "", fmt.Errorf("config is nil")
|
||||||
|
|
@ -84,12 +91,17 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
|
||||||
if apiBase == "" {
|
if apiBase == "" {
|
||||||
apiBase = getDefaultAPIBase(protocol)
|
apiBase = getDefaultAPIBase(protocol)
|
||||||
}
|
}
|
||||||
|
// For Ollama models, default to higher timeout if none specified
|
||||||
|
requestTimeout := cfg.RequestTimeout
|
||||||
|
if protocol == "ollama" && requestTimeout <= 0 {
|
||||||
|
requestTimeout = 300 // Ollama models often need more time, default to 300 seconds
|
||||||
|
}
|
||||||
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
||||||
cfg.APIKey,
|
cfg.APIKey,
|
||||||
apiBase,
|
apiBase,
|
||||||
cfg.Proxy,
|
cfg.Proxy,
|
||||||
cfg.MaxTokensField,
|
cfg.MaxTokensField,
|
||||||
cfg.RequestTimeout,
|
requestTimeout,
|
||||||
), modelID, nil
|
), modelID, nil
|
||||||
|
|
||||||
case "litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
|
case "litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
|
||||||
|
|
@ -103,12 +115,17 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
|
||||||
if apiBase == "" {
|
if apiBase == "" {
|
||||||
apiBase = getDefaultAPIBase(protocol)
|
apiBase = getDefaultAPIBase(protocol)
|
||||||
}
|
}
|
||||||
|
// For Ollama models, default to higher timeout if none specified
|
||||||
|
requestTimeout := cfg.RequestTimeout
|
||||||
|
if protocol == "ollama" && requestTimeout <= 0 {
|
||||||
|
requestTimeout = 300 // Ollama models often need more time, default to 300 seconds
|
||||||
|
}
|
||||||
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
||||||
cfg.APIKey,
|
cfg.APIKey,
|
||||||
apiBase,
|
apiBase,
|
||||||
cfg.Proxy,
|
cfg.Proxy,
|
||||||
cfg.MaxTokensField,
|
cfg.MaxTokensField,
|
||||||
cfg.RequestTimeout,
|
requestTimeout,
|
||||||
), modelID, nil
|
), modelID, nil
|
||||||
|
|
||||||
case "anthropic":
|
case "anthropic":
|
||||||
|
|
@ -128,12 +145,17 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
|
||||||
if cfg.APIKey == "" {
|
if cfg.APIKey == "" {
|
||||||
return nil, "", fmt.Errorf("api_key is required for anthropic protocol (model: %s)", cfg.Model)
|
return nil, "", fmt.Errorf("api_key is required for anthropic protocol (model: %s)", cfg.Model)
|
||||||
}
|
}
|
||||||
|
// For Ollama models, default to higher timeout if none specified
|
||||||
|
requestTimeout := cfg.RequestTimeout
|
||||||
|
if protocol == "ollama" && requestTimeout <= 0 {
|
||||||
|
requestTimeout = 300 // Ollama models often need more time, default to 300 seconds
|
||||||
|
}
|
||||||
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
|
||||||
cfg.APIKey,
|
cfg.APIKey,
|
||||||
apiBase,
|
apiBase,
|
||||||
cfg.Proxy,
|
cfg.Proxy,
|
||||||
cfg.MaxTokensField,
|
cfg.MaxTokensField,
|
||||||
cfg.RequestTimeout,
|
requestTimeout,
|
||||||
), modelID, nil
|
), modelID, nil
|
||||||
|
|
||||||
case "antigravity":
|
case "antigravity":
|
||||||
|
|
|
||||||
|
|
@ -179,10 +179,65 @@ func TestResolveProviderSelection(t *testing.T) {
|
||||||
setup: func(cfg *config.Config) {
|
setup: func(cfg *config.Config) {
|
||||||
cfg.Agents.Defaults.Model = "openrouter/auto"
|
cfg.Agents.Defaults.Model = "openrouter/auto"
|
||||||
},
|
},
|
||||||
wantErrSubstr: "no API key configured for provider",
|
{
|
||||||
|
|
||||||
|
name: "deepseek-ai model with DeepSeek API key uses DeepSeek API",
|
||||||
|
|
||||||
|
setup: func(cfg *config.Config) {
|
||||||
|
|
||||||
|
cfg.Agents.Defaults.Model = "deepseek-ai/DeepSeek-V3.2"
|
||||||
|
|
||||||
|
cfg.Providers.DeepSeek.APIKey = "deepseek-key"
|
||||||
|
|
||||||
|
cfg.Providers.DeepSeek.APIBase = "https://api.deepseek.com/v1"
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
wantType: providerTypeHTTPCompat,
|
||||||
|
|
||||||
|
wantAPIBase: "https://api.deepseek.com/v1",
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
name: "deepseek-ai prefix model routes to DeepSeek when key configured",
|
||||||
|
|
||||||
|
setup: func(cfg *config.Config) {
|
||||||
|
|
||||||
|
cfg.Agents.Defaults.Model = "deepseek-ai/deepseek-coder"
|
||||||
|
|
||||||
|
cfg.Providers.DeepSeek.APIKey = "deepseek-key"
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
wantType: providerTypeHTTPCompat,
|
||||||
|
|
||||||
|
wantAPIBase: "https://api.deepseek.com/v1",
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
name: "deepseek model still works for backward compatibility",
|
||||||
|
|
||||||
|
setup: func(cfg *config.Config) {
|
||||||
|
|
||||||
|
cfg.Agents.Defaults.Model = "deepseek/deepseek-chat"
|
||||||
|
|
||||||
|
cfg.Providers.DeepSeek.APIKey = "deepseek-key"
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
wantType: providerTypeHTTPCompat,
|
||||||
|
|
||||||
|
wantAPIBase: "https://api.deepseek.com/v1",
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
cfg := config.DefaultConfig()
|
cfg := config.DefaultConfig()
|
||||||
|
|
|
||||||
|
|
@ -137,8 +137,21 @@ func (p *Provider) Chat(
|
||||||
fieldName = "max_tokens"
|
fieldName = "max_tokens"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Validate max_tokens range for deepseek model
|
||||||
|
if strings.Contains(strings.ToLower(model), "deepseek") {
|
||||||
|
// Clamp max_tokens to the valid range [1, 8192]
|
||||||
|
adjustedMaxTokens := maxTokens
|
||||||
|
if maxTokens > 8192 {
|
||||||
|
adjustedMaxTokens = 8192
|
||||||
|
}
|
||||||
|
if maxTokens < 1 {
|
||||||
|
adjustedMaxTokens = 1
|
||||||
|
}
|
||||||
|
requestBody[fieldName] = adjustedMaxTokens
|
||||||
|
} else {
|
||||||
requestBody[fieldName] = maxTokens
|
requestBody[fieldName] = maxTokens
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if temperature, ok := asFloat(options["temperature"]); ok {
|
if temperature, ok := asFloat(options["temperature"]); ok {
|
||||||
lowerModel := strings.ToLower(model)
|
lowerModel := strings.ToLower(model)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue