Skip to content

fix: Telegram show typing#640

Merged
xieyxclack merged 1 commit intoagentscope-ai:mainfrom
Leirunlin:fix/telegram-typing-indicator
Mar 4, 2026
Merged

fix: Telegram show typing#640
xieyxclack merged 1 commit intoagentscope-ai:mainfrom
Leirunlin:fix/telegram-typing-indicator

Conversation

@Leirunlin
Copy link
Copy Markdown
Collaborator

@Leirunlin Leirunlin commented Mar 4, 2026

Description

Typing was fired once right before send(), making it invisible to users.
Now starts a 4s typing loop on message receipt and cancels it on reply.

Related Issue: Fixes #387

Security Considerations: [If applicable, e.g. channel auth, env/config handling]

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Refactoring

Component(s) Affected

  • Core / Backend (app, agents, config, providers, utils, local_models)
  • Console (frontend web UI)
  • Channels (DingTalk, Feishu, QQ, Discord, iMessage, etc.)
  • Skills
  • CLI
  • Documentation (website)
  • Tests
  • CI/CD
  • Scripts / Deploy

Checklist

  • I ran pre-commit run --all-files locally and it passes
  • If pre-commit auto-fixed files, I committed those changes and reran checks
  • I ran tests locally (pytest or as relevant) and they pass
  • Documentation updated (if needed)
  • Ready for review

Testing

  • Send message to bot, verify "typing..." appears immediately
  • Verify typing persists during long agent processing (>5s)
  • Verify typing disappears when reply arrives
  • Verify show_typing=False disables the indicator

Additional Notes

[Optional: any other context]

Summary by CodeRabbit

Release Notes

  • New Features
    • Telegram: Added automatic typing indicator that displays while the bot is actively processing messages and preparing responses
    • The typing status automatically activates upon message receipt and deactivates before sending, providing users with real-time visibility into bot activity and improving the conversational experience

  Typing was fired once right before send(), making it invisible to users.
  Now starts a 4s typing loop on message receipt and cancels it on reply.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 4, 2026

📝 Walkthrough

Walkthrough

The changes implement per-chat typing indicator management in the Telegram channel. A new _typing_tasks dictionary tracks active typing tasks by chat ID. Three internal methods handle the typing lifecycle: _start_typing initiates a background task, _typing_loop sends periodic typing actions every 4 seconds, and _stop_typing cancels active tasks. Typing is triggered on message enqueue and cancelled before sending content, with cleanup on channel stop.

Changes

Cohort / File(s) Summary
Telegram Typing Indicator
src/copaw/app/channels/telegram/channel.py
Introduces per-chat typing indicator mechanism with _typing_tasks dictionary tracking, _start_typing(), _stop_typing(), and _typing_loop() methods. Integrates typing lifecycle with message handling—typing starts on enqueue, stops before sending content, and tasks are cleaned up on channel stop.

Sequence Diagram

sequenceDiagram
    participant User
    participant TelegramChannel
    participant AsyncTask as Asyncio Task Loop
    participant TelegramAPI

    User->>TelegramChannel: Message arrives (enqueue)
    TelegramChannel->>TelegramChannel: _start_typing(chat_id)
    TelegramChannel->>AsyncTask: Create background _typing_loop task
    
    loop Every 4 seconds
        AsyncTask->>TelegramAPI: _send_chat_action("typing")
        TelegramAPI-->>AsyncTask: ✓ Typing indicator sent
    end
    
    TelegramChannel->>TelegramChannel: Message processing complete
    TelegramChannel->>TelegramChannel: _stop_typing(chat_id)
    TelegramChannel->>AsyncTask: task.cancel()
    AsyncTask-->>TelegramChannel: Task terminated
    
    TelegramChannel->>TelegramAPI: send (text/media)
    TelegramAPI-->>User: Message delivered
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Suggested reviewers

  • zhijianma
  • xieyxclack

Poem

🐰 hop hop While humans type so slow and steady,
I show the typing dance, always ready!
Four seconds loop, a background delight,
Cleanup at the end—no tasks left in flight! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses only the Telegram typing indicator bug (issue #387 scope), but #387 requests adding both Telegram AND Matrix integrations. The Matrix integration is not included in this PR. Either implement Matrix channel integration to fully satisfy #387, or clarify if this PR is a partial fix with a separate Matrix PR planned.
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: Telegram show typing' directly describes the main change - fixing the Telegram typing indicator behavior by implementing a persistent typing loop.
Out of Scope Changes check ✅ Passed All changes are scoped to the Telegram typing indicator fix; no unrelated modifications to other components or integrations were detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a bug in the Telegram channel where the typing indicator was not effectively displayed to users. It introduces a robust mechanism to show a persistent 'typing...' status from the moment a message is received until the bot sends its reply. This enhancement significantly improves the user experience by providing real-time feedback and indicating that the bot is actively processing their request, making interactions feel more natural and responsive.

Highlights

  • Persistent Telegram Typing Indicator: Implemented a continuous typing indicator for Telegram that activates upon message receipt and persists until a response is sent, addressing the issue of the indicator being too brief to be noticed.
  • Asynchronous Task Management: Introduced _typing_tasks to manage multiple concurrent typing indicator loops for different chats, ensuring proper lifecycle management of these asynchronous operations.
  • Typing Indicator Control: Added dedicated methods (_start_typing, _stop_typing, _typing_loop) to control the initiation, termination, and continuous sending of the 'typing' action.
  • Cleanup on Channel Stop: Ensured all active typing tasks are properly cancelled and cleaned up when the Telegram channel is stopped.
Changelog
  • src/copaw/app/channels/telegram/channel.py
    • Added a dictionary _typing_tasks to the class constructor to store and manage active typing indicator tasks for each chat.
    • Modified handle_message to call _start_typing when a message is enqueued, initiating the typing indicator.
    • Introduced _start_typing method to create and manage an asyncio.Task for the typing loop.
    • Added _stop_typing method to cancel and remove the typing task for a specific chat.
    • Implemented _typing_loop as an asynchronous coroutine that repeatedly sends the 'typing' action every 4 seconds until cancelled.
    • Updated the send method to call _stop_typing before sending a text response, ensuring the indicator disappears.
    • Modified the send_media method to call _stop_typing before sending media, stopping the indicator.
    • Enhanced the stop method to iterate through and cancel all active typing tasks, ensuring proper cleanup when the channel is shut down.
Activity
  • The author identified and addressed a bug where the Telegram typing indicator was not visible to users.
  • Extensive testing was performed to verify the new typing indicator's behavior, including its immediate appearance, persistence during long processing, disappearance upon reply, and correct disabling when configured.
  • Pre-commit hooks were run successfully, and local tests passed.
  • The pull request is marked as ready for review.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/copaw/app/channels/telegram/channel.py (1)

452-459: Consider adding a maximum typing duration as a safeguard.

If message processing fails or hangs before send() is reached, the typing loop continues indefinitely until a new message arrives or the channel stops. Adding a timeout (e.g., 60-120s) could prevent phantom typing indicators in edge cases.

💡 Optional: Add max duration timeout
 async def _typing_loop(self, chat_id: str) -> None:
-    """Repeatedly send 'typing' action every 4s until cancelled."""
+    """Repeatedly send 'typing' action every 4s until cancelled or timeout."""
+    max_duration = 120  # seconds
+    elapsed = 0
     try:
-        while self._application:
+        while self._application and elapsed < max_duration:
             await self._send_chat_action(chat_id, "typing")
             await asyncio.sleep(4)
+            elapsed += 4
     except asyncio.CancelledError:
         pass
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/copaw/app/channels/telegram/channel.py` around lines 452 - 459, The
_typing_loop currently can run indefinitely if message handling stalls; modify
async def _typing_loop(self, chat_id: str) to enforce a maximum typing duration
(e.g., 60–120 seconds) by recording start time and breaking the loop when
elapsed exceeds a configurable max_typing_seconds (or default to 60); keep
sending typing via _send_chat_action and sleeping as before but exit the loop
(or cancel) when the timeout is reached to avoid phantom typing indicators, and
ensure any existing asyncio.CancelledError handling remains intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/copaw/app/channels/telegram/channel.py`:
- Around line 452-459: The _typing_loop currently can run indefinitely if
message handling stalls; modify async def _typing_loop(self, chat_id: str) to
enforce a maximum typing duration (e.g., 60–120 seconds) by recording start time
and breaking the loop when elapsed exceeds a configurable max_typing_seconds (or
default to 60); keep sending typing via _send_chat_action and sleeping as before
but exit the loop (or cancel) when the timeout is reached to avoid phantom
typing indicators, and ensure any existing asyncio.CancelledError handling
remains intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5d69d108-98bc-4be3-aea6-b3ff5fa0858f

📥 Commits

Reviewing files that changed from the base of the PR and between cd2fea8 and 90d27d4.

📒 Files selected for processing (1)
  • src/copaw/app/channels/telegram/channel.py

@xieyxclack xieyxclack merged commit cf2ec66 into agentscope-ai:main Mar 4, 2026
5 checks passed
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request aims to fix an issue where the Telegram typing indicator was not visible, by implementing a typing loop that starts upon message receipt and cancels upon reply. However, this introduces potential resource exhaustion and resource leak vulnerabilities. Specifically, the typing loop lacks a timeout, which could lead to a Denial of Service if the agent hangs, and a race condition in the stop() method might lead to leaked typing tasks during shutdown. A key issue identified is that the typing indicator could run indefinitely if the bot fails to generate a response, leading to a poor user experience and potential resource issues.

Comment on lines +452 to +459
async def _typing_loop(self, chat_id: str) -> None:
"""Repeatedly send 'typing' action every 4s until cancelled."""
try:
while self._application:
await self._send_chat_action(chat_id, "typing")
await asyncio.sleep(4)
except asyncio.CancelledError:
pass
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The _typing_loop currently runs indefinitely, sending a 'typing' action every 4 seconds. This presents a resource exhaustion vulnerability: if the agent hangs or fails to respond, the typing indicator will continue indefinitely, potentially leading to resource exhaustion and rate-limiting by Telegram. This also negatively impacts user experience, as the bot would appear stuck. A timeout mechanism is crucial to prevent this.

    async def _typing_loop(self, chat_id: str) -> None:
        """Repeatedly send 'typing' action every 4s for a limited time."""
        try:
            # Loop for a limited time (e.g., 7 iterations * 4s = 28s) to avoid
            # showing the typing indicator indefinitely if no reply is sent.
            for _ in range(7):
                if not self._application:
                    break
                await self._send_chat_action(chat_id, "typing")
                await asyncio.sleep(4)
        except asyncio.CancelledError:
            # This is the expected way to stop the loop when a reply is sent.
            pass

Comment on lines +627 to +628
for cid in list(self._typing_tasks):
self._stop_typing(cid)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The stop() method cancels all current typing tasks at the beginning of the shutdown process. However, the polling task is not cancelled until line 630, and the application is not stopped until line 640. There is a race condition where a new message can arrive and trigger _start_typing() after the initial cancellation loop but before the polling task is fully stopped. This results in new typing tasks being created that are never cancelled, leading to a resource leak.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Telegram and Matrix channels

2 participants