You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two independent Telegraf consumers run against the same bot token concurrently:
@elizaos/plugin-telegram — auto-enabled when connectors.telegram.enabled === true. Spawns its own Telegraf instance and starts long-polling.
milady's standalone wrapper at packages/app-core/src/runtime/eliza.ts:534 (function ensureTelegramBotPolling) — spawns a second Telegraf instance with the same token, calls bot.startPolling().
Telegram's getUpdates long-poll API delivers each update to exactly one consumer. Whichever long-poll wins the race for a given message gets it; the other sees nothing. Updates routed to the upstream plugin go through elizaOS message handling — which on milady is not wired to a Telegram-channel-aware agent — and silently drop. Updates routed to milady's wrapper go through useModel directly and reply correctly.
End result: every other Telegram message (roughly) gets dropped silently. From the user's perspective, the bot replies sometimes, ignores others.
Why both exist
The wrapper was added with this comment (packages/app-core/src/runtime/eliza.ts:531-533):
"Ensure Telegram bot is polling. The upstream plugin's bot.launch() is not awaited and silently fails on bun/Windows. We create a standalone Telegraf instance with proper lifecycle management."
So milady spawns its own Telegraf to work around #7241 (Bun + Telegraf 4.16.3 launch() readonly-property bug). But it never disables the upstream plugin to avoid the duplicate poller.
Symptoms
Inconsistent: bot replies to ~50% of messages, ignores the rest.
Logs show [milady] Telegram bot polling started AND [PLUGIN:TELEGRAM] Starting Telegram bot on boot.
curl https://api.telegram.org/bot<token>/getUpdates returns empty (something did consume them) but no [milady] Telegram message from @user: ... log entry for the dropped messages.
Reproduction
Fresh milady, telegram connector enabled with a valid bot token.
bun run dev — both pollers start.
From a Telegram client, DM the bot 5 messages back to back.
~2-3 will get a reply, ~2-3 will be silently dropped depending on which poller wins each getUpdates race.
Workaround (verified locally)
Disable the upstream plugin so milady's wrapper is the only consumer:
After restart: only one Telegraf polls, every inbound message routes through milady's wrapper, every message gets a reply. Verified with 4 back-to-back messages — 4 logged inbound, 4 logged replies.
Suggested fix
Two paths:
Mutually exclusive at config time. When milady spawns its own wrapper (ensureTelegramBotPolling), it should also force-disable the upstream @elizaos/plugin-telegram and the connectors.telegram auto-enable. One owner per bot token, no exceptions.
Option 2 is the cleaner architectural fix. Option 1 is the right tactical fix until the upstream Bun issue is resolved. Either way, the current "both run, hope for the best" state is not OK because silent message loss looks like working software to the user.
Why this matters
Combined with #7240 (token bridge bug) and #7241 (Telegraf launch bug), the Telegram setup path is currently unable to deliver "I sent 5 messages and got 5 replies" reliably out of the box. Even with the user's token correctly bridged into the env and the launch bug worked around, the dual-poller race means inconsistent delivery — a user-facing failure mode that's nearly impossible to diagnose without log access.
Environment
bun 1.3.13
telegraf 4.16.3
@elizaos/plugin-telegram (current alice submodule pin)
Summary
Two independent Telegraf consumers run against the same bot token concurrently:
@elizaos/plugin-telegram— auto-enabled whenconnectors.telegram.enabled === true. Spawns its own Telegraf instance and starts long-polling.packages/app-core/src/runtime/eliza.ts:534(functionensureTelegramBotPolling) — spawns a second Telegraf instance with the same token, callsbot.startPolling().Telegram's
getUpdateslong-poll API delivers each update to exactly one consumer. Whichever long-poll wins the race for a given message gets it; the other sees nothing. Updates routed to the upstream plugin go through elizaOS message handling — which on milady is not wired to a Telegram-channel-aware agent — and silently drop. Updates routed to milady's wrapper go throughuseModeldirectly and reply correctly.End result: every other Telegram message (roughly) gets dropped silently. From the user's perspective, the bot replies sometimes, ignores others.
Why both exist
The wrapper was added with this comment (
packages/app-core/src/runtime/eliza.ts:531-533):So milady spawns its own Telegraf to work around #7241 (Bun + Telegraf 4.16.3
launch()readonly-property bug). But it never disables the upstream plugin to avoid the duplicate poller.Symptoms
[milady] Telegram bot polling startedAND[PLUGIN:TELEGRAM] Starting Telegram boton boot.curl https://api.telegram.org/bot<token>/getUpdatesreturns empty (something did consume them) but no[milady] Telegram message from @user: ...log entry for the dropped messages.Reproduction
bun run dev— both pollers start.getUpdatesrace.Workaround (verified locally)
Disable the upstream plugin so milady's wrapper is the only consumer:
After restart: only one Telegraf polls, every inbound message routes through milady's wrapper, every message gets a reply. Verified with 4 back-to-back messages — 4 logged inbound, 4 logged replies.
Suggested fix
Two paths:
Mutually exclusive at config time. When milady spawns its own wrapper (
ensureTelegramBotPolling), it should also force-disable the upstream@elizaos/plugin-telegramand theconnectors.telegramauto-enable. One owner per bot token, no exceptions.Remove the wrapper, fix the upstream plugin. Address the
launch()Bun bug at the source (@elizaos/plugin-telegram (Telegraf 4.16.3) bot.launch() throws 'Attempted to assign to readonly property' under Bun #7241). Then the wrapper becomes unnecessary and@elizaos/plugin-telegramis the single source of truth.Option 2 is the cleaner architectural fix. Option 1 is the right tactical fix until the upstream Bun issue is resolved. Either way, the current "both run, hope for the best" state is not OK because silent message loss looks like working software to the user.
Why this matters
Combined with #7240 (token bridge bug) and #7241 (Telegraf launch bug), the Telegram setup path is currently unable to deliver "I sent 5 messages and got 5 replies" reliably out of the box. Even with the user's token correctly bridged into the env and the launch bug worked around, the dual-poller race means inconsistent delivery — a user-facing failure mode that's nearly impossible to diagnose without log access.
Environment
alice(PR fix(deps): update dependency @diffusionstudio/vits-web to v1.0.3 #105 sync)