mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-07 22:09:57 +00:00
fix: render telegram draft streams with markdown html
This commit is contained in:
@@ -26,6 +26,7 @@ import type { TelegramStreamMode } from "./bot/types.js";
|
||||
import type { TelegramInlineButtons } from "./button-types.js";
|
||||
import { resolveTelegramDraftStreamingChunking } from "./draft-chunking.js";
|
||||
import { createTelegramDraftStream } from "./draft-stream.js";
|
||||
import { renderTelegramHtmlText } from "./format.js";
|
||||
import { editMessageTelegram } from "./send.js";
|
||||
import { cacheSticker, describeStickerImage } from "./sticker-cache.js";
|
||||
|
||||
@@ -101,6 +102,15 @@ export const dispatchTelegramMessage = async ({
|
||||
} = context;
|
||||
|
||||
const draftMaxChars = Math.min(textLimit, 4096);
|
||||
const tableMode = resolveMarkdownTableMode({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
accountId: route.accountId,
|
||||
});
|
||||
const renderDraftPreview = (text: string) => ({
|
||||
text: renderTelegramHtmlText(text, { tableMode }),
|
||||
parseMode: "HTML" as const,
|
||||
});
|
||||
const accountBlockStreamingEnabled =
|
||||
typeof telegramCfg.blockStreaming === "boolean"
|
||||
? telegramCfg.blockStreaming
|
||||
@@ -117,6 +127,7 @@ export const dispatchTelegramMessage = async ({
|
||||
thread: threadSpec,
|
||||
replyToMessageId: draftReplyToMessageId,
|
||||
minInitialChars: draftMinInitialChars,
|
||||
renderText: renderDraftPreview,
|
||||
log: logVerbose,
|
||||
warn: logVerbose,
|
||||
})
|
||||
@@ -129,6 +140,7 @@ export const dispatchTelegramMessage = async ({
|
||||
thread: threadSpec,
|
||||
replyToMessageId: draftReplyToMessageId,
|
||||
minInitialChars: draftMinInitialChars,
|
||||
renderText: renderDraftPreview,
|
||||
log: logVerbose,
|
||||
warn: logVerbose,
|
||||
})
|
||||
@@ -259,11 +271,6 @@ export const dispatchTelegramMessage = async ({
|
||||
channel: "telegram",
|
||||
accountId: route.accountId,
|
||||
});
|
||||
const tableMode = resolveMarkdownTableMode({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
accountId: route.accountId,
|
||||
});
|
||||
const chunkMode = resolveChunkMode(cfg, "telegram", route.accountId);
|
||||
|
||||
// Handle uncached stickers: get a dedicated vision description before dispatch
|
||||
|
||||
@@ -133,6 +133,26 @@ describe("createTelegramDraftStream", () => {
|
||||
expect(api.sendMessage).toHaveBeenCalledTimes(2);
|
||||
expect(api.sendMessage).toHaveBeenLastCalledWith(123, "After thinking", undefined);
|
||||
});
|
||||
|
||||
it("supports rendered previews with parse_mode", async () => {
|
||||
const api = createMockDraftApi();
|
||||
const stream = createTelegramDraftStream({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
api: api as any,
|
||||
chatId: 123,
|
||||
renderText: (text) => ({ text: `<i>${text}</i>`, parseMode: "HTML" }),
|
||||
});
|
||||
|
||||
stream.update("hello");
|
||||
await stream.flush();
|
||||
expect(api.sendMessage).toHaveBeenCalledWith(123, "<i>hello</i>", { parse_mode: "HTML" });
|
||||
|
||||
stream.update("hello again");
|
||||
await stream.flush();
|
||||
expect(api.editMessageText).toHaveBeenCalledWith(123, 17, "<i>hello again</i>", {
|
||||
parse_mode: "HTML",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("draft stream initial message debounce", () => {
|
||||
|
||||
@@ -15,6 +15,11 @@ export type TelegramDraftStream = {
|
||||
forceNewMessage: () => void;
|
||||
};
|
||||
|
||||
type TelegramDraftPreview = {
|
||||
text: string;
|
||||
parseMode?: "HTML";
|
||||
};
|
||||
|
||||
export function createTelegramDraftStream(params: {
|
||||
api: Bot["api"];
|
||||
chatId: number;
|
||||
@@ -24,6 +29,8 @@ export function createTelegramDraftStream(params: {
|
||||
throttleMs?: number;
|
||||
/** Minimum chars before sending first message (debounce for push notifications) */
|
||||
minInitialChars?: number;
|
||||
/** Optional preview renderer (e.g. markdown -> HTML + parse mode). */
|
||||
renderText?: (text: string) => TelegramDraftPreview;
|
||||
log?: (message: string) => void;
|
||||
warn?: (message: string) => void;
|
||||
}): TelegramDraftStream {
|
||||
@@ -42,6 +49,7 @@ export function createTelegramDraftStream(params: {
|
||||
|
||||
let streamMessageId: number | undefined;
|
||||
let lastSentText = "";
|
||||
let lastSentParseMode: "HTML" | undefined;
|
||||
let stopped = false;
|
||||
let isFinal = false;
|
||||
|
||||
@@ -63,24 +71,43 @@ export function createTelegramDraftStream(params: {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (trimmed === lastSentText) {
|
||||
const rendered = params.renderText?.(trimmed) ?? { text: trimmed };
|
||||
const renderedText = rendered.text.trimEnd();
|
||||
const renderedParseMode = rendered.parseMode;
|
||||
if (!renderedText) {
|
||||
return false;
|
||||
}
|
||||
if (renderedText === lastSentText && renderedParseMode === lastSentParseMode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Debounce first preview send for better push notification quality.
|
||||
if (typeof streamMessageId !== "number" && minInitialChars != null && !isFinal) {
|
||||
if (trimmed.length < minInitialChars) {
|
||||
if (renderedText.length < minInitialChars) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
lastSentText = trimmed;
|
||||
lastSentText = renderedText;
|
||||
lastSentParseMode = renderedParseMode;
|
||||
try {
|
||||
if (typeof streamMessageId === "number") {
|
||||
await params.api.editMessageText(chatId, streamMessageId, trimmed);
|
||||
if (renderedParseMode) {
|
||||
await params.api.editMessageText(chatId, streamMessageId, renderedText, {
|
||||
parse_mode: renderedParseMode,
|
||||
});
|
||||
} else {
|
||||
await params.api.editMessageText(chatId, streamMessageId, renderedText);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const sent = await params.api.sendMessage(chatId, trimmed, replyParams);
|
||||
const sendParams = renderedParseMode
|
||||
? {
|
||||
...replyParams,
|
||||
parse_mode: renderedParseMode,
|
||||
}
|
||||
: replyParams;
|
||||
const sent = await params.api.sendMessage(chatId, renderedText, sendParams);
|
||||
const sentMessageId = sent?.message_id;
|
||||
if (typeof sentMessageId !== "number" || !Number.isFinite(sentMessageId)) {
|
||||
stopped = true;
|
||||
@@ -138,6 +165,7 @@ export function createTelegramDraftStream(params: {
|
||||
const forceNewMessage = () => {
|
||||
streamMessageId = undefined;
|
||||
lastSentText = "";
|
||||
lastSentParseMode = undefined;
|
||||
loop.resetPending();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user