Skip to content

fix(telegram): fix streaming with extended thinking models overwriting previous messages/ also happens to Execution error#17973

Merged
obviyus merged 5 commits into
openclaw:mainfrom
Marvae:fix/telegram-streaming-thinking-overwrite
Feb 16, 2026
Merged

fix(telegram): fix streaming with extended thinking models overwriting previous messages/ also happens to Execution error#17973
obviyus merged 5 commits into
openclaw:mainfrom
Marvae:fix/telegram-streaming-thinking-overwrite

Conversation

@Marvae

@Marvae Marvae commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix for Telegram streaming with extended thinking models overwriting previous messages. Execution error will also ovrrerwritng normal message. Manually tested.
Close: #17935 #17883

Test

Problem

When using extended thinking models (e.g. Claude Opus) with Telegram streaming enabled, text output after a thinking block overwrites the previous message instead of creating a new one.

An alternative solution is to provide an option for user to decide, some app like chatGPT or gemini, only shows think process before reply.

Root Cause

The draft stream kept editing the same message because streamMessageId was never reset after a streaming buffer reset. This reset happens when the new partial text is not a continuation of the previous text (e.g., after a thinking block ends).

Fix

  1. Add forceNewMessage() method to TelegramDraftStream that resets internal state (streamMessageId, lastSentText, pendingText)
  2. Call forceNewMessage() in bot-message-dispatch.ts when a streaming buffer reset is detected

Changes

  • src/telegram/draft-stream.ts: Add forceNewMessage() method
  • src/telegram/bot-message-dispatch.ts: Call forceNewMessage() on buffer reset
  • src/telegram/draft-stream.test.ts: Add test case for forceNewMessage()

Testing

  • All existing tests pass and new added test cases
  • New test verifies that forceNewMessage() causes a new message to be sent

AI usage

  • AI finds codes and provide solution, human provide feedback and review implementation
  • TDD by adding test case before writing code

Greptile Summary

This PR fixes Telegram streaming with extended thinking models by forcing a new message when a streaming buffer reset is detected (e.g., after a thinking block ends). Previously, the draft stream kept editing the same message because streamMessageId was never cleared on buffer reset.

  • Adds forceNewMessage() to TelegramDraftStream that resets streamMessageId, lastSentText, and pendingText
  • Calls forceNewMessage() in the buffer reset branch of updateDraftFromPartial in bot-message-dispatch.ts
  • Includes a test verifying that forceNewMessage() causes a new sendMessage call instead of editing the existing message
  • The fix is minimal, well-targeted, and correctly placed in the streaming pipeline

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk — it's a focused bug fix with correct logic and test coverage.
  • The fix correctly addresses the root cause (streamMessageId not being reset on buffer reset). The changes are minimal and well-scoped. One minor robustness concern: forceNewMessage() doesn't reset the stopped flag, which could prevent streaming from resuming in edge cases where the stream was previously stopped. This is unlikely to cause issues in the primary thinking-block scenario but is worth addressing for completeness.
  • src/telegram/draft-stream.ts — consider whether stopped should also be reset in forceNewMessage().

Last reviewed commit: b974057

@openclaw-barnacle openclaw-barnacle Bot added channel: telegram Channel integration: telegram size: XS labels Feb 16, 2026

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +174 to +178
const forceNewMessage = () => {
streamMessageId = undefined;
lastSentText = "";
pendingText = "";
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stopped flag not reset

forceNewMessage() resets streamMessageId, lastSentText, and pendingText, but does not reset the stopped flag. If the stream was previously stopped (e.g., text exceeded 4096 chars or an API error occurred), subsequent update() calls after forceNewMessage() will silently no-op because update() checks stopped first at line 150. Consider also resetting stopped = false here so the stream can resume after a buffer reset.

Suggested change
const forceNewMessage = () => {
streamMessageId = undefined;
lastSentText = "";
pendingText = "";
};
const forceNewMessage = () => {
streamMessageId = undefined;
lastSentText = "";
pendingText = "";
stopped = false;
};
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/telegram/draft-stream.ts
Line: 174:178

Comment:
**`stopped` flag not reset**

`forceNewMessage()` resets `streamMessageId`, `lastSentText`, and `pendingText`, but does not reset the `stopped` flag. If the stream was previously stopped (e.g., text exceeded 4096 chars or an API error occurred), subsequent `update()` calls after `forceNewMessage()` will silently no-op because `update()` checks `stopped` first at line 150. Consider also resetting `stopped = false` here so the stream can resume after a buffer reset.

```suggestion
  const forceNewMessage = () => {
    streamMessageId = undefined;
    lastSentText = "";
    pendingText = "";
    stopped = false;
  };
```

How can I resolve this? If you propose a fix, please make it concise.

@Marvae Marvae changed the title fix(telegram): force new message after streaming buffer reset fix(telegram): fix Telegram streaming with extended thinking models overwriting previous messages. Feb 16, 2026
@Marvae Marvae changed the title fix(telegram): fix Telegram streaming with extended thinking models overwriting previous messages. fix(telegram): fix Telegram streaming with extended thinking models overwriting previous messages Feb 16, 2026
@Marvae Marvae force-pushed the fix/telegram-streaming-thinking-overwrite branch 2 times, most recently from 489236e to fa63a74 Compare February 16, 2026 10:44
@Marvae Marvae force-pushed the fix/telegram-streaming-thinking-overwrite branch 2 times, most recently from 418815b to 58c5405 Compare February 16, 2026 11:01
@openclaw-barnacle openclaw-barnacle Bot added the agents Agent runtime and tooling label Feb 16, 2026
@Marvae Marvae changed the title fix(telegram): fix Telegram streaming with extended thinking models overwriting previous messages fix(telegram): fix Telegram streaming with extended thinking models overwriting previous messages/ also happens to Execution error Feb 16, 2026
@Marvae Marvae changed the title fix(telegram): fix Telegram streaming with extended thinking models overwriting previous messages/ also happens to Execution error fix(telegram): fix streaming with extended thinking models overwriting previous messages/ also happens to Execution error Feb 16, 2026
@Marvae Marvae force-pushed the fix/telegram-streaming-thinking-overwrite branch 3 times, most recently from eb736bd to 4802017 Compare February 16, 2026 12:05
@obviyus obviyus force-pushed the fix/telegram-streaming-thinking-overwrite branch 3 times, most recently from 23693af to 50ca6cb Compare February 16, 2026 13:23
Marvae and others added 5 commits February 16, 2026 18:53
… message starts

When using extended thinking models with Telegram streaming, text output
after a thinking block was overwriting the previous message instead of
creating a new one.

Root cause: The draft stream kept editing the same message because
streamMessageId was never reset after reasoning completed.

Fix:
1. Add forceNewMessage() to TelegramDraftStream that resets internal state
2. Add onReasoningEnd callback that fires when </think> tag is processed
3. Add onAssistantMessageStart callback exposure through ReplyOptions
4. When either callback fires AND we've already streamed content,
   call forceNewMessage() to ensure the next output creates a new message

This covers two scenarios:
- Tool call followed by new assistant message (onAssistantMessageStart)
- Thinking block within same message (onReasoningEnd)

Tests added:
- forces new message when new assistant message starts after previous output
- does not force new message on first assistant message start
- forces new message when reasoning ends after previous output
- does not force new message on reasoning end without previous output
- creates new message after forceNewMessage is called (draft-stream.test.ts)

Fixes openclaw#17935
…iting

When a tool execution fails, the error payload would previously overwrite
the streaming preview message, hiding the original response text.

Changes:
1. Error payloads (isError: true) skip preview edit path
2. onAssistantMessageStart forces new message after tool calls
3. onReasoningEnd forces new message after thinking blocks

This ensures thinking, text, and errors appear as separate messages.

Added test: error payloads not editing preview messages
… blocks)

Extended thinking from API (thinking content blocks) wasn't triggering
onReasoningEnd because it doesn't go through </think> tag processing.
This caused reasoning to be displayed briefly then overwritten by the
final reply in draft streaming mode.

Now we explicitly call onReasoningEnd in handleAssistantMessageEnd when
reasoning came from API blocks (extended thinking), while avoiding
double-calling when using <think> tags which already trigger it.
…ing (API blocks)"

This reverts commit 3f8fc4d0c38ccca1fab836d55390073e475d9023.
@obviyus obviyus force-pushed the fix/telegram-streaming-thinking-overwrite branch from 50ca6cb to 34b52ee Compare February 16, 2026 13:23
@obviyus obviyus merged commit dddb1bc into openclaw:main Feb 16, 2026
13 checks passed
@obviyus

obviyus commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

Thanks @Marvae!

archerhpagent pushed a commit to howardpark/openclaw that referenced this pull request Feb 18, 2026
…g previous messages/ also happens to Execution error (openclaw#17973)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 34b52ee
Co-authored-by: Marvae <11957602+Marvae@users.noreply.github.com>
Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com>
Reviewed-by: @obviyus
@obviyus obviyus self-assigned this Mar 23, 2026
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
…g previous messages/ also happens to Execution error (openclaw#17973)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 34b52ee
Co-authored-by: Marvae <11957602+Marvae@users.noreply.github.com>
Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com>
Reviewed-by: @obviyus
@Marvae Marvae deleted the fix/telegram-streaming-thinking-overwrite branch April 29, 2026 15:30
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…g previous messages/ also happens to Execution error (openclaw#17973)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 34b52ee
Co-authored-by: Marvae <11957602+Marvae@users.noreply.github.com>
Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com>
Reviewed-by: @obviyus
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
…g previous messages/ also happens to Execution error (openclaw#17973)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 34b52ee
Co-authored-by: Marvae <11957602+Marvae@users.noreply.github.com>
Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com>
Reviewed-by: @obviyus
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: telegram Channel integration: telegram size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Telegram] Streaming with extended thinking overwrites previous message text

2 participants