"""SkillConfig v7 preconditions + provenance 字段单元测试""" import pytest from agentkit.core.exceptions import ConfigValidationError from agentkit.skills.base import SkillConfig # llm_generate 模式要求 prompt,所有构造提供最小 prompt _PROMPT = {"identity": "test"} _BASE = {"name": "x", "agent_type": "y", "task_mode": "llm_generate", "prompt": _PROMPT} class TestSkillConfigPreconditions: """v7 preconditions / provenance 字段测试""" def test_construct_with_preconditions_and_provenance(self): config = SkillConfig( name="x", agent_type="y", task_mode="llm_generate", prompt=_PROMPT, preconditions=["用户已登录", "当前分支非 main"], provenance="yaml:test.yaml", ) assert config.preconditions == ["用户已登录", "当前分支非 main"] assert config.provenance == "yaml:test.yaml" def test_from_dict_backward_compatible_defaults(self): """旧 YAML 无 preconditions/provenance 字段时取默认值""" config = SkillConfig.from_dict(dict(_BASE)) assert config.preconditions is None assert config.provenance == "" def test_from_dict_with_new_fields(self): data = dict(_BASE) data["preconditions"] = ["需要网络连接"] data["provenance"] = "entry_point:my_skill" config = SkillConfig.from_dict(data) assert config.preconditions == ["需要网络连接"] assert config.provenance == "entry_point:my_skill" def test_to_dict_contains_new_fields(self): config = SkillConfig( name="x", agent_type="y", task_mode="llm_generate", prompt=_PROMPT, preconditions=["条件A"], provenance="yaml:a.yaml", ) d = config.to_dict() assert d["preconditions"] == ["条件A"] assert d["provenance"] == "yaml:a.yaml" def test_to_dict_none_vs_empty_list_distinct(self): """preconditions=None 与 preconditions=[] 在 to_dict 中区分保留""" none_cfg = SkillConfig( name="x", agent_type="y", task_mode="llm_generate", prompt=_PROMPT, preconditions=None ) empty_cfg = SkillConfig( name="x", agent_type="y", task_mode="llm_generate", prompt=_PROMPT, preconditions=[] ) assert none_cfg.to_dict()["preconditions"] is None assert empty_cfg.to_dict()["preconditions"] == [] def test_to_dict_default_provenance(self): config = SkillConfig(name="x", agent_type="y", task_mode="llm_generate", prompt=_PROMPT) assert config.to_dict()["provenance"] == "" def test_round_trip_from_dict_to_dict(self): data = dict(_BASE) data["preconditions"] = ["条件1", "条件2"] data["provenance"] = "skill_md:foo.md" config = SkillConfig.from_dict(data) out = config.to_dict() assert out["preconditions"] == ["条件1", "条件2"] assert out["provenance"] == "skill_md:foo.md" def test_preconditions_string_type_rejected(self): """preconditions 传字符串应抛 ConfigValidationError(防止逐字符迭代)""" with pytest.raises(ConfigValidationError, match="preconditions"): SkillConfig( name="x", agent_type="y", task_mode="llm_generate", prompt=_PROMPT, preconditions="必须提供代码", # type: ignore[arg-type] ) def test_preconditions_dict_type_rejected(self): """preconditions 传 dict 应抛 ConfigValidationError""" with pytest.raises(ConfigValidationError, match="preconditions"): SkillConfig( name="x", agent_type="y", task_mode="llm_generate", prompt=_PROMPT, preconditions={"key": "val"}, # type: ignore[arg-type] )