Files
openclaw/extensions/telegram/src/bot-message-context.body.test.ts
tarouca bf0f4d93f0 fix: restore Telegram DM voice-note transcription (#61008) (thanks @manueltarouca)
* fix(telegram): enable voice-note transcription in DMs

The preflight transcription condition only triggered for group chats
(isGroup && requireMention), so voice notes sent in direct messages
were never transcribed -- they arrived as raw <media:audio> placeholders.

This regression was introduced when the Telegram channel was moved from
src/telegram/ to extensions/telegram/, losing the fix from c15385fc94.

Widen the condition to fire whenever there is audio and no accompanying
text, regardless of chat type. Group-specific guards (requireMention,
disableAudioPreflight, senderAllowedForAudioPreflight) still apply
only in group contexts.

* fix: restore Telegram DM voice-note transcription (#61008) (thanks @manueltarouca)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-05 09:49:44 +05:30

193 lines
6.0 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { normalizeAllowFrom } from "./bot-access.js";
const transcribeFirstAudioMock = vi.fn();
vi.mock("./media-understanding.runtime.js", () => ({
transcribeFirstAudio: (...args: unknown[]) => transcribeFirstAudioMock(...args),
}));
const { resolveTelegramInboundBody } = await import("./bot-message-context.body.js");
describe("resolveTelegramInboundBody", () => {
it("keeps the media marker when a captioned video has no downloaded media", async () => {
const result = await resolveTelegramInboundBody({
cfg: {
channels: { telegram: {} },
} as never,
primaryCtx: {
me: { id: 7, username: "bot" },
} as never,
msg: {
message_id: 0,
date: 1_700_000_000,
chat: { id: 42, type: "private", first_name: "Pat" },
from: { id: 42, first_name: "Pat" },
caption: "episode caption",
video: {
file_id: "video-1",
file_unique_id: "video-u1",
duration: 10,
width: 320,
height: 240,
},
} as never,
allMedia: [],
isGroup: false,
chatId: 42,
senderId: "42",
senderUsername: "",
routeAgentId: undefined,
effectiveGroupAllow: normalizeAllowFrom([]),
effectiveDmAllow: normalizeAllowFrom([]),
groupConfig: undefined,
topicConfig: undefined,
requireMention: false,
options: undefined,
groupHistories: new Map(),
historyLimit: 0,
logger: { info: vi.fn() },
});
expect(result).toMatchObject({
rawBody: "episode caption",
bodyText: "<media:video> [file_id:video-1]\nepisode caption",
});
});
it("does not transcribe group audio for unauthorized senders", async () => {
transcribeFirstAudioMock.mockReset();
const logger = { info: vi.fn() };
const result = await resolveTelegramInboundBody({
cfg: {
channels: { telegram: {} },
messages: { groupChat: { mentionPatterns: ["\\bbot\\b"] } },
} as never,
primaryCtx: {
me: { id: 7, username: "bot" },
} as never,
msg: {
message_id: 1,
date: 1_700_000_000,
chat: { id: -1001234567890, type: "supergroup", title: "Test Group" },
from: { id: 46, first_name: "Eve" },
voice: { file_id: "voice-1" },
entities: [],
} as never,
allMedia: [{ path: "/tmp/voice.ogg", contentType: "audio/ogg" }],
isGroup: true,
chatId: -1001234567890,
senderId: "46",
senderUsername: "",
routeAgentId: undefined,
effectiveGroupAllow: normalizeAllowFrom(["999"]),
effectiveDmAllow: normalizeAllowFrom([]),
groupConfig: { requireMention: true } as never,
topicConfig: undefined,
requireMention: true,
options: undefined,
groupHistories: new Map(),
historyLimit: 0,
logger,
});
expect(transcribeFirstAudioMock).not.toHaveBeenCalled();
expect(logger.info).toHaveBeenCalledWith(
{ chatId: -1001234567890, reason: "no-mention" },
"skipping group message",
);
expect(result).toBeNull();
});
it("still transcribes when commands.useAccessGroups is false", async () => {
transcribeFirstAudioMock.mockReset();
transcribeFirstAudioMock.mockResolvedValueOnce("hey bot please help");
const result = await resolveTelegramInboundBody({
cfg: {
channels: { telegram: {} },
commands: { useAccessGroups: false },
messages: { groupChat: { mentionPatterns: ["\\bbot\\b"] } },
tools: { media: { audio: { enabled: true } } },
} as never,
primaryCtx: {
me: { id: 7, username: "bot" },
} as never,
msg: {
message_id: 2,
date: 1_700_000_001,
chat: { id: -1001234567891, type: "supergroup", title: "Test Group" },
from: { id: 46, first_name: "Eve" },
voice: { file_id: "voice-2" },
entities: [],
} as never,
allMedia: [{ path: "/tmp/voice-2.ogg", contentType: "audio/ogg" }],
isGroup: true,
chatId: -1001234567891,
senderId: "46",
senderUsername: "",
routeAgentId: undefined,
effectiveGroupAllow: normalizeAllowFrom(["999"]),
effectiveDmAllow: normalizeAllowFrom([]),
groupConfig: { requireMention: true } as never,
topicConfig: undefined,
requireMention: true,
options: undefined,
groupHistories: new Map(),
historyLimit: 0,
logger: { info: vi.fn() },
});
expect(transcribeFirstAudioMock).toHaveBeenCalledTimes(1);
expect(result).toMatchObject({
bodyText: "hey bot please help",
effectiveWasMentioned: true,
});
});
it("transcribes DM voice notes via preflight (not only groups)", async () => {
transcribeFirstAudioMock.mockReset();
transcribeFirstAudioMock.mockResolvedValueOnce("hello from a voice note");
const result = await resolveTelegramInboundBody({
cfg: {
channels: { telegram: {} },
tools: { media: { audio: { enabled: true } } },
} as never,
primaryCtx: {
me: { id: 7, username: "bot" },
} as never,
msg: {
message_id: 10,
date: 1_700_000_010,
chat: { id: 42, type: "private", first_name: "Pat" },
from: { id: 42, first_name: "Pat" },
voice: { file_id: "voice-dm-1" },
entities: [],
} as never,
allMedia: [{ path: "/tmp/voice-dm.ogg", contentType: "audio/ogg" }],
isGroup: false,
chatId: 42,
senderId: "42",
senderUsername: "",
routeAgentId: undefined,
effectiveGroupAllow: normalizeAllowFrom([]),
effectiveDmAllow: normalizeAllowFrom([]),
groupConfig: undefined,
topicConfig: undefined,
requireMention: false,
options: undefined,
groupHistories: new Map(),
historyLimit: 0,
logger: { info: vi.fn() },
});
expect(transcribeFirstAudioMock).toHaveBeenCalledTimes(1);
expect(result).toMatchObject({
bodyText: "hello from a voice note",
});
expect(result?.bodyText).not.toContain("<media:audio>");
});
});