For the complete documentation index, see llms.txt. This page is also available as Markdown.

Правила хоста

Хост — общая половина системы плагинов: обнаружение и загрузка файлов, передача аргументов, семантика возврата, изоляция сбоев, порядок, перезагрузка, эпохи, интроспекция, версии и dry-run. Это общий контракт семейства; реализации встроены в HelpSearchServer, SSLSearchServer, SyntaxCheckServer, TemplatesSearchServer, Graph Metadata Search и 1CCodeChecker. Различается только набор хуков — он в справочнике по серверам.

Загрузка файла

Плагин — один файл, без церемоний. Загрузка не требует базового класса, декоратора, регистрации, записи в манифесте и импорта. Файл, не объявивший ни хука, ни таблицы, загружается успешно и ничего не меняет.

Имена хуков — закрытый набор. Разрешены ровно те имена, которые объявил продукт. Имя верхнего уровня, похожее на хук, но отсутствующее в наборе, отклоняет загрузку всего файла, называя нарушителя и перечисляя допустимые имена. Сервер при этом стартует с остальными плагинами. Функция, чьё имя не похоже на имя хука, — ваш собственный помощник, её не трогают.

Файлы читаются как UTF-8, с BOM или без. Другая кодировка отклоняет файл с указанием имени и правила, а не угадывается.

Порядок детерминирован и объявлен. Файлы выполняются в отсортированном порядке имён, каждый хук применяется конвейером: выход одного файла — вход следующего. Действующий порядок показывает интроспекция.

Аргументы и возврат

Аргументы передаются по объявленным именам. Хук получает ровно те аргументы, которые названы в его сигнатуре, выбранные по имени из предложенных для этого хука. def on_result(result): и def on_result(result, request): — оба корректны. Имя параметра, которое хост не может предоставить, отклоняет файл при загрузке, а не при первом вызове.

Возврат — единственный канал. Хук получает копию payload, применяется только возвращённое значение. Возврат None (или выход из функции без return) оставляет payload неизменным — это нормальный способ сказать «не мой случай». Изменение аргумента без возврата не даёт никакого эффекта.

В хуки передаются данные, а не живые объекты. Каждое значение — примитив, список или словарь. Из аргумента хука недостижимы ни хранилище, ни модель, ни соединение, ни поколение индекса, ни объект сервера.

Изоляция сбоев

Упавший плагин никогда не роняет сервер. Исключение перехватывается, пишется в журнал с файлом, именем хука и трассировкой, и не распространяется дальше. Сервер продолжает так, как если бы хук вернул None.

  • Упавший call-scoped хук отключается до следующей перезагрузки и показывается как отключённый со своей ошибкой и счётчиком сбоев.

  • Упавший derived-state хук не оставляет отдельную единицу наполовину преобразованной: по умолчанию она берётся неизменённой, сбой считается и попадает в сводку. В строгом режиме (PLUGIN_STRICT_DERIVED_STATE, у Graph — GRAPH_PLUGIN_STRICT_BUILD) сборка падает целиком. Сохраняется ли прежнее поколение в обслуживании, зависит от механизма перестроения конкретного сервера — см. предупреждение ниже.

  • Файл, который не загрузился вообще, не мешает старту: сервер поднимается и называет файл и причину.

Границы производного состояния

Derived-state хуки участвуют в отпечатке годности. Там, где сервер решает, актуально ли сохранённое производное состояние, сравнивая отпечаток породивших его правил, исходник каждого derived-state хука входит в этот отпечаток. Правка такого файла делает сохранённое состояние устаревшим: следующий старт пересобирает его. Серверы с поколенческой схемой продолжают обслуживать прежнее поколение до проверки и promotion; для SSL обычная инвалидизация и операторская миграция имеют разную семантику, описанную выше. Манифест состояния перечисляет плагины, которые его сформировали, с отпечатком исходника каждого.

Call-scoped хуки не инвалидируют производное состояние. Их правка не входит ни в один отпечаток и не вызывает пересборки.

Токены продолжения несут эпоху плагинов. Там, где сервер выдаёт курсор для продолжения ответа, курсор привязан к действовавшему набору плагинов так же, как к поколению индекса и запросу. Курсор, предъявленный в другой эпохе, отклоняется как принадлежащий устаревшему состоянию (например, кодом stale_cursor), и это означает «искать заново», а не «продолжать». Пока эпоха держится, страницы не дублируются и ничего не теряется.

Контракт ответа

Опубликованный контракт ответа применяется после хуков:

  • объявленные пределы (max_items, max_chars, top_k, лимиты бюджета) измеряются после последнего хука;

  • счётчики в ответе пересчитываются из фактически возвращённого — счёт никогда не принимается на веру;

  • payload проверяется по схеме ответа продукта.

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

Изменённый запрос виден вызывающей стороне. Если хук поменял аргументы вызова, ответ сообщает и то, что прислал клиент, и то, что было использовано, и файл плагина, который это сделал.

Классификация приватности распространяется на плагины. Поля, которые продукт считает чувствительными, остаются такими и внутри плагина, включая значения, произведённые плагином. Секреты не приходят в on_startup в открытом виде: часть серверов подменяет их на <redacted> / ***redacted***, Graph Metadata Search передаёт булево «задано или нет».

Версии и совместимость

Константа в plugin_api.py

Что версионирует

HOST_CONTRACT_VERSION

Общий контракт хоста — правила этой страницы. Одинаков во всех серверах семейства

PRODUCT

Идентификатор продукта: 1c-help, ssl-search, bsl-syntax-check, template-search, graph-metadata-search, onec-code-checker

HOOKS_VERSION

Набор хуков и таблиц конкретного продукта; поднимается, когда payload меняет форму так, что плагин этого не переживёт

Плагин может закрепить любую из трёх через REQUIRES. Это необязательно, и единственная причина так делать — быть отклонённым рано и внятно:

Плагин, написанный для другого продукта семейства, отклоняется с указанием обоих продуктов, а не сообщением о пяти неизвестных именах функций. Плагин, требующий версию набора хуков, которую продукт больше не предлагает, отклоняется с указанием обеих версий.

Интроспекция и перезагрузка

Перезагрузка без перезапуска. Каталог перечитывается целиком, действующие хуки заменяются атомарно, начинается новая эпоха плагинов. Неудачная перезагрузка не меняет ничего: прежний набор остаётся в силе, ответ называет файл и причину. Derived-state хуки вступают в силу со следующего построения, а не задним числом.

Загруженные плагины интроспектируемы. Состояние подсистемы показывает: каждый файл, объявленные им хуки и таблицы, классификацию каждого хука, включён он или отключён, ошибку, которая его отключила, счётчик сбоев, накопленное в каждом хуке время, порядок файлов и текущую эпоху.

Бюджет времени хука — продуктовое дополнение: Graph Metadata Search ограничивает один hook значением GRAPH_PLUGIN_HOOK_TIMEOUT_SECONDS (0 отключает контроль), CodeMetadataSearchServer — значением PLUGIN_HOOK_TIMEOUT_SECONDS (по умолчанию 5.0; превысивший бюджет хук считается упавшим и call-scoped отключается до следующей перезагрузки каталога). Остальные серверы бюджета не навязывают, но накопленное время каждого хука показывают.

Упаковка и dry-run

plugin_api.py поставляется читаемым исходником в runtime-образе и является полным справочником: форма payload и рабочий пример для каждого хука и таблицы продукта. Он не импортирует ничего вне стандартной библиотеки. Скомпилированные модули собраны без встроенных docstring — описания реализации в бинарниках нет.

Каталог плагинов самоописывающийся. В нём лежат инструкция для агента (AGENTS.md) и закомментированный пример (example.py), объявляющий все хуки и таблицы продукта.

Плагин можно попробовать без данных и без сборки. Каждый образ содержит команду, которая прогоняет хуки файла на зашитых в образ фикстурах и печатает payload до и после — без смонтированных данных, без построенного состояния и без запущенного сервера. Ошибку загрузки dry-run сообщает теми же словами, что и сервер. Команды по серверам — в Как написать плагин.

Чего система не обещает

Хук — это Python внутри процесса сервера, поэтому плагин может прочитать всё, что может процесс. Компиляция модулей повышает стоимость чтения реализации, но не останавливает плагин. Система не защищает реализацию от автора плагина — она гарантирует, что плагин не испортит производное состояние, не нарушит опубликованный контракт ответа и не уронит сервер.

Last updated