fischer-agentkit/tests/unit/test_business_skill_precond...

114 lines
4.2 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.

"""U4 验证10 个业务 Skill YAML 的 preconditions 字段加载正确。
验证项:
- 全部 16 个 skill YAML 可被 SkillConfig.from_dict 正常加载
- 10 个业务 skill 的 preconditions 字段非空且为 list[str]
- 6 个引擎模板的 preconditions 字段为 None未配置
"""
from __future__ import annotations
from pathlib import Path
import pytest
import yaml
from agentkit.skills.base import SkillConfig
_SKILLS_DIR = Path(__file__).resolve().parents[2] / "configs" / "skills"
# 10 个业务 skill应配置 preconditions
_BUSINESS_SKILLS = {
"code_reviewer",
"geo_optimizer",
"content_generator",
"competitor_analyzer",
"benchmark_runner",
"trend_agent",
"monitor",
"citation_detector",
"schema_advisor",
"deai_agent",
}
# 6 个引擎模板(不应配置 preconditions
_ENGINE_TEMPLATES = {
"react_agent",
"direct_agent",
"rewoo_agent",
"reflexion_agent",
"plan_exec_agent",
"goal_driven_agent",
}
def _load_all_skill_configs() -> dict[str, SkillConfig]:
"""加载 configs/skills/ 下全部 YAML 为 SkillConfig。"""
result: dict[str, SkillConfig] = {}
for yaml_path in sorted(_SKILLS_DIR.glob("*.yaml")):
with yaml_path.open("r", encoding="utf-8") as f:
data = yaml.safe_load(f)
if not isinstance(data, dict) or "name" not in data:
continue
config = SkillConfig.from_dict(data)
result[config.name] = config
return result
class TestBusinessSkillPreconditions:
"""U4业务 skill preconditions 字段验证。"""
def test_all_16_skills_load_without_error(self) -> None:
"""全部 16 个 skill YAML 可被 SkillConfig.from_dict 正常加载。"""
configs = _load_all_skill_configs()
assert len(configs) == 16, f"期望 16 个 skill实际加载 {len(configs)}"
def test_business_skills_have_non_empty_preconditions(self) -> None:
"""10 个业务 skill 的 preconditions 字段非空且为 list[str]。"""
configs = _load_all_skill_configs()
missing = _BUSINESS_SKILLS - set(configs.keys())
assert not missing, f"缺少业务 skill: {missing}"
for name in _BUSINESS_SKILLS:
config = configs[name]
assert config.preconditions is not None, f"{name}.preconditions 为 None"
assert isinstance(config.preconditions, list), (
f"{name}.preconditions 不是 list"
)
assert len(config.preconditions) >= 2, (
f"{name}.preconditions 少于 2 条(实际 {len(config.preconditions)} 条)"
)
assert all(isinstance(p, str) and p.strip() for p in config.preconditions), (
f"{name}.preconditions 存在非字符串或空字符串项"
)
def test_engine_templates_have_no_preconditions(self) -> None:
"""6 个引擎模板的 preconditions 字段为 None未配置"""
configs = _load_all_skill_configs()
missing = _ENGINE_TEMPLATES - set(configs.keys())
assert not missing, f"缺少引擎模板: {missing}"
for name in _ENGINE_TEMPLATES:
config = configs[name]
assert config.preconditions is None, (
f"引擎模板 {name} 不应配置 preconditions实际为 {config.preconditions}"
)
def test_preconditions_round_trip_through_to_dict(self) -> None:
"""preconditions 字段经 to_dict 序列化后保持一致。"""
configs = _load_all_skill_configs()
for name in _BUSINESS_SKILLS:
config = configs[name]
dumped = config.to_dict()
assert dumped.get("preconditions") == config.preconditions, (
f"{name}.to_dict() 的 preconditions 与原值不一致"
)
def test_code_reviewer_preconditions_content(self) -> None:
"""code_reviewer 的 preconditions 包含 shell 工具使用约束。"""
configs = _load_all_skill_configs()
cr = configs["code_reviewer"]
joined = " ".join(cr.preconditions)
assert "shell" in joined.lower() or "读取" in joined, (
"code_reviewer preconditions 应包含 shell 工具使用约束"
)