fix(gateway): preserve thread routing for /update progress and prompts

This commit is contained in:
Yukipukii1 2026-04-29 16:55:12 +03:00 committed by Teknium
parent f48ba47d1e
commit 25cbe3e1d6
5 changed files with 138 additions and 9 deletions

View file

@ -17,13 +17,14 @@ from gateway.session import SessionSource
def _make_event(text="/update", platform=Platform.TELEGRAM,
user_id="12345", chat_id="67890"):
user_id="12345", chat_id="67890", thread_id=None):
"""Build a MessageEvent for testing."""
source = SessionSource(
platform=platform,
user_id=user_id,
chat_id=chat_id,
user_name="testuser",
thread_id=thread_id,
)
return MessageEvent(text=text, source=source)
@ -214,6 +215,34 @@ class TestHandleUpdateCommand:
assert "timestamp" in data
assert not (hermes_home / ".update_exit_code").exists()
@pytest.mark.asyncio
async def test_writes_pending_marker_with_thread_id(self, tmp_path):
"""Persists thread_id so update notifications can route back to the thread."""
runner = _make_runner()
event = _make_event(
platform=Platform.TELEGRAM,
chat_id="99999",
thread_id="777",
)
fake_root = tmp_path / "project"
fake_root.mkdir()
(fake_root / ".git").mkdir()
(fake_root / "gateway").mkdir()
(fake_root / "gateway" / "run.py").touch()
fake_file = str(fake_root / "gateway" / "run.py")
hermes_home = tmp_path / "hermes"
hermes_home.mkdir()
with patch("gateway.run._hermes_home", hermes_home), \
patch("gateway.run.__file__", fake_file), \
patch("shutil.which", side_effect=lambda x: "/usr/bin/hermes" if x == "hermes" else "/usr/bin/setsid"), \
patch("subprocess.Popen"):
await runner._handle_update_command(event)
data = json.loads((hermes_home / ".update_pending.json").read_text())
assert data["thread_id"] == "777"
@pytest.mark.asyncio
async def test_spawns_setsid(self, tmp_path):
"""Uses setsid when available."""
@ -432,6 +461,31 @@ class TestSendUpdateNotification:
assert call_args[0][0] == "67890" # chat_id
assert "Update complete" in call_args[0][1] or "update finished" in call_args[0][1].lower()
@pytest.mark.asyncio
async def test_sends_notification_with_thread_metadata(self, tmp_path):
"""Final update notification preserves thread metadata when present."""
runner = _make_runner()
hermes_home = tmp_path / "hermes"
hermes_home.mkdir()
pending = {
"platform": "telegram",
"chat_id": "67890",
"thread_id": "777",
"user_id": "12345",
}
(hermes_home / ".update_pending.json").write_text(json.dumps(pending))
(hermes_home / ".update_output.txt").write_text("done")
(hermes_home / ".update_exit_code").write_text("0")
mock_adapter = AsyncMock()
runner.adapters = {Platform.TELEGRAM: mock_adapter}
with patch("gateway.run._hermes_home", hermes_home):
await runner._send_update_notification()
assert mock_adapter.send.call_args.kwargs["metadata"] == {"thread_id": "777"}
@pytest.mark.asyncio
async def test_strips_ansi_codes(self, tmp_path):
"""ANSI escape codes are removed from output."""