Bug Summary
When a Telegram DM is received, the gateway runs the agent successfully (isError=false) and produces a valid text payload, but sendMessage is never called — the response is silently dropped. No error is logged at any point after the agent run completes.
Environment
- OpenClaw version: 2026.2.21-2
- Node: v22.14.0
- OS: macOS 26.3 (Darwin 25.3.0)
- Gateway: LaunchAgent (
ai.openclaw.gateway) on port 18789
- Model provider: Custom OpenAI-compatible proxy at
localhost:3456 (api: "openai-completions", provider name: claude-max)
- Telegram config:
channels.telegram.streaming: false, dmPolicy: "pairing"
- TTS:
messages.tts.auto: "always", provider: openai, model: gpt-4o-mini-tts
Reproduction Steps
- Configure OpenClaw with Telegram plugin enabled and a custom model provider using
api: "openai-completions"
- Send a DM to the bot from Telegram
- Gateway receives the message (long polling)
- Agent runs to completion — payload produced
- No response delivered to Telegram
Expected Behavior
Agent response should be dispatched via Telegram Bot API sendMessage to the originating chat.
Actual Behavior
Agent completes with isError=false and produces a valid payload (e.g. "무엇을 도와드릴까요?"), but:
- No
sendMessage call is made
- No error is logged
- The result JSON appears only in the detailed log (
/tmp/openclaw/) as a console.log entry
- The gateway stdout log shows the response text printed to console (not via Telegram API)
Investigation Details
Successful vs Failed Delivery Comparison
We observed one successful delivery and multiple failures within the same day. Comparing the two:
✅ Successful (2026-02-22 14:49 UTC)
[embedded] run provider=anthropic model=claude-sonnet-4-20250514 messageChannel=telegram
[tool] tts ...
isError=false
[telegram] sendMessage ok chat=XXXXXXX message=418 ← DELIVERED
❌ Failed (2026-02-22 16:04 UTC — after config change to custom provider)
[embedded] run provider=claude-max model=claude-opus-4 messageChannel=telegram
isError=false
(result JSON logged to console)
— NO sendMessage, NO error —
Both runs used the same OpenClaw installation (files are byte-identical by MD5). The only difference is the model provider.
Code Path Analysis
We traced the source code extensively:
-
Telegram plugin path (subagent-registry-Bdm_X-N1.js):
registerTelegramHandlers (line 56081) → debouncer onFlush → processMessage (line 56127)
processMessage = createTelegramMessageProcessor (line 58263) → dispatchTelegramMessage (line 57801)
dispatchTelegramMessage → dispatchReplyWithBufferedBlockDispatcher (line 58081) with deliver callback that calls deliverReplies → Telegram sendMessage
- This path should work — it has inline delivery via
deliverReplies
-
CLI fallback path (register.agent-zRCF5dMQ.js):
agentCliCommand (line 205) → tries agentViaGatewayCommand (WS) → fails → falls back to agentCommand (embedded)
- The fallback runs the agent locally and logs results via
formatPayloadForLog → console.log
- This path does NOT dispatch to Telegram — it only logs to console
-
Observed behavior matches the CLI fallback path: the response appears in console output but never reaches Telegram API. The detailed log shows the full result JSON logged but no subsequent sendMessage.
What We Ruled Out
- Block streaming: NOT the cause.
streaming: false → previewStreamingEnabled=false → disableBlockStreaming=true → blockStreamingEnabled=false. The shouldDropFinalPayloads flag is false.
- Payload filtering:
isRenderablePayload returns true (text is non-empty). shouldSuppressMessagingToolReplies is not triggered.
- Telegram API connectivity: Confirmed working — we successfully sent test messages via
sendMessage API directly.
- Two installations: Both
/usr/local/lib/node_modules/openclaw/ and ~/.npm-global/lib/node_modules/openclaw/ exist but are byte-for-byte identical (MD5 verified).
- Model execution: Agent runs complete with
isError=false, aborted=false, valid text payload.
Hypothesis
When using a custom model provider with api: "openai-completions", something in the reply pipeline causes the Telegram dispatch path to silently exit without calling sendMessage. The agent result is produced but the deliver callback inside dispatchTelegramMessage (line 58086) either:
- Is never invoked (payloads array empty after
buildReplyPayloads), or
- The reply pipeline exits at a silent early-return point (e.g.,
runReplyAgent lines 70119/70139 in reply-B2UJINPw.js — empty payload check)
This may be related to how buildEmbeddedRunPayloads or buildReplyPayloads processes the output from an openai-completions API response format vs the native Anthropic format.
Key Log Evidence
Detailed log (/tmp/openclaw/openclaw-2026-02-23.log):
// Line ~1074: Agent run starts
{"provider":"claude-max","model":"claude-opus-4","messageChannel":"telegram","isError":false}
// Line ~1092: Result logged to console, then nothing
{"runId":"5867c723...","status":"ok","result":{"payloads":[{"text":"무엇을 도와드릴까요?","mediaUrl":null}]}}
Gateway log — after the agent result, no sendMessage entry appears. Compare with the successful case where [telegram] sendMessage ok chat=XXXXXXX message=418 appears immediately after the agent run.
Relevant Config (sanitized)
{
"agents": {
"defaults": {
"model": { "primary": "claude-max/claude-opus-4" }
}
},
"channels": {
"telegram": {
"dmPolicy": "pairing",
"streaming": false
}
},
"models": {
"providers": {
"claude-max": {
"baseUrl": "http://localhost:3456/v1",
"apiKey": "not-needed",
"api": "openai-completions",
"models": [
{ "id": "claude-opus-4", "reasoning": true, "contextWindow": 200000, "maxTokens": 16384 }
]
}
}
},
"messages": {
"tts": { "auto": "always", "provider": "openai", "model": "gpt-4o-mini-tts", "voice": "nova" }
}
}
Steps to Diagnose
- Add debug logging inside the
deliver callback at dispatchTelegramMessage (line 58086 in subagent-registry-Bdm_X-N1.js) to confirm whether it's ever called
- Add logging in
buildReplyPayloads / runReplyAgent to check if payloads are being filtered or if an early return is triggered
- Compare the payload structure returned by
openai-completions vs native Anthropic provider to identify format differences that might cause silent payload drops
Bug Summary
When a Telegram DM is received, the gateway runs the agent successfully (
isError=false) and produces a valid text payload, butsendMessageis never called — the response is silently dropped. No error is logged at any point after the agent run completes.Environment
ai.openclaw.gateway) on port 18789localhost:3456(api: "openai-completions", provider name:claude-max)channels.telegram.streaming: false,dmPolicy: "pairing"messages.tts.auto: "always", provider:openai, model:gpt-4o-mini-ttsReproduction Steps
api: "openai-completions"Expected Behavior
Agent response should be dispatched via Telegram Bot API
sendMessageto the originating chat.Actual Behavior
Agent completes with
isError=falseand produces a valid payload (e.g."무엇을 도와드릴까요?"), but:sendMessagecall is made/tmp/openclaw/) as a console.log entryInvestigation Details
Successful vs Failed Delivery Comparison
We observed one successful delivery and multiple failures within the same day. Comparing the two:
✅ Successful (2026-02-22 14:49 UTC)
❌ Failed (2026-02-22 16:04 UTC — after config change to custom provider)
Both runs used the same OpenClaw installation (files are byte-identical by MD5). The only difference is the model provider.
Code Path Analysis
We traced the source code extensively:
Telegram plugin path (
subagent-registry-Bdm_X-N1.js):registerTelegramHandlers(line 56081) → debounceronFlush→processMessage(line 56127)processMessage=createTelegramMessageProcessor(line 58263) →dispatchTelegramMessage(line 57801)dispatchTelegramMessage→dispatchReplyWithBufferedBlockDispatcher(line 58081) withdelivercallback that callsdeliverReplies→ TelegramsendMessagedeliverRepliesCLI fallback path (
register.agent-zRCF5dMQ.js):agentCliCommand(line 205) → triesagentViaGatewayCommand(WS) → fails → falls back toagentCommand(embedded)formatPayloadForLog→console.logObserved behavior matches the CLI fallback path: the response appears in console output but never reaches Telegram API. The detailed log shows the full result JSON logged but no subsequent
sendMessage.What We Ruled Out
streaming: false→previewStreamingEnabled=false→disableBlockStreaming=true→blockStreamingEnabled=false. TheshouldDropFinalPayloadsflag isfalse.isRenderablePayloadreturnstrue(text is non-empty).shouldSuppressMessagingToolRepliesis not triggered.sendMessageAPI directly./usr/local/lib/node_modules/openclaw/and~/.npm-global/lib/node_modules/openclaw/exist but are byte-for-byte identical (MD5 verified).isError=false,aborted=false, valid text payload.Hypothesis
When using a custom model provider with
api: "openai-completions", something in the reply pipeline causes the Telegram dispatch path to silently exit without callingsendMessage. The agent result is produced but thedelivercallback insidedispatchTelegramMessage(line 58086) either:buildReplyPayloads), orrunReplyAgentlines 70119/70139 inreply-B2UJINPw.js— empty payload check)This may be related to how
buildEmbeddedRunPayloadsorbuildReplyPayloadsprocesses the output from anopenai-completionsAPI response format vs the native Anthropic format.Key Log Evidence
Detailed log (
/tmp/openclaw/openclaw-2026-02-23.log):Gateway log — after the agent result, no
sendMessageentry appears. Compare with the successful case where[telegram] sendMessage ok chat=XXXXXXX message=418appears immediately after the agent run.Relevant Config (sanitized)
{ "agents": { "defaults": { "model": { "primary": "claude-max/claude-opus-4" } } }, "channels": { "telegram": { "dmPolicy": "pairing", "streaming": false } }, "models": { "providers": { "claude-max": { "baseUrl": "http://localhost:3456/v1", "apiKey": "not-needed", "api": "openai-completions", "models": [ { "id": "claude-opus-4", "reasoning": true, "contextWindow": 200000, "maxTokens": 16384 } ] } } }, "messages": { "tts": { "auto": "always", "provider": "openai", "model": "gpt-4o-mini-tts", "voice": "nova" } } }Steps to Diagnose
delivercallback atdispatchTelegramMessage(line 58086 insubagent-registry-Bdm_X-N1.js) to confirm whether it's ever calledbuildReplyPayloads/runReplyAgentto check if payloads are being filtered or if an early return is triggeredopenai-completionsvs native Anthropic provider to identify format differences that might cause silent payload drops