Cordis-pluginok készítése
A híd a cordis.patch.yml soraiban megnevezett pluginfát tölti be. Képesség hozzáadásához Cordis-plugin és új sor kell, nem Libre WebUI-forrásmódosítás. Ez az oldal a gazda által megkövetelt szabályokat ismerteti.
Előbb olvassa el a Cordis-híd szerkezetét és a Cordis-konfiguráció sormezőit.
A két pluginforma
A plugin függvény vagy apply metódusú objektum lehet. Mindkettőt a Loader oldja fel.
// Function form.
export function apply(ctx, config) {
// ...
}
// Object form, when the plugin also declares dependencies.
export const name = 'my-plugin';
export const inject = ['tools'];
export function apply(ctx, config) {
// ...
}
A Loader a modul névterét olvassa, így név szerinti apply és inject export kell. Alapértelmezett export is működik, de a mellékelt DSH-pluginok megnevezettet használnak; kövesse ezt.
Függőségek megadása
Az inject a teljes függőségmechanizmus. Cordis csak az összes megnevezett szolgáltatás meglétekor indítja a plugint, és újból futtatja, ha egy szolgáltatás visszavonás után helyreáll.
export const inject = ['tools', 'systemPrompt'];
export function apply(ctx, config) {
// `ctx.tools` and `ctx.systemPrompt` are guaranteed present here.
}
Két fontos következmény:
- A hiányzó szolgáltatás nem hiba. A sor csendben, korlátlanul vár. Ezért a
GET /api/cordis/healthszolgáltatásonként jelez, nem egyetlen logikai értékkel. - Az injektálás szabja a sorrendet. Nem kell kézzel sorba rendezni a végrehajtást; a mellékelt kompozíció sorrendje nem betöltési sorrend.
Opcionális függőséghez az apply belsejében használjon ctx.inject hívást. A callback azonnal fut, ha a szolgáltatások megvannak, és újra, amikor megjelennek:
export function apply(ctx) {
ctx.inject(['typert'], inner => {
inner.typert.lookups.register('session', {/* ... */});
});
}
Meglévő függőségekkel a ctx.inject szinkron: a későn betöltött plugin is az apply alatt regisztrál, nem egy későbbi körben.
Szolgáltatás közzététele
Származtasson a Service osztályból, és adja át a nevet a super hívásnak. Ezen a tulajdonságon olvasnak a fogyasztók; a regisztráció a plugin fiberéhez tartozik.
import { Service } from '@deepseek-ai/cordis';
export class WidgetRegistry extends Service {
static provide = 'widgets';
constructor(ctx) {
super(ctx, 'widgets');
this.widgets = new Map();
}
register(widget) {
// Return the disposer so the caller's fiber owns the entry.
return this.ctx.effect(() => {
this.widgets.set(widget.id, widget);
return () => this.widgets.delete(widget.id);
}, 'widgets.register()');
}
}
export default WidgetRegistry;
Viselkedéshez a Service leszármazott előnyösebb a ctx.reflect.provide(...) helyett: egyszer regisztrál, típusos metódusokat ad, és a fiberrel automatikusan visszavonódik.
Mellékhatások tulajdonlása
Minden mellékhatásnak legyen tulajdonosa. Ez az egyetlen, könnyen megsérthető szabály biztosítja a visszavonási garanciát.
| Mellékhatás | Tulajdonos |
|---|---|
| Szolgáltatásregisztráció | Automatikusan a plugin fibere |
| Eseményfigyelő | A pluginon belüli ctx.on(...) |
| Felszabadítandó erőforrás | ctx.effect(() => disposer) |
| Időzítő | ctx.setTimeout / ctx.setInterval |
| Eszközregisztráció | A ctx.effect által visszaadott disposer |
A ctx.effect disposer-függvényt visszaadó függvényt vagy disposereket kiadó generátort fogad:
ctx.effect(() => {
const registration = ctx.llm.registerAdapter(['my-route'], adapter);
return () => registration();
}, 'my-adapter.register');
A címke diagnosztikai: felszabadítási hibánál ez nevezi meg a hatást.
A Cordis számára ismeretlen socketet, workert vagy handle-t magának kell felszabadítania:
ctx.effect(() => {
const worker = startWorker();
return () => worker.terminate();
}, 'my-plugin.worker');
Mi töri meg a visszavonást
- Regisztráció az
applyparaméterétől eltérő kontextuson: a szolgáltatás túléli a sort. - Globális
setTimeoutidőzítő: életben tartja a folyamatot, és nem szakad meg. - Külső emitterre feliratkozás leiratkozás nélkül a disposerben.
- Modulszintű singleton írása: a felszabadítás nem vonja vissza, az érték a sor után is megmarad. Használjon fiberenkénti állapotot.
Konfiguráció
A plugin beállítása a sor config mapje. Adjon sémát, hogy az elírás betöltéskor hibát okozzon, ne csendben alapértéket használjon:
import z from '@deepseek-ai/schemastery';
export const Config = z.object({
route: z.string().required(),
maxRetries: z.number().default(2),
});
export function apply(ctx, config) {
// `config` is validated before this runs.
}
Az értékek használhatnak !!js kifejezést. Kiértékelésük a sor fiberében, a Loader kontextusával történik: process.env és ctx.get(...) működik, import.meta nem. A name sosem értékelődik ki, így a modulhivatkozás sztringliterál legyen.
Teljes példa
A repó két működő, a híd tesztjei által használt, könnyen másolható fixture-t tartalmaz.
Modelladapter — a scripts/fixtures/cordis/fake-adapter.mjs a ctx.llm felületén útvonalat regisztrál, a disposerét egy hatásból adja vissza, és állandó szöveggel válaszol. Ennyi a szerződés: inject deklaráció, regisztráció, annak tulajdonlása.
Életciklus-próba — a scripts/fixtures/cordis/lifecycle-probe.mjs szolgáltatást ad, eseményt figyel, és feljegyzi a takarítást; így bizonyítja a teszt mindkettő megszűnését.
Bármelyiket sor hozzáadásával töltse be:
- id: my-adapter
name: './scripts/fixtures/cordis/fake-adapter.mjs'
config:
route: my-route
Relatív hivatkozás a kompozíciós fájl mappájához, puszta csomagnév a backendcsomaghoz viszonyul.
Plugin tesztelése
A híd tesztkészletei mutatják a mintát:
- A
scripts/test-cordis-bridge.mjsvalódi fát tölt ideiglenes mappába, ellenőrzi az elérhetőséget és szerződést, majd a szolgáltatás és figyelő megszűnését. - A
scripts/test-cordis-bridge-http.mjsvalódi HTTP-szerveren teszteli az útvonalakat és NDJSON-streamet.
Szolgáltató nélkül használjon model.provider: none értéket, saját plugint és motorsorokat. llm-függőséghez tegyen fixture-adaptert egy szabad útvonalra, és állítson model.provider: none értéket, hogy a gazda ne töltsön versengő adaptert.
A plugin csak akkor helyes, ha sorának eltávolítása nem hagy nyomot. Ellenőrzés: regisztrálás, megfigyelés, felszabadítás, újabb megfigyelés.
Ellenőrzőlista
- Az
applyésinjectmegnevezett export. - A szolgáltatás
Serviceleszármazott stabilprovidenévvel. - Minden regisztráció disposert ad, és mindegyik a
ctx.effectvisszatérése. - Az időzítők a
ctx-ből, nem globális függvényből jönnek. - Változó állapot a példányban él, nem modulsingletonban.
- Séma ellenőrzi a konfigurációt.
- Kompozíciós és beállítási dokumentumokban nincs titok.
- Teszt bizonyítja a plugin nyomtalan felszabadítását.