aboutsummaryrefslogtreecommitdiffstats
path: root/test_llamachat.py
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-25 18:11:32 +0200
committerDanilo M. <danix@danix.xyz>2026-08-25 18:11:32 +0200
commitea63943b0e9f755d00cf3e69b5ae5cebb41eb959 (patch)
treeaa627d867f019c2fc01b54275c838c90ff85efd2 /test_llamachat.py
parent8e35d35796d5925ac7a4ee95dd60120a3c6b9539 (diff)
downloadllamachat-ea63943b0e9f755d00cf3e69b5ae5cebb41eb959.tar.gz
llamachat-ea63943b0e9f755d00cf3e69b5ae5cebb41eb959.zip
feat: skill store parsing for SKILL.md instruction files
Diffstat (limited to 'test_llamachat.py')
-rwxr-xr-xtest_llamachat.py136
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")