Архитектура

Файлы результатов и pipe-инструменты

Bulk-инструменты (поиск, дочерние объекты, список типов и т.п.) записывают результат в файл JSONL (один JSON-объект на строку) в %TEMP%\pilot-mcp и возвращают модели только метаданные: путь к файлу, число записей, список колонок. Это позволяет работать с тысячами объектов без перегрузки контекста.

Дальше результат обрабатывается pipe-инструментами, каждый из которых читает один файл и пишет новый:

Search("проект") -> {resultFile: "tmp/search_x.jsonl", count: 8543}
     |
FilterObjects("tmp/search_x.jsonl", "typeName", "document") -> tmp/filter_x.jsonl (85 записей)
     |
ExportCsv("tmp/filter_x.jsonl", "C:/result/docs.csv", "name,typeName,created")

Инструменты: ExtractFields, FilterObjects, ExtractFieldToText, PreviewFile, ReadFile, CountFile, ExportCsv, SaveResult (см. справочник). outputFile не может совпадать с inputFile. Файлы *.jsonl старше 24 часов удаляются при старте сервера.

Каждый вызов инструмента пишется в журнал %TEMP%\pilot-mcp\tools.log (результат обрезается до 500 символов).

Подтверждение записи

Операции записи через Modifier и Backend выполняются методом ApplyAndWait: изменение отправляется на сервер, а затем вызов ждёт ответа сервера о результате этого changeset (до 60 с).

  • Отказ сервера возвращается как ошибка с текстом сервера («Сервер отклонил изменение: ...»).
  • Если подтверждение не пришло за 60 с, сообщается, что результат неизвестен и состояние нужно проверить перед повтором.
  • Ответ может прийти раньше, чем вызывающий начнёт ждать: результат изменения сохраняется по идентификатору changeset.

InvokeCommand ждёт результат серверной команды до 15 с.

Переподключение и повтор вызовов

Вызовы Server API, File API и Messages API идут через прокси с автопереподключением. При транспортной ошибке (соединение закрыто, TransportClient уничтожен, таймаут) клиент пересоздаётся с сохранёнными учётными данными, а затем вызов повторяется только при выполнении одного из условий:

  • имя метода начинается с Get, Load, Calc, Open, Check, Enumerate или это SearchMessages (читающие вызовы);
  • цель вызова уже была уничтожена, то есть запрос на сервер не уходил.

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

Админское подключение (LoginServerAdministrator) при транспортной ошибке сбрасывается, а прерванный вызов не повторяется: через него идут неидемпотентные записи (изменение пользователей, метаданных, перенос оргединиц).

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

Метаданные

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

Изменение метаданных через админский API (типы, атрибуты, состояния, машины состояний, автоматизации) устроено как чтение свежей копии, точечная правка и запись целиком, поэтому параллельные правки в myAdmin не затираются. Внутри одного процесса PilotMCP такие операции выполняются последовательно; между разными процессами защиты нет.

Разбор документов

Текст и координаты извлекаются из XPS (ZIP с XAML-страницами) и PDF. Для XPS заданы пределы на распаковку:

Ограничение Значение
Страниц в документе не больше 10 000
Суммарно распакованных XML-частей одного извлечения 512 МБ
Один шрифт 32 МБ
Все шрифты 128 МБ

При превышении возвращается ошибка о недопустимом размере или числе страниц. XPS в формате interleaved (части [N].piece) поддерживается; нумерация страниц следует за FixedDocument, как у рендерера.

Единицы координат у FindTextOnPage и ExtractPageText: XPS — 1/96 дюйма, PDF — пункты (1/72 дюйма), y — верх текста сверху вниз; единицы указаны в ответе. Документ без текстового слоя (скан) возвращает соответствующее сообщение.