-
Notifications
You must be signed in to change notification settings - Fork 585
Expand file tree
/
Copy pathtest_skill_module.py
More file actions
119 lines (88 loc) · 3.67 KB
/
Copy pathtest_skill_module.py
File metadata and controls
119 lines (88 loc) · 3.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"""Tests for skill module loading and parsing."""
import pytest
from pathlib import Path
from evolution.skills.skill_module import SkillModule, load_skill, reassemble_skill
SAMPLE_SKILL = """---
name: test-skill
description: A skill for testing things
version: 1.0.0
metadata:
hermes:
tags: [testing]
---
# Test Skill — Testing Things
## When to Use
Use this when you need to test things.
## Procedure
1. First, do the thing
2. Then, verify it worked
3. Report results
## Pitfalls
- Don't forget to check edge cases
"""
class TestLoadSkill:
def test_parses_frontmatter(self, tmp_path):
skill_file = tmp_path / "SKILL.md"
skill_file.write_text(SAMPLE_SKILL)
skill = load_skill(skill_file)
assert skill["name"] == "test-skill"
assert skill["description"] == "A skill for testing things"
assert "version: 1.0.0" in skill["frontmatter"]
def test_parses_body(self, tmp_path):
skill_file = tmp_path / "SKILL.md"
skill_file.write_text(SAMPLE_SKILL)
skill = load_skill(skill_file)
assert "# Test Skill" in skill["body"]
assert "## Procedure" in skill["body"]
assert "Don't forget" in skill["body"]
def test_raw_contains_everything(self, tmp_path):
skill_file = tmp_path / "SKILL.md"
skill_file.write_text(SAMPLE_SKILL)
skill = load_skill(skill_file)
assert skill["raw"] == SAMPLE_SKILL
def test_path_is_stored(self, tmp_path):
skill_file = tmp_path / "SKILL.md"
skill_file.write_text(SAMPLE_SKILL)
skill = load_skill(skill_file)
assert skill["path"] == skill_file
class TestReassembleSkill:
def test_roundtrip(self, tmp_path):
skill_file = tmp_path / "SKILL.md"
skill_file.write_text(SAMPLE_SKILL)
skill = load_skill(skill_file)
reassembled = reassemble_skill(skill["frontmatter"], skill["body"])
assert "---" in reassembled
assert "name: test-skill" in reassembled
assert "# Test Skill" in reassembled
def test_preserves_frontmatter(self):
frontmatter = "name: my-skill\ndescription: Does stuff"
body = "# My Skill\nDo the thing."
result = reassemble_skill(frontmatter, body)
assert result.startswith("---\n")
assert "name: my-skill" in result
assert "# My Skill" in result
def test_evolved_body_replaces_original(self):
frontmatter = "name: my-skill\ndescription: Does stuff"
evolved_body = "# EVOLVED\nNew and improved procedure."
result = reassemble_skill(frontmatter, evolved_body)
assert "EVOLVED" in result
assert "New and improved" in result
class TestSkillModuleOptimizable:
"""The skill text must live where GEPA mutates: signature.instructions.
GEPA's candidate space is {name: pred.signature.instructions} over
named_predictors() (dspy.teleprompt.gepa). A plain module attribute is
invisible to it, so the evolved text could never reach the saved artifact.
"""
def test_skill_text_lives_in_signature_instructions(self):
text = "# My Skill\nAlways verify before concluding."
module = SkillModule(text)
predictors = list(module.named_predictors())
assert len(predictors) == 1
_, predictor = predictors[0]
assert predictor.signature.instructions == text
def test_skill_text_property_reflects_mutation(self):
module = SkillModule("# Original")
# Mutate the way GEPA applies candidates: rewrite the instructions.
for _, predictor in module.named_predictors():
predictor.signature = predictor.signature.with_instructions("# Evolved")
assert module.skill_text == "# Evolved"