mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-02 07:11:49 +00:00
fix(kanban): persist worker session metadata on completion
Salvages #25579 by @wesleysimplicio. Stamps task_runs.metadata.worker_session_id from HERMES_SESSION_ID on kanban_complete. Cherry-picked the substantive commit (not the AUTHOR_MAP fixup tip) onto current main.
This commit is contained in:
parent
4f6101cc74
commit
86279160b0
2 changed files with 68 additions and 0 deletions
|
|
@ -128,6 +128,7 @@ def worker_env(monkeypatch, tmp_path):
|
|||
home.mkdir()
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
monkeypatch.setenv("HERMES_PROFILE", "test-worker")
|
||||
monkeypatch.delenv("HERMES_SESSION_ID", raising=False)
|
||||
from pathlib import Path as _Path
|
||||
monkeypatch.setattr(_Path, "home", lambda: tmp_path)
|
||||
|
||||
|
|
@ -310,6 +311,58 @@ def test_complete_metadata_round_trips_through_show(worker_env):
|
|||
assert shown["runs"][-1]["metadata"] == handoff
|
||||
|
||||
|
||||
def test_complete_stamps_worker_session_id_from_env(monkeypatch, worker_env):
|
||||
from tools import kanban_tools as kt
|
||||
|
||||
monkeypatch.setenv("HERMES_SESSION_ID", "session-trusted")
|
||||
metadata = {"files": 2, "worker_session_id": "user-spoof"}
|
||||
|
||||
out = kt._handle_complete({
|
||||
"summary": "done by scoped worker",
|
||||
"metadata": metadata,
|
||||
})
|
||||
assert json.loads(out)["ok"] is True
|
||||
assert metadata["worker_session_id"] == "user-spoof"
|
||||
|
||||
from hermes_cli import kanban_db as kb
|
||||
conn = kb.connect()
|
||||
try:
|
||||
run = kb.latest_run(conn, worker_env)
|
||||
assert run.metadata == {
|
||||
"files": 2,
|
||||
"worker_session_id": "session-trusted",
|
||||
}
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_complete_does_not_stamp_worker_session_id_without_scoped_task(
|
||||
monkeypatch, worker_env
|
||||
):
|
||||
from tools import kanban_tools as kt
|
||||
|
||||
monkeypatch.delenv("HERMES_KANBAN_TASK", raising=False)
|
||||
monkeypatch.setenv("HERMES_SESSION_ID", "session-trusted")
|
||||
|
||||
out = kt._handle_complete({
|
||||
"task_id": worker_env,
|
||||
"summary": "done outside worker scope",
|
||||
"metadata": {"files": 2, "worker_session_id": "user-provided"},
|
||||
})
|
||||
assert json.loads(out)["ok"] is True
|
||||
|
||||
from hermes_cli import kanban_db as kb
|
||||
conn = kb.connect()
|
||||
try:
|
||||
run = kb.latest_run(conn, worker_env)
|
||||
assert run.metadata == {
|
||||
"files": 2,
|
||||
"worker_session_id": "user-provided",
|
||||
}
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_complete_with_result_only(worker_env):
|
||||
"""`result` alone (without summary) is accepted for legacy compat."""
|
||||
from tools import kanban_tools as kt
|
||||
|
|
|
|||
|
|
@ -112,6 +112,20 @@ def _worker_run_id(task_id: str) -> Optional[int]:
|
|||
return None
|
||||
|
||||
|
||||
def _stamp_worker_session_metadata(
|
||||
task_id: str, metadata: Optional[dict]
|
||||
) -> Optional[dict]:
|
||||
"""Add trusted worker session id metadata for this worker's own task."""
|
||||
if os.environ.get("HERMES_KANBAN_TASK") != task_id:
|
||||
return metadata
|
||||
session_id = os.environ.get("HERMES_SESSION_ID")
|
||||
if not session_id:
|
||||
return metadata
|
||||
stamped = dict(metadata or {})
|
||||
stamped["worker_session_id"] = session_id
|
||||
return stamped
|
||||
|
||||
|
||||
def _enforce_worker_task_ownership(tid: str) -> Optional[str]:
|
||||
"""Reject worker-driven destructive calls on foreign task IDs.
|
||||
|
||||
|
|
@ -432,6 +446,7 @@ def _handle_complete(args: dict, **kw) -> str:
|
|||
return tool_error(
|
||||
f"metadata must be an object/dict, got {type(metadata).__name__}"
|
||||
)
|
||||
metadata = _stamp_worker_session_metadata(tid, metadata)
|
||||
try:
|
||||
kb, conn = _connect()
|
||||
try:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue