mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-18 04:41:56 +00:00
feat(curator): hint at hermes curator pin in the rename block (#23212)
Surfaces the pin command at the moment users care about it: when a
consolidation just landed against their skill library and they're
looking at the umbrella name in the curator output. Previously `hermes
curator pin` existed but had no discovery surface — users only learned
it existed by reading docs or stumbling onto `hermes curator --help`.
The hint:
archived 3 skill(s):
• docx-extraction → document-tools
• pdf-extraction → document-tools
• old-stale — pruned (stale)
full report: hermes curator status
keep an umbrella stable: hermes curator pin document-tools
Gated on having at least one consolidation that produced an umbrella.
Pruned-only runs (nothing surviving to pin) skip the hint. When
multiple umbrellas were produced, picks alphabetically first as a
concrete example rather than listing them all.
3 new tests in tests/agent/test_curator_classification.py covering:
consolidation produces hint with real umbrella name, pruned-only run
omits it, multi-umbrella picks one example.
This commit is contained in:
parent
50f9fee988
commit
7312f7f849
2 changed files with 118 additions and 1 deletions
|
|
@ -1020,3 +1020,106 @@ def test_rename_summary_mixed_consolidation_and_pruning(curator_env):
|
|||
assert merge_idx < drop_idx, "consolidated should render before pruned"
|
||||
assert "merge-me → umbrella" in lines[merge_idx]
|
||||
assert "drop-me — pruned (stale)" in lines[drop_idx]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pin hint — surfaces `hermes curator pin <umbrella>` in the rename block so
|
||||
# users learn the command exists at the moment they care (a consolidation
|
||||
# just landed against their library). The hint is gated on having at least
|
||||
# one umbrella destination — pruned-only runs skip it.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_rename_summary_pin_hint_appears_when_consolidation_produced_umbrella(curator_env):
|
||||
"""When at least one skill was absorbed into an umbrella, hint at pinning it."""
|
||||
result = curator_env._build_rename_summary(
|
||||
before_names={"pdf-extraction", "docx-extraction", "document-tools"},
|
||||
after_report=[{"name": "document-tools", "state": "active"}],
|
||||
tool_calls=[
|
||||
{
|
||||
"name": "skill_manage",
|
||||
"arguments": json.dumps({
|
||||
"action": "delete",
|
||||
"name": "pdf-extraction",
|
||||
"absorbed_into": "document-tools",
|
||||
}),
|
||||
},
|
||||
{
|
||||
"name": "skill_manage",
|
||||
"arguments": json.dumps({
|
||||
"action": "delete",
|
||||
"name": "docx-extraction",
|
||||
"absorbed_into": "document-tools",
|
||||
}),
|
||||
},
|
||||
],
|
||||
model_final="",
|
||||
)
|
||||
assert "hermes curator pin document-tools" in result
|
||||
assert "keep an umbrella stable" in result
|
||||
|
||||
|
||||
def test_rename_summary_pin_hint_skipped_for_pruned_only_runs(curator_env):
|
||||
"""Pruned-only runs have nothing surviving to pin — hint should not appear."""
|
||||
result = curator_env._build_rename_summary(
|
||||
before_names={"old-flaky-thing", "another-stale", "keeper"},
|
||||
after_report=[{"name": "keeper", "state": "active"}],
|
||||
tool_calls=[
|
||||
{
|
||||
"name": "skill_manage",
|
||||
"arguments": json.dumps({
|
||||
"action": "delete",
|
||||
"name": "old-flaky-thing",
|
||||
"absorbed_into": "",
|
||||
}),
|
||||
},
|
||||
{
|
||||
"name": "skill_manage",
|
||||
"arguments": json.dumps({
|
||||
"action": "delete",
|
||||
"name": "another-stale",
|
||||
"absorbed_into": "",
|
||||
}),
|
||||
},
|
||||
],
|
||||
model_final="",
|
||||
)
|
||||
# Block still renders (skills were archived) but no pin hint.
|
||||
assert "archived 2 skill(s):" in result
|
||||
assert "hermes curator pin" not in result
|
||||
assert "keep an umbrella stable" not in result
|
||||
|
||||
|
||||
def test_rename_summary_pin_hint_picks_one_umbrella_when_multiple_absorbed(curator_env):
|
||||
"""Multiple umbrellas → hint shows one example (alphabetically first), not a list."""
|
||||
result = curator_env._build_rename_summary(
|
||||
before_names={"a-skill", "b-skill", "umbrella-zeta", "umbrella-alpha"},
|
||||
after_report=[
|
||||
{"name": "umbrella-zeta", "state": "active"},
|
||||
{"name": "umbrella-alpha", "state": "active"},
|
||||
],
|
||||
tool_calls=[
|
||||
{
|
||||
"name": "skill_manage",
|
||||
"arguments": json.dumps({
|
||||
"action": "delete",
|
||||
"name": "a-skill",
|
||||
"absorbed_into": "umbrella-zeta",
|
||||
}),
|
||||
},
|
||||
{
|
||||
"name": "skill_manage",
|
||||
"arguments": json.dumps({
|
||||
"action": "delete",
|
||||
"name": "b-skill",
|
||||
"absorbed_into": "umbrella-alpha",
|
||||
}),
|
||||
},
|
||||
],
|
||||
model_final="",
|
||||
)
|
||||
# Sorted picks alphabetically first.
|
||||
assert "hermes curator pin umbrella-alpha" in result
|
||||
# Exactly one hint line, not one per umbrella.
|
||||
pin_lines = [ln for ln in result.splitlines() if "hermes curator pin" in ln]
|
||||
assert len(pin_lines) == 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue