"""声明式 Skill 激活:匹配、提示注入、Run 级工具别名和事件。""" from __future__ import annotations from typing import TYPE_CHECKING from app.application.agent.prompt_composer import compose_system_messages from app.application.agent.skill_loader import load_skill_manifests from app.modules.runtime.events import Event if TYPE_CHECKING: from app.application.tool_runtime.view import RunScopedToolView from app.modules.runtime.events import EventStore class SkillExecutor: """把数据库 Skill 激活到当前 Run 的工具视图。""" def __init__( self, tool_view: RunScopedToolView | None = None, event_store: EventStore | None = None, ) -> None: self._tool_view = tool_view self._event_store = event_store async def match_and_activate( self, context_text: str, system_messages: list[str], *, run_id: str | None = None, character_id: str | None = None, skill_refs: tuple[str, ...] = (), ) -> list[str]: """匹配技能并把提示与别名写入当前 Run。""" if not context_text: return system_messages manifests = await load_skill_manifests(context_text, skill_refs=skill_refs) system_messages.extend(compose_system_messages([], None, manifests)) activated_names: list[str] = [] for manifest in manifests: if self._tool_view is not None: for tool_name in manifest.allowed_tools: self._tool_view.bind_alias( f"skill:{manifest.name}/{tool_name}", tool_name, description_prefix=f"[{manifest.name}] ", ) activated_names.append(manifest.name) if activated_names and self._event_store: await self._emit_activation_event( activated_names, run_id=run_id, character_id=character_id, ) return system_messages async def _emit_activation_event( self, skill_names: list[str], *, run_id: str | None = None, character_id: str | None = None, ) -> None: event_store = self._event_store if event_store is None: return await event_store.append( Event( type="skill.activated", source="skill_executor", visibility="public", run_id=run_id, character_id=character_id, payload={"skills": skill_names}, ) ) __all__ = ["SkillExecutor"]