fischer-agentkit/src/agentkit/skills/loader.py

106 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""SkillLoader - 从 YAML/SKILL.md 目录批量加载 Skill"""
import glob
import logging
import os
from agentkit.skills.base import Skill, SkillConfig
from agentkit.skills.registry import SkillRegistry
from agentkit.tools.registry import ToolRegistry
logger = logging.getLogger(__name__)
class SkillLoader:
"""从 YAML/SKILL.md 目录批量加载 Skill 并注册到 SkillRegistry"""
def __init__(
self,
skill_registry: SkillRegistry,
tool_registry: ToolRegistry | None = None,
):
self._skill_registry = skill_registry
self._tool_registry = tool_registry
def load_from_directory(self, directory: str) -> list[Skill]:
"""加载目录下所有 YAML 和 SKILL.md 文件为 Skill并注册到 SkillRegistry
无效的文件会被跳过并记录警告。
"""
skills: list[Skill] = []
# 加载 YAML 文件
yaml_pattern = os.path.join(directory, "*.yaml")
yaml_files = sorted(glob.glob(yaml_pattern))
for yaml_path in yaml_files:
try:
skill = self._load_skill_from_file(yaml_path)
skills.append(skill)
except Exception as e:
logger.warning(f"Skipping invalid YAML file '{yaml_path}': {e}")
# 加载 SKILL.md 文件
md_pattern = os.path.join(directory, "*.md")
md_files = sorted(glob.glob(md_pattern))
for md_path in md_files:
try:
skill = self.load_from_skill_md(md_path)
skills.append(skill)
except Exception as e:
logger.warning(f"Skipping invalid SKILL.md file '{md_path}': {e}")
return skills
def load_from_file(self, path: str) -> Skill:
"""加载单个 YAML 文件为 Skill并注册到 SkillRegistry"""
skill = self._load_skill_from_file(path)
return skill
def _load_skill_from_file(self, path: str) -> Skill:
"""从 YAML 文件加载 SkillConfig创建 Skill绑定工具注册"""
config = SkillConfig.from_yaml(path)
tools = self._bind_tools(config)
skill = Skill(config, tools=tools)
self._skill_registry.register(skill)
logger.info(f"Loaded skill '{skill.name}' from '{path}'")
return skill
def load_from_skill_md(self, path: str, disclosure_level: int = 1) -> Skill:
"""加载 SKILL.md 文件为 Skill并注册到 SkillRegistry
Args:
path: SKILL.md 文件路径
disclosure_level: 渐进式加载层级0=概要, 1=完整, 2=参考)
Returns:
加载的 Skill 实例
"""
from agentkit.skills.skill_md import SkillMdParser
frontmatter, sections, body = SkillMdParser.parse(path)
config = SkillMdParser.to_skill_config(
frontmatter, sections, path, disclosure_level=disclosure_level,
)
tools = self._bind_tools(config)
skill = Skill(config, tools=tools)
self._skill_registry.register(skill)
logger.info(f"Loaded skill '{skill.name}' from SKILL.md '{path}' (level={disclosure_level})")
return skill
def _bind_tools(self, config: SkillConfig) -> list:
"""根据配置中的 tools 列表绑定工具"""
if not self._tool_registry or not config.tools:
return []
tools = []
for tool_name in config.tools:
try:
tool = self._tool_registry.get(tool_name)
tools.append(tool)
logger.info(f"Bound tool '{tool_name}' to skill '{config.name}'")
except Exception as e:
logger.warning(
f"Failed to bind tool '{tool_name}' to skill '{config.name}': {e}"
)
return tools