Vai al contenuto
CADCAMFUN
Documentazione

Documentazione

Scrivi un plugin per lo strumento assistente

Costruisci uno strumento di lettura autonomo, convalidane il manifest e gli argomenti, abilitalo deliberatamente e testa il confine del lavoratore che effettivamente ricevi.

Tradotto automaticamente dall'inglese. Vedi l'originale in inglese

Scegli il formato dell'estensione dell'assistente

Il caricatore di estensioni dell'assistente di produzione accetta una directory contenente plugin.json e una voce JavaScript in bundle. Importa il modulo in un lavoratore Bun ed espone all'assistente le funzioni dichiarate dal suo record aiTools. La funzionalità attualmente supportata è ai:tool. Questa guida crea un calcolatore di cerchi di bulloni di sola lettura che restituisce le coordinate; non inserisce la geometria in un disegno.

Esiste anche un'API ZIP del plug-in del browser in /api/plugins con manifest.json, main, autorizzazioni del browser e risorse bootstrap. Quel programma di installazione non abilita il plugin di lavoro descritto qui. IL riferimento HTTP del plugin documenti che separano il formato; Plugin spiega entrambe le superfici. Non tradurre tra loro semplicemente rinominando un manifest.

Uno strumento assistente è un codice eseguito all'interno del limite del runtime dell'applicazione. I controlli della funzionalità dell'host limitano l'accesso tramite RPC dell'host, ma il lavoratore corrente non è un sandbox del sistema operativo. Utilizza il codice di estensione la cui esecuzione è appropriata per quell'ambiente e fai in modo che il suo comportamento di lettura/scrittura dichiarato corrisponda a ciò che fa effettivamente la funzione.

Creare la directory e il record di consenso

Utilizza l'esatta directory dei dati dell'applicazione del sidecar che intendi estendere. Crea questa struttura, mantenendo l'ID della directory identico all'ID DNS inverso del manifest:

Directory dei plugin dell'applicazione
<dataDir>/plugins/
  enabled.json
  com.example.bolt-circle/
    plugin.json
    index.js

Il caricatore di produzione legge Enabled.json come un array JSON di identificatori sicuri. Ignora le voci duplicate/non valide e JSON in formato errato o mancante significa che non sono abilitati plug-in. Una cartella non elencata non è caricata. Il caricatore rifiuta inoltre una mancata corrispondenza dell'ID cartella/manifest e i manifest che richiedono funzionalità non supportate.

Il caricamento avviene quando viene inizializzato il servizio plugin dell'assistente. Non configura un watcher del filesystem per il ricaricamento a caldo. Preparare e convalidare prima i file, quindi abilitare/riavviare l'istanza. Un plug-in non riuscito registra un avviso mentre gli altri plug-in e l'avvio dell'applicazione continuano; controllare tali avvisi invece di dare per scontato che una voce di file abilitato garantisca uno strumento in esecuzione.

Dichiarare un contratto strumento preciso

Questo manifest completo nomina un singolo strumento di lettura. L'ID contributo è l'identificatore locale rivolto al modello; la voce nomina la funzione esportata dal modulo. Queste stringhe possono differire, come fanno qui Bolt_circle e 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
      }
    }]
  }
}

L'SDK richiede ID DNS inversi di 3–128 caratteri, una versione semantica major.minor.patch con prerelease facoltativa, versione API "1", nome/voce non vuota e funzionalità riconosciute. Gli ID strumento iniziano con una lettera minuscola e utilizzano lettere minuscole, cifre o trattini bassi fino a 40 caratteri. Le descrizioni contengono 10–2,000 caratteri. Il tipo di strumento è di lettura o scrittura; non esiste un tipo di estensione distruttiva.

Mantenere lo schema dei parametri piccolo e descrittivo. Il suo ruolo è aiutare il modello a produrre argomenti validi e consentire all'adattatore di respingere gli errori ordinari prima dell'esecuzione. Non sostituisce la convalida all'interno del codice.

Implementare il modulo autonomo

La voce esporta aiTools con la funzione di voce denominata nel manifest. Convalida nuovamente gli argomenti di runtime e restituisce un piccolo risultato compatibile con JSON. L'aritmetica delle coordinate finite e il conteggio limitato impediscono all'input non corretto di produrre un elenco illimitato o un output privo di significato.

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.

Raggruppare le dipendenze nella voce anziché presumere che le importazioni relative in stile nodo vengano risolte. L'host legge il testo della voce e lo importa tramite un modulo blob. Il codice di livello superiore del modulo viene eseguito durante l'importazione, quindi evita gli effetti collaterali derivanti semplicemente dal caricamento di una calcolatrice.

Convalidare il manifest ed entrambi i percorsi degli argomenti

Convalidare prima di aggiungere il plug-in a Enabled.json. Questo controllo dello sviluppo utilizza lo stesso parser manifesto dell'SDK e l'adattatore dello schema AI dell'applicazione. Posiziona lo script in un'area di lavoro con tali dipendenze, ad esempio apps/sidecar, e passa la directory assoluta del plugin come argomento.

Script di convalida dello sviluppo
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 }))

Le ultime due chiamate testano il comportamento a livello di funzione indipendentemente dal rifiuto dell'adattatore. L'SDK convalida la struttura del manifest, ma il caricatore di produzione aggiunge le proprie funzionalità e regole per l'ID cartella. Testare tutti e tre i limiti: dichiarazione, adattatore dell'argomento e funzione effettiva del modulo.

Abilita e scopri l'identificatore effettivo dello strumento

Dopo la convalida, abilitare l'ID nella directory dei dati dell'applicazione:

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

Riavvia/reinizializza il servizio sidecar previsto e controlla i log per gli avvisi di caricamento. Quindi elenca GET /api/ai/actions. Gli strumenti dei plugin di lettura sono esposti lì così come nell'assistente incorporato; la politica può restringere il catalogo. L'identificatore dello strumento viene generato dall'ID del plugin e dall'ID dello strumento locale, normalizzato e limitato alla dimensione dell'identificatore dell'host.

Per questo manifest, l'ID derivato corrente è plugin_com_example_bolt_circle_bolt_circle. Scoprilo invece di reimplementare la regola di denominazione in ogni client. Un ID plug-in lungo può essere troncato per lasciare spazio al suffisso dello strumento. La descrizione del catalogo include il nome del plugin in modo che l'utente possa identificare la fonte.

Uno strumento di scrittura è contrassegnato per l'approvazione umana nell'assistente incorporato, indipendentemente dalla modalità di autorizzazione ordinaria. Il bridge esterno espone solo gli strumenti del plug-in di lettura e rifiuta le chiamate di estensione di scrittura anche con un token di lettura/scrittura. Sii gentile e accurato; l'applicazione non può dedurre effetti collaterali arbitrari del modulo da uno schema JSON.

Chiamare uno strumento di lettura tramite accesso esterno con ambito

Utilizza un token bridge emesso dall'applicazione per un progetto reale. Il suo portatore apre solo GET /api/ai/actions e POST /api/ai/actions/invoke. Non consente ai chiamanti di installare plug-in, modificare credenziali o enumerare progetti non correlati. Il progetto/modalità del token viene controllato dal gestore dell'azione; un token a livello di applicazione non è necessario per un client di calcolatrice autonomo.

bridge-call.json, con un ID progetto reale
{
  "projectId": "replace-with-your-project-id",
  "tool": "plugin_com_example_bolt_circle_bolt_circle",
  "input": { "count": 4, "radius": 10 }
}
Richiama lo strumento plugin in esecuzione
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"

Gli input del plugin sono l'oggetto argomento dichiarato; a differenza degli strumenti raggruppati integrati, questo plugin di lettura non richiede un discriminatore di azioni all'interno dell'input. Il bridge racchiude il valore restituito con i metadati dello strumento/azione; l'azione viene eseguita. Il livello di funzione ok=false rimane un risultato leggibile piuttosto che un successo del trasporto HTTP che dimostra un utile elenco di coordinate.

La policy bridge controlla tool.use e bridge.use. Un token mancante, scaduto, revocato o di tipo errato provoca un errore di autorizzazione. Un token associato a un altro progetto non è un modo per ampliare l'ambito di questa chiamata.

Comprendere la conversione dello schema e i limiti di capacità

L'adattatore converte lo schema JSON del contributo in zod quando rappresentabile. Se la conversione fallisce, lo schema supera i 20,000 caratteri serializzati o non descrive un oggetto, torna a uno schema di oggetti arbitrari. Questo è il motivo per cui la funzione di esempio controlla il conteggio e il raggio stesso. Il passaggio locale di un dispositivo negativo di uno schema supportato non dimostra che tutte le funzionalità dello schema rimarranno rappresentabili.

L'SDK riconosce drawing:read, drawing:write, toolpath:read, storage, ui:panel e ai:tool; disegnare scrivere implica disegnare leggere. Il caricatore dell'assistente di produzione attualmente accetta solo ai:tool. L'aggiunta di drawing:write a questo manifest fa sì che venga ignorato e non venga concesso un contesto di editor di disegno.

Il bootstrap del lavoratore generale contiene gestori di disegno/percorso utensile/interfaccia utente segnaposto. Questi gestori non sono un'integrazione della geometria di produzione. Allo stesso modo, la dichiarazione dei contributi post-processore o operativi non fa sì che l'assistente caricatore li colleghi ai registri di produzione. Scegli un'azione dell'applicazione supportata quando la funzionalità deve modificare dati CAD/CAM reali.

Progettare attorno al ciclo di vita del lavoratore implementato

L'SDK descrive un modulo con hook manifest, attivazione, pulizia facoltativa e disattivazione. L'attuale percorso AI di produzione importa la voce e richiama le funzioni aiTools esportate. I suoi gestori RPC di attivazione/disattivazione del lavoratore riconoscono i messaggi del ciclo di vita ma non richiamano gli hook del modulo esportati. Una calcolatrice può quindi utilizzare il modulo minimo mostrato qui senza dipendere dai callback di attivazione.

L'host avvia un lavoratore per plug-in abilitato, correla le risposte con gli ID RPC e tiene traccia delle chiamate in sospeso. Un'eccezione di funzione fallisce quella chiamata; test mirati su lavoratori reali mostrano che le chiamate successive possono ancora avere successo. Restituisce rifiuti strutturati per input non validi previsti e riserva gli errori generati per errori di calcolo imprevisti.

Un timeout della chiamata termina il suo lavoratore e manda immediatamente in errore il plugin. Anche gli arresti anomali del lavoratore e gli errori di pubblicazione rimuovono l'istanza in esecuzione e la contrassegnano come guasta. La cronologia degli arresti anomali ha una finestra di dieci minuti, ma il gestore corrente segnala un errore al primo arresto anomalo; non attende tre tentativi di riavvio riusciti. Correggere l'origine e ricaricare/riattivare deliberatamente invece di assumere il riavvio automatico.

Mantieni le garanzie di runtime in proporzione

Il caricatore di produzione fornisce un budget host di 10 secondi per il ciclo di vita/comando RPC ordinario. Le chiamate agli strumenti AI hanno una scadenza separata di 30 secondi. L'host limita un plug-in a 2,000 chiamate al minuto e 64 chiamate in sospeso. Passa un'impostazione di limite di risorse di 256 MB a Bun durante la creazione del lavoratore. Si tratta di controlli di runtime, non di un processo separato o di una policy di contenimento del sistema operativo.

Il bootstrap inizia con un ambiente vuoto e tenta di eliminare i processi/rete globali selezionati. L'eliminazione richiede il massimo sforzo e alcuni Bun globali rimangono raggiungibili. Il controllo della capacità è quindi significativo per le API fornite dall'host, ma non può essere presentato come un completo isolamento di JavaScript arbitrario.

Nello schema manifest sono presenti campi firma e sviluppo facoltativi. Il percorso di installazione del lavoratore corrente registra il testo della firma senza verifica crittografica. Non etichettare un editore verificato perché quel campo è presente. Una revisione autonoma del codice sorgente e una politica di installazione rimangono decisioni separate dall'accettazione dello schema.

I plug-in che si arrestano in modo anomalo tre volte in dieci minuti vengono disattivati automaticamente e una chiamata allo strumento assistente viene interrotta dopo 30 secondi. Entrambi i valori sono costanti in apps/sidecar/src/plugins/host.ts.

Aggiorna, rimuovi e diagnostica uno strumento

Per un aggiornamento, modificare e convalidare il modulo/manifest in bundle prima di riavviare il servizio di destinazione. Mantieni stabile il suo ID quando si tratta della stessa estensione e aumenta la versione per identificare cosa è stato caricato. Per interrompere il caricamento durante l'inizializzazione futura, rimuovere il relativo ID da Enabled.json e riavviare/reinizializzare. La sola modifica del file non elimina un lavoratore già in esecuzione.

Se lo strumento non è presente, controlla l'array abilitato, l'esatta uguaglianza dell'ID cartella/manifest, l'elenco delle funzionalità supportate e l'errore di decodifica del manifest nei log. NoSuchTool di solito significa che la voce non nomina una funzione aiTools esportata. Un rifiuto dell'argomento punta allo schema o alla funzione di guardia. Un timeout indica un blocco del lavoro o una promessa non mantenuta. Gli endpoint di abilitazione/configurazione ZIP del browser non gestiscono questo file di consenso dell'operatore.

La copertura mirata è arrivata apps/sidecar/test/plugins-ai-tools.test.ts per i lavoratori effettivi e ai-plugin-tools.test.ts per il caricamento della produzione, la convalida degli argomenti, l'esposizione in lettura/scrittura e il comportamento del bridge. Le fonti di implementazione sono packages/plugin-sdk/src/manifest.ts, packages/ai/src/tools/plugin-tool.ts, apps/sidecar/src/plugins/host.ts, e services/ai-plugins.ts. Utilizzare questi limiti per determinare cosa ha effettivamente dimostrato un test riuscito.

Le regole contrattuali in breve

ArticoloVincoloCosa succede se violato
Attrezzo id^[a-z][a-z0-9_]{0,39}$La decodifica del manifest non riesce; il plugin non è caricato.
description10–2,000 caratteriLa decodifica del manifest non riesce.
kindread o write; non esiste un tipo distruttivoLa decodifica del manifest non riesce.
parametersOggetto schema JSON, al massimo 20,000 caratteri quando serializzatoSchemi sovradimensionati o non convertibili ricadono nell'accettare qualsiasi oggetto.
CapacitàSoltanto ai:tool nell'assistente ospiteIl plugin viene saltato con un avviso.
Nome della cartellaUguale al manifesto idIl plugin viene saltato con un avviso che nomina entrambi i valori.
Budget ordinario delle chiamate5 secondi per chiamata per impostazione predefinitaIl lavoratore viene arrestato come qualsiasi plug-in che non risponde.
Budget delle chiamate dello strumento Assistente30 sLa chiamata restituisce un risultato di errore.
Memoria256 MB di heapL'operaio viene ucciso.
Valutare2,000 chiamate per plug-in al minuto, 64 chiamate in sospesoLe chiamate oltre la tariffa vengono rifiutate; una coda completa fallisce plugin RPC queue is full.
Crash e timeoutConteggiato su 10 minuti, limite 3Ogni arresto anomalo o timeout termina il lavoratore e contrassegna il plug-in in errore.

Scrivi la descrizione del modello. Indica cosa calcola lo strumento, le sue unità e quando utilizzarlo; ad esempio, "Restituisce i centri dei fori di un cerchio di bulloni in millimetri. Da utilizzare quando l'utente richiede fori equidistanti su un diametro." Descrizioni vaghe portano a far sì che gli strumenti vengano richiamati nel momento sbagliato o non vengano richiamati affatto.

Lista di controllo pre-rilascio

  1. Raggruppa la voce in un unico modulo autonomo. Il lavoratore non può risolvere le importazioni dell'area di lavoro in fase di esecuzione.
  2. Correre parseManifest sulla finale plugin.json e risolvere ogni problema segnalato.
  3. Chiama direttamente ciascuna funzione dello strumento esportato con argomenti validi, limite e non validi e verifica che l'input non valido produca un risultato di errore leggibile anziché un'eccezione che sfugge.
  4. Mantieni i risultati piccoli e compatibili con JSON. L'assistente li legge e risultati di grandi dimensioni affollano il contesto.
  5. Scegliere read a meno che lo strumento non cambi qualcosa. UN write lo strumento richiede all'utente prima di ogni chiamata.
  6. Posiziona la cartella sotto <data dir>/plugins/<id>/, aggiungi l'ID a enabled.json, riavviare il sidecar e confermare l'ID dello strumento derivato dall'elenco degli strumenti dell'assistente.
  7. Colpo version per ogni modifica che spedisci e mantieni id stabile in modo che l'ID dello strumento derivato non cambi.

Matrice di risoluzione dei problemi

SintomoProbabile causaAggiustare
Lo strumento non viene mai visualizzatoID mancante enabled.jsonoppure il formato JSON non è validoCorreggi l'array; JSON malformato o mancante non abilita nulla.
Il registro dice che la cartella si chiama X ma il manifest dice YCartella e manifesto id differireRinominarne uno in modo che corrisponda esattamente.
Il registro dice che richiede il disegno: leggi, ...Funzionalità non supportata in questo hostDichiarare solo ai:tool.
L'assistente trasmette forme di argomento inaspettateLo schema ricadeva su qualsiasi oggettoUtilizzare uno schema di oggetti con properties sotto 20,000 caratteri e convalidare anche all'interno della funzione.
Le chiamate ritornano ok: false dopo circa 30 sLo strumento ha superato il budget temporaleSvolgi meno lavoro per chiamata o precalcolo; evitare cicli illimitati.
Il plugin smette di rispondere dopo un erroreUn arresto anomalo o un timeout del lavoratore termina il lavoratore e contrassegna il plug-in faulted; vengono conteggiati anche gli arresti anomali in una finestra di 10 minuti con un limite di 3Risolvi il crash, quindi riavvia il sidecar per caricarlo di nuovo.

Lint un manifest prima dell'installazione

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)
Errore comuneAggiustare
"version": "1.0"Utilizza tre numeri: 1.0.0
"apiVersion": 1È una stringa: "1"
ID del plug-in gear o My.PluginDNS inverso, minuscolo: com.example.gear
ID strumento Lookup-ThreadLettere minuscole, cifre e trattini bassi, prima la lettera, ≤ 40 caratteri
Descrizione dello strumento più breve di 10 caratteriDescrivi cosa fa e quando usarlo
Dichiararli entrambi drawing:read e drawing:writeConsentito, ma drawing:write da solo implica già leggere
Chiave di archiviazione che inizia con / o contenente ..Utilizzare chiavi relative come presets/m2

Nel 3D

Tabelle dei plugin Trascina per orbitare · scorri per ingrandire · trascina con il tasto destro per eseguire la panoramica
PluginRegistryEntry e PluginConfiguration dalle migrazioni: le configurazioni fanno riferimento alle voci del registro.