fix(telegram): render interactive reply buttons

This commit is contained in:
Kelaw - Keshav's Agent
2026-05-03 01:27:41 +05:30
committed by Peter Steinberger
parent c979ed3a3a
commit 01a22d4ec9
2 changed files with 51 additions and 2 deletions

View File

@@ -28,7 +28,7 @@ import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
import { loadWebMedia } from "openclaw/plugin-sdk/web-media";
import type { TelegramInlineButtons } from "../button-types.js";
import { resolveTelegramInlineButtons, type TelegramInlineButtons } from "../button-types.js";
import { splitTelegramCaption } from "../caption.js";
import {
markdownToTelegramChunks,
@@ -803,7 +803,12 @@ export async function deliverReplies(params: {
try {
const deliveredCountBeforeReply = progress.deliveredCount;
const telegramData = reply.channelData?.telegram as TelegramReplyChannelData | undefined;
const replyMarkup = buildInlineKeyboard(telegramData?.buttons);
const replyMarkup = buildInlineKeyboard(
resolveTelegramInlineButtons({
buttons: telegramData?.buttons,
interactive: reply.interactive,
}),
);
let firstDeliveredMessageId: number | undefined;
if (mediaList.length === 0) {
firstDeliveredMessageId = await deliverTextReply({

View File

@@ -213,6 +213,50 @@ describe("deliverReplies", () => {
expect(sendMessage.mock.calls[0]?.[1]).toBe("hello");
});
it("renders shared interactive reply buttons as Telegram inline buttons", async () => {
const runtime = createRuntime(false);
const sendMessage = vi.fn().mockResolvedValue({ message_id: 2, chat: { id: "123" } });
const bot = createBot({ sendMessage });
await deliverWith({
replies: [
{
text: "Plugin bind approval required",
interactive: {
blocks: [
{
type: "buttons",
buttons: [
{ label: "Allow once", value: "pluginbind:req:o", style: "success" },
{ label: "Always allow", value: "pluginbind:req:a", style: "primary" },
{ label: "Deny", value: "pluginbind:req:d", style: "danger" },
],
},
],
},
},
],
runtime,
bot,
});
expect(sendMessage).toHaveBeenCalledWith(
"123",
"Plugin bind approval required",
expect.objectContaining({
reply_markup: {
inline_keyboard: [
[
{ text: "Allow once", callback_data: "pluginbind:req:o", style: "success" },
{ text: "Always allow", callback_data: "pluginbind:req:a", style: "primary" },
{ text: "Deny", callback_data: "pluginbind:req:d", style: "danger" },
],
],
},
}),
);
});
it("reports message_sent success=false when hooks blank out a text-only reply", async () => {
messageHookRunner.hasHooks.mockImplementation(
(name: string) => name === "message_sending" || name === "message_sent",