mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-06 10:47:12 +08:00
Tighten the provenance semantics added in #19618: skills a user asks a foreground agent to write via skill_manage(create) now stay invisible to the curator. Only skills the background self-improvement review fork sediments through skill_manage get the created_by=agent marker. - tools/skill_provenance.py — new ContextVar module mirroring the _approval_session_key pattern: set_current_write_origin / reset / get / is_background_review. Default origin is 'foreground'; the review fork sets 'background_review'. - run_agent.py — run_conversation() binds the ContextVar from self._memory_write_origin at the top of each call. The review fork runs on its own thread (fresh context), so foreground and review contexts never cross-contaminate. - tools/skill_manager_tool.py — skill_manage(action='create') now only calls mark_agent_created() when is_background_review(). All other cases (foreground create, patch, edit, write_file, delete) continue as before. - tests: test_skill_provenance.py (6 tests covering the ContextVar surface), split test_full_create_via_dispatcher into foreground vs. review-fork variants, curator status tests now mark-first. Why: the agent routinely edits existing user skills on the user's behalf; those writes must never flip provenance. And when a user explicitly asks the foreground agent to create a skill, that skill belongs to the user. The curator should only be cleaning up after its own autonomous sediment from the review nudge loop.
79 lines
2.5 KiB
Python
79 lines
2.5 KiB
Python
"""Skill write-origin provenance — ContextVar for distinguishing agent-sediment skill writes from foreground user-directed writes.
|
|
|
|
The curator only consolidates/prunes skills it autonomously created via the
|
|
background self-improvement review fork. Skills a user asks a foreground
|
|
agent to write belong to the user and must never be auto-curated.
|
|
|
|
This module exposes a ContextVar that run_agent.py sets before each tool
|
|
loop so tool handlers (e.g. skill_manage create) can check whether they
|
|
are executing inside the background-review fork.
|
|
|
|
The signal piggybacks on AIAgent._memory_write_origin, which is already
|
|
set to "background_review" for review-fork instances (see
|
|
_spawn_background_review in run_agent.py) and defaults to "assistant_tool"
|
|
for normal (foreground) agents.
|
|
|
|
Usage:
|
|
from tools.skill_provenance import (
|
|
set_current_write_origin,
|
|
reset_current_write_origin,
|
|
get_current_write_origin,
|
|
)
|
|
|
|
token = set_current_write_origin("background_review")
|
|
try:
|
|
... # tool runs here
|
|
finally:
|
|
reset_current_write_origin(token)
|
|
|
|
# inside a tool:
|
|
if get_current_write_origin() == "background_review":
|
|
mark_agent_created(skill_name)
|
|
"""
|
|
|
|
import contextvars
|
|
|
|
|
|
_write_origin: contextvars.ContextVar[str] = contextvars.ContextVar(
|
|
"skill_write_origin",
|
|
default="foreground",
|
|
)
|
|
|
|
# The sentinel value the background review fork uses; mirrors
|
|
# run_agent.py's AIAgent._memory_write_origin override in
|
|
# _spawn_background_review().
|
|
BACKGROUND_REVIEW = "background_review"
|
|
|
|
|
|
def set_current_write_origin(origin: str) -> contextvars.Token[str]:
|
|
"""Bind the active write origin to the current context.
|
|
|
|
Returns a Token the caller must pass to reset_current_write_origin
|
|
in a finally block.
|
|
"""
|
|
return _write_origin.set(origin or "foreground")
|
|
|
|
|
|
def reset_current_write_origin(token: contextvars.Token[str]) -> None:
|
|
"""Restore the prior write origin context."""
|
|
_write_origin.reset(token)
|
|
|
|
|
|
def get_current_write_origin() -> str:
|
|
"""Return the active write origin.
|
|
|
|
Default: "foreground" — any tool call made by a regular (non-review)
|
|
agent, from the CLI, the gateway, cron, or a subagent.
|
|
|
|
"background_review" — the self-improvement review fork; only skills
|
|
created under this origin should be marked agent-created for curator
|
|
management.
|
|
"""
|
|
return _write_origin.get()
|
|
|
|
|
|
def is_background_review() -> bool:
|
|
"""Convenience: True iff the current write origin is the background
|
|
review fork."""
|
|
return get_current_write_origin() == BACKGROUND_REVIEW
|