134 lines
3.4 KiB
Python
134 lines
3.4 KiB
Python
|
|
"""Skills 注册表 - Phase 9.1"""
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
from typing import Any
|
|||
|
|
|
|||
|
|
from app.agents.skills.metadata import SkillMetadata
|
|||
|
|
from app.agents.skills.loaders.local_loader import LocalSkillLoader
|
|||
|
|
|
|||
|
|
|
|||
|
|
class SkillRegistry:
|
|||
|
|
"""Skills 注册表
|
|||
|
|
|
|||
|
|
管理所有 Skills 的注册、发现和加载。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self._skills: dict[str, SkillMetadata] = {}
|
|||
|
|
self._loaders: list[Any] = []
|
|||
|
|
|
|||
|
|
def load_all(self, skills_dir: str | None = None) -> int:
|
|||
|
|
"""加载所有 Skills
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
skills_dir: Skills 目录,None 则使用默认目录
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
加载的 Skill 数量
|
|||
|
|
"""
|
|||
|
|
if skills_dir is None:
|
|||
|
|
skills_dir = os.path.join(
|
|||
|
|
os.path.dirname(__file__), "..", "..", "..", ".claude", "skills"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
count = 0
|
|||
|
|
|
|||
|
|
# 本地加载器
|
|||
|
|
local_loader = LocalSkillLoader(skills_dir)
|
|||
|
|
local_skills = local_loader.load_all()
|
|||
|
|
for skill in local_skills:
|
|||
|
|
self.register(skill)
|
|||
|
|
count += 1
|
|||
|
|
|
|||
|
|
# 插件加载器
|
|||
|
|
for loader in self._loaders:
|
|||
|
|
try:
|
|||
|
|
external_skills = loader.load_all()
|
|||
|
|
for skill in external_skills:
|
|||
|
|
self.register(skill)
|
|||
|
|
count += 1
|
|||
|
|
except Exception:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
return count
|
|||
|
|
|
|||
|
|
def register(self, skill: SkillMetadata) -> None:
|
|||
|
|
"""注册 Skill"""
|
|||
|
|
self._skills[skill.name] = skill
|
|||
|
|
|
|||
|
|
def unregister(self, name: str) -> bool:
|
|||
|
|
"""注销 Skill"""
|
|||
|
|
if name in self._skills:
|
|||
|
|
del self._skills[name]
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def get_skill(self, name: str) -> SkillMetadata | None:
|
|||
|
|
"""获取 Skill"""
|
|||
|
|
return self._skills.get(name)
|
|||
|
|
|
|||
|
|
def search(self, query: str) -> list[SkillMetadata]:
|
|||
|
|
"""搜索 Skills
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
query: 搜索关键词
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
匹配的 Skills 列表
|
|||
|
|
"""
|
|||
|
|
query_lower = query.lower()
|
|||
|
|
results = []
|
|||
|
|
|
|||
|
|
for skill in self._skills.values():
|
|||
|
|
if not skill.enabled:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
# 匹配名称、描述、标签
|
|||
|
|
if (
|
|||
|
|
query_lower in skill.name.lower()
|
|||
|
|
or query_lower in skill.description.lower()
|
|||
|
|
or any(query_lower in tag.lower() for tag in skill.tags)
|
|||
|
|
or any(query_lower in trigger.lower() for trigger in skill.triggers)
|
|||
|
|
):
|
|||
|
|
results.append(skill)
|
|||
|
|
|
|||
|
|
return results
|
|||
|
|
|
|||
|
|
def get_skill_context(self, names: list[str]) -> str:
|
|||
|
|
"""获取 Skill 上下文
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
names: Skill 名称列表
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
拼接的 Skill 内容
|
|||
|
|
"""
|
|||
|
|
contexts = []
|
|||
|
|
|
|||
|
|
for name in names:
|
|||
|
|
skill = self._skills.get(name)
|
|||
|
|
if skill and skill.enabled:
|
|||
|
|
contexts.append(f"# {skill.name}\n\n{skill.content}")
|
|||
|
|
|
|||
|
|
return "\n\n---\n\n".join(contexts)
|
|||
|
|
|
|||
|
|
def add_loader(self, loader: Any) -> None:
|
|||
|
|
"""添加加载器"""
|
|||
|
|
self._loaders.append(loader)
|
|||
|
|
|
|||
|
|
def list_all(self) -> list[SkillMetadata]:
|
|||
|
|
"""列出所有 Skills"""
|
|||
|
|
return list(self._skills.values())
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 全局单例
|
|||
|
|
_registry: SkillRegistry | None = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_skill_registry() -> SkillRegistry:
|
|||
|
|
"""获取全局 Skills 注册表"""
|
|||
|
|
global _registry
|
|||
|
|
if _registry is None:
|
|||
|
|
_registry = SkillRegistry()
|
|||
|
|
return _registry
|