openclaw - ✅(Solved) Fix [Bug] Reasoning mode 'On' sends only thinking content, no final response in Telegram [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#43807Fetched 2026-04-08 00:17:52
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
cross-referenced ×2referenced ×1subscribed ×1

When using /reasoning on in Telegram, only the thinking content is displayed/sent, and the final response message is never delivered to the user.

Root Cause

When using /reasoning on in Telegram, only the thinking content is displayed/sent, and the final response message is never delivered to the user.

Fix Action

Fix / Workaround

The "Stream" mode appears to work correctly and is currently the recommended workaround.

PR fix notes

PR #43885: fix: restore final response delivery when Telegram reasoning mode is "on"

Description (problem / solution / changelog)

Summary

Fixes #43807

When using /reasoning on in Telegram, users only received the thinking content — the final response was silently dropped and never delivered. /reasoning off and /reasoning stream both worked correctly.

Root cause: two separate bugs in the reply pipeline:

  1. Reasoning payloads suppressed on the wrong path. The generic onBlockReply handler in dispatch-from-config.ts unconditionally dropped all payloads where isReasoning: true. A comment in that file claimed Telegram had its own dispatch path, but in reasoning="on" mode Telegram was actually going through this generic path. The reasoning payload was swallowed before it could reach the Telegram lane coordinator, which meant the pipeline registered a "did stream" state but never forwarded the final answer, leaving the user with no response at all.

  2. Answer fragmented across multiple messages. blockReplyBreak defaulted to "text_end", so in reasoning="on" mode the answer was split into many small Telegram messages rather than one coherent reply.

Behavior Changes

  • /reasoning on: now delivers both the reasoning block (as a separate Telegram message) and the final answer (as a single consolidated message). Previously only the reasoning block appeared.
  • /reasoning off / /reasoning stream: behavior unchanged.
  • Other channels (WhatsApp, web, etc.): unaffected — reasoning payloads are still suppressed on those paths.

Existing Functionality Check

  • Searched for all call sites of shouldSuppressReasoningPayload and onBlockReply to confirm no other channel is affected.
  • Verified forceBlockStreamingForReasoning is only true when reasoningLevel === "on", so allowReasoningPayloads is never set for other reasoning levels or other channels.
  • Confirmed blockReplyBreak = "message_end" override is scoped to resolvedReasoningLevel === "on" only.

What Changed

  • src/auto-reply/types.ts

    • Added allowReasoningPayloads?: boolean to GetReplyOptions. Channels with a dedicated reasoning lane (Telegram reasoning="on") set this to true to bypass generic reasoning suppression.
  • src/auto-reply/reply/dispatch-from-config.ts

    • The shouldSuppressReasoningPayload guard is now conditional: suppression is skipped when params.replyOptions?.allowReasoningPayloads is true.
  • src/auto-reply/reply/get-reply-directives.ts

    • resolvedBlockStreamingBreak is forced to "message_end" when resolvedReasoningLevel === "on", ensuring the answer is delivered as one complete message instead of many fragments.
  • src/telegram/bot-message-dispatch.ts

    • Passes allowReasoningPayloads: forceBlockStreamingForReasoning in replyOptions so the new guard in dispatch-from-config.ts is activated for Telegram reasoning="on" sessions.
  • src/telegram/bot-message-dispatch.test.ts

    • Extended the "keeps block streaming enabled when session reasoning level is on" test to assert:
      • replyOptions includes allowReasoningPayloads: true
      • deliverReplies is called with the reasoning block ("Reasoning:\n_step_")
      • deliverReplies is also called with the final answer ("Hello")

Tests

  • src/telegram/bot-message-dispatch.test.ts66 tests passed
  • src/auto-reply/reply/dispatch-from-config.test.ts44 tests passed

Files Changed

  • src/auto-reply/types.ts (+4 lines)
  • src/auto-reply/reply/dispatch-from-config.ts (+5 lines, -4 lines)
  • src/auto-reply/reply/get-reply-directives.ts (+3 lines, -1 line)
  • src/telegram/bot-message-dispatch.ts (+1 line)
  • src/telegram/bot-message-dispatch.test.ts (+6 lines)

Checklist

  • Test locally with your OpenClaw instance
  • Run tests: node_modules/.bin/vitest.CMD run src/telegram/bot-message-dispatch.test.ts
  • Run tests: node_modules/.bin/vitest.CMD run src/auto-reply/reply/dispatch-from-config.test.ts
  • Keep PRs focused (one thing per PR) ✅
  • Describe what & why ✅

Sign-Off

  • Models used: Claude
  • Submitter effort: AI-assisted with manual code review
  • Agent notes: Fix is minimal and surgical — 19 lines changed across 5 files. No new abstractions introduced; the allowReasoningPayloads flag follows the same opt-in pattern already used by disableBlockStreaming and onPartialReply in GetReplyOptions.

Changed files

  • src/auto-reply/reply/dispatch-from-config.ts (modified, +5/-4)
  • src/auto-reply/reply/get-reply-directives.ts (modified, +3/-1)
  • src/auto-reply/types.ts (modified, +4/-0)
  • src/telegram/bot-message-dispatch.test.ts (modified, +6/-0)
  • src/telegram/bot-message-dispatch.ts (modified, +1/-0)

PR #43902: fix: restore final response delivery when Telegram reasoning mode is "on"

Description (problem / solution / changelog)

Summary

Fixes #43807

When using /reasoning on in Telegram, users only received the thinking content — the final response was silently dropped and never delivered. /reasoning off and /reasoning stream both worked correctly.

Root cause: two separate bugs in the reply pipeline:

  1. Reasoning payloads suppressed on the wrong path. The generic onBlockReply handler in dispatch-from-config.ts unconditionally dropped all payloads where isReasoning: true. A comment in that file claimed Telegram had its own dispatch path, but in reasoning="on" mode Telegram was actually going through this generic path. The reasoning payload was swallowed before it could reach the Telegram lane coordinator, which meant the pipeline registered a "did stream" state but never forwarded the final answer, leaving the user with no response at all.

  2. Answer fragmented across multiple messages. blockReplyBreak defaulted to "text_end", so in reasoning="on" mode the answer was split into many small Telegram messages rather than one coherent reply.

Behavior Changes

  • /reasoning on: now delivers both the reasoning block (as a separate Telegram message) and the final answer (as a single consolidated message). Previously only the reasoning block appeared.
  • /reasoning off / /reasoning stream: behavior unchanged.
  • Other channels (WhatsApp, web, etc.): unaffected — reasoning payloads are still suppressed on those paths.

Existing Functionality Check

  • Searched for all call sites of shouldSuppressReasoningPayload and onBlockReply to confirm no other channel is affected.
  • Verified forceBlockStreamingForReasoning is only true when reasoningLevel === "on", so allowReasoningPayloads is never set for other reasoning levels or other channels.
  • Confirmed blockReplyBreak = "message_end" override is scoped to resolvedReasoningLevel === "on" only.

What Changed

  • src/auto-reply/types.ts

    • Added allowReasoningPayloads?: boolean to GetReplyOptions. Channels with a dedicated reasoning lane (Telegram reasoning="on") set this to true to bypass generic reasoning suppression.
  • src/auto-reply/reply/dispatch-from-config.ts

    • The shouldSuppressReasoningPayload guard is now conditional: suppression is skipped when params.replyOptions?.allowReasoningPayloads is true.
  • src/auto-reply/reply/get-reply-directives.ts

    • resolvedBlockStreamingBreak is forced to "message_end" when resolvedReasoningLevel === "on", ensuring the answer is delivered as one complete message instead of many fragments.
  • src/telegram/bot-message-dispatch.ts

    • Passes allowReasoningPayloads: forceBlockStreamingForReasoning in replyOptions so the new guard in dispatch-from-config.ts is activated for Telegram reasoning="on" sessions.
  • src/telegram/bot-message-dispatch.test.ts

    • Extended the "keeps block streaming enabled when session reasoning level is on" test to assert:
      • replyOptions includes allowReasoningPayloads: true
      • deliverReplies is called with the reasoning block ("Reasoning:\n_step_")
      • deliverReplies is also called with the final answer ("Hello")

Tests

  • src/telegram/bot-message-dispatch.test.ts66 tests passed
  • src/auto-reply/reply/dispatch-from-config.test.ts44 tests passed

Files Changed

  • src/auto-reply/types.ts (+4 lines)
  • src/auto-reply/reply/dispatch-from-config.ts (+5 lines, -4 lines)
  • src/auto-reply/reply/get-reply-directives.ts (+3 lines, -1 line)
  • src/telegram/bot-message-dispatch.ts (+1 line)
  • src/telegram/bot-message-dispatch.test.ts (+6 lines)

Checklist

  • Test locally with your OpenClaw instance
  • Run tests: node_modules/.bin/vitest.CMD run src/telegram/bot-message-dispatch.test.ts
  • Run tests: node_modules/.bin/vitest.CMD run src/auto-reply/reply/dispatch-from-config.test.ts
  • Keep PRs focused (one thing per PR) ✅
  • Describe what & why ✅

Sign-Off

  • Models used: Claude
  • Submitter effort: AI-assisted with manual code review
  • Agent notes: Fix is minimal and surgical — 19 lines changed across 5 files. No new abstractions introduced; the allowReasoningPayloads flag follows the same opt-in pattern already used by disableBlockStreaming and onPartialReply in GetReplyOptions.

Changed files

  • src/auto-reply/reply/dispatch-from-config.ts (modified, +5/-4)
  • src/auto-reply/reply/get-reply-directives.ts (modified, +3/-1)
  • src/auto-reply/types.ts (modified, +4/-0)
  • src/telegram/bot-message-dispatch.test.ts (modified, +6/-0)
  • src/telegram/bot-message-dispatch.ts (modified, +1/-0)
RAW_BUFFERClick to expand / collapse

Description

When using /reasoning on in Telegram, only the thinking content is displayed/sent, and the final response message is never delivered to the user.

Environment

  • OpenClaw version: 2026.3.8
  • Channel: Telegram
  • Model: MiniMax-M2.5 (via minimax-portal)
  • Reasoning mode: On (via /reasoning command)

Steps to Reproduce

  1. In a Telegram DM with the OpenClaw bot, send /reasoning on
  2. Send any message that requires a response
  3. Observe: only thinking/reasoning content appears
  4. Expected: both thinking AND final response should be sent

Current Behavior

  • /reasoning off: Works correctly, sends only the final response
  • /reasoning on: Only shows thinking content, final response is missing
  • /reasoning stream: Works correctly - shows thinking in real-time preview AND sends final response

Additional Notes

This issue makes the "On" mode unusable as users cannot receive the actual response, only the internal thinking process.

The "Stream" mode appears to work correctly and is currently the recommended workaround.

extent analysis

Fix Summary

Bug: In the Telegram channel the “reasoning‑on” mode only sends the intermediate “thinking” message and never dispatches the final answer.
Fix: Adjust the Telegram adapter so that after the reasoning text is posted it also sends the final response (or edits the thinking message). The logic used by the “stream” mode can be reused – the only difference is that we don’t stream token‑by‑token, we just send the whole reasoning block first and then the final answer.


Step‑by‑Step Fix Plan

1. Locate the Telegram channel implementation

File (example): src/channels/telegram.ts (or telegram_adapter.py if Python).

You’ll find a switch on reasoningMode that builds a Message object:

switch (reasoningMode) {
  case 'off':
    // send final only
    break;
  case 'on':
    // currently: sendThinkingOnly()
    break;
  case 'stream':
    // sendThinkingLive() + sendFinal()
    break;
}

2. Add a “send final” step for reasoningMode === 'on'

TypeScript / Node example

// Existing helper – sends the reasoning block as a separate message
async function sendThinking(chatId: string, thinking: string) {
  await bot.sendMessage(chatId, `🧠 *Thinking...*\n${thinking}`, {
    parse_mode: 'Markdown',
    disable_web_page_preview: true,
  });
}

// New helper – sends the final answer
async function sendFinal(chatId: string, answer: string) {
  await bot.sendMessage(chatId, answer, {
    parse_mode: 'Markdown',
    disable_web_page_preview: true,
  });
}

// Updated case
case 'on': {
  // 1️⃣ Send the reasoning block
  await sendThinking(chatId, reasoningText);

  // 2️⃣ After the model finishes, send the final answer
  await sendFinal(chatId, finalAnswer);
  break;
}

Python example (if the bot is written in Python)

async def _send_thinking(chat

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING