Руководство по стандартизации адаптеров (общие положения)
Данный документ представляет собой общее положение стандартизации адаптеров ErisPulse: устанавливает принципы и стандарты стандартизации для кроссплатформенного использования, карту стандартов, режимы обработки различий, процесс введения новых возможностей в стандарт и дает полное определение стандартов интерактивных компонентов (кнопки/клавиатура, выпадающий выбор и т.д.) и событий обратного вызова интерактивных действий. Любые разработчики адаптеров при реализации новых функций должны в первую очередь использовать стандартные определения, чтобы разработчики модулей могли получить последовательный опыт на любой платформе с помощью одного и того же кода — с одинаковыми именами, параметрами и возвращаемыми значениями.
1. Принципы стандартизации
- Единообразное наименование: Одно и то же понятие на всех платформах должно иметь одинаковое наименование (например, отмена сообщения —
delete_message, набор кнопок —keyboard), не завися от платформы. - Единообразные параметры: Структура параметров стандартных действий/сегментов/методов должна оставаться одинаковой на всех платформах; платформенно-специфичные параметры предоставляются как необязательные расширенные параметры или расширенные поля, не загрязняя стандартный сигнатуру.
- Единообразные возвращаемые значения: Все вызовы API/отправки должны возвращать стандартную структуру ответа (
status/retcode/data/message_id/message), стандартные поля вdata(например,user_id/user_name) должны иметь одинаковую семантику; платформенно-специфичные данные помещаются в{platform}_raw. - Обоснованное расширение: Платформенно-специфичные возможности должны иметь префикс
{platform}_(сегмент:yunhu_form; действие:yunhu.board; поле события:qqbot_button_id), четко указывая, что они не являются кроссплатформенными. - Абсорбция различий на уровне адаптера: Модульный код должен быть ориентирован на стандартное программирование, а различия между платформами должны обрабатываться адаптером (маппинг параметров, стандартизация полей, снижение возможностей), без необходимости написания платформенно-специфичных ветвлений в модуле.
- Не критическое снижение возможностей: При отсутствии поддержки какой-либо стандартной возможности платформой, должна происходить элегантная деградация (возвращается
retcode=10002, компоненты преобразуются в текст и помещаются вalt_message), без выброса исключений и прерывания логики модуля.
2. Стандартные карты
| Область | Стандартный документ | Охватываемое содержимое |
|---|---|---|
| Преобразование событий | Стандарт преобразования событий | Структура событий, стандартные сегменты сообщений (text/image/mention/reply/keyboard и др.), стандартные расширения платформы |
| Интерактивные компоненты | Этот документ §5 | Кнопки/клавиатуры, выпадающие списки, карточки, стандартные поля событий обратной связи, соглашения о модификаторах, сопоставление с платформами |
| API-действия | Стандарт API-действий | Стандартные действия OneBot12 (управление пользователями/группами/каналами/сообщениями/мета-действия) с единым интерфейсом и ApiDSL |
| Запросы и операции | Спецификация запросов и операций | Поля событий запроса (request_id) и DSL запросов (approve/reject) |
| Методы отправки | Спецификация методов отправки | Назначение, параметры, модификаторы и обратное преобразование (OB12→платформа) методов класса Send |
| Типы сессий | Стандарт типов сессий | Определения и сопоставления типов сессий (user/group/channel/guild/dms) |
| Ответы API | Стандарт ответов API | Стандартная структура ответа и соглашение о retcode |
3. Стандартизированный рабочий процесс (Как новые возможности попадают в стандарт)
Платформенные специфические возможности ({platform}_ префикс)
│ ≥2 платформы имеют подобные возможности
▼
Выявление общих черт (извлечение общих концепций и подмножества параметров)
│
▼
Проект стандарта (название + параметры + возвращаемое значение + таблица соответствия для каждой платформы)
│ Обзор
▼
Включение в общее руководство / документы по стандартам для различных областей + реализация базового класса фреймворка / адаптеров для обеспечения совместимости
│
▼
Стандартные сегменты / действия (без префикса) — модули могут использоваться на разных платформах
Пример: Кнопка изначально реализовывалась независимо на каждой платформе (telegram_inline_keyboard / Yunhu buttons / QQBot keyboard) → появляется на ≥3 платформах → извлекается общая структура (label/type/data + rows) → публикуется стандартный сегмент keyboard → адаптеры реализуют слой совместимости (декоратор принимает общую структуру + преобразование стандартного сегмента + прямая передача оригинального сегмента).
3.1 Правила именования
| Объект | Правило | Пример |
|---|---|---|
| Стандартный сегмент сообщения | Нижний регистр, общая концепция без префикса | keyboard, select, mention |
| Расширенный сегмент платформы | Префикс {platform}_ |
telegram_sticker, yunhu_form |
| Стандартное API действие | Стандартное имя OB12 (snake_case) | get_group_info, delete_message |
| Расширенное действие платформы | Префикс {platform}. или общее имя протокола |
yunhu.board, send_poke (расширение OB11) |
| Декоратор | PascalCase, общая возможность в базовом классе фреймворка | .Keyboard(rows), .At(uid) |
| Стандартное поле события | Общая концепция без префикса | interaction_id, button_data, request_id |
| Поле события платформы | Префикс {platform}_ |
qqbot_event_id, telegram_chat_id |
3.2 Правила параметров и возвращаемых значений
- Стандартные параметры во всех платформах имеют одинаковое имя и значение; единицы измерения/формат указываются в стандартизированном документе (например, временная метка в секундах, строковый идентификатор)
- Обязательные параметры — это общее подмножество возможностей всех платформ; расширенные возможности платформы — необязательные параметры
- Сильные ограничения платформы (например, в QQBot нельзя одновременно отправлять богатые медиа и event_id) обрабатываются адаптером автоматически/с понижением, и не передаются модулям
- Возвращаемые поля
dataстандартизированы для всех платформ; дополнительная информация платформы помещается во внутренние поляdataс именем платформы или{platform}_raw
4. Режимы обработки различий (уровень адаптера)
| Режим | Описание | Пример |
|---|---|---|
| Отображение параметров | Стандартные параметры → параметры платформы | delete_message(message_id) → TG deleteMessage(chat_id, message_id) (дополнение chat_id из регистра) |
| Преобразование структуры | Стандартный сегмент → структура платформы | Сегмент keyboard → inline_keyboard / buttons / клавиатура QQBot |
| Отображение действий | Стандартное имя действия → имя действия платформы | get_self_info → get_login_info (OB11) |
| Стандартизация полей | Ответ платформы → стандартные поля | getMe() → {user_id, user_name, user_displayname} |
| Синтез идентификатора | Генерация определенного ID, когда платформа не имеет оригинального идентификатора | Запрос на присоединение TG без ID → tjr_{chat}_{user}_{date} |
| Деградация возможностей | Текстуализация / возврат 10002 при отсутствии поддержки | Kook без клавиатуры → alt_message в текстовом формате; get_friend_list → 10002 |
| Нормализация | Платформенные "грязные" данные → стандартный формат | Отметка @ в QQBot openid → bot_id (нормализация имени) |
| Двухмаршрутная совместимость | Стандартная структура и структура платформы одновременно принимаются | .Keyboard() принимает общие rows или оригинальную структуру |
5. Стандартные интерактивные компоненты
5.1 Список компонентов и состояния
| Компонент | Стандартный тип сегмента | Состояние | Поддерживаемые платформы |
|---|---|---|---|
| Кнопка/клавиатура (keyboard) | keyboard |
✅ Стандартизирован | Telegram / Yunhu / QQBot |
| Выпадающий список (select) | select |
📋 Зарезервировано (структура см. §5.4) | Discord / Telegram(bot) |
| Карточка (card) | card |
📋 Зарезервировано (см. §5.5) | Kook / Yunhu(html) |
| Модальное окно (modal) | modal |
📋 Зарезервировано | Discord |
Правила иерархии модификаторов: Модификаторы отправки для общих интерактивных компонентов реализуются в Send-классе адаптера (базовый класс фреймворка не содержит их), именование следует §5.2, параметры соответствуют стандартной структуре данного документа.
5.2 keyboard Кнопка/внутренняя клавиатура
Структура сегмента сообщения (направление отправки)
{
"type": "keyboard",
"data": {
"rows": [
[
{"label": "Опция A", "type": "callback", "data": "vote:A"},
{"label": "Официальный сайт", "type": "link", "data": "https://example.com"}
]
]
}
}
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
data.rows |
Двумерный массив | Да | Каждый подмассив — строка кнопок |
rows[][].label |
str | Да | Текст, отображаемый на кнопке |
rows[][].type |
str | Да | callback (возврат данных при нажатии) / link (переход по URL) |
rows[][].data |
str | Да | Данные для вызова (callback) или адрес перехода (link) |
rows[][].* |
Any | Нет | Платформенно-специфичные дополнительные поля (например web_app, menus), адаптер отображает или игнорирует по возможностям |
Сопоставление с платформами
| Платформа | Стандартный сегмент → оригинальная структура | Оригинальная структура |
|---|---|---|
| Telegram | reply_markup.inline_keyboard: [{text, callback_data | url}] |
callback→callback_data (≤64 байт), link→url |
| Yunhu | content.buttons: [{label, action_type}] |
callback→action_type:2 + action + value, link→action_type:1 + url |
| QQBot | keyboard.content.rows: [{label, type, data}] |
callback→type:2 + data, link→type:0 + data (сообщение должно быть в формате markdown) |
| Kook | Модуль action-group карточки: [{type, text, value, click}] |
callback→click:return + value, link→click:link + url |
| Discord | components[].components: [{label, style, custom_id | url}] |
callback→style:1 + custom_id, link→style:5 + url |
Модификаторы отправки (реализуются в Send-классе каждого адаптера)
Общие модификаторы реализуются в Send-классе каждого адаптера (базовый класс фреймворка не изменяется):
.Keyboard(rows): стандартное наименование, принимает общую структуру rows из §5.2, генерирует стандартный сегментkeyboard(или преобразует в оригинальную структуру платформы), обрабатываетсяRaw_ob12.Buttons(rows): опциональный синоним, поведение идентично- Обратная совместимость: при обнаружении оригинальной структуры платформы — пропуск без ошибок и преобразований
- Платформенно-специфичные расширенные сегменты (например
telegram_inline_keyboard) пропускаются без изменений
# Одна и та же кодовая база, произвольная платформа (адаптеры реализуют модификаторы и преобразование)
rows = [[{"label": "Лайк", "type": "callback", "data": "like:1"},
{"label": "Главная", "type": "link", "data": "https://example.com"}]]
await adapter.Send.To("group", gid).Keyboard(rows).Text("Пожалуйста, выберите")
Список совместимых адаптеров: QQBot / Telegram / Yunhu реализованы (модификаторы + преобразование стандартных сегментов); новые адаптеры реализуют по данному документу (см. §7 Checklist).
5.3 События интерактивного ответа (после нажатия кнопки)
События, отправляемые платформой после нажатия кнопки, должны содержать следующие стандартные поля (detail_type может сохранять оригинальное название платформы):
| Стандартное поле | Тип | Обязательно | Описание |
|---|---|---|---|
interaction_id |
str | Да | ID текущей интеракции (используется для ответа, например, индикатор загрузки/уведомление) |
button_data |
str | Да | Данные, возвращаемые кнопкой (см. §5.2 data) |
button_label |
str | Нет | Текст, отображаемый на кнопке |
user_id |
str | Да | ID пользователя, нажавшего |
message_id |
str | Нет | ID сообщения, в котором находится кнопка |
group_id / channel_id |
str | Нет | ID сессии/чат-канала |
Поле detail_type: сохраняется оригинальное название платформы (qqbot_interaction / telegram_callback_query / yunhu_a2ui_button и т.д.), но стандартные поля должны быть заполнены — модули могут использовать event.get("button_data") для получения данных на кроссплатформенной основе.
Рекомендуемые расширения Event (предоставляются EventMixin адаптера):
def get_button_data(self) -> str: ... # button_data
def get_interaction_id(self) -> str: ... # interaction_id
Ответ на интеракцию (в зависимости от возможностей платформы): adapter.reply_interaction(interaction_id, code=0) (QQBot) / answerCallbackQuery (Telegram) и т.д., именование следует семейству методов платформы, не обязательно унифицировать.
Сопоставление событий интеракции по платформам
| Платформа | Оригинальное событие | detail_type | Источник interaction_id | Источник button_data |
|---|---|---|---|---|
| Telegram | callback_query |
telegram_callback_query (notice) |
callback_query.id |
callback_query.data |
| Yunhu | Событие нажатия кнопки | yunhu_button_click / yunhu_a2ui_button |
buttonId / sourceComponentId |
value / actionName |
| QQBot | INTERACTION_CREATE |
qqbot_interaction |
interaction.id |
data.resolved.button_data |
| Kook | Событие нажатия кнопки | kook_button_click |
msg_id+value |
value |
| Discord | INTERACTION_CREATE |
discord_interaction |
interaction.id |
data.custom_id |
5.4 select Выпадающий список (зарезервировано)
{
"type": "select",
"data": {
"placeholder": "Выберите",
"options": [
{"label": "Опция A", "data": "opt:A"},
{"label": "Опция B", "data": "opt:B"}
],
"min_values": 1,
"max_values": 1
}
}
События ответа повторяют поля из §5.3 (button_data = выбранный data, при множественном выборе — JSON-массив). Платформы с первоочередной реализацией: Discord (выпадающее меню), Telegram (переключение клавиатуры). Платформы без реализации должны в alt_message заменить сегмент текстовым списком.
5.5 card Карточка (зарезервирована, отложена стандартизация)
Структура карточек сильно различается (Kook — полнофункциональный модуль карточек, Yunhu — html, QQ — markdown+keyboard), стандартизация пока не проводится. Рекомендации:
- Более сложные карточки выражаются комбинацией
text+keyboard(достаточно для большинства сценариев) - Полнофункциональные карточки платформы продолжают использовать расширенные сегменты (например
kook_card) - Стандартизация будет рассмотрена при появлении ≥2 платформ с одинаковыми возможностями карточек
6. Кандидаты на будущее (Roadmap)
Следующие функции уже появляются или ожидается появление на ≥2 платформах, и их стандартизация будет осуществляться в порядке приоритета:
| Кандидат | Платформы | Приоритет | Примечание |
|---|---|---|---|
| Выпадающий список выбора (select) | Discord / Telegram | Высокий | Структурный черновик см. в §5.4 |
| Реакции/эмодзи (reactions) | QQBot / Telegram / Discord / Kook | Высокий | Стандартизация действий и событий с обеих сторон |
| Действия по управлению группой (мут/кик/одобрение) | QQBot / Облако-Озеро / OB11 | Высокий | Большинство уже реализовано как платформенные действия, ожидается стандартизация подписей |
| Анонсы/доска объявлений | Облако-Озеро / Telegram / Discord | Средний | Действия типа set_announcement |
| Модель ресурсов файлов (двухчастный file_id) | Все платформы | Низкий (отложено) | Отправка прямой передачи SendDSL.File(file, filename) уже является стандартным путем (URL/путь/bytes прямая передача, см. спецификацию методов отправки §2.1); модель file_id передается только при наличии на стороне сервера, см. стандарт API-действий §3.5 |
| Карточки (card) | Kook / Облако-Озеро | Низкий | Структурные различия, см. §5.5 |
| Формы (form) | Облако-Озеро | Низкий | Платформенно-специфичный, сохраняется префикс {platform}_ |
| Транскодирование/определение размера медиа | Все платформы | Низкий | Реализуется внутри адаптера, не стандартизируется для внешнего использования |
7. Стандартный чек-лист для разработчиков новых адаптеров
При разработке нового адаптера, пожалуйста, сверьтесь с этим списком (★ обязательные пункты, остальные рекомендуемые):
- ★ Преобразование событий в стандартную структуру OneBot12, наследование от
BaseConverter - ★ Поддержка стандартных сообщений (text/image/mention/reply/keyboard…; медиа-сегменты обрабатываются с помощью иерархии повышения и понижения по форме, как указано в спецификации метода отправки §2.1)
- ★ Реализация
Raw_ob12(включая преобразование стандартных сегментов в структуру платформы; обязательная реализация стандартного сегментаkeyboard) - ★ Возврат стандартной структуры ответа (
make_response/make_error) - ★ Поддержка нескольких аккаунтов:
AccountConfigClass(BotAccountConfig)+_resolve_account - ★ Класс Send наследует
BaseAdapter.Send, использование_apply_modifiers/send_context - ☆ DSL для API: стандартные действия сопоставляются с API платформы (см. стандарт действий API)
- ☆ DSL для запросов: события запроса содержат
request_id+accept/reject - ☆ Интерактивные компоненты: преобразование сегмента
keyboard+ стандартные поля для обратного вызова + модификаторы.Keyboard()/.Buttons()(реализация в классе Send адаптера) - ☆ EventMixin: методы платформы расширения, такие как
get_raw_event()/get_button_data() - ☆ Задачи жизненного цикла с использованием
runtime.spawn_background - ☆ Чтение конфигурации с использованием
self.cfg - ☆ Мягкие зависимости фреймворка: отсутствие жесткой зависимости от ErisPulse + проверка версии во время выполнения
- ☆ i18n: многоязычные конфигурационные поля и логи
- ☆ Документация платформы в
platform-guide+platform-features.mdв репозитории адаптера
8. Связанные документы
- Стандарты для различных областей см. в §2 Стандартные карты
- Встроенные адаптеры фреймворка могут служить примерами реализации: QQBot (полная модель v5), OneBot11 (отображение DSL-интерфейса), Юньху (BaseConverter + расширение Web API)