mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-07 08:02:23 +00:00
fix: backfill official optional skill provenance
This commit is contained in:
parent
a38e283395
commit
f040710d04
4 changed files with 414 additions and 2 deletions
|
|
@ -1,5 +1,6 @@
|
|||
"""Tests for tools/skills_sync.py — manifest-based skill seeding and updating."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ from tools.skills_sync import (
|
|||
_dir_hash,
|
||||
sync_skills,
|
||||
reset_bundled_skill,
|
||||
restore_official_optional_skill,
|
||||
MANIFEST_FILE,
|
||||
SKILLS_DIR,
|
||||
)
|
||||
|
|
@ -196,6 +198,7 @@ class TestSyncSkills:
|
|||
from contextlib import ExitStack
|
||||
stack = ExitStack()
|
||||
stack.enter_context(patch("tools.skills_sync._get_bundled_dir", return_value=bundled))
|
||||
stack.enter_context(patch("tools.skills_sync._get_optional_dir", return_value=bundled.parent / "optional-skills"))
|
||||
stack.enter_context(patch("tools.skills_sync.SKILLS_DIR", skills_dir))
|
||||
stack.enter_context(patch("tools.skills_sync.MANIFEST_FILE", manifest_file))
|
||||
return stack
|
||||
|
|
@ -482,12 +485,123 @@ class TestSyncSkills:
|
|||
assert "new-skill" in captured
|
||||
assert "hermes skills reset new-skill" in captured
|
||||
|
||||
def test_backfills_official_optional_provenance_for_existing_identical_skill(self, tmp_path):
|
||||
bundled = self._setup_bundled(tmp_path)
|
||||
optional = tmp_path / "optional-skills"
|
||||
optional_skill = optional / "mlops" / "training" / "trl-fine-tuning"
|
||||
optional_skill.mkdir(parents=True)
|
||||
(optional_skill / "SKILL.md").write_text(
|
||||
"---\nname: fine-tuning-with-trl\n---\n# TRL\n"
|
||||
)
|
||||
(optional_skill / "references").mkdir()
|
||||
(optional_skill / "references" / "api.md").write_text("api\n")
|
||||
|
||||
skills_dir = tmp_path / "user_skills"
|
||||
manifest_file = skills_dir / ".bundled_manifest"
|
||||
active = skills_dir / "mlops" / "training" / "trl-fine-tuning"
|
||||
active.mkdir(parents=True)
|
||||
(active / "SKILL.md").write_text(
|
||||
"---\nname: fine-tuning-with-trl\n---\n# TRL\n"
|
||||
)
|
||||
(active / "references").mkdir()
|
||||
(active / "references" / "api.md").write_text("api\n")
|
||||
|
||||
with self._patches(bundled, skills_dir, manifest_file):
|
||||
with patch("tools.skills_sync._get_optional_dir", return_value=optional):
|
||||
result = sync_skills(quiet=True)
|
||||
|
||||
assert result["optional_provenance_backfilled"] == ["trl-fine-tuning"]
|
||||
lock_path = skills_dir / ".hub" / "lock.json"
|
||||
data = json.loads(lock_path.read_text())
|
||||
entry = data["installed"]["trl-fine-tuning"]
|
||||
assert entry["source"] == "official"
|
||||
assert entry["identifier"] == "official/mlops/training/trl-fine-tuning"
|
||||
assert entry["trust_level"] == "builtin"
|
||||
assert entry["install_path"] == "mlops/training/trl-fine-tuning"
|
||||
|
||||
def test_does_not_backfill_optional_provenance_for_modified_skill(self, tmp_path):
|
||||
bundled = self._setup_bundled(tmp_path)
|
||||
optional = tmp_path / "optional-skills"
|
||||
optional_skill = optional / "mlops" / "training" / "trl-fine-tuning"
|
||||
optional_skill.mkdir(parents=True)
|
||||
(optional_skill / "SKILL.md").write_text("# upstream optional\n")
|
||||
|
||||
skills_dir = tmp_path / "user_skills"
|
||||
manifest_file = skills_dir / ".bundled_manifest"
|
||||
active = skills_dir / "mlops" / "training" / "trl-fine-tuning"
|
||||
active.mkdir(parents=True)
|
||||
(active / "SKILL.md").write_text("# user modified\n")
|
||||
|
||||
with self._patches(bundled, skills_dir, manifest_file):
|
||||
with patch("tools.skills_sync._get_optional_dir", return_value=optional):
|
||||
result = sync_skills(quiet=True)
|
||||
|
||||
assert result["optional_provenance_backfilled"] == []
|
||||
assert not (skills_dir / ".hub" / "lock.json").exists()
|
||||
|
||||
def test_repair_official_optional_restores_reorganized_skill_with_backup(self, tmp_path):
|
||||
bundled = self._setup_bundled(tmp_path)
|
||||
optional = tmp_path / "optional-skills"
|
||||
optional_skill = optional / "mlops" / "training" / "trl-fine-tuning"
|
||||
optional_skill.mkdir(parents=True)
|
||||
(optional_skill / "SKILL.md").write_text(
|
||||
"---\nname: fine-tuning-with-trl\n---\n# Official TRL\n"
|
||||
)
|
||||
|
||||
skills_dir = tmp_path / "user_skills"
|
||||
manifest_file = skills_dir / ".bundled_manifest"
|
||||
wrong = skills_dir / "mlops" / "trl-fine-tuning"
|
||||
wrong.mkdir(parents=True)
|
||||
(wrong / "SKILL.md").write_text(
|
||||
"---\nname: fine-tuning-with-trl\n---\n# Curator mangled\n"
|
||||
)
|
||||
|
||||
with self._patches(bundled, skills_dir, manifest_file):
|
||||
with patch("tools.skills_sync._get_optional_dir", return_value=optional):
|
||||
result = restore_official_optional_skill("fine-tuning-with-trl", restore=True)
|
||||
|
||||
canonical = skills_dir / "mlops" / "training" / "trl-fine-tuning"
|
||||
assert result["ok"] is True
|
||||
assert result["restored"] == ["trl-fine-tuning"]
|
||||
assert result["backed_up"] == ["mlops/trl-fine-tuning"]
|
||||
assert "Official TRL" in (canonical / "SKILL.md").read_text()
|
||||
assert not wrong.exists()
|
||||
assert (Path(result["backup_dir"]) / "mlops" / "trl-fine-tuning" / "SKILL.md").exists()
|
||||
|
||||
data = json.loads((skills_dir / ".hub" / "lock.json").read_text())
|
||||
assert data["installed"]["trl-fine-tuning"]["source"] == "official"
|
||||
assert data["installed"]["trl-fine-tuning"]["install_path"] == "mlops/training/trl-fine-tuning"
|
||||
|
||||
def test_repair_official_optional_without_restore_does_not_replace_modified_copy(self, tmp_path):
|
||||
bundled = self._setup_bundled(tmp_path)
|
||||
optional = tmp_path / "optional-skills"
|
||||
optional_skill = optional / "mlops" / "training" / "trl-fine-tuning"
|
||||
optional_skill.mkdir(parents=True)
|
||||
(optional_skill / "SKILL.md").write_text("# official\n")
|
||||
|
||||
skills_dir = tmp_path / "user_skills"
|
||||
manifest_file = skills_dir / ".bundled_manifest"
|
||||
canonical = skills_dir / "mlops" / "training" / "trl-fine-tuning"
|
||||
canonical.mkdir(parents=True)
|
||||
(canonical / "SKILL.md").write_text("# modified\n")
|
||||
|
||||
with self._patches(bundled, skills_dir, manifest_file):
|
||||
with patch("tools.skills_sync._get_optional_dir", return_value=optional):
|
||||
result = restore_official_optional_skill("trl-fine-tuning", restore=False)
|
||||
|
||||
assert result["ok"] is True
|
||||
assert result["restored"] == []
|
||||
assert result["backfilled"] == []
|
||||
assert (canonical / "SKILL.md").read_text() == "# modified\n"
|
||||
assert not (skills_dir / ".hub" / "lock.json").exists()
|
||||
|
||||
def test_nonexistent_bundled_dir(self, tmp_path):
|
||||
with patch("tools.skills_sync._get_bundled_dir", return_value=tmp_path / "nope"):
|
||||
result = sync_skills(quiet=True)
|
||||
assert result == {
|
||||
"copied": [], "updated": [], "skipped": 0,
|
||||
"user_modified": [], "cleaned": [], "total_bundled": 0,
|
||||
"optional_provenance_backfilled": [],
|
||||
}
|
||||
|
||||
def test_failed_copy_does_not_poison_manifest(self, tmp_path):
|
||||
|
|
@ -620,6 +734,7 @@ class TestResetBundledSkill:
|
|||
from contextlib import ExitStack
|
||||
stack = ExitStack()
|
||||
stack.enter_context(patch("tools.skills_sync._get_bundled_dir", return_value=bundled))
|
||||
stack.enter_context(patch("tools.skills_sync._get_optional_dir", return_value=bundled.parent / "optional-skills"))
|
||||
stack.enter_context(patch("tools.skills_sync.SKILLS_DIR", skills_dir))
|
||||
stack.enter_context(patch("tools.skills_sync.MANIFEST_FILE", manifest_file))
|
||||
return stack
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue