fix: newline chunking across channels

This commit is contained in:
Peter Steinberger
2026-01-25 04:05:14 +00:00
parent ca78ccf74c
commit 458e731f8b
80 changed files with 580 additions and 91 deletions

View File

@@ -1,5 +1,6 @@
// @ts-nocheck
import { EmbeddedBlockChunker } from "../agents/pi-embedded-block-chunker.js";
import { resolveChunkMode } from "../auto-reply/chunk.js";
import { clearHistoryEntriesIfEnabled } from "../auto-reply/reply/history.js";
import { dispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.js";
import { removeAckReactionAfterReply } from "../channels/ack-reactions.js";
@@ -125,6 +126,7 @@ export const dispatchTelegramMessage = async ({
channel: "telegram",
accountId: route.accountId,
});
const chunkMode = resolveChunkMode(cfg, "telegram", route.accountId);
const { queuedFinal } = await dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
@@ -147,6 +149,7 @@ export const dispatchTelegramMessage = async ({
textLimit,
messageThreadId: resolvedThreadId,
tableMode,
chunkMode,
onVoiceRecording: sendRecordVoice,
});
},

View File

@@ -1,6 +1,7 @@
import type { Bot, Context } from "grammy";
import { resolveEffectiveMessagesConfig } from "../agents/identity.js";
import { resolveChunkMode } from "../auto-reply/chunk.js";
import {
buildCommandTextFromArgs,
findCommandByNativeName,
@@ -320,6 +321,7 @@ export const registerTelegramNativeCommands = ({
typeof telegramCfg.blockStreaming === "boolean"
? !telegramCfg.blockStreaming
: undefined;
const chunkMode = resolveChunkMode(cfg, "telegram", route.accountId);
await dispatchReplyWithBufferedBlockDispatcher({
ctx: ctxPayload,
@@ -337,6 +339,7 @@ export const registerTelegramNativeCommands = ({
textLimit,
messageThreadId: resolvedThreadId,
tableMode,
chunkMode,
});
},
onError: (err, info) => {

View File

@@ -4,6 +4,7 @@ import {
markdownToTelegramHtml,
renderTelegramHtmlText,
} from "../format.js";
import { chunkMarkdownTextWithMode, type ChunkMode } from "../../auto-reply/chunk.js";
import { splitTelegramCaption } from "../caption.js";
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { ReplyToMode } from "../../config/config.js";
@@ -32,12 +33,33 @@ export async function deliverReplies(params: {
textLimit: number;
messageThreadId?: number;
tableMode?: MarkdownTableMode;
chunkMode?: ChunkMode;
/** Callback invoked before sending a voice message to switch typing indicator. */
onVoiceRecording?: () => Promise<void> | void;
}) {
const { replies, chatId, runtime, bot, replyToMode, textLimit, messageThreadId } = params;
const chunkMode = params.chunkMode ?? "length";
const threadParams = buildTelegramThreadParams(messageThreadId);
let hasReplied = false;
const chunkText = (markdown: string) => {
const markdownChunks =
chunkMode === "newline"
? chunkMarkdownTextWithMode(markdown, textLimit, chunkMode)
: [markdown];
const chunks: ReturnType<typeof markdownToTelegramChunks> = [];
for (const chunk of markdownChunks) {
const nested = markdownToTelegramChunks(chunk, textLimit, { tableMode: params.tableMode });
if (!nested.length && chunk) {
chunks.push({
html: markdownToTelegramHtml(chunk, { tableMode: params.tableMode }),
text: chunk,
});
continue;
}
chunks.push(...nested);
}
return chunks;
};
for (const reply of replies) {
const hasMedia = Boolean(reply?.mediaUrl) || (reply?.mediaUrls?.length ?? 0) > 0;
if (!reply?.text && !hasMedia) {
@@ -55,9 +77,7 @@ export async function deliverReplies(params: {
? [reply.mediaUrl]
: [];
if (mediaList.length === 0) {
const chunks = markdownToTelegramChunks(reply.text || "", textLimit, {
tableMode: params.tableMode,
});
const chunks = chunkText(reply.text || "");
for (const chunk of chunks) {
await sendTelegramText(bot, chatId, chunk.html, runtime, {
replyToMessageId:
@@ -151,9 +171,7 @@ export async function deliverReplies(params: {
// Send deferred follow-up text right after the first media item.
// Chunk it in case it's extremely long (same logic as text-only replies).
if (pendingFollowUpText && isFirstMedia) {
const chunks = markdownToTelegramChunks(pendingFollowUpText, textLimit, {
tableMode: params.tableMode,
});
const chunks = chunkText(pendingFollowUpText);
for (const chunk of chunks) {
const replyToMessageIdFollowup =
replyToId && (replyToMode === "all" || !hasReplied) ? replyToId : undefined;