Summary
In Telegram group chats, when the model generates a text response but does not call the message tool, the response is silently discarded and the user sees nothing. This happens because sourceReplyDeliveryMode: "message_tool_only" (the default for group/channel chats) causes dispatch-from-config.ts to suppress all payloads that lack deliverDespiteSourceReplySuppression metadata.
The model intermittently skips calling the message tool — especially after long idle periods when the Anthropic prompt cache goes cold — even though the delivery hint ("Delivery: to send a message, use the message tool.") is present in every prompt.
Reproduction
- Configure a Telegram bot with default settings (queue mode: steer)
- Have an active group chat session with working message tool usage
- Wait 90+ minutes (long enough for the prompt cache to go cold)
- Send a message to the bot in the group chat
- The model generates a relevant response but may not call the
message tool
- The response is silently dropped — no error, no delivery, no log indication
Evidence from trajectory data
Three consecutive broken turns in topic:2027 session, all with the same pattern:
| Time (UTC) |
outputTokens |
toolMetas |
didSend |
assistantTexts |
messagingToolSentTexts |
| 20:16 |
196 |
[] |
false |
"Plan A from the playbook. 150g chicken + 150g roasted veg..." |
[] |
| 20:17 |
96 |
[] |
false |
"Hey — did you see the lunch rec?..." |
[] |
| 20:19 |
56 |
[] |
false |
"Lunch: 150g chicken + 150g roasted veg..." |
[] |
Every working turn in the same session had toolMetas containing {"toolName":"message"}, didSend: true, and non-empty messagingToolSentTexts. A separate session (topic:1) broke at the same time with the same pattern.
Root cause
Two-part problem:
-
Model behavior: claude-opus-4-7 intermittently generates direct text without calling the message tool, particularly after long idle gaps.
-
Runtime suppression: In dispatch-from-config.ts (~line 1608):
if (suppressDelivery && !shouldDeliverDespiteSourceReplySuppression(reply)) {
continue; // payload silently skipped
}
When sourceReplyDeliveryMode is "message_tool_only", suppressDelivery is true. Only payloads marked with deliverDespiteSourceReplySuppression (set by markReplyPayloadForSourceSuppressionDelivery) survive. Plain assistant text payloads from buildEmbeddedRunPayloads never get this flag, so they are silently dropped.
Proposed fix
In agent-runner.ts, after the agent run completes: when sourceReplyDeliveryMode is "message_tool_only" and the model produced text payloads but no side-effect delivery occurred (no message tool, no block streaming), mark those payloads with deliverDespiteSourceReplySuppression so they bypass the dispatch suppression and the user still sees the response.
PR incoming.
Environment
- OpenClaw v2026.5.12
- Model:
claude-opus-4-7 via Anthropic API
- Channel: Telegram (group chat, queue mode: steer)
- Block streaming enabled for Telegram
Summary
In Telegram group chats, when the model generates a text response but does not call the
messagetool, the response is silently discarded and the user sees nothing. This happens becausesourceReplyDeliveryMode: "message_tool_only"(the default for group/channel chats) causesdispatch-from-config.tsto suppress all payloads that lackdeliverDespiteSourceReplySuppressionmetadata.The model intermittently skips calling the message tool — especially after long idle periods when the Anthropic prompt cache goes cold — even though the delivery hint ("Delivery: to send a message, use the
messagetool.") is present in every prompt.Reproduction
messagetoolEvidence from trajectory data
Three consecutive broken turns in topic:2027 session, all with the same pattern:
[]false[][]false[][]false[]Every working turn in the same session had
toolMetascontaining{"toolName":"message"},didSend: true, and non-emptymessagingToolSentTexts. A separate session (topic:1) broke at the same time with the same pattern.Root cause
Two-part problem:
Model behavior:
claude-opus-4-7intermittently generates direct text without calling themessagetool, particularly after long idle gaps.Runtime suppression: In
dispatch-from-config.ts(~line 1608):When
sourceReplyDeliveryModeis"message_tool_only",suppressDeliveryistrue. Only payloads marked withdeliverDespiteSourceReplySuppression(set bymarkReplyPayloadForSourceSuppressionDelivery) survive. Plain assistant text payloads frombuildEmbeddedRunPayloadsnever get this flag, so they are silently dropped.Proposed fix
In
agent-runner.ts, after the agent run completes: whensourceReplyDeliveryModeis"message_tool_only"and the model produced text payloads but no side-effect delivery occurred (no message tool, no block streaming), mark those payloads withdeliverDespiteSourceReplySuppressionso they bypass the dispatch suppression and the user still sees the response.PR incoming.
Environment
claude-opus-4-7via Anthropic API