feat: Enhance Hook System with HookHandler and Dispatcher

- Introduced HookHandlerEntry to manage hook processing with attributes like hook name, mode, order, timeout, and error policy.
- Implemented normalization methods for hook attributes to ensure valid configurations.
- Updated ComponentRegistry to support retrieval of hook handlers based on hook names, with sorting by mode and order.
- Refactored HookDispatcher to handle invocation of hooks, separating blocking and non-blocking handlers, and managing execution results.
- Added support for registering hook specifications and invoking hooks across supervisors in PluginRuntimeManager.
- Removed deprecated workflow step handling from PluginRunner, streamlining hook invocation responses.
This commit is contained in:
DrSmoothl
2026-03-24 19:04:05 +08:00
parent 865e4916e3
commit 0b0f47a444
6 changed files with 1247 additions and 523 deletions

View File

@@ -3,8 +3,9 @@
提供 PluginRuntimeManager 单例,负责:
1. 管理双 PluginSupervisor 的生命周期(内置插件 / 第三方插件各一个子进程)
2. 将 EventType 桥接到运行时的 event dispatch
3. 在运行时的 ComponentRegistry 中查找命令
4. 提供统一的能力实现注册接口,使插件可以调用主程序功能
3. 触发跨 Supervisor 的命名 Hook 调用
4. 在运行时的 ComponentRegistry 中查找命令
5. 提供统一的能力实现注册接口,使插件可以调用主程序功能
"""
from pathlib import Path
@@ -24,6 +25,7 @@ from src.plugin_runtime.capabilities import (
RuntimeDataCapabilityMixin,
)
from src.plugin_runtime.capabilities.registry import register_capability_impls
from src.plugin_runtime.host.hook_dispatcher import HookDispatchResult, HookDispatcher, HookSpec
from src.plugin_runtime.host.message_utils import MessageDict, PluginMessageUtils
from src.plugin_runtime.runner.manifest_validator import ManifestValidator
@@ -72,6 +74,7 @@ class PluginRuntimeManager(
self._manifest_validator: ManifestValidator = ManifestValidator()
self._config_reload_callback: Callable[[Sequence[str]], Awaitable[None]] = self._handle_main_config_reload
self._config_reload_callback_registered: bool = False
self._hook_dispatcher: HookDispatcher = HookDispatcher(lambda: self.supervisors)
async def _dispatch_platform_inbound(self, envelope: InboundMessageEnvelope) -> None:
"""接收 Platform IO 审核后的入站消息并送入主消息链。
@@ -182,6 +185,7 @@ class PluginRuntimeManager(
if builtin_dirs:
self._builtin_supervisor = PluginSupervisor(
plugin_dirs=builtin_dirs,
group_name="builtin",
socket_path=builtin_socket,
)
self._register_capability_impls(self._builtin_supervisor)
@@ -189,6 +193,7 @@ class PluginRuntimeManager(
if third_party_dirs:
self._third_party_supervisor = PluginSupervisor(
plugin_dirs=third_party_dirs,
group_name="third_party",
socket_path=third_party_socket,
)
self._register_capability_impls(self._third_party_supervisor)
@@ -235,6 +240,7 @@ class PluginRuntimeManager(
await platform_io_manager.stop()
except Exception as platform_io_exc:
logger.warning(f"Platform IO 停止失败: {platform_io_exc}")
await self._hook_dispatcher.stop()
self._started = False
self._builtin_supervisor = None
self._third_party_supervisor = None
@@ -274,6 +280,7 @@ class PluginRuntimeManager(
else:
logger.info("插件运行时已停止")
finally:
await self._hook_dispatcher.stop()
self._started = False
self._builtin_supervisor = None
self._third_party_supervisor = None
@@ -284,11 +291,41 @@ class PluginRuntimeManager(
"""返回插件运行时是否处于启动状态。"""
return self._started
@property
def hook_dispatcher(self) -> HookDispatcher:
"""返回跨 Supervisor 的命名 Hook 分发器。"""
return self._hook_dispatcher
@property
def invoke_dispatcher(self) -> HookDispatcher:
"""返回命名 Hook 分发器的兼容别名。"""
return self._hook_dispatcher
@property
def supervisors(self) -> List["PluginSupervisor"]:
"""获取所有活跃的 Supervisor"""
return [s for s in (self._builtin_supervisor, self._third_party_supervisor) if s is not None]
def register_hook_spec(self, spec: HookSpec) -> None:
"""注册单个命名 Hook 规格。
Args:
spec: 需要注册的 Hook 规格。
"""
self._hook_dispatcher.register_hook_spec(spec)
def register_hook_specs(self, specs: Sequence[HookSpec]) -> None:
"""批量注册命名 Hook 规格。
Args:
specs: 需要注册的 Hook 规格序列。
"""
self._hook_dispatcher.register_hook_specs(specs)
def _build_registered_dependency_map(self) -> Dict[str, Set[str]]:
"""根据当前已注册插件构建全局依赖图。"""
@@ -588,6 +625,19 @@ class PluginRuntimeManager(
return True, modified
async def invoke_hook(self, hook_name: str, **kwargs: Any) -> HookDispatchResult:
"""触发一次跨 Supervisor 的命名 Hook 调用。
Args:
hook_name: 本次触发的 Hook 名称。
**kwargs: 传递给 Hook 处理器的关键字参数。
Returns:
HookDispatchResult: 聚合后的 Hook 调用结果。
"""
return await self._hook_dispatcher.invoke_hook(hook_name, **kwargs)
# ─── 命令查找 ──────────────────────────────────────────────
def find_command_by_text(self, text: str) -> Optional[Dict[str, Any]]: