From 7df6115199278f415bd3d3dacf439e467341245c Mon Sep 17 00:00:00 2001 From: Guillaume Meyer Date: Wed, 6 May 2026 15:55:01 +0000 Subject: [PATCH] feat(gateway): also gate pre-restart "Gateway restarting" notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the gateway_restart_notification flag to cover _notify_active_sessions_of_shutdown — the message that fires just before drain ("⚠️ Gateway restarting — Your current task will be interrupted. Send any message after restart and I'll try to resume where you left off.") sent to active sessions and home channels. Same operator/end-user reasoning: on a Slack workspace shared with end users, "Gateway restarting" reads as "the bot is broken" — the operator should be able to suppress it consistently with the other two lifecycle pings rather than having a partial opt-out. Co-Authored-By: Claude Opus 4.7 (1M context) --- gateway/run.py | 16 ++++++++++++++ tests/gateway/test_restart_drain.py | 34 +++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/gateway/run.py b/gateway/run.py index 77f20178d1..15ce3ab08c 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -2458,6 +2458,14 @@ class GatewayRunner: if not adapter: continue + platform_cfg = self.config.platforms.get(platform) + if platform_cfg is not None and not platform_cfg.gateway_restart_notification: + logger.info( + "Shutdown notification suppressed for active session: %s has gateway_restart_notification=false", + platform_str, + ) + continue + # Include thread_id if present so the message lands in the # correct forum topic / thread. metadata = {"thread_id": thread_id} if thread_id else None @@ -2488,6 +2496,14 @@ class GatewayRunner: if not home or not home.chat_id: continue + platform_cfg = self.config.platforms.get(platform) + if platform_cfg is not None and not platform_cfg.gateway_restart_notification: + logger.info( + "Shutdown notification suppressed for home channel: %s has gateway_restart_notification=false", + platform.value, + ) + continue + dedup_key = (platform.value, str(home.chat_id), str(home.thread_id) if home.thread_id else None) if dedup_key in notified: continue diff --git a/tests/gateway/test_restart_drain.py b/tests/gateway/test_restart_drain.py index 3aca6d6405..55de5a4554 100644 --- a/tests/gateway/test_restart_drain.py +++ b/tests/gateway/test_restart_drain.py @@ -257,6 +257,40 @@ async def test_shutdown_notification_send_failure_does_not_block(): await runner._notify_active_sessions_of_shutdown() +@pytest.mark.asyncio +async def test_shutdown_notification_suppressed_when_flag_disabled(): + """Active-session ping is muted when gateway_restart_notification=False on the platform.""" + from gateway.config import Platform + + runner, adapter = make_restart_runner() + runner._restart_requested = True + runner.config.platforms[Platform.TELEGRAM].gateway_restart_notification = False + session_key = "agent:main:telegram:dm:999" + runner._running_agents[session_key] = MagicMock() + + await runner._notify_active_sessions_of_shutdown() + + assert adapter.sent == [] + + +@pytest.mark.asyncio +async def test_shutdown_notification_home_channel_suppressed_when_flag_disabled(): + """Home-channel ping during shutdown is muted when the flag is False.""" + from gateway.config import HomeChannel, Platform + + runner, adapter = make_restart_runner() + runner.config.platforms[Platform.TELEGRAM].home_channel = HomeChannel( + platform=Platform.TELEGRAM, + chat_id="home-42", + name="Ops Home", + ) + runner.config.platforms[Platform.TELEGRAM].gateway_restart_notification = False + + await runner._notify_active_sessions_of_shutdown() + + assert adapter.sent == [] + + @pytest.mark.asyncio async def test_shutdown_notification_uses_persisted_origin_for_colon_ids(): """Shutdown notifications should route from persisted origin, not reparsed keys."""