Skip to main content

Usar un plugin

config lo tipa el plugin (definePlugin<MiConfig>()): una opción desconocida es un error de compilación, y una configuración declarada con la interfaz de configuración del plugin se pasa tal cual. bot.plug(plugin, config?) devuelve una función unplug (no el bot, así que las llamadas a plug() no se encadenan). Al llamarla, primero ejecuta el uninstall(ctx) del plugin, si lo tiene, y después revierte, de lo más nuevo a lo más antiguo, lo que el plugin registró vía ctx.bot:
  • comandos (command()), matchers (when(), onMessage(), onType()), conversaciones y disparadores de flows (conversation(), use(flow));
  • hooks (before(), after(), onError(), hook());
  • plugins anidados (ctx.bot.plug());
  • flows registrados en caliente con ctx.bot.registerFlow(), o creados (no reemplazados) con ctx.bot.replaceFlow();
  • cada callback de ctx.onDispose(fn).
No deshace nada más: listeners de eventos (ctx.bot.on() / once()), herramientas inyectadas (ctx.bot.provide() / ctx.tools), mensajes de idioma (ctx.bot.locale()), tareas programadas (schedule(), every(), delay()), handlers de inactividad (onIdle()), un flow que replaceFlow() sobrescribió (no se restaura), el estado de handoff, escrituras en el store ni timers o conexiones propios. Deshazlos en ctx.onDispose() (o en uninstall()). Llamar a unplug dos veces no hace nada. Si install() lanza de forma síncrona, lo que alcanzó a registrar se revierte antes de que el error te llegue; si devuelve una promesa que rechaza, el rechazo va al evento 'error' y no se revierte nada.

Dependencias entre plugins (requires)

Un plugin puede listar por nombre los plugins que necesita. bot.plug() los comprueba antes de ejecutar install() y lanza un error descriptivo si falta alguno:
La comprobación solo ocurre al enchufar: desenchufar inbox después no desenchufa crm. Un plugin anidado dentro de otro (ctx.bot.plug() desde install()) puede requerir a su padre.

Una instancia por nombre (multiple)

bot.plug() rechaza un plugin cuyo name ya está enchufado en el bot, así un plugin registrado dos veces por error nunca ejecuta sus handlers dos veces:
Un plugin pensado para correr varias veces con configuraciones distintas pone multiple: true en su spec (todas las instancias deben ponerlo). Cada instancia se desenchufa por separado y cualquiera de ellas cumple requires.

Incluido: slashCommands

Config: { greeting?: string; unknownMessage?: string }. El prefijo de comandos es una opción del bot (new Bot({ commandPrefix })), no del plugin. Las respuestas son textos internos en el idioma del bot. Los /comandos desconocidos reciben automáticamente una respuesta de “comando desconocido” (unknownMessage).

Crear un plugin

Plugin simple

Plugin configurable con cleanup

Estructura de un plugin

definePlugin(spec) devuelve el spec sin cambios, tipado. Un plugin también puede ser una función (config) => spec. El ctx que recibe install:
install() debe ser síncrono y no devolver nadabot.plug() no hace await de install(). TypeScript rechaza un install async (o uno que devuelva una promesa o cualquier otro valor) en tiempo de compilación: PluginSpec.install devuelve void | SyncInstallError, y el mensaje de error explica el motivo. En JavaScript el bot sigue antes de que un install async termine y su rechazo solo llega al evento 'error': no se revierte nada y el plugin cuenta como enchufado; la regla de ESLint no-async-plugin-install cubre ese caso. Si tu plugin necesita inicialización async (abrir una conexión, cargar un SDK), mantén install síncrono y resuelve de forma perezosa en el primer uso, reportando los errores de configuración sin tumbar el bot. Así carga @botmesh/ai los SDKs de sus proveedores.

Compartir herramientas (inyección de dependencias)

Comparte herramientas entre handlers, hooks y plugins sin usar globales.

El problema que resuelve

Cómo funciona

1. Registrar una herramienta

bot.provide(name, value) devuelve this, así que las llamadas se pueden encadenar:

2. Tiparla

ctx.tools se tipa con la interfaz DefaultTools, que está vacía hasta que la amplías (declaration merging). Declara cada herramienta una vez, junto al código que la registra, y todos los handlers la ven tipada:
Los plugins hacen lo mismo con las herramientas que registran: importar @botmesh/ai tipa ctx.tools.ai, e importar @botmesh/nlu tipa ctx.tools.nlu. En JavaScript no hay nada que declarar.

3. Usarla en cualquier handler

4. También disponible en hooks y plugins

El install(ctx) de un plugin también recibe ctx.tools, así que los plugins pueden consumir herramientas registradas en otro lugar (o registrar las suyas con ctx.bot.provide). Fuera de los handlers (una tarea programada, un webhook), léelas de bot.injectTools.

Quitar una herramienta

bot.unprovide(name) quita una herramienta y devuelve true si existía. Desenchufar un plugin no deshace sus provide(), así que hazlo en ctx.onDispose():

Múltiples herramientas

Con TypeScript, declara las tres en DefaultTools como arriba.

Paquetes de plugins

Además de slashCommandsPlugin, estos paquetes traen plugins listos:
  • IA — @botmesh/ai: respuestas con LLM (aiPlugin), con herramientas, memoria y RAG y streaming.
  • Voz — @botmesh/voice (voicePlugin): voz a texto para las notas de voz entrantes y respuestas con texto a voz.
  • Integraciones — @botmesh/chatwoot, @botmesh/tickets, @botmesh/moderation, @botmesh/dialogflow y @botmesh/nlu (intenciones locales).
  • Trazas — @botmesh/otel (otelMetricsPlugin): bot.metrics() y los spans del bot en OpenTelemetry.
Todos están en npm. @botmesh/rag (recuperación para aiPlugin) se explica en memoria y RAG.

Siguientes pasos