mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-28 06:51:16 +08:00
refactor(curator): point review prompt at existing tools
The LLM review prompt mentioned bespoke `archive_skill` and `pin_skill` tools that are not registered as model tools. Swap the prompt to rely on the real surface: - skill_manage action=patch — for patching and consolidation - terminal — to `mv` skill dirs into .archive/ Also drop `pin` from the model's decision list — pinning is a user opt-out for `hermes curator pin <skill>`, not something the model should do autonomously. Decision list is now: keep / patch / consolidate / archive. Tests updated: prompt-invariant test now asserts the existing tools are referenced and that bespoke tool names do NOT appear. New test prevents `pin` from being re-added as a model decision.
This commit is contained in:
@@ -261,28 +261,33 @@ def apply_automatic_transitions(now: Optional[datetime] = None) -> Dict[str, int
|
||||
CURATOR_REVIEW_PROMPT = (
|
||||
"You are running as Hermes' background skill CURATOR.\n\n"
|
||||
"Your job is to maintain the collection of AGENT-CREATED skills. Review "
|
||||
"each one and decide what to do, using skill_manage and the curator tools.\n\n"
|
||||
"each candidate below and decide what to do.\n\n"
|
||||
"Rules — all load-bearing, do not violate:\n"
|
||||
"1. You MUST NOT touch bundled or hub-installed skills. The candidate list "
|
||||
"below is already filtered to agent-created skills only.\n"
|
||||
"2. You MUST NOT delete any skill. Archive (move to .archive/) is the "
|
||||
"maximum action. Archives are recoverable; deletion is not.\n"
|
||||
"3. You MUST NOT touch pinned skills. If a skill is pinned, skip it.\n"
|
||||
"4. Prefer GENERALIZING overlapping skills by patching the better one and "
|
||||
"archiving the duplicate, rather than leaving two narrow skills in the "
|
||||
"2. You MUST NOT delete any skill. Archiving (moving the skill's directory "
|
||||
"into ~/.hermes/skills/.archive/) is the maximum action. Archives are "
|
||||
"recoverable; deletion is not.\n"
|
||||
"3. You MUST NOT touch skills shown as pinned=yes. Skip them.\n"
|
||||
"4. Prefer GENERALIZING overlapping skills by patching the stronger one "
|
||||
"and archiving the weaker, rather than leaving two narrow skills in the "
|
||||
"collection.\n\n"
|
||||
"For each candidate decide one of:\n"
|
||||
" keep — leave as-is (most common default)\n"
|
||||
" patch — fix stale commands, wrong paths, environment-specific "
|
||||
"claims that are no longer true. Use skill_manage action=patch.\n"
|
||||
" consolidate — when two skills overlap, patch the stronger one to "
|
||||
"absorb the weaker, then archive the weaker via the 'archive_skill' tool.\n"
|
||||
" archive — if the skill is genuinely obsolete and the sidecar shows "
|
||||
"it has not been used recently. Use the 'archive_skill' tool.\n"
|
||||
" pin — if the skill is rare but important (low use_count but "
|
||||
"high value). Use the 'pin_skill' tool.\n\n"
|
||||
"Start by calling skills_list and then skill_view on any skill you want to "
|
||||
"consider patching or consolidating. Be conservative — if in doubt, keep. "
|
||||
"Your toolset:\n"
|
||||
" - skills_list, skill_view — read the current landscape\n"
|
||||
" - skill_manage action=patch — fix stale commands, wrong paths, or "
|
||||
"merge two overlapping skills by broadening the stronger one\n"
|
||||
" - terminal — move a skill directory into the archive, "
|
||||
"e.g. mv ~/.hermes/skills/<skill-dir> ~/.hermes/skills/.archive/\n\n"
|
||||
"For each candidate, decide one of:\n"
|
||||
" keep — leave as-is (most common default; don't over-curate)\n"
|
||||
" patch — skill_manage action=patch to fix stale commands, wrong "
|
||||
"paths, or env-specific claims that are no longer true\n"
|
||||
" consolidate — two skills overlap: patch the stronger one to absorb "
|
||||
"the weaker (skill_manage), then mv the weaker directory to .archive/\n"
|
||||
" archive — the skill is genuinely obsolete and has not been used "
|
||||
"recently: mv its directory to ~/.hermes/skills/.archive/\n\n"
|
||||
"Start by calling skills_list and skill_view on anything you consider "
|
||||
"patching or consolidating. Be conservative — if in doubt, keep. "
|
||||
"When you are done, write a one-sentence summary of what you changed."
|
||||
)
|
||||
|
||||
|
||||
@@ -359,5 +359,37 @@ def test_curator_review_prompt_has_invariants():
|
||||
assert "delete" in CURATOR_REVIEW_PROMPT.lower()
|
||||
assert "pinned" in CURATOR_REVIEW_PROMPT.lower()
|
||||
# Must mention the decisions the reviewer can make
|
||||
for verb in ("keep", "patch", "archive", "pin"):
|
||||
for verb in ("keep", "patch", "archive", "consolidate"):
|
||||
assert verb in CURATOR_REVIEW_PROMPT.lower()
|
||||
|
||||
|
||||
def test_curator_review_prompt_points_at_existing_tools_only():
|
||||
"""The review prompt must rely on existing tools (skill_manage + terminal)
|
||||
and must NOT reference bespoke curator tools that are not registered
|
||||
model tools."""
|
||||
from agent.curator import CURATOR_REVIEW_PROMPT
|
||||
assert "skill_manage" in CURATOR_REVIEW_PROMPT
|
||||
assert "skills_list" in CURATOR_REVIEW_PROMPT
|
||||
assert "skill_view" in CURATOR_REVIEW_PROMPT
|
||||
assert "terminal" in CURATOR_REVIEW_PROMPT.lower()
|
||||
# These would be nice but aren't actually registered as tools — the
|
||||
# curator uses skill_manage + terminal mv instead.
|
||||
assert "archive_skill" not in CURATOR_REVIEW_PROMPT
|
||||
assert "pin_skill" not in CURATOR_REVIEW_PROMPT
|
||||
|
||||
|
||||
def test_curator_does_not_instruct_model_to_pin():
|
||||
"""Pinning is a user opt-out, not a model decision. The prompt should
|
||||
not tell the reviewer to pin skills autonomously."""
|
||||
from agent.curator import CURATOR_REVIEW_PROMPT
|
||||
# "pinned" appears in the invariant ("skip pinned skills"), but "pin"
|
||||
# as a decision verb should not.
|
||||
lines = CURATOR_REVIEW_PROMPT.split("\n")
|
||||
decision_block = "\n".join(
|
||||
l for l in lines
|
||||
if l.strip().startswith(("keep", "patch", "archive", "consolidate", "pin "))
|
||||
)
|
||||
# No standalone "pin" action line
|
||||
assert not any(l.strip().startswith("pin ") for l in lines), (
|
||||
f"Found a pin action line in:\n{decision_block}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user