mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-06-10 08:11:23 +00:00
e63ff014cb
* 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
86 lines
2.9 KiB
Go
86 lines
2.9 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
"github.com/nextlevelbuilder/goclaw/internal/store/pg"
|
|
)
|
|
|
|
// testPostgresConnection verifies connectivity to Postgres with a 5s timeout.
|
|
func testPostgresConnection(dsn string) error {
|
|
db, err := pg.OpenDB(dsn)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer db.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
return db.PingContext(ctx)
|
|
}
|
|
|
|
// defaultPlaceholderProviders defines disabled placeholder providers seeded for
|
|
// UI discoverability. Users can later enable and configure them via the dashboard.
|
|
var defaultPlaceholderProviders = []store.LLMProviderData{
|
|
{Name: "openrouter", DisplayName: "OpenRouter", ProviderType: store.ProviderOpenRouter, APIBase: "https://openrouter.ai/api/v1", Enabled: false},
|
|
{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
|
|
// so they appear in the UI for easy configuration.
|
|
func seedOnboardPlaceholders(dsn string) error {
|
|
storeCfg := store.StoreConfig{
|
|
PostgresDSN: dsn,
|
|
EncryptionKey: os.Getenv("GOCLAW_ENCRYPTION_KEY"),
|
|
}
|
|
stores, err := pg.NewPGStores(storeCfg)
|
|
if err != nil {
|
|
return fmt.Errorf("open PG stores: %w", err)
|
|
}
|
|
|
|
if stores.Providers == nil {
|
|
return nil
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
// Build a set of existing api_base values to avoid overwriting user-configured entries.
|
|
existing, err := stores.Providers.ListProviders(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("list providers: %w", err)
|
|
}
|
|
existingBases := make(map[string]bool, len(existing))
|
|
for _, p := range existing {
|
|
if p.APIBase != "" {
|
|
existingBases[p.APIBase] = true
|
|
}
|
|
}
|
|
|
|
seeded := 0
|
|
for _, ph := range defaultPlaceholderProviders {
|
|
if ph.APIBase != "" && existingBases[ph.APIBase] {
|
|
continue
|
|
}
|
|
p := ph // copy
|
|
if err := stores.Providers.CreateProvider(ctx, &p); err != nil {
|
|
slog.Debug("seed placeholder skipped (may already exist)", "name", ph.Name, "error", err)
|
|
continue
|
|
}
|
|
seeded++
|
|
}
|
|
|
|
if seeded > 0 {
|
|
slog.Info("seeded placeholder providers", "count", seeded)
|
|
}
|
|
return nil
|
|
}
|