Add Telegram patch (second transport) - #1
Open
arlin17 wants to merge 1 commit into
Open
Conversation
Implements a Telegram transport adapter under src/patches/telegram/ behind the
existing Patch interface, with zero core changes beyond config wiring — the
transport-agnostic abstraction held.
Conversations map to private chats (DMs, allowlist-gated) and forum topics in one
configured supergroup (TELEGRAM_GROUP_ID, membership-gated like Discord's private
forum channel). conversation_id encodes the (chatId, threadId) pair the Bot API
needs to deliver: "<chatId>" for DM/General, "<chatId>:<threadId>" for a topic.
Transport specifics handled in the patch:
- grammY long polling (no public URL); history:false (Bot API has no history for bots)
- forum_topic_created/closed lifecycle (forum_topic_deleted doesn't exist in the API)
- permission Allow/Deny via inline keyboard; 64-byte callback_data limit worked around
with a minted token -> request_id map
- reactions normalized into Telegram's fixed emoji set (✅→👍, ❌→👎, …)
- attachments via getFile + file endpoint, with file_id -> {name,mime} stash
- native commands (no typed args) sanitized to [a-z0-9_]≤32, mapped back to core names
Wiring: TelegramConfig + telegram branch in loadConfig/patchbayd; grammy dep;
.env.example block. Docs: docs/telegram.md, decisions.md entry, principles.md index.
Tests mirror the Discord DM allowlist regression plus id round-trip, reaction, and
chunking units.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Adds Telegram as a second transport, implemented as a self-contained patch under
src/patches/telegram/behind the existingPatchinterface — with zero changes to the transport-agnostic core beyond config wiring. The abstraction held: nocore/logic changed.How it maps
Conversations are private chats (DMs) and forum topics in one configured supergroup:
TELEGRAM_GROUP_ID)conversation_id(<chatId>:<threadId>) → one agent sessionconversation_id(privatechatId) → one session, nameddm-<user>getFile→ download into the agent's.inbox/conversation_idencodes the(chatId, threadId)pair the Bot API needs to deliver —"<chatId>"for DM/General,"<chatId>:<threadId>"for a topic (chat ids may be negative but never contain:, so one split round-trips). The core still treats it as opaque.Access control mirrors Discord's forum-vs-DM split: topics gate on group membership (
chat.id == TELEGRAM_GROUP_ID), DMs gate onTELEGRAM_ALLOWLIST, and permission verdicts are always allowlist-gated by the core.Telegram realities handled (verified against the Bot API)
history: false— the Bot API has no history endpoint for bots, sofetchMessagesreturns[]and the core leans on its own message log. This is exactly the casediscord.mdanticipated for a history-less transport.forum_topic_deleteddoesn't exist — only created/closed/reopened are observable; a deleted topic just goes dormant and resumes on next message.callback_data64-byte cap — permission buttons carry a minted short token mapped back to the arbitrary-lengthrequest_id, not the id itself.setMessageReactionfixed emoji set — reactions are normalized (✅→👍,❌→👎,🤖/⏳→👀, stripsU+FE0F) and unreactable ones dropped rather than erroring./cmdis free text →$ARGUMENTS; names are sanitized to[a-z0-9_]≤32 and mapped back to the core's original name. An unregistered/foofalls through to the agent as text.bot.start()) — no public URL/webhook needed for a self-hosted daemon.Files
src/patches/telegram/{index,client,permissions,attachments}.tsTelegramConfig+telegrambranch incore/config.tsandbin/patchbayd.ts;grammydependency;.env.exampleblockdocs/telegram.md, adecisions.mdentry, and theprinciples.mdindex rowTests
src/patches/telegram/telegram.test.tsmirrors the Discord DM allowlist security regression, plus wrong-group rejection,conversation_idround-trip (incl. negative supergroup ids), reaction normalization, and text chunking.bun run typecheck— cleanbun test— 53 pass, 0 fail (44 baseline + 9 new)Not yet done
The live long-poll round-trip (real message → spawn → reply/buttons/attachments) needs a host with a real bot token; the one-time setup checklist is in
docs/telegram.md.🤖 Generated with Claude Code