Checkpoint: Phase 10: LLM Provider Configuration — Ollama Cloud как дефолт, локальный Ollama закомментирован (GPU only), docker-compose/stack обновлены, .env.example с 4 провайдерами
This commit is contained in:
53
docker/.env.example
Normal file
53
docker/.env.example
Normal file
@@ -0,0 +1,53 @@
|
||||
##############################################################################
|
||||
# GoClaw Control Center — Environment Variables
|
||||
# Copy this file to docker/.env and fill in your values.
|
||||
#
|
||||
# cp docker/.env.example docker/.env
|
||||
# docker compose -f docker/docker-compose.yml up -d
|
||||
##############################################################################
|
||||
|
||||
# ── LLM Provider ─────────────────────────────────────────────────────────────
|
||||
#
|
||||
# Choose ONE of the following providers by setting LLM_BASE_URL + LLM_API_KEY.
|
||||
#
|
||||
# Option 1: Ollama Cloud (default)
|
||||
# Sign up at https://ollama.com → Settings → API Keys
|
||||
# Supports all public Ollama models (qwen2.5, llama3, mistral, etc.)
|
||||
LLM_BASE_URL=https://ollama.com/v1
|
||||
LLM_API_KEY=your-ollama-cloud-api-key-here
|
||||
|
||||
# Option 2: OpenAI
|
||||
# LLM_BASE_URL=https://api.openai.com/v1
|
||||
# LLM_API_KEY=sk-...
|
||||
|
||||
# Option 3: Any OpenAI-compatible API (Groq, Together, Mistral, etc.)
|
||||
# LLM_BASE_URL=https://api.groq.com/openai/v1
|
||||
# LLM_API_KEY=gsk_...
|
||||
|
||||
# Option 4: Local Ollama on a GPU machine (no API key needed)
|
||||
# Also uncomment the "ollama" service in docker-compose.yml if running locally.
|
||||
# LLM_BASE_URL=http://localhost:11434
|
||||
# LLM_API_KEY=
|
||||
|
||||
# Default model to use when agent config is not available
|
||||
DEFAULT_MODEL=qwen2.5:7b
|
||||
|
||||
# ── Database ──────────────────────────────────────────────────────────────────
|
||||
MYSQL_ROOT_PASSWORD=goClawRoot123
|
||||
MYSQL_DATABASE=goclaw
|
||||
MYSQL_USER=goclaw
|
||||
MYSQL_PASSWORD=goClawPass123
|
||||
|
||||
# ── Authentication ────────────────────────────────────────────────────────────
|
||||
JWT_SECRET=change-me-to-a-random-64-char-string
|
||||
|
||||
# ── Manus OAuth (optional, for Manus-hosted deployment) ──────────────────────
|
||||
VITE_APP_ID=
|
||||
OAUTH_SERVER_URL=
|
||||
VITE_OAUTH_PORTAL_URL=
|
||||
|
||||
# ── Manus Built-in APIs (optional) ───────────────────────────────────────────
|
||||
BUILT_IN_FORGE_API_URL=
|
||||
BUILT_IN_FORGE_API_KEY=
|
||||
VITE_FRONTEND_FORGE_API_KEY=
|
||||
VITE_FRONTEND_FORGE_API_URL=
|
||||
@@ -6,8 +6,9 @@ RUN npm install -g pnpm@latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files for layer caching
|
||||
# Copy package files and patches for layer caching
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
COPY patches/ ./patches/
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Copy source code (exclude gateway/ and docker/)
|
||||
@@ -40,7 +41,9 @@ RUN npm install -g pnpm@latest
|
||||
|
||||
# Copy package files and install production deps only
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile --prod
|
||||
COPY patches/ ./patches/
|
||||
# Install all deps (vite is needed at runtime for SSR/proxy)
|
||||
RUN pnpm install --frozen-lockfile --ignore-scripts
|
||||
|
||||
# Copy built artifacts
|
||||
COPY --from=builder /app/dist ./dist
|
||||
|
||||
@@ -4,23 +4,34 @@
|
||||
# Services:
|
||||
# control-center — React + Node.js tRPC frontend/backend (:3000)
|
||||
# gateway — Go Orchestrator + Tool Executor (:18789)
|
||||
# ollama — Local LLM server (:11434)
|
||||
# db — MySQL 8 (:3306)
|
||||
#
|
||||
# LLM Provider (set in .env or environment):
|
||||
# Cloud (default): LLM_BASE_URL=https://ollama.com/v1 + LLM_API_KEY=<key>
|
||||
# OpenAI-compat: LLM_BASE_URL=https://api.openai.com/v1 + LLM_API_KEY=<key>
|
||||
# Local GPU node: LLM_BASE_URL=http://<gpu-host>:11434 (no key needed)
|
||||
#
|
||||
# Local Ollama (GPU only):
|
||||
# The ollama service below is commented out by default.
|
||||
# Uncomment it only on machines with a compatible GPU.
|
||||
# Then set: LLM_BASE_URL=http://ollama:11434
|
||||
#
|
||||
# Usage:
|
||||
# cp docker/.env.example docker/.env # fill in LLM_API_KEY etc.
|
||||
# docker compose -f docker/docker-compose.yml up -d
|
||||
# docker compose -f docker/docker-compose.yml logs -f gateway
|
||||
# docker compose -f docker/docker-compose.yml down -v
|
||||
##############################################################################
|
||||
|
||||
version: "3.9"
|
||||
name: goclaw
|
||||
|
||||
networks:
|
||||
goclaw-net:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
ollama-data:
|
||||
mysql-data:
|
||||
# ollama-data: # Uncomment when using local Ollama service below
|
||||
|
||||
services:
|
||||
|
||||
@@ -47,27 +58,32 @@ services:
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
# ── Ollama LLM Server ─────────────────────────────────────────────────────
|
||||
ollama:
|
||||
image: ollama/ollama:latest
|
||||
container_name: goclaw-ollama
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "11434:11434"
|
||||
volumes:
|
||||
- ollama-data:/root/.ollama
|
||||
networks:
|
||||
- goclaw-net
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
# Uncomment if no GPU:
|
||||
# environment:
|
||||
# - OLLAMA_NUM_PARALLEL=2
|
||||
# ── Local Ollama LLM Server (GPU ONLY — disabled by default) ─────────────
|
||||
# Uncomment this entire block only on machines with a compatible NVIDIA or
|
||||
# Apple Silicon GPU. Then set LLM_BASE_URL=http://ollama:11434 in the
|
||||
# gateway service below (or in your .env file).
|
||||
#
|
||||
# ollama:
|
||||
# image: ollama/ollama:latest
|
||||
# container_name: goclaw-ollama
|
||||
# restart: unless-stopped
|
||||
# ports:
|
||||
# - "11434:11434"
|
||||
# volumes:
|
||||
# - ollama-data:/root/.ollama
|
||||
# networks:
|
||||
# - goclaw-net
|
||||
# environment:
|
||||
# - OLLAMA_NUM_PARALLEL=2
|
||||
# - OLLAMA_MAX_LOADED_MODELS=2
|
||||
# # NVIDIA GPU support — uncomment if available:
|
||||
# # deploy:
|
||||
# # resources:
|
||||
# # reservations:
|
||||
# # devices:
|
||||
# # - driver: nvidia
|
||||
# # count: all
|
||||
# # capabilities: [gpu]
|
||||
|
||||
# ── Go Gateway (Orchestrator + Tool Executor) ─────────────────────────────
|
||||
gateway:
|
||||
@@ -80,21 +96,34 @@ services:
|
||||
- "18789:18789"
|
||||
environment:
|
||||
PORT: "18789"
|
||||
OLLAMA_BASE_URL: "http://ollama:11434"
|
||||
# ── LLM Provider ─────────────────────────────────────────────────────
|
||||
# Cloud default (Ollama Cloud, OpenAI-compatible):
|
||||
LLM_BASE_URL: "${LLM_BASE_URL:-https://ollama.com/v1}"
|
||||
LLM_API_KEY: "${LLM_API_KEY:-${OLLAMA_API_KEY:-}}"
|
||||
# Legacy alias (still supported):
|
||||
OLLAMA_API_KEY: "${OLLAMA_API_KEY:-${LLM_API_KEY:-}}"
|
||||
# ── To use local Ollama on GPU node, set in .env: ─────────────────────
|
||||
# LLM_BASE_URL=http://ollama:11434 (if ollama service above is enabled)
|
||||
# LLM_BASE_URL=http://<gpu-host-ip>:11434 (external GPU machine)
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
DEFAULT_MODEL: "${DEFAULT_MODEL:-qwen2.5:7b}"
|
||||
DATABASE_URL: "${MYSQL_USER:-goclaw}:${MYSQL_PASSWORD:-goClawPass123}@tcp(db:3306)/${MYSQL_DATABASE:-goclaw}?parseTime=true"
|
||||
PROJECT_ROOT: "/app"
|
||||
REQUEST_TIMEOUT_SECS: "120"
|
||||
GATEWAY_REQUEST_TIMEOUT_SECS: "120"
|
||||
GATEWAY_MAX_TOOL_ITERATIONS: "10"
|
||||
LOG_LEVEL: "info"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
ollama:
|
||||
condition: service_started
|
||||
# ollama: # Uncomment if using local Ollama service above
|
||||
# condition: service_started
|
||||
networks:
|
||||
- goclaw-net
|
||||
volumes:
|
||||
# Mount project root for file tools (read-only in prod, rw in dev)
|
||||
# Mount project root for file tools (read-only)
|
||||
- ..:/app:ro
|
||||
# Mount Docker socket for docker_exec tool
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://localhost:18789/health"]
|
||||
interval: 15s
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
##############################################################################
|
||||
# GoClaw Control Center — Docker Stack (Docker Swarm Production)
|
||||
#
|
||||
# LLM Provider:
|
||||
# By default the gateway uses Ollama Cloud (https://ollama.com/v1).
|
||||
# Set LLM_BASE_URL and LLM_API_KEY via Docker secrets or environment.
|
||||
#
|
||||
# To use a local Ollama instance on a GPU-equipped Swarm node:
|
||||
# 1. Uncomment the "ollama" service below.
|
||||
# 2. Add the label gpu=true to the GPU node:
|
||||
# docker node update --label-add gpu=true <node-id>
|
||||
# 3. Change LLM_BASE_URL in the gateway service to: http://ollama:11434
|
||||
#
|
||||
# Deploy:
|
||||
# # Create required secrets first:
|
||||
# echo "rootpass" | docker secret create mysql-root-password -
|
||||
# echo "pass" | docker secret create mysql-password -
|
||||
# echo "jwtsecret"| docker secret create jwt-secret -
|
||||
# echo "ollamakey"| docker secret create llm-api-key -
|
||||
#
|
||||
# docker stack deploy -c docker/docker-stack.yml goclaw
|
||||
#
|
||||
# Remove:
|
||||
@@ -19,14 +35,10 @@ networks:
|
||||
attachable: true
|
||||
|
||||
volumes:
|
||||
ollama-data:
|
||||
driver: local
|
||||
mysql-data:
|
||||
driver: local
|
||||
|
||||
configs:
|
||||
gateway-env:
|
||||
external: true
|
||||
# ollama-data: # Uncomment when using local Ollama service below
|
||||
# driver: local
|
||||
|
||||
secrets:
|
||||
mysql-root-password:
|
||||
@@ -35,6 +47,8 @@ secrets:
|
||||
external: true
|
||||
jwt-secret:
|
||||
external: true
|
||||
llm-api-key:
|
||||
external: true
|
||||
|
||||
services:
|
||||
|
||||
@@ -73,45 +87,59 @@ services:
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
# ── Ollama LLM Server ─────────────────────────────────────────────────────
|
||||
ollama:
|
||||
image: ollama/ollama:latest
|
||||
volumes:
|
||||
- ollama-data:/root/.ollama
|
||||
networks:
|
||||
- goclaw-net
|
||||
deploy:
|
||||
replicas: 1
|
||||
placement:
|
||||
constraints:
|
||||
# Pin to GPU node if available
|
||||
- node.labels.gpu == true
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 15s
|
||||
resources:
|
||||
limits:
|
||||
memory: 16G
|
||||
reservations:
|
||||
memory: 4G
|
||||
# GPU support via nvidia-container-runtime
|
||||
# Uncomment on GPU-enabled nodes:
|
||||
# runtime: nvidia
|
||||
# environment:
|
||||
# - NVIDIA_VISIBLE_DEVICES=all
|
||||
# ── Local Ollama LLM Server (GPU ONLY — disabled by default) ─────────────
|
||||
# Uncomment this entire block only on Swarm nodes with a compatible GPU.
|
||||
# After uncommenting, also change gateway LLM_BASE_URL to http://ollama:11434
|
||||
# and remove the llm-api-key secret from gateway (not needed for local Ollama).
|
||||
#
|
||||
# ollama:
|
||||
# image: ollama/ollama:latest
|
||||
# volumes:
|
||||
# - ollama-data:/root/.ollama
|
||||
# networks:
|
||||
# - goclaw-net
|
||||
# deploy:
|
||||
# replicas: 1
|
||||
# placement:
|
||||
# constraints:
|
||||
# # Pin to GPU-labelled node: docker node update --label-add gpu=true <id>
|
||||
# - node.labels.gpu == true
|
||||
# restart_policy:
|
||||
# condition: on-failure
|
||||
# delay: 15s
|
||||
# resources:
|
||||
# limits:
|
||||
# memory: 16G
|
||||
# reservations:
|
||||
# memory: 4G
|
||||
# # NVIDIA GPU support — uncomment on GPU-enabled nodes:
|
||||
# # runtime: nvidia
|
||||
# # environment:
|
||||
# # - NVIDIA_VISIBLE_DEVICES=all
|
||||
|
||||
# ── Go Gateway (Orchestrator + Tool Executor) ─────────────────────────────
|
||||
gateway:
|
||||
image: git.softuniq.eu/uniqai/goclaw/gateway:latest
|
||||
environment:
|
||||
PORT: "18789"
|
||||
OLLAMA_BASE_URL: "http://ollama:11434"
|
||||
# ── LLM Provider ─────────────────────────────────────────────────────
|
||||
# Default: Ollama Cloud (requires llm-api-key secret below)
|
||||
LLM_BASE_URL: "${LLM_BASE_URL:-https://ollama.com/v1}"
|
||||
DEFAULT_MODEL: "${DEFAULT_MODEL:-qwen2.5:7b}"
|
||||
# LLM_API_KEY is injected via /run/secrets/llm-api-key (see below)
|
||||
# ── To switch to local GPU Ollama, set: ──────────────────────────────
|
||||
# LLM_BASE_URL: "http://ollama:11434"
|
||||
# (and uncomment the ollama service above)
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
DATABASE_URL: "goclaw:{{MYSQL_PASSWORD}}@tcp(db:3306)/goclaw?parseTime=true"
|
||||
PROJECT_ROOT: "/app"
|
||||
REQUEST_TIMEOUT_SECS: "120"
|
||||
GATEWAY_REQUEST_TIMEOUT_SECS: "120"
|
||||
GATEWAY_MAX_TOOL_ITERATIONS: "10"
|
||||
LOG_LEVEL: "info"
|
||||
secrets:
|
||||
- mysql-password
|
||||
- source: llm-api-key
|
||||
target: /run/secrets/llm-api-key
|
||||
networks:
|
||||
- goclaw-net
|
||||
ports:
|
||||
@@ -119,6 +147,9 @@ services:
|
||||
published: 18789
|
||||
protocol: tcp
|
||||
mode: ingress
|
||||
volumes:
|
||||
# Docker socket for docker_exec tool
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
deploy:
|
||||
replicas: 2
|
||||
update_config:
|
||||
|
||||
@@ -4,15 +4,35 @@ 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
|
||||
|
||||
// Ollama / LLM
|
||||
// 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
|
||||
|
||||
@@ -29,17 +49,34 @@ type Config struct {
|
||||
}
|
||||
|
||||
func Load() *Config {
|
||||
// Try to load .env from parent directory (project root)
|
||||
// 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"),
|
||||
OllamaBaseURL: getEnv("OLLAMA_BASE_URL", "https://ollama.com/v1"),
|
||||
OllamaAPIKey: getEnv("OLLAMA_API_KEY", ""),
|
||||
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"),
|
||||
@@ -47,16 +84,43 @@ func Load() *Config {
|
||||
RequestTimeoutSecs: timeout,
|
||||
}
|
||||
|
||||
if cfg.OllamaAPIKey == "" {
|
||||
log.Println("[Config] WARNING: OLLAMA_API_KEY is not set")
|
||||
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
|
||||
|
||||
8
todo.md
8
todo.md
@@ -143,3 +143,11 @@
|
||||
- [ ] Write Go unit tests (gateway/internal/tools/executor_test.go)
|
||||
- [ ] Write Go integration test for orchestrator chat loop
|
||||
- [ ] Push to Gitea (NW)
|
||||
|
||||
## Phase 10: LLM Provider Configuration
|
||||
- [x] config.go: default LLM_BASE_URL = https://ollama.com/v1 (Ollama Cloud)
|
||||
- [x] config.go: support LLM_BASE_URL + LLM_API_KEY env vars (legacy OLLAMA_* aliases kept)
|
||||
- [x] config.go: normaliseLLMURL() — auto-append /v1 for bare Ollama hosts
|
||||
- [x] docker-compose.yml: ollama service commented out (GPU only), LLM_BASE_URL/LLM_API_KEY added
|
||||
- [x] docker-stack.yml: ollama service commented out (GPU only), llm-api-key secret added
|
||||
- [x] docker/.env.example: 4 LLM provider options documented (Ollama Cloud, OpenAI, Groq, Local GPU)
|
||||
|
||||
Reference in New Issue
Block a user