mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-07 02:51:50 +00:00
fix(skills): keep manual skills out of curator
This commit is contained in:
parent
cac4f2c0e6
commit
abcaf05229
5 changed files with 102 additions and 18 deletions
|
|
@ -11,8 +11,9 @@ Design notes:
|
|||
- Atomic writes via tempfile + os.replace (same pattern as .bundled_manifest).
|
||||
- All counter bumps are best-effort: failures log at DEBUG and return silently.
|
||||
A broken sidecar never breaks the underlying tool call.
|
||||
- Provenance filter: "agent-created" == not in .bundled_manifest AND not in
|
||||
.hub/lock.json. The curator only ever mutates agent-created skills.
|
||||
- Provenance filter: curator-managed skills are explicitly marked when
|
||||
created through skill_manage. Bundled / hub-installed skills stay
|
||||
off-limits, and manually authored skills are not inferred from location.
|
||||
|
||||
Lifecycle states:
|
||||
active -> default
|
||||
|
|
@ -149,11 +150,13 @@ def _read_hub_installed_names() -> Set[str]:
|
|||
|
||||
|
||||
def list_agent_created_skill_names() -> List[str]:
|
||||
"""Enumerate skills that were authored by the agent (or user), NOT by a
|
||||
bundled or hub-installed source.
|
||||
"""Enumerate skills explicitly authored by the agent.
|
||||
|
||||
The curator operates exclusively on this set. Bundled / hub skills are
|
||||
maintained by their upstream sources and must never be pruned here.
|
||||
The curator operates exclusively on this set. Skills are only eligible
|
||||
after ``skill_manage(action="create")`` marks them in ``.usage.json``;
|
||||
manually authored skills must not be inferred from filesystem location.
|
||||
Bundled / hub skills are maintained by their upstream sources and must
|
||||
never be pruned here.
|
||||
"""
|
||||
base = _skills_dir()
|
||||
if not base.exists():
|
||||
|
|
@ -161,6 +164,7 @@ def list_agent_created_skill_names() -> List[str]:
|
|||
bundled = _read_bundled_manifest_names()
|
||||
hub = _read_hub_installed_names()
|
||||
off_limits = bundled | hub
|
||||
usage = load_usage()
|
||||
|
||||
names: List[str] = []
|
||||
# Top-level SKILL.md files (flat layout) AND nested category/skill/SKILL.md
|
||||
|
|
@ -176,6 +180,8 @@ def list_agent_created_skill_names() -> List[str]:
|
|||
name = _read_skill_name(skill_md, fallback=skill_md.parent.name)
|
||||
if name in off_limits:
|
||||
continue
|
||||
if not _is_curator_managed_record(usage.get(name)):
|
||||
continue
|
||||
names.append(name)
|
||||
return sorted(set(names))
|
||||
|
||||
|
|
@ -207,12 +213,20 @@ def is_agent_created(skill_name: str) -> bool:
|
|||
return skill_name not in off_limits
|
||||
|
||||
|
||||
def _is_curator_managed_record(record: Any) -> bool:
|
||||
"""Return True when a usage record opts a skill into curator management."""
|
||||
if not isinstance(record, dict):
|
||||
return False
|
||||
return record.get("created_by") == "agent" or record.get("agent_created") is True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Sidecar I/O
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _empty_record() -> Dict[str, Any]:
|
||||
return {
|
||||
"created_by": None,
|
||||
"use_count": 0,
|
||||
"view_count": 0,
|
||||
"last_used_at": None,
|
||||
|
|
@ -287,9 +301,8 @@ def _mutate(skill_name: str, mutator) -> None:
|
|||
"""Load, apply *mutator(record)* in place, save. Best-effort.
|
||||
|
||||
Bundled and hub-installed skills are NEVER recorded in the sidecar.
|
||||
This keeps .usage.json focused on agent-created skills (the only ones
|
||||
the curator considers) and prevents stale counters from hanging around
|
||||
for upstream-managed skills.
|
||||
Local manual skills may still accrue usage telemetry, but they only
|
||||
become curator-managed when ``created_by`` is explicitly marked.
|
||||
"""
|
||||
if not skill_name:
|
||||
return
|
||||
|
|
@ -336,6 +349,17 @@ def bump_patch(skill_name: str) -> None:
|
|||
_mutate(skill_name, _apply)
|
||||
|
||||
|
||||
def mark_agent_created(skill_name: str) -> None:
|
||||
"""Opt a skill created by skill_manage into curator management.
|
||||
|
||||
Viewing or invoking a manually authored skill may still create telemetry,
|
||||
but only this explicit marker makes it eligible for automatic curation.
|
||||
"""
|
||||
def _apply(rec: Dict[str, Any]) -> None:
|
||||
rec["created_by"] = "agent"
|
||||
_mutate(skill_name, _apply)
|
||||
|
||||
|
||||
def set_state(skill_name: str, state: str) -> None:
|
||||
"""Set lifecycle state. No-op if *state* is invalid."""
|
||||
if state not in _VALID_STATES:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue