fix(provider): add insecure_skip_verify option for HTTP providers

Add insecure_skip_verify configuration option to ModelConfig to allow
skipping TLS certificate verification for development/testing environments.

This fixes SSL certificate verification issues when using volcengine
and other providers in environments with missing or outdated CA certificates
(e.g., Android Termux).

Changes:
- Add InsecureSkipVerify field to ModelConfig in config.go
- Add WithInsecureSkipVerify option function in openai_compat/provider.go
- Add NewHTTPProviderWithOptions function in http_provider.go
- Update factory_provider.go to pass insecure_skip_verify to all HTTP providers

Usage example in config.json:
{
  "model_list": [{
    "model_name": "doubao",
    "model": "volcengine/doubao-pro",
    "api_key": "your-api-key",
    "insecure_skip_verify": true
  }]
}

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
曾文锋0668000834 2026-03-12 20:58:07 +08:00
parent 95716b106b
commit 38df3a7ae5
4 changed files with 44 additions and 3 deletions

View file

@ -563,6 +563,9 @@ type ModelConfig struct {
MaxTokensField string `json:"max_tokens_field,omitempty"` // Field name for max tokens (e.g., "max_completion_tokens") MaxTokensField string `json:"max_tokens_field,omitempty"` // Field name for max tokens (e.g., "max_completion_tokens")
RequestTimeout int `json:"request_timeout,omitempty"` RequestTimeout int `json:"request_timeout,omitempty"`
ThinkingLevel string `json:"thinking_level,omitempty"` // Extended thinking: off|low|medium|high|xhigh|adaptive ThinkingLevel string `json:"thinking_level,omitempty"` // Extended thinking: off|low|medium|high|xhigh|adaptive
// TLS configuration
InsecureSkipVerify bool `json:"insecure_skip_verify,omitempty"` // Skip TLS certificate verification (for development/testing only)
} }
// Validate checks if the ModelConfig has all required fields. // Validate checks if the ModelConfig has all required fields.

View file

@ -84,12 +84,13 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
if apiBase == "" { if apiBase == "" {
apiBase = getDefaultAPIBase(protocol) apiBase = getDefaultAPIBase(protocol)
} }
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout( return NewHTTPProviderWithOptions(
cfg.APIKey, cfg.APIKey,
apiBase, apiBase,
cfg.Proxy, cfg.Proxy,
cfg.MaxTokensField, cfg.MaxTokensField,
cfg.RequestTimeout, cfg.RequestTimeout,
cfg.InsecureSkipVerify,
), modelID, nil ), modelID, nil
case "litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia", case "litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
@ -104,12 +105,13 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
if apiBase == "" { if apiBase == "" {
apiBase = getDefaultAPIBase(protocol) apiBase = getDefaultAPIBase(protocol)
} }
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout( return NewHTTPProviderWithOptions(
cfg.APIKey, cfg.APIKey,
apiBase, apiBase,
cfg.Proxy, cfg.Proxy,
cfg.MaxTokensField, cfg.MaxTokensField,
cfg.RequestTimeout, cfg.RequestTimeout,
cfg.InsecureSkipVerify,
), modelID, nil ), modelID, nil
case "anthropic": case "anthropic":
@ -129,12 +131,13 @@ 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)
} }
return NewHTTPProviderWithMaxTokensFieldAndRequestTimeout( return NewHTTPProviderWithOptions(
cfg.APIKey, cfg.APIKey,
apiBase, apiBase,
cfg.Proxy, cfg.Proxy,
cfg.MaxTokensField, cfg.MaxTokensField,
cfg.RequestTimeout, cfg.RequestTimeout,
cfg.InsecureSkipVerify,
), modelID, nil ), modelID, nil
case "antigravity": case "antigravity":

View file

@ -30,6 +30,21 @@ func NewHTTPProviderWithMaxTokensField(apiKey, apiBase, proxy, maxTokensField st
func NewHTTPProviderWithMaxTokensFieldAndRequestTimeout( func NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
apiKey, apiBase, proxy, maxTokensField string, apiKey, apiBase, proxy, maxTokensField string,
requestTimeoutSeconds int, requestTimeoutSeconds int,
) *HTTPProvider {
return NewHTTPProviderWithOptions(
apiKey,
apiBase,
proxy,
maxTokensField,
requestTimeoutSeconds,
false,
)
}
func NewHTTPProviderWithOptions(
apiKey, apiBase, proxy, maxTokensField string,
requestTimeoutSeconds int,
insecureSkipVerify bool,
) *HTTPProvider { ) *HTTPProvider {
return &HTTPProvider{ return &HTTPProvider{
delegate: openai_compat.NewProvider( delegate: openai_compat.NewProvider(
@ -38,6 +53,7 @@ func NewHTTPProviderWithMaxTokensFieldAndRequestTimeout(
proxy, proxy,
openai_compat.WithMaxTokensField(maxTokensField), openai_compat.WithMaxTokensField(maxTokensField),
openai_compat.WithRequestTimeout(time.Duration(requestTimeoutSeconds)*time.Second), openai_compat.WithRequestTimeout(time.Duration(requestTimeoutSeconds)*time.Second),
openai_compat.WithInsecureSkipVerify(insecureSkipVerify),
), ),
} }
} }

View file

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -54,6 +55,24 @@ func WithRequestTimeout(timeout time.Duration) Option {
} }
} }
func WithInsecureSkipVerify(skip bool) Option {
return func(p *Provider) {
if skip {
transport := p.httpClient.Transport
if transport == nil {
transport = &http.Transport{}
}
if tr, ok := transport.(*http.Transport); ok {
if tr.TLSClientConfig == nil {
tr.TLSClientConfig = &tls.Config{}
}
tr.TLSClientConfig.InsecureSkipVerify = true
p.httpClient.Transport = tr
}
}
}
}
func NewProvider(apiKey, apiBase, proxy string, opts ...Option) *Provider { func NewProvider(apiKey, apiBase, proxy string, opts ...Option) *Provider {
client := &http.Client{ client := &http.Client{
Timeout: defaultRequestTimeout, Timeout: defaultRequestTimeout,