diff --git a/gateway/run.py b/gateway/run.py index 1ab57984e0..9926920b81 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -3498,17 +3498,11 @@ class GatewayRunner: # /background must bypass the running-agent guard — it starts a # parallel task and must never interrupt the active conversation. + # /btw is an alias of /background and resolves to the same canonical + # name, so this branch handles both commands. if _cmd_def_inner and _cmd_def_inner.name == "background": return await self._handle_background_command(event) - # /btw must bypass the running-agent guard for the same reason - # as /background: it spawns a parallel ephemeral side-question - # task (see _handle_btw_command) that doesn't interrupt the - # active conversation and self-guards against concurrent /btw - # on the same chat. - if _cmd_def_inner and _cmd_def_inner.name == "btw": - return await self._handle_btw_command(event) - # Session-level toggles that are safe to run mid-agent — # /yolo can unblock a pending approval prompt, /verbose cycles # the tool-progress display mode for the ongoing stream. diff --git a/run_agent.py b/run_agent.py index 7b23b5b41c..43c367e460 100644 --- a/run_agent.py +++ b/run_agent.py @@ -892,7 +892,6 @@ class AIAgent: checkpoints_enabled: bool = False, checkpoint_max_snapshots: int = 50, pass_session_id: bool = False, - persist_session: bool = True, ): """ Initialize the AI Agent. @@ -964,7 +963,6 @@ class AIAgent: self.background_review_callback = None # Optional sync callback for gateway delivery self.skip_context_files = skip_context_files self.pass_session_id = pass_session_id - self.persist_session = persist_session self._credential_pool = credential_pool self.log_prefix_chars = log_prefix_chars self.log_prefix = f"{log_prefix} " if log_prefix else "" @@ -3353,10 +3351,7 @@ class AIAgent: """Save session state to both JSON log and SQLite on any exit path. Ensures conversations are never lost, even on errors or early returns. - Skipped when ``persist_session=False`` (ephemeral helper flows). """ - if not self.persist_session: - return self._apply_persist_user_message_override(messages) self._session_messages = messages self._save_session_log(messages) diff --git a/tests/gateway/test_running_agent_session_toggles.py b/tests/gateway/test_running_agent_session_toggles.py index d60e5b154e..6bf8be9973 100644 --- a/tests/gateway/test_running_agent_session_toggles.py +++ b/tests/gateway/test_running_agent_session_toggles.py @@ -169,23 +169,22 @@ async def test_reasoning_rejected_mid_run(): @pytest.mark.asyncio async def test_btw_dispatches_mid_run(): - """/btw mid-run must dispatch to its handler, not hit the catch-all. + """/btw mid-run must dispatch to /background's handler, not hit the catch-all. - /btw spawns a parallel ephemeral side-question task that does NOT - interrupt the active conversation (see _handle_btw_command). It's the - whole point of the command — asking a side question while the main - turn is still working. Before the mid-turn bypass was added, /btw - fell through to the "Agent is running — wait or /stop first" catch-all, - making it useless in exactly the scenario it was designed for. + /btw is an alias of /background (see hermes_cli/commands.py). Typing + /btw mid-turn must spawn a parallel background task — that's the whole + point of the command. Before the mid-turn bypass was added for + /background, /btw fell through to the "Agent is running — wait or + /stop first" catch-all, making it useless in exactly the scenario it + was designed for. The alias and the bypass together make it work. """ runner = _make_runner() - runner._handle_btw_command = AsyncMock( - return_value='💬 /btw: "what module owns titles?"\nReply will appear here shortly.' + runner._handle_background_command = AsyncMock( + return_value='🚀 Background task started: "what module owns titles?"' ) result = await runner._handle_message(_make_event("/btw what module owns titles?")) - runner._handle_btw_command.assert_awaited_once() + runner._handle_background_command.assert_awaited_once() assert result is not None - assert "💬 /btw" in result assert "can't run mid-turn" not in result