feat(curator): make skill consolidation opt-in (prune stays default-on) (#47840)
The curator now defaults to prune-only: the deterministic inactivity pass (mark stale / archive long-unused skills) still runs whenever the curator is enabled, but the opinionated LLM umbrella-building consolidation fork is OFF by default. - agent/curator.py: add DEFAULT_CONSOLIDATE=False + get_consolidate(); gate the forked aux-model review in run_curator_review behind it (new consolidate param, None=read config). When off, the LLM pass is skipped entirely (no aux-model cost); the run is still recorded and reported. - config.py: add curator.consolidate (default false); v29->v30 migration seeds the key for existing installs without clobbering a user-set value. - hermes_cli/curator.py: 'hermes curator run --consolidate' override; status shows consolidate state; prune-only notice on run. - docs + tests.
This commit is contained in:
parent
e48803daec
commit
7bbffceb9c
5 changed files with 217 additions and 11 deletions
|
|
@ -520,7 +520,7 @@ def test_dry_run_injects_report_only_banner(curator_env, monkeypatch):
|
|||
"tool_calls": [], "error": None}
|
||||
monkeypatch.setattr(c, "_run_llm_review", _stub)
|
||||
|
||||
c.run_curator_review(synchronous=True, dry_run=True)
|
||||
c.run_curator_review(synchronous=True, dry_run=True, consolidate=True)
|
||||
assert "DRY-RUN" in captured["prompt"]
|
||||
assert "DO NOT" in captured["prompt"]
|
||||
|
||||
|
|
@ -571,7 +571,11 @@ def test_run_review_synchronous_invokes_llm_stub(curator_env, monkeypatch):
|
|||
monkeypatch.setattr(c, "_run_llm_review", _stub)
|
||||
|
||||
captured = []
|
||||
c.run_curator_review(on_summary=lambda s: captured.append(s), synchronous=True)
|
||||
c.run_curator_review(
|
||||
on_summary=lambda s: captured.append(s),
|
||||
synchronous=True,
|
||||
consolidate=True,
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert "skill CURATOR" in calls[0] or "CURATOR" in calls[0]
|
||||
|
|
@ -595,6 +599,69 @@ def test_run_review_skips_llm_when_no_candidates(curator_env, monkeypatch):
|
|||
assert any("skipped" in s for s in captured)
|
||||
|
||||
|
||||
def test_consolidate_default_off(curator_env):
|
||||
"""Consolidation (the LLM umbrella pass) is OFF by default — only the
|
||||
deterministic inactivity prune runs unless the user opts in."""
|
||||
c = curator_env["curator"]
|
||||
assert c.get_consolidate() is False
|
||||
|
||||
|
||||
def test_consolidate_enabled_via_config(curator_env, monkeypatch):
|
||||
c = curator_env["curator"]
|
||||
monkeypatch.setattr(c, "_load_config", lambda: {"consolidate": True})
|
||||
assert c.get_consolidate() is True
|
||||
|
||||
|
||||
def test_run_review_skips_llm_when_consolidate_off(curator_env, monkeypatch):
|
||||
"""With consolidation off (the default), a run does the deterministic
|
||||
prune but never spawns the LLM consolidation fork — even with candidates
|
||||
present. The run is still recorded and a 'consolidation off' summary is
|
||||
surfaced."""
|
||||
c = curator_env["curator"]
|
||||
u = curator_env["usage"]
|
||||
skills_dir = curator_env["home"] / "skills"
|
||||
_write_skill(skills_dir, "a")
|
||||
u.mark_agent_created("a")
|
||||
|
||||
calls = []
|
||||
monkeypatch.setattr(
|
||||
c, "_run_llm_review",
|
||||
lambda prompt: (calls.append(prompt), "never-called")[1],
|
||||
)
|
||||
|
||||
captured = []
|
||||
c.run_curator_review(on_summary=lambda s: captured.append(s), synchronous=True)
|
||||
|
||||
assert calls == [] # LLM consolidation fork not invoked
|
||||
assert any("consolidation off" in s for s in captured)
|
||||
# The run is still recorded (deterministic prune happened).
|
||||
state = c.load_state()
|
||||
assert state["last_run_at"] is not None
|
||||
assert state["run_count"] >= 1
|
||||
|
||||
|
||||
def test_run_review_consolidate_override_runs_llm(curator_env, monkeypatch):
|
||||
"""Passing consolidate=True overrides the config default (off) and drives
|
||||
the LLM consolidation pass — mirrors `hermes curator run --consolidate`."""
|
||||
c = curator_env["curator"]
|
||||
u = curator_env["usage"]
|
||||
skills_dir = curator_env["home"] / "skills"
|
||||
_write_skill(skills_dir, "a")
|
||||
u.mark_agent_created("a")
|
||||
|
||||
calls = []
|
||||
monkeypatch.setattr(
|
||||
c, "_run_llm_review",
|
||||
lambda prompt: (calls.append(prompt), {
|
||||
"final": "", "summary": "s", "model": "", "provider": "",
|
||||
"tool_calls": [], "error": None,
|
||||
})[1],
|
||||
)
|
||||
|
||||
c.run_curator_review(synchronous=True, consolidate=True)
|
||||
assert len(calls) == 1
|
||||
|
||||
|
||||
def test_maybe_run_curator_respects_disabled(curator_env, monkeypatch):
|
||||
c = curator_env["curator"]
|
||||
monkeypatch.setattr(c, "_load_config", lambda: {"enabled": False})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue