ai 26.1100.0 Заметное

AI 26.1100.0: срок жизни задачи очереди ИИ-запросов задаётся на запрос

4 мин чтения
Узнавайте о ломающих изменениях Битрикса раньше, чем они доедут до прода: свежие разборы — в канале @bxmax_updates

В модуле ai коробочного Битрикс24 версии 26.1100.0 срок жизни задачи очереди ИИ-запросов больше не зашит в четыре часа. Его задают на запрос через Engine::setQueueJobTtl(), момент истечения пишется в новую колонку b_ai_queue.EXPIRE_DATE, а просроченную задачу QueueJob::createFromHash() теперь проваливает и удаляет сам. Ещё установщик переехал с SQL-скриптов на миграции ядра, и появилась заготовка триггера перезапуска ИИ-агентов.

В коробку версия вышла 14 сентября 2026 года, по данным официального канала «Битрикс24 changelog». Читать стоит тем, кто шлёт ИИ-запросы из своего кода через Engine или достаёт задачи очереди по хешу.

Что может сломаться

Удалённых и несовместимо изменённых публичных сигнатур нет, новых @deprecated тоже, в API добавились только новые методы и необязательные параметры. Сломать ваш код может изменившееся поведение.

Проверьте вызовы createFromHash()

Раньше QueueJob::createFromHash() (lib/QueueJob.php) отдавал задачу любого возраста, а старые задачи чистил только агент clearOldAgent(). Теперь у метода сигнатура createFromHash(string $hash, bool $allowExpired = false), и просроченную задачу он по умолчанию не отдаёт.

Просроченной считается задача, у которой EXPIRE_DATE в прошлом. Если EXPIRE_DATE равен NULL, срок считается от DATE_CREATE плюс DEFAULT_TTL, то есть 14400 секунд, четыре часа. Для такой задачи метод возвращает null и сам вызывает приватный expire(). Тот удаляет строку, шлёт backend- и frontend-события провала с ошибкой HASH_EXPIRED и откатывает списание лимита. Просроченную «битую» строку, у которой не распаковались движок или payload, метод удаляет сразу.

Колбэки в ядре ведут себя по-разному. Колбэки успеха передают allowExpired: true и принимают поздний результат, пока строка существует. Это callbackBodyAction в lib/controller/queue.php и callbackSuccessAction в lib/controller/integration/b24cloudai.php и thirdparty.php. Колбэки ошибок (callbackErrorAction в тех же файлах) зовут метод со значением по умолчанию, так что просроченную задачу провалит и удалит сам createFromHash().

Если вы вызываете createFromHash() в своём коде, проверяйте null и учитывайте, что сам вызов теперь может удалить задачу и разослать событие провала. Если нужен поздний результат, как в колбэках успеха, передавайте allowExpired: true.

getTTL() больше не константа

Приватную константу TTL_SECONDS = 14400 заменили две публичные, QueueJob::DEFAULT_TTL = 14400 и QueueJob::MAX_TTL = 86400. getTTL() теперь возвращает TTL конкретной задачи. У задачи, загруженной из БД, это разница EXPIRE_DATE − DATE_CREATE, а если EXPIRE_DATE пуст, DEFAULT_TTL. Если ваш код считал, что задача всегда живёт четыре часа, берите срок из getTTL().

QueueJob::createWithinFromEngine(IEngine $engine, ?int $ttl = null) получил необязательный TTL. Он и Engine::setQueueJobTtl() бросают \InvalidArgumentException, если значение меньше единицы или больше 86400.

could_not_lock стал ошибкой провайдера

Ответ с кодом could_not_lock теперь считается ошибкой провайдера (lib/Engine/Engine.php, QueueJob::fail()). Пользователь получит AI_ENGINE_ERROR_PROVIDER, как на коды 100 и от 500 и выше. Для кода завели константу Engine::ERROR_CODE_COULD_NOT_LOCK = 'could_not_lock'.

Задайте срок жизни своему запросу

Engine::setQueueJobTtl(int $ttl): static задаёт время жизни задачи очереди для конкретного запроса, getQueueJobTtl(): int его возвращает (по умолчанию QueueJob::DEFAULT_TTL). Engine и ThirdParty (lib/Engine/ThirdParty.php) передают это значение в QueueJob::createWithinFromEngine(), а QueueJob::register() записывает в EXPIRE_DATE момент «сейчас + TTL». Потолок — MAX_TTL, сутки. Срок выставляйте до отправки запроса, потому что createWithinFromEngine() получает его при постановке задачи в очередь.

Метод бросает исключение на недопустимом значении, так что в сервисе его удобно обернуть в Result:

        <?php declare(strict_types=1);

namespace Vendor\Assistant\Application\Service;

use Bitrix\AI\Engine\Engine;
use Bitrix\AI\QueueJob;
use Bitrix\Main\Error;
use Bitrix\Main\Loader;
use Bitrix\Main\Result;

final class AiQueueTtlService
{
    public function __construct()
    {
        Loader::requireModule('ai');
    }

    public function apply(Engine $engine, int $ttlSeconds): Result
    {
        $result = new Result();

        try {
            $engine->setQueueJobTtl($ttlSeconds);
        } catch (\InvalidArgumentException) {
            return $result->addError(new Error(
                sprintf('TTL задачи должен быть от 1 до %d с, передано %d', QueueJob::MAX_TTL, $ttlSeconds),
                'AI_QUEUE_TTL_OUT_OF_RANGE',
            ));
        }

        return $result->setData(['ttl' => $engine->getQueueJobTtl()]);
    }
}

    

Не стройте процессы на триггере перезапуска ИИ-агентов

В модуле появилась активити бизнес-процессов aiagentrestarttrigger (install/activities/bitrix/aiagentrestarttrigger/). Это триггер CBPAiAgentRestartTrigger extends \Bitrix\Bizproc\Activity\BaseTrigger в группах STARTER и AI, секция AI_AGENT. Он возвращает restartRunId, previousRunId, initiatorId (в виде user_N), timestamp и runType (по умолчанию restart), а runType и restartRunId дублирует в переменные процесса. Триггер скрыт, если опция feature_ai_agents модуля bizproc не задана или равна N, а также если NodeAvailabilityServiceInterface не зарегистрирован в ServiceLocator или сообщает, что узел недоступен.

Параметры события тоже расширили. В enum ProcessedEvent появилось OnAiAgentRestart. Конструктор AiListenerParameters получил необязательные agentInstanceId, restartRunId, previousRunId, initiatorId, timestamp и runType = RUN_TYPE_INITIAL. В классе появились константы KEY_AGENT_TEMPLATE_ID, KEY_AGENT_INSTANCE_ID, KEY_RESTART_RUN_ID, KEY_PREVIOUS_RUN_ID, KEY_INITIATOR_ID, KEY_TIMESTAMP, KEY_RUN_TYPE, RUN_TYPE_INITIAL и RUN_TYPE_RESTART. toArray() добавляет новые ключи, только когда runType === 'restart'.

Отправлять событие пока некому. В коробочном Битрикс24 с этой версией OnAiAgentRestart в bitrix/modules встречается только в enum ProcessedEvent, а параметры перезапуска есть только в AiListenerParameters. Сервис SystemTemplateActivationService в bizproc (lib/Internal/Service/AiAgentGrid/) отправляет только OnAiAgentStart. Bizproc запускает триггеры по коду (Starter::addEvent(code: 'AiAgentStartTrigger', …) для старта), а код AiAgentRestartTrigger вне папки самой активити не встречается, так что процесс на новом триггере пока не запустится.

БД: проверьте колонку EXPIRE_DATE

Установщик переехал на миграции ядра. Файлы install/db/mysql/install.sql, uninstall.sql и их пары в install/db/pgsql/ удалены. Вместо них появились install/migrations/tables.php на построителе Bitrix\Main\UpdateSystem\Migration, events.php и agents.php. В install/index.php installDB() вызывает installMigrations(), а uninstallDB() вызывает uninstallMigrations($dropTables). Из 1349 удалённых строк релиза 908 приходятся на эти SQL-скрипты.

tables.php создаёт те же 31 таблицу, что и старый install.sql. По именам колонок и индексов новая схема отличается от MySQL-скрипта только в b_ai_queue, где добавились колонка EXPIRE_DATE datetime и индекс IX_B_EXPIRE_DATE.

Как колонка появится на уже установленных порталах, из кода модуля не видно, потому что скрипт обновления в папке модуля не остаётся. Комментарий в QueueJob::clearOldAgent() упоминает «interrupted updater backfill». Код везде готов к EXPIRE_DATE = NULL и тогда считает срок от DATE_CREATE + DEFAULT_TTL. На MySQL после обновления проверить колонку и индекс можно так:

        SHOW COLUMNS FROM b_ai_queue LIKE 'EXPIRE_DATE';
SHOW INDEX FROM b_ai_queue WHERE Key_name = 'IX_B_EXPIRE_DATE';

    

Из install/index.php ушли ручные registerEventHandler, CAgent::AddAgent, CAgent::removeModuleAgents('ai') и приватные методы configureBoxBitrixGptFeatures() и getConnectionType(). Агентов при удалении модуля снимает ModuleManager::unRegisterModule() из main. Руками отписывается только старый обработчик PublicAgreement::onPageStart, рядом в коде комментарий «legacy cleanup».

agents.php ставит агентов по окружениям с теми же интервалами, что были в index.php:

  • везде: QueueJob::clearOldAgent (раз в 120 с), Updater::refreshDbAgent (раз в 3600 с), PropertiesSync::retrieveModelsAgent (раз в 86400 с);
  • в облаке (BX24_HOST_NAME): EngineSettings::resetToBitrixAudioInCloudAgent, resetToBitrixGPTInCloudAgent, enforceEngineBaselineAgent, раз в час, первый запуск через 600, 600 и 3600 с, как раньше;
  • в коробке: resetFollowUpTextStepsToBGPTAgent и resetFlowsToBGPTAgent, раз в час, первый запуск через 600 с.

Мелочи и находки

  • Внутреннее JS-расширение ai.roles-dialog (install/js/ai/roles-dialog/src/) переделали. Глобальные события EventEmitter update и update-complete убраны вместе с перезагрузкой диалога после закрытия слайдера библиотеки ролей. Перед открытием библиотеки диалог теперь закрывается (this.hide()), аналитику open_list отправляет сам RolesDialog. components/roles-dialog-roles-library.js экспортирует фабрику getRolesDialogRolesLibrary(onOpenRolesLibrary) вместо объекта RolesDialogRolesLibrary, а getRolesDialogEmptyGroupStubWithStates() получил второй параметр onOpenRolesLibrary. Если вы подписывались на update или update-complete снаружи, эти обработчики больше не вызовутся.
  • Приватный QueueJob::tryDelete() удаляет строку сырым DELETE FROM ?# WHERE ID = ?i через SqlExpression и проверяет getAffectedRowsCount(). События провала и откат лимита отправляет только тот запрос, который действительно удалил строку. Почему не ORM, сказано в комментарии: «ORM delete() gives no affected-rows contract». Так закрыта гонка между поздним колбэком и тиком агента.
  • Комментарий у Engine::ERROR_CODE_COULD_NOT_LOCK требует, чтобы значение совпадало с Bitrix\AiProxy\Controller\Query::ERROR_CODE_COULD_NOT_LOCK. Модуля aiproxy в коробочном Битрикс24 нет, это серверная сторона облачного прокси.
  • Агенты EngineSettings::resetToBitrixGPTInCloudAgent() и resetToBitrixAudioInCloudAgent() теперь возвращают __METHOD__ . '();', то есть имя без ведущего обратного слэша. Раньше возвращалось '\Bitrix\AI\Agents\EngineSettings::…'. В коробке это не заметно, agents.php ставит их только в облаке.
  • В install/migrations/agents.php среди английских комментариев затесался один русский. В нём сказано, что legacy-вызов PropertiesSync без интервала переведён в явные 86400 с, «поведение сохранено (подтверждено verify-харнессом)».
  • В lib/Payload/Formatter/StatementTrait.php и UserMarkers.php перед mb_strtolower() и str_replace() добавили приведение к (string). EngineSettingsService теперь пропускает пустой или нестроковый код движка.
  • VERSION_DATE в install/version.php ровно 2026-07-21 12:00:00, а в коробку версия вышла 14 сентября.
  • 20 JS/CSS-файлов в install/js/ai/copilot/ значатся в статистике с нулём строк. У них сменились только права, 100755 → 100644.

Что делать

  • Найдите в своём коде createFromHash(. Проверяйте null, а если нужен поздний результат, передавайте allowExpired: true.
  • Если вы рассчитывали на фиксированные четыре часа, берите срок задачи из getTTL(), а свой задавайте через Engine::setQueueJobTtl() в пределах 1–86400 секунд.
  • После обновления проверьте, что в b_ai_queue есть колонка EXPIRE_DATE и индекс IX_B_EXPIRE_DATE.
  • Уберите подписки на события update и update-complete из ai.roles-dialog, если они у вас были.
  • Триггер aiagentrestarttrigger в шаблоны пока не ставьте, событие OnAiAgentRestart никто не отправляет.

Новая версия вышла — разбор уже в Telegram

В канале @bxmax_updates публикуем каждый свежий разбор: что сломается, что устарело и что появилось в API. Узнаете до того, как обновите прод.

Подписаться

Читайте дальше

ai 26.1200.0 Безопасность Свежее

AI 26.1200.0: запись истории ИИ-запросов через REST включает только администратор

В модуле `ai` коробочного Битрикс24 версии 26.1200.0 REST-методы `ai.history.enable` и `ai.history.disable` пускают только администратора. Они включают и выключают запись истории всех ИИ-запросов портала, а проверки администратора в них до этой версии не было. Ещё модуль перестал подключаться на лиц…

3 мин
timeman 26.350.0 Заметное Свежее

Timeman 26.350.0: план дня пишется в нужную запись, блоки БП возвращают Saved

В timeman 26.350.0 для коробочного Битрикс24 блоки «Сохранить план на день» и «Сохранить отчёт сотрудника за день» из нового конструктора бизнес-процессов научились писать в заданную запись рабочего дня, оставлять Markdown как есть и сообщать, сохранилось ли (у отчёта новые настройки в конструкторе,…

2 мин
rpa 26.300.0 Безопасность Свежее

Rpa 26.300.0: права на перемещение элементов наконец проверяются

До RPA 26.300.0 `UserPermissions::canMoveItem()` сразу отвечал `true`, и любой сотрудник, кроме экстранет-пользователей, мог перетащить любой элемент на любую стадию, а права стадии на перемещение не учитывались. Теперь права проверяются, а тем, кто может только смотреть, `rpa.item.get` и `rpa.item….

3 мин
booking 26.500.100 Заметное Свежее

Booking 26.500.100: addList отвечает ошибкой, когда не создал ни одной брони, а четыре колонки дат стали DATETIME

В коробочный Битрикс24 пришёл booking 26.500.100 с двумя правками. AJAX-экшен `booking.api_v1.Booking.addList` теперь возвращает ошибку, если не создал ни одной брони. Апдейтер переводит четыре колонки дат с `TIMESTAMP` на `DATETIME`, и в `install/migrations/tables.php` они объявлены через `datetime…

3 мин
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…
Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти