fix(telegram): keep callback_data under Telegram's 64-byte cap
``InlineKeyboardButton(label, callback_data=label)`` fails Telegram's API when the label exceeds 64 bytes UTF-8. An LLM-generated long option (realistic in multilingual flows) used to 400 the ``send_message`` call silently — user got nothing, agent heard a successful retry-then-drop. Decouple display from wire: button text keeps the full label, callback_data gets truncated at a UTF-8 char boundary. Tap echoes the prefix back as the user message; the LLM understands a prefix of its own option just fine, and the display the user saw was always the full string. Locks: helper boundary behavior (ASCII, CJK, short labels pass through) and end-to-end ``_build_keyboard`` integration with an over-cap label. Made-with: Cursor
This commit is contained in:
@@ -1205,11 +1205,19 @@ class TelegramChannel(BaseChannel):
|
||||
if not buttons or not self.config.inline_keyboards:
|
||||
return None
|
||||
keyboard = [
|
||||
[InlineKeyboardButton(label, callback_data=label) for label in row]
|
||||
[InlineKeyboardButton(label, callback_data=self._safe_callback_data(label)) for label in row]
|
||||
for row in buttons
|
||||
]
|
||||
return InlineKeyboardMarkup(keyboard)
|
||||
|
||||
@staticmethod
|
||||
def _safe_callback_data(label: str) -> str:
|
||||
# Telegram caps callback_data at 64 bytes UTF-8; truncate at a char boundary so the keyboard still sends.
|
||||
encoded = label.encode("utf-8")
|
||||
if len(encoded) <= 64:
|
||||
return label
|
||||
return encoded[:64].decode("utf-8", errors="ignore")
|
||||
|
||||
@staticmethod
|
||||
def _buttons_as_text(buttons: list[list[str]]) -> str:
|
||||
# Buttons are semantic options; when we can't render a keyboard, the user still needs to see them.
|
||||
|
||||
Reference in New Issue
Block a user