diff --git a/src/serena/agent.py b/src/serena/agent.py index 96753ef7..5a22b2d3 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -19,7 +19,7 @@ from typing import TYPE_CHECKING, Any, TypeVar, Union import click from pathspec import PathSpec from sensai.util import logging -from sensai.util.logging import FallbackHandler, LogTime +from sensai.util.logging import LogTime from serena import serena_version from serena.config.context_mode import SerenaAgentContext, SerenaAgentMode @@ -46,27 +46,6 @@ SUCCESS_RESULT = "OK" DEFAULT_TOOL_TIMEOUT: float = 240 -def show_fatal_exception_safe(e: Exception) -> None: - """ - Shows the given exception in the GUI log viewer on the main thread and ensures that the exception is logged or at - least printed to stderr. - """ - # Make sure the error is logged (adding a fallback handler which writes to stderr in case there is no other handler) - fallback_handler = FallbackHandler(logging.StreamHandler(sys.stderr)) - Logger.root.addHandler(fallback_handler) - log.error(f"Fatal exception: {e}", exc_info=e) - - # attempt to show the error in the GUI - try: - # NOTE: The import can fail on macOS if Tk is not available (depends on Python interpreter installation, which uv - # used as a base); while tkinter as such is always available, its dependencies can be unavailable on macOS. - from serena.gui_log_viewer import show_fatal_exception - - show_fatal_exception(e) - except: - pass - - class ProjectNotFoundError(Exception): pass diff --git a/src/serena/agno.py b/src/serena/agno.py index 28284ab8..07ab7371 100644 --- a/src/serena/agno.py +++ b/src/serena/agno.py @@ -14,9 +14,10 @@ from agno.tools.toolkit import Toolkit from dotenv import load_dotenv from sensai.util.logging import LogTime -from serena.agent import SerenaAgent, Tool, show_fatal_exception_safe +from serena.agent import SerenaAgent, Tool from serena.config.context_mode import SerenaAgentContext from serena.constants import REPO_ROOT +from serena.util.exception import show_fatal_exception_safe log = logging.getLogger(__name__) diff --git a/src/serena/config/serena_config.py b/src/serena/config/serena_config.py index 232afd27..b321fa5c 100644 --- a/src/serena/config/serena_config.py +++ b/src/serena/config/serena_config.py @@ -4,18 +4,15 @@ The Serena Model Context Protocol (MCP) Server import os import shutil -import sys from copy import deepcopy from dataclasses import dataclass, field from functools import cached_property -from logging import Logger from pathlib import Path from typing import TYPE_CHECKING, Any, Self, TypeVar import yaml from ruamel.yaml.comments import CommentedMap from sensai.util import logging -from sensai.util.logging import FallbackHandler from sensai.util.string import ToStringMixin from serena.constants import ( @@ -38,27 +35,6 @@ T = TypeVar("T") DEFAULT_TOOL_TIMEOUT: float = 240 -def show_fatal_exception_safe(e: Exception) -> None: - """ - Shows the given exception in the GUI log viewer on the main thread and ensures that the exception is logged or at - least printed to stderr. - """ - # Make sure the error is logged (adding a fallback handler which writes to stderr in case there is no other handler) - fallback_handler = FallbackHandler(logging.StreamHandler(sys.stderr)) - Logger.root.addHandler(fallback_handler) - log.error(f"Fatal exception: {e}", exc_info=e) - - # attempt to show the error in the GUI - try: - # NOTE: The import can fail on macOS if Tk is not available (depends on Python interpreter installation, which uv - # used as a base); while tkinter as such is always available, its dependencies can be unavailable on macOS. - from serena.gui_log_viewer import show_fatal_exception - - show_fatal_exception(e) - except: - pass - - class SerenaConfigError(Exception): pass diff --git a/src/serena/mcp.py b/src/serena/mcp.py index 8128c525..3f918194 100644 --- a/src/serena/mcp.py +++ b/src/serena/mcp.py @@ -22,11 +22,11 @@ from sensai.util import logging from serena.agent import ( SerenaAgent, SerenaConfig, - show_fatal_exception_safe, ) from serena.config.context_mode import SerenaAgentContext, SerenaAgentMode from serena.constants import DEFAULT_CONTEXT, DEFAULT_MODES from serena.tools import ToolInterface +from serena.util.exception import show_fatal_exception_safe log = logging.getLogger(__name__) LOG_FORMAT = "%(levelname)-5s %(asctime)-15s %(name)s:%(funcName)s:%(lineno)d - %(message)s" diff --git a/src/serena/util/exception.py b/src/serena/util/exception.py new file mode 100644 index 00000000..a0cebfb9 --- /dev/null +++ b/src/serena/util/exception.py @@ -0,0 +1,28 @@ +import sys +from logging import Logger + +from sensai.util import logging +from sensai.util.logging import FallbackHandler + +from serena.agent import log + + +def show_fatal_exception_safe(e: Exception) -> None: + """ + Shows the given exception in the GUI log viewer on the main thread and ensures that the exception is logged or at + least printed to stderr. + """ + # Make sure the error is logged (adding a fallback handler which writes to stderr in case there is no other handler) + fallback_handler = FallbackHandler(logging.StreamHandler(sys.stderr)) + Logger.root.addHandler(fallback_handler) + log.error(f"Fatal exception: {e}", exc_info=e) + + # attempt to show the error in the GUI + try: + # NOTE: The import can fail on macOS if Tk is not available (depends on Python interpreter installation, which uv + # used as a base); while tkinter as such is always available, its dependencies can be unavailable on macOS. + from serena.gui_log_viewer import show_fatal_exception + + show_fatal_exception(e) + except: + pass