Skip to content

[Bug] Duplicate Telegram messages when using ACP binding with shouldRouteToOriginating=true (v2026.3.24) #55603

@smallgun01

Description

@smallgun01

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

After upgrading to 2026.3.24, ACP binding to Telegram topic results in duplicate messages being sent.

Steps to reproduce

  1. Set up ACP binding with Kiro to Telegram group topic.
  2. Send a message to the topic.
  3. Kiro agent responds → same message appears twice.

Expected behavior

In 2026.3.23-2 the ACP binding works fine. Message only appears once.

Actual behavior

Root Cause

In dispatch-acp.runtime / src/auto-reply/reply/dispatch-acp-delivery.ts:

When shouldRouteToOriginating=true (Telegram → ACP binding), deliver() with kind="block" sends via routeReply() immediately AND accumulates into accumulatedBlockText. However, state.deliveredFinalReply is only set for kind="final".

In finalizeAcpTurnOutput, the guard !params.delivery.hasDeliveredFinalReply() is true (no "final" was delivered), so it sends accumulatedBlockText again as a second "final" message — duplicating the already-sent block content.

Exact Double-Send Path

  1. ACP agent streams response → block delivered via routeReply() → message sent to Telegram ✓
  2. Turn ends → finalizeAcpTurnOutput runs → hasDeliveredFinalReply()=false → sends same text again ✗

Likely Related Change

From 2026.3.24 changelog:

ACP/direct chats: always deliver a terminal ACP result when final TTS does not yield audio, even if block text already streamed earlier, and skip redundant empty-text final synthesis. (#53692)

This fix was for direct chats but may have caused regression for ACP bindings with shouldRouteToOriginating=true.

Suggested Fix

In finalizeAcpTurnOutput, add check for routedCounts.block:

// Current (buggy):
if (ttsMode !== "all" && hasAccumulatedBlockText && !finalMediaDelivered && !params.delivery.hasDeliveredFinalReply()) {

// Fixed:
if (ttsMode !== "all" && hasAccumulatedBlockText && !finalMediaDelivered 
 && !params.delivery.hasDeliveredFinalReply()
 && params.delivery.getRoutedCounts().block === 0) {

Or alternatively, in deliver(), set deliveredFinalReply = true when a block is successfully routed via routeReply.

### OpenClaw version

2026.3.24

### Operating system

Ubuntu 24.04

### Install method

npm global

### Model

Minimax m2.5/Kiro

### Provider / routing chain

openclaw -> minimax

### Additional provider/model setup details

_No response_

### Logs, screenshots, and evidence

```shell

Impact and severity

No response

Additional information

Bug report generated by Openclaw agent, model: Minimax m2.5, think/high

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingbug:behaviorIncorrect behavior without a crash

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions