diff --git a/astrbot/api/event/filter/__init__.py b/astrbot/api/event/filter/__init__.py index 287c60b73e..7354ec766c 100644 --- a/astrbot/api/event/filter/__init__.py +++ b/astrbot/api/event/filter/__init__.py @@ -24,6 +24,7 @@ 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 @@ "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 8a79b96c96..9422d6317a 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.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 @@ async def process( 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 4856ffe50d..f1daf2968b 100644 --- a/astrbot/core/star/register/__init__.py +++ b/astrbot/core/star/register/__init__.py @@ -13,6 +13,7 @@ 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 @@ "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 dfca5a25c0..c4ed0d4a7e 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -339,6 +339,24 @@ def decorator(awaitable): 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 ced4d7739f..63b0c447de 100644 --- a/astrbot/core/star/star_handler.py +++ b/astrbot/core/star/star_handler.py @@ -97,6 +97,14 @@ def get_handlers_by_event_type( 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 ca271cdf6b..bfa4dca397 100644 --- a/astrbot/dashboard/routes/plugin.py +++ b/astrbot/dashboard/routes/plugin.py @@ -73,6 +73,7 @@ def __init__( EventType.OnDecoratingResultEvent: "回复消息前", EventType.OnCallingFuncToolEvent: "函数工具", EventType.OnAfterMessageSentEvent: "发送消息后", + EventType.OnPluginErrorEvent: "插件报错时", } self._logo_cache = {}