teleo-infrastructure/tests/test_hermes_response_transform_patch.py
2026-07-15 22:49:20 +02:00

119 lines
4.2 KiB
Python

"""Tests for the managed Hermes response-transform lifecycle patch."""
from __future__ import annotations
import importlib.util
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
PATCHER = ROOT / "hermes-agent" / "patches" / "apply_response_transform_hook.py"
def load_patcher():
spec = importlib.util.spec_from_file_location("hermes_response_transform_patcher", PATCHER)
assert spec and spec.loader
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def upstream_fixture() -> str:
return '''class Agent:
def run(self, messages, user_message, completed, effective_task_id, conversation_history,
final_response, interrupted, original_user_message):
# Save trajectory if enabled
self._save_trajectory(messages, user_message, completed)
# Clean up VM and browser for this task after conversation completes
self._cleanup_task_resources(effective_task_id)
# Persist session to both JSON log and SQLite
self._persist_session(messages, conversation_history)
# Plugin hook: post_llm_call
if final_response and not interrupted:
from hermes_cli.plugins import invoke_hook as _invoke_hook
_invoke_hook(
"post_llm_call",
session_id=self.session_id,
user_message=original_user_message,
assistant_response=final_response,
)
# Extract reasoning from the last assistant message (if any)
last_reasoning = None
return final_response, last_reasoning
'''
def test_patch_moves_response_transform_before_persistence_and_is_idempotent() -> None:
module = load_patcher()
patched, changed = module.patch_source(upstream_fixture())
assert changed is True
assert module.PATCH_MARKER in patched
assert patched.index('_candidate = _post_result.get("assistant_response")') < patched.index(
"self._save_trajectory(messages, user_message, completed)"
)
assert patched.index("self._save_trajectory(messages, user_message, completed)") < patched.index(
"self._persist_session(messages, conversation_history)"
)
assert module.patch_source(patched) == (patched, False)
def test_patch_refuses_unknown_hermes_lifecycle() -> None:
module = load_patcher()
with pytest.raises(ValueError, match="anchors changed"):
module.patch_source("class Agent:\n pass\n")
def test_install_check_reports_patch_required_then_installed(tmp_path: Path) -> None:
module = load_patcher()
target = tmp_path / "run_agent.py"
target.write_text(upstream_fixture(), encoding="utf-8")
before, before_code = module.install(target, check=True)
assert before_code == 1
assert before["status"] == "patch_required"
applied, applied_code = module.install(target, check=False)
assert applied_code == 0
assert applied["status"] == "installed_now"
after, after_code = module.install(target, check=True)
assert after_code == 0
assert after["status"] == "installed"
def test_runtime_installer_manages_response_and_telegram_name_patches(tmp_path: Path) -> None:
module = load_patcher()
run_agent = tmp_path / "run_agent.py"
telegram = tmp_path / "gateway" / "platforms" / "telegram.py"
telegram.parent.mkdir(parents=True)
run_agent.write_text(upstream_fixture(), encoding="utf-8")
telegram.write_text(
'''def build_source(user):
return dict(
user_id=str(user.id) if user else None,
user_name=user.full_name if user else None,
)
''',
encoding="utf-8",
)
before, before_code = module.install_runtime(run_agent, check=True)
assert before_code == 1
assert before["status"] == "patch_required"
applied, applied_code = module.install_runtime(run_agent, check=False)
assert applied_code == 0
assert applied["status"] == "installed_now"
assert applied["response_transform"]["status"] == "installed_now"
assert applied["telegram_sender_name_policy"]["status"] == "installed_now"
after, after_code = module.install_runtime(run_agent, check=True)
assert after_code == 0
assert after["status"] == "installed"