From 09a03c4ed57cf9340dd6c67ed9f9545fcd2af5fa Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 18 Feb 2026 12:12:42 +0000 Subject: [PATCH] fix: complete provider migration from Moonshot/Kimi to Z.ai The previous migration (c96c882) was incomplete - the agent was still resolving to Moonshot/Kimi provider configs instead of Z.ai. This commit fully migrates the provider system: - Rename Zhipu/Moonshot provider to Zai in ProvidersConfig (with backward-compat fields for "zhipu" and "moonshot" JSON keys) - Add migrateProviders() in LoadConfig to auto-migrate old configs - Merge moonshot/kimi and zhipu/glm provider cases into unified zai case in CreateProvider - Update default API base to https://api.z.ai/api/paas/v4 - Update status command, migration logic, example config, and tests https://claude.ai/code/session_01MYemTMPtHrcgidWs8UdjcG --- .github/pull_request_template.md | 2 +- cmd/picoclaw/main.go | 4 +-- config/config.example.json | 6 ++--- pkg/config/config.go | 31 ++++++++++++++++------ pkg/config/config_test.go | 4 +-- pkg/migrate/config.go | 8 +++--- pkg/providers/codex_provider.go | 3 ++- pkg/providers/http_provider.go | 45 ++++++++++++++++---------------- 8 files changed, 60 insertions(+), 43 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 7910cb1e2..7e81176be 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -20,7 +20,7 @@ ## 🧪 Test Environment & Hardware - **Hardware:** [e.g. Raspberry Pi 5, Orange Pi, PC] - **OS:** [e.g. Debian 12, Ubuntu 22.04] -- **Model/Provider:** [e.g. OpenAI GPT-4o, Kimi k2, DeepSeek-V3] +- **Model/Provider:** [e.g. OpenAI GPT-4o, Z.ai GLM-4.7, DeepSeek-V3] - **Channels:** [e.g. Discord, Telegram, Feishu, ...] diff --git a/cmd/picoclaw/main.go b/cmd/picoclaw/main.go index b78983dc4..19f3de17f 100644 --- a/cmd/picoclaw/main.go +++ b/cmd/picoclaw/main.go @@ -729,7 +729,7 @@ func statusCmd() { hasAnthropic := cfg.Providers.Anthropic.APIKey != "" hasOpenAI := cfg.Providers.OpenAI.APIKey != "" hasGemini := cfg.Providers.Gemini.APIKey != "" - hasZhipu := cfg.Providers.Zhipu.APIKey != "" + hasZai := cfg.Providers.Zai.APIKey != "" hasGroq := cfg.Providers.Groq.APIKey != "" hasVLLM := cfg.Providers.VLLM.APIBase != "" @@ -743,7 +743,7 @@ func statusCmd() { fmt.Println("Anthropic API:", status(hasAnthropic)) fmt.Println("OpenAI API:", status(hasOpenAI)) fmt.Println("Gemini API:", status(hasGemini)) - fmt.Println("Zhipu API:", status(hasZhipu)) + fmt.Println("Z.ai API:", status(hasZai)) fmt.Println("Groq API:", status(hasGroq)) if hasVLLM { fmt.Printf("vLLM/Local: ✓ %s\n", cfg.Providers.VLLM.APIBase) diff --git a/config/config.example.json b/config/config.example.json index 7cd0ab8c6..b461451b8 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -89,8 +89,8 @@ "api_key": "gsk_xxx", "api_base": "" }, - "zhipu": { - "api_key": "YOUR_ZHIPU_API_KEY", + "zai": { + "api_key": "YOUR_ZAI_API_KEY", "api_base": "" }, "gemini": { @@ -107,7 +107,7 @@ "proxy": "http://127.0.0.1:7890" }, "moonshot": { - "api_key": "sk-xxx", + "api_key": "", "api_base": "" }, "ollama": { diff --git a/pkg/config/config.go b/pkg/config/config.go index 1d34f56f3..e88b30ff4 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -171,12 +171,13 @@ type ProvidersConfig struct { OpenAI ProviderConfig `json:"openai"` OpenRouter ProviderConfig `json:"openrouter"` Groq ProviderConfig `json:"groq"` - Zhipu ProviderConfig `json:"zhipu"` + Zai ProviderConfig `json:"zai"` + Zhipu ProviderConfig `json:"zhipu"` // Deprecated: use "zai" instead VLLM ProviderConfig `json:"vllm"` Gemini ProviderConfig `json:"gemini"` Nvidia ProviderConfig `json:"nvidia"` Ollama ProviderConfig `json:"ollama"` - Moonshot ProviderConfig `json:"moonshot"` + Moonshot ProviderConfig `json:"moonshot"` // Deprecated: use "zai" instead ShengSuanYun ProviderConfig `json:"shengsuanyun"` DeepSeek ProviderConfig `json:"deepseek"` GitHubCopilot ProviderConfig `json:"github_copilot"` @@ -311,11 +312,10 @@ func DefaultConfig() *Config { OpenAI: ProviderConfig{}, OpenRouter: ProviderConfig{}, Groq: ProviderConfig{}, - Zhipu: ProviderConfig{}, + Zai: ProviderConfig{}, VLLM: ProviderConfig{}, Gemini: ProviderConfig{}, Nvidia: ProviderConfig{}, - Moonshot: ProviderConfig{}, ShengSuanYun: ProviderConfig{}, }, Gateway: GatewayConfig{ @@ -373,9 +373,24 @@ func LoadConfig(path string) (*Config, error) { return nil, err } + // Migrate deprecated provider configs to Zai (Z.ai, formerly Zhipu/Moonshot) + cfg.migrateProviders() + return cfg, nil } +// migrateProviders merges deprecated Zhipu and Moonshot provider configs into Zai. +// If Zai is not configured, it falls back to Zhipu first, then Moonshot. +func (c *Config) migrateProviders() { + if c.Providers.Zai.APIKey == "" { + if c.Providers.Zhipu.APIKey != "" { + c.Providers.Zai = c.Providers.Zhipu + } else if c.Providers.Moonshot.APIKey != "" { + c.Providers.Zai = c.Providers.Moonshot + } + } +} + func SaveConfig(path string, cfg *Config) error { cfg.mu.RLock() defer cfg.mu.RUnlock() @@ -414,8 +429,8 @@ func (c *Config) GetAPIKey() string { if c.Providers.Gemini.APIKey != "" { return c.Providers.Gemini.APIKey } - if c.Providers.Zhipu.APIKey != "" { - return c.Providers.Zhipu.APIKey + if c.Providers.Zai.APIKey != "" { + return c.Providers.Zai.APIKey } if c.Providers.Groq.APIKey != "" { return c.Providers.Groq.APIKey @@ -438,8 +453,8 @@ func (c *Config) GetAPIBase() string { } return "https://openrouter.ai/api/v1" } - if c.Providers.Zhipu.APIKey != "" { - return c.Providers.Zhipu.APIBase + if c.Providers.Zai.APIKey != "" { + return c.Providers.Zai.APIBase } if c.Providers.VLLM.APIKey != "" && c.Providers.VLLM.APIBase != "" { return c.Providers.VLLM.APIBase diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index febfd0456..174d0bcc8 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -92,8 +92,8 @@ func TestDefaultConfig_Providers(t *testing.T) { if cfg.Providers.Groq.APIKey != "" { t.Error("Groq API key should be empty by default") } - if cfg.Providers.Zhipu.APIKey != "" { - t.Error("Zhipu API key should be empty by default") + if cfg.Providers.Zai.APIKey != "" { + t.Error("Z.ai API key should be empty by default") } if cfg.Providers.VLLM.APIKey != "" { t.Error("VLLM API key should be empty by default") diff --git a/pkg/migrate/config.go b/pkg/migrate/config.go index 9c1e36359..e6cd0f6b8 100644 --- a/pkg/migrate/config.go +++ b/pkg/migrate/config.go @@ -113,8 +113,8 @@ func ConvertConfig(data map[string]interface{}) (*config.Config, []string, error cfg.Providers.OpenRouter = pc case "groq": cfg.Providers.Groq = pc - case "zhipu": - cfg.Providers.Zhipu = pc + case "zhipu", "zai": + cfg.Providers.Zai = pc case "vllm": cfg.Providers.VLLM = pc case "gemini": @@ -244,8 +244,8 @@ func MergeConfig(existing, incoming *config.Config) *config.Config { if existing.Providers.Groq.APIKey == "" { existing.Providers.Groq = incoming.Providers.Groq } - if existing.Providers.Zhipu.APIKey == "" { - existing.Providers.Zhipu = incoming.Providers.Zhipu + if existing.Providers.Zai.APIKey == "" { + existing.Providers.Zai = incoming.Providers.Zai } if existing.Providers.VLLM.APIKey == "" && existing.Providers.VLLM.APIBase == "" { existing.Providers.VLLM = incoming.Providers.VLLM diff --git a/pkg/providers/codex_provider.go b/pkg/providers/codex_provider.go index 7617bf716..77a2be05b 100644 --- a/pkg/providers/codex_provider.go +++ b/pkg/providers/codex_provider.go @@ -158,7 +158,7 @@ func resolveCodexModel(model string) (string, string) { "anthropic", "gemini", "google", - "moonshot", + "zai", "kimi", "qwen", "deepseek", @@ -168,6 +168,7 @@ func resolveCodexModel(model string) (string, string) { "grok", "xai", "zhipu", + "moonshot", } for _, prefix := range unsupportedPrefixes { if strings.HasPrefix(m, prefix) { diff --git a/pkg/providers/http_provider.go b/pkg/providers/http_provider.go index 8b5381a71..959169fb1 100644 --- a/pkg/providers/http_provider.go +++ b/pkg/providers/http_provider.go @@ -53,10 +53,10 @@ func (p *HTTPProvider) Chat(ctx context.Context, messages []Message, tools []Too return nil, fmt.Errorf("API base not configured") } - // Strip provider prefix from model name (e.g., moonshot/kimi-k2.5 -> kimi-k2.5, groq/openai/gpt-oss-120b -> openai/gpt-oss-120b, ollama/qwen2.5:14b -> qwen2.5:14b) + // Strip provider prefix from model name (e.g., zai/glm-4.7 -> glm-4.7, groq/openai/gpt-oss-120b -> openai/gpt-oss-120b, ollama/qwen2.5:14b -> qwen2.5:14b) if idx := strings.Index(model, "/"); idx != -1 { prefix := model[:idx] - if prefix == "moonshot" || prefix == "nvidia" || prefix == "groq" || prefix == "ollama" { + if prefix == "zai" || prefix == "moonshot" || prefix == "nvidia" || prefix == "groq" || prefix == "ollama" { model = model[idx+1:] } } @@ -272,12 +272,13 @@ func CreateProvider(cfg *config.Config) (LLMProvider, error) { apiBase = "https://openrouter.ai/api/v1" } } - case "zhipu", "glm": - if cfg.Providers.Zhipu.APIKey != "" { - apiKey = cfg.Providers.Zhipu.APIKey - apiBase = cfg.Providers.Zhipu.APIBase + case "zai", "z.ai", "zhipu", "glm": + if cfg.Providers.Zai.APIKey != "" { + apiKey = cfg.Providers.Zai.APIKey + apiBase = cfg.Providers.Zai.APIBase + proxy = cfg.Providers.Zai.Proxy if apiBase == "" { - apiBase = "https://open.bigmodel.cn/api/paas/v4" + apiBase = "https://api.z.ai/api/paas/v4" } } case "gemini", "google": @@ -325,12 +326,12 @@ func CreateProvider(cfg *config.Config) (LLMProvider, error) { } } case "moonshot", "kimi": - if cfg.Providers.Moonshot.APIKey != "" { - apiKey = cfg.Providers.Moonshot.APIKey - apiBase = cfg.Providers.Moonshot.APIBase - proxy = cfg.Providers.Moonshot.Proxy + if cfg.Providers.Zai.APIKey != "" { + apiKey = cfg.Providers.Zai.APIKey + apiBase = cfg.Providers.Zai.APIBase + proxy = cfg.Providers.Zai.Proxy if apiBase == "" { - apiBase = "https://api.moonshot.cn/v1" + apiBase = "https://api.z.ai/api/paas/v4" } } case "github_copilot", "copilot": @@ -348,12 +349,12 @@ func CreateProvider(cfg *config.Config) (LLMProvider, error) { // Fallback: detect provider from model name if apiKey == "" && apiBase == "" { switch { - case (strings.Contains(lowerModel, "kimi") || strings.Contains(lowerModel, "moonshot") || strings.HasPrefix(model, "moonshot/")) && cfg.Providers.Moonshot.APIKey != "": - apiKey = cfg.Providers.Moonshot.APIKey - apiBase = cfg.Providers.Moonshot.APIBase - proxy = cfg.Providers.Moonshot.Proxy + case (strings.Contains(lowerModel, "kimi") || strings.Contains(lowerModel, "moonshot") || strings.HasPrefix(model, "moonshot/") || strings.Contains(lowerModel, "zai") || strings.HasPrefix(model, "zai/")) && cfg.Providers.Zai.APIKey != "": + apiKey = cfg.Providers.Zai.APIKey + apiBase = cfg.Providers.Zai.APIBase + proxy = cfg.Providers.Zai.Proxy if apiBase == "" { - apiBase = "https://api.moonshot.cn/v1" + apiBase = "https://api.z.ai/api/paas/v4" } case strings.HasPrefix(model, "openrouter/") || strings.HasPrefix(model, "anthropic/") || strings.HasPrefix(model, "openai/") || strings.HasPrefix(model, "meta-llama/") || strings.HasPrefix(model, "deepseek/") || strings.HasPrefix(model, "google/"): @@ -395,12 +396,12 @@ func CreateProvider(cfg *config.Config) (LLMProvider, error) { apiBase = "https://generativelanguage.googleapis.com/v1beta" } - case (strings.Contains(lowerModel, "glm") || strings.Contains(lowerModel, "zhipu") || strings.Contains(lowerModel, "zai")) && cfg.Providers.Zhipu.APIKey != "": - apiKey = cfg.Providers.Zhipu.APIKey - apiBase = cfg.Providers.Zhipu.APIBase - proxy = cfg.Providers.Zhipu.Proxy + case (strings.Contains(lowerModel, "glm") || strings.Contains(lowerModel, "zhipu")) && cfg.Providers.Zai.APIKey != "": + apiKey = cfg.Providers.Zai.APIKey + apiBase = cfg.Providers.Zai.APIBase + proxy = cfg.Providers.Zai.Proxy if apiBase == "" { - apiBase = "https://open.bigmodel.cn/api/paas/v4" + apiBase = "https://api.z.ai/api/paas/v4" } case (strings.Contains(lowerModel, "groq") || strings.HasPrefix(model, "groq/")) && cfg.Providers.Groq.APIKey != "":