mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-03-16 18:33:08 +00:00
Remove legacy env-var-based provider/mode detection that caused misleading UI badges (e.g., GLM badge showing when Settings was set to Claude). Key changes: - Remove _is_glm_mode() and _is_ollama_mode() env-var sniffing functions from server/routers/settings.py; derive glm_mode/ollama_mode purely from the api_provider setting - Remove `import os` from settings router (no longer needed) - Update schema comments to reflect settings-based derivation - Remove "(configured via .env)" from badge tooltips in App.tsx - Remove Kimi/GLM/Ollama/Playwright-headless sections from .env.example; add note pointing to Settings UI - Update CLAUDE.md and README.md documentation to reference Settings UI for alternative provider configuration - Update model IDs from claude-opus-4-5-20251101 to claude-opus-4-6 across registry, client, chat sessions, tests, and UI defaults - Add LEGACY_MODEL_MAP with auto-migration in get_all_settings() - Show model ID subtitle in SettingsModal model selector - Add Vertex passthrough test for claude-opus-4-6 (no date suffix) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
185 lines
6.4 KiB
Python
185 lines
6.4 KiB
Python
"""
|
|
Settings Router
|
|
===============
|
|
|
|
API endpoints for global settings management.
|
|
Settings are stored in the registry database and shared across all projects.
|
|
"""
|
|
|
|
import mimetypes
|
|
import sys
|
|
|
|
from fastapi import APIRouter
|
|
|
|
from ..schemas import ModelInfo, ModelsResponse, ProviderInfo, ProvidersResponse, SettingsResponse, SettingsUpdate
|
|
from ..services.chat_constants import ROOT_DIR
|
|
|
|
# Mimetype fix for Windows - must run before StaticFiles is mounted
|
|
mimetypes.add_type("text/javascript", ".js", True)
|
|
|
|
# Ensure root is on sys.path for registry import
|
|
if str(ROOT_DIR) not in sys.path:
|
|
sys.path.insert(0, str(ROOT_DIR))
|
|
|
|
from registry import (
|
|
API_PROVIDERS,
|
|
AVAILABLE_MODELS,
|
|
DEFAULT_MODEL,
|
|
get_all_settings,
|
|
get_setting,
|
|
set_setting,
|
|
)
|
|
|
|
router = APIRouter(prefix="/api/settings", tags=["settings"])
|
|
|
|
|
|
def _parse_yolo_mode(value: str | None) -> bool:
|
|
"""Parse YOLO mode string to boolean."""
|
|
return (value or "false").lower() == "true"
|
|
|
|
|
|
@router.get("/providers", response_model=ProvidersResponse)
|
|
async def get_available_providers():
|
|
"""Get list of available API providers."""
|
|
current = get_setting("api_provider", "claude") or "claude"
|
|
providers = []
|
|
for pid, pdata in API_PROVIDERS.items():
|
|
providers.append(ProviderInfo(
|
|
id=pid,
|
|
name=pdata["name"],
|
|
base_url=pdata.get("base_url"),
|
|
models=[ModelInfo(id=m["id"], name=m["name"]) for m in pdata.get("models", [])],
|
|
default_model=pdata.get("default_model", ""),
|
|
requires_auth=pdata.get("requires_auth", False),
|
|
))
|
|
return ProvidersResponse(providers=providers, current=current)
|
|
|
|
|
|
@router.get("/models", response_model=ModelsResponse)
|
|
async def get_available_models():
|
|
"""Get list of available models.
|
|
|
|
Returns models for the currently selected API provider.
|
|
"""
|
|
current_provider = get_setting("api_provider", "claude") or "claude"
|
|
provider = API_PROVIDERS.get(current_provider)
|
|
|
|
if provider and current_provider != "claude":
|
|
provider_models = provider.get("models", [])
|
|
return ModelsResponse(
|
|
models=[ModelInfo(id=m["id"], name=m["name"]) for m in provider_models],
|
|
default=provider.get("default_model", ""),
|
|
)
|
|
|
|
# Default: return Claude models
|
|
return ModelsResponse(
|
|
models=[ModelInfo(id=m["id"], name=m["name"]) for m in AVAILABLE_MODELS],
|
|
default=DEFAULT_MODEL,
|
|
)
|
|
|
|
|
|
def _parse_int(value: str | None, default: int) -> int:
|
|
"""Parse integer setting with default fallback."""
|
|
if value is None:
|
|
return default
|
|
try:
|
|
return int(value)
|
|
except (ValueError, TypeError):
|
|
return default
|
|
|
|
|
|
def _parse_bool(value: str | None, default: bool = False) -> bool:
|
|
"""Parse boolean setting with default fallback."""
|
|
if value is None:
|
|
return default
|
|
return value.lower() == "true"
|
|
|
|
|
|
@router.get("", response_model=SettingsResponse)
|
|
async def get_settings():
|
|
"""Get current global settings."""
|
|
all_settings = get_all_settings()
|
|
|
|
api_provider = all_settings.get("api_provider", "claude")
|
|
|
|
glm_mode = api_provider == "glm"
|
|
ollama_mode = api_provider == "ollama"
|
|
|
|
return SettingsResponse(
|
|
yolo_mode=_parse_yolo_mode(all_settings.get("yolo_mode")),
|
|
model=all_settings.get("model", DEFAULT_MODEL),
|
|
glm_mode=glm_mode,
|
|
ollama_mode=ollama_mode,
|
|
testing_agent_ratio=_parse_int(all_settings.get("testing_agent_ratio"), 1),
|
|
playwright_headless=_parse_bool(all_settings.get("playwright_headless"), default=True),
|
|
batch_size=_parse_int(all_settings.get("batch_size"), 3),
|
|
api_provider=api_provider,
|
|
api_base_url=all_settings.get("api_base_url"),
|
|
api_has_auth_token=bool(all_settings.get("api_auth_token")),
|
|
api_model=all_settings.get("api_model"),
|
|
)
|
|
|
|
|
|
@router.patch("", response_model=SettingsResponse)
|
|
async def update_settings(update: SettingsUpdate):
|
|
"""Update global settings."""
|
|
if update.yolo_mode is not None:
|
|
set_setting("yolo_mode", "true" if update.yolo_mode else "false")
|
|
|
|
if update.model is not None:
|
|
set_setting("model", update.model)
|
|
|
|
if update.testing_agent_ratio is not None:
|
|
set_setting("testing_agent_ratio", str(update.testing_agent_ratio))
|
|
|
|
if update.playwright_headless is not None:
|
|
set_setting("playwright_headless", "true" if update.playwright_headless else "false")
|
|
|
|
if update.batch_size is not None:
|
|
set_setting("batch_size", str(update.batch_size))
|
|
|
|
# API provider settings
|
|
if update.api_provider is not None:
|
|
old_provider = get_setting("api_provider", "claude")
|
|
set_setting("api_provider", update.api_provider)
|
|
|
|
# When provider changes, auto-set defaults for the new provider
|
|
if update.api_provider != old_provider:
|
|
provider = API_PROVIDERS.get(update.api_provider)
|
|
if provider:
|
|
# Auto-set base URL from provider definition
|
|
if provider.get("base_url"):
|
|
set_setting("api_base_url", provider["base_url"])
|
|
# Auto-set model to provider's default
|
|
if provider.get("default_model") and update.api_model is None:
|
|
set_setting("api_model", provider["default_model"])
|
|
|
|
if update.api_base_url is not None:
|
|
set_setting("api_base_url", update.api_base_url)
|
|
|
|
if update.api_auth_token is not None:
|
|
set_setting("api_auth_token", update.api_auth_token)
|
|
|
|
if update.api_model is not None:
|
|
set_setting("api_model", update.api_model)
|
|
|
|
# Return updated settings
|
|
all_settings = get_all_settings()
|
|
api_provider = all_settings.get("api_provider", "claude")
|
|
glm_mode = api_provider == "glm"
|
|
ollama_mode = api_provider == "ollama"
|
|
|
|
return SettingsResponse(
|
|
yolo_mode=_parse_yolo_mode(all_settings.get("yolo_mode")),
|
|
model=all_settings.get("model", DEFAULT_MODEL),
|
|
glm_mode=glm_mode,
|
|
ollama_mode=ollama_mode,
|
|
testing_agent_ratio=_parse_int(all_settings.get("testing_agent_ratio"), 1),
|
|
playwright_headless=_parse_bool(all_settings.get("playwright_headless"), default=True),
|
|
batch_size=_parse_int(all_settings.get("batch_size"), 3),
|
|
api_provider=api_provider,
|
|
api_base_url=all_settings.get("api_base_url"),
|
|
api_has_auth_token=bool(all_settings.get("api_auth_token")),
|
|
api_model=all_settings.get("api_model"),
|
|
)
|