mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 22:54:31 +00:00
fix(telegram): fail loud on empty text fallback
This commit is contained in:
@@ -278,6 +278,25 @@ describe("deliverReplies", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("throws when formatted and plain fallback text are both empty", async () => {
|
||||||
|
const runtime = { error: vi.fn(), log: vi.fn() };
|
||||||
|
const sendMessage = vi.fn();
|
||||||
|
const bot = { api: { sendMessage } } as unknown as Bot;
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
deliverReplies({
|
||||||
|
replies: [{ text: " " }],
|
||||||
|
chatId: "123",
|
||||||
|
token: "tok",
|
||||||
|
runtime,
|
||||||
|
bot,
|
||||||
|
replyToMode: "off",
|
||||||
|
textLimit: 4000,
|
||||||
|
}),
|
||||||
|
).rejects.toThrow("empty formatted text and empty plain fallback");
|
||||||
|
expect(sendMessage).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it("uses reply_to_message_id when quote text is provided", async () => {
|
it("uses reply_to_message_id when quote text is provided", async () => {
|
||||||
const runtime = createRuntime();
|
const runtime = createRuntime();
|
||||||
const sendMessage = vi.fn().mockResolvedValue({
|
const sendMessage = vi.fn().mockResolvedValue({
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
import type { StickerMetadata, TelegramContext } from "./types.js";
|
import type { StickerMetadata, TelegramContext } from "./types.js";
|
||||||
|
|
||||||
const PARSE_ERR_RE = /can't parse entities|parse entities|find end of the entity/i;
|
const PARSE_ERR_RE = /can't parse entities|parse entities|find end of the entity/i;
|
||||||
|
const EMPTY_TEXT_ERR_RE = /message text is empty/i;
|
||||||
const VOICE_FORBIDDEN_RE = /VOICE_MESSAGES_FORBIDDEN/;
|
const VOICE_FORBIDDEN_RE = /VOICE_MESSAGES_FORBIDDEN/;
|
||||||
const FILE_TOO_BIG_RE = /file is too big/i;
|
const FILE_TOO_BIG_RE = /file is too big/i;
|
||||||
const TELEGRAM_MEDIA_SSRF_POLICY = {
|
const TELEGRAM_MEDIA_SSRF_POLICY = {
|
||||||
@@ -41,7 +42,6 @@ const TELEGRAM_MEDIA_SSRF_POLICY = {
|
|||||||
allowedHostnames: ["api.telegram.org"],
|
allowedHostnames: ["api.telegram.org"],
|
||||||
allowRfc2544BenchmarkRange: true,
|
allowRfc2544BenchmarkRange: true,
|
||||||
};
|
};
|
||||||
const EMPTY_TEXT_ERR_RE = /message text is empty/i;
|
|
||||||
|
|
||||||
export async function deliverReplies(params: {
|
export async function deliverReplies(params: {
|
||||||
replies: ReplyPayload[];
|
replies: ReplyPayload[];
|
||||||
@@ -544,7 +544,7 @@ async function sendTelegramText(
|
|||||||
linkPreview?: boolean;
|
linkPreview?: boolean;
|
||||||
replyMarkup?: ReturnType<typeof buildInlineKeyboard>;
|
replyMarkup?: ReturnType<typeof buildInlineKeyboard>;
|
||||||
},
|
},
|
||||||
): Promise<number | undefined> {
|
): Promise<number> {
|
||||||
const baseParams = buildTelegramSendParams({
|
const baseParams = buildTelegramSendParams({
|
||||||
replyToMessageId: opts?.replyToMessageId,
|
replyToMessageId: opts?.replyToMessageId,
|
||||||
thread: opts?.thread,
|
thread: opts?.thread,
|
||||||
@@ -557,9 +557,6 @@ async function sendTelegramText(
|
|||||||
const fallbackText = opts?.plainText ?? text;
|
const fallbackText = opts?.plainText ?? text;
|
||||||
const hasFallbackText = fallbackText.trim().length > 0;
|
const hasFallbackText = fallbackText.trim().length > 0;
|
||||||
const sendPlainFallback = async () => {
|
const sendPlainFallback = async () => {
|
||||||
if (!hasFallbackText) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const res = await withTelegramApiErrorLogging({
|
const res = await withTelegramApiErrorLogging({
|
||||||
operation: "sendMessage",
|
operation: "sendMessage",
|
||||||
runtime,
|
runtime,
|
||||||
@@ -570,12 +567,15 @@ async function sendTelegramText(
|
|||||||
...baseParams,
|
...baseParams,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
runtime.log?.(`telegram sendMessage ok chat=${chatId} message=${res.message_id} (plain)`);
|
||||||
return res.message_id;
|
return res.message_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Markdown can occasionally render to empty HTML (for example syntax-only chunks).
|
// Markdown can render to empty HTML for syntax-only chunks; recover with plain text.
|
||||||
// Telegram rejects those sends, so fall back to plain text early.
|
|
||||||
if (!htmlText.trim()) {
|
if (!htmlText.trim()) {
|
||||||
|
if (!hasFallbackText) {
|
||||||
|
throw new Error("telegram sendMessage failed: empty formatted text and empty plain fallback");
|
||||||
|
}
|
||||||
return await sendPlainFallback();
|
return await sendPlainFallback();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -599,6 +599,9 @@ async function sendTelegramText(
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errText = formatErrorMessage(err);
|
const errText = formatErrorMessage(err);
|
||||||
if (PARSE_ERR_RE.test(errText) || EMPTY_TEXT_ERR_RE.test(errText)) {
|
if (PARSE_ERR_RE.test(errText) || EMPTY_TEXT_ERR_RE.test(errText)) {
|
||||||
|
if (!hasFallbackText) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
runtime.log?.(`telegram formatted send failed; retrying without formatting: ${errText}`);
|
runtime.log?.(`telegram formatted send failed; retrying without formatting: ${errText}`);
|
||||||
return await sendPlainFallback();
|
return await sendPlainFallback();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user