Перейти к содержанию

Миграция с aiogram 3.x

Знакомые концепции намеренно сохраняют знакомые имена:

aiogram aiomax2 Примечание
Bot Bot MAX token отправляется без Bearer
Dispatcher Dispatcher корневой router
Router Router observers и вложенные routers
Command("start") Command("start") добавляет CommandObject
F.text F.text собственный небольшой expression engine
Message Message реальные поля MAX; id хранится в body.mid
message.answer() message.answer() выбирает MAX chat_id или user_id
FSMContext FSMContext async storage API
State, StatesGroup те же имена похожий декларативный стиль

Простой handler

aiogram:

from aiogram import F, Router
from aiogram.filters import Command
from aiogram.types import Message

router = Router()


@router.message(Command("start"))
async def start(message: Message) -> None:
    await message.answer("Hello")

aiomax2:

from aiomax2 import F, Router
from aiomax2.filters import Command
from aiomax2.types import Message

router = Router()


@router.message(Command("start"))
async def start(message: Message) -> None:
    await message.answer("Hello")

Сходство заканчивается там, где различаются платформы.

Поля Message

# aiogram / Telegram
chat_id = message.chat.id
message_id = message.message_id

# aiomax2 / MAX
chat_id = message.chat_id
message_id = message.message_id  # удобное свойство поверх message.body.mid
recipient = message.recipient

В aiomax2 нет искусственного message.chat.id. В диалоге target может быть представлен recipient.user_id, а в чате/канале — recipient.chat_id.

Callback

MAX-событие содержит Callback и иногда исходный Message. Router передаёт удобный CallbackQuery, но операция соответствует POST /answers, а не Telegram answerCallbackQuery:

@router.callback_query(F.payload == "confirm")
async def confirm(callback: CallbackQuery) -> None:
    await callback.answer(notification="Подтверждено")


@router.bot_started()
async def started(event: BotStartedUpdate) -> None:
    # MAX передаёт chat_id, user, optional payload и locale.
    ...

Клавиатуры

На wire MAX использует attachment. Для знакомого DX можно использовать InlineKeyboardBuilder и convenience-параметр reply_markup:

builder = InlineKeyboardBuilder()
builder.button(text="OK", callback_data="confirm")
await message.answer("Выберите", reply_markup=builder.as_markup())

Это не Telegram Reply Keyboard: внутри всё равно создаётся MAX inline_keyboard attachment. Low-level вариант также сохранён:

keyboard = InlineKeyboardAttachmentRequest(
    payload=Keyboard(buttons=[[CallbackButton(text="OK", payload="confirm")]])
)
await message.answer("Выберите", attachments=[keyboard])

Используйте реальные типы кнопок и payload MAX. Telegram Reply Keyboard, ReplyKeyboardRemove и ForceReply не эмулируются.

Events, которых нет в Telegram

bot_started, bot_stopped, dialog muted/cleared/removed, comments и изменение прав администратора моделируются напрямую. Не пытайтесь преобразовывать их в похожие Telegram updates.

Запуск

В aiogram polling часто используют и в production. MAX ограничивает Long Polling по скорости и хранению событий и рекомендует Webhook. Для production перенесите startup на FastAPI/aiohttp adapter и создайте подписку через Bot.subscribe().

FSM и storage

Объявление StatesGroup похоже, но встроенное MemoryStorage локально одному процессу. Для нескольких workers понадобится внешнее storage. Автоматической совместимости с aiogram Redis storage нет.