UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

175 lines (174 loc) 8.1 kB
import { C as resolveMessagePresentationButtonAction, c as isMessagePresentationInteractiveBlock, d as normalizeLegacyInteractiveReply, f as normalizeMessagePresentation, l as legacyInteractiveReplyToPresentation, v as renderMessagePresentationFallbackText } from "./payload-DYE7bQ2k.js"; import { l as resolveAskUserQuestionOptionIndex } from "./reply-payload-Bfsi665c.js"; import { h as parseExecApprovalCommandText } from "./exec-approval-reply-ZdeEqz7J.js"; import "./approval-reply-runtime-CaHYlGF_.js"; import { c as hasTelegramApprovalCallbackPrefix, d as sanitizeTelegramCallbackData, n as buildTelegramOpaqueCallbackData, o as buildTelegramApprovalCallbackData, s as fitsTelegramCallbackData, t as buildTelegramNativeCommandCallbackData, u as rewriteTelegramApprovalDecisionAlias } from "./native-command-callback-data-C1RSVJRf.js"; //#region extensions/telegram/src/question-callback-data.ts const TELEGRAM_QUESTION_CALLBACK_PREFIXES = ["tgq1:", "tgqo1:"]; const QUESTION_RECORD_ID_PATTERN = /^ask_[a-f0-9]{32}$/u; function hasTelegramQuestionCallbackPrefix(data) { return TELEGRAM_QUESTION_CALLBACK_PREFIXES.some((prefix) => data?.startsWith(prefix) === true); } function buildTelegramQuestionCallbackData(callback) { if (!QUESTION_RECORD_ID_PATTERN.test(callback.questionId) || !Number.isInteger(callback.optionIndex) || callback.optionIndex < 0 || callback.optionIndex > 3) return; const data = `tgq1:${callback.questionId}:${callback.optionIndex}`; return fitsTelegramCallbackData(data) ? data : void 0; } function buildTelegramQuestionCustomInputCallbackData(questionId) { if (!QUESTION_RECORD_ID_PATTERN.test(questionId)) return; const data = `tgqo1:${questionId}`; return fitsTelegramCallbackData(data) ? data : void 0; } function parseTelegramQuestionCallbackData(data) { if (!hasTelegramQuestionCallbackPrefix(data) || !data || !fitsTelegramCallbackData(data)) return null; const selectMatch = /^tgq1:(ask_[a-f0-9]{32}):([0-3])$/u.exec(data); if (selectMatch?.[1] && selectMatch[2]) return { questionId: selectMatch[1], intent: "select", optionIndex: Number(selectMatch[2]) }; const customInputMatch = /^tgqo1:(ask_[a-f0-9]{32})$/u.exec(data); return customInputMatch?.[1] ? { questionId: customInputMatch[1], intent: "custom-input" } : null; } //#endregion //#region extensions/telegram/src/button-types.ts function appendTelegramDroppedControlFallback(text, controls) { const fallback = renderMessagePresentationFallbackText({ presentation: { blocks: [{ type: "buttons", buttons: controls.map((control) => ({ label: control.label, value: "unavailable" })) }] } }); if (!fallback || text === fallback || text.endsWith(`\n\n${fallback}`)) return text; return [text, fallback].filter(Boolean).join("\n\n"); } const TELEGRAM_INTERACTIVE_ROW_SIZE = 3; function toTelegramButtonStyle(style) { return style === "danger" || style === "success" || style === "primary" ? style : void 0; } function recordDroppedControl(button, options, reason, callbackData) { const callbackDataBytes = callbackData ? Buffer.byteLength(callbackData, "utf8") : void 0; options?.onDroppedControl?.({ label: button.label, reason: callbackDataBytes !== void 0 && callbackDataBytes > 64 ? "callback_data_too_long" : reason, ...callbackDataBytes !== void 0 ? { callbackDataBytes } : {} }); } function toTelegramInlineButton(button, options) { const style = toTelegramButtonStyle(button.style); const action = resolveMessagePresentationButtonAction(button); if (!action) return recordDroppedControl(button, options, "invalid_action"); if (action.type === "url") return { text: button.label, url: action.url, style }; if (action.type === "web-app") return options?.allowWebAppButtons === true && action.url ? { text: button.label, web_app: { url: action.url }, style } : recordDroppedControl(button, options, "web_app_unavailable"); if (action.type === "approval") { const callbackData = buildTelegramApprovalCallbackData(action); return callbackData ? { text: button.label, callback_data: callbackData, style } : recordDroppedControl(button, options, "invalid_action"); } if (action.type === "question") { const hasQuestionContext = options?.questionOptionIndices?.has(action.questionId) === true; if ("intent" in action) { const callbackData = hasQuestionContext ? buildTelegramQuestionCustomInputCallbackData(action.questionId) : void 0; return callbackData ? { text: button.label, callback_data: callbackData, style } : recordDroppedControl(button, options, "question_context_unavailable"); } const optionIndex = resolveAskUserQuestionOptionIndex({ questionOptionIndices: options?.questionOptionIndices, questionId: action.questionId, optionValue: action.optionValue }); if (optionIndex === void 0) return recordDroppedControl(button, options, "question_context_unavailable"); const callbackData = buildTelegramQuestionCallbackData({ questionId: action.questionId, optionIndex }); if (!callbackData) return recordDroppedControl(button, options, "invalid_action"); return { text: button.label, callback_data: callbackData, style }; } if (action.type === "command") { const command = rewriteTelegramApprovalDecisionAlias(action.command.trim()); const nativeCandidate = command ? buildTelegramNativeCommandCallbackData(command) : void 0; const callbackData = (nativeCandidate ? sanitizeTelegramCallbackData(nativeCandidate) : void 0) ?? (parseExecApprovalCommandText(command) ? sanitizeTelegramCallbackData(command) : void 0); return callbackData ? { text: button.label, callback_data: callbackData, style } : recordDroppedControl(button, options, "invalid_action", nativeCandidate); } const normalizedCallbackValue = action.value.trim(); const callbackDataCandidate = Boolean(button.action) || hasTelegramApprovalCallbackPrefix(normalizedCallbackValue) || hasTelegramQuestionCallbackPrefix(normalizedCallbackValue) ? buildTelegramOpaqueCallbackData(action.value) : action.value; const callbackData = sanitizeTelegramCallbackData(callbackDataCandidate); return callbackData ? { text: button.label, callback_data: callbackData, style } : recordDroppedControl(button, options, "invalid_action", callbackDataCandidate); } function chunkInteractiveButtons(buttons, rows, options) { let row = []; const flush = () => { if (row.length > 0) { rows.push(row); row = []; } }; for (const button of buttons) { const rendered = toTelegramInlineButton(button, options); if (!rendered) continue; if (resolveMessagePresentationButtonAction(button)?.type === "question") { flush(); rows.push([rendered]); continue; } row.push(rendered); if (row.length === TELEGRAM_INTERACTIVE_ROW_SIZE) flush(); } flush(); } /** Convert portable presentation controls to Telegram inline keyboard rows. */ function buildTelegramPresentationButtons(presentation, options) { const rows = []; for (const block of presentation?.blocks ?? []) { if (!isMessagePresentationInteractiveBlock(block)) continue; if (block.type === "buttons") { chunkInteractiveButtons(block.buttons, rows, options); continue; } chunkInteractiveButtons(block.options.map((option) => ({ label: option.label, action: option.action, value: option.value })), rows, options); } return rows.length > 0 ? rows : void 0; } /** Resolve Telegram inline buttons, preserving explicit and legacy button precedence. */ function resolveTelegramInlineButtons(params, options) { if (params.buttons) return params.buttons; const interactive = normalizeLegacyInteractiveReply(params.interactive); return buildTelegramPresentationButtons(interactive ? legacyInteractiveReplyToPresentation(interactive) : void 0, options) ?? buildTelegramPresentationButtons(normalizeMessagePresentation(params.presentation), options); } //#endregion export { parseTelegramQuestionCallbackData as a, hasTelegramQuestionCallbackPrefix as i, buildTelegramPresentationButtons as n, resolveTelegramInlineButtons as r, appendTelegramDroppedControlFallback as t };