fix(telegram): retry failed model callbacks

This commit is contained in:
Vincent Koc
2026-04-13 17:24:44 +01:00
parent bde246e7af
commit a78d922acf
2 changed files with 102 additions and 23 deletions

View File

@@ -9,6 +9,7 @@ const {
botCtorSpy,
commandSpy,
dispatchReplyWithBufferedBlockDispatcher,
editMessageTextSpy,
enqueueSystemEventSpy,
getLoadWebMediaMock,
getChatSpy,
@@ -2859,4 +2860,76 @@ describe("createTelegramBot", () => {
expect(enqueueSystemEventSpy).toHaveBeenCalledTimes(2);
expect(enqueueSystemEventSpy.mock.calls.at(-1)?.[0]).toContain("Telegram reaction added:");
});
it("retries model callback updates after a bubbled preflight failure", async () => {
loadConfig.mockReturnValue({
agents: {
defaults: {
model: "openai/gpt-5.4",
},
},
channels: {
telegram: {
dmPolicy: "open",
allowFrom: ["*"],
},
},
});
const buildModelsProviderDataMock =
telegramBotDepsForTest.buildModelsProviderData as unknown as ReturnType<typeof vi.fn>;
buildModelsProviderDataMock.mockClear();
editMessageTextSpy.mockClear();
createTelegramBot({ token: "tok" });
const callbackHandler = getOnHandler("callback_query");
const middlewares = middlewareUseSpy.mock.calls
.map((call) => call[0])
.filter(
(fn): fn is (ctx: Record<string, unknown>, next: () => Promise<void>) => Promise<void> =>
typeof fn === "function",
);
const runMiddlewareChain = async (ctx: Record<string, unknown>) => {
let idx = -1;
const dispatch = async (i: number): Promise<void> => {
if (i <= idx) {
throw new Error("middleware dispatch called multiple times");
}
idx = i;
const fn = middlewares[i];
if (!fn) {
await callbackHandler(ctx);
return;
}
await fn(ctx, async () => dispatch(i + 1));
};
await dispatch(0);
};
const ctx = {
update: { update_id: 666 },
callbackQuery: {
id: "cbq-model-retry-1",
data: "mdl_prov",
from: { id: 9, first_name: "Ada", username: "ada_bot" },
message: {
chat: { id: 1234, type: "private" },
date: 1736380800,
message_id: 18,
},
},
me: { username: "openclaw_bot" },
getFile: async () => ({ download: async () => new Uint8Array() }),
};
buildModelsProviderDataMock.mockImplementationOnce(async () => {
throw new Error("providers boom");
});
await expect(runMiddlewareChain(ctx)).rejects.toThrow("providers boom");
await runMiddlewareChain(ctx);
expect(buildModelsProviderDataMock).toHaveBeenCalledTimes(2);
expect(editMessageTextSpy).toHaveBeenCalledTimes(1);
expect(editMessageTextSpy.mock.calls[0]?.[2]).toContain("Select a provider:");
});
});