mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 15:24:58 +00:00
fix: skip Telegram command sync when menu is unchanged (#32017)
Hash the command list and cache it to disk per account. On restart, compare the current hash against the cached one and skip the deleteMyCommands + setMyCommands round-trip when nothing changed. This prevents 429 rate-limit errors when the gateway restarts several times in quick succession. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Peter Steinberger
parent
4a2329e0af
commit
10fb632c9e
@@ -2,6 +2,7 @@ import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
buildCappedTelegramMenuCommands,
|
||||
buildPluginTelegramMenuCommands,
|
||||
hashCommandList,
|
||||
syncTelegramMenuCommands,
|
||||
} from "./bot-native-command-menu.js";
|
||||
|
||||
@@ -108,6 +109,66 @@ describe("bot-native-command-menu", () => {
|
||||
expect(callOrder).toEqual(["delete", "set"]);
|
||||
});
|
||||
|
||||
it("produces a stable hash regardless of command order (#32017)", () => {
|
||||
const commands = [
|
||||
{ command: "bravo", description: "B" },
|
||||
{ command: "alpha", description: "A" },
|
||||
];
|
||||
const reversed = [...commands].toReversed();
|
||||
expect(hashCommandList(commands)).toBe(hashCommandList(reversed));
|
||||
});
|
||||
|
||||
it("produces different hashes for different command lists (#32017)", () => {
|
||||
const a = [{ command: "alpha", description: "A" }];
|
||||
const b = [{ command: "alpha", description: "Changed" }];
|
||||
expect(hashCommandList(a)).not.toBe(hashCommandList(b));
|
||||
});
|
||||
|
||||
it("skips sync when command hash is unchanged (#32017)", async () => {
|
||||
const deleteMyCommands = vi.fn(async () => undefined);
|
||||
const setMyCommands = vi.fn(async () => undefined);
|
||||
const runtimeLog = vi.fn();
|
||||
|
||||
// Use a unique accountId so cached hashes from other tests don't interfere.
|
||||
const accountId = `test-skip-${Date.now()}`;
|
||||
const commands = [{ command: "skip_test", description: "Skip test command" }];
|
||||
|
||||
// First sync — no cached hash, should call setMyCommands.
|
||||
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: commands,
|
||||
accountId,
|
||||
});
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(setMyCommands).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// Second sync with the same commands — hash is cached, should skip.
|
||||
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: commands,
|
||||
accountId,
|
||||
});
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(runtimeLog).toHaveBeenCalledWith("telegram: command menu unchanged; skipping sync");
|
||||
});
|
||||
|
||||
// setMyCommands should NOT have been called a second time.
|
||||
expect(setMyCommands).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("retries with fewer commands on BOT_COMMANDS_TOO_MUCH", async () => {
|
||||
const deleteMyCommands = vi.fn(async () => undefined);
|
||||
const setMyCommands = vi
|
||||
|
||||
Reference in New Issue
Block a user