mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-04-27 22:57:29 +08:00
feat(provider): switch to clawgo provider and improve office state handling
This commit is contained in:
@@ -92,6 +92,7 @@ func printHelp() {
|
||||
fmt.Println(" agent Interact with the agent directly")
|
||||
fmt.Println(" gateway Register/manage gateway service")
|
||||
fmt.Println(" status Show clawgo status")
|
||||
fmt.Println(" provider Configure provider credentials")
|
||||
fmt.Println(" config Get/set config values")
|
||||
fmt.Println(" cron Manage scheduled tasks")
|
||||
fmt.Println(" channel Test and manage messaging channels")
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"clawgo/pkg/config"
|
||||
@@ -26,8 +28,6 @@ func configCmd() {
|
||||
configCheckCmd()
|
||||
case "reload":
|
||||
configReloadCmd()
|
||||
case "login":
|
||||
configLoginCmd()
|
||||
default:
|
||||
fmt.Printf("Unknown config command: %s\n", os.Args[2])
|
||||
configHelp()
|
||||
@@ -171,35 +171,216 @@ func configCheckCmd() {
|
||||
}
|
||||
}
|
||||
|
||||
func configLoginCmd() {
|
||||
func providerCmd() {
|
||||
cfg, err := loadConfig()
|
||||
if err != nil {
|
||||
fmt.Printf("Error loading config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("Configuring CLIProxyAPI...")
|
||||
fmt.Printf("Current Base: %s\n", cfg.Providers.Proxy.APIBase)
|
||||
|
||||
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
|
||||
defaultProxy := strings.TrimSpace(cfg.Agents.Defaults.Proxy)
|
||||
if defaultProxy == "" {
|
||||
defaultProxy = "proxy"
|
||||
}
|
||||
available := providerNames(cfg)
|
||||
fmt.Printf("Current default provider: %s\n", defaultProxy)
|
||||
fmt.Printf("Available providers: %s\n", strings.Join(available, ", "))
|
||||
|
||||
argName := ""
|
||||
if len(os.Args) >= 3 {
|
||||
argName = strings.TrimSpace(os.Args[2])
|
||||
}
|
||||
if argName == "" || strings.HasPrefix(argName, "-") {
|
||||
argName = defaultProxy
|
||||
}
|
||||
providerName := promptLine(reader, "Provider name to configure", argName)
|
||||
if providerName == "" {
|
||||
providerName = defaultProxy
|
||||
}
|
||||
|
||||
fmt.Print("Enter API Key (optional): ")
|
||||
fmt.Scanln(&cfg.Providers.Proxy.APIKey)
|
||||
pc := providerConfigByName(cfg, providerName)
|
||||
if pc.TimeoutSec <= 0 {
|
||||
pc.TimeoutSec = 90
|
||||
}
|
||||
if strings.TrimSpace(pc.Auth) == "" {
|
||||
pc.Auth = "bearer"
|
||||
}
|
||||
if len(pc.Models) == 0 {
|
||||
pc.Models = append([]string{}, cfg.Providers.Proxy.Models...)
|
||||
}
|
||||
if len(pc.Models) == 0 {
|
||||
pc.Models = []string{"glm-4.7"}
|
||||
}
|
||||
|
||||
pc.APIBase = promptLine(reader, "api_base", pc.APIBase)
|
||||
apiKey := promptLine(reader, "api_key (leave empty to keep current)", "")
|
||||
if apiKey != "" {
|
||||
pc.APIKey = apiKey
|
||||
}
|
||||
modelsRaw := promptLine(reader, "models (comma-separated)", strings.Join(pc.Models, ","))
|
||||
if models := parseCSV(modelsRaw); len(models) > 0 {
|
||||
pc.Models = models
|
||||
}
|
||||
pc.Auth = promptLine(reader, "auth (bearer/oauth/none)", pc.Auth)
|
||||
timeoutRaw := promptLine(reader, "timeout_sec", fmt.Sprintf("%d", pc.TimeoutSec))
|
||||
pc.TimeoutSec = parseIntOrDefault(timeoutRaw, pc.TimeoutSec)
|
||||
pc.SupportsResponsesCompact = promptBool(reader, "supports_responses_compact", pc.SupportsResponsesCompact)
|
||||
|
||||
setProviderConfigByName(cfg, providerName, pc)
|
||||
|
||||
makeDefault := promptBool(reader, fmt.Sprintf("Set %s as agents.defaults.proxy", providerName), providerName == defaultProxy)
|
||||
if makeDefault {
|
||||
cfg.Agents.Defaults.Proxy = providerName
|
||||
}
|
||||
|
||||
currentFallbacks := strings.Join(cfg.Agents.Defaults.ProxyFallbacks, ",")
|
||||
fallbackRaw := promptLine(reader, "agents.defaults.proxy_fallbacks (comma-separated names)", currentFallbacks)
|
||||
fallbacks := parseCSV(fallbackRaw)
|
||||
valid := map[string]struct{}{}
|
||||
for _, name := range providerNames(cfg) {
|
||||
valid[name] = struct{}{}
|
||||
}
|
||||
filteredFallbacks := make([]string, 0, len(fallbacks))
|
||||
seen := map[string]struct{}{}
|
||||
defaultName := strings.TrimSpace(cfg.Agents.Defaults.Proxy)
|
||||
for _, fb := range fallbacks {
|
||||
if fb == "" || fb == defaultName {
|
||||
continue
|
||||
}
|
||||
if _, ok := valid[fb]; !ok {
|
||||
fmt.Printf("Skip unknown fallback provider: %s\n", fb)
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[fb]; ok {
|
||||
continue
|
||||
}
|
||||
seen[fb] = struct{}{}
|
||||
filteredFallbacks = append(filteredFallbacks, fb)
|
||||
}
|
||||
cfg.Agents.Defaults.ProxyFallbacks = filteredFallbacks
|
||||
|
||||
if err := config.SaveConfig(getConfigPath(), cfg); err != nil {
|
||||
fmt.Printf("Error saving config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("✓ CLIProxyAPI configuration saved.")
|
||||
fmt.Println("✓ Provider configuration saved.")
|
||||
running, err := triggerGatewayReload()
|
||||
if err != nil {
|
||||
if running {
|
||||
fmt.Printf("Hot reload not applied: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Gateway not running, reload skipped: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("✓ Gateway hot reload signal sent")
|
||||
}
|
||||
|
||||
func providerNames(cfg *config.Config) []string {
|
||||
names := []string{"proxy"}
|
||||
for k := range cfg.Providers.Proxies {
|
||||
k = strings.TrimSpace(k)
|
||||
if k == "" {
|
||||
continue
|
||||
}
|
||||
names = append(names, k)
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
|
||||
func providerConfigByName(cfg *config.Config, name string) config.ProviderConfig {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" || name == "proxy" {
|
||||
return cfg.Providers.Proxy
|
||||
}
|
||||
if cfg.Providers.Proxies != nil {
|
||||
if pc, ok := cfg.Providers.Proxies[name]; ok {
|
||||
return pc
|
||||
}
|
||||
}
|
||||
return config.ProviderConfig{
|
||||
APIBase: cfg.Providers.Proxy.APIBase,
|
||||
TimeoutSec: cfg.Providers.Proxy.TimeoutSec,
|
||||
Auth: cfg.Providers.Proxy.Auth,
|
||||
Models: append([]string{}, cfg.Providers.Proxy.Models...),
|
||||
}
|
||||
}
|
||||
|
||||
func setProviderConfigByName(cfg *config.Config, name string, pc config.ProviderConfig) {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" || name == "proxy" {
|
||||
cfg.Providers.Proxy = pc
|
||||
return
|
||||
}
|
||||
if cfg.Providers.Proxies == nil {
|
||||
cfg.Providers.Proxies = map[string]config.ProviderConfig{}
|
||||
}
|
||||
cfg.Providers.Proxies[name] = pc
|
||||
}
|
||||
|
||||
func promptLine(reader *bufio.Reader, label, defaultValue string) string {
|
||||
label = strings.TrimSpace(label)
|
||||
if defaultValue != "" {
|
||||
fmt.Printf("%s [%s]: ", label, defaultValue)
|
||||
} else {
|
||||
fmt.Printf("%s: ", label)
|
||||
}
|
||||
line, _ := reader.ReadString('\n')
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
return defaultValue
|
||||
}
|
||||
return line
|
||||
}
|
||||
|
||||
func promptBool(reader *bufio.Reader, label string, defaultValue bool) bool {
|
||||
def := "N"
|
||||
if defaultValue {
|
||||
def = "Y"
|
||||
}
|
||||
raw := promptLine(reader, label+" (y/n)", def)
|
||||
switch strings.ToLower(strings.TrimSpace(raw)) {
|
||||
case "y", "yes", "true", "1":
|
||||
return true
|
||||
case "n", "no", "false", "0":
|
||||
return false
|
||||
default:
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
func parseCSV(raw string) []string {
|
||||
parts := strings.Split(raw, ",")
|
||||
out := make([]string, 0, len(parts))
|
||||
seen := map[string]struct{}{}
|
||||
for _, p := range parts {
|
||||
v := strings.TrimSpace(p)
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[v]; ok {
|
||||
continue
|
||||
}
|
||||
seen[v] = struct{}{}
|
||||
out = append(out, v)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func parseIntOrDefault(raw string, def int) int {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return def
|
||||
}
|
||||
v, err := strconv.Atoi(raw)
|
||||
if err != nil || v <= 0 {
|
||||
return def
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func loadConfigAsMap(path string) (map[string]interface{}, error) {
|
||||
return configops.LoadConfigAsMap(path)
|
||||
|
||||
@@ -59,6 +59,8 @@ func main() {
|
||||
gatewayCmd()
|
||||
case "status":
|
||||
statusCmd()
|
||||
case "provider":
|
||||
providerCmd()
|
||||
case "config":
|
||||
configCmd()
|
||||
case "cron":
|
||||
|
||||
Reference in New Issue
Block a user