mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(skills): read name from SKILL.md frontmatter in skills_sync
_discover_bundled_skills() used the directory name to identify skills, but skills_tool.py and skills_hub.py use the `name:` field from SKILL.md frontmatter. This mismatch caused 9 builtin skills whose directory name differs from their SKILL.md name to be written to .bundled_manifest under the wrong key, so `hermes skills list` showed them as "local" instead of "builtin". Read the frontmatter name field (with directory-name fallback) so the manifest keys match what the rest of the codebase expects. Closes #6835
This commit is contained in:
parent
d442f25a2f
commit
b87e0f59cc
2 changed files with 54 additions and 1 deletions
|
|
@ -6,6 +6,7 @@ from unittest.mock import patch
|
|||
from tools.skills_sync import (
|
||||
_get_bundled_dir,
|
||||
_read_manifest,
|
||||
_read_skill_name,
|
||||
_write_manifest,
|
||||
_discover_bundled_skills,
|
||||
_compute_relative_dest,
|
||||
|
|
@ -132,6 +133,37 @@ class TestDiscoverBundledSkills:
|
|||
assert skills == []
|
||||
|
||||
|
||||
class TestReadSkillName:
|
||||
def test_reads_name_from_frontmatter(self, tmp_path):
|
||||
skill_md = tmp_path / "SKILL.md"
|
||||
skill_md.write_text("---\nname: audiocraft-audio-generation\n---\n# Skill")
|
||||
assert _read_skill_name(skill_md, "audiocraft") == "audiocraft-audio-generation"
|
||||
|
||||
def test_falls_back_to_dir_name_without_frontmatter(self, tmp_path):
|
||||
skill_md = tmp_path / "SKILL.md"
|
||||
skill_md.write_text("# Just a heading\nNo frontmatter here")
|
||||
assert _read_skill_name(skill_md, "my-skill") == "my-skill"
|
||||
|
||||
def test_falls_back_when_name_field_empty(self, tmp_path):
|
||||
skill_md = tmp_path / "SKILL.md"
|
||||
skill_md.write_text("---\nname:\n---\n")
|
||||
assert _read_skill_name(skill_md, "fallback") == "fallback"
|
||||
|
||||
def test_handles_quoted_name(self, tmp_path):
|
||||
skill_md = tmp_path / "SKILL.md"
|
||||
skill_md.write_text('---\nname: "serving-llms-vllm"\n---\n')
|
||||
assert _read_skill_name(skill_md, "vllm") == "serving-llms-vllm"
|
||||
|
||||
def test_discover_uses_frontmatter_name(self, tmp_path):
|
||||
skill_dir = tmp_path / "category" / "audiocraft"
|
||||
skill_dir.mkdir(parents=True)
|
||||
(skill_dir / "SKILL.md").write_text(
|
||||
"---\nname: audiocraft-audio-generation\n---\n# Skill"
|
||||
)
|
||||
skills = _discover_bundled_skills(tmp_path)
|
||||
assert skills[0][0] == "audiocraft-audio-generation"
|
||||
|
||||
|
||||
class TestComputeRelativeDest:
|
||||
def test_preserves_category_structure(self):
|
||||
bundled = Path("/repo/skills")
|
||||
|
|
|
|||
|
|
@ -109,6 +109,27 @@ def _write_manifest(entries: Dict[str, str]):
|
|||
logger.debug("Failed to write skills manifest %s: %s", MANIFEST_FILE, e, exc_info=True)
|
||||
|
||||
|
||||
def _read_skill_name(skill_md: Path, fallback: str) -> str:
|
||||
"""Read the name field from SKILL.md YAML frontmatter, falling back to *fallback*."""
|
||||
try:
|
||||
content = skill_md.read_text(encoding="utf-8", errors="replace")[:4000]
|
||||
except OSError:
|
||||
return fallback
|
||||
in_frontmatter = False
|
||||
for line in content.split("\n"):
|
||||
stripped = line.strip()
|
||||
if stripped == "---":
|
||||
if in_frontmatter:
|
||||
break
|
||||
in_frontmatter = True
|
||||
continue
|
||||
if in_frontmatter and stripped.startswith("name:"):
|
||||
value = stripped.split(":", 1)[1].strip().strip("\"'")
|
||||
if value:
|
||||
return value
|
||||
return fallback
|
||||
|
||||
|
||||
def _discover_bundled_skills(bundled_dir: Path) -> List[Tuple[str, Path]]:
|
||||
"""
|
||||
Find all SKILL.md files in the bundled directory.
|
||||
|
|
@ -123,7 +144,7 @@ def _discover_bundled_skills(bundled_dir: Path) -> List[Tuple[str, Path]]:
|
|||
if "/.git/" in path_str or "/.github/" in path_str or "/.hub/" in path_str:
|
||||
continue
|
||||
skill_dir = skill_md.parent
|
||||
skill_name = skill_dir.name
|
||||
skill_name = _read_skill_name(skill_md, skill_dir.name)
|
||||
skills.append((skill_name, skill_dir))
|
||||
|
||||
return skills
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue