Engineering a persistent AI assistant requires more than just a connection to the Bot API; it requires a scalable, middleware-driven architecture.
In the most recent core update, Moltbot fully transitioned to grammY, the world's most advanced TypeScript Bot API client. This move allowed for the deprecation of hand-rolled fetch implementations in favor of a robust, professional-grade infrastructure.
Why grammY?
Prior to this migration, Moltbot relied on a custom fetch-based implementation that required manual handling of FormData, media chunks, and error retries. Moving to grammY provided three critical engineering advantages:
TS-First Design
Built-in long-poll and webhook helpers with type-safe context for all Bot API methods.
Native Throttler
Built-in handling for Bot API 429 rate limits, ensuring smooth delivery across thousands of users.
Extensible Middleware
A unified pipeline for session management, error handling, and media processing.
The middleware point deserves unpacking, because it is the architectural difference rather than a convenience feature. grammY organises handlers as a layered stack: every update enters at the top, and each layer receives a context object plus a next function. Calling await next() passes the update downstream; not calling it stops the chain there. As the grammY documentation puts it, you can view all installed middleware functions "as a number of layers that are stacked on top of each other".
That structure lets you wrap behaviour around downstream work rather than merely routing to it. Authentication, allowlist checks, logging, timing, session loading and error boundaries all become layers you compose once and apply everywhere, and a Composer lets you group several of them into a single reusable unit. A hand-rolled fetch implementation gives you flat routing and nothing else; every cross-cutting concern has to be copied into every handler. One warning grammY makes emphatically and every team learns the hard way: always await your next(). Omitting it breaks execution order, loses data and prevents error handling from working at all.
Single Client Architecture
Moltbot has removed all legacy Telegram client paths. grammY is now the sole engine for both message sends and gateway monitoring. By enabling the grammY throttler by default, Moltbot intelligently queues outbound messages to comply with Telegram’s strict broadcast limits.
Consolidating on one client sounds like housekeeping, but it removes an entire class of bug. With two code paths, media handling, retry semantics, error shapes and rate-limit accounting all drift apart, and the failure only shows up under load when both paths are contending for the same quota. One client means one queue, one set of types, and one place to fix things. It also means the dependency surface is auditable: what the bot can do to Telegram is exactly what grammY exposes, nothing more.
Rate Limits, Throttling and Retries
Telegram's Bot API enforces rate limits, and exceeding them returns HTTP 429. grammY's transformer-throttler plugin handles this by enqueueing outgoing API requests through the Bottleneck library, applying three separate throttling layers rather than one blunt global cap.
| Throttler | Scope | Default Limit |
|---|---|---|
| Global | All outbound API calls | 30 requests per second |
| Group | Sends into a single group chat | 20 requests per minute, processed sequentially |
| Private | Direct messages to one user | One concurrent request, one-second interval |
The group limit is the one that catches people out. Twenty messages per minute into a single chat is a genuinely tight budget for an assistant that streams or posts follow-ups, and it is why Moltbot queues rather than fires. Without a throttler the failure mode is not a clean error — it is a partially delivered conversation where some replies arrive and others silently do not.
The throttler is necessary but not sufficient
grammY's own documentation is explicit about the limitation: "Telegram implements unspecified and undocumented rate limits for some API calls. These undocumented limits are not accounted for by the throttler." The recommended pattern is therefore to pair the throttler with the auto-retry plugin, so that a 429 the throttler could not have predicted is backed off and retried rather than surfaced as a dropped message. Any production Telegram bot that ships only one of the two is relying on luck.
The Gateway Provider Engine
The monitorTelegramProvider is the heart of the integration. It does the heavy lifting:
- Gating: Wires mention requirements and allowlist checks before passing messages to the AI.
- Media Download: Uses
getFileanddownloadto process inbound photos, videos, and documents for vision analysis. - Unified Delivery: Delivers AI-generated replies using optimized
sendMessage,sendPhoto, andsendAudiopipes.

Proxies & Webhook Support
Professional Deployment Modes
For production environments, Moltbot now supports two distinct connectivity patterns:
Webhook Mode
Enabled via webhookUrl. Includes health checks and graceful shutdown listeners on port 8787.
Proxy Support
Uses undici.ProxyAgent through grammY's baseFetch for restricted network environments.
Choosing between the two is less about preference than about where you are running. Long polling is grammY's default and the right answer for local development, standard servers, and anywhere you lack a public URL or a valid TLS certificate — the bot simply holds a request open until Telegram has something to send. Webhooks suit serverless platforms and cloud functions, where you are billed for execution rather than uptime and a persistently open connection is the wrong shape entirely. grammY covers both: bot.start() for polling, and webhookCallback to mount the bot as middleware inside whichever web framework you already run.
Update Ordering and Delivery Guarantees
The single most under-appreciated hazard in webhook deployments is re-delivery. grammY's documentation states it plainly: "If you don't end a webhook request fast enough, Telegram will re-send the update, assuming that it was not delivered." For an ordinary echo bot this is harmless. For an AI assistant, where a single turn may involve a model call that takes many seconds, it is a duplicate-processing bug waiting to happen — the same user message answered twice, or worse, the same tool call executed twice.
The recommended remedy is to acknowledge the webhook immediately and hand the actual work to a background task queue rather than attempting a long operation inside the request handler. This is a genuine architectural constraint rather than an optimisation: any Telegram assistant that runs inference synchronously inside its webhook handler will eventually process duplicates under load.
Ordering is the related concern. Updates that arrive concurrently are not guaranteed to finish in the order they were sent, which matters enormously when a user fires three messages in quick succession and each one mutates the same conversation state. The standard grammY answer is to constrain concurrency per chat — processing updates sequentially within a chat whilst still handling different chats in parallel — which is exactly the boundary Moltbot's session keys draw in the next section.
Multi-Chat Session Isolation
Moltbot implements a deterministic session mapping strategy to ensure agent context never "leaks" between different chats:
| Context | Session ID Mapping |
|---|---|
| Direct Message | agent:{agentId}:{mainKey} |
| Group Chat | agent:{agentId}:telegram:group:{chatId} |
| Forum Topic | agent:{agentId}:telegram:group:{chatId}:topic:{threadId} |
The three-tier scheme is deliberately deterministic: the same chat always resolves to the same key, with no lookup table to fall out of sync. Forum topics get their own session keyed by both chat ID and thread ID, which is what stops a support thread and a general-chatter thread inside the same group from bleeding into one another. This is also a privacy boundary, not merely a quality one — a group chat should never be able to surface something a user said in a direct message, and keying the session rather than filtering the output is the only way to guarantee that structurally. If you are setting this up for the first time, our Moltbot Telegram setup guide walks through the configuration end to end.
Draft Streaming (Bot API 9.3+)
A standout feature of the grammY implementation is the optional Draft Streaming. By utilizing the sendMessageDraft method (available in private topic chats), Moltbot can show a live, evolving text bubble to the user while the model is still generating.
This provides a significantly lower "perceived latency" compared to standard block-based messaging.
It is worth being clear about why this is optional rather than default. Draft streaming is available only in private topic chats on Bot API 9.3 and later, so it cannot be relied upon as the universal delivery path. It also interacts directly with the rate limits described earlier: an approach that edits a message repeatedly as tokens arrive consumes API calls at a rate a naive implementation will not survive. The pragmatic pattern is draft streaming where the platform supports it and the chat type allows it, with a clean fall-back to conventional block sends everywhere else — which is why streamMode is exposed as a configuration flag rather than hard-coded.
Developer Configuration Knobs
A comprehensive set of configuration flags has been exposed to give developers full control over the grammY instance:
channels.telegram.dmPolicychannels.telegram.groupPolicychannels.telegram.mediaMaxMbchannels.telegram.streamModeFuture Engineering Roadmap
While the migration to grammY is complete, developments continue. The current backlog includes:
Structured Media Tests
Adding extensive test fixtures for vision-processing stickers and audio-to-voice re-encoding.
Dynamic Webhook Routing
Making the internal webhook listener port configurable beyond the current default (8787).
Lessons for Other Bot Builders
Most of what made this migration worthwhile generalises well beyond Moltbot, and beyond Telegram. Four points are worth stating directly for anyone building an assistant on a messaging platform.
Adopt the ecosystem, not just the client
The value of grammY is not that it wraps HTTP calls — anyone can write that in an afternoon. It is the plugin ecosystem: throttler, auto-retry, session handling, concurrency control and file helpers, all of which are problems you will otherwise solve badly at 2am in production.
Design for the rate limit from day one
Twenty messages per minute per group is not a limit you can retrofit around. It shapes how you chunk replies, whether you stream, and how you handle a burst of users in a busy channel. Bolt a throttler on late and you will find your message-composition logic was built on an assumption that was never true.
Make isolation structural
Deterministic session keys derived from chat and thread identifiers are cheap to implement and impossible to get subtly wrong later. Filtering context at output time, by contrast, is a leak waiting for its first edge case.
Answer the webhook, then do the work
Model inference does not belong inside a webhook request handler. Acknowledge fast, queue the job, and deliver the reply asynchronously. This one decision eliminates duplicate processing, and it is far harder to retrofit than to design in.
For readers arriving here without context on the project itself, our explainer on what Moltbot is covers the wider architecture and the other channel integrations.
Final Thoughts
The decision to unify Moltbot's Telegram infrastructure under grammY was driven by a single goal: Reliability. As AI assistants move from novelties to mission-critical tools, the underlying communication layer must be indestructible.
By leveraging middleware, throttlers, and professional deployment patterns, Moltbot is now ready for the next generation of ambient agents.






