Разработка плагина (SDK)
Плагин Conveyor — отдельный Node-процесс: он публикует манифест в plugin-manager и принимает задачи исполнителей по TCP. На TypeScript удобнее через npm-пакет @kosolapus/plugin-ts-sdk.
На какие вопросы отвечает раздел: Как устроен процесс плагина? Какие поля manifest допустимы? Как собрать свой пакет и проверить публикацию?
Перед обновлением SDK сверьте матрицу совместимости и npm view @kosolapus/plugin-ts-sdk version.
Как плагин стыкуется с платформой
При старте процесс отправляет manifest (список nodeType, адрес pull для batch). Plugin-manager сохраняет каталог. После включения плагина в редакторе узлы попадают в библиотеку. При Запуске процесса runtime передаёт задачу в control plane, control plane маршрутизирует её на TCP-порт исполнителя плагина.
sequenceDiagram
participant P as Процесс плагина
participant PM as Plugin-manager
participant UI as Редактор
participant RT as Runtime
participant CP as Control plane
P->>PM: TCP manifest и pull
PM->>PM: Каталог и staticAssets по URL если есть
UI->>PM: Список плагинов enable disable
RT->>CP: Задача на nodeType плагина
CP->>P: executor.task
P->>CP: Результат шага
CP->>RT: Продолжение процесса
Подробнее о роли plugin-manager: сервис plugin-manager. Модель в целом: Плагины и интеграции.
Можно и нельзя
Контракт публикации задаёт тип PluginManifestRequestV2 в SDK. Ниже правила для собственного пакета.
Можно
- поля manifest только из типов SDK;
- в массиве
executors[]только{ nodeType }. Transport, DTO и help задаются в@Executorи ответе batch pull; - несколько исполнителей в одном процессе: реестр классов и
executorsFromClasses; - секреты на узле через
FieldDecoratorсtype: 'ref'иsecretKind. Массивvariablesв manifest оставьте пустым; - отдельный output-порт на каждое поле
OutputDto; - файл
help.mdна каждый исполнитель. Сборка:tsc, затемcopy:help,bundle,prune:dist; - npm-зависимости домена (HTTP-клиенты и т.п.) внутри пакета плагина;
- переменные окружения для pull, RPC, control plane и для домена (например base URL внешнего API).
Нельзя
- произвольные поля manifest, которых нет в SDK;
- секреты в
variablesmanifest; - presets внутри
PluginManifestRequestV2(presets регистрируются отдельно через preset-service); - один blob-output (
result,data) вместо структурированных портов, если ответ API структурирован; - адрес
127.0.0.1вpull.host, если plugin-manager работает в другом контейнере; - разные значения у
PLUGIN_TCP_PORT,EXECUTOR_TCP_PORTиPORTв одном процессе.
Пример skeleton manifest (без секретов):
{
"kind": "plugin_manifest_request_v2",
"pluginId": "my-integration",
"publicationVersion": "0.0.1",
"label": "My integration",
"description": "Краткое описание для каталога",
"variables": [],
"staticAssets": [],
"executors": [{ "nodeType": "plugin.my-integration.action" }],
"pull": { "host": "my-integration", "port": 9409 }
}
Чеклист: от идеи до готового плагина
Минимальный путь предполагает один исполнитель. Расширения (несколько узлов, секреты, внешние API) см. раздел Паттерны на учебном примере.
Работайте в checkout репозитория plugins или в своём fork с тем же layout workspace.
| # | Шаг | Артефакт | Критерий готовности |
|---|---|---|---|
| 1 | Intake | Запись: pluginId, список nodeType, контур (sidecar / host / external) | Решение до кода |
| 2 | Пакет | <id>/package.json: имя @conveyor/plugin-<id>, conveyorPluginBuild, scripts build/start, зависимость SDK по матрице | tsc проходит |
| 3 | TypeScript | <id>/tsconfig.json: decorators, strict, outDir: dist | — |
| 4 | Workspace | Каталог <id> в workspaces корневого package.json | npm install из корня checkout |
| 5 | Точка входа | src/main.ts: bootstrapPluginExecutorMicroservice(AppModule) | процесс стартует |
| 6 | Pull из env | src/getUrlFromEnv.ts: host и port для manifest и transport | совпадает с compose или .env |
| 7 | Manifest | src/<id>-manifest.builder.ts: buildManifestRequest(), pull, executors[] | JSON manifest в логах при старте |
| 8 | Batch pull | src/<id>-publication-batch.source.ts: buildExecutorBatchPullResponseFromEntries | plugin-manager получает transport |
| 9 | Реестр | src/executors.index.ts: список классов исполнителей | — |
| 10 | Nest module | src/app.module.ts: PluginPublicationTcpHostModule.forRoot, BulkExecutorRouterService, pluginId в options | wiring полный |
| 11 | Исполнитель | src/.../executor.ts: @Executor, InputDto/OutputDto, transport: { type: 'tcp', params: publicationPullEndpointFromEnv() } | узел в палитре после enable |
| 12 | Справка узла | src/.../help.md, loadHelpFromFile, script copy:help | help.md в dist/ |
| 13 | README пакета | <id>/README.md: назначение, таблица узлов, конфиг в редакторе, блок для разработчика | — |
| 14 | Env | <id>/env.example или комментарии в README пакета | локальный npm start с demo |
| 15 | Сборка | npm run build -w @conveyor/plugin-<id> из корня checkout | есть dist/run.cjs |
| 16 | Compose | sidecar-сервис по образцу в README repo (файлы compose.demo.yml, compose.env.example) | контейнер healthy, publication ok |
| 17 | Проверка | раздел ниже | Запуск с узлом плагина успешен |
Сборка на хосте из корня checkout:
npm install
npm run build -w @conveyor/plugin-<id>
cd <id>
npm start
Переменные RPC, control plane, pull и порты executor должны совпадать с контуром, в котором вы проверяете плагин. Шаблоны env и compose: репозиторий plugins.
Паттерны на учебном примере
В checkout репозитория plugins откройте пакет llm/ (только как учебный образец, не как фиксированный список интеграций платформы). Там показаны типовые усложнения.
Несколько исполнителей. Один AppModule, реестр в executors.index.ts, разные nodeType (например llm.ollama.generate и plugin.huggingface.inference). Manifest перечисляет все nodeType, batch pull отдаёт transport для каждого.
Секрет на узле, не в manifest. В OpenAI-исполнителе поле API key оформлено как type: 'ref', secretKind: 'OPENAI_API_KEY', static: true. Значение берётся из «Хранилища» редактора при Запуске.
Конфиг домена. У Ollama-исполнителя base URL можно задать static-полем узла. В Docker sidecar часто добавляют fallback через переменную окружения (например OLLAMA_BASE_URL в compose repo).
Сервисный слой. HTTP-логика вынесена в ollama.service.ts, executor остаётся тонким адаптером между SDK и доменом.
Несколько файлов help. В package.json поле conveyorPluginBuild.helpMarkdown может указывать { "distRelativePath": "…/help.md" }, если primary help не первый в dist/.
Расширенные возможности (staticAssets, формы воркспейса, widgets, presets) описаны в SDK и в исходниках repo. На landing пошаговый tutorial для них не приводится. Presets регистрируются через preset-service, не через manifest v2.
Проверка публикации
- Исполнитель запущен в контуре, токены совпадают с ядром (см. Подключение).
- В редакторе на вкладке «Плагины» включите переключатель. Статус «онлайн» означает, что plugin-manager видит pull-endpoint.
- На вкладке «Палитра» появляются узлы с вашими
nodeType. - В логах процесса плагина:
plugin_wire_outbound_manifest_ok. В логах plugin-manager:plugin_publication_committed. - Маркер
plugin_static_cachedпоявляется только если в manifest непустой массивstaticAssets. - Соберите процесс с одним узлом плагина и выполните тестовый Запуск.
Секреты и параметры узлов настраиваются в полях узла на канвасе (тип ref → «Хранилище»), а не на карточке плагина, если variables в manifest пусты.
Диагностика
| Симптом | Что проверить |
|---|---|
unauthorized | PLUGIN_MANAGER_INGRESS_TOKEN, PLUGIN_CONTROL_PLANE_KEY совпадают с ядром |
| batch pull не доходит | pull.host и порт достижимы из сети plugin-manager (DNS sidecar или IP хоста) |
| узлов нет в палитре | логи manifest, плагин включён в UI |
Operational-детали demo и external stack: Подключение и интеграции и README репозитория plugins.
Docker-образ одного плагина
В checkout repo используется multi-stage Dockerfile.plugin. Сборка из корня checkout (подставьте <id>):
docker build -f Dockerfile.plugin --build-arg PLUGIN_DIR=<id> -t plugin-<id>:local .
SDK резолвится из npm lockfile, каталог dist/ на хосте перед сборкой образа не обязателен. Sidecar-сервисы в compose repo описаны в README.