mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-02-01 23:13:36 +00:00
Token reduction (~40% per session, ~2.3M fewer tokens per 200-feature project): - Agent-type-specific tool lists: coding 9, testing 5, init 5 (was 19 for all) - Right-sized max_turns: coding 300, testing 100 (was 1000 for all) - Trimmed coding prompt template (~150 lines removed) - Streamlined testing prompt with batch support - YOLO mode now strips browser testing instructions from prompt - Added Grep, WebFetch, WebSearch to expand project session Performance improvements: - Rate limit retries start at ~15s with jitter (was fixed 60s) - Post-spawn delay reduced to 0.5s (was 2s) - Orchestrator consolidated to 1 DB query per loop (was 5-7) - Testing agents batch 3 features per session (was 1) - Smart context compaction preserves critical state, discards noise Bug fixes: - Removed ghost feature_release_testing MCP tool (wasted tokens every test session) - Forward all 9 Vertex AI env vars to chat sessions (was missing 3) - Fix DetachedInstanceError risk in test batch ORM access - Prevent duplicate testing of same features in parallel mode Code deduplication: - _get_project_path(): 9 copies -> 1 shared utility (project_helpers.py) - validate_project_name(): 9 copies -> 2 variants in 1 file (validation.py) - ROOT_DIR: 10 copies -> 1 definition (chat_constants.py) - API_ENV_VARS: 4 copies -> 1 source of truth (env_constants.py) Security hardening: - Unified sensitive directory blocklist (14 dirs, was two divergent lists) - Cached get_blocked_paths() for O(1) directory listing checks - Terminal security warning when ALLOW_REMOTE=1 exposes WebSocket - 20 new security tests for EXTRA_READ_PATHS blocking - Extracted _validate_command_list() and _validate_pkill_processes() helpers Type safety: - 87 mypy errors -> 0 across 58 source files - Installed types-PyYAML for proper yaml stub types - Fixed SQLAlchemy Column[T] coercions across all routers Dead code removed: - 13 files deleted (~2,679 lines): unused UI components, debug logs, outdated docs - 7 unused npm packages removed (Radix UI components with 0 imports) - AgentAvatar.tsx reduced from 615 -> 119 lines (SVGs extracted to mascotData.tsx) New CLI options: - --testing-batch-size (1-5) for parallel mode test batching - --testing-feature-ids for direct multi-feature testing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
118 lines
3.5 KiB
Python
118 lines
3.5 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 os
|
|
import sys
|
|
|
|
from fastapi import APIRouter
|
|
|
|
from ..schemas import ModelInfo, ModelsResponse, 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 (
|
|
AVAILABLE_MODELS,
|
|
DEFAULT_MODEL,
|
|
get_all_settings,
|
|
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"
|
|
|
|
|
|
def _is_glm_mode() -> bool:
|
|
"""Check if GLM API is configured via environment variables."""
|
|
base_url = os.getenv("ANTHROPIC_BASE_URL", "")
|
|
# GLM mode is when ANTHROPIC_BASE_URL is set but NOT pointing to Ollama
|
|
return bool(base_url) and not _is_ollama_mode()
|
|
|
|
|
|
def _is_ollama_mode() -> bool:
|
|
"""Check if Ollama API is configured via environment variables."""
|
|
base_url = os.getenv("ANTHROPIC_BASE_URL", "")
|
|
return "localhost:11434" in base_url or "127.0.0.1:11434" in base_url
|
|
|
|
|
|
@router.get("/models", response_model=ModelsResponse)
|
|
async def get_available_models():
|
|
"""Get list of available models.
|
|
|
|
Frontend should call this to get the current list of models
|
|
instead of hardcoding them.
|
|
"""
|
|
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()
|
|
|
|
return SettingsResponse(
|
|
yolo_mode=_parse_yolo_mode(all_settings.get("yolo_mode")),
|
|
model=all_settings.get("model", DEFAULT_MODEL),
|
|
glm_mode=_is_glm_mode(),
|
|
ollama_mode=_is_ollama_mode(),
|
|
testing_agent_ratio=_parse_int(all_settings.get("testing_agent_ratio"), 1),
|
|
)
|
|
|
|
|
|
@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))
|
|
|
|
# Return updated settings
|
|
all_settings = get_all_settings()
|
|
return SettingsResponse(
|
|
yolo_mode=_parse_yolo_mode(all_settings.get("yolo_mode")),
|
|
model=all_settings.get("model", DEFAULT_MODEL),
|
|
glm_mode=_is_glm_mode(),
|
|
ollama_mode=_is_ollama_mode(),
|
|
testing_agent_ratio=_parse_int(all_settings.get("testing_agent_ratio"), 1),
|
|
)
|