mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-30 06:41:51 +00:00
fix(telegram): resume typing indicator after inline approval click (#27853)
The text /approve and /deny paths in gateway/run.py call resume_typing_for_chat() after resolve_gateway_approval() succeeds, but the Telegram inline-button (ea:*) callback in _handle_callback_query did not. Typing is paused when the approval is sent (gateway/run.py:15658), so without a matching resume the typing indicator stayed gone for the remainder of a long-running turn after a button click. Symmetry-match the text path: after a successful resolve, call self.resume_typing_for_chat(str(query_chat_id)). Guarded by count > 0 to match /approve's "if not count" early-return — if nothing was actually resolved, the agent thread was never unblocked, so typing should remain paused. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9a444a9355
commit
ba2572e54c
2 changed files with 70 additions and 0 deletions
|
|
@ -2814,6 +2814,15 @@ class TelegramAdapter(BasePlatformAdapter):
|
|||
)
|
||||
except Exception as exc:
|
||||
logger.error("Failed to resolve gateway approval from Telegram button: %s", exc)
|
||||
count = 0
|
||||
|
||||
# Resume the typing indicator — paused when the approval was
|
||||
# sent (gateway/run.py). The text /approve and /deny paths
|
||||
# call resume_typing_for_chat here too; without it, typing
|
||||
# stays paused for the rest of the turn after an inline
|
||||
# button click.
|
||||
if count and query_chat_id is not None:
|
||||
self.resume_typing_for_chat(str(query_chat_id))
|
||||
return
|
||||
|
||||
# --- Slash-confirm callbacks (sc:choice:confirm_id) ---
|
||||
|
|
|
|||
|
|
@ -271,6 +271,67 @@ class TestTelegramApprovalCallback:
|
|||
# State should be cleaned up
|
||||
assert 1 not in adapter._approval_state
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_resume_typing_after_inline_approval(self):
|
||||
"""Clicking an inline approval button must un-pause the chat's typing.
|
||||
|
||||
Regression for #27853: the text /approve path resumed typing, but the
|
||||
ea: callback path did not, so the typing indicator stayed gone for the
|
||||
rest of a long-running turn after a button click.
|
||||
"""
|
||||
adapter = _make_adapter()
|
||||
adapter._approval_state[5] = "agent:main:telegram:group:12345:99"
|
||||
adapter.pause_typing_for_chat("12345")
|
||||
assert "12345" in adapter._typing_paused
|
||||
|
||||
query = AsyncMock()
|
||||
query.data = "ea:once:5"
|
||||
query.message = MagicMock()
|
||||
query.message.chat_id = 12345
|
||||
query.from_user = MagicMock()
|
||||
query.from_user.first_name = "Norbert"
|
||||
query.from_user.id = "12345"
|
||||
query.answer = AsyncMock()
|
||||
query.edit_message_text = AsyncMock()
|
||||
|
||||
update = MagicMock()
|
||||
update.callback_query = query
|
||||
context = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {"TELEGRAM_ALLOWED_USERS": "*"}, clear=False):
|
||||
with patch("tools.approval.resolve_gateway_approval", return_value=1):
|
||||
await adapter._handle_callback_query(update, context)
|
||||
|
||||
assert "12345" not in adapter._typing_paused
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_typing_stays_paused_when_resolve_returns_zero(self):
|
||||
"""If resolve_gateway_approval reports 0 resolves, the agent thread
|
||||
was never unblocked, so typing should NOT be force-resumed."""
|
||||
adapter = _make_adapter()
|
||||
adapter._approval_state[6] = "agent:main:telegram:group:12345:99"
|
||||
adapter.pause_typing_for_chat("12345")
|
||||
|
||||
query = AsyncMock()
|
||||
query.data = "ea:once:6"
|
||||
query.message = MagicMock()
|
||||
query.message.chat_id = 12345
|
||||
query.from_user = MagicMock()
|
||||
query.from_user.first_name = "Norbert"
|
||||
query.from_user.id = "12345"
|
||||
query.answer = AsyncMock()
|
||||
query.edit_message_text = AsyncMock()
|
||||
|
||||
update = MagicMock()
|
||||
update.callback_query = query
|
||||
context = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {"TELEGRAM_ALLOWED_USERS": "*"}, clear=False):
|
||||
with patch("tools.approval.resolve_gateway_approval", return_value=0):
|
||||
await adapter._handle_callback_query(update, context)
|
||||
|
||||
assert "12345" in adapter._typing_paused
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_approval_callback_escapes_dynamic_user_name(self):
|
||||
adapter = _make_adapter()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue