From 8bbefbe9ae2e3543bc751423c50fae554668ef72 Mon Sep 17 00:00:00 2001 From: DBT Date: Thu, 12 Feb 2026 04:21:20 +0000 Subject: [PATCH] refactor: enforce CLIProxyAPI as mandatory upstream and remove individual providers --- README.md | 10 +-- README_EN.md | 10 +-- cmd/clawgo/main.go | 130 ++++++--------------------------- pkg/config/config.go | 55 ++------------ pkg/providers/http_provider.go | 83 +-------------------- 5 files changed, 40 insertions(+), 248 deletions(-) diff --git a/README.md b/README.md index f4645ac..a042fc4 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ - **💰 极低成本**:完美适配 LicheeRV Nano 或 Orange Pi Zero 等 $10 级别的单板机。 - **🔌 即插即用**:单二进制文件,无复杂依赖。 - **🧩 技能系统**:通过 `clawhub`、`coding-agent` 等技能扩展能力。 -- **🔐 便捷认证**:交互式 `login` 命令,支持 OpenAI、Anthropic、Gemini 等主流服务商。 +- **🔐 统一接口**:强制要求使用 [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) 作为上游。 ## 🏁 快速开始 @@ -20,14 +20,10 @@ clawgo onboard ``` -**2. 配置服务商** -交互式设置您的 API Key (OpenAI, Anthropic, Gemini, Zhipu 等): +**2. 配置 CLIProxyAPI** +确保您的 [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) 正在运行。 ```bash clawgo login -# 或者直接指定服务商: -# clawgo login openai -# clawgo login anthropic -# clawgo login gemini ``` **3. 开始聊天!** diff --git a/README_EN.md b/README_EN.md index dd78bf8..f3df2e5 100644 --- a/README_EN.md +++ b/README_EN.md @@ -7,7 +7,7 @@ - **💰 Ultra-Low Cost**: Perfect for $10 SBCs like LicheeRV Nano or Orange Pi Zero. - **🔌 Plug & Play**: Single binary. No complex dependencies. - **🧩 Skill System**: Extend capabilities with `clawhub`, `coding-agent`, and more. -- **🔐 Easy Auth**: Interactive `login` command for OpenAI, Anthropic, Gemini, etc. +- **🔐 Unified Interface**: Mandatory use of [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) as the upstream proxy. ## 🏁 Quick Start @@ -16,14 +16,10 @@ clawgo onboard ``` -**2. Configure Provider** -Interactively set up your API key (OpenAI, Anthropic, Gemini, Zhipu, etc.): +**2. Configure CLIProxyAPI** +Ensure [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) is running. ```bash clawgo login -# Or specify provider directly: -# clawgo login openai -# clawgo login anthropic -# clawgo login gemini ``` **3. Chat!** diff --git a/cmd/clawgo/main.go b/cmd/clawgo/main.go index 18f0a8f..e6f9f35 100644 --- a/cmd/clawgo/main.go +++ b/cmd/clawgo/main.go @@ -171,7 +171,7 @@ func printHelp() { fmt.Println(" gateway Start clawgo gateway") fmt.Println(" status Show clawgo status") fmt.Println(" cron Manage scheduled tasks") - fmt.Println(" login Configure model provider credentials") + fmt.Println(" login Configure CLIProxyAPI upstream") fmt.Println(" skills Manage skills (install, list, remove)") fmt.Println(" version Show version information") } @@ -205,8 +205,8 @@ func onboard() { fmt.Printf("%s clawgo is ready!\n", logo) fmt.Println("\nNext steps:") - fmt.Println(" 1. Add your API key to", configPath) - fmt.Println(" Get one at: https://openrouter.ai/keys") + fmt.Println(" 1. Configure CLIProxyAPI at", configPath) + fmt.Println(" Ensure CLIProxyAPI is running: https://github.com/router-for-me/CLIProxyAPI") fmt.Println(" 2. Chat: clawgo agent -m \"Hello!\"") } @@ -681,32 +681,13 @@ func statusCmd() { if _, err := os.Stat(configPath); err == nil { fmt.Printf("Model: %s\n", cfg.Agents.Defaults.Model) - - hasOpenRouter := cfg.Providers.OpenRouter.APIKey != "" - hasAnthropic := cfg.Providers.Anthropic.APIKey != "" - hasOpenAI := cfg.Providers.OpenAI.APIKey != "" - hasGemini := cfg.Providers.Gemini.APIKey != "" - hasZhipu := cfg.Providers.Zhipu.APIKey != "" - hasGroq := cfg.Providers.Groq.APIKey != "" - hasVLLM := cfg.Providers.VLLM.APIBase != "" - - status := func(enabled bool) string { - if enabled { - return "✓" - } - return "not set" - } - fmt.Println("OpenRouter API:", status(hasOpenRouter)) - 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("Groq API:", status(hasGroq)) - if hasVLLM { - fmt.Printf("vLLM/Local: ✓ %s\n", cfg.Providers.VLLM.APIBase) - } else { - fmt.Println("vLLM/Local: not set") + fmt.Printf("CLIProxyAPI Base: %s\n", cfg.Providers.Proxy.APIBase) + hasKey := cfg.Providers.Proxy.APIKey != "" + status := "not set" + if hasKey { + status = "✓" } + fmt.Printf("CLIProxyAPI Key: %s\n", status) } } @@ -1181,91 +1162,28 @@ func loginCmd() { os.Exit(1) } - providersList := []string{"OpenAI", "Anthropic", "Gemini", "OpenRouter", "Zhipu", "Groq", "VLLM"} + fmt.Println("Configuring CLIProxyAPI...") + fmt.Printf("Current Base: %s\n", cfg.Providers.Proxy.APIBase) - if len(os.Args) > 2 { - provider := os.Args[2] - found := false - for _, p := range providersList { - if strings.EqualFold(p, provider) { - configureProvider(cfg, p) - found = true - break - } - } - if !found { - fmt.Printf("Unknown provider: %s\n", provider) - fmt.Println("Available providers:", strings.Join(providersList, ", ")) - } - return + fmt.Print("Enter CLIProxyAPI Base URL (e.g. http://localhost:8080/v1): ") + reader := bufio.NewReader(os.Stdin) + line, _ := reader.ReadString('\n') + apiBase := strings.TrimSpace(line) + if apiBase != "" { + cfg.Providers.Proxy.APIBase = apiBase } - fmt.Println("Select provider to configure:") - for i, p := range providersList { - fmt.Printf("%d. %s\n", i+1, p) - } - - fmt.Print("\nEnter choice (number): ") - var choice int - _, err = fmt.Scanln(&choice) - if err != nil || choice < 1 || choice > len(providersList) { - fmt.Println("Invalid choice.") - return - } - - selected := providersList[choice-1] - configureProvider(cfg, selected) -} - -func configureProvider(cfg *config.Config, provider string) { - fmt.Printf("\nConfiguring %s...\n", provider) - - fmt.Print("Enter API Key: ") - var apiKey string - fmt.Scanln(&apiKey) - - var apiBase string - // For VLLM or OpenAI, user might want custom base - if provider == "VLLM" || provider == "OpenAI" || provider == "OpenRouter" { - fmt.Print("Enter API Base URL (optional, press Enter to skip): ") - reader := bufio.NewReader(os.Stdin) - line, _ := reader.ReadString('\n') - apiBase = strings.TrimSpace(line) - } - - switch provider { - case "OpenAI": - cfg.Providers.OpenAI.APIKey = apiKey - if apiBase != "" { - cfg.Providers.OpenAI.APIBase = apiBase - } - case "Anthropic": - cfg.Providers.Anthropic.APIKey = apiKey - if apiBase != "" { - cfg.Providers.Anthropic.APIBase = apiBase - } - case "Gemini": - cfg.Providers.Gemini.APIKey = apiKey - case "OpenRouter": - cfg.Providers.OpenRouter.APIKey = apiKey - if apiBase != "" { - cfg.Providers.OpenRouter.APIBase = apiBase - } - case "Zhipu": - cfg.Providers.Zhipu.APIKey = apiKey - case "Groq": - cfg.Providers.Groq.APIKey = apiKey - case "VLLM": - cfg.Providers.VLLM.APIKey = apiKey - if apiBase != "" { - cfg.Providers.VLLM.APIBase = apiBase - } - } + fmt.Print("Enter API Key (optional): ") + fmt.Scanln(&cfg.Providers.Proxy.APIKey) if err := config.SaveConfig(getConfigPath(), cfg); err != nil { fmt.Printf("Error saving config: %v\n", err) os.Exit(1) } - fmt.Printf("✓ %s configuration saved.\n", provider) + fmt.Println("✓ CLIProxyAPI configuration saved.") +} + +func configureProvider(cfg *config.Config, provider string) { + // Deprecated: Migrated to CLIProxyAPI logic in loginCmd } diff --git a/pkg/config/config.go b/pkg/config/config.go index e76378a..9ad12db 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -89,13 +89,7 @@ type DingTalkConfig struct { } type ProvidersConfig struct { - Anthropic ProviderConfig `json:"anthropic"` - OpenAI ProviderConfig `json:"openai"` - OpenRouter ProviderConfig `json:"openrouter"` - Groq ProviderConfig `json:"groq"` - Zhipu ProviderConfig `json:"zhipu"` - VLLM ProviderConfig `json:"vllm"` - Gemini ProviderConfig `json:"gemini"` + Proxy ProviderConfig `json:"proxy"` } type ProviderConfig struct { @@ -203,13 +197,9 @@ func DefaultConfig() *Config { }, }, Providers: ProvidersConfig{ - Anthropic: ProviderConfig{}, - OpenAI: ProviderConfig{}, - OpenRouter: ProviderConfig{}, - Groq: ProviderConfig{}, - Zhipu: ProviderConfig{}, - VLLM: ProviderConfig{}, - Gemini: ProviderConfig{}, + Proxy: ProviderConfig{ + APIBase: "http://localhost:8080/v1", + }, }, Gateway: GatewayConfig{ Host: "0.0.0.0", @@ -274,46 +264,13 @@ func (c *Config) WorkspacePath() string { func (c *Config) GetAPIKey() string { c.mu.RLock() defer c.mu.RUnlock() - if c.Providers.OpenRouter.APIKey != "" { - return c.Providers.OpenRouter.APIKey - } - if c.Providers.Anthropic.APIKey != "" { - return c.Providers.Anthropic.APIKey - } - if c.Providers.OpenAI.APIKey != "" { - return c.Providers.OpenAI.APIKey - } - if c.Providers.Gemini.APIKey != "" { - return c.Providers.Gemini.APIKey - } - if c.Providers.Zhipu.APIKey != "" { - return c.Providers.Zhipu.APIKey - } - if c.Providers.Groq.APIKey != "" { - return c.Providers.Groq.APIKey - } - if c.Providers.VLLM.APIKey != "" { - return c.Providers.VLLM.APIKey - } - return "" + return c.Providers.Proxy.APIKey } func (c *Config) GetAPIBase() string { c.mu.RLock() defer c.mu.RUnlock() - if c.Providers.OpenRouter.APIKey != "" { - if c.Providers.OpenRouter.APIBase != "" { - return c.Providers.OpenRouter.APIBase - } - return "https://openrouter.ai/api/v1" - } - if c.Providers.Zhipu.APIKey != "" { - return c.Providers.Zhipu.APIBase - } - if c.Providers.VLLM.APIKey != "" && c.Providers.VLLM.APIBase != "" { - return c.Providers.VLLM.APIBase - } - return "" + return c.Providers.Proxy.APIBase } func expandHome(path string) string { diff --git a/pkg/providers/http_provider.go b/pkg/providers/http_provider.go index 0028777..0889776 100644 --- a/pkg/providers/http_provider.go +++ b/pkg/providers/http_provider.go @@ -175,87 +175,12 @@ func (p *HTTPProvider) GetDefaultModel() string { } func CreateProvider(cfg *config.Config) (LLMProvider, error) { - model := cfg.Agents.Defaults.Model - - var apiKey, apiBase, authMode string - - lowerModel := strings.ToLower(model) - - switch { - 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/"): - apiKey = cfg.Providers.OpenRouter.APIKey - authMode = cfg.Providers.OpenRouter.Auth - if cfg.Providers.OpenRouter.APIBase != "" { - apiBase = cfg.Providers.OpenRouter.APIBase - } else { - apiBase = "https://openrouter.ai/api/v1" - } - - case strings.Contains(lowerModel, "claude") || strings.HasPrefix(model, "anthropic/"): - apiKey = cfg.Providers.Anthropic.APIKey - authMode = cfg.Providers.Anthropic.Auth - apiBase = cfg.Providers.Anthropic.APIBase - if apiBase == "" { - apiBase = "https://api.anthropic.com/v1" - } - - case strings.Contains(lowerModel, "gpt") || strings.HasPrefix(model, "openai/") || strings.Contains(lowerModel, "codex"): - apiKey = cfg.Providers.OpenAI.APIKey - authMode = cfg.Providers.OpenAI.Auth - apiBase = cfg.Providers.OpenAI.APIBase - if apiBase == "" { - apiBase = "https://api.openai.com/v1" - } - - case strings.Contains(lowerModel, "gemini") || strings.HasPrefix(model, "google/"): - apiKey = cfg.Providers.Gemini.APIKey - authMode = cfg.Providers.Gemini.Auth - apiBase = cfg.Providers.Gemini.APIBase - if apiBase == "" { - apiBase = "https://generativelanguage.googleapis.com/v1beta" - } - - case strings.Contains(lowerModel, "glm") || strings.Contains(lowerModel, "zhipu") || strings.Contains(lowerModel, "zai"): - apiKey = cfg.Providers.Zhipu.APIKey - authMode = cfg.Providers.Zhipu.Auth - apiBase = cfg.Providers.Zhipu.APIBase - if apiBase == "" { - apiBase = "https://open.bigmodel.cn/api/paas/v4" - } - - case strings.Contains(lowerModel, "groq") || strings.HasPrefix(model, "groq/"): - apiKey = cfg.Providers.Groq.APIKey - authMode = cfg.Providers.Groq.Auth - apiBase = cfg.Providers.Groq.APIBase - if apiBase == "" { - apiBase = "https://api.groq.com/openai/v1" - } - - case cfg.Providers.VLLM.APIBase != "": - apiKey = cfg.Providers.VLLM.APIKey - authMode = cfg.Providers.VLLM.Auth - apiBase = cfg.Providers.VLLM.APIBase - - default: - if cfg.Providers.OpenRouter.APIKey != "" { - apiKey = cfg.Providers.OpenRouter.APIKey - authMode = cfg.Providers.OpenRouter.Auth - if cfg.Providers.OpenRouter.APIBase != "" { - apiBase = cfg.Providers.OpenRouter.APIBase - } else { - apiBase = "https://openrouter.ai/api/v1" - } - } else { - return nil, fmt.Errorf("no API key configured for model: %s", model) - } - } - - if apiKey == "" && !strings.HasPrefix(model, "bedrock/") { - return nil, fmt.Errorf("no API key configured for provider (model: %s)", model) - } + apiKey := cfg.Providers.Proxy.APIKey + apiBase := cfg.Providers.Proxy.APIBase + authMode := cfg.Providers.Proxy.Auth if apiBase == "" { - return nil, fmt.Errorf("no API base configured for provider (model: %s)", model) + return nil, fmt.Errorf("no API base (CLIProxyAPI) configured") } return NewHTTPProvider(apiKey, apiBase, authMode), nil