diff --git a/tests/cli/test_cli_resume_command.py b/tests/cli/test_cli_resume_command.py index 2790ce5be69..6368d973c88 100644 --- a/tests/cli/test_cli_resume_command.py +++ b/tests/cli/test_cli_resume_command.py @@ -75,3 +75,44 @@ class TestCliResumeCommand: assert "out of range" in printed.lower() assert "/resume" in printed assert cli_obj.session_id == "current_session" + + def test_handle_resume_strips_outer_brackets(self): + """Users copy `` from the usage hint literally. + + Strip outer ``<>``, ``[]``, ``""``, and ``''`` before lookup so + ``/resume `` works the same as ``/resume abc123``. + """ + cli_obj = _make_cli() + cli_obj._session_db.get_session.return_value = {"id": "sess_alpha", "title": "Alpha"} + cli_obj._session_db.get_messages_as_conversation.return_value = [] + cli_obj._session_db.resolve_resume_session_id.return_value = "sess_alpha" + + for raw in ("", "[sess_alpha]", '"sess_alpha"', "'sess_alpha'"): + cli_obj.session_id = "current_session" + with ( + patch("hermes_cli.main._resolve_session_by_name_or_id", return_value="sess_alpha"), + patch("cli._cprint"), + ): + cli_obj._handle_resume_command(f"/resume {raw}") + assert cli_obj.session_id == "sess_alpha", ( + f"bracket-stripping failed for {raw!r}: session_id stayed {cli_obj.session_id}" + ) + + def test_handle_resume_does_not_strip_partial_brackets(self): + """Mismatched or single brackets must pass through unmodified. + + ``"` from the usage hint literally. + + The gateway should strip outer ``<>``, ``[]``, ``""``, and ``''`` + before lookup so ``/resume `` works the same as + ``/resume abc123``. + """ + from hermes_state import SessionDB + db = SessionDB(db_path=tmp_path / "state.db") + db.create_session("abc123", "telegram") + db.set_session_title("abc123", "Bracketed") + db.create_session("current_session_001", "telegram") + + for raw in ("", "[abc123]", '"abc123"', "'abc123'"): + event = _make_event(text=f"/resume {raw}") + runner = _make_runner( + session_db=db, + current_session_id="current_session_001", + event=event, + ) + result = await runner._handle_resume_command(event) + # Either the session was resumed (and we get a "Resumed" / "Already on" reply) + # or it was found-then-redirected. Failure mode = "No session found matching ''". + assert "abc123" not in str(result) or "not found" not in str(result).lower(), ( + f"bracket stripping failed for {raw!r}: gateway returned {result!r}" + ) + db.close() + + @pytest.mark.asyncio + async def test_resume_resolves_by_session_id(self, tmp_path): + """The gateway should accept a bare session ID, not just a title. + + Before this fix, /resume in the gateway only called + ``resolve_session_by_title``, so ``/resume `` always + returned "Session not found" even for valid IDs. + """ + from hermes_state import SessionDB + db = SessionDB(db_path=tmp_path / "state.db") + db.create_session("unnamed_session_xyz", "telegram") + # Deliberately no title set — this session can ONLY be resolved by ID. + db.create_session("current_session_001", "telegram") + + event = _make_event(text="/resume unnamed_session_xyz") + runner = _make_runner( + session_db=db, + current_session_id="current_session_001", + event=event, + ) + result = await runner._handle_resume_command(event) + + # Should NOT be the not-found error. + assert "not found" not in str(result).lower(), ( + f"session-id lookup failed: {result!r}" + ) + db.close()