feat: add Novita provider integration

- Add Novita as a new OpenAI-compatible provider in factory.go
- Add Novita config struct in pkg/config/config.go
- Add Novita default models in pkg/config/defaults.go:
  * deepseek/deepseek-v3.2
  * zai-org/glm-5
  * minimax/minimax-m2.5
- Add env var NOVITA_API_KEY to .env.example
- Add tests in pkg/providers/factory_test.go
- Use Novita endpoint: https://api.novita.ai/openai
This commit is contained in:
Alex-wuhu 2026-03-17 16:03:05 +08:00
parent 0499cdab72
commit 9eecca0376
5 changed files with 59 additions and 0 deletions

View file

@ -7,6 +7,7 @@
# GEMINI_API_KEY=xxx
# MODELSCOPE_API_KEY=xxx
# CLAUDE_CODE_OAUTH=xxx
# NOVITA_API_KEY=sk-xxx
# ── Chat Channel ──────────────────────────
# TELEGRAM_BOT_TOKEN=123456:ABC...
# DISCORD_BOT_TOKEN=xxx

View file

@ -523,6 +523,7 @@ type ProvidersConfig struct {
Cerebras ProviderConfig `json:"cerebras"`
Vivgrid ProviderConfig `json:"vivgrid"`
VolcEngine ProviderConfig `json:"volcengine"`
Novita ProviderConfig `json:"novita"`
GitHubCopilot ProviderConfig `json:"github_copilot"`
Antigravity ProviderConfig `json:"antigravity"`
Qwen ProviderConfig `json:"qwen"`
@ -552,6 +553,7 @@ func (p ProvidersConfig) IsEmpty() bool {
p.Cerebras.APIKey == "" && p.Cerebras.APIBase == "" &&
p.Vivgrid.APIKey == "" && p.Vivgrid.APIBase == "" &&
p.VolcEngine.APIKey == "" && p.VolcEngine.APIBase == "" &&
p.Novita.APIKey == "" && p.Novita.APIBase == "" &&
p.GitHubCopilot.APIKey == "" && p.GitHubCopilot.APIBase == "" &&
p.Antigravity.APIKey == "" && p.Antigravity.APIBase == "" &&
p.Qwen.APIKey == "" && p.Qwen.APIBase == "" &&

View file

@ -377,6 +377,26 @@ func DefaultConfig() *Config {
APIKey: "",
},
// Novita AI - https://novita.ai
{
ModelName: "deepseek-v3.2",
Model: "novita/deepseek/deepseek-v3.2",
APIBase: "https://api.novita.ai/openai",
APIKey: "",
},
{
ModelName: "glm-5",
Model: "novita/zai-org/glm-5",
APIBase: "https://api.novita.ai/openai",
APIKey: "",
},
{
ModelName: "minimax-m2.5",
Model: "novita/minimax/minimax-m2.5",
APIBase: "https://api.novita.ai/openai",
APIKey: "",
},
// VLLM (local) - http://localhost:8000
{
ModelName: "local-model",

View file

@ -230,6 +230,15 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
sel.apiBase = "https://api.longcat.chat/openai"
}
}
case "novita":
if cfg.Providers.Novita.APIKey != "" {
sel.apiKey = cfg.Providers.Novita.APIKey
sel.apiBase = cfg.Providers.Novita.APIBase
sel.proxy = cfg.Providers.Novita.Proxy
if sel.apiBase == "" {
sel.apiBase = "https://api.novita.ai/openai"
}
}
case "github_copilot", "copilot":
sel.providerType = providerTypeGitHubCopilot
if cfg.Providers.GitHubCopilot.APIBase != "" {
@ -368,6 +377,13 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
if sel.apiBase == "" {
sel.apiBase = "https://api.longcat.chat/openai"
}
case (strings.Contains(lowerModel, "novita") || strings.HasPrefix(model, "novita/")) && cfg.Providers.Novita.APIKey != "":
sel.apiKey = cfg.Providers.Novita.APIKey
sel.apiBase = cfg.Providers.Novita.APIBase
sel.proxy = cfg.Providers.Novita.Proxy
if sel.apiBase == "" {
sel.apiBase = "https://api.novita.ai/openai"
}
case cfg.Providers.VLLM.APIBase != "":
sel.apiKey = cfg.Providers.VLLM.APIKey
sel.apiBase = cfg.Providers.VLLM.APIBase

View file

@ -189,6 +189,17 @@ func TestResolveProviderSelection(t *testing.T) {
wantAPIBase: "https://api.longcat.chat/openai",
wantProxy: "http://127.0.0.1:7890",
},
{
name: "explicit novita provider uses defaults",
setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Provider = "novita"
cfg.Providers.Novita.APIKey = "novita-key"
cfg.Providers.Novita.Proxy = "http://127.0.0.1:7890"
},
wantType: providerTypeHTTPCompat,
wantAPIBase: "https://api.novita.ai/openai",
wantProxy: "http://127.0.0.1:7890",
},
{
name: "longcat model fallback uses longcat base default",
setup: func(cfg *config.Config) {
@ -198,6 +209,15 @@ func TestResolveProviderSelection(t *testing.T) {
wantType: providerTypeHTTPCompat,
wantAPIBase: "https://api.longcat.chat/openai",
},
{
name: "novita model fallback uses novita base default",
setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Model = "novita/deepseek/deepseek-v3.2"
cfg.Providers.Novita.APIKey = "novita-key"
},
wantType: providerTypeHTTPCompat,
wantAPIBase: "https://api.novita.ai/openai",
},
{
name: "missing keys returns model config error",
setup: func(cfg *config.Config) {