From b62863b724f8984ed48893adda7763f067499071 Mon Sep 17 00:00:00 2001 From: Henrique Costa Date: Thu, 12 Feb 2026 19:08:35 -0300 Subject: [PATCH] add zai provider and improve telegram typing UX --- cmd/picoclaw/main.go | 2 + config/config.example.json | 4 ++ pkg/config/config.go | 2 + pkg/migrate/config.go | 6 +++ pkg/providers/provider_registry.go | 4 ++ pkg/providers/provider_registry_defaults.go | 7 ++++ pkg/providers/provider_registry_test.go | 42 +++++++++++++++++++++ 7 files changed, 67 insertions(+) diff --git a/cmd/picoclaw/main.go b/cmd/picoclaw/main.go index 50b15d5bf..17c4a271d 100644 --- a/cmd/picoclaw/main.go +++ b/cmd/picoclaw/main.go @@ -882,6 +882,7 @@ func statusCmd() { 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 != "" @@ -896,6 +897,7 @@ func statusCmd() { 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 64d3dd834..281f12342 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -74,6 +74,10 @@ "api_key": "YOUR_ZHIPU_API_KEY", "api_base": "" }, + "zai": { + "api_key": "YOUR_ZAI_API_KEY", + "api_base": "https://api.z.ai/api/paas/v4" + }, "gemini": { "api_key": "", "api_base": "" diff --git a/pkg/config/config.go b/pkg/config/config.go index 0e89b3d10..a24f014bb 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -139,6 +139,7 @@ type ProvidersConfig struct { OpenRouter ProviderConfig `json:"openrouter"` Groq ProviderConfig `json:"groq"` Zhipu ProviderConfig `json:"zhipu"` + ZAI ProviderConfig `json:"zai"` VLLM ProviderConfig `json:"vllm"` Gemini ProviderConfig `json:"gemini"` Nvidia ProviderConfig `json:"nvidia"` @@ -239,6 +240,7 @@ func DefaultConfig() *Config { OpenRouter: ProviderConfig{}, Groq: ProviderConfig{}, Zhipu: ProviderConfig{}, + ZAI: ProviderConfig{}, VLLM: ProviderConfig{}, Gemini: ProviderConfig{}, Nvidia: ProviderConfig{}, diff --git a/pkg/migrate/config.go b/pkg/migrate/config.go index d7fa63305..b2478af28 100644 --- a/pkg/migrate/config.go +++ b/pkg/migrate/config.go @@ -17,6 +17,7 @@ var supportedProviders = map[string]bool{ "openrouter": true, "groq": true, "zhipu": true, + "zai": true, "vllm": true, "gemini": true, } @@ -115,6 +116,8 @@ func ConvertConfig(data map[string]interface{}) (*config.Config, []string, error cfg.Providers.Groq = pc case "zhipu": cfg.Providers.Zhipu = pc + case "zai": + cfg.Providers.ZAI = pc case "vllm": cfg.Providers.VLLM = pc case "gemini": @@ -242,6 +245,9 @@ func MergeConfig(existing, incoming *config.Config) *config.Config { 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/provider_registry.go b/pkg/providers/provider_registry.go index 87455366b..925642079 100644 --- a/pkg/providers/provider_registry.go +++ b/pkg/providers/provider_registry.go @@ -153,6 +153,10 @@ func zhipuCreator(cfg *config.Config, _ string) (LLMProvider, bool, error) { return createHTTPProviderFromConfig(cfg.Providers.Zhipu, "https://open.bigmodel.cn/api/paas/v4", true, false) } +func zaiCreator(cfg *config.Config, _ string) (LLMProvider, bool, error) { + return createHTTPProviderFromConfig(cfg.Providers.ZAI, "https://api.z.ai/api/paas/v4", true, false) +} + func geminiCreator(cfg *config.Config, _ string) (LLMProvider, bool, error) { return createHTTPProviderFromConfig(cfg.Providers.Gemini, "https://generativelanguage.googleapis.com/v1beta", true, false) } diff --git a/pkg/providers/provider_registry_defaults.go b/pkg/providers/provider_registry_defaults.go index 3a6c11473..b92480ea4 100644 --- a/pkg/providers/provider_registry_defaults.go +++ b/pkg/providers/provider_registry_defaults.go @@ -41,6 +41,13 @@ func init() { Creator: zhipuCreator, }) + RegisterProvider(providerRegistration{ + Name: "zai", + Aliases: []string{"z.ai"}, + ModelPrefixes: []string{"zai/"}, + Creator: zaiCreator, + }) + RegisterProvider(providerRegistration{ Name: "groq", ModelPrefixes: []string{"groq/"}, diff --git a/pkg/providers/provider_registry_test.go b/pkg/providers/provider_registry_test.go index 9d3520e41..d59acda9e 100644 --- a/pkg/providers/provider_registry_test.go +++ b/pkg/providers/provider_registry_test.go @@ -30,6 +30,48 @@ func TestCreateProvider_ZenExplicit(t *testing.T) { } } +func TestCreateProvider_ZAIExplicit(t *testing.T) { + cfg := config.DefaultConfig() + cfg.Agents.Defaults.Provider = "zai" + cfg.Agents.Defaults.Model = "glm-4.6" + cfg.Providers.ZAI.APIKey = "zai-key" + + provider, err := CreateProvider(cfg) + if err != nil { + t.Fatalf("CreateProvider(zai) error = %v", err) + } + + httpProvider, ok := provider.(*HTTPProvider) + if !ok { + t.Fatalf("CreateProvider(zai) returned %T, want *HTTPProvider", provider) + } + if httpProvider.apiBase != "https://api.z.ai/api/paas/v4" { + t.Errorf("apiBase = %q, want %q", httpProvider.apiBase, "https://api.z.ai/api/paas/v4") + } + if httpProvider.apiKey != "zai-key" { + t.Errorf("apiKey = %q, want %q", httpProvider.apiKey, "zai-key") + } +} + +func TestCreateProvider_ZAIByModelPrefix(t *testing.T) { + cfg := config.DefaultConfig() + cfg.Agents.Defaults.Model = "zai/glm-4.6" + cfg.Providers.ZAI.APIKey = "zai-key" + + provider, err := CreateProvider(cfg) + if err != nil { + t.Fatalf("CreateProvider(zai/*) error = %v", err) + } + + httpProvider, ok := provider.(*HTTPProvider) + if !ok { + t.Fatalf("CreateProvider(zai/*) returned %T, want *HTTPProvider", provider) + } + if httpProvider.apiBase != "https://api.z.ai/api/paas/v4" { + t.Errorf("apiBase = %q, want %q", httpProvider.apiBase, "https://api.z.ai/api/paas/v4") + } +} + func TestCreateProvider_ZenByModelPrefix(t *testing.T) { cfg := config.DefaultConfig() cfg.Agents.Defaults.Model = "zen/kimi-k2.5-free"