Перейти к содержанию
CADCAMFUN
Документы

Документация

Напишите плагин помощника

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

Автоматически переведено с английского. Смотреть оригинал на английском

Выберите формат расширения помощника

Загрузчик расширений Production Assistant принимает каталог, содержащий плагин Plugin.json и связанную запись JavaScript. Он импортирует модуль в рабочий процесс Bun и предоставляет помощнику объявленные функции из записи aiTools. В настоящее время поддерживается возможность ai:tool. В этом руководстве создается калькулятор окружности болтов, доступный только для чтения, который возвращает координаты; он не вставляет геометрию в чертеж.

В каталоге /api/plugins также имеется ZIP API для плагина браузера с манифестом.json, main, разрешениями браузера и ресурсами начальной загрузки. Этот установщик не включает рабочий плагин, описанный здесь. ссылка на HTTP-плагин документы, разделяющие формат; Плагины объясняет обе поверхности. Не осуществляйте перевод между ними, просто переименовывая манифест.

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

Создайте каталог и запись согласия.

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

Каталог плагинов приложения
<dataDir>/plugins/
  enabled.json
  com.example.bolt-circle/
    plugin.json
    index.js

Рабочий загрузчик считывает файл Enabled.json как массив безопасных идентификаторов JSON. Он игнорирует повторяющиеся/недействительные записи, а неверный формат или отсутствие JSON означает, что плагины не включены. Папка, не указанная в списке, не загружается. Загрузчик также отклоняет несоответствие идентификатора папки и манифеста и манифесты, запрашивающие неподдерживаемые возможности.

Загрузка происходит при инициализации службы плагина помощника. Он не настраивает наблюдатель файловой системы для горячей перезагрузки. Сначала подготовьте и проверьте файлы, затем включите/перезапустите этот экземпляр. Неисправный плагин регистрирует предупреждение, в то время как запуск других плагинов и приложений продолжается; проверяйте эти предупреждения вместо того, чтобы предполагать, что запись в включенном файле гарантирует работу инструмента.

Объявите точный контракт на инструмент

Этот полный манифест называет один инструмент чтения. Идентификатор вклада — это локальный идентификатор, связанный с моделью; запись называет функцию, экспортируемую модулем. Эти строки могут различаться, как в данном случае Bolt_circle и BoltCircle.

plugin.json
{
  "id": "com.example.bolt-circle",
  "name": "Bolt circle calculator",
  "version": "1.0.0",
  "apiVersion": "1",
  "entry": "index.js",
  "capabilities": ["ai:tool"],
  "contributes": {
    "aiTools": [{
      "id": "bolt_circle",
      "description": "Calculate equally spaced XY hole centers around the origin for a bolt circle. Returns coordinates without changing a drawing.",
      "kind": "read",
      "entry": "boltCircle",
      "parameters": {
        "type": "object",
        "properties": {
          "count": { "type": "integer", "minimum": 1, "maximum": 64 },
          "radius": { "type": "number", "exclusiveMinimum": 0 }
        },
        "required": ["count", "radius"],
        "additionalProperties": false
      }
    }]
  }
}

Для SDK требуются идентификаторы обратного DNS, состоящие из символов 3–128, семантическая версия major.minor.patch с дополнительной предварительной версией, версия API "1", непустое имя/запись и признанные возможности. Идентификаторы инструментов начинаются со строчной буквы и могут содержать строчные буквы, цифры или знаки подчеркивания длиной до 40 символов. Описания содержат символы 10–2,000. Тип инструмента — чтение или запись; не существует деструктивного типа расширения.

Сохраняйте схему параметров небольшой и описательной. Его роль — помочь модели выдавать действительные аргументы и позволить адаптеру отклонять обычные ошибки перед выполнением. Он не заменяет проверку внутри кода.

Реализуйте автономный модуль

Запись экспортирует aiTools с функцией записи, указанной в манифесте. Он снова проверяет аргументы времени выполнения и возвращает небольшой результат, совместимый с JSON. Арифметика с конечными координатами и ограниченный счетчик не позволяют некорректному вводу создавать неограниченный список или бессмысленный вывод.

index.js
export const aiTools = {
  boltCircle: async (args) => {
    if (!args || typeof args !== "object") {
      return { ok: false, error: "Expected count and radius" }
    }
    const { count, radius } = args
    if (!Number.isInteger(count) || count < 1 || count > 64) {
      return { ok: false, error: "count must be an integer from 1 to 64" }
    }
    if (typeof radius !== "number" || !Number.isFinite(radius) || radius <= 0) {
      return { ok: false, error: "radius must be a positive finite number" }
    }
    const holes = Array.from({ length: count }, (_, index) => {
      const angle = 2 * Math.PI * index / count
      return {
        x: Number((radius * Math.cos(angle)).toFixed(4)),
        y: Number((radius * Math.sin(angle)).toFixed(4))
      }
    })
    return { ok: true, units: "mm", holes }
  }
}

Count 4 and radius 10 return centers at approximately (10,0), (0,10), (−10,0), and (0,−10), in counter-clockwise order around the origin. The result deliberately contains no database mutation or drawing identifier. A client wanting to insert holes must use a separate supported application action with its own access and permission behavior.

Объедините зависимости в запись, а не предполагайте, что относительный импорт в стиле Node разрешится. Хост считывает текст ввода и импортирует его через модуль BLOB-объектов. Код верхнего уровня модуля запускается при импорте, поэтому избегайте побочных эффектов от простой загрузки калькулятора.

Проверьте манифест и оба пути аргументов.

Подтвердите перед добавлением плагина в файл Enabled.json. Эта проверка разработки использует тот же синтаксический анализатор манифеста SDK и адаптер схемы AI, что и приложение. Поместите скрипт в рабочую область с этими зависимостями, например apps/sidecar, и передайте в качестве аргумента абсолютный каталог плагина.

Сценарий проверки разработки
import { join } from "node:path"
import { Effect } from "effect"
import { parseManifest } from "@cadcamfun/plugin-sdk"
import { pluginParameters } from "@cadcamfun/ai"

const directory = process.argv[2]
if (!directory) throw new Error("Pass the absolute plugin directory")
const manifest = await Effect.runPromise(parseManifest(
  await Bun.file(join(directory, "plugin.json")).text()))
if (manifest.capabilities.some((capability) => capability !== "ai:tool")) {
  throw new Error("This production loader accepts only ai:tool")
}
const contribution = manifest.contributes?.aiTools?.[0]
if (!contribution) throw new Error("No tool contribution")
const parameters = pluginParameters(contribution.parameters)
console.log(parameters.safeParse({ count: 4, radius: 10 }).success) // true
console.log(parameters.safeParse({ count: 0, radius: 10 }).success) // false
const module = await import(join(directory, manifest.entry))
console.log(await module.aiTools[contribution.entry]({ count: 4, radius: 10 }))
console.log(await module.aiTools[contribution.entry]({ count: 0, radius: 10 }))

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

Включите и узнайте действительный идентификатор инструмента

После проверки включите идентификатор в каталоге данных приложения:

enabled.json
["com.example.bolt-circle"]

Перезапустите/переинициализируйте предполагаемую дополнительную службу и проверьте журналы на наличие предупреждений о загрузке. Затем перечислите GET /api/ai/actions. Инструменты плагина чтения доступны там, а также во встроенном помощнике; политика может сузить каталог. Идентификатор инструмента генерируется на основе идентификатора плагина и локального идентификатора инструмента, нормализованных и привязанных к размеру идентификатора хоста.

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

Инструмент записи помечен для одобрения человеком во встроенном помощнике, независимо от обычного режима разрешений. Внешний мост предоставляет только инструменты плагина для чтения и отказывается от вызовов расширения записи даже при наличии токена чтения/записи. Будьте добры и аккуратны; приложение не может вывести произвольные побочные эффекты модуля из схемы JSON.

Вызов инструмента чтения через внешний доступ с ограниченной областью действия.

Используйте токен моста, выданный приложением, для реального проекта. Его носитель открывает только GET /api/ai/actions и POST /api/ai/actions/invoke. Он не позволяет вызывающим сторонам устанавливать плагины, редактировать учетные данные или перечислять несвязанные проекты. Проект/режим токена проверяется обработчиком действий; токен всего приложения не нужен для автономного клиента калькулятора.

bridge-call.json с реальным идентификатором проекта
{
  "projectId": "replace-with-your-project-id",
  "tool": "plugin_com_example_bolt_circle_bolt_circle",
  "input": { "count": 4, "radius": 10 }
}
Вызов работающего плагина
curl --fail-with-body \
  -H "Authorization: Bearer $CADCAMFUN_BRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @bridge-call.json \
  "$CADCAMFUN_URL/api/ai/actions/invoke"

Входные данные плагина — это объявленный объект аргумента; в отличие от встроенных сгруппированных инструментов, этот плагин чтения не требует дискриминатора действий внутри ввода. Мост оборачивает возвращаемое значение метаданными инструмента/действия; действие запущено. На уровне функции ok=false остается читаемым результатом, а не успехом HTTP-транспорта, подтверждающим полезный список координат.

Политика моста проверяет Tool.use и Bridge.use. Отсутствующий, просроченный, отозванный или неправильный токен приводит к сбою авторизации. Токен, привязанный к другому проекту, не является способом расширить область действия этого вызова.

Понимать преобразование схемы и ограничения возможностей.

Адаптер преобразует схему JSON вклада в zod, если она представима. Если преобразование завершается неудачей, схема превышает 20,000 сериализованных символов или не описывает объект, она возвращается к схеме произвольного объекта. Вот почему функция из примера сама проверяет счетчик и радиус. Отрицательное фикстуру поддерживаемой схемы, передаваемое локально, не доказывает, что каждая функция схемы останется представимой.

SDK распознает рисование: чтение, рисование: запись, путь к инструменту: чтение, хранилище, пользовательский интерфейс: панель и ai: инструмент; рисование-запись подразумевает рисование-чтение. Загрузчик производственного помощника в настоящее время принимает только ai:tool. Добавление draw:write в этот манифест приводит к его пропуску без предоставления контекста редактора рисунков.

Общая рабочая загрузка содержит заполнители для рисования/траекторий/обработчиков пользовательского интерфейса. Эти обработчики не являются интеграцией производственной геометрии. Аналогичным образом, объявление вклада постпроцессора или операций не заставляет помощника загрузчика вносить их в производственные реестры. Выберите поддерживаемое действие приложения, когда функции необходимо изменить реальные данные CAD/CAM.

Проектируйте с учетом реализованного жизненного цикла работника

SDK описывает модуль с перехватчиками манифеста, активации, дополнительной очистки и деактивации. Текущий производственный путь AI импортирует запись и вызывает экспортированные функции aiTools. Его рабочий процесс активации/деактивации обработчиков RPC подтверждает сообщения жизненного цикла, но не вызывает перехватчики экспортированных модулей. Таким образом, калькулятор может использовать показанный здесь минимальный модуль, не зависящий от обратных вызовов активации.

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

Тайм-аут вызова завершает работу его работника и немедленно приводит к сбою плагина. Сбои воркера и ошибки публикации также удаляют работающий экземпляр и отмечают его как неисправный. История сбоев имеет десятиминутное окно, но текущий обработчик дает сбой при первом сбое; он не ждет трех успешных попыток перезапуска. Исправьте источник и намеренно перезагрузите/повторно включите вместо автоматического перезапуска.

Соблюдайте пропорциональность гарантий времени выполнения

Рабочий загрузчик предоставляет 10-секундный бюджет хоста для обычного жизненного цикла/командного RPC. Вызовы инструментов искусственного интеллекта имеют отдельный крайний срок в 30 секунды. Хост ограничивает плагин 2, 000 вызовами в минуту и 64 ожидающими вызовами. Он передает параметр ограничения ресурсов 256 МБ в Bun при создании рабочего процесса. Это элементы управления во время выполнения, а не отдельный процесс или политика сдерживания операционной системы.

Начальная загрузка начинается с пустой среды и пытается удалить выбранные глобальные переменные процесса/сети. Удаление выполняется с максимальной эффективностью, и некоторые глобальные элементы Bun остаются доступными. Таким образом, проверка возможностей имеет смысл для API, предоставляемых хостом, но не может быть представлена как полная изоляция произвольного JavaScript.

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

Плагины, в которых происходит сбой трижды в течение десяти минут, автоматически отключаются, а вызов помощника прекращается через 30 секунд. Оба значения являются константами в apps/sidecar/src/plugins/host.ts.

Обновление, удаление и диагностика инструмента

Для обновления отредактируйте и проверьте связанный модуль/манифест перед перезапуском целевой службы. Сохраняйте его идентификатор стабильным, если это одно и то же расширение, и увеличьте версию, чтобы определить, что было загружено. Чтобы прекратить его загрузку при будущей инициализации, удалите его идентификатор из Enabled.json и перезапустите/повторно инициализируйте. Изменение файла само по себе не удаляет уже работающий рабочий процесс.

Если инструмент отсутствует, проверьте включенный массив, точное равенство идентификаторов папки и манифеста, список поддерживаемых возможностей и ошибку декодирования манифеста в журналах. NoSuchTool обычно означает, что запись не называет экспортированную функцию aiTools. Отказ от аргумента указывает на защиту схемы или функции. Тайм-аут указывает на блокировку работы или невыполненное обещание. Конечные точки включения/конфигурации ZIP браузера не управляют этим файлом согласия работника.

Целенаправленное освещение находится в apps/sidecar/test/plugins-ai-tools.test.ts для реальных работников и ai-plugin-tools.test.ts для производственной загрузки, проверки аргументов, доступа к чтению/записи и поведения моста. Источники реализации: packages/plugin-sdk/src/manifest.ts, packages/ai/src/tools/plugin-tool.ts, apps/sidecar/src/plugins/host.ts, и services/ai-plugins.ts. Используйте эти границы, чтобы определить, что на самом деле доказал успешный тест.

Коротко о правилах контракта

ЭлементОграничениеЧто произойдет, если нарушить
Инструмент id^[a-z][a-z0-9_]{0,39}$Декодирование манифеста не удалось; плагин не загружается.
description10–2,000 символовДекодирование манифеста не удалось.
kindread или write; нет разрушительного видаДекодирование манифеста не удалось.
parametersОбъект схемы JSON, не более 20,000 символов при сериализацииНегабаритные или неконвертируемые схемы возвращаются к принятию любого объекта.
ВозможностиТолько ai:tool в помощнике ведущегоПлагин пропускается с предупреждением.
Имя папкиРавен манифесту idПлагин пропускается с предупреждением, в котором указаны оба значения.
Обычный бюджет звонка5 с на вызов по умолчаниюРабочий остановлен, как и любой не отвечающий плагин.
Бюджет вызова помощника30 sВызов возвращает неудачный результат.
Память256 МБ кучиРабочий убит.
Ставка2, 000 вызовов на плагин в минуту, 64 ожидающих вызововЗвонки сверх тарифа отклоняются; полная очередь терпит неудачу с plugin RPC queue is full.
Сбои и таймаутыНасчитывается более 10 минут, ограничение — 3.Каждый сбой или тайм-аут завершает работу работника и помечает плагин как неисправный.

Напишите описание модели. Укажите, что вычисляет инструмент, его единицы измерения и когда его использовать; например, «Возвращает центры отверстий окружности болтов в миллиметрах. Используйте, когда пользователь запрашивает равномерное расположение отверстий по диаметру». Расплывчатые описания приводят к тому, что инструменты вызываются не вовремя или вообще не вызываются.

Контрольный список перед выпуском

  1. Объедините запись в один автономный модуль. Рабочий не может разрешить импорт рабочей области во время выполнения.
  2. Бегать parseManifest в финале plugin.json и исправить каждую сообщенную проблему.
  3. Вызовите каждую экспортированную функцию инструмента напрямую с допустимыми, граничными и недопустимыми аргументами и убедитесь, что недопустимый ввод приводит к читаемому результату ошибки, а не к исключению исключения.
  4. Сохраняйте результаты небольшими и совместимыми с JSON. Ассистент читает их, а большие результаты заполняют контекст.
  5. Выбирать read если инструмент что-то не изменит. А write инструмент запрашивает пользователя перед каждым вызовом.
  6. Поместите папку под <data dir>/plugins/<id>/, добавьте идентификатор в enabled.json, перезапустите сайдкар и подтвердите производный идентификатор инструмента из списка инструментов помощника.
  7. Ударяться version за каждое отправленное вами изменение и сохраните id стабильный, поэтому идентификатор производного инструмента не изменяется.

Матрица устранения неполадок

СимптомВероятная причинаИсправить
Инструмент никогда не появляетсяID отсутствует в enabled.json, или JSON имеет неверный форматИсправить массив; искаженный или отсутствующий JSON ничего не дает.
В журнале указано, что папка называется X, но в манифесте указано Y.Папка и манифест id отличатьсяПереименуйте один, чтобы они точно совпадали.
В журнале написано, что запрашивается рисунок: читайте,...Неподдерживаемая возможность на этом хостеОбъявить только ai:tool.
Ассистент передает неожиданные формы аргументовСхема вернулась к любому объектуИспользуйте схему объекта с properties под символами 20,000, а также проверяйте внутри функции.
Возврат звонков ok: false примерно через 30 сек.Инструмент превысил бюджет времениВыполняйте меньше работы за вызов или предварительные вычисления; избегайте неограниченных циклов.
Плагин перестает отвечать после ошибкиСбой или тайм-аут рабочего завершает работу и помечает плагин. faulted; сбои также учитываются в течение 10-минутного окна с ограничением 3.Устраните сбой, а затем перезапустите сайдкар, чтобы загрузить ее снова.

Проверка манифеста перед установкой

check-manifest.ts
import { decodeManifest, requestedCapabilities } from "@cadcamfun/plugin-sdk"
import { Effect } from "effect"

const raw = JSON.parse(await Bun.file(process.argv[2] ?? "plugin.json").text())
const manifest = await Effect.runPromise(decodeManifest(raw))   // throws a SchemaError naming the bad field
console.log(manifest.id, manifest.version, requestedCapabilities(manifest))
for (const tool of manifest.contributes?.aiTools ?? [])
  console.log(`plugin_${manifest.id}_${tool.id}`, tool.kind)
Распространенная ошибкаИсправить
"version": "1.0"Используйте три цифры: 1.0.0
"apiVersion": 1Это строка: "1"
Идентификатор плагина gear или My.PluginОбратный DNS, нижний регистр: com.example.gear
Идентификатор инструмента Lookup-ThreadНижний регистр, цифры и символы подчеркивания, сначала буква, символы ≤ 40
Описание инструмента короче 10 символов.Опишите, что он делает и когда его использовать.
Объявление обоих drawing:read и drawing:writeРазрешено, но drawing:write само по себе уже подразумевает чтение
Ключ хранения, начинающийся с / или содержащий ..Используйте относительные ключи, такие как presets/m2

Через 3Д

Таблицы плагинов Перетащите на орбиту · прокрутите, чтобы увеличить · перетащите вправо, чтобы панорамировать
PluginRegistryEntry и PluginConfiguration из миграций: конфигурации ссылаются на записи реестра.