From 200dd634fb6ba2f88767dc5804ceab59848413c7 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 3 Jan 2026 17:14:01 +0100 Subject: [PATCH] fix: preserve block streaming order --- CHANGELOG.md | 1 + src/auto-reply/reply.ts | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0df9cad07..41efd549f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Fixes - Telegram: chunk block-stream replies to avoid “message is too long” errors (#124) — thanks @mukhtharcm. - Block streaming: default to text_end and suppress duplicate block sends while in-flight. +- Block streaming: drop final payloads after soft chunking to keep Discord order intact. - Gmail hooks: resolve gcloud Python to a real executable when PATH uses mise shims — thanks @joargp. - Control UI: generate UUIDs when `crypto.randomUUID()` is unavailable over HTTP — thanks @ratulsarna. - Agent: add soft block-stream chunking (800–1200 chars default) with paragraph/newline preference. diff --git a/src/auto-reply/reply.ts b/src/auto-reply/reply.ts index af07632de..eb34dacab 100644 --- a/src/auto-reply/reply.ts +++ b/src/auto-reply/reply.ts @@ -1133,6 +1133,7 @@ export async function getReplyFromConfig( const streamedPayloadKeys = new Set(); const pendingStreamedPayloadKeys = new Set(); const pendingBlockTasks = new Set>(); + let didStreamBlockReply = false; const buildPayloadKey = (payload: ReplyPayload) => { const text = payload.text?.trim() ?? ""; const mediaList = payload.mediaUrls?.length @@ -2239,6 +2240,7 @@ export async function getReplyFromConfig( return; } pendingStreamedPayloadKeys.add(payloadKey); + didStreamBlockReply = true; const task = (async () => { await startTypingOnText(cleaned); await opts.onBlockReply?.(blockPayload); @@ -2345,11 +2347,15 @@ export async function getReplyFromConfig( (payload.mediaUrls && payload.mediaUrls.length > 0), ); - const filteredPayloads = blockStreamingEnabled - ? replyTaggedPayloads.filter( - (payload) => !streamedPayloadKeys.has(buildPayloadKey(payload)), - ) - : replyTaggedPayloads; + const shouldDropFinalPayloads = + blockStreamingEnabled && blockReplyChunking && didStreamBlockReply; + const filteredPayloads = shouldDropFinalPayloads + ? [] + : blockStreamingEnabled + ? replyTaggedPayloads.filter( + (payload) => !streamedPayloadKeys.has(buildPayloadKey(payload)), + ) + : replyTaggedPayloads; if (filteredPayloads.length === 0) return finalizeWithFollowup(undefined);