From c6289d8f754c7d1f5c0ff6669778567ee25f4ad2 Mon Sep 17 00:00:00 2001 From: sanyekana Date: Wed, 18 Feb 2026 21:38:27 +0800 Subject: [PATCH] feat(core): add plugin error hook for custom error routing (#5192) * feat(core): add plugin error hook for custom error routing * fix(core): align plugin error suppression with event stop state --- astrbot/api/event/filter/__init__.py | 2 ++ .../process_stage/method/star_request.py | 18 ++++++++++++++---- astrbot/core/star/register/__init__.py | 2 ++ astrbot/core/star/register/star_handler.py | 18 ++++++++++++++++++ astrbot/core/star/star_handler.py | 9 +++++++++ astrbot/dashboard/routes/plugin.py | 1 + 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/astrbot/api/event/filter/__init__.py b/astrbot/api/event/filter/__init__.py index 287c60b73..7354ec766 100644 --- a/astrbot/api/event/filter/__init__.py +++ b/astrbot/api/event/filter/__init__.py @@ -24,6 +24,7 @@ from astrbot.core.star.register import ( register_on_llm_tool_respond as on_llm_tool_respond, ) from astrbot.core.star.register import register_on_platform_loaded as on_platform_loaded +from astrbot.core.star.register import register_on_plugin_error as on_plugin_error from astrbot.core.star.register import register_on_using_llm_tool as on_using_llm_tool from astrbot.core.star.register import ( register_on_waiting_llm_request as on_waiting_llm_request, @@ -52,6 +53,7 @@ __all__ = [ "on_decorating_result", "on_llm_request", "on_llm_response", + "on_plugin_error", "on_platform_loaded", "on_waiting_llm_request", "permission_type", diff --git a/astrbot/core/pipeline/process_stage/method/star_request.py b/astrbot/core/pipeline/process_stage/method/star_request.py index 8a79b96c9..9422d6317 100644 --- a/astrbot/core/pipeline/process_stage/method/star_request.py +++ b/astrbot/core/pipeline/process_stage/method/star_request.py @@ -8,9 +8,9 @@ from astrbot.core import logger from astrbot.core.message.message_event_result import MessageEventResult from astrbot.core.platform.astr_message_event import AstrMessageEvent from astrbot.core.star.star import star_map -from astrbot.core.star.star_handler import StarHandlerMetadata +from astrbot.core.star.star_handler import EventType, StarHandlerMetadata -from ...context import PipelineContext, call_handler +from ...context import PipelineContext, call_event_hook, call_handler from ..stage import Stage @@ -48,10 +48,20 @@ class StarRequestSubStage(Stage): yield ret event.clear_result() # 清除上一个 handler 的结果 except Exception as e: - logger.error(traceback.format_exc()) + traceback_text = traceback.format_exc() + logger.error(traceback_text) logger.error(f"Star {handler.handler_full_name} handle error: {e}") - if event.is_at_or_wake_command: + await call_event_hook( + event, + EventType.OnPluginErrorEvent, + md.name, + handler.handler_name, + e, + traceback_text, + ) + + if not event.is_stopped() and event.is_at_or_wake_command: ret = f":(\n\n在调用插件 {md.name} 的处理函数 {handler.handler_name} 时出现异常:{e}" event.set_result(MessageEventResult().message(ret)) yield diff --git a/astrbot/core/star/register/__init__.py b/astrbot/core/star/register/__init__.py index 4856ffe50..f1daf2968 100644 --- a/astrbot/core/star/register/__init__.py +++ b/astrbot/core/star/register/__init__.py @@ -13,6 +13,7 @@ from .star_handler import ( register_on_llm_response, register_on_llm_tool_respond, register_on_platform_loaded, + register_on_plugin_error, register_on_using_llm_tool, register_on_waiting_llm_request, register_permission_type, @@ -32,6 +33,7 @@ __all__ = [ "register_on_decorating_result", "register_on_llm_request", "register_on_llm_response", + "register_on_plugin_error", "register_on_platform_loaded", "register_on_waiting_llm_request", "register_permission_type", diff --git a/astrbot/core/star/register/star_handler.py b/astrbot/core/star/register/star_handler.py index dfca5a25c..c4ed0d4a7 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -339,6 +339,24 @@ def register_on_platform_loaded(**kwargs): return decorator +def register_on_plugin_error(**kwargs): + """当插件处理消息异常时触发。 + + Hook 参数: + event, plugin_name, handler_name, error, traceback_text + + 说明: + 在 hook 中调用 `event.stop_event()` 可屏蔽默认报错回显, + 并由插件自行决定是否转发到其他会话。 + """ + + def decorator(awaitable): + _ = get_handler_or_create(awaitable, EventType.OnPluginErrorEvent, **kwargs) + return awaitable + + return decorator + + def register_on_waiting_llm_request(**kwargs): """当等待调用 LLM 时的通知事件(在获取锁之前) diff --git a/astrbot/core/star/star_handler.py b/astrbot/core/star/star_handler.py index ced4d7739..63b0c447d 100644 --- a/astrbot/core/star/star_handler.py +++ b/astrbot/core/star/star_handler.py @@ -97,6 +97,14 @@ class StarHandlerRegistry(Generic[T]): plugins_name: list[str] | None = None, ) -> list[StarHandlerMetadata[Callable[..., Awaitable[Any]]]]: ... + @overload + def get_handlers_by_event_type( + self, + event_type: Literal[EventType.OnPluginErrorEvent], + only_activated=True, + plugins_name: list[str] | None = None, + ) -> list[StarHandlerMetadata[Callable[..., Awaitable[Any]]]]: ... + @overload def get_handlers_by_event_type( self, @@ -192,6 +200,7 @@ class EventType(enum.Enum): OnUsingLLMToolEvent = enum.auto() # 使用 LLM 工具 OnLLMToolRespondEvent = enum.auto() # 调用函数工具后 OnAfterMessageSentEvent = enum.auto() # 发送消息后 + OnPluginErrorEvent = enum.auto() # 插件处理消息异常时 H = TypeVar("H", bound=Callable[..., Any]) diff --git a/astrbot/dashboard/routes/plugin.py b/astrbot/dashboard/routes/plugin.py index ca271cdf6..bfa4dca39 100644 --- a/astrbot/dashboard/routes/plugin.py +++ b/astrbot/dashboard/routes/plugin.py @@ -73,6 +73,7 @@ class PluginRoute(Route): EventType.OnDecoratingResultEvent: "回复消息前", EventType.OnCallingFuncToolEvent: "函数工具", EventType.OnAfterMessageSentEvent: "发送消息后", + EventType.OnPluginErrorEvent: "插件报错时", } self._logo_cache = {}