From 73d6cfcd369558881c060f9c215df7d7fe36158a Mon Sep 17 00:00:00 2001 From: Auto Date: Fri, 6 Feb 2026 08:10:18 +0200 Subject: [PATCH] fix: address PR #163 review findings - Fix model selection regression: _get_settings_defaults() now checks api_model (set by new provider UI) before falling back to legacy model setting, ensuring Claude model selection works end-to-end - Add input validation for provider settings: api_base_url must start with http:// or https:// (max 500 chars), api_auth_token max 500 chars, api_model max 200 chars - Fix terminal.py misleading import alias: replace is_valid_project_name aliased as validate_project_name with direct is_valid_project_name import across all 5 call sites Co-Authored-By: Claude Opus 4.6 --- server/routers/agent.py | 2 +- server/routers/terminal.py | 12 ++++++------ server/schemas.py | 15 ++++++++++++--- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/server/routers/agent.py b/server/routers/agent.py index 9288745..26605e4 100644 --- a/server/routers/agent.py +++ b/server/routers/agent.py @@ -32,7 +32,7 @@ def _get_settings_defaults() -> tuple[bool, str, int, bool, int]: settings = get_all_settings() yolo_mode = (settings.get("yolo_mode") or "false").lower() == "true" - model = settings.get("model", DEFAULT_MODEL) + model = settings.get("api_model") or settings.get("model", DEFAULT_MODEL) # Parse testing agent settings with defaults try: diff --git a/server/routers/terminal.py b/server/routers/terminal.py index 6845a27..fb468c6 100644 --- a/server/routers/terminal.py +++ b/server/routers/terminal.py @@ -26,7 +26,7 @@ from ..services.terminal_manager import ( stop_terminal_session, ) from ..utils.project_helpers import get_project_path as _get_project_path -from ..utils.validation import is_valid_project_name as validate_project_name +from ..utils.validation import is_valid_project_name logger = logging.getLogger(__name__) @@ -89,7 +89,7 @@ async def list_project_terminals(project_name: str) -> list[TerminalInfoResponse Returns: List of terminal info objects """ - if not validate_project_name(project_name): + if not is_valid_project_name(project_name): raise HTTPException(status_code=400, detail="Invalid project name") project_dir = _get_project_path(project_name) @@ -122,7 +122,7 @@ async def create_project_terminal( Returns: The created terminal info """ - if not validate_project_name(project_name): + if not is_valid_project_name(project_name): raise HTTPException(status_code=400, detail="Invalid project name") project_dir = _get_project_path(project_name) @@ -148,7 +148,7 @@ async def rename_project_terminal( Returns: The updated terminal info """ - if not validate_project_name(project_name): + if not is_valid_project_name(project_name): raise HTTPException(status_code=400, detail="Invalid project name") if not validate_terminal_id(terminal_id): @@ -180,7 +180,7 @@ async def delete_project_terminal(project_name: str, terminal_id: str) -> dict: Returns: Success message """ - if not validate_project_name(project_name): + if not is_valid_project_name(project_name): raise HTTPException(status_code=400, detail="Invalid project name") if not validate_terminal_id(terminal_id): @@ -225,7 +225,7 @@ async def terminal_websocket(websocket: WebSocket, project_name: str, terminal_i await websocket.accept() # Validate project name - if not validate_project_name(project_name): + if not is_valid_project_name(project_name): await websocket.send_json({"type": "error", "message": "Invalid project name"}) await websocket.close( code=TerminalCloseCode.INVALID_PROJECT_NAME, reason="Invalid project name" diff --git a/server/schemas.py b/server/schemas.py index 8365e7a..c9c703d 100644 --- a/server/schemas.py +++ b/server/schemas.py @@ -436,9 +436,18 @@ class SettingsUpdate(BaseModel): playwright_headless: bool | None = None batch_size: int | None = None # Features per agent batch (1-3) api_provider: str | None = None - api_base_url: str | None = None - api_auth_token: str | None = None # Write-only, never returned - api_model: str | None = None + api_base_url: str | None = Field(None, max_length=500) + api_auth_token: str | None = Field(None, max_length=500) # Write-only, never returned + api_model: str | None = Field(None, max_length=200) + + @field_validator('api_base_url') + @classmethod + def validate_api_base_url(cls, v: str | None) -> str | None: + if v is not None and v.strip(): + v = v.strip() + if not v.startswith(("http://", "https://")): + raise ValueError("api_base_url must start with http:// or https://") + return v @field_validator('model') @classmethod