Saltar al contenido
CADCAMFUN
Documentos

Documentación

Escribir un complemento de herramienta asistente

Cree una herramienta de lectura autónoma, valide su manifiesto y sus argumentos, habilítela deliberadamente y pruebe el límite de trabajo que realmente recibe.

Traducido automáticamente del inglés. Ver el original en inglés

Elija el formato de extensión del asistente

El cargador de extensiones del asistente de producción acepta un directorio que contiene plugin.json y una entrada de JavaScript incluida. Importa el módulo a un trabajador Bun y expone las funciones declaradas desde su registro aiTools al asistente. La capacidad actualmente admitida es ai:tool. Esta guía crea una calculadora de círculos de pernos de solo lectura que devuelve coordenadas; no inserta geometría en un dibujo.

También hay una API ZIP de complemento de navegador en /api/plugins con manifest.json, main, permisos de navegador y activos de arranque. Ese instalador no habilita el complemento de trabajo que se describe aquí. El referencia HTTP del complemento documentos que separan formato; Complementos explica ambas superficies. No traduzca entre ellos simplemente cambiando el nombre de un manifiesto.

Una herramienta asistente es un código ejecutado dentro del límite del tiempo de ejecución de la aplicación. Las comprobaciones de capacidad del host limitan el acceso a través del RPC del host, pero el trabajador actual no es un entorno limitado del sistema operativo. Utilice un código de extensión cuya ejecución sea apropiada para ese entorno y haga que su comportamiento de lectura/escritura declarado coincida con lo que realmente hace la función.

Crear el directorio y el registro de consentimiento.

Utilice el directorio de datos de aplicación exacto del sidecar que desea ampliar. Cree esta estructura, manteniendo el ID del directorio idéntico al ID de DNS inverso del manifiesto:

Directorio de complementos de aplicaciones
<dataDir>/plugins/
  enabled.json
  com.example.bolt-circle/
    plugin.json
    index.js

El cargador de producción lee enable.json como una matriz JSON de identificadores seguros. Ignora las entradas duplicadas/no válidas, y JSON con formato incorrecto o faltante significa que no hay complementos habilitados. Una carpeta no listada no está cargada. El cargador también rechaza una discrepancia de ID de manifiesto/carpeta y manifiestos que solicitan capacidades no compatibles.

La carga se produce cuando se inicializa el servicio del complemento asistente. No configura un observador del sistema de archivos para recarga en caliente. Primero prepare y valide los archivos, luego habilite/reinicie esa instancia. Un complemento fallido registra una advertencia mientras otros complementos y el inicio de la aplicación continúan; inspeccione esas advertencias en lugar de asumir que una entrada de archivo habilitada garantiza una herramienta en ejecución.

Declarar un contrato de herramienta preciso

Este manifiesto completo nombra una única herramienta de lectura. El ID de contribución es el identificador local del modelo; La entrada nombra la función exportada por el módulo. Esas cadenas pueden diferir, como lo hacen aquí Bolt_circle y 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
      }
    }]
  }
}

El SDK requiere ID de DNS inverso de 3–128 caracteres, una versión semántica major.minor.patch con versión preliminar opcional, versión de API "1", nombre/entrada que no esté vacío y capacidades reconocidas. Los ID de herramientas comienzan con una letra minúscula y utilizan letras minúsculas, dígitos o guiones bajos de hasta 40 caracteres. Las descripciones contienen 10–2,000 caracteres. El tipo de herramienta es de lectura o escritura; No existe ningún tipo de extensión destructiva.

Mantenga el esquema de parámetros pequeño y descriptivo. Su función es ayudar al modelo a producir argumentos válidos y permitir que el adaptador rechace errores comunes antes de la ejecución. No reemplaza la validación dentro del código.

Implementar el módulo autónomo.

La entrada exporta aiTools con la función de entrada nombrada en el manifiesto. Valida nuevamente los argumentos en tiempo de ejecución y devuelve un pequeño resultado compatible con JSON. La aritmética de coordenadas finitas y el recuento acotado evitan que la entrada con formato incorrecto produzca una lista ilimitada o una salida sin sentido.

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.

Agrupe las dependencias en la entrada en lugar de asumir que se resuelven las importaciones relativas al estilo de nodo. El host lee el texto de entrada y lo importa a través de un módulo blob. El código de nivel superior del módulo se ejecuta al importar, así que evite los efectos secundarios simplemente al cargar una calculadora.

Validar el manifiesto y ambas rutas de argumentos.

Valide antes de agregar el complemento a enable.json. Esta verificación de desarrollo utiliza el mismo analizador de manifiesto SDK y adaptador de esquema AI que la aplicación. Coloque el script en un espacio de trabajo con esas dependencias, como apps/sidecar, y pase el directorio absoluto del complemento como argumento.

Guión de validación de desarrollo
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 }))

Las dos últimas llamadas prueban el comportamiento a nivel de función independientemente del rechazo del adaptador. El SDK valida la estructura del manifiesto, pero el cargador de producción agrega su propia capacidad y reglas de ID de carpeta. Pruebe los tres límites: declaración, adaptador de argumentos y función del módulo real.

Habilite y descubra el identificador de herramienta real

Después de la validación, habilite la ID en el directorio de datos de la aplicación:

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

Reinicie/reinicialice el servicio sidecar previsto e inspeccione los registros para detectar advertencias de carga. Luego enumere GET /api/ai/actions. Las herramientas de complemento de lectura están expuestas allí, así como al asistente integrado; La política puede reducir el catálogo. El identificador de herramienta se genera a partir del ID del complemento y el ID de la herramienta local, normalizado y limitado al tamaño del identificador del host.

Para este manifiesto, el ID derivado actual es plugin_com_example_bolt_circle_bolt_circle. Descúbrelo en lugar de volver a implementar la regla de nombres en cada cliente. Un ID de complemento largo se puede truncar para dejar espacio para el sufijo de la herramienta. La descripción del catálogo incluye el nombre del complemento para que el usuario pueda identificar la fuente.

Una herramienta de escritura está marcada para aprobación humana en el asistente integrado, independientemente del modo de permiso ordinario. El puente exterior solo expone herramientas de complemento de lectura y rechaza llamadas de extensión de escritura incluso con un token de lectura/escritura. Sea amable y preciso; la aplicación no puede inferir efectos secundarios de módulos arbitrarios a partir de un esquema JSON.

Llame a una herramienta de lectura a través del acceso externo con alcance

Utilice un token puente emitido por la aplicación para un proyecto real. Su portador abre solo GET /api/ai/actions y POST /api/ai/actions/invoke. No permite que las personas que llaman instalen complementos, editen credenciales o enumeren proyectos no relacionados. El controlador de acciones verifica el proyecto/modo del token; un token para toda la aplicación no es necesario para un cliente de calculadora independiente.

bridge-call.json, con un ID de proyecto real
{
  "projectId": "replace-with-your-project-id",
  "tool": "plugin_com_example_bolt_circle_bolt_circle",
  "input": { "count": 4, "radius": 10 }
}
Invocar la herramienta de complemento en ejecución
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"

Las entradas del complemento son el objeto de argumento declarado; A diferencia de las herramientas agrupadas integradas, este complemento de lectura no requiere un discriminador de acción dentro de la entrada. El puente envuelve el valor devuelto con metadatos de herramienta/acción; se ejecuta la acción. El nivel de función ok=false sigue siendo un resultado legible en lugar de un éxito del transporte HTTP, lo que demuestra una lista de coordenadas útil.

La política de puente comprueba el uso de herramientas y el uso de puentes. Un token faltante, caducado, revocado o de tipo incorrecto produce un error de autorización. Un token vinculado a otro proyecto no es una forma de ampliar el alcance de esta convocatoria.

Comprender la conversión de esquemas y los límites de capacidad

El adaptador convierte el esquema JSON de la contribución a zod cuando sea representable. Si la conversión falla, el esquema excede 20,000 caracteres serializados o no describe un objeto, recurre a un esquema de objeto arbitrario. Es por eso que la función de ejemplo verifica el recuento y el radio. El hecho de que un elemento negativo de un esquema admitido pase localmente no prueba que todas las características del esquema seguirán siendo representables.

El SDK reconoce dibujo: lectura, dibujo: escritura, ruta de herramienta: lectura, almacenamiento, ui: panel y ai: herramienta; dibujar escribir implica dibujar leer. Actualmente, el cargador del asistente de producción solo acepta ai:tool. Agregar dibujo: escribir a este manifiesto hace que se omita y no se le otorgue un contexto de editor de dibujo.

El programa de arranque del trabajador general contiene controladores de dibujo/trayectoria/UI de marcador de posición. Esos controladores no son una integración de geometría de producción. Asimismo, declarar los aportes de posprocesamiento u operación no obliga al ayudante de carga a incorporarlos a los registros de fabricación. Elija una acción de aplicación compatible cuando la función necesite cambiar datos CAD/CAM reales.

Diseño en torno al ciclo de vida del trabajador implementado

El SDK describe un módulo con ganchos de manifiesto, activación, limpieza opcional y desactivación. La ruta de producción actual de IA importa la entrada y llama a las funciones de aiTools exportadas. Su trabajador activa/desactiva los controladores RPC reconoce los mensajes del ciclo de vida pero no invoca los enlaces del módulo exportado. Por lo tanto, una calculadora puede utilizar el módulo mínimo que se muestra aquí sin depender de las devoluciones de llamada de activación.

El host inicia un trabajador por complemento habilitado, correlaciona las respuestas con los ID de RPC y realiza un seguimiento de las llamadas pendientes. Una excepción de función falla en esa llamada; Las pruebas enfocadas en trabajadores reales muestran que las llamadas posteriores aún pueden tener éxito. Devuelva rechazos estructurados para entradas no válidas esperadas y reserve fallas arrojadas para errores de cálculo inesperados.

Un tiempo de espera de llamada termina su trabajador y falla el complemento inmediatamente. Los bloqueos de los trabajadores y los errores de publicación también eliminan la instancia en ejecución y la marcan como errónea. El historial de fallos tiene una ventana de diez minutos, pero el controlador actual falla en un primer fallo; no espera tres intentos exitosos de reinicio. Corrija la fuente y vuelva a cargar/habilitar deliberadamente en lugar de asumir el reinicio automático.

Mantenga las garantías de tiempo de ejecución proporcionadas

El cargador de producción proporciona un presupuesto de host de 10 segundos para RPC de comando/ciclo de vida normal. Las llamadas a herramientas de IA tienen una fecha límite separada de 30 segundos. El anfitrión limita un complemento a 2,000 llamadas por minuto y 64 llamadas pendientes. Pasa una configuración de límite de recursos de 256 MB a Bun al crear el trabajador. Estos son controles de tiempo de ejecución, no un proceso separado o una política de contención del sistema operativo.

El programa de arranque comienza con un entorno vacío e intenta eliminar los procesos/redes globales seleccionados. La eliminación es el mejor esfuerzo y algunos globales de Bun siguen siendo accesibles. Por lo tanto, la verificación de capacidad es significativa para las API que proporciona el host, pero no puede presentarse como un aislamiento completo de JavaScript arbitrario.

Existen campos opcionales de firma y desarrollo en el esquema de manifiesto. La ruta de instalación del trabajador actual registra el texto de la firma sin verificación criptográfica. No etiquete a un editor como verificado porque ese campo está presente. Una política de instalación y revisión de fuente autónoma siguen siendo decisiones independientes de la aceptación del esquema.

Los complementos que fallan tres veces en diez minutos se desactivan automáticamente y la llamada a la herramienta asistente se detiene después de 30 segundos. Ambos valores son constantes en apps/sidecar/src/plugins/host.ts.

Actualizar, eliminar y diagnosticar una herramienta

Para una actualización, edite y valide el módulo/manifiesto incluido antes de reiniciar el servicio de destino. Mantenga estable su ID cuando sea la misma extensión y aumente la versión para identificar lo que se cargó. Para dejar de cargarlo en una inicialización futura, elimine su ID de enable.json y reinicie/reinicialice. Cambiar el archivo por sí solo no elimina un trabajador que ya se está ejecutando.

Si falta la herramienta, verifique la matriz habilitada, la igualdad exacta de ID de carpeta/manifiesto, la lista de capacidades admitidas y el error de decodificación de manifiesto en los registros. NoSuchTool generalmente significa que la entrada no nombra una función de aiTools exportada. Un rechazo de argumento apunta al esquema o función de guardia. Un tiempo de espera indica un bloqueo del trabajo o una promesa no resuelta. Los puntos finales de configuración/activación de ZIP del navegador no administran este archivo de consentimiento del trabajador.

La cobertura enfocada está en apps/sidecar/test/plugins-ai-tools.test.ts para trabajadores reales y ai-plugin-tools.test.ts para carga de producción, validación de argumentos, exposición de lectura/escritura y comportamiento de puente. Las fuentes de implementación son packages/plugin-sdk/src/manifest.ts, packages/ai/src/tools/plugin-tool.ts, apps/sidecar/src/plugins/host.ts, y services/ai-plugins.ts. Utilice estos límites para determinar lo que realmente demostró una prueba exitosa.

Reglas del contrato de un vistazo

ArtículoRestricción¿Qué pasa si se viola?
Herramienta id^[a-z][a-z0-9_]{0,39}$La decodificación del manifiesto falla; el complemento no está cargado.
description10–2,000 caracteresLa decodificación del manifiesto falla.
kindread o write; no hay ningún tipo destructivoLa decodificación del manifiesto falla.
parametersObjeto de esquema JSON, como máximo 20,000 caracteres cuando se serializaLos esquemas sobredimensionados o no convertibles vuelven a aceptar cualquier objeto.
CapacidadesSolo ai:tool en el asistente de anfitriónEl complemento se omite con una advertencia.
Nombre de la carpetaIgual al manifiesto idEl complemento se omite con una advertencia que nombra ambos valores.
Presupuesto de convocatoria ordinaria5 s por llamada de forma predeterminadaEl trabajador se detiene como cualquier complemento que no responde.
Presupuesto de llamada de herramienta asistente30 sLa llamada devuelve un resultado de error.
Memoria256 MB de montónEl trabajador muere.
Tasa2,000 llamadas por complemento por minuto, 64 llamadas pendientesSe rechazan las llamadas que superen la tarifa; una cola completa falla con plugin RPC queue is full.
Fallos y tiempos de esperaContado durante 10 minutos, límite 3Cada falla o tiempo de espera finaliza al trabajador y marca el complemento como defectuoso.

Escribe la descripción del modelo. Indique qué calcula la herramienta, sus unidades y cuándo usarla; por ejemplo, "Devuelve los centros de los orificios de un círculo de pernos en milímetros. Utilícelo cuando el usuario solicite orificios espaciados uniformemente en un diámetro". Las descripciones vagas provocan que las herramientas se llamen en el momento equivocado o que no se llamen en absoluto.

Lista de verificación previa al lanzamiento

  1. Agrupe la entrada en un único módulo autónomo. El trabajador no puede resolver las importaciones de espacios de trabajo en tiempo de ejecución.
  2. Correr parseManifest en la final plugin.json y solucione todos los problemas informados.
  3. Llame a cada función de herramienta exportada directamente con argumentos válidos, de límite y no válidos, y confirme que la entrada no válida produce un resultado de error legible en lugar de una excepción que se escapa.
  4. Mantenga los resultados pequeños y compatibles con JSON. El asistente los lee y los resultados grandes llenan el contexto.
  5. Elegir read a menos que la herramienta cambie algo. A write la herramienta avisa al usuario antes de cada llamada.
  6. Coloque la carpeta debajo <data dir>/plugins/<id>/, agregue el ID a enabled.json, reinicie el sidecar y confirme la ID de herramienta derivada de la lista de herramientas del asistente.
  7. Bulto version por cada cambio que envíes y mantén id estable, por lo que el ID de la herramienta derivada no cambia.

Matriz de resolución de problemas

Síntomacausa probableArreglar
La herramienta nunca apareceFalta identificación de enabled.json, o el JSON tiene un formato incorrectoArreglar la matriz; JSON mal formado o faltante no permite nada.
El registro dice que la carpeta se llama X pero el manifiesto dice YCarpeta y manifiesto id diferir deCambie el nombre de uno para que coincida exactamente.
El registro dice que solicita un dibujo: leer, ...Capacidad no admitida en este hostDeclarar solo ai:tool.
El asistente pasa formas de argumento inesperadasEl esquema volvió a cualquier objeto.Utilice un esquema de objeto con properties debajo de 20,000 caracteres y valide también dentro de la función.
Devuelven llamadas ok: false después de aproximadamente 30 sLa herramienta superó su presupuesto de tiempoHaga menos trabajo por llamada o cálculo previo; Evite bucles ilimitados.
El complemento deja de responder después de un errorUn bloqueo o tiempo de espera del trabajador termina con el trabajador y marca el complemento faulted; los bloqueos también se cuentan durante una ventana de 10 minutos con un límite de 3Solucione el problema y luego reinicie el sidecar para cargarlo nuevamente.

Lint un manifiesto antes de instalar

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)
Error comúnArreglar
"version": "1.0"Utilice tres números: 1.0.0
"apiVersion": 1Es una cadena: "1"
ID del complemento gear o My.PluginDNS inverso, minúsculas: com.example.gear
Identificación de herramienta Lookup-ThreadMinúsculas, dígitos y guiones bajos, primera letra, ≤ 40 caracteres
Descripción de la herramienta con menos de 10 caracteresDescribe qué hace y cuándo usarlo.
declarando ambos drawing:read y drawing:writePermitido, pero drawing:write solo ya implica leer
Clave de almacenamiento que comienza con / o que contiene ..Utilice claves relativas como presets/m2

En 3D

Tablas de complementos Arrastrar para orbitar · desplazarse para hacer zoom · arrastrar con el botón derecho para desplazarse
PluginRegistryEntry y PluginConfiguration de las migraciones: las configuraciones hacen referencia a las entradas del registro.