diff --git a/EvoScientist/cli/__init__.py b/EvoScientist/cli/__init__.py index 9a355db..ed2cbba 100644 --- a/EvoScientist/cli/__init__.py +++ b/EvoScientist/cli/__init__.py @@ -26,13 +26,18 @@ from .tui_runtime import ( # noqa: F401 def main(): """CLI entry point.""" + import os import warnings warnings.filterwarnings("ignore", message=".*not known to support tools.*") warnings.filterwarnings( "ignore", message=".*type is unknown and inference may fail.*" ) + from ..config import load_config from .commands import _configure_logging - _configure_logging() + # Priority: env var > config file > default (WARNING) + config = load_config() + _log_level = os.environ.get("EVOSCIENTIST_LOG_LEVEL", "") or config.log_level + _configure_logging(debug=_log_level.upper() == "DEBUG") app() diff --git a/EvoScientist/cli/commands.py b/EvoScientist/cli/commands.py index f8574ef..4e50481 100644 --- a/EvoScientist/cli/commands.py +++ b/EvoScientist/cli/commands.py @@ -498,6 +498,11 @@ def serve( "--ask-user", help="Enable agent to ask clarifying questions about your research preferences", ), + debug: bool = typer.Option( + False, + "--debug", + help="Enable debug logging (shows all log levels including DEBUG)", + ), ): """Run EvoScientist in headless mode -- channels only, no interactive prompt. @@ -514,6 +519,10 @@ def serve( config = get_effective_config(cli_overrides) apply_config_to_env(config) + # Enable verbose logging when debug flag is set + if debug: + _configure_logging(debug=True) + # Auto-start ccproxy if any provider uses OAuth mode _ccproxy_proc_serve = None if config.anthropic_auth_mode == "oauth" or config.openai_auth_mode == "oauth": @@ -1166,10 +1175,12 @@ def _main_callback( ) -def _configure_logging(): +def _configure_logging(debug: bool = False): """Configure logging with warning symbols for better visibility.""" from rich.logging import RichHandler + log_level = logging.DEBUG if debug else logging.WARNING + class DimWarningHandler(RichHandler): """Custom handler that renders warnings in dim style.""" @@ -1185,9 +1196,9 @@ def _configure_logging(): # Configure root logger to use our handler for WARNING and above handler = DimWarningHandler( - console=console, show_time=False, show_path=False, show_level=False + console=console, show_time=debug, show_path=debug, show_level=debug ) - handler.setLevel(logging.WARNING) + handler.setLevel(log_level) # Apply to root logger (catches all loggers including deepagents) root_logger = logging.getLogger() @@ -1195,7 +1206,7 @@ def _configure_logging(): for h in root_logger.handlers[:]: root_logger.removeHandler(h) root_logger.addHandler(handler) - root_logger.setLevel(logging.WARNING) + root_logger.setLevel(log_level) # Suppress noisy schema warnings from langchain_google_genai # (e.g. "Key '$schema' is not supported in schema, ignoring") diff --git a/EvoScientist/config/settings.py b/EvoScientist/config/settings.py index 75b34a8..68b368f 100644 --- a/EvoScientist/config/settings.py +++ b/EvoScientist/config/settings.py @@ -92,6 +92,9 @@ class EvoScientistConfig: # UI Settings show_thinking: bool = True ui_backend: Literal["cli", "tui"] = "tui" + log_level: str = ( + "" # "DEBUG" | "WARNING" | "" (empty = check env var EVOSCIENTIST_LOG_LEVEL) + ) # Channel Settings channel_enabled: str = "" # "imessage" | "telegram" | "discord" | "slack" | "wechat" | "dingtalk" | "feishu" | "email" | "qq" | "signal" | "" (comma-separated for multiple) diff --git a/tests/test_config.py b/tests/test_config.py index 7f4eab5..62cc4ae 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -30,6 +30,11 @@ def temp_config_dir(tmp_path, monkeypatch): """Use a temporary directory for config during tests.""" config_dir = tmp_path / "evoscientist" monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path)) + # Prevent load_dotenv from loading the project's real .env file + monkeypatch.setattr( + "EvoScientist.config.settings.find_dotenv", + lambda *a, **k: str(tmp_path / ".env"), + ) # Also clear any API keys from environment for key in [ "ANTHROPIC_API_KEY",