v1.32.1
Hotfix зависания rlm_start на Windows при stdio-транспорте. Контракты хелперов, стратегия, состав MCP-тулов, схема SQLite и BUILDER_VERSION (14) не тронуты — пересборка индексов не требуется. Поведение на streamable-http не меняется вовсе.
Исправлено
rlm_startзависал на Windows при stdio-транспорте в дефолтном режиме песочницы (#25). Было так: транспортstdio(значение по умолчанию) ведёт протокол по дескрипторам 0 и 1 и весь сеанс держит на fd 0 висящее блокирующее чтение. Windows сериализует операции на синхронном pipe и передаёт дочернему процессу стандартные хэндлы родителя даже приbInheritHandles=FALSE— поэтому sandbox-worker, который в режимеRLM_SANDBOX_MODE=process(тоже значение по умолчанию) запускается на каждую сессию, зависал внутри инициализации интерпретатора, до первой строки собственного кода: сброс буферов на старте упирался в занятую трубу. Наблюдалось это как молчаливое зависаниеrlm_startдо истеченияRLM_SANDBOX_START_TIMEOUT_SECONDS(60 секунд по умолчанию) с последующей ошибкой; процесс-worker при этом жив, но не отвечает. Собственная отвязка stdio внутри worker не помогала: она исполняется уже после инициализации интерпретатора, до которой дело не доходило. По HTTP-транспорту воспроизвести было нельзя — там на трубах никто не висит, поэтому установки, работающие через службу (--transport streamable-http), проблему не видели. Стало: при старте сstdioпротокол обслуживается с приватных дубликатов дескрипторов, а fd 0 и 1 уводятся наos.devnullи на stderr — дети наследуют отводы, а не протокольные трубы. Проверено на Python 3.10, 3.12 и 3.14: зависание воспроизводилось на всех трёх и на всех трёх устранено. Разводка обратима и best-effort — если увести дескрипторы не удалось, они возвращаются в исходное состояние, а сервер стартует как прежде; отключаетсяRLM_STDIO_HARDENING=0(не рекомендуется).- Посторонний вывод в
stdoutбольше не попадает в поток протокола. Побочное следствие того же исправления: при stdio-транспорте протокол идёт по приватным дубликатам дескрипторов, аsys.stdoutвместе с самим дескриптором 1 указывает на stderr. Поэтому любой посторонний вывод из процесса сервера —print()своего или библиотечного кода, raw-запись в дескриптор 1, вывод дочернего процесса — уходит в stderr, а не в JSON-RPC поток, где ломал бы кадрирование сообщений. Оговорка: гарантия опирается на то, что stderr и stdout ведут в разные места; если клиент запускает сервер со stderr, слитым в stdout (2>&1), отвод и есть протокольная труба — тогда посторонний вывод по-прежнему может попасть в поток (зависание при этом всё равно вылечено, его порождает сторона стандартного ввода). - Скрипты установки обрывались на финальном блоке, если программа что-то писала в stderr. Было так: строка с версией вызывала
rlm-tools-bsl --versionс перенаправлением2>&1. В PowerShell 5.1 stderr нативной программы, уведённый в поток успеха, становится ошибкой (NativeCommandError), а при действующем в скриптах$ErrorActionPreference = "Stop"— завершающей. Достаточно было одного предупреждения любой зависимости при запуске — и установка, уже сделав всю работу и подняв службу, обрывалась на выводе версии: адрес endpoint, ссылка на health, готовый фрагмент дляmcp.jsonи команды управления службой до пользователя не доходили, а вместо них печаталась красная трассировка. Стало: подавление stderr вынесено вcmd(cmd /c 'rlm-tools-bsl --version 2>nul'), поэтому PowerShell его не видит вовсе и никакой посторонний вывод больше не может оборвать скрипт. Правка внесена вsimple-install.ps1иsimple-install-from-pip.ps1. Вsimple-install.shиsimple-install-from-pip.shобрыва не было — bash так себя не ведёт, — но stderr подмешивался прямо в строку версии, поэтому там2>&1заменено на2>/dev/null.
Добавлено
RLM_STDIO_HARDENING— выключатель разводки дескрипторов (по умолчанию включена, действует только на stdio-транспорт). Значения0,false,no,offотключают. См.docs/ENV_REFERENCE.md.
Полный список изменений: CHANGELOG.md