diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-25 18:11:32 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-25 18:11:32 +0200 |
| commit | ea63943b0e9f755d00cf3e69b5ae5cebb41eb959 (patch) | |
| tree | aa627d867f019c2fc01b54275c838c90ff85efd2 /test_llamachat.py | |
| parent | 8e35d35796d5925ac7a4ee95dd60120a3c6b9539 (diff) | |
| download | llamachat-ea63943b0e9f755d00cf3e69b5ae5cebb41eb959.tar.gz llamachat-ea63943b0e9f755d00cf3e69b5ae5cebb41eb959.zip | |
feat: skill store parsing for SKILL.md instruction files
Diffstat (limited to 'test_llamachat.py')
| -rwxr-xr-x | test_llamachat.py | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/test_llamachat.py b/test_llamachat.py index 407c5dc..ef73fe3 100755 --- a/test_llamachat.py +++ b/test_llamachat.py @@ -55,6 +55,37 @@ ctx-size = 16384 ngl = all """ +SKILLS_SAMPLE = { + "firefly-cli/SKILL.md": ( + "---\n" + "name: firefly-cli\n" + "description: Operate a Firefly III instance from the command line.\n" + "---\n" + "\n" + "# firefly-cli\n" + "Run `firefly auth test` first.\n" + ), + "test-build-slackbuild/SKILL.md": ( + "---\n" + "name: test-build-slackbuild\n" + "description: Drive the sbo-dockerbuild test-build tool.\n" + "---\n" + "\n" + "Load the skill, then test-build.\n" + ), + "no-frontmatter/SKILL.md": ( + "# no-frontmatter\n" + "Skill with no frontmatter; the name falls back to the directory.\n" + ), +} + + +def _write_skills(root: Path, sample: dict) -> None: + for rel, content in sample.items(): + path = root / rel + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content) + def test_presets(): with tempfile.TemporaryDirectory() as tmp: @@ -3325,6 +3356,107 @@ def test_title_prompt(): print("ok title prompt") +def test_skills_store(): + from llamachat import skills + + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + _write_skills(root, SKILLS_SAMPLE) + store = skills.SkillStore(root) + + assert store.names() == [ + "firefly-cli", "no-frontmatter", "test-build-slackbuild" + ] + + skill = store.load("firefly-cli") + assert skill is not None + assert skill.name == "firefly-cli" + assert skill.description == "Operate a Firefly III instance from the command line." + assert skill.text.startswith("# firefly-cli") + + # A name that does not exist, and an absent directory, both yield None. + assert store.load("nope") is None + assert skills.SkillStore(Path(tmp) / "missing").names() == [] + + schema = store.tool_schema() + function = schema["function"] + assert function["name"] == "load_skill" + assert function["parameters"]["required"] == ["name"] + assert function["parameters"]["properties"]["name"]["enum"] == store.names() + assert "firefly-cli" in function["description"] + + directory = store.directory() + assert "firefly-cli" in directory + assert "test-build-slackbuild" in directory + print("ok skills store") + + +def test_skills_mentions(): + from llamachat import skills + + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + _write_skills(root, {"firefly-cli/SKILL.md": SKILLS_SAMPLE["firefly-cli/SKILL.md"]}) + store = skills.SkillStore(root) + + assert store.match_mentions("use firefly-cli for this") == ["firefly-cli"] + assert store.match_mentions("USE FIREFLY-CLI now") == ["firefly-cli"] + # No word boundary, no mention: a substring must not load a skill. + assert store.match_mentions("firefly-cli2 rocks") == [] + assert store.match_mentions("the fireflies are out") == [] + assert store.match_mentions("nothing here") == [] + print("ok skills mentions") + + +def test_skills_parse_commands(): + from llamachat import skills + + known = {"firefly-cli", "handoff"} + text, loaded = skills.parse_commands( + "/firefly-cli fix my budget /unknown stays", known + ) + assert loaded == ["firefly-cli"] + assert text == "fix my budget /unknown stays" + + text, loaded = skills.parse_commands("no commands here", known) + assert loaded == [] + assert text == "no commands here" + + # A lone command leaves nothing behind. + text, loaded = skills.parse_commands("/handoff", known) + assert loaded == ["handoff"] + assert text == "" + + # A name that is not a known skill is kept as plain text. + text, loaded = skills.parse_commands("/nope", known) + assert loaded == [] + assert text == "/nope" + print("ok skills parse commands") + + +def test_skill_tool_message(): + from llamachat import skills + + skill = skills.Skill(name="firefly-cli", description="d", text="body text") + msg = skills.tool_message("call_1", skill) + assert msg["role"] == "tool" + assert msg["tool_call_id"] == "call_1" + assert "[skill: firefly-cli]" in msg["content"] + assert "body text" in msg["content"] + + err = skills.tool_message("call_1", None, error="No such skill") + assert "error: No such skill" in err["content"] + + last = skills.tool_message("call_1", skill, last=True) + assert skills.NO_MORE_TOOLS in last["content"] + + assert skills.parse_name('{"name": "firefly-cli"}') == "firefly-cli" + assert skills.parse_name("not json") == "" + assert skills.parse_name('{"query": "x"}') == "" + assert skills.parse_name("") == "" + print("ok skill tool message") + + if __name__ == "__main__": test_presets() test_real_presets() @@ -3387,4 +3519,8 @@ if __name__ == "__main__": test_code_block_wrapping() test_code_block_copy_links() test_code_block_copy_states() + test_skills_store() + test_skills_mentions() + test_skills_parse_commands() + test_skill_tool_message() print("\nall checks passed") |
