fix: enforce Telegram menu cap + keep hidden commands callable (#15844) (thanks @battman21)

This commit is contained in:
Peter Steinberger
2026-02-14 01:37:24 +01:00
parent 7bf4d8280b
commit 7ab44f0a38
4 changed files with 64 additions and 2 deletions

View File

@@ -15,6 +15,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Agents/Heartbeat: stop auto-creating `HEARTBEAT.md` during workspace bootstrap so missing files continue to run heartbeat as documented. (#11766) Thanks @shadril238.
- Telegram: cap bot menu registration to Telegram's 100-command limit with an overflow warning while keeping typed hidden commands available. (#15844) Thanks @battman21.
- CLI: lazily load outbound provider dependencies and remove forced success-path exits so commands terminate naturally without killing intentional long-running foreground actions. (#12906) Thanks @DrCrinkle.
- Auto-reply/Heartbeat: strip sentence-ending `HEARTBEAT_OK` tokens even when followed by up to 4 punctuation characters, while preserving surrounding sentence punctuation. (#15847) Thanks @Spacefish.
- Clawdock: avoid Zsh readonly variable collisions in helper scripts. (#15501) Thanks @nkelner.

View File

@@ -23,6 +23,67 @@ vi.mock("../pairing/pairing-store.js", () => ({
}));
describe("registerTelegramNativeCommands (plugin auth)", () => {
it("caps menu registration at 100 while leaving hidden plugin handlers available", () => {
const specs = Array.from({ length: 101 }, (_, i) => ({
name: `cmd_${i}`,
description: `Command ${i}`,
}));
getPluginCommandSpecs.mockReturnValue(specs);
matchPluginCommand.mockReset();
executePluginCommand.mockReset();
deliverReplies.mockReset();
const handlers: Record<string, (ctx: unknown) => Promise<void>> = {};
const setMyCommands = vi.fn().mockResolvedValue(undefined);
const log = vi.fn();
const bot = {
api: {
setMyCommands,
sendMessage: vi.fn(),
},
command: (name: string, handler: (ctx: unknown) => Promise<void>) => {
handlers[name] = handler;
},
} as const;
registerTelegramNativeCommands({
bot: bot as unknown as Parameters<typeof registerTelegramNativeCommands>[0]["bot"],
cfg: {} as OpenClawConfig,
runtime: { log } as RuntimeEnv,
accountId: "default",
telegramCfg: {} as TelegramAccountConfig,
allowFrom: [],
groupAllowFrom: [],
replyToMode: "off",
textLimit: 4000,
useAccessGroups: false,
nativeEnabled: false,
nativeSkillsEnabled: false,
nativeDisabledExplicit: false,
resolveGroupPolicy: () =>
({
allowlistEnabled: false,
allowed: true,
}) as ChannelGroupPolicy,
resolveTelegramGroupConfig: () => ({
groupConfig: undefined,
topicConfig: undefined,
}),
shouldSkipUpdate: () => false,
opts: { token: "token" },
});
const registered = setMyCommands.mock.calls[0]?.[0] as Array<{
command: string;
description: string;
}>;
expect(registered).toHaveLength(100);
expect(registered[0]).toEqual({ command: "cmd_0", description: "Command 0" });
expect(registered[99]).toEqual({ command: "cmd_99", description: "Command 99" });
expect(log).toHaveBeenCalledWith(expect.stringContaining("registering first 100"));
expect(Object.keys(handlers)).toHaveLength(101);
});
it("allows requireAuth:false plugin command even when sender is unauthorized", async () => {
const command = {
name: "plugin",

View File

@@ -112,7 +112,7 @@ describe("registerTelegramNativeCommands", () => {
expect(registeredCommands).toHaveLength(100);
expect(registeredCommands).toEqual(customCommands.slice(0, 100));
expect(runtimeLog).toHaveBeenCalledWith(
"telegram: truncating 120 commands to 100 (Telegram Bot API limit)",
"Telegram limits bots to 100 commands. 120 configured; registering first 100. Use channels.telegram.commands.native: false to disable, or reduce skill/custom commands.",
);
});
});

View File

@@ -368,7 +368,7 @@ export const registerTelegramNativeCommands = ({
];
const TELEGRAM_MAX_COMMANDS = 100;
if (allCommandsFull.length > TELEGRAM_MAX_COMMANDS) {
runtime.warn?.(
runtime.log?.(
`Telegram limits bots to ${TELEGRAM_MAX_COMMANDS} commands. ` +
`${allCommandsFull.length} configured; registering first ${TELEGRAM_MAX_COMMANDS}. ` +
`Use channels.telegram.commands.native: false to disable, or reduce skill/custom commands.`,