feat(provider): add Venice AI support and update related documentation

This commit is contained in:
lc6464 2026-04-01 09:52:06 +08:00
parent 0f395ce110
commit 5cfb0ad193
No known key found for this signature in database
GPG key ID: 53C61B42FEC71D6D
10 changed files with 101 additions and 5 deletions

View file

@ -48,6 +48,11 @@
"model": "deepseek/deepseek-chat",
"api_key": "sk-your-deepseek-key"
},
{
"model_name": "venice-uncensored",
"model": "venice/venice-uncensored",
"api_key": "your-venice-api-key"
},
{
"model_name": "lmstudio-local",
"model": "lmstudio/openai/gpt-oss-20b"

View file

@ -16,6 +16,7 @@
| `openrouter` | LLM (recommended, access to all models) | [openrouter.ai](https://openrouter.ai) |
| `anthropic` | LLM (Claude direct) | [console.anthropic.com](https://console.anthropic.com) |
| `openai` | LLM (GPT direct) | [platform.openai.com](https://platform.openai.com) |
| `venice` | LLM (Venice AI direct) | [venice.ai](https://venice.ai) |
| `deepseek` | LLM (DeepSeek direct) | [platform.deepseek.com](https://platform.deepseek.com) |
| `qwen` | LLM (Qwen direct) | [dashscope.console.aliyun.com](https://dashscope.console.aliyun.com) |
| `groq` | LLM + **Voice transcription** (Whisper) | [console.groq.com](https://console.groq.com) |
@ -46,6 +47,7 @@ This design also enables **multi-agent support** with flexible provider selectio
| Vendor | `model` Prefix | Default API Base | Protocol | API Key |
| ------------------- | ----------------- |-----------------------------------------------------| --------- | ---------------------------------------------------------------- |
| **OpenAI** | `openai/` | `https://api.openai.com/v1` | OpenAI | [Get Key](https://platform.openai.com) |
| **Venice AI** | `venice/` | `https://api.venice.ai/api/v1` | OpenAI | [Get Key](https://venice.ai) |
| **Anthropic** | `anthropic/` | `https://api.anthropic.com/v1` | Anthropic | [Get Key](https://console.anthropic.com) |
| **智谱 AI (GLM)** | `zhipu/` | `https://open.bigmodel.cn/api/paas/v4` | OpenAI | [Get Key](https://open.bigmodel.cn/usercenter/proj-mgmt/apikeys) |
| **Z.AI Coding Plan** | `openai/` | `https://api.z.ai/api/coding/paas/v4` | OpenAI | [Get Key](https://z.ai/manage-apikey/apikey-list) |

View file

@ -15,6 +15,7 @@
| `openrouter` | LLM (推荐,可访问所有模型) | [openrouter.ai](https://openrouter.ai) |
| `anthropic` | LLM (Claude 直连) | [console.anthropic.com](https://console.anthropic.com) |
| `openai` | LLM (GPT 直连) | [platform.openai.com](https://platform.openai.com) |
| `venice` | LLM (Venice AI 直连) | [venice.ai](https://venice.ai) |
| `deepseek` | LLM (DeepSeek 直连) | [platform.deepseek.com](https://platform.deepseek.com) |
| `qwen` | LLM (通义千问) | [dashscope.console.aliyun.com](https://dashscope.console.aliyun.com) |
| `groq` | LLM + **语音转录** (Whisper) | [console.groq.com](https://console.groq.com) |
@ -44,6 +45,7 @@
| 厂商 | `model` 前缀 | 默认 API Base | 协议 | 获取 API Key |
| ------------------- | ----------------- | --------------------------------------------------- | --------- | ----------------------------------------------------------------- |
| **OpenAI** | `openai/` | `https://api.openai.com/v1` | OpenAI | [获取密钥](https://platform.openai.com) |
| **Venice AI** | `venice/` | `https://api.venice.ai/api/v1` | OpenAI | [获取密钥](https://venice.ai) |
| **Anthropic** | `anthropic/` | `https://api.anthropic.com/v1` | Anthropic | [获取密钥](https://console.anthropic.com) |
| **智谱 AI (GLM)** | `zhipu/` | `https://open.bigmodel.cn/api/paas/v4` | OpenAI | [获取密钥](https://open.bigmodel.cn/usercenter/proj-mgmt/apikeys) |
| **DeepSeek** | `deepseek/` | `https://api.deepseek.com/v1` | OpenAI | [获取密钥](https://platform.deepseek.com) |

View file

@ -24,8 +24,8 @@ func supportsAudioTranscription(model string) bool {
switch protocol {
case "openai", "azure", "azure-openai",
"litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
"litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia", "venice",
"ollama", "lmstudio", "moonshot", "shengsuanyun", "deepseek", "cerebras",
"vivgrid", "volcengine", "vllm", "qwen", "qwen-intl", "qwen-international", "dashscope-intl",
"qwen-us", "dashscope-us", "mistral", "avian", "minimax", "longcat", "modelscope", "novita",
"coding-plan", "alibaba-coding", "qwen-coding":
@ -45,8 +45,8 @@ func supportsWhisperTranscription(model string) bool {
protocol, _ := providers.ExtractProtocol(model)
switch protocol {
case "openai", "litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
case "openai", "litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia", "venice",
"ollama", "lmstudio", "moonshot", "shengsuanyun", "deepseek", "cerebras",
"vivgrid", "volcengine", "vllm", "qwen", "qwen-intl", "qwen-international", "dashscope-intl",
"qwen-us", "dashscope-us", "mistral", "avian", "minimax", "longcat", "modelscope", "novita",
"coding-plan", "alibaba-coding", "qwen-coding", "mimo":

View file

@ -74,6 +74,20 @@ func TestDetectTranscriber(t *testing.T) {
},
wantName: "whisper",
},
{
name: "lmstudio whisper alias selects whisper transcriber",
cfg: &config.Config{
Voice: config.VoiceConfig{ModelName: "my-asr-model"},
ModelList: []*config.ModelConfig{
{
ModelName: "my-asr-model",
Model: "lmstudio/whisper-1",
APIKeys: config.SimpleSecureStrings("sk-lmstudio-model"),
},
},
},
wantName: "whisper",
},
{
name: "whisper via model list fallback",
cfg: &config.Config{
@ -102,6 +116,34 @@ func TestDetectTranscriber(t *testing.T) {
},
wantName: "audio-model",
},
{
name: "voice model name selects venice audio model transcriber",
cfg: &config.Config{
Voice: config.VoiceConfig{ModelName: "voice-venice"},
ModelList: []*config.ModelConfig{
{
ModelName: "voice-venice",
Model: "venice/venice-uncensored",
APIKeys: config.SimpleSecureStrings("venice-key"),
},
},
},
wantName: "audio-model",
},
{
name: "voice model name selects lmstudio audio model transcriber",
cfg: &config.Config{
Voice: config.VoiceConfig{ModelName: "voice-lmstudio"},
ModelList: []*config.ModelConfig{
{
ModelName: "voice-lmstudio",
Model: "lmstudio/openai/gpt-4o-audio-preview",
APIKeys: config.SimpleSecureStrings("sk-lmstudio-model"),
},
},
},
wantName: "audio-model",
},
{
name: "voice model name selects azure audio model transcriber",
cfg: &config.Config{

View file

@ -185,6 +185,12 @@ func DefaultConfig() *Config {
APIBase: "https://api.deepseek.com/v1",
},
// Venice AI - https://venice.ai
{
ModelName: "venice-uncensored",
Model: "venice/venice-uncensored",
},
// Google Gemini - https://ai.google.dev/
{
ModelName: "gemini-2.0-flash",

View file

@ -24,6 +24,7 @@ type protocolMeta struct {
var protocolMetaByName = map[string]protocolMeta{
"openai": {defaultAPIBase: "https://api.openai.com/v1"},
"venice": {defaultAPIBase: "https://api.venice.ai/api/v1"},
"openrouter": {defaultAPIBase: "https://openrouter.ai/api/v1"},
"litellm": {defaultAPIBase: "http://localhost:4000/v1"},
"lmstudio": {defaultAPIBase: "http://localhost:1234/v1", emptyAPIKeyAllowed: true},
@ -209,7 +210,7 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
}
return provider, modelID, nil
case "litellm", "lmstudio", "openrouter", "groq", "zhipu", "gemini", "nvidia",
case "litellm", "lmstudio", "openrouter", "groq", "zhipu", "gemini", "nvidia", "venice",
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
"vivgrid", "volcengine", "vllm", "qwen", "qwen-intl", "qwen-international", "dashscope-intl",
"qwen-us", "dashscope-us", "mistral", "avian", "longcat", "modelscope", "novita",

View file

@ -112,6 +112,7 @@ func TestCreateProviderFromConfig_DefaultAPIBase(t *testing.T) {
protocol string
}{
{"openai", "openai"},
{"venice", "venice"},
{"groq", "groq"},
{"novita", "novita"},
{"openrouter", "openrouter"},
@ -160,6 +161,12 @@ func TestGetDefaultAPIBase_LMStudio(t *testing.T) {
}
}
func TestGetDefaultAPIBase_Venice(t *testing.T) {
if got := getDefaultAPIBase("venice"); got != "https://api.venice.ai/api/v1" {
t.Fatalf("getDefaultAPIBase(%q) = %q, want %q", "venice", got, "https://api.venice.ai/api/v1")
}
}
func TestCreateProviderFromConfig_LiteLLM(t *testing.T) {
cfg := &config.ModelConfig{
ModelName: "test-litellm",
@ -362,6 +369,28 @@ func TestCreateProviderFromConfig_Mimo(t *testing.T) {
}
}
func TestCreateProviderFromConfig_Venice(t *testing.T) {
cfg := &config.ModelConfig{
ModelName: "test-venice",
Model: "venice/venice-uncensored",
}
cfg.SetAPIKey("test-key")
provider, modelID, err := CreateProviderFromConfig(cfg)
if err != nil {
t.Fatalf("CreateProviderFromConfig() error = %v", err)
}
if provider == nil {
t.Fatal("CreateProviderFromConfig() returned nil provider")
}
if modelID != "venice-uncensored" {
t.Errorf("modelID = %q, want %q", modelID, "venice-uncensored")
}
if _, ok := provider.(*HTTPProvider); !ok {
t.Fatalf("expected *HTTPProvider, got %T", provider)
}
}
func TestGetDefaultAPIBase_Mimo(t *testing.T) {
if got := getDefaultAPIBase("mimo"); got != "https://api.xiaomimimo.com/v1" {
t.Fatalf("getDefaultAPIBase(%q) = %q, want %q", "mimo", got, "https://api.xiaomimimo.com/v1")

View file

@ -44,6 +44,7 @@ const defaultRequestTimeout = common.DefaultRequestTimeout
var stripModelPrefixProviders = map[string]struct{}{
"litellm": {},
"venice": {},
"moonshot": {},
"nvidia": {},
"groq": {},

View file

@ -479,6 +479,11 @@ func TestProviderChat_StripsKnownProviderPrefixes(t *testing.T) {
input: "lmstudio/openai/gpt-oss-20b",
wantModel: "openai/gpt-oss-20b",
},
{
name: "strips venice prefix",
input: "venice/venice-uncensored",
wantModel: "venice-uncensored",
},
{
name: "strips deepseek prefix",
input: "deepseek/deepseek-chat",
@ -587,6 +592,9 @@ func TestNormalizeModel_UsesAPIBase(t *testing.T) {
if got := normalizeModel("lmstudio/openai/gpt-oss-20b", "http://localhost:1234/v1"); got != "openai/gpt-oss-20b" {
t.Fatalf("normalizeModel(lmstudio) = %q, want %q", got, "openai/gpt-oss-20b")
}
if got := normalizeModel("venice/venice-uncensored", "https://api.venice.ai/api/v1"); got != "venice-uncensored" {
t.Fatalf("normalizeModel(venice) = %q, want %q", got, "venice-uncensored")
}
if got := normalizeModel("openrouter/auto", "https://openrouter.ai/api/v1"); got != "openrouter/auto" {
t.Fatalf("normalizeModel(openrouter) = %q, want %q", got, "openrouter/auto")
}