[OMEGA-318 & OMEGA-319] Telegram's multi chat and multi-user issue fixed - #327
[OMEGA-318 & OMEGA-319] Telegram's multi chat and multi-user issue fixed#327blackhammer116 wants to merge 13 commits into
Conversation
Fix Telegram multi-chat routing and per-group authorization
|
Tested: ✅ Group access works, and the DM secret leak is closedThe owner bootstrap,
Worth calling out separately: on ❌ Replies are delivered to whichever chat spoke lastThis is the blocker. I asked a question in the owner's DM and sent an unrelated line to the group three seconds later: The answer arrived in the group. The DM got nothing. Shell output requested privately was published to every member of the room. Reproduced 5 times out of 5, at delays of 0, 2, 3, 5, 8 and 10 seconds.
telegram._enqueue_message("dm: what is my secret note?", "dm_owner")
telegram.getLastMessage()
telegram._enqueue_message("group: unrelated chatter", "group_public")
telegram.getLastMessage()
telegram.send_message("your secret note is: buy milk")
# AssertionError: assert ['group_public'] == ['dm_owner']Carrying the originating chat with the message through to the send would fix it. ❌ The agent can no longer speak firstEverything the agent says before someone talks to it is dropped. In one run it executed
❌ Telegram is the only channel left without delivery retryDropping ❌ A damaged group file silences the bot permanently and eats the messagesAppending garbage to Group messages stop being processed, the DM path keeps working, and the user is told nothing. The file is now read from disk on every inbound message, so this window stays open for the life of the process. ❌ The same question from two chats is answered onceSend identical text from the DM and from the group and only the first is processed. The second never reaches the model: no ❌ Operational gaps
Verdict: ❌ FAIL |
…t bleeding effect.
- serialize inbound Telegram chats to prevent reply misrouting - retain destination-aware outbound messages for retry - use TG_CHAT_ID for proactive messages - add owner-only /unbind support - validate and cache persisted authorization before polling - advance update offsets only after successful processing - tolerate Telegram getMe failures - document Telegram binding, routing, and retry behavior
|
Retested on ✅ Most of the first round is closed
Group access itself still behaves correctly: silent before ❌ Any message the model does not answer freezes the whole channel
The cheapest way to trigger it is to say
A message repeated from another chat hits the same wall, which is the case The test does not catch this because it calls telegram._enqueue_message("someone: hi from the dead group", "dead_group")
telegram.getLastMessage()
telegram.send_message("reply into the dead group") # 403, retried forever
telegram._enqueue_message("owner: are you alive?", "dm_owner")
telegram.getLastMessage() # returns "" — DM is blocked too
# AssertionError: assert '' == 'owner: are you alive?'Releasing the slot on a failure the model cannot recover from, or timing it out, would keep one bad chat from taking the rest down. ❌ The agent still cannot say anything on its ownThe version banner is dropped on a cold start and on all three restarts I did, with both chats already authorized and loaded from disk:
I understand On Behaviour change worth a deliberate decision
Verdict: ❌ FAIL |
…uting descriptions
…ppend to reduce write failures.
Description
This PR removes Telegram’s single-chat limitation and adds safe support for using one OmegaClaw instance from an authenticated owner’s DM and one or more authorized groups.
Responses are routed back to the chat that produced the corresponding message. Group access is authorized by the persisted Telegram owner without exposing the reusable authentication secret in the group.
Problem
The Telegram adapter previously stored one global
chat_idand one authenticateduser_id.This caused two problems:
Authentication model
When authentication is enabled:
auth <secret>in a private DM.user_idis persisted./bindin a group.chat_idis persisted as authorized.The authentication secret is accepted only in a private chat. It is never required or validated inside a group.
A persisted owner always takes precedence over the reusable secret, preventing another user from replacing the owner after a restart.
Telegram command compatibility
The group authorization command supports:
/bind/bind@BotName/authorize_group/authorize_group@BotNameAddressed commands are accepted only when the username suffix matches the current bot’s username, obtained through Telegram’s
getMeAPI.Commands addressed to another bot are ignored.
Multi-chat routing
Inbound messages are queued with their originating Telegram
chat_id.When the agent processes a message, outbound responses are sent back to that originating chat. This allows an owner DM and authorized groups to operate through the same OmegaClaw process without replies being sent to the wrong destination.
All authorized Telegram chats continue to share the same OmegaClaw agent state and conversation history.
Chat allowlists
Existing
TG_CHAT_IDbehavior is preserved, and this PR adds:Closes #294
How Has This Been Tested?
Checklist