fix(telegram): extract and send buttons from channelData

Plugin commands can return buttons in channelData.telegram.buttons,
but deliverReplies() was ignoring them. Now we:

1. Extract buttons from reply.channelData?.telegram?.buttons
2. Build inline keyboard using buildInlineKeyboard()
3. Pass reply_markup to sendMessage()

Buttons are attached to the first text chunk when text is chunked.
This commit is contained in:
Joshua Mitchell
2026-01-25 16:15:40 -06:00
committed by Ayaan Zaidi
parent b8e6f0b135
commit db2395744b

View File

@@ -18,6 +18,7 @@ import { saveMediaBuffer } from "../../media/store.js";
import type { RuntimeEnv } from "../../runtime.js"; import type { RuntimeEnv } from "../../runtime.js";
import { loadWebMedia } from "../../web/media.js"; import { loadWebMedia } from "../../web/media.js";
import { resolveTelegramVoiceSend } from "../voice.js"; import { resolveTelegramVoiceSend } from "../voice.js";
import { buildInlineKeyboard } from "../send.js";
import { buildTelegramThreadParams, resolveTelegramReplyId } from "./helpers.js"; import { buildTelegramThreadParams, resolveTelegramReplyId } from "./helpers.js";
import type { TelegramContext } from "./types.js"; import type { TelegramContext } from "./types.js";
@@ -81,8 +82,18 @@ export async function deliverReplies(params: {
? [reply.mediaUrl] ? [reply.mediaUrl]
: []; : [];
if (mediaList.length === 0) { if (mediaList.length === 0) {
// Extract Telegram buttons from channelData
const telegramData = reply.channelData?.telegram as
| { buttons?: Array<Array<{ text: string; callback_data: string }>> }
| undefined;
const replyMarkup = buildInlineKeyboard(telegramData?.buttons);
const chunks = chunkText(reply.text || ""); const chunks = chunkText(reply.text || "");
for (const chunk of chunks) { for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i];
if (!chunk) continue;
// Only attach buttons to the first chunk
const shouldAttachButtons = i === 0 && replyMarkup;
await sendTelegramText(bot, chatId, chunk.html, runtime, { await sendTelegramText(bot, chatId, chunk.html, runtime, {
replyToMessageId: replyToMessageId:
replyToId && (replyToMode === "all" || !hasReplied) ? replyToId : undefined, replyToId && (replyToMode === "all" || !hasReplied) ? replyToId : undefined,
@@ -90,6 +101,7 @@ export async function deliverReplies(params: {
textMode: "html", textMode: "html",
plainText: chunk.text, plainText: chunk.text,
linkPreview, linkPreview,
replyMarkup: shouldAttachButtons ? replyMarkup : undefined,
}); });
if (replyToId && !hasReplied) { if (replyToId && !hasReplied) {
hasReplied = true; hasReplied = true;
@@ -322,6 +334,7 @@ async function sendTelegramText(
textMode?: "markdown" | "html"; textMode?: "markdown" | "html";
plainText?: string; plainText?: string;
linkPreview?: boolean; linkPreview?: boolean;
replyMarkup?: ReturnType<typeof buildInlineKeyboard>;
}, },
): Promise<number | undefined> { ): Promise<number | undefined> {
const baseParams = buildTelegramSendParams({ const baseParams = buildTelegramSendParams({
@@ -337,6 +350,7 @@ async function sendTelegramText(
const res = await bot.api.sendMessage(chatId, htmlText, { const res = await bot.api.sendMessage(chatId, htmlText, {
parse_mode: "HTML", parse_mode: "HTML",
...(linkPreviewOptions ? { link_preview_options: linkPreviewOptions } : {}), ...(linkPreviewOptions ? { link_preview_options: linkPreviewOptions } : {}),
...(opts?.replyMarkup ? { reply_markup: opts.replyMarkup } : {}),
...baseParams, ...baseParams,
}); });
return res.message_id; return res.message_id;
@@ -347,6 +361,7 @@ async function sendTelegramText(
const fallbackText = opts?.plainText ?? text; const fallbackText = opts?.plainText ?? text;
const res = await bot.api.sendMessage(chatId, fallbackText, { const res = await bot.api.sendMessage(chatId, fallbackText, {
...(linkPreviewOptions ? { link_preview_options: linkPreviewOptions } : {}), ...(linkPreviewOptions ? { link_preview_options: linkPreviewOptions } : {}),
...(opts?.replyMarkup ? { reply_markup: opts.replyMarkup } : {}),
...baseParams, ...baseParams,
}); });
return res.message_id; return res.message_id;