chatbot1-9 Exercise 2: Which Group Messages Does the Bot Answer? ================================================================== ex2.py (save in the project root): import asyncio from bot.channels.telegram import TelegramAdapter from bot.core import Bot from bot.providers import FakeProvider class FakeAPI: def __init__(self): self.sent = [] async def send_message(self, chat_id, text, reply_to=None): self.sent.append((chat_id, text, reply_to)) async def send_chat_action(self, chat_id, action="typing"): pass def group(text, uid=7, update_id=1, reply_to_bot=False, chat_type="supergroup"): msg = {"message_id": update_id, "from": {"id": uid, "is_bot": False}, "chat": {"id": -100, "type": chat_type}, "date": 1, "text": text} if reply_to_bot: msg["reply_to_message"] = {"message_id": 1, "from": {"id": 999, "is_bot": True}, "chat": msg["chat"], "date": 1, "text": "x"} return {"update_id": update_id, "message": msg} CASES = [ ("plain chat between members", group("did anyone read the new novel?")), ("mentions the bot", group("@LibraryBot when do you open?")), ("mentions it in the middle, other case", group("hey @librarybot, any news?")), ("a command without the bot's name", group("/facts")), ("a command with the bot's name", group("/facts@LibraryBot")), ("a reply to one of the bot's messages", group("thanks!", reply_to_bot=True)), ("addresses a DIFFERENT bot", group("@OtherBot when do you open?")), ("message from another bot that mentions us", {**group("@LibraryBot hello"), "message": {**group("@LibraryBot hello")["message"], "from": {"id": 5, "is_bot": True}}}), ] async def main(): print(f"{'group message':<44} {'answered?':<10} text sent to the model") for n, (label, update) in enumerate(CASES, start=1): api = FakeAPI() bot = Bot(FakeProvider(["(model reply)"])) adapter = TelegramAdapter(bot, api, username="LibraryBot", bot_id=999) update["update_id"] = n await adapter.handle_update(update) sent = bot.provider.calls[0][-1]["content"] if bot.provider.calls else "-" answered = bool(api.sent) print(f"{label:<44} {'yes' if answered else 'no':<10} {sent if bot.provider.calls else ('(a command, no model call)' if answered else '')}") asyncio.run(main()) Run with: py ex2.py Output: group message answered? text sent to the model plain chat between members no mentions the bot yes when do you open? mentions it in the middle, other case yes hey , any news? a command without the bot's name no a command with the bot's name yes (a command, no model call) a reply to one of the bot's messages yes thanks! addresses a DIFFERENT bot no message from another bot that mentions us no The rule I would reconsider: ignoring a bare command such as /facts. In a group with only this bot, people will type /facts and expect an answer, and the bot's silence looks like a fault. Telegram's own behaviour is that general commands go to all bots in the group (and to privacy-mode bots only in limited cases), and the update does not say which bot the person meant. The risk of accepting bare commands is that two bots in the same group both answer, or that this bot reacts to a command meant for another. A reasonable compromise: accept bare commands when the group has a single bot, which needs a setting (or a member-count check) that I did not build. WHY THIS WORKS AS AN ANSWER --------------------------- Each case is a fresh bot and adapter fed one hand-written group update. Only messages that mention the bot, use /command@BotName or reply to one of the bot's messages are answered, matching case-insensitively. The mention is removed before the text reaches the model (the middle-of-sentence case leaves "hey , any news?", untidy but harmless). A command is answered by the bot's own command handler without a model call. A mention of a different bot and a message from another bot are ignored, which also avoids two bots endlessly answering each other.