Документация 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 требует
обновления ссылки в сценарии, повторной генерации и перезапуска.
- Формат project.json
- Переменные и контекст
- Переходы
- Команды
- Runtime-контекст
- Безопасность
- Отладка и логи
Ноды
Для 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
- Калькулятор
- Создание ноды
- Изменение проекта
- Навигация кнопок
- Запуск и перезапуск
- Диагностика
- Таблицы
- Telethon Userbot
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 при засыпании. Фоновые ноды по-прежнему требуют постоянной работы.