Guides
Telegram Adapter
Production-quality Telegram adapter using ORO Bridge SDK — the reference implementation.
Telegram Adapter
The oro-tg-adapter is the reference implementation of a platform adapter. It connects a Telegram supergroup with forum topics to ORO Claude Bridge.
Architecture
Telegram Supergroup (forum topics)
↕ Bot API
┌──────────────────────────────┐
│ oro-tg-adapter │
│ ┌────────────────────────┐ │
│ │ TelegramPlatformAdapter│ │ ← PlatformAdapter impl
│ │ TelegramFormatter │ │ ← Formatter impl
│ └────────────┬───────────┘ │
│ │ │
│ ┌────────────┴───────────┐ │
│ │ bridge-adapter-sdk │ │ ← Runtime, Store, Orchestrators
│ └────────────────────────┘ │
└──────────────────────────────┘
↕ Socket.IO + REST
ORO Claude Bridge
Key Mapping
| Bridge Concept | Telegram Concept |
|---|---|
| Session | Forum Topic |
| Session Title | Topic Name |
| Message | Topic Message |
| Attachment | Document/Photo |
| Session Delete | Topic Close |
Project Structure
oro-tg-adapter/
├── src/
│ ├── index.ts # Entry point + runtime setup
│ ├── config.ts # Environment variable loading
│ └── telegram/
│ ├── platform.ts # TelegramPlatformAdapter
│ ├── formatter.ts # TelegramFormatter (SemanticBlock → HTML)
│ └── markdown.ts # Markdown → Telegram HTML converter
├── package.json
└── tsconfig.json
Just 5 files. Everything else (bridge transport, store, reconciliation, replay, streaming, dedup) is handled by the SDK.
Environment Variables
TELEGRAM_BOT_TOKEN=123456:ABC-DEF # Bot token from @BotFather
TELEGRAM_CHAT_ID=-100123456789 # Supergroup chat ID
BRIDGE_URL=http://localhost:3000 # Bridge server URL
DATA_DIR=./data # SQLite database directory
SKIP_REPLAY=false # Skip historical replay on start
PlatformAdapter Highlights
Container → Forum Topic
async createContainer(session: SessionSummary): Promise<ContainerId> {
const topic = await this.bot.createForumTopic(this.chatId, {
name: truncate(title, 128),
icon_color: this.hashColor(session.projectName),
})
return String(topic.message_thread_id)
}
Incoming Message Parsing
The adapter parses Telegram updates and calls handlers.onMessage() with normalized data:
// Text message with optional photos/documents
handlers.onMessage({
updateId: String(update.update_id),
containerId: String(msg.message_thread_id),
platformMessageId: String(msg.message_id),
text: msg.text || msg.caption || '',
files: this.extractFiles(msg),
sender: {
id: `tg:${msg.from.id}`,
username: msg.from.username,
displayName: buildDisplayName(msg.from),
},
})
Attachment Round-Trip
Incoming (TG → Bridge): Download via Bot API → temp file → upload to bridge.
Outgoing (Bridge → TG): Read from bridge attachment path → send via Bot API as photo/document based on type.
Formatter Highlights
SemanticBlock → Telegram HTML
The formatter renders semantic blocks to Telegram-compatible HTML:
- text with
inlineFormat: 'md'→ markdown-to-HTML conversion - tool_card → bold name + italic summary + expandable blockquote for input/result
- code →
<pre><code class="language-X">blocks - result_card → usage stats in monospace
- user_message_card → formatted conversation buffer
Message Chunking
Telegram messages have a 4096-character limit. The formatter automatically chunks long messages:
render(blocks: SemanticBlock[]): FormattedContent[] {
const html = this.renderBlocks(blocks)
return chunkText(html, 4000).map(chunk => ({
kind: 'text',
text: chunk,
parseMode: 'html',
}))
}
Running
# Install dependencies
npm install
# Build
npx tsc
# Run
node dist/index.js
The adapter will:
- Connect to the bridge
- Fetch all sessions
- Create forum topics for each session
- Start listening for both bridge events and Telegram messages
- Route messages bidirectionally