Перейти к основному содержимому

Документация Bot Builder для ИИ

Общий Python-воркер не сохраняет события Update в глобальном LRU свойства event_type aiogram 3.31.0: такой кеш удерживал бота и пространство имён выгруженного сценария. Защитная замена сохраняет определение типа события и ошибки неизвестного события; новых полей project.json нет. Применяется после обновления и перезапуска runtime; обновление версии aiogram требует повторной проверки совместимости.

Вложенные меню связываются переходами кнопок (action: "goto", target следующей keyboard-ноды). К сообщению привязывается только его исходная клавиатура через keyboardNodeId; переход по кнопке не переносит кнопки вложенного меню на стартовое сообщение при генерации.

Для inline-кнопки с customCallbackData генератор создаёт отдельный виртуальный callback-триггер. Целевая message-нода продолжает слушать свой идентификатор; явный callback_trigger с тем же значением имеет приоритет и исключает дублирование обработчиков. Динамический customCallbackData с {переменной} создаёт переход по префиксу также для message, start и command; edit_message обрабатывает такой префикс сама.

hideAfterClick — поддерживаемое поле отдельной inline-кнопки (data.buttons[i]), а не keyboard-ноды. Общий обработчик нажатий снимает клавиатуру до запуска целевой ноды независимо от её типа и настройки БД. Сообщение и текст нажатой кнопки сохраняются, цепочка продолжается. edit_message в режиме сохранения клавиатуры не восстанавливает снятое меню. Изменение применяется после повторной генерации и перезапуска бота.

Сбор пользовательского ответа в локальную переменную работает при отключённой БД пользователей и без логирования сообщений. Функция времени ответа генерируется независимо от этих настроек; для применения исправления к существующему боту нужны повторная генерация и перезапуск.

Адрес локального Telegram Bot API задаётся окружением запуска TELEGRAM_BOT_API_URL, а не полями JSON узлов. Если адрес не задан, бот использует официальный API. Для применения к существующему боту требуется повторная генерация и перезапуск.

В режиме polling при доступном Redis блокировка запуска принадлежит конкретному процессу: её продление и освобождение выполняются только владельцем. При потере блокировки или невозможности подтвердить продление в течение 50 секунд бот останавливается до окончания её 60-секундного срока. Для применения изменения требуется повторная генерация и перезапуск бота.

Внутренние оптимизации памяти не требуют новых полей project.json. Блокировки переменных и code-узлов очищаются только после завершения всех владельцев и ожидающих, включая отмену; данные пользователей при очистке блокировок не сбрасываются. Кеш Bot Tables обновляется одним конкурентным запросом на 60 секунд, колонки и строки читаются отдельно; формат подстановок и прежнее преобразование пустых значений сохранены. Для существующих ботов нужна повторная генерация и перезапуск.

При отмене запуска во время подключения Redis или проверки PostgreSQL созданный клиент или пул закрывается; отмена передаётся вызывающему коду, а не превращается в повтор подключения или переход на локальное хранилище. Новых полей сценария для этого не требуется.

Сгенерированный пул PostgreSQL освобождает свободные соединения после 60 секунд непрерывного простоя; следующее обращение к БД открывает соединение снова. Служебная переменная окружения BOT_DB_POOL_IDLE_SECONDS принимает конечное число секунд больше нуля и не больше 86400; некорректное значение заменяется на 60. Это не поле JSON ноды и не таймаут выполнения запроса. Очистка соединений не удаляет сохранённые данные и не останавливает постоянный сценарий. Изменение шаблона применяется после повторной генерации и перезапуска бота.

При роли bot_runtime служебная функция настройки соединения PostgreSQL хранит только строковые идентификаторы проекта и токена, без глобального пространства сценария. Она по-прежнему выставляет app.project_id и app.token_id при создании и каждом получении соединения из пула. Закрытый пул не удерживает сценарий через эту функцию; это не гарантия немедленного уменьшения RSS или полного отсутствия других удерживающих ссылок. Поля JSON и режимы ботов не меняются; существующим ботам нужны повторная генерация и перезапуск.

В общем Python-воркере обработчики polling не регистрируют собственные SIGTERM/SIGINT в цикле событий: сигналами процесса владеет воркер. Это устраняет ссылку от обработчика сигнала на выгруженный сценарий; отдельный запуск Python без воркера сохраняет стандартную регистрацию сигналов aiogram. Пользовательских переключателей и полей JSON для этого нет. Для применения требуются новый runtime, повторная генерация и перезапуск ботов; исправление не доказывает отсутствия других причин роста памяти.

При завершении сценария выполняются независимые попытки очистки PostgreSQL, Redis, HTTP, аналитики и обработчиков завершения с общим бюджетом ожидания 10 секунд. Ошибка или отмена отдельного этапа не должна пропускать остальные попытки; ошибки и зависшие задачи отмечаются в журнале, для PostgreSQL предусмотрено принудительное завершение пула. Это ограниченная по времени очистка, а не гарантия успешного закрытия любого пользовательского ресурса или немедленного снижения RSS. Исходная отмена не подавляется. Постоянный режим не меняется; новых полей узлов нет.

При выгрузке сценария служебное логирование не должно удерживать его пространство имён через глобальные фильтры и обёртки. Очистка ссылок сохраняет логирование исходящих сообщений, аналитику и маскирование секретов; не отключайте эти возможности ради уменьшения памяти. Новых полей JSON и изменений режимов запуска нет. Изменения шаблонов применяются к существующим ботам после повторной генерации и перезапуска.

При неудачной инициализации подключения БД и Redis освобождаются; очистка подключения не удаляет состояние FSM в Redis. Временные оригиналы медиа очищаются только в управляемом каталоге бота после завершения использующих их операций; пользовательские файлы и активные операции сохраняются. Эти изменения также требуют повторной генерации и перезапуска существующих ботов.

У rate_counter данные остаются в памяти процесса и теряются при перезапуске. Истёкшие ключи очищаются небольшими порциями при событиях и в фоне примерно раз в секунду без удаления ещё действующих событий; новых пользовательских настроек и лимита количества живых ключей нет.

Это короткий индекс. Подробные правила разделены по тематическим Markdown-файлам. Полная прежняя версия сохранена в docs/mcp/legacy/bot-json-prompt-source.md.

Перед изменением живого проекта прочитайте правила сохранения и конфликтов MCP. В компактном профиле найдите действие через search_actions, получите его схему через describe_actions и выполните через call_action. Подготовленный JSON не считается сохранённым. Проверяйте подтверждение persistence.confirmed, ревизию и отдельные статусы live-доставки и применения ботом. При конфликте перечитайте проект; неизвестный исход внешнего действия не разрешает слепой повтор с новым идентификатором запроса.

inputTargetNodeId задаёт переход после ввода, но сам не включает сбор ответа. Оставшееся поле в message с выключенным или отсутствующим collectUserInput не должно создавать input-ноду при загрузке. Для новых сценариев используйте отдельный input; активные старые message с collectUserInput: true сохраняют совместимость.

Основные правила​

В Bot Manager карточка пользователя использует imageUrl: "{user_detail.photoDownloadUrl}". API возвращает photoFileId только для исходного бота, photoUrl для авторизованного интерфейса и photoDownloadUrl для менеджера. Закрытый адрес /api/bot/tokens/<id>/users/<id>/photo?telegram_id=<id> загружается узлом message в память с STUDIO_BOT_MANAGER_TOKEN только с настроенного API_BASE_URL; перенаправления запрещены, предел — 5 МиБ и 10 секунд. При ошибке отправляется текстовая карточка. Не подставляйте photoFileId чужого бота в отправку и не используйте HTTP-ноду с ответом file для аватара: её base64 сохраняется в данных пользователя. Существующий Bot Manager требует обновления ссылки в сценарии, повторной генерации и перезапуска.

Ноды​

Для loop указывайте реальные ноды и идентификаторы целей. Генератор пропускает пустые записи при сборе циклов, но не создавайте их в project.json.

Для psql_query допустимы форматы результата first_row, json, text и affected. Форматы bot_table для SQL-ноды не подходят и отклоняются при генерации.

В set_variable режимы lookup, str_replace, json_push и json_format задаются в поле mode отдельного присваивания.

Если у schedule_trigger нет поля rules, генератор применяет интервал пять минут; для других расписаний задавайте правила явно.

Для отправки файлового результата convert_file укажите в message единственное вложение attachedMedia: ["{имя_переменной}"] без других полей медиа. Данные файла декодируются из base64 и отправляются документом.

В userbot_click_button источник messageIdSource: "last_message" совместим с режимом "last"; для заданного идентификатора используйте "manual" и messageId. Настройки узлов юзербота сохраняются при проверке схемы проекта.

Workflow​

MCP-инструменты документации​

  • get_node_docs(node_type) — подробное руководство по ноде.
  • get_rule_docs(rule_name) — тематические правила.
  • get_workflow_docs(task) — рекомендуемый workflow.
  • search_docs(query) — поиск по документации.
  • get_tool_docs(tool_name) — технический контракт MCP-тулa.

Секретные ссылки входа

Для /start link_… генератор скрывает код в логах, аналитике и истории сообщений. Проверяйте исходное сообщение в code-ноде; не сохраняйте и не выводите код.

Метаданные исходящих фотографий​

При включённой истории сообщений генератор сохраняет photo.file_size из ответа Telegram для bot.send_photo, message.answer_photo и send_photo_with_caption. Размер берётся у наибольшего варианта фото (photo[-1]) и записывается рядом с его file_id, шириной и высотой. Если Telegram не вернул размер, сохраняется null; значение нельзя выдумывать или заменять нулём. Новые настройки ноды не требуются. Изменение применяется к новым отправкам после повторной генерации и перезапуска бота; старые записи автоматически не дополняются.

При включённой истории сообщений генератор передаёт ID message-блока при отправке текста, фото, видео, аудио, документов и альбомов, включая Telegram file_id и повторную отправку из кэша. Каждый элемент альбома сохраняется отдельно с тем же node_id. Это позволяет определить блок отправки в истории файлов; старые сообщения без node_id автоматически не восстанавливаются. Эта связь отличается от поиска текущих использований URL файла в сценарии.

Для обложки видео thumbnailFileIds имеет приоритет перед thumbnailUrls. Если задан готовый file_id, URL обложки не используется и не записывается в кэш из ответа Telegram.

Аналитика v2​

Reply- и inline-клавиатуры сохраняются в истории вместе с исходящим сообщением. Session middleware берёт reply-клавиатуру из запроса отправки: Telegram не возвращает её в Message. Повторное логирование обёртками только дополняет недостающие метаданные и ID блока, сохраняя одну запись и один аналитический факт.

При включённой базе пользователей аналитика записывается на границе реальных Telegram-событий, а не переходов между нодами. Пользователь — человек, написавший в личный чат, нажавший настоящую callback-кнопку, адресовавший команду текущему боту, вызвавший принятую команду или ответивший на сообщение этого бота. Переписка группы остаётся отдельным наблюдением. MockCallback, исходящие и служебные события не создают пользователя.

Исходящие сообщения считаются только после успешного ответа Telegram, включая стикеры, голосовые, GIF и элементы альбома. Вызовы ручного логирования без Telegram ID не добавляют вторую отправку. Все записи дедуплицируются по идентичности сообщения/callback в общей SQL-транзакции.

Для настоящего нажатия история сохраняет callback_query_id; переходы между нодами его не создают. Команда с адресатом в группе должна иметь допустимое имя из латиницы, цифр и _, длиной до 32 символов: произвольный текст /bad!@bot не подтверждает использование бота. Обычная зарегистрированная команда подтверждается результатом Command-фильтра, а не совпадением текста.

Успешные forwardMessage, copyMessage, forwardMessages и copyMessages также учитываются; каждый возвращённый MessageId — отдельная отправка. Предпочитайте числовой chat_id: он не требует дополнительного запроса. При копировании на @username после отправки выполняется getChat с таймаутом 2 секунды; если числовой адрес установить не удалось, доставка остаётся успешной, а пропуск учёта явно журналируется. Неизвестный тип отрицательного чата не объявляется группой. Правки сообщений не увеличивают число отправок.

Для /start порядок пользовательских exact/startsWith сохраняется. Новая атрибуция использует зарегистрированную короткую метку, а не предположение по ref_. Старые deep_link_param и referrer_id сохраняют совместимость и не являются подтверждённой атрибуцией v2. link_ — назначение входа, а не доказательство рекламного источника. Исходный command.args доступен обработчику; настроенная переменная авторизации существует в памяти во время обработки и удаляется после неё. В стандартную историю, профиль и уведомления записывается link_[скрыто]. Не записывайте секрет отдельно через пользовательский SQL/код.

Работающему боту нужны повторная генерация и перезапуск для начала покрытия v2. Старое наличие профиля само по себе не доказывает дату первого взаимодействия.

До PostgreSQL минимальный факт фиксируется в локальной очереди. Сбой БД или реестра оставляет его для повторной доставки после восстановления/перезапуска; ошибки не становятся «без метки». Очередь не содержит текстов, callback payload или кодов входа. observed_tag — публичная метка до 64 символов, link_ даёт только статус auth_candidate. Для production ANALYTICS_SPOOL_DIR должен указывать на постоянный том; по умолчанию используется ~/.botcraft/analytics-spool/{projectId}/{tokenId}. Очередь не заменяет резервирование диска.

Узел исключения пользователя

Узел kick_user обрабатывается отдельным шаблоном исключения пользователя.

Управляемые медиа и хранилища​

Для файлов проекта используйте сохранённые относительные адреса /uploads/...; не заменяйте их временными подписанными ссылками S3. Внешний URL остаётся внешним URL, даже если в его пути встречается /uploads/. Источник прикреплённого файла определяется по его записи, поэтому смена выбранного хранилища не переносит и не удаляет старые вложения. Успешная загрузка, сохранение ноды и запуск бота не подтверждают отправку файла в Telegram.

Вновь сгенерированный бот подтверждает запуск после проверки Telegram и получения доступной Redis-блокировки в режиме polling. Если Redis недоступен, запуск возможен без защиты от двойного запуска; старый сгенерированный код подтверждает запуск по прежнему протоколу.

Резервная отправка текста при отсутствующем медиа​

Если исходник вложения не найден (MediaNotFoundError), узел message отправляет непустой текст без медиа, сохраняя форматирование, кнопки, тему чата и привязку к узлу в истории. Это происходит только до первой успешной отправки в данный чат: сбой дополнительных вложений или клавиатуры альбома не создаёт повтор основного сообщения. При пустом тексте, ошибке доступа, таймауте и сбое хранилища резервная отправка не выполняется; ошибка остаётся в журнале. Сохранённый Telegram file_id используется первым; если он устарел, бот пробует исходник и только при его подтверждённом отсутствии переходит к тексту.

Внешний polling-приёмник и сон обработчика​

Это серверный режим исполнения без новых полей нод и без переключателя в интерфейсе. Обычный polling и webhook сохраняются. Внешний приёмник получает обновления отдельно, а сгенерированный обработчик принимает их через внутренний протокол _WORKER_EXTERNAL_UPDATES_PROTOCOL и _worker_external_updates(dp, bot, stop_event). Обработчик проходит startup/shutdown aiogram и закрывает свои подключения при засыпании. Сон не публикует событие логической остановки бота; сообщения из внешней надёжной очереди не отбрасываются стандартным фильтром возраста сообщения.

Сборки с schedule_trigger, api_trigger, userbot, фоновым delay, положительным inputTimeout или parallel_split без awaitAll помечаются как несовместимые со сном. Для них нужен постоянный обработчик: независимые таймеры и фоновые ветки нельзя терять при выгрузке модуля. Произвольный код, создающий собственные фоновые задачи, также требует постоянного режима. Не добавляйте служебные поля протокола в JSON сценария.

Внешний режим требует доступного Redis; при ошибке подключения обработчик не переходит на локальное хранилище. Протокол состояния _WORKER_EXTERNAL_STATE_PROTOCOL = 1 передаёт воркеру словарь user_data, включая ожидание пользовательского ввода. Произвольные глобальные переменные пользовательского кода не входят в этот контракт; такие сценарии требуют постоянного режима.

Webhook: панель автоматически создаёт индивидуальный секрет бота. Сгенерированный Python читает WEBHOOK_SECRET_TOKEN, передаёт secret_token в Telegram и проверяет входящий заголовок; подтверждение доставки отправляется после обработки запроса. Секрет не включается в JSON сценария.

Webhook со сном: при BOT_WEBHOOK_INGRESS=node регистрацией и приёмом обновлений владеет Node. Python с протоколом внешних обновлений просыпается по очереди, не открывает отдельный HTTP-порт и не удаляет webhook при засыпании. Фоновые ноды по-прежнему требуют постоянной работы.