mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-09-08 06:17:26 +00:00
feat: add Z.ai provider support (general API + coding plan) (#102)
* feat: add Z.ai provider support (general API + coding plan) Add Z.ai (GLM) as a new LLM provider with two variants: - `zai`: general API (api.z.ai/api/paas/v4) - `zai_coding`: coding plan (api.z.ai/api/coding/paas/v4) Reuses OpenAIProvider — Z.ai API is OpenAI-compatible with Bearer token auth, SSE streaming, and reasoning_content support. Includes: store constants, config struct fields, env var loading (GOCLAW_ZAI_API_KEY, GOCLAW_ZAI_CODING_API_KEY), secret masking, config + DB registration, onboard wizard, and UI provider types. Default model: glm-5 Closes #100 * docs: add Z.ai provider entries to providers documentation
This commit is contained in:
@@ -98,6 +98,24 @@ func registerProviders(registry *providers.Registry, cfg *config.Config) {
|
||||
slog.Info("registered provider", "name", "bailian")
|
||||
}
|
||||
|
||||
if cfg.Providers.Zai.APIKey != "" {
|
||||
base := cfg.Providers.Zai.APIBase
|
||||
if base == "" {
|
||||
base = "https://api.z.ai/api/paas/v4"
|
||||
}
|
||||
registry.Register(providers.NewOpenAIProvider("zai", cfg.Providers.Zai.APIKey, base, "glm-5"))
|
||||
slog.Info("registered provider", "name", "zai")
|
||||
}
|
||||
|
||||
if cfg.Providers.ZaiCoding.APIKey != "" {
|
||||
base := cfg.Providers.ZaiCoding.APIBase
|
||||
if base == "" {
|
||||
base = "https://api.z.ai/api/coding/paas/v4"
|
||||
}
|
||||
registry.Register(providers.NewOpenAIProvider("zai-coding", cfg.Providers.ZaiCoding.APIKey, base, "glm-5"))
|
||||
slog.Info("registered provider", "name", "zai-coding")
|
||||
}
|
||||
|
||||
// Claude CLI provider (subscription-based, no API key needed)
|
||||
if cfg.Providers.ClaudeCLI.CLIPath != "" {
|
||||
cliPath := cfg.Providers.ClaudeCLI.CLIPath
|
||||
@@ -243,6 +261,18 @@ func registerProvidersFromDB(registry *providers.Registry, provStore store.Provi
|
||||
base = "https://coding-intl.dashscope.aliyuncs.com/v1"
|
||||
}
|
||||
registry.Register(providers.NewOpenAIProvider(p.Name, p.APIKey, base, "qwen3.5-plus"))
|
||||
case store.ProviderZai:
|
||||
base := p.APIBase
|
||||
if base == "" {
|
||||
base = "https://api.z.ai/api/paas/v4"
|
||||
}
|
||||
registry.Register(providers.NewOpenAIProvider(p.Name, p.APIKey, base, "glm-5"))
|
||||
case store.ProviderZaiCoding:
|
||||
base := p.APIBase
|
||||
if base == "" {
|
||||
base = "https://api.z.ai/api/coding/paas/v4"
|
||||
}
|
||||
registry.Register(providers.NewOpenAIProvider(p.Name, p.APIKey, base, "glm-5"))
|
||||
case store.ProviderSuno:
|
||||
// Suno is a media-only provider (music gen). Register as OpenAI-compat
|
||||
// so credentialProvider interface works for API key/base extraction.
|
||||
|
||||
@@ -31,6 +31,8 @@ var defaultPlaceholderProviders = []store.LLMProviderData{
|
||||
{Name: "synthetic", DisplayName: "Synthetic", ProviderType: store.ProviderOpenAICompat, APIBase: "https://api.synthetic.new/openai/v1", Enabled: false},
|
||||
{Name: "alicloud-api", DisplayName: "AliCloud API", ProviderType: store.ProviderDashScope, APIBase: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", Enabled: false},
|
||||
{Name: "alicloud-sub", DisplayName: "AliCloud Sub", ProviderType: store.ProviderBailian, APIBase: "https://coding-intl.dashscope.aliyuncs.com/v1", Enabled: false},
|
||||
{Name: "zai", DisplayName: "Z.ai API", ProviderType: store.ProviderZai, APIBase: "https://api.z.ai/api/paas/v4", Enabled: false},
|
||||
{Name: "zai-coding", DisplayName: "Z.ai Coding Plan", ProviderType: store.ProviderZaiCoding, APIBase: "https://api.z.ai/api/coding/paas/v4", Enabled: false},
|
||||
}
|
||||
|
||||
// seedOnboardPlaceholders opens a PG store and seeds disabled placeholder providers
|
||||
|
||||
@@ -45,6 +45,8 @@ The Anthropic provider uses `x-api-key` header authentication and the `anthropic
|
||||
| perplexity | OpenAI-compatible | `https://api.perplexity.ai` | `sonar-pro` |
|
||||
| dashscope | OpenAI-compatible | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1` | `qwen3-max` |
|
||||
| bailian | OpenAI-compatible | `https://coding-intl.dashscope.aliyuncs.com/v1` | `qwen3.5-plus` |
|
||||
| zai | OpenAI-compatible | `https://api.z.ai/api/paas/v4` | `glm-5` |
|
||||
| zai_coding | OpenAI-compatible | `https://api.z.ai/api/coding/paas/v4` | `glm-5` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -182,6 +182,8 @@ type ProvidersConfig struct {
|
||||
Perplexity ProviderConfig `json:"perplexity"`
|
||||
DashScope ProviderConfig `json:"dashscope"`
|
||||
Bailian ProviderConfig `json:"bailian"`
|
||||
Zai ProviderConfig `json:"zai"`
|
||||
ZaiCoding ProviderConfig `json:"zai_coding"`
|
||||
ClaudeCLI ClaudeCLIConfig `json:"claude_cli"`
|
||||
}
|
||||
|
||||
@@ -214,6 +216,8 @@ func (c *Config) HasAnyProvider() bool {
|
||||
p.Perplexity.APIKey != "" ||
|
||||
p.DashScope.APIKey != "" ||
|
||||
p.Bailian.APIKey != "" ||
|
||||
p.Zai.APIKey != "" ||
|
||||
p.ZaiCoding.APIKey != "" ||
|
||||
p.ClaudeCLI.CLIPath != ""
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ func (c *Config) applyEnvOverrides() {
|
||||
envStr("GOCLAW_PERPLEXITY_API_KEY", &c.Providers.Perplexity.APIKey)
|
||||
envStr("GOCLAW_DASHSCOPE_API_KEY", &c.Providers.DashScope.APIKey)
|
||||
envStr("GOCLAW_BAILIAN_API_KEY", &c.Providers.Bailian.APIKey)
|
||||
envStr("GOCLAW_ZAI_API_KEY", &c.Providers.Zai.APIKey)
|
||||
envStr("GOCLAW_ZAI_CODING_API_KEY", &c.Providers.ZaiCoding.APIKey)
|
||||
envStr("GOCLAW_GATEWAY_TOKEN", &c.Gateway.Token)
|
||||
envStr("GOCLAW_TELEGRAM_TOKEN", &c.Channels.Telegram.Token)
|
||||
envStr("GOCLAW_DISCORD_TOKEN", &c.Channels.Discord.Token)
|
||||
|
||||
@@ -34,6 +34,8 @@ func (c *Config) MaskedCopy() *Config {
|
||||
maskNonEmpty(&cp.Providers.Perplexity.APIKey)
|
||||
maskNonEmpty(&cp.Providers.DashScope.APIKey)
|
||||
maskNonEmpty(&cp.Providers.Bailian.APIKey)
|
||||
maskNonEmpty(&cp.Providers.Zai.APIKey)
|
||||
maskNonEmpty(&cp.Providers.ZaiCoding.APIKey)
|
||||
|
||||
// Mask gateway token
|
||||
maskNonEmpty(&cp.Gateway.Token)
|
||||
@@ -81,6 +83,8 @@ func (c *Config) StripSecrets() {
|
||||
c.Providers.Perplexity.APIKey = ""
|
||||
c.Providers.DashScope.APIKey = ""
|
||||
c.Providers.Bailian.APIKey = ""
|
||||
c.Providers.Zai.APIKey = ""
|
||||
c.Providers.ZaiCoding.APIKey = ""
|
||||
|
||||
// Gateway token
|
||||
c.Gateway.Token = ""
|
||||
@@ -133,6 +137,8 @@ func (c *Config) StripMaskedSecrets() {
|
||||
stripIfMasked(&c.Providers.Perplexity.APIKey)
|
||||
stripIfMasked(&c.Providers.DashScope.APIKey)
|
||||
stripIfMasked(&c.Providers.Bailian.APIKey)
|
||||
stripIfMasked(&c.Providers.Zai.APIKey)
|
||||
stripIfMasked(&c.Providers.ZaiCoding.APIKey)
|
||||
|
||||
// Gateway token
|
||||
stripIfMasked(&c.Gateway.Token)
|
||||
|
||||
@@ -26,6 +26,8 @@ const (
|
||||
ProviderClaudeCLI = "claude_cli"
|
||||
ProviderSuno = "suno"
|
||||
ProviderYesScale = "yescale"
|
||||
ProviderZai = "zai"
|
||||
ProviderZaiCoding = "zai_coding"
|
||||
)
|
||||
|
||||
// ValidProviderTypes lists all accepted provider_type values.
|
||||
@@ -47,6 +49,8 @@ var ValidProviderTypes = map[string]bool{
|
||||
ProviderClaudeCLI: true,
|
||||
ProviderSuno: true,
|
||||
ProviderYesScale: true,
|
||||
ProviderZai: true,
|
||||
ProviderZaiCoding: true,
|
||||
}
|
||||
|
||||
// LLMProviderData represents an LLM provider configuration.
|
||||
|
||||
@@ -21,5 +21,7 @@ export const PROVIDER_TYPES: ProviderTypeInfo[] = [
|
||||
{ value: "dashscope", label: "DashScope (Qwen)", apiBase: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", placeholder: "" },
|
||||
{ value: "bailian", label: "Bailian Coding", apiBase: "https://coding-intl.dashscope.aliyuncs.com/v1", placeholder: "" },
|
||||
{ value: "yescale", label: "YesScale", apiBase: "https://api.yescale.one/v1", placeholder: "" },
|
||||
{ value: "zai", label: "Z.ai API", apiBase: "https://api.z.ai/api/paas/v4", placeholder: "" },
|
||||
{ value: "zai_coding", label: "Z.ai Coding Plan", apiBase: "https://api.z.ai/api/coding/paas/v4", placeholder: "" },
|
||||
{ value: "claude_cli", label: "Claude CLI (Local)", apiBase: "", placeholder: "" },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user