From 28bfb3b8b27714b8f6858ff6c1fcb82315e91ed5 Mon Sep 17 00:00:00 2001 From: PyuraMazo <1605025385@qq.com> Date: Mon, 23 Feb 2026 23:13:41 +0800 Subject: [PATCH] feat: add plugin load&unload hook (#5331) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 添加了插件的加载完成和卸载完成的钩子事件 * 添加了插件的加载完成和卸载完成的钩子事件 * format code with ruff * ruff format --------- Co-authored-by: Soulter <905617992@qq.com> --- astrbot/api/event/filter/__init__.py | 4 +++ astrbot/core/star/register/__init__.py | 4 +++ astrbot/core/star/register/star_handler.py | 34 ++++++++++++++++++++++ astrbot/core/star/star_handler.py | 4 +++ astrbot/core/star/star_manager.py | 28 +++++++++++++++++- 5 files changed, 73 insertions(+), 1 deletion(-) diff --git a/astrbot/api/event/filter/__init__.py b/astrbot/api/event/filter/__init__.py index 7354ec766..f5ab15ed0 100644 --- a/astrbot/api/event/filter/__init__.py +++ b/astrbot/api/event/filter/__init__.py @@ -25,6 +25,8 @@ from astrbot.core.star.register import ( ) 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_plugin_loaded as on_plugin_loaded +from astrbot.core.star.register import register_on_plugin_unloaded as on_plugin_unloaded 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, @@ -54,6 +56,8 @@ __all__ = [ "on_llm_request", "on_llm_response", "on_plugin_error", + "on_plugin_loaded", + "on_plugin_unloaded", "on_platform_loaded", "on_waiting_llm_request", "permission_type", diff --git a/astrbot/core/star/register/__init__.py b/astrbot/core/star/register/__init__.py index f1daf2968..5e99948cd 100644 --- a/astrbot/core/star/register/__init__.py +++ b/astrbot/core/star/register/__init__.py @@ -14,6 +14,8 @@ from .star_handler import ( register_on_llm_tool_respond, register_on_platform_loaded, register_on_plugin_error, + register_on_plugin_loaded, + register_on_plugin_unloaded, register_on_using_llm_tool, register_on_waiting_llm_request, register_permission_type, @@ -34,6 +36,8 @@ __all__ = [ "register_on_llm_request", "register_on_llm_response", "register_on_plugin_error", + "register_on_plugin_loaded", + "register_on_plugin_unloaded", "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 c4ed0d4a7..87b9b9998 100644 --- a/astrbot/core/star/register/star_handler.py +++ b/astrbot/core/star/register/star_handler.py @@ -357,6 +357,40 @@ def register_on_plugin_error(**kwargs): return decorator +def register_on_plugin_loaded(**kwargs): + """当有插件加载完成时 + + Hook 参数: + metadata + + 说明: + 当有插件加载完成时,触发该事件并获取到该插件的元数据 + """ + + def decorator(awaitable): + _ = get_handler_or_create(awaitable, EventType.OnPluginLoadedEvent, **kwargs) + return awaitable + + return decorator + + +def register_on_plugin_unloaded(**kwargs): + """当有插件卸载完成时 + + Hook 参数: + metadata + + 说明: + 当有插件卸载完成时,触发该事件并获取到该插件的元数据 + """ + + def decorator(awaitable): + _ = get_handler_or_create(awaitable, EventType.OnPluginUnloadedEvent, **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 63b0c447d..762db8655 100644 --- a/astrbot/core/star/star_handler.py +++ b/astrbot/core/star/star_handler.py @@ -144,6 +144,8 @@ class StarHandlerRegistry(Generic[T]): not in ( EventType.OnAstrBotLoadedEvent, EventType.OnPlatformLoadedEvent, + EventType.OnPluginLoadedEvent, + EventType.OnPluginUnloadedEvent, ) and not plugin.reserved ): @@ -201,6 +203,8 @@ class EventType(enum.Enum): OnLLMToolRespondEvent = enum.auto() # 调用函数工具后 OnAfterMessageSentEvent = enum.auto() # 发送消息后 OnPluginErrorEvent = enum.auto() # 插件处理消息异常时 + OnPluginLoadedEvent = enum.auto() # 插件加载完成 + OnPluginUnloadedEvent = enum.auto() # 插件卸载完成 H = TypeVar("H", bound=Callable[..., Any]) diff --git a/astrbot/core/star/star_manager.py b/astrbot/core/star/star_manager.py index 5f5157337..0f61c0274 100644 --- a/astrbot/core/star/star_manager.py +++ b/astrbot/core/star/star_manager.py @@ -33,7 +33,7 @@ from .command_management import sync_command_configs from .context import Context from .filter.permission import PermissionType, PermissionTypeFilter from .star import star_map, star_registry -from .star_handler import star_handlers_registry +from .star_handler import EventType, star_handlers_registry from .updator import PluginUpdator try: @@ -783,6 +783,19 @@ class PluginManager: if hasattr(metadata.star_cls, "initialize") and metadata.star_cls: await metadata.star_cls.initialize() + # 触发插件加载事件 + handlers = star_handlers_registry.get_handlers_by_event_type( + EventType.OnPluginLoadedEvent, + ) + for handler in handlers: + try: + logger.info( + f"hook(on_plugin_loaded) -> {star_map[handler.handler_module_path].name} - {handler.handler_name}", + ) + await handler.handler(metadata) + except Exception: + logger.error(traceback.format_exc()) + except BaseException as e: logger.error(f"----- 插件 {root_dir_name} 载入失败 -----") errors = traceback.format_exc() @@ -1175,6 +1188,19 @@ class PluginManager: elif "terminate" in star_metadata.star_cls_type.__dict__: await star_metadata.star_cls.terminate() + # 触发插件卸载事件 + handlers = star_handlers_registry.get_handlers_by_event_type( + EventType.OnPluginUnloadedEvent, + ) + for handler in handlers: + try: + logger.info( + f"hook(on_plugin_unloaded) -> {star_map[handler.handler_module_path].name} - {handler.handler_name}", + ) + await handler.handler(star_metadata) + except Exception: + logger.error(traceback.format_exc()) + async def turn_on_plugin(self, plugin_name: str) -> None: plugin = self.context.get_registered_star(plugin_name) if plugin is None: