Skip to content

ACP stream deliveryMode: final_only still sends duplicate block+final replies #56198

@lishixiang0705

Description

@lishixiang0705

Bug Description

When acp.stream.deliveryMode is set to "final_only", ACP binding replies in Telegram groups still produce two identical messages (a block reply + a final reply).

Root Cause (from source analysis)

In dispatch-acp.runtime (dist/dispatch-acp.runtime-BgoLNt3T.js), the drainChunker function checks:

const drainChunker = (force) => {
    if (settings.deliveryMode === "final_only" && !force) return;
    // ...
};

When a turn ends, flush(true) is called with force=true, which bypasses the final_only guard. This causes the accumulated text to be drained into blockReplyPipeline, emitting a deliver("block") call.

Then finalizeAcpTurnOutput (line ~800) checks hasAccumulatedBlockText && !deliveredFinalReply and emits another deliver("final") with the same text.

Result: two identical sendMessage calls to Telegram, ~1 second apart.

Steps to Reproduce

  1. Configure an ACP binding for a Telegram group topic:
{
  "type": "acp",
  "agentId": "claude",
  "match": {
    "channel": "telegram",
    "peer": { "kind": "group", "id": "-100xxxxx:topic:1" }
  },
  "acp": { "mode": "persistent" }
}
  1. Set acp.stream.deliveryMode: "final_only"
  2. Send a message in the bound topic
  3. Observe two identical bot replies

Expected Behavior

With deliveryMode: "final_only", only the final reply should be sent. The force flush at turn end should respect the delivery mode setting and skip the block pipeline drain.

Suggested Fix

Change drainChunker to always skip when deliveryMode === "final_only":

const drainChunker = (force) => {
    if (settings.deliveryMode === "final_only") return;  // remove !force condition
    // ...
};

Or alternatively, in finalizeAcpTurnOutput, check if a block with the same content was already delivered and skip the final in that case.

Environment

  • OpenClaw: 2026.3.24
  • acpx: 0.3.1
  • ACP backend: claude (Claude Code via OAuth)
  • Channel: Telegram (forum group with topics)
  • Config: blockStreamingDefault: "off", acp.stream.deliveryMode: "final_only"

Gateway Log Evidence

Every ACP reply produces paired sendMessage calls ~1s apart:

2026-03-28T11:37:15.888+08:00 [telegram] sendMessage ok chat=-100xxxxx message=458
2026-03-28T11:37:16.663+08:00 [telegram] sendMessage ok chat=-100xxxxx message=459

This persists regardless of blockStreamingDefault, requireMention, or spawnAcpSessions settings.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    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