Skip to content

Support rich messages in message manager - #532

Draft
Tishka17 wants to merge 5 commits into
developfrom
feature/rich_message
Draft

Tishka17 wants to merge 5 commits into
developfrom
feature/rich_message

Conversation

@Tishka17

Copy link
Copy Markdown
Owner

TODO:

  • Rich params provider as Widget
  • save and load rich params in old message

@coderabbitai

coderabbitai Bot commented Jun 13, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/rich_message
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@biradrags biradrags left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


@biradrags biradrags left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline-ревью по строкам. Дизайн RichFormat+RichParams в data норм, send-путь и фиксы html/md/async/link_preview ок. Блокеры — в edit-пути и совместимости, плюс фича пока не включается end-to-end (нет конкретного RichFormat). Детали в комментах ниже.

Не привязалось к строкам, но важно:

  • Публичный API: RichParams/RichParseMode/RichFormat нет в пакетном __init__.__all__, юзеры импортят из internal.
  • Тестов на rich-путь ноль; MockMessageManager без send_rich → тест с Window(rich=) упадёт AttributeError.
  • HTML-инъекция: rich-html строится из текста виджетов без экранирования, юзер-данные с <>& ломают разметку — нужен контракт/хелпер.

Готов взять edit_rich+_combine (главные рантайм-баги) отдельным PR.

Comment thread example/mega/bot.py
from bot_dialogs.main import main_dialog
from bot_dialogs.mutltiwidget import multiwidget_dialog
from bot_dialogs.reply_buttons import reply_kbd_dialog
from bot_dialogs.rich import rich_dialog

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Блокер. example/mega/bot_dialogs/rich.py в ветке нет → пример падает ModuleNotFoundError. Плюс конкретного класса под RichFormat нигде нет (только Protocol), rich=Rich(...) из примера в чате не импортируется → фичу нельзя включить end-to-end. Нужен Rich-класс + сам пример.

Comment thread pyproject.toml Outdated
]
dependencies = [
"aiogram>=3.14.0",
"aiogram>=3.29.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Блокер (совместимость). Floor aiogram>=3.14→>=3.29 двигает всем ради опциональной фичи. Вместе с безусловным импортом InputRichMessage и убранным ButtonStyle-шимом → юзеры на 3.14-3.28 ловят ImportError на старте, даже без rich. Вынести rich в extra [rich] + guarded import?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужна версия новее, не вижу смысла делать extra

InputMediaDocument,
InputMediaPhoto,
InputMediaVideo,
InputRichMessage,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Безусловный импорт InputRichMessage (есть только в aiogram 3.29) на уровне модуля → import aiogram_dialog падает на старых aiogram. См. коммент к pyproject.toml про extra [rich] + try/except.

# we cannot actually compare reply keyboards
(new_message.reply_markup or old_message.has_reply_keyboard) or
# formatting changed
(new_message.rich_params != old_message.rich_params) or

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Блокер. Сравнение всегда True для rich-окна: _combine (строка 63) строит OldMessage без rich_params, поле остаётся None, а тут set != None → лишний edit/resend на каждое взаимодействие, no-op оптимизация мертва. Фикс на строку: rich_params=sent_message.rich_params в _combine.

chat_id=old_message.chat.id,
business_connection_id=new_message.business_connection_id,
text=new_message.text,
rich_message=self._get_rich_input(new_message),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Блокер. edit_text всегда шлёт text + rich_message + parse_mode разом, а по Bot API text/rich_message взаимоисключающие. send-путь роутится в send_rich (поля убраны), edit — нет. Первый показ ок, любая перерисовка окна → TelegramBadRequest. Нужен edit_rich симметрично send_rich, либо delete-and-resend при rich в _can_edit.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не вижу где сказано что они взаимоисключающие, всё и так работает.

Comment thread src/aiogram_dialog/window.py Outdated
manager,
)

current_data["rich_params"] = rich_params

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

current_data["rich_params"] = rich_params инъектит computed-значение в getter-data юзера — прецедента в классе нет (parse_mode/protect_content так не прокидываются), течёт в jinja/format контекст, может затереть одноимённый ключ. Плюс избыточно — rich_params уже идёт прямым полем в NewMessage. Убрать, если виджетам не нужно читать из data.

@@ -1,5 +1,6 @@
from dataclasses import dataclass
from enum import Enum
from typing import Literal, TypeAlias

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Literal/TypeAlias больше не используются после перехода на RichParseMode → ruff F401 завалит CI.

UNKNOWN = object()


class RichParseMode(str, Enum):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit. Члены RichParseMode lowercase (html/markdown) против titlecase у aiogram ParseMode — путает при смешивании.

@dataclass
class RichParams:
parse_mode: RichParseMode
is_rtl: bool

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_rtl/skip_entity_detection без дефолтов, хотя в InputRichMessage опциональны → caller всегда пишет все три поля. is_rtl: bool = False / skip_entity_detection: bool = False?


@runtime_checkable
class RichFormat(Protocol):
async def render_rich_params(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit (×3): render_rich_params без @abstractmethod (соседние протоколы в файле ставят), нет финального newline (W292, строка 151), докстринг "Transform new_message" (150) ничего не описывает.

@orinowl orinowl mentioned this pull request Oct 19, 2026
@Tishka17

Copy link
Copy Markdown
Owner Author

Todo: check if we can edit from rich to not rich and vice versa

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants