mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 13:26:04 -06:00
refactor(telegram): unify interactive keyboard rendering (#128728)
* refactor(telegram): unify interactive keyboard rendering * chore(telegram): ratchet removed keyboard assertion
This commit is contained in:
committed by
GitHub
parent
898b1ce4b3
commit
15e9bea3cb
@@ -1279,7 +1279,7 @@ extensions/telegram/src/bot/body-helpers.ts 1
|
||||
extensions/telegram/src/bot/delivery.replies.ts 1
|
||||
extensions/telegram/src/bot/delivery.resolve-media.ts 1
|
||||
extensions/telegram/src/bot/helpers.ts 2
|
||||
extensions/telegram/src/button-types.ts 2
|
||||
extensions/telegram/src/button-types.ts 1
|
||||
extensions/telegram/src/callback-query-answer-state.ts 1
|
||||
extensions/telegram/src/channel-actions.ts 1
|
||||
extensions/telegram/src/channel.ts 1
|
||||
|
||||
@@ -53,6 +53,55 @@ describe("buildTelegramInteractiveButtons callback limits", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveTelegramInlineButtons precedence", () => {
|
||||
it("returns explicit buttons without reading lower-priority payloads", () => {
|
||||
const buttons = [[{ text: "Explicit", callback_data: "explicit" }]];
|
||||
const params = {
|
||||
buttons,
|
||||
get interactive(): never {
|
||||
throw new Error("unexpected interactive normalization");
|
||||
},
|
||||
get presentation(): never {
|
||||
throw new Error("unexpected presentation normalization");
|
||||
},
|
||||
};
|
||||
|
||||
expect(resolveTelegramInlineButtons(params)).toBe(buttons);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
description: "the legacy payload contains only text",
|
||||
interactive: { blocks: [{ type: "text", text: "Legacy heading" }] },
|
||||
expectedDropped: [],
|
||||
},
|
||||
{
|
||||
description: "every legacy callback exceeds the Telegram byte limit",
|
||||
interactive: {
|
||||
blocks: [{ type: "buttons", buttons: [{ label: "Oversized", value: "x".repeat(65) }] }],
|
||||
},
|
||||
expectedDropped: [
|
||||
{ label: "Oversized", reason: "callback_data_too_long", callbackDataBytes: 65 },
|
||||
],
|
||||
},
|
||||
])("falls back to presentation buttons when $description", ({ interactive, expectedDropped }) => {
|
||||
const dropped: Array<{ label: string; reason: string; callbackDataBytes?: number }> = [];
|
||||
|
||||
expect(
|
||||
resolveTelegramInlineButtons(
|
||||
{
|
||||
interactive,
|
||||
presentation: {
|
||||
blocks: [{ type: "buttons", buttons: [{ label: "Fallback", value: "fallback" }] }],
|
||||
},
|
||||
},
|
||||
{ onDroppedControl: (control) => dropped.push(control) },
|
||||
),
|
||||
).toEqual([[{ text: "Fallback", callback_data: "fallback", style: undefined }]]);
|
||||
expect(dropped).toEqual(expectedDropped);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildTelegramPresentationButtons", () => {
|
||||
it("builds inline buttons from presentation blocks", () => {
|
||||
expect(
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// Telegram plugin module implements button types behavior.
|
||||
import { parseExecApprovalCommandText } from "openclaw/plugin-sdk/approval-reply-runtime";
|
||||
import {
|
||||
reduceLegacyInteractiveReply,
|
||||
legacyInteractiveReplyToPresentation,
|
||||
isMessagePresentationInteractiveBlock,
|
||||
normalizeMessagePresentation,
|
||||
normalizeLegacyInteractiveReply,
|
||||
renderMessagePresentationFallbackText,
|
||||
resolveMessagePresentationButtonAction,
|
||||
type LegacyInteractiveReply,
|
||||
type MessagePresentation,
|
||||
type MessagePresentationButton,
|
||||
} from "openclaw/plugin-sdk/interactive-runtime";
|
||||
@@ -228,38 +227,6 @@ function chunkInteractiveButtons(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use buildTelegramPresentationButtons with MessagePresentation.
|
||||
*/
|
||||
function buildTelegramInteractiveButtons(
|
||||
interactive?: LegacyInteractiveReply,
|
||||
options?: TelegramButtonBuildOptions,
|
||||
): TelegramInlineButtons | undefined {
|
||||
const rows = reduceLegacyInteractiveReply(
|
||||
interactive,
|
||||
[] as TelegramInlineButton[][],
|
||||
(state, block) => {
|
||||
if (block.type === "buttons") {
|
||||
chunkInteractiveButtons(block.buttons, state, options);
|
||||
return state;
|
||||
}
|
||||
if (block.type === "select") {
|
||||
chunkInteractiveButtons(
|
||||
block.options.map((option) => ({
|
||||
label: option.label,
|
||||
action: option.action,
|
||||
value: option.value,
|
||||
})),
|
||||
state,
|
||||
options,
|
||||
);
|
||||
}
|
||||
return state;
|
||||
},
|
||||
);
|
||||
return rows.length > 0 ? rows : undefined;
|
||||
}
|
||||
|
||||
/** Convert portable presentation controls to Telegram inline keyboard rows. */
|
||||
export function buildTelegramPresentationButtons(
|
||||
presentation?: MessagePresentation,
|
||||
@@ -296,9 +263,16 @@ export function resolveTelegramInlineButtons(
|
||||
},
|
||||
options?: TelegramButtonBuildOptions,
|
||||
): TelegramInlineButtons | undefined {
|
||||
if (params.buttons) {
|
||||
return params.buttons;
|
||||
}
|
||||
|
||||
const interactive = normalizeLegacyInteractiveReply(params.interactive);
|
||||
return (
|
||||
params.buttons ??
|
||||
buildTelegramInteractiveButtons(normalizeLegacyInteractiveReply(params.interactive), options) ??
|
||||
buildTelegramPresentationButtons(
|
||||
interactive ? legacyInteractiveReplyToPresentation(interactive) : undefined,
|
||||
options,
|
||||
) ??
|
||||
buildTelegramPresentationButtons(normalizeMessagePresentation(params.presentation), options)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user