"""Environment-only runtime configuration for the GAIA agent.""" from __future__ import annotations import os from dataclasses import dataclass from pathlib import Path def _int(name: str, default: int) -> int: try: return int(os.getenv(name, str(default))) except ValueError as exc: raise ValueError(f"{name} must be an integer") from exc def _float(name: str, default: float) -> float: try: return float(os.getenv(name, str(default))) except ValueError as exc: raise ValueError(f"{name} must be a number") from exc def _bool(name: str, default: bool) -> bool: value = os.getenv(name) if value is None: return default return value.strip().lower() in {"1", "true", "yes", "on"} @dataclass(frozen=True) class Settings: api_url: str hf_token: str | None model_id: str vision_model_id: str inference_provider: str | None asr_model_id: str cache_dir: Path request_timeout: float retries: int backoff_seconds: float max_steps: int use_cache: bool stockfish_path: str | None fallback_model_id: str | None = None fallback_provider: str | None = None worker_limit: int = 3 model_requests_per_minute: float = 20.0 search_requests_per_minute: float = 30.0 user_agent: str = "GAIA-Level1-Agent/1.0 (public Hugging Face Space)" agent_code_url: str | None = None allow_inline_agent_code: bool = False local_model_id: str | None = None local_model_url: str = "http://127.0.0.1:11434/v1" prefer_local_model: bool = False @classmethod def from_env(cls) -> Settings: root = Path(os.getenv("GAIA_CACHE_DIR", "data")) provider = ( os.getenv("HF_PROVIDER") or os.getenv("HF_INFERENCE_PROVIDER") or None ) return cls( api_url=os.getenv( "GAIA_API_URL", "https://agents-course-unit4-scoring.hf.space" ).rstrip("/"), hf_token=os.getenv("HF_TOKEN") or None, model_id=os.getenv("MODEL_ID") or os.getenv("GAIA_MODEL_ID", "openai/gpt-oss-120b"), vision_model_id=os.getenv( "GAIA_VISION_MODEL_ID", "Qwen/Qwen3-VL-235B-A22B-Instruct" ), inference_provider=provider, asr_model_id=os.getenv("GAIA_ASR_MODEL_ID", "openai/whisper-large-v3"), cache_dir=root, request_timeout=_float("GAIA_REQUEST_TIMEOUT", 60.0), retries=max(1, _int("GAIA_RETRIES", 3)), backoff_seconds=max(0.0, _float("GAIA_BACKOFF_SECONDS", 1.0)), max_steps=max(1, _int("GAIA_MAX_STEPS", 10)), use_cache=_bool("GAIA_USE_CACHE", True), stockfish_path=os.getenv("STOCKFISH_PATH") or None, fallback_model_id=os.getenv("FALLBACK_MODEL_ID") or "openai/gpt-oss-20b", fallback_provider=os.getenv("HF_FALLBACK_PROVIDER") or None, worker_limit=max(1, _int("GAIA_WORKERS", 3)), model_requests_per_minute=max( 1.0, _float("GAIA_MODEL_REQUESTS_PER_MINUTE", 20.0) ), search_requests_per_minute=max( 1.0, _float("GAIA_SEARCH_REQUESTS_PER_MINUTE", 30.0) ), user_agent=os.getenv( "GAIA_USER_AGENT", "GAIA-Level1-Agent/1.0 (public Hugging Face Space)", ), agent_code_url=os.getenv("GAIA_AGENT_CODE_URL") or None, allow_inline_agent_code=_bool("GAIA_ALLOW_INLINE_AGENT_CODE", False), local_model_id=os.getenv("GAIA_LOCAL_MODEL_ID") or None, local_model_url=os.getenv( "GAIA_LOCAL_MODEL_URL", "http://127.0.0.1:11434/v1" ).rstrip("/"), prefer_local_model=_bool("GAIA_PREFER_LOCAL_MODEL", False), ) def require_hf_token(self) -> str: if not self.hf_token: raise RuntimeError( "HF_TOKEN is required for inference. Add it as a Hugging Face Space secret." ) return self.hf_token