fix: wire telegram disableAudioPreflight config validation and precedence tests (#23067) (thanks @yangnim21029)

This commit is contained in:
Peter Steinberger
2026-03-02 22:26:30 +00:00
parent d3cb85eaf5
commit 1fa2488db1
6 changed files with 138 additions and 28 deletions

View File

@@ -0,0 +1,49 @@
import { describe, expect, it } from "vitest";
import { OpenClawSchema } from "./zod-schema.js";
describe("telegram disableAudioPreflight schema", () => {
it("accepts disableAudioPreflight for groups and topics", () => {
const res = OpenClawSchema.safeParse({
channels: {
telegram: {
groups: {
"*": {
requireMention: true,
disableAudioPreflight: true,
topics: {
"123": {
disableAudioPreflight: false,
},
},
},
},
},
},
});
expect(res.success).toBe(true);
if (!res.success) {
return;
}
const group = res.data.channels?.telegram?.groups?.["*"];
expect(group?.disableAudioPreflight).toBe(true);
expect(group?.topics?.["123"]?.disableAudioPreflight).toBe(false);
});
it("rejects non-boolean disableAudioPreflight values", () => {
const res = OpenClawSchema.safeParse({
channels: {
telegram: {
groups: {
"*": {
disableAudioPreflight: "yes",
},
},
},
},
});
expect(res.success).toBe(false);
});
});

View File

@@ -57,6 +57,7 @@ const TelegramCapabilitiesSchema = z.union([
export const TelegramTopicSchema = z
.object({
requireMention: z.boolean().optional(),
disableAudioPreflight: z.boolean().optional(),
groupPolicy: GroupPolicySchema.optional(),
skills: z.array(z.string()).optional(),
enabled: z.boolean().optional(),
@@ -68,6 +69,7 @@ export const TelegramTopicSchema = z
export const TelegramGroupSchema = z
.object({
requireMention: z.boolean().optional(),
disableAudioPreflight: z.boolean().optional(),
groupPolicy: GroupPolicySchema.optional(),
tools: ToolPolicySchema,
toolsBySender: ToolPolicyBySenderSchema,

View File

@@ -45,39 +45,22 @@ describe("buildTelegramMessageContext audio transcript body", () => {
it("skips preflight transcription when disableAudioPreflight is true", async () => {
transcribeFirstAudioMock.mockClear();
const ctx = await buildTelegramMessageContext({
primaryCtx: {
message: {
message_id: 2,
chat: { id: -1001234567891, type: "supergroup", title: "Test Group 2" },
date: 1700000100,
from: { id: 43, first_name: "Bob" },
voice: { file_id: "voice-2" },
},
me: { id: 7, username: "bot" },
} as never,
const ctx = await buildTelegramMessageContextForTest({
message: {
message_id: 2,
chat: { id: -1001234567891, type: "supergroup", title: "Test Group 2" },
date: 1700000100,
text: undefined,
from: { id: 43, first_name: "Bob" },
voice: { file_id: "voice-2" },
},
allMedia: [{ path: "/tmp/voice2.ogg", contentType: "audio/ogg" }],
storeAllowFrom: [],
options: { forceWasMentioned: true },
bot: {
api: {
sendChatAction: vi.fn(),
setMessageReaction: vi.fn(),
},
} as never,
cfg: {
agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } },
channels: { telegram: {} },
messages: { groupChat: { mentionPatterns: ["\\bbot\\b"] } },
} as never,
account: { accountId: "default" } as never,
historyLimit: 0,
groupHistories: new Map(),
dmPolicy: "open",
allowFrom: [],
groupAllowFrom: [],
ackReactionScope: "off",
logger: { info: vi.fn() },
},
resolveGroupActivation: () => true,
resolveGroupRequireMention: () => true,
resolveTelegramGroupConfig: () => ({
@@ -90,4 +73,70 @@ describe("buildTelegramMessageContext audio transcript body", () => {
expect(transcribeFirstAudioMock).not.toHaveBeenCalled();
expect(ctx?.ctxPayload?.Body).toContain("<media:audio>");
});
it("uses topic disableAudioPreflight=false to override group disableAudioPreflight=true", async () => {
transcribeFirstAudioMock.mockResolvedValueOnce("topic override transcript");
const ctx = await buildTelegramMessageContextForTest({
message: {
message_id: 3,
chat: { id: -1001234567892, type: "supergroup", title: "Test Group 3" },
date: 1700000200,
text: undefined,
from: { id: 44, first_name: "Cara" },
voice: { file_id: "voice-3" },
},
allMedia: [{ path: "/tmp/voice3.ogg", contentType: "audio/ogg" }],
options: { forceWasMentioned: true },
cfg: {
agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } },
channels: { telegram: {} },
messages: { groupChat: { mentionPatterns: ["\\bbot\\b"] } },
},
resolveGroupActivation: () => true,
resolveGroupRequireMention: () => true,
resolveTelegramGroupConfig: () => ({
groupConfig: { requireMention: true, disableAudioPreflight: true },
topicConfig: { disableAudioPreflight: false },
}),
});
expect(ctx).not.toBeNull();
expect(transcribeFirstAudioMock).toHaveBeenCalledTimes(1);
expect(ctx?.ctxPayload?.BodyForAgent).toBe("topic override transcript");
expect(ctx?.ctxPayload?.Body).toContain("topic override transcript");
expect(ctx?.ctxPayload?.Body).not.toContain("<media:audio>");
});
it("uses topic disableAudioPreflight=true to override group disableAudioPreflight=false", async () => {
transcribeFirstAudioMock.mockClear();
const ctx = await buildTelegramMessageContextForTest({
message: {
message_id: 4,
chat: { id: -1001234567893, type: "supergroup", title: "Test Group 4" },
date: 1700000300,
text: undefined,
from: { id: 45, first_name: "Dan" },
voice: { file_id: "voice-4" },
},
allMedia: [{ path: "/tmp/voice4.ogg", contentType: "audio/ogg" }],
options: { forceWasMentioned: true },
cfg: {
agents: { defaults: { model: "anthropic/claude-opus-4-5", workspace: "/tmp/openclaw" } },
channels: { telegram: {} },
messages: { groupChat: { mentionPatterns: ["\\bbot\\b"] } },
},
resolveGroupActivation: () => true,
resolveGroupRequireMention: () => true,
resolveTelegramGroupConfig: () => ({
groupConfig: { requireMention: true, disableAudioPreflight: false },
topicConfig: { disableAudioPreflight: true },
}),
});
expect(ctx).not.toBeNull();
expect(transcribeFirstAudioMock).not.toHaveBeenCalled();
expect(ctx?.ctxPayload?.Body).toContain("<media:audio>");
});
});

View File

@@ -394,7 +394,10 @@ export const buildTelegramMessageContext = async ({
const hasAudio = allMedia.some((media) => media.contentType?.startsWith("audio/"));
const disableAudioPreflight =
firstDefined(topicConfig?.disableAudioPreflight, groupConfig?.disableAudioPreflight) === true;
firstDefined(
topicConfig?.disableAudioPreflight,
(groupConfig as TelegramGroupConfig | undefined)?.disableAudioPreflight,
) === true;
// Preflight audio transcription for mention detection in groups
// This allows voice notes to be checked for mentions before being dropped