🧩 Типы узлов (блоков)
Полный справочник всех доступных узлов в конструкторе Telegram Bot Builder.
📨 Триггеры
Триггеры — это точки входа в сценарий. Они определяют, когда бот начинает выполнять цепочку действий.
🔔 Триггер команды (command_trigger)
Срабатывает когда пользователь вводит команду (/start, /help, любая своя).
| Настройка | Описание |
|---|---|
| Команда | Текст команды (например /start) |
| Описание | Отображается в меню команд Telegram |
| Показать в меню | Добавить команду в список меню бота |
| Автопереход | Узел, на который перейти после срабатывания |
💬 Триггер текста (text_trigger)
Срабатывает когда пользователь отправляет определённое текстовое сообщение.
| Настройка | Описание |
|---|---|
| Тип совпадения | exact — точное совпадение, contains — содержит подстроку |
| Синонимы | Список слов/фраз для срабатывания |
| Автопереход | Узел для перехода |
📩 Триггер входящего сообщения (incoming_message_trigger)
Срабатывает на каждое входящее сообщение от пользователя (любой тип контента). Работает через middleware aiogram 3 — перехватывает сообщение до стандартных обработчиков и передаёт управление целевому узлу.
| Настройка | Поле | Описание |
|---|---|---|
| Тип чата | imtChatTypeFilter | any — любой чат, private — только личные, group — группы и супергруппы |
| ID группы | imtGroupChatId | Фильтр по конкретной группе (без префикса -100). Активен при imtChatTypeFilter: "group" |
| Источник ID группы | imtGroupChatIdSource | manual — значение из imtGroupChatId, variable — из переменной groupChatVariableName |
| Остановка цепочки | imtStopOnFlag | По умолчанию true. Если у пользователя установлен флаг _stop_processing (узел stop_processing), middleware не вызывает следующий handler и сбрасывает флаг |
| Автопереход | autoTransitionTo | Узел, на который перейти после срабатывания |
💡 Паттерн «охрана группы». Связка
incoming_message_trigger(фильтрgroup+ конкретныйimtGroupChatId) →stop_processing→ дальнейшая логика позволяет перехватывать сообщения в группе и блокировать стандартную обработку команд/текста для этого пользователя в текущем апдейте.
⚙️ Catch-all обработчики и предохранитель. Настройка «Catch-all обработчики» (тумблер в карточке бота, env
CATCH_ALL_HANDLERS=0|1, по умолчанию включена) управляет генерацией универсальных обработчиковhandle_unhandled_message,handle_unhandled_photo,fallback_callback_handler. Их можно отключить для лёгких ботов, чтобы убрать лишний код. Однако при наличииincoming_message_trigger,incoming_callback_triggerили динамических кнопок эти обработчики генерируются принудительно независимо от тумблера — без подходящего хендлера middleware этих триггеров в aiogram 3 не запускается. Это предохранитель-автодетект: формулаgenerateCatchAll = (флаг ≠ 0) || есть incoming-триггеры/динамические кнопки.
🔒 Защита контента. Настройка «Защита контента» (тумблер в карточке бота, env
PROTECT_CONTENT=0|1, по умолчанию выключена) управляет генерацией обёртки, которая добавляетprotect_content=Trueко всем исходящим сообщениям бота (запрет копирования/пересылки). Код защиты генерируется только при включённом флаге — при выключенной защите этот блок в сгенерированный код не попадает вовсе.
🔄 Живое обновление контента. Настройка «Живое обновление контента» (тумблер в карточке бота, env
CONTENT_CACHE=0|1, по умолчанию выключена) управляет генерацией машинерии live-reload контента из таблицы_content: функцийload_content/reload_content, фоновой перезагрузки кэша каждые 60 сек и мгновенного обновления через Redis pub/sub. При выключении (CONTENT_CACHE=0) эта машинерия не генерируется, но аксессорget_content(...)и кэш_content_cacheостаются всегда — тексты нод берутся из вшитых в код fallback-значений, а живое обновление из БД отключается. Включение повышает расход памяти.
� Триггер исходящего сообщения (outgoing_message_trigger)
Срабатывает когда бот отправляет сообщение. Позволяет реагировать на собственные действия бота.
�🔘 Триггер inline-кнопки (incoming_callback_trigger)
Срабатывает при нажатии inline-кнопки с определённым callback_data.
| Настройка | Описание |
|---|---|
| Паттерн callback_data | Строка для фильтрации (например work_) |
| Тип совпадения | startsWith / equals / contains |
| Удалить префикс | Убрать часть строки перед сохранением |
| Сохранить в переменную | Имя переменной для значения callback_data |
🔔 Триггер callback (callback_trigger)
Срабатывает на конкретный callback_data от inline-кнопки.
| Настройка | Описание |
|---|---|
| callback_data | Паттерн для перехвата |
| Тип совпадения | exact — точное, startswith — начинается с |
| Шаблон парсинга | Извлечение переменных из callback_data |
| Автопереход | Узел для перехода после срабатывания |
Паттерн: кросс-пользовательский сценарий (модерация, заявки)
Когда один пользователь (админ) действует в контексте другого (заявитель):
keyboard (кнопка с customCallbackData: "approve_{user_id}")
→ callback_trigger (startsWith "approve_", извлекает ID в _cb_dynamic_id)
→ bot_table READ (загружает данные по {_cb_dynamic_id})
→ edit_message / message (использует {app.*} из таблицы)
Это рекомендуемый способ реализации кросс-пользовательских сценариев. Не нужно менять движок — используй существующие ноды.
Кнопка с customCallbackData вида profile:name:{user_id} на input (или другую ноду без собственного startswith) ловится автоматически: виртуальный триггер слушает префикс profile:name:.
👥 Триггер сообщений в группе (group_message_trigger)
Срабатывает на сообщения в групповых чатах.
👤 Триггер участника (member_trigger)
Срабатывает на сервисные сообщения Telegram о входе или выходе участника из группы/супергруппы (new_chat_members, left_chat_member).
| Настройка | Поле | Описание |
|---|---|---|
| Тип события | memberEventType | join — вход, leave — выход, both — оба события (два обработчика) |
| ID группы | groupChatId | Опциональный фильтр по чату (без префикса -100) |
| Источник ID группы | groupChatIdSource | manual — из groupChatId, variable — из groupChatVariableName |
| Переменные входа | saveJoinedUserIdTo, saveJoinedUsernameTo | ID и username вошедшего участника (по умолчанию joined_user_id, joined_username) |
| Переменные выхода | saveLeftUserIdTo, saveLeftUsernameTo | ID и username вышедшего участника (по умолчанию left_user_id, left_username) |
| Автопереход | autoTransitionTo | Узел для перехода после срабатывания |
Ограничения:
- Бот должен быть добавлен в группу и видеть сервисные сообщения
- При
memberEventType: "both"генерируются отдельные обработчики для join и leave - Контекст сообщения (
chat_id,message_*) заполняется черезcapture_message_context
⏰ Триггер по расписанию (schedule_trigger)
Запускает цепочку автоматически по расписанию.
| Режим | Описание |
|---|---|
| Интервал | Каждые N минут |
| Ежедневно | В указанное время каждый день |
| Еженедельно | По выбранным дням недели в указанное время |
| Cron | Произвольное cron-выражение |
Дополнительные настройки: часовой пояс, запуск при старте бота, лимит параллельных выполнений.
🔌 API-триггер (api_trigger)
Принимает HTTP-запрос от внешней системы (платёжка, CRM, backend) и запускает цепочку.
| Настройка | Описание |
|---|---|
| Метод | GET, POST, PUT, PATCH, DELETE |
| Путь | /payment, /webhook/order и т.д. |
| Secret | Обязателен; заголовок X-Api-Secret или Authorization: Bearer |
| Сохранить body/query/headers | Имена переменных для данных запроса |
| Публичный URL | {API_BASE_URL}/api/hooks/{projectId}{apiPath} |
Ограничения MVP: max body 1 MB; rate limit на Node; бот офлайн → 503 bot_offline.
📤 Ответ API (api_response)
Завершает HTTP-запрос, инициированный api_trigger.
| Настройка | Описание |
|---|---|
| HTTP статус | Код ответа (200, 400, …) |
| Content-Type | application/json, text/plain, text/html |
| Тело | JSON/текст с {переменными} |
Без api_response в цепочке клиент получит 200 {"ok":true}; таймаут 30 с → 504.
💬 Сообщения и контент
📝 Текстовое сообщение (message)
Отправляет текстовое сообщение пользователю. Основной узел для коммуникации.
| Настройка | Описание |
|---|---|
| Текст | Текст сообщения (поддерживает {переменные}) |
| Форматирование | Без формата / HTML / Markdown |
| Клавиатура | Без кнопок / Inline / Reply |
| Сбор ввода | Ожидать ответ и сохранить в переменную |
| Типы ввода | Текст, фото, видео, аудио, документ |
| Условные сообщения | Разный текст в зависимости от условий |
| Только для админов | Ограничить доступ |
Форматирование текста:
none— обычный текстhtml— поддержка тегов<b>,<i>,<u>,<s>,<code>,<pre>,<a href="">,<tg-spoiler>markdown—*жирный*,_курсив_,`код`
ℹ️ Форматирование в режиме hot-reload (projectId / contentCache). Когда бот сгенерирован с горячей перезагрузкой контента,
parse_modeвычисляется в рантайме в переменную_parse_mode. СтатичныйformatModeноды имеет приоритет:markdown→Markdown,html→HTML. ПриformatMode: "none"(или отсутствии поля) работает автодетект —HTMLподставляется только если в тексте есть HTML-теги (<b>,<i>,<u>,<s>,<code>,<pre>,<a,<tg-spoiler>), иначе форматирование отключено. Ограничение: режимformatModeстатичен (известен на генерации) и не перечитывается из таблицы контента — меняется только при перегенерации бота; динамически из текста определяется лишь HTML-fallback приnone.
📸 Медиа-узлы
| Узел | Что отправляет | Ключевое поле |
|---|---|---|
photo | Фотографию | imageUrl |
video | Видео | videoUrl |
audio | Аудиофайл | audioUrl |
document | Документ | documentUrl, documentName |
sticker | Стикер | — |
animation | GIF-анимацию | — |
location | Геолокацию | — |
contact | Контакт | — |
Все медиа-узлы поддерживают подпись (mediaCaption) и автопереход.
💾 Сохранить ответ (save_answer)
Сохраняет ответ пользователя (текст, фото, видео и т.д.) в переменную для дальнейшего использования в сценарии.
| Настройка | Описание |
|---|---|
| Переменная | Имя переменной для сохранения |
| Типы ввода | Какой контент принимать (текст, фото, видео, аудио, документ) |
⌨️ Клавиатура (keyboard)
Отдельный узел клавиатуры — набор кнопок, который можно привязать к любому сообщению. Позволяет переиспользовать одну клавиатуру в нескольких местах и динамически менять кнопки по нажатию.
При нажатии кнопки с переходом на keyboard-ноду — кнопки текущего сообщения обновляются через editMessageReplyMarkup без отправки нового сообщения.
🔧 Авто-нормализация при записи через API/MCP. Если у message-ноды заданы инлайн/reply-кнопки прямо внутри неё (непустой
buttonsиkeyboardType=inline/reply), при сохранении через API или MCP-инструменты они автоматически выносятся в отдельнуюkeyboard-ноду (каноничная модель). В самой message при этом проставляетсяkeyboardType: "none",buttons: []иkeyboardNodeIdсо ссылкой на созданную keyboard-ноду; рядом появляетсяkeyboard-нода со смещением +360 по X. Операция идемпотентна — повторная запись не создаёт дублей. Валидация выдаёт неблокирующее предупреждениеinline_keyboard_will_hoistдля таких message-нод.
✏️ Редактировать сообщение (edit_message)
Редактирует текст или кнопки уже отправленного сообщения.
| Настройка | Описание |
|---|---|
editKeyboardMode: 'node' | Берёт клавиатуру из привязанного keyboard-узла |
keyboardLayout | Если задан в keyboard-узле и autoLayout: false — кнопки группируются по рядам согласно layout |
Динамический callback (customCallbackData)
Кнопки, ведущие к edit_message, могут содержать customCallbackData с переменными (например "approve_{user_id}"). При нажатии динамическая часть извлекается в переменную {_cb_dynamic_id}, доступную в тексте редактирования и последующих узлах.
↗️ Переслать сообщение (forward_message)
Пересылает сообщение в другой чат.
⌨️ Кнопки
Кнопки добавляются к узлу сообщения. Тип клавиатуры:
- Inline — кнопки под сообщением
- Reply — кнопки под полем ввода
Действия кнопок
| Действие | Что происходит |
|---|---|
| Перейти на узел | Переход к другому блоку сценария |
| Открыть URL | Открывает ссылку в браузере |
| Mini App | Открывает Telegram Mini App |
| Скопировать текст | Копирует текст в буфер обмена |
| Запросить контакт | Запрашивает номер телефона |
| Запросить геолокацию | Запрашивает местоположение |
| Создать бота | Запрос на создание управляемого бота |
Дополнительно: перемешивание кнопок (shuffleButtons) для квизов и капч.
📋 Создать тему форума (create_forum_topic)
Создаёт новый топик в форум-группе Telegram.
🔌 Интеграции и логика
🌐 HTTP-запрос (http_request)
Отправляет запрос к любому внешнему API.
| Настройка | Описание |
|---|---|
| URL | Адрес API (поддерживает {переменные} и ключи env бота) |
| Метод | GET, POST, PUT, DELETE, PATCH |
| Заголовки | JSON с заголовками запроса ({имя} = сценарий + env) |
| Тело | JSON тело запроса |
| Auth | none / bearer / basic / header / query — поля токена поддерживают {VAR} из env бота |
| Таймаут | Время ожидания ответа (сек) |
| Сохранить ответ | Имя переменной для результата |
| Формат ответа | JSON (по умолчанию) или файл (base64) |
{имя} подставляется из переменных сценария и env бота (вкладка Бот → env у токена). При конфликте имён побеждают переменные сценария/FSM. Пример Bearer: httpRequestAuthBearerToken: "{API_TOKEN}".
🗄️ Таблица данных (bot_table)
Работа с внутренними таблицами проекта — без SQL, через визуальный интерфейс.
Операции
| Операция | Описание |
|---|---|
| Чтение | Получить строку(и) по условию |
| Вставка | Добавить новую строку (таблица создаётся автоматически) |
| Обновление | Изменить поля (атомарный increment/decrement) |
| Upsert | Вставить или обновить если существует |
| Удаление | Удалить строку(и) по условию |
| Подсчёт | Количество строк |
| Сумма / Макс / Мин / Среднее | Агрегация по числовой колонке |
| Уникальные | Список уникальных значений колонки |
| Удалить всё | Очистить таблицу |
Операторы условий: равно, не равно, больше, меньше, содержит, пусто, не пусто.
Операции обновления: установить, увеличить, уменьшить, минимум, максимум — все атомарные.
Формат результата: первая строка (объект), все строки (массив), одно значение, количество, случайная строка.
Поддерживает сортировку, лимит, смещение (пагинация) и динамические имена таблиц через переменные.
🐘 PostgreSQL запрос (psql_query)
Выполняет произвольный SQL-запрос к базе данных.
| Настройка | Описание |
|---|---|
| SQL-запрос | Любой SQL (поддерживает {переменные}) |
| Сохранить результат | Имя переменной |
| Формат результата | Первая строка / Все строки / Одно значение |
| Источник подключения | Встроенная БД / Переменная окружения / Строка подключения |
Когда использовать: сложные JOIN, аналитика, кросс-таблицы. Для простого CRUD лучше bot_table.
Преобразование файлов между форматами (например PDF → изображение, аудио → другой формат).
Ветвление логики: «если... то... иначе...»
| Настройка | Описание |
|---|---|
| Переменная | Какую переменную проверять |
| Ветки | Список условий с целевыми узлами |
Операторы: равно, не равно, содержит, не содержит, больше, меньше, пусто, не пусто, иначе.
Значения в условиях поддерживают переменные: {user.balance}, {item.price}.
📝 Установить переменную (set_variable)
Задаёт, изменяет или вычисляет переменные.
| Режим | Что делает | Пример |
|---|---|---|
| Текст | Простая подстановка | "Привет, {first_name}" |
| Выражение | Арифметика (+, -, *, /, %) | "{balance} - 50" |
| Случайное число | Число в диапазоне | от 500 до 900 |
| Случайный элемент | Из списка через запятую | "🔧,💥,💡,⚡" |
| Элемент массива | По индексу или ключу | data.users.0.name |
| Timestamp | Текущее время ± смещение | "90" = сейчас + 90 сек |
| Форматирование времени | Секунды → MM:SS | "{expires} - {now}" |
| Поиск в таблице | Lookup по условию | — |
| Замена подстроки | str_replace | "старое" → "новое" |
| Добавить в массив | json_push | JSON-объект в массив |
| Форматировать массив | json_format | Массив → строка |
| Regex извлечение | Извлечь по регулярке | "(\d+)\s*руб" группа 1 → "7216970" |
| Число из строки | extract_number | "{text}" → первое число |
| Разделить и взять | split_get | "{email}" sep=@ idx=1 → домен |
| JSON по ключу | json_get | "{api}" path=data.user.name |
| Подстрока | substring | "{id}" start=0 end=8 |
| Условие (если/иначе) | conditional | если {balance} > 1000 → "💰", иначе → "💸" |
| Нижний регистр | lowercase | "{text}" → все строчные |
| Верхний регистр | uppercase | "{text}" → все заглавные |
| Убрать пробелы | trim | " текст " → "текст" |
| Длина | length | "[1,2,3]" → "3" |
| Объединение массивов | array_concat | value: "{arr1}", concatWith: "{arr2}" → склеенный массив |
Сохранение в PostgreSQL (persistToDb)
У каждого присваивания в массиве assignments можно включить флаг persistToDb: true. После записи значения в user_data оно дополнительно сохраняется в PostgreSQL через set_user_var — переменная переживает перезапуск бота (при включённой пользовательской БД).
{ "id": "a1", "variable": "reputation", "value": "{reputation} + 10", "mode": "expression", "persistToDb": true }
ℹ️ Работает только при включённой пользовательской БД бота. Без неё флаг игнорируется.
🛑 Стоп обработки (stop_processing)
Устанавливает user_data[user_id]['_stop_processing'] = True для текущего пользователя. Используется вместе с incoming_message_trigger и включённым imtStopOnFlag: middleware триггера увидит флаг и не вызовет следующий handler в цепочке aiogram для этого апдейта.
| Настройка | Описание |
|---|---|
| Автопереход | Следующий узел после установки флага (enableAutoTransition: true) |
Флаг сбрасывается автоматически при следующем проходе middleware incoming_message_trigger.
📊 Счётчик частоты (rate_counter)
In-memory счётчик событий в скользящем временном окне (deque по ключу). Каждый вызов узла добавляет метку времени и удаляет устаревшие записи за пределами окна.
| Настройка | Поле | Описание |
|---|---|---|
| Ключ счётчика | counterKey | Уникальный ключ (поддерживает {переменные}, напр. {user_id}) |
| Окно | windowSeconds | Размер окна в секундах (по умолчанию 60) |
| Результат | saveResultTo | Имя переменной для количества событий в окне (по умолчанию rate_count) |
| Автопереход | autoTransitionTo | Следующий узел (enableAutoTransition: true) |
Ограничения:
- Данные хранятся только в памяти процесса — при перезапуске бота счётчики обнуляются
- Типичное применение: антиспам, лимиты действий, детекция флуда
🧮 Inline-выражения ({=...})
Вычисление формул прямо в тексте сообщения без отдельной ноды set_variable.
| Синтаксис | Результат | Описание |
|---|---|---|
{=credits - price} | 3800 | Арифметика |
{=thousands(credits)} | 5 000 | Форматирование числа |
{=round(score / games, 2)} | 70.58 | Округление |
{=max(hp - damage, 0)} | 0 | Функции min/max |
Поддерживается в любом текстовом поле: messageText, mediaCaption, button text, httpRequestUrl и т.д.
Доступные функции: round, abs, int, float, min, max, str, reversed, thousands.
Доступные методы строк: replace, strip, lstrip, rstrip, lower, upper, startswith, endswith, split, join, count, find, format и проверки isdigit, isnumeric, isdecimal, isalpha, isalnum, isspace.
Генераторы и comprehension не поддерживаются — такое выражение вернётся как текст, не вычислившись. Чтобы отсечь нечисловой ввод, применяйте isdigit, а не comprehension.
При ошибке или невалидном выражении текст {=...} остаётся без изменений (бот не падает).
🔄 Цикл (loop)
Итерация по массиву данных.
| Настройка | Описание |
|---|---|
| Источник | Переменная с массивом |
| Переменная элемента | Имя для текущего элемента (доступ: {item.field}) |
| Переменная индекса | Имя для номера итерации (0, 1, 2...) |
| Параллельно | Выполнять все итерации одновременно |
| Задержка | Пауза между итерациями (сек) |
| Лимит | Максимум итераций (0 = без лимита) |
| Тело цикла | Первый узел внутри цикла |
| После цикла | Узел после завершения |
⚡ Параллельная группа (parallel_split)
Одновременный запуск нескольких независимых веток сценария (fan-out). Каждая ветка — отдельная asyncio-задача; точки сбора (join) нет.
| Настройка | Описание |
|---|---|
| Ветки | Список веток: подпись + стартовая нода. Каждая ветка — отдельный порт на холсте |
| При ошибке ветки | Необязательная нода-фоллбек (обычно setv-инкремент, чтобы сбор не завис) |
| Максимум одновременных | Лимит веток через Semaphore (0 = без лимита, по умолчанию 5) — защита от FloodWait |
| Не запускать повторно | Включено по умолчанию — повторное нажатие блокируется, пока прогон не завершён |
| Ждать завершения всех | По умолчанию выключено (fire-and-forget) |
Сбор результатов (join без join-ноды): каждая ветка в конце инкрементит счётчик
(set_variable, mode=expression — инкремент атомарный), а condition проверяет
«все ли финишировали» — последняя завершившаяся ветка запускает итог.
Ограничения:
- Внутри веток нельзя использовать
input— FSM один на пользователя - Триггеры внутри веток не имеют смысла (это точки входа)
- Сброс счётчика сбора ставить до ноды, не внутри веток
Подробная концепция и сценарии: docs/futures/nodes/parallel-split-node.md.
⏱️ Задержка (delay)
Пауза перед следующим действием.
| Настройка | Описание |
|---|---|
| Время | Значение (поддерживает {переменные}; для секунд — дробные, напр. 0.1) |
| Единица | Секунды / минуты / часы / дни / недели |
| Режим | Блокирующий — ждёт, потом продолжает. Фоновый — текущая цепочка завершается, переход через N времени |
💻 Python-код (code)
Выполняет произвольный Python как тело async-функции. Позволяет заменить длинную цепочку userbot-нод одним узлом.
| Настройка | Описание |
|---|---|
| Скрипт | Async-тело с await (не оборачивать в async def самому) |
| Следующий узел | autoTransitionTo + enableAutoTransition: true |
Пространство имён
| Имя | Что это |
|---|---|
| переменные пользователя | Доступны просто по имени, без user_data[...] |
client, userbot_client | Telethon-клиент юзербота (тот же, что у userbot-узлов) |
bot | Экземпляр aiogram Bot — правка сообщений самого бота, прогрессбар |
user_id | ID текущего пользователя |
user_data | Переменные текущего пользователя |
all_user_data | Все пользователи: all_user_data[user_id] |
set_user_var | Функция записи переменной пользователя |
callback_query, state | Объекты aiogram текущего апдейта, могут быть None |
asyncio, json, re, math, datetime, logging, Button, events | Предзагруженные модули |
Возврат значений
Присваивание на верхнем уровне кода автоматически сохраняется в переменные пользователя:
lucky_payment = 8942
Внутри вложенных функций локальное присваивание наружу не попадёт — пишите напрямую в _ns:
async def _worker():
_ns['lucky_payment'] = 8942
set_user_var во вложенных функциях недоступна, только _ns[...].
Не сохраняются: имена, начинающиеся с _, предзагруженные модули, функции и классы.
Прогрессбар
bot в пространстве имён позволяет обновлять сообщение по ходу работы — полезно, когда узел опрашивает много внешних ботов:
await bot.edit_message_text('Опрашиваю… 3/15', chat_id=chat_id,
message_id=progress_msg_id, parse_mode='HTML')
Ограничения и грабли
- Таймаут 180 секунд на весь узел; ошибка не рвёт переход дальше.
- Нужны
USERBOT_API_ID,USERBOT_API_HASH,USERBOT_SESSION_STRING, иначе Telethon-вызовы не сработают (остальной Python — сработает). - Self-hosted: полный доступ к сессии аккаунта, без RestrictedPython.
- Одна userbot-сессия на процесс. Не запускайте параллельно внешний скрипт на той же сессии — Telegram может разлогинить одного из клиентов.
asyncio.wait_forначинает отсчёт сразу. Если задачи ждут в очереди семафора, таймаут выгорит на ожидании — ставьтеwait_forвнутри воркера, а не вокруг всей очереди.MessageButton.click()у Telethon ждётanswerCallbackQueryи падает сBotResponseTimeoutError, если бот не отвечает. Оборачивайте вasyncio.wait_for(..., timeout=2..3).
📥 Ожидание ввода (input)
Единственный способ сбора ввода. Message-нода только отправляет вопрос, input-нода ожидает и сохраняет ответ.
⛔ Поля
collectUserInput,inputVariableв message-ноде — запрещены. Используйте только отдельную нодуinput.
Типичные цепочки:
- Текстовый ввод:
message→input→ следующий узел - Кнопочный ввод:
message→keyboard→input (callback)→ следующий узел
| Настройка | Описание |
|---|---|
| Переменная | Куда сохранить ответ |
| Тип ввода | Текст / фото / видео / аудио / документ / геолокация / контакт / callback |
| Следующий узел | Куда перейти после получения ответа |
| Режим записи | Заменить / добавить к существующему |
| Валидация | email / phone / number / min-max длина |
| Сохранить метаданные | Дополнительные переменные с информацией о файле |
| Таймаут ожидания | inputTimeout — лимит в секундах (число > 0). По истечении FSM сбрасывается, пользователю отправляется inputTimeoutMessage |
| Сообщение при таймауте | inputTimeoutMessage — текст при истечении (по умолчанию «Время ожидания истекло.») |
Отмена формы (/cancel)
При активном сборе ввода бот автоматически регистрирует команду /cancel. По ней вызывается _clear_form_session — FSM сбрасывается, пользователь получает ответ «Форма отменена.». Обработчик генерируется только если в проекте есть хотя бы одна input-нода с активным сбором ввода.
Метаданные медиа
При включении "Сохранить метаданные медиа" для медиа-типов (фото, видео, аудио, документ) бот автоматически создаёт дополнительные переменные с суффиксами:
| Суффикс | Описание | Типы |
|---|---|---|
_file_id | Telegram file_id | все |
_file_unique_id | Уникальный ID файла | все |
_thumbnail | file_id обложки | видео, аудио, документ |
_duration | Длительность (сек) | видео, аудио |
_file_size | Размер файла (байт) | все |
_file_name | Имя файла | видео, аудио, документ |
_width / _height | Размеры (px) | фото, видео |
_mime_type | MIME тип | видео, аудио, документ |
_title / _performer | Название / исполнитель | аудио |
_small_file_id | file_id миниатюры | фото |
_all_sizes | JSON всех размеров | фото |
Пользователь может выбрать какие метаданные сохранять и задать кастомные имена переменных.
✏️ Действия с сообщениями
| Узел | Что делает |
|---|---|
delete_message | Удаляет одно или несколько сообщений |
pin_message | Закрепляет сообщение в чате |
unpin_message | Открепляет сообщение |
answer_callback_query | Всплывающее уведомление при нажатии inline-кнопки |
🗑️ Удалить сообщение (delete_message)
Полноценная action-нода для удаления сообщений. Может стоять в любом месте сценария.
| Настройка | Описание |
|---|---|
| Источник сообщения | current_message — текущее сообщение пользователя |
last_bot_message — последнее сообщение бота | |
reply_message — сообщение, на которое ответили (reply) | |
range_from_reply — все сообщения от reply до текущего (пург) | |
last_n — последние N сообщений (по диапазону ID) | |
custom — указать ID вручную или через {переменную} | |
| Чат | current_chat — текущий чат |
custom — указать ID чата или {переменную} | |
| Игнорировать ошибки | Не прерывать сценарий если сообщение не найдено (вкл по умолчанию) |
| Массовое удаление | Переменная с JSON-массивом message_id (до 100 за вызов, автобатчинг) |
| Автопереход | Следующий узел |
Ограничения Telegram:
- Бот удаляет чужие сообщения только в группах (нужны права
can_delete_messages) - Сообщения старше 48 часов удалить нельзя
- В личных чатах бот удаляет только свои сообщения
deleteMessagesпринимает до 100 ID за один вызов (автоматически разбивается на батчи)
👥 Действия с пользователями (группы)
| Узел | Что делает |
|---|---|
ban_user | Забанить пользователя в группе |
unban_user | Разбанить |
mute_user | Замутить (запретить писать) |
unmute_user | Размутить |
kick_user | Исключить пользователя из группы |
promote_user | Назначить администратором |
demote_user | Снять права администратора |
admin_rights | Установить конкретные права |
👢 Исключить пользователя (kick_user)
Исключает пользователя из группы через unbanChatMember(only_if_banned=False). Пользователь удаляется из чата, но может вернуться по ссылке-приглашению.
| Настройка | Описание |
|---|---|
| Источник пользователя | current_user — отправитель сообщения-триггера |
reply_user — автор сообщения, на которое ответили (reply) | |
custom — указать ID вручную или через {переменную} | |
| Чат | current_chat — текущий чат |
custom — указать ID чата или {переменную} | |
| Игнорировать ошибки | Не прерывать сценарий если пользователь не в чате или бот не имеет прав (вкл по умолчанию) |
Ограничения Telegram:
- Бот должен быть админом с правом «Блокировка участников» (
can_restrict_members) - Работает только в группах и супергруппах
🔗 Переменные
Переменные используются в текстах, URL, SQL-запросах и других полях через синтаксис {имя}.
Системные переменные
| Переменная | Описание |
|---|---|
{user_id} | Telegram ID пользователя |
{username} | Username пользователя |
{first_name} | Имя |
{last_name} | Фамилия |
{chat_id} | ID чата (заполняется при входящем сообщении) |
{chat_type} | Тип чата: private, group, supergroup, channel |
{message_text} | Текст или подпись последнего сообщения |
{message_type} | Тип содержимого: text, photo, video, document и т.д. |
{callback_data} | Данные нажатой кнопки |
{reply_to_user_id} | ID автора сообщения, на которое ответили |
{reply_to_username} | Username автора сообщения-ответа |
{reply_to_first_name} | Имя автора сообщения-ответа |
{reply_to_last_name} | Фамилия автора сообщения-ответа |
{reply_to_message_id} | ID сообщения, на которое ответили |
{reply_to_text} | Текст сообщения, на которое ответили |
{message_id} | ID текущего сообщения |
Переменные
chat_id,chat_type,message_*иreply_to_*записываются функциейcapture_message_contextв обработчиках команд, текста, входящих сообщений и триггера участника (member_trigger). Переменныеreply_to_*заполняются только если входящее сообщение является ответом (reply) на другое сообщение; иначе остаются пустыми.
Пользовательские переменные
Создаются через узлы set_variable, bot_table, http_request, psql_query и сбор ввода.
Вложенный доступ: {response.data.user.name}, {profile.balance}.
🔗 Связи между узлами
| Способ связи | Описание |
|---|---|
| Автопереход | Автоматический переход после выполнения узла |
| Кнопка → узел | Переход при нажатии кнопки |
| Ветка условия → узел | Переход по результату проверки |
| После цикла → узел | Переход после завершения всех итераций |
💡 Рекомендации
Когда использовать bot_table vs psql_query
| Задача | Рекомендация |
|---|---|
| Простой CRUD (профиль, баланс) | bot_table — проще и безопаснее |
| Атомарный increment/decrement | bot_table — встроено |
| Сложные JOIN и аналитика | psql_query |
| Автосоздание таблицы | bot_table |
Типичные паттерны
- Регистрация:
/start→ upsert профиля → приветствие - Профиль:
/profile→ чтение из таблицы → вывод данных - Магазин: меню с кнопками → проверка баланса → списание → подтверждение
- Расписание: триггер по времени → SQL-обновление → отчёт в админ-чат
🟣 Юзербот (Telethon)
Узлы для работы через аккаунт пользователя (Telethon MTProto). Работают параллельно с основным ботом.
📤 Сообщение юзербота (userbot_message)
Отправляет сообщение от аккаунта пользователя через Telethon. Поддерживает текст, медиа, переменные, несколько получателей.
| Настройка | Описание |
|---|---|
| Получатели | Список entity: @username, числовой ID, {переменная}, 'me' |
| Текст сообщения | Поддерживает {переменные} и HTML/Markdown форматирование |
| Медиафайлы | Локальные файлы (/uploads/) или URL |
| Режим форматирования | html, markdown, none |
| Отключить превью ссылок | Не показывать превью URL в сообщении |
| Сохранить ID сообщения | Переменная для message_id отправленного сообщения |
| Сохранить ID ответа | Переменная для ID ответного сообщения от получателя (saveResponseIdTo) |
| Сохранить текст ответа | Переменная для текста ответного сообщения (saveResponseTextTo) |
| Сохранить кнопки ответа | Переменная для кнопок ответа как JSON-массив [{text, type, data?, url?}] (saveButtonsTo) |
| Автопереход | Узел для перехода после отправки |
Ограничения:
- Кнопки (inline/reply) НЕ поддерживаются — ограничение Telegram для user-аккаунтов
- File_id от Bot API нельзя использовать в Telethon (разные сессии)
- Лимит: ~50 сообщений/день разным пользователям, 1 сообщение/секунду в один чат
- Встроенная защита от FloodWait с автоматическим retry
Требования:
- В настройках бота должен быть включён и авторизован Telethon Userbot
- Переменные
USERBOT_API_ID,USERBOT_API_HASH,USERBOT_SESSION_STRINGв .env
👆 Нажать кнопку (userbot_click_button)
Нажимает inline-кнопку в сообщении через Telethon. Поддерживает поиск по тексту, callback_data или индексу.
| Настройка | Описание |
|---|---|
| Entity (чат) | Чат где находится сообщение с кнопками |
| Источник сообщения | Последнее сообщение / Конкретный ID |
| Message ID | ID сообщения (если конкретный) |
| Способ поиска | По тексту кнопки / По callback_data / По индексу (row, col) |
| Значение | Текст кнопки / callback_data / "0, 1" |
| Сохранить alert | Переменная для текста alert от бота |
| Сохранить текст | Переменная для текста обновлённого сообщения |
| Сохранить кнопки | Переменная для JSON массива кнопок (с типами) |
| Сохранить медиа | Переменная для медиа-объекта |
| Автопереход | Узел для перехода после нажатия |
Формат JSON кнопок:
[
{"text": "Купить", "data": "buy_btc", "type": "callback"},
{"text": "Сайт", "url": "https://...", "type": "url"},
{"text": "Меню", "type": "text"}
]
Типы кнопок: callback, url, text, switch_inline, web_app, request_phone, request_location, buy, game
🔍 Inline-запрос (userbot_inline_query)
Выполняет inline-запрос к боту (@bot query) и отправляет выбранный результат в чат.
| Настройка | Описание |
|---|---|
| Bot username | Username бота для inline-запроса |
| Query | Текст запроса (поддерживает {переменные}) |
| Отправить в тот же чат | Результат отправляется в чат с ботом |
| Целевой чат | Куда отправить (если не в тот же) |
| Индекс результата | Какой результат выбрать (0 = первый) |
| Сохранить title | Переменная для заголовка результата |
| Сохранить description | Переменная для описания результата |
| Сохранить ID сообщения | Переменная для ID отправленного |
| Автопереход | Узел для перехода после отправки |
🧰 Утилиты
📝 Комментарий (comment)
Текстовая заметка-стикер на холсте. Не влияет на логику бота — игнорируется при генерации Python-кода. Не имеет портов, связей и автоперехода.
Используется для пояснений к сценарию: помечать воронки, ветки, TODO, описывать назначение групп нод.
| Настройка | Описание |
|---|---|
| Текст заметки | Произвольный текст (поддерживает многострочный ввод) |
| Цвет заметки | yellow, blue, green, pink, gray — для визуального разделения зон |
Содержит только два поля — messageText и commentColor. Служебных полей сообщения (buttons, keyboardType и т.п.) у ноды нет.
Ограничения:
- Не генерирует кода и не участвует в потоке выполнения
- Соединить с другими нодами нельзя (нет портов)
- При авто-раскладке остаётся отдельным свободным блоком
- В превью на холсте отображается до 200 символов