/** * Discord AI Toolkit — las herramientas que un discordAction expone cuando * `aiEnabled` está encendido. * * **Se escribe una sola vez.** Antes vivía dos veces: una copia en * `dashboard/components/discord-actions/discord-operations-schemas.ts` y otra en * `api/src/mcp-servers/toolkit-specs.ts`, las dos a mano y en repos distintos, * así que ningún test podía compararlas. Es la octava y novena mudanza de esta * serie; de las siete anteriores, la de Contacts salió de que una copia * anunciara 15 herramientas y expusiera una. * * Y sí había deriva, medida al mudar: la descripción de `addReaction` decía en * el dashboard «URL-encoding is handled.» y en la api «URL-encoding is handled — * pass the raw form.». Gana la de la api, que es la que el servidor MCP sirve * hoy a clientes externos y la que dice qué hacer. Las 17 operaciones, sus * nombres de herramienta y sus parámetros coincidían exactamente. * * Targets Discord API v10. Los parámetros snowflake son `string` porque los ids * de Discord se pasan de la precisión de Number (17-20 dígitos). * * La forma es la que ya consume `toolkitSpecToMcpTool` en la api, para que * pueda usarse sin adaptador. Los textos van en inglés porque los lee el modelo * y quien mire la lista de herramientas del servidor MCP. * * ## [2026-10-03] Lo que cambió en la revisión de Discord * * - **`guildId` es opcional en todas.** Sin él, el servidor de la credencial: * la de «Add to Discord» (`discord_oauth`) guarda el suyo y lo pone el * nodo. Antes era obligatorio, y el modelo —que no ve el payload ni la * credencial— no tenía de dónde sacarlo: `list_discord_channels`, la vía * que se anunciaba para encontrar un canal, pedía justo lo que faltaba. Un * Bot Token propio no tiene un servidor único; con él hay que pasarlo. * - **`channelId` lo da el disparador** cuando el modelo lo omite: está en * `PARAMETROS_DE_CONTEXTO`, y el AI Node deja que gane el del modelo, como * `channel` de Slack. Por eso las descripciones ya no dicen «get it from * the trigger payload»: el modelo no ve el payload. * - **Nacen bloqueadas las siete destructivas** (las que marca el verbo, * `clase-de-herramienta.ts`), como los borrados de Jira o Airtable: * `delete_discord_channel` se lleva el canal con todos sus mensajes y * Discord no lo devuelve. El dueño las desbloquea en el nodo. * - **Un DM a quien no los acepta FALLA**: Discord contesta 403 (código * 50007, «Cannot send messages to this user»). La descripción decía que * se descartaba en silencio, y el modelo daba por enviado lo que no. */ import type { DiscordOperation } from './discord-operations.js'; export interface DiscordToolkitParameter { name: string; type: 'string' | 'number' | 'boolean'; description: string; required: boolean; } export interface DiscordToolkitSpec { operation: DiscordOperation; /** Etiqueta corta de la fila en la lista de herramientas. */ label: string; /** Nombre con el que el LLM llama a la herramienta. */ toolName: string; /** Descripción (más reglas de uso) que ve el LLM. */ description: string; parameters: DiscordToolkitParameter[]; /** Pisa o borra. Lo pone `marcarDestructivas` leyendo el verbo del * nombre (ver `clase-de-herramienta.ts`), no se escribe a mano. */ destructive?: boolean; /** Nace bloqueada en el nodo; el dueño la desbloquea. Ver `toolkits.ts`. */ bloqueadaPorDefecto?: boolean; } export declare const DISCORD_TOOLKIT_SPECS: DiscordToolkitSpec[]; export declare const DISCORD_TOOLKIT_BY_TOOL_NAME: Record; /** * Las herramientas que ofrecerle al modelo con ESTA credencial. * * Vive aquí y no en cada consumidor porque son dos —la expansión MCP de la api * y el selector del AI Node del dashboard— y filtrar «casi igual» en dos sitios * es exactamente la duplicación que costó tres PR quitar de este paquete. * * Filtra en los dos niveles, que es lo que hace falta y no es obvio: * * 1. **Operaciones**: sin esto, a un nodo con credencial de webhook se le * entregan al modelo 17 herramientas de las que 13 fallan siempre. El * modelo no tiene forma de saberlo: las ve anunciadas. * 2. **Parámetros**: una herramienta que sigue pidiendo `channelId` invita al * modelo a inventarse un canal que el webhook va a ignorar. Peor que * fallar, porque parece que funcionó. */ export declare function herramientasDeDiscordPara(tipoDeCredencial: string | null | undefined): DiscordToolkitSpec[];