You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Stops the gateway typing refresh before final response delivery starts.
GatewayRunner._run_agent() already calls adapter.stop_typing() after the agent returns, but BasePlatformAdapter._keep_typing() can still be alive until _process_message_background() reaches its later cleanup path. On Discord, a late _keep_typing() tick can re-enter send_typing() after that handler-level stop and just before _send_with_retry() delivers the final answer. Because Discord has no explicit "typing stop" endpoint, that last typing pulse can leave the client showing "bot is typing" after the final response has already appeared.
This patch stops the base typing refresh immediately after the message handler returns and before the final send/media delivery path begins. The existing finally-block cleanup is kept as a fallback.
Manual verification: reproduced in a Discord DM on current main after a long turn (time=199.0s api_calls=16), applied this patch, restarted the gateway, and confirmed the "Atropos is typing" indicator no longer lingers after the final response.
Notes
This is intentionally a small lifecycle-ordering fix. It does not remove or redesign Discord's adapter-level typing behavior; PR #43691 may still be a better long-term fix for orphaned Discord typing loops. This patch closes the remaining race where the base refresh loop can issue a final typing pulse after the agent has returned but before final response delivery begins.
Competing fix for the typing-indicator race. The most comprehensive open PR in this cluster is #29172 (covers the stream consumer + all delivery paths via per-chat stop events); this PR instead stops the base typing refresh at the _message_handler return boundary. Other approaches in the cluster: #25210, #43390 (both closed). Flagging for a maintainer to pick the canonical mechanism — not marking either as a duplicate.
Thanks for isolating the pre-delivery lifecycle boundary. The premise remains valid on the inspected current main: gateway/platforms/base.py:4882 returns from the handler and final text can begin at lines 5029-5034, while refresh shutdown is currently deferred to cleanup at line 5259.
Problems
The surrounding lifecycle has been refactored since this PR’s diff. Current main’s local _stop_typing_task() delegates to the atomic _stop_typing_refresh() helper (gateway/platforms/base.py:4872-4876; helper at lines 3887-3917), so the insertion needs a small transplant at the current handler-return boundary rather than a blind application of the old hunk.
Suggested changes
Preserve the proposed ordering immediately after response = await self._message_handler(event) at gateway/platforms/base.py:4882, before response processing and all final delivery paths.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Stops the gateway typing refresh before final response delivery starts.
GatewayRunner._run_agent()already callsadapter.stop_typing()after the agent returns, butBasePlatformAdapter._keep_typing()can still be alive until_process_message_background()reaches its later cleanup path. On Discord, a late_keep_typing()tick can re-entersend_typing()after that handler-level stop and just before_send_with_retry()delivers the final answer. Because Discord has no explicit "typing stop" endpoint, that last typing pulse can leave the client showing "bot is typing" after the final response has already appeared.This patch stops the base typing refresh immediately after the message handler returns and before the final send/media delivery path begins. The existing finally-block cleanup is kept as a fallback.
Related issues / PRs
main.main.Changes made
gateway/platforms/base.py_stop_typing_task()immediately after_message_handler(event)returns and before final response delivery.tests/gateway/test_typing_stop_before_delivery.pystop_typing()has fired.Verification
Run on macOS from this checkout:
Manual verification: reproduced in a Discord DM on current
mainafter a long turn (time=199.0s api_calls=16), applied this patch, restarted the gateway, and confirmed the "Atropos is typing" indicator no longer lingers after the final response.Notes
This is intentionally a small lifecycle-ordering fix. It does not remove or redesign Discord's adapter-level typing behavior; PR #43691 may still be a better long-term fix for orphaned Discord typing loops. This patch closes the remaining race where the base refresh loop can issue a final typing pulse after the agent has returned but before final response delivery begins.