mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 02:34:32 +00:00
fix(telegram): degrade command sync on BOT_COMMANDS_TOO_MUCH
When Telegram rejects native command registration for excessive commands, progressively retry with fewer commands instead of hard-failing startup.
Made-with: Cursor
(cherry picked from commit a02c40483e)
This commit is contained in:
committed by
Peter Steinberger
parent
79176cc4e5
commit
1ba525f94d
@@ -86,4 +86,42 @@ describe("bot-native-command-menu", () => {
|
|||||||
|
|
||||||
expect(callOrder).toEqual(["delete", "set"]);
|
expect(callOrder).toEqual(["delete", "set"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("retries with fewer commands on BOT_COMMANDS_TOO_MUCH", async () => {
|
||||||
|
const deleteMyCommands = vi.fn(async () => undefined);
|
||||||
|
const setMyCommands = vi
|
||||||
|
.fn()
|
||||||
|
.mockRejectedValueOnce(new Error("400: Bad Request: BOT_COMMANDS_TOO_MUCH"))
|
||||||
|
.mockResolvedValue(undefined);
|
||||||
|
const runtimeLog = vi.fn();
|
||||||
|
|
||||||
|
syncTelegramMenuCommands({
|
||||||
|
bot: {
|
||||||
|
api: {
|
||||||
|
deleteMyCommands,
|
||||||
|
setMyCommands,
|
||||||
|
},
|
||||||
|
} as unknown as Parameters<typeof syncTelegramMenuCommands>[0]["bot"],
|
||||||
|
runtime: {
|
||||||
|
log: runtimeLog,
|
||||||
|
error: vi.fn(),
|
||||||
|
exit: vi.fn(),
|
||||||
|
} as Parameters<typeof syncTelegramMenuCommands>[0]["runtime"],
|
||||||
|
commandsToRegister: Array.from({ length: 100 }, (_, i) => ({
|
||||||
|
command: `cmd_${i}`,
|
||||||
|
description: `Command ${i}`,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
await vi.waitFor(() => {
|
||||||
|
expect(setMyCommands).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
const firstPayload = setMyCommands.mock.calls[0]?.[0] as Array<unknown>;
|
||||||
|
const secondPayload = setMyCommands.mock.calls[1]?.[0] as Array<unknown>;
|
||||||
|
expect(firstPayload).toHaveLength(100);
|
||||||
|
expect(secondPayload).toHaveLength(80);
|
||||||
|
expect(runtimeLog).toHaveBeenCalledWith(
|
||||||
|
"Telegram rejected 100 commands (BOT_COMMANDS_TOO_MUCH); retrying with 80.",
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import type { RuntimeEnv } from "../runtime.js";
|
|||||||
import { withTelegramApiErrorLogging } from "./api-logging.js";
|
import { withTelegramApiErrorLogging } from "./api-logging.js";
|
||||||
|
|
||||||
export const TELEGRAM_MAX_COMMANDS = 100;
|
export const TELEGRAM_MAX_COMMANDS = 100;
|
||||||
|
const TELEGRAM_COMMAND_RETRY_RATIO = 0.8;
|
||||||
|
|
||||||
export type TelegramMenuCommand = {
|
export type TelegramMenuCommand = {
|
||||||
command: string;
|
command: string;
|
||||||
@@ -18,6 +19,31 @@ type TelegramPluginCommandSpec = {
|
|||||||
description: string;
|
description: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isBotCommandsTooMuchError(err: unknown): boolean {
|
||||||
|
if (!err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const pattern = /\bBOT_COMMANDS_TOO_MUCH\b/i;
|
||||||
|
if (typeof err === "string") {
|
||||||
|
return pattern.test(err);
|
||||||
|
}
|
||||||
|
if (err instanceof Error) {
|
||||||
|
if (pattern.test(err.message)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof err === "object") {
|
||||||
|
const maybe = err as { description?: unknown; message?: unknown };
|
||||||
|
if (typeof maybe.description === "string" && pattern.test(maybe.description)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (typeof maybe.message === "string" && pattern.test(maybe.message)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export function buildPluginTelegramMenuCommands(params: {
|
export function buildPluginTelegramMenuCommands(params: {
|
||||||
specs: TelegramPluginCommandSpec[];
|
specs: TelegramPluginCommandSpec[];
|
||||||
existingCommands: Set<string>;
|
existingCommands: Set<string>;
|
||||||
@@ -93,11 +119,34 @@ export function syncTelegramMenuCommands(params: {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await withTelegramApiErrorLogging({
|
let retryCommands = commandsToRegister;
|
||||||
operation: "setMyCommands",
|
while (retryCommands.length > 0) {
|
||||||
runtime,
|
try {
|
||||||
fn: () => bot.api.setMyCommands(commandsToRegister),
|
await withTelegramApiErrorLogging({
|
||||||
});
|
operation: "setMyCommands",
|
||||||
|
runtime,
|
||||||
|
fn: () => bot.api.setMyCommands(retryCommands),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} catch (err) {
|
||||||
|
if (!isBotCommandsTooMuchError(err)) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
const nextCount = Math.floor(retryCommands.length * TELEGRAM_COMMAND_RETRY_RATIO);
|
||||||
|
const reducedCount =
|
||||||
|
nextCount < retryCommands.length ? nextCount : retryCommands.length - 1;
|
||||||
|
if (reducedCount <= 0) {
|
||||||
|
runtime.error?.(
|
||||||
|
"Telegram rejected native command registration (BOT_COMMANDS_TOO_MUCH); leaving menu empty. Reduce commands or disable channels.telegram.commands.native.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
runtime.log?.(
|
||||||
|
`Telegram rejected ${retryCommands.length} commands (BOT_COMMANDS_TOO_MUCH); retrying with ${reducedCount}.`,
|
||||||
|
);
|
||||||
|
retryCommands = retryCommands.slice(0, reducedCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void sync().catch((err) => {
|
void sync().catch((err) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user