Files
GoClaw/gateway/config/config.go

130 lines
3.8 KiB
Go

package config
import (
"log"
"os"
"strconv"
"strings"
"github.com/joho/godotenv"
)
// Config holds all runtime configuration for the GoClaw Gateway.
//
// LLM Provider selection (via LLM_BASE_URL env):
//
// Cloud (default): https://ollama.com/v1 — Ollama Cloud API (requires OLLAMA_API_KEY)
// OpenAI-compat: https://api.openai.com/v1 — OpenAI or any OpenAI-compatible endpoint
// Local GPU node: http://localhost:11434/v1 — Local Ollama (only on machines with GPU)
//
// To use a local Ollama instance on a GPU-equipped agent node, set:
//
// LLM_BASE_URL=http://<gpu-node-ip>:11434/v1
// LLM_API_KEY= # (empty for local Ollama)
type Config struct {
// Server
Port string
// LLM / Ollama Cloud
// LLM_BASE_URL — OpenAI-compatible base URL (without trailing slash, /v1 suffix included).
// Default: https://ollama.com/v1 (Ollama Cloud).
// For local GPU agents set LLM_BASE_URL=http://<host>:11434/v1
LLMBaseURL string
LLMAPIKey string
// Deprecated aliases kept for backward-compat (mapped to LLMBaseURL / LLMAPIKey)
OllamaBaseURL string
OllamaAPIKey string
// Database (MySQL/TiDB)
DatabaseURL string
// Project root (for file tools)
ProjectRoot string
// Gateway defaults
DefaultModel string
MaxToolIterations int
RequestTimeoutSecs int
}
func Load() *Config {
// Try to load .env from parent directory (project root) or current dir
_ = godotenv.Load("../.env")
_ = godotenv.Load(".env")
maxIter, _ := strconv.Atoi(getEnv("GATEWAY_MAX_TOOL_ITERATIONS", "10"))
timeout, _ := strconv.Atoi(getEnv("GATEWAY_REQUEST_TIMEOUT_SECS", "120"))
// Resolve LLM base URL — priority: LLM_BASE_URL > OLLAMA_BASE_URL > default cloud
rawLLMURL := getEnvFirst(
"LLM_BASE_URL", // preferred new name
"OLLAMA_BASE_URL", // legacy alias
)
if rawLLMURL == "" {
// Default: Ollama Cloud (OpenAI-compatible, requires OLLAMA_API_KEY)
rawLLMURL = "https://ollama.com/v1"
}
// Normalise: strip trailing slash, ensure /v1 suffix for bare Ollama hosts
llmBaseURL := normaliseLLMURL(rawLLMURL)
// Resolve API key — priority: LLM_API_KEY > OLLAMA_API_KEY
llmAPIKey := getEnvFirst("LLM_API_KEY", "OLLAMA_API_KEY")
cfg := &Config{
Port: getEnv("GATEWAY_PORT", "18789"),
LLMBaseURL: llmBaseURL,
LLMAPIKey: llmAPIKey,
OllamaBaseURL: llmBaseURL, // backward-compat alias
OllamaAPIKey: llmAPIKey, // backward-compat alias
DatabaseURL: getEnv("DATABASE_URL", ""),
ProjectRoot: getEnv("PROJECT_ROOT", "/home/ubuntu/goclaw-control-center"),
DefaultModel: getEnv("DEFAULT_MODEL", "qwen2.5:7b"),
MaxToolIterations: maxIter,
RequestTimeoutSecs: timeout,
}
if cfg.LLMAPIKey == "" {
log.Println("[Config] WARNING: LLM_API_KEY / OLLAMA_API_KEY is not set — cloud API calls will fail")
}
if cfg.DatabaseURL == "" {
log.Println("[Config] WARNING: DATABASE_URL is not set — agent config will use defaults")
}
log.Printf("[Config] LLM endpoint: %s", cfg.LLMBaseURL)
return cfg
}
// normaliseLLMURL ensures the URL has a /v1 suffix for bare Ollama hosts.
// Examples:
//
// "http://localhost:11434" → "http://localhost:11434/v1"
// "http://localhost:11434/" → "http://localhost:11434/v1"
// "https://ollama.com/v1" → "https://ollama.com/v1" (unchanged)
// "https://api.openai.com/v1" → unchanged
func normaliseLLMURL(raw string) string {
u := strings.TrimRight(raw, "/")
if !strings.HasSuffix(u, "/v1") {
u += "/v1"
}
return u
}
// getEnvFirst returns the value of the first non-empty env variable from the list.
func getEnvFirst(keys ...string) string {
for _, k := range keys {
if v := os.Getenv(k); v != "" {
return v
}
}
return ""
}
func getEnv(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}