Skip to content

Telegram DM: agent completes successfully but response never delivered (silent drop) #23702

Description

@sege66

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

  1. Configure OpenClaw with Telegram plugin enabled and a custom model provider using api: "openai-completions"
  2. Send a DM to the bot from Telegram
  3. Gateway receives the message (long polling)
  4. Agent runs to completion — payload produced
  5. 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:

  1. Telegram plugin path (subagent-registry-Bdm_X-N1.js):

    • registerTelegramHandlers (line 56081) → debouncer onFlushprocessMessage (line 56127)
    • processMessage = createTelegramMessageProcessor (line 58263) → dispatchTelegramMessage (line 57801)
    • dispatchTelegramMessagedispatchReplyWithBufferedBlockDispatcher (line 58081) with deliver callback that calls deliverReplies → Telegram sendMessage
    • This path should work — it has inline delivery via deliverReplies
  2. 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 formatPayloadForLogconsole.log
    • This path does NOT dispatch to Telegram — it only logs to console
  3. 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: falsepreviewStreamingEnabled=falsedisableBlockStreaming=trueblockStreamingEnabled=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

  1. 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
  2. Add logging in buildReplyPayloads / runReplyAgent to check if payloads are being filtered or if an early return is triggered
  3. Compare the payload structure returned by openai-completions vs native Anthropic provider to identify format differences that might cause silent payload drops

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions