From 0d02f0d1dc9d22400a58fc5a169185cbace680cb Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Sat, 29 Aug 2026 19:51:42 +0530 Subject: [PATCH] fix: re-derive the live busy text mode after a non-profile /busy change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review finding (quality pass): on a single-profile gateway, _handle_busy_command set _busy_input_mode but left _busy_text_mode stale, so the adapter refresh a line later re-read the old value — /busy queue persisted to config but live text messages kept interrupting until restart. The profile path already re-derives both from the fresh config; the non-profile path now does the same via _load_busy_text_mode() (busy_input_mode is the source of truth, run.py:9877). Regression assertion added to test_set_mode_persists; verified red without the production fix. --- gateway/slash_commands.py | 6 ++++++ tests/gateway/test_busy_command.py | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/gateway/slash_commands.py b/gateway/slash_commands.py index f1cdaea2ca..12548e5ac0 100644 --- a/gateway/slash_commands.py +++ b/gateway/slash_commands.py @@ -4287,6 +4287,12 @@ class GatewaySlashCommandsMixin: ) else: self._busy_input_mode = arg + # busy_input_mode is the source of truth for the text mode + # too (run.py:_load_busy_text_mode) — re-derive it so the + # adapter refresh below doesn't read a stale value and keep + # interrupting after e.g. /busy queue (config IS saved; only + # the live session lagged until restart). + self._busy_text_mode = self._load_busy_text_mode() adapter = self._adapter_for_source(event.source) if adapter is not None: diff --git a/tests/gateway/test_busy_command.py b/tests/gateway/test_busy_command.py index 7236541dcc..dfeb806de2 100644 --- a/tests/gateway/test_busy_command.py +++ b/tests/gateway/test_busy_command.py @@ -68,11 +68,26 @@ class TestBusyCommandPersistence: async def test_set_mode_persists(self, monkeypatch, initial_mode, new_mode): """Each supported /busy mode is saved and applied.""" runner = _make_runner(busy_mode=initial_mode) + runner._busy_text_mode = "interrupt" monkeypatch.setattr("cli.save_config_value", lambda k, v: True) + # The handler re-derives _busy_text_mode from the saved config; + # emulate the write that the mocked save_config_value skipped. + monkeypatch.setattr( + gateway_run, + "_load_gateway_runtime_config", + lambda: {"display": {"busy_input_mode": new_mode}}, + ) + monkeypatch.delenv("HERMES_GATEWAY_BUSY_TEXT_MODE", raising=False) + monkeypatch.delenv("HERMES_GATEWAY_BUSY_INPUT_MODE", raising=False) event = _make_event(f"/busy {new_mode}") result = await runner._handle_busy_command(event) assert new_mode in str(result).lower() assert runner._busy_input_mode == new_mode + # busy_input_mode is the source of truth for the text mode: /busy + # queue must stop live text messages from interrupting (#97932). + assert runner._busy_text_mode == ( + "queue" if new_mode == "queue" else "interrupt" + ) @pytest.mark.asyncio async def test_save_failure_preserves_mode(self, monkeypatch):