fischer-agentkit/tests/unit/test_skill_loader.py

179 lines
6.1 KiB
Python
Raw Permalink 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 单元测试"""
import os
import tempfile
import pytest
import yaml
from agentkit.skills.base import Skill, SkillConfig
from agentkit.skills.loader import SkillLoader
from agentkit.skills.registry import SkillRegistry
from agentkit.tools.base import Tool
from agentkit.tools.registry import ToolRegistry
class DummyTool(Tool):
"""测试用 Tool 实现"""
def __init__(self, name: str = "dummy_tool", **kwargs):
super().__init__(name=name, description="dummy", **kwargs)
async def execute(self, **kwargs):
return {"result": "ok"}
def _write_yaml(directory: str, filename: str, data: dict) -> str:
path = os.path.join(directory, filename)
with open(path, "w", encoding="utf-8") as f:
yaml.dump(data, f, allow_unicode=True)
return path
class TestSkillLoader:
"""SkillLoader 从 YAML 批量加载测试"""
def test_load_from_directory_with_multiple_yaml_files(self):
registry = SkillRegistry()
loader = SkillLoader(skill_registry=registry)
with tempfile.TemporaryDirectory() as tmpdir:
_write_yaml(tmpdir, "skill_a.yaml", {
"name": "skill_a",
"agent_type": "type_a",
"task_mode": "llm_generate",
"prompt": {"identity": "技能 A"},
})
_write_yaml(tmpdir, "skill_b.yaml", {
"name": "skill_b",
"agent_type": "type_b",
"task_mode": "llm_generate",
"prompt": {"identity": "技能 B"},
})
skills = loader.load_from_directory(tmpdir)
assert len(skills) == 2
names = [s.name for s in skills]
assert "skill_a" in names
assert "skill_b" in names
def test_skip_invalid_yaml_files_and_log_warning(self, caplog):
registry = SkillRegistry()
loader = SkillLoader(skill_registry=registry)
with tempfile.TemporaryDirectory() as tmpdir:
# 有效 YAML
_write_yaml(tmpdir, "valid.yaml", {
"name": "valid_skill",
"agent_type": "valid",
"task_mode": "llm_generate",
"prompt": {"identity": "有效技能"},
})
# 无效 YAML缺少必要字段
invalid_path = os.path.join(tmpdir, "invalid.yaml")
with open(invalid_path, "w", encoding="utf-8") as f:
f.write("just_a_string_not_a_mapping")
with caplog.at_level("WARNING"):
skills = loader.load_from_directory(tmpdir)
assert len(skills) == 1
assert skills[0].name == "valid_skill"
def test_empty_directory_returns_empty_list(self):
registry = SkillRegistry()
loader = SkillLoader(skill_registry=registry)
with tempfile.TemporaryDirectory() as tmpdir:
skills = loader.load_from_directory(tmpdir)
assert skills == []
def test_loaded_skills_are_auto_registered(self):
registry = SkillRegistry()
loader = SkillLoader(skill_registry=registry)
with tempfile.TemporaryDirectory() as tmpdir:
_write_yaml(tmpdir, "auto_reg.yaml", {
"name": "auto_registered",
"agent_type": "auto",
"task_mode": "llm_generate",
"prompt": {"identity": "自动注册"},
})
loader.load_from_directory(tmpdir)
assert registry.has_skill("auto_registered")
def test_load_from_single_file(self):
registry = SkillRegistry()
loader = SkillLoader(skill_registry=registry)
with tempfile.TemporaryDirectory() as tmpdir:
path = _write_yaml(tmpdir, "single.yaml", {
"name": "single_skill",
"agent_type": "single",
"task_mode": "llm_generate",
"prompt": {"identity": "单文件技能"},
})
skill = loader.load_from_file(path)
assert skill.name == "single_skill"
assert registry.has_skill("single_skill")
def test_tool_binding_during_load(self):
"""当提供 tool_registry 时,加载 Skill 应自动绑定配置中声明的工具"""
tool_registry = ToolRegistry()
dummy_tool = DummyTool(name="my_tool")
tool_registry.register(dummy_tool)
skill_registry = SkillRegistry()
loader = SkillLoader(
skill_registry=skill_registry,
tool_registry=tool_registry,
)
with tempfile.TemporaryDirectory() as tmpdir:
_write_yaml(tmpdir, "with_tools.yaml", {
"name": "tooled_skill",
"agent_type": "tooled",
"task_mode": "tool_call",
"tools": ["my_tool"],
})
skills = loader.load_from_directory(tmpdir)
assert len(skills) == 1
skill = skills[0]
assert len(skill.tools) == 1
assert skill.tools[0].name == "my_tool"
def test_load_from_file_invalid_yaml_raises_error(self):
registry = SkillRegistry()
loader = SkillLoader(skill_registry=registry)
with tempfile.TemporaryDirectory() as tmpdir:
invalid_path = os.path.join(tmpdir, "bad.yaml")
with open(invalid_path, "w", encoding="utf-8") as f:
f.write("not_a_mapping")
with pytest.raises(Exception):
loader.load_from_file(invalid_path)
def test_load_from_directory_skips_non_yaml_files(self):
registry = SkillRegistry()
loader = SkillLoader(skill_registry=registry)
with tempfile.TemporaryDirectory() as tmpdir:
_write_yaml(tmpdir, "skill.yaml", {
"name": "yaml_skill",
"agent_type": "yaml",
"task_mode": "llm_generate",
"prompt": {"identity": "YAML 技能"},
})
# 非 YAML 文件
txt_path = os.path.join(tmpdir, "readme.txt")
with open(txt_path, "w") as f:
f.write("not a yaml")
skills = loader.load_from_directory(tmpdir)
assert len(skills) == 1
assert skills[0].name == "yaml_skill"