Merge pull request #60 from oraios/exception-display

Improve handling of fatal exceptions
This commit is contained in:
Michael Panchenko authored and GitHub committed 2025-04-16 12:36:13 +02:00
commit 7b92fa064a
3 files changed
+29 -7

No files matched your search

+25 -1
View File
@@ -6,6 +6,7 @@ import inspect
import json
import os
import platform
import sys
import traceback
from abc import ABC
from collections import defaultdict
@@ -16,6 +17,7 @@ from typing import TYPE_CHECKING, Any, Self, TypeVar, Union, cast
import yaml
from sensai.util import logging
from sensai.util.logging import FallbackHandler
from sensai.util.string import ToStringMixin, dict_string
from multilspy import SyncLanguageServer
@@ -40,6 +42,27 @@ TTool = TypeVar("TTool", bound="Tool")
SUCCESS_RESULT = "OK"
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
@@ -171,7 +194,8 @@ class SerenaAgent:
if platform.system() == "Darwin":
log.warning("GUI log window is not supported on macOS")
else:
# even importing on macOS may fail since tkinter is not available by default
# even importing on macOS may fail if tkinter dependencies are unavailable (depends on Python interpreter installation
# which uv used as a base, unfortunately)
from serena.gui_log_viewer import GuiLogViewer, GuiLogViewerHandler
log_level = self.serena_config.gui_log_window_level
+2 -3
View File
@@ -15,8 +15,7 @@ from dotenv import load_dotenv
from sensai.util.logging import LogTime
from serena import serena_root_path
from serena.agent import SerenaAgent, Tool
from serena.gui_log_viewer import show_fatal_exception
from serena.agent import SerenaAgent, Tool, show_fatal_exception_safe
log = logging.getLogger(__name__)
@@ -92,7 +91,7 @@ class SerenaAgnoAgentProvider:
try:
serena_agent = SerenaAgent(project_file)
except Exception as e:
show_fatal_exception(e)
show_fatal_exception_safe(e)
raise
# Even though we don't want to keep history between sessions,
+2 -3
View File
@@ -15,8 +15,7 @@ from mcp.server.fastmcp.utilities.func_metadata import func_metadata
from sensai.util import logging
from sensai.util.helper import mark_used
from serena.agent import SerenaAgent, Tool
from serena.gui_log_viewer import show_fatal_exception
from serena.agent import SerenaAgent, Tool, show_fatal_exception_safe
log = logging.getLogger(__name__)
LOG_FORMAT = "%(levelname)-5s %(asctime)-15s %(name)s:%(funcName)s:%(lineno)d - %(message)s"
@@ -100,7 +99,7 @@ def create_mcp_server() -> FastMCP:
# project_activation_callback=update_tools
)
except Exception as e:
show_fatal_exception(e)
show_fatal_exception_safe(e)
raise
@asynccontextmanager