Telegram Delivery Bugs Are a Reminder That Agent Replies Are Not Just Chat History
The bug in OpenClaw PR #85361 is easy to undersell as a Telegram annoyance. A direct message came in, the assistant generated an answer, the transcript stored it, and Telegram never received it. Annoying, yes. But the real lesson is larger: in agent systems, “the model answered” and “the user received the answer” are not the same event.
That distinction is becoming one of the important fault lines in agent-platform design. Chat apps can often get away with treating history append and delivery as one conceptual motion. Agent runtimes cannot. They have session stores, webchat polling, channel adapters, abort semantics, streaming drafts, message-tool lanes, control commands, background tasks, and multiple surfaces that may share a logical session. Delivery is its own state machine. Pretending otherwise creates bugs that look like ghosts.
PR #85361 was opened on May 22 at 13:04 UTC and changes two files with 86 additions. The source issue, #85314, was filed earlier the same morning against OpenClaw 2026.5.20 (e510042) on macOS, using Telegram DM, shared webchat/Telegram session key agent:main:main, and provider minimax/MiniMax-M2.7. The symptoms were specific: Telegram inbound messages were logged, assistant replies existed in the session transcript, but outbound Telegram send logs had no matching send rows for the affected messages.
A transcript is not a receipt
The issue timeline is the useful part. User messages at 10:22, 10:23, 10:24, 10:26, and 10:26 all produced assistant replies in the transcript with no outbound Telegram delivery. Later messages at 18:28 and after delivered normally. Webchat could show the missing replies by polling history. Telegram users, obviously, could not read messages that were never sent.
The root cause is a reply-fencing problem. Telegram reply fences were keyed by effective session key, and direct chats commonly use agent:main:main. Before the patch, every normal Telegram user request superseded the active fence for that session. In practical terms, overlapping direct-message turns could cause an earlier turn’s final reply to be superseded before it reached Telegram. The answer existed. The delivery lane had moved on.
The fix is careful in the way this class of bug requires. Normal Telegram direct-chat turns no longer supersede active same-session reply work. Authorized abort requests still supersede. /btw and read-only control lanes remain non-interrupting. Group and room-event latest-wins behavior is unchanged. That split matters because latest-wins semantics are not inherently wrong. They are just context-dependent.
In a group chat, latest-wins can be the sane behavior. A newer message may change the room context enough that the old reply is now stale. In a control lane, aborting or superseding work may be exactly what the operator asked for. But a direct-message conversation has a different social contract. If a user sends two DMs quickly, they usually expect two replies or a visible cancellation. They do not expect one hidden transcript reply and one delivered message.
Delivery bugs become trust bugs
This is not just UX polish. Many OpenClaw deployments use chat channels as the human control plane for background agents, crons, subagents, approvals, and notifications. If delivery silently drops, the human supervisor gets a partial picture while the system believes it communicated. That is the worst version of reliability failure: not loud enough to page anyone, not obvious enough to reproduce casually, and perfectly capable of eroding trust.
There is also a monitoring lesson. If your observability only checks whether an assistant message was generated or appended to session history, it is measuring the wrong thing. The useful lifecycle is closer to: generated, stored, queued, sent, acknowledged, superseded, aborted, failed. Different systems may collapse some of those states, but serious agent runtimes need to know the difference between “final response exists” and “the channel adapter delivered it to the peer that asked.”
The issue links adjacent channel-delivery problems that make this look less like a one-off Telegram paper cut and more like an active design surface: Signal replies staying on an internal surface, Telegram message-tool sends appearing as tool cards, Telegram group replies going to the wrong chat_id, and a proposed sendPolicy.peerEquals feature for constraining outbound delivery to the inbound peer. That constellation is the real story. Agent platforms are outgrowing the idea that “send a message” is a simple side effect.
For operators, the test is straightforward and worth adding to your smoke suite. Send two direct messages before the first final reply arrives. Then inspect both the transcript and the channel send logs. If the transcript has two replies and the channel has one send, your platform has not completed both turns. It has merely convinced its own history store that it did.
For framework builders, the guidance is even more direct: do not key delivery fences too broadly. Session identity, peer identity, channel identity, and abort authority are related but not interchangeable. A shared session key can be useful for memory continuity while still being the wrong key for delivery supersession. If your runtime treats them as the same thing, overlapping turns will eventually find the seam.
The patch includes a regression test proving overlapping direct-message turns both remain deliverable, alongside focused Telegram dispatch and conversation-route tests. The PR still carries triage: needs-real-behavior-proof, so the right posture is measured: this is the correct fix shape, but operators should verify it against a real bot once it lands in a release. Delivery bugs are where mocks can prove intent and still miss provider timing.
The headline is not “Telegram had a bug.” It is that agent runtimes need delivery semantics, not just transcripts. If the user never receives the reply, the agent did not finish the job.
Sources: OpenClaw PR #85361, OpenClaw issue #85314, OpenClaw issue #85175, OpenClaw v2026.5.20 release