@hostwebhook/node-types 1.66.0 → 1.68.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capacidad-de-credencial.d.ts +75 -0
- package/dist/capacidad-de-credencial.js +73 -0
- package/dist/credentials.js +17 -0
- package/dist/discord-operations.d.ts +31 -0
- package/dist/discord-operations.js +55 -1
- package/dist/discord-toolkit.d.ts +17 -0
- package/dist/discord-toolkit.js +29 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +23 -2
- package/dist/llm-models.d.ts +25 -1
- package/dist/llm-models.js +50 -0
- package/dist/openrouter.d.ts +142 -0
- package/dist/openrouter.js +104 -0
- package/dist/slack-operations.d.ts +28 -0
- package/dist/slack-operations.js +43 -1
- package/dist/slack-toolkit.d.ts +13 -0
- package/dist/slack-toolkit.js +21 -0
- package/package.json +1 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qué puede hacer un nodo según el TIPO de credencial que lleva puesta.
|
|
3
|
+
*
|
|
4
|
+
* Hasta ahora un nodo ofrecía siempre todas sus operaciones, porque todas sus
|
|
5
|
+
* credenciales podían hacerlas todas. Con los webhooks deja de ser cierto, y de
|
|
6
|
+
* una forma muy desigual:
|
|
7
|
+
*
|
|
8
|
+
* - Un webhook de Discord ejecuta 4 de las 17 —publicar, y leer/editar/borrar
|
|
9
|
+
* **sus propios** mensajes—, siempre en el único canal para el que se creó.
|
|
10
|
+
* - Un webhook de Slack ejecuta **1 de 16**, y ni siquiera puede elegir el
|
|
11
|
+
* canal: lo fija quien instala la credencial.
|
|
12
|
+
*
|
|
13
|
+
* Esa desigualdad es la que decide la forma de este fichero. No basta con
|
|
14
|
+
* esconder operaciones: hay que esconder **campos dentro de** una operación,
|
|
15
|
+
* porque el destino deja de ser una pregunta. Por eso son dos listas y no una.
|
|
16
|
+
*
|
|
17
|
+
* ── Dónde vive esto y por qué ──
|
|
18
|
+
*
|
|
19
|
+
* Aquí, en el paquete, y no en cada consumidor. Lo mismo tienen que saberlo
|
|
20
|
+
* CUATRO sitios, y si cada uno lo deduce por su cuenta acaban discrepando sin
|
|
21
|
+
* que nada falle al compilar:
|
|
22
|
+
*
|
|
23
|
+
* 1. el selector de operación de la pantalla de detalle;
|
|
24
|
+
* 2. el renderizador de campos de esa misma pantalla;
|
|
25
|
+
* 3. la validación al guardar, en la api;
|
|
26
|
+
* 4. **la expansión del toolkit de IA** — que es el que se rompe más callado:
|
|
27
|
+
* sin esto, a un nodo con credencial de webhook se le entregan al modelo
|
|
28
|
+
* 17 herramientas de las que 13 fallan siempre.
|
|
29
|
+
*
|
|
30
|
+
* Es la misma razón por la que los toolkits se mudaron aquí en 1.66.0. Tener el
|
|
31
|
+
* dato dos veces es tenerlo mal a la vuelta de unas semanas.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Lo que una credencial concreta deja hacer.
|
|
35
|
+
*
|
|
36
|
+
* `operaciones` ausente significa «todas»: así el caso normal —un bot, que
|
|
37
|
+
* puede con todo— no necesita enumerarse ni mantenerse, y sólo se escribe lo
|
|
38
|
+
* que está ACOTADO. Añadir una operación nueva al nodo no obliga a tocar este
|
|
39
|
+
* fichero salvo que el webhook también pueda ejecutarla, que es justo la
|
|
40
|
+
* decisión que uno quiere tener que tomar a mano.
|
|
41
|
+
*/
|
|
42
|
+
export interface CapacidadDeCredencial<Op extends string = string> {
|
|
43
|
+
/** Las que puede ejecutar. Ausente = todas las del nodo. */
|
|
44
|
+
operaciones?: readonly Op[];
|
|
45
|
+
/**
|
|
46
|
+
* Campos que desaparecen del formulario y que la validación rechaza.
|
|
47
|
+
*
|
|
48
|
+
* Se juntan aquí dos motivos que para el usuario son el mismo —«esto no lo
|
|
49
|
+
* eliges tú»— aunque por dentro no lo sean: el que viene FIJADO por la
|
|
50
|
+
* credencial (el canal de un webhook) y el que el endpoint sencillamente NO
|
|
51
|
+
* ADMITE (responder a un mensaje: `Execute Webhook` no acepta
|
|
52
|
+
* `message_reference`). Separarlos daría dos listas que se consultan siempre
|
|
53
|
+
* juntas.
|
|
54
|
+
*/
|
|
55
|
+
camposNoDisponibles?: readonly string[];
|
|
56
|
+
}
|
|
57
|
+
/** Mapa de un proveedor: tipo de credencial → lo que deja hacer. */
|
|
58
|
+
export type CapacidadesPorCredencial<Op extends string = string> = Readonly<Record<string, CapacidadDeCredencial<Op>>>;
|
|
59
|
+
/**
|
|
60
|
+
* Qué operaciones ofrecer para esta credencial.
|
|
61
|
+
*
|
|
62
|
+
* Sin tipo de credencial —el nodo todavía no tiene ninguna elegida— se
|
|
63
|
+
* devuelven todas: es un hueco por rellenar, no una restricción, y esconder
|
|
64
|
+
* operaciones ahí haría creer que el nodo no sabe hacerlas.
|
|
65
|
+
*/
|
|
66
|
+
export declare function operacionesPara<Op extends string>(todas: readonly Op[], mapa: CapacidadesPorCredencial<Op>, tipoDeCredencial: string | null | undefined): readonly Op[];
|
|
67
|
+
/** Si esta credencial puede ejecutar esta operación. */
|
|
68
|
+
export declare function puedeEjecutar<Op extends string>(todas: readonly Op[], mapa: CapacidadesPorCredencial<Op>, tipoDeCredencial: string | null | undefined, operacion: Op): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Campos que esta credencial no deja elegir.
|
|
71
|
+
*
|
|
72
|
+
* Devuelve un `Set` porque quien lo usa siempre pregunta «¿este campo sí o
|
|
73
|
+
* no?», nunca recorre la lista.
|
|
74
|
+
*/
|
|
75
|
+
export declare function camposNoDisponiblesPara(mapa: CapacidadesPorCredencial, tipoDeCredencial: string | null | undefined): ReadonlySet<string>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Qué puede hacer un nodo según el TIPO de credencial que lleva puesta.
|
|
4
|
+
*
|
|
5
|
+
* Hasta ahora un nodo ofrecía siempre todas sus operaciones, porque todas sus
|
|
6
|
+
* credenciales podían hacerlas todas. Con los webhooks deja de ser cierto, y de
|
|
7
|
+
* una forma muy desigual:
|
|
8
|
+
*
|
|
9
|
+
* - Un webhook de Discord ejecuta 4 de las 17 —publicar, y leer/editar/borrar
|
|
10
|
+
* **sus propios** mensajes—, siempre en el único canal para el que se creó.
|
|
11
|
+
* - Un webhook de Slack ejecuta **1 de 16**, y ni siquiera puede elegir el
|
|
12
|
+
* canal: lo fija quien instala la credencial.
|
|
13
|
+
*
|
|
14
|
+
* Esa desigualdad es la que decide la forma de este fichero. No basta con
|
|
15
|
+
* esconder operaciones: hay que esconder **campos dentro de** una operación,
|
|
16
|
+
* porque el destino deja de ser una pregunta. Por eso son dos listas y no una.
|
|
17
|
+
*
|
|
18
|
+
* ── Dónde vive esto y por qué ──
|
|
19
|
+
*
|
|
20
|
+
* Aquí, en el paquete, y no en cada consumidor. Lo mismo tienen que saberlo
|
|
21
|
+
* CUATRO sitios, y si cada uno lo deduce por su cuenta acaban discrepando sin
|
|
22
|
+
* que nada falle al compilar:
|
|
23
|
+
*
|
|
24
|
+
* 1. el selector de operación de la pantalla de detalle;
|
|
25
|
+
* 2. el renderizador de campos de esa misma pantalla;
|
|
26
|
+
* 3. la validación al guardar, en la api;
|
|
27
|
+
* 4. **la expansión del toolkit de IA** — que es el que se rompe más callado:
|
|
28
|
+
* sin esto, a un nodo con credencial de webhook se le entregan al modelo
|
|
29
|
+
* 17 herramientas de las que 13 fallan siempre.
|
|
30
|
+
*
|
|
31
|
+
* Es la misma razón por la que los toolkits se mudaron aquí en 1.66.0. Tener el
|
|
32
|
+
* dato dos veces es tenerlo mal a la vuelta de unas semanas.
|
|
33
|
+
*/
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.operacionesPara = operacionesPara;
|
|
36
|
+
exports.puedeEjecutar = puedeEjecutar;
|
|
37
|
+
exports.camposNoDisponiblesPara = camposNoDisponiblesPara;
|
|
38
|
+
/** Ninguna restricción: el caso del bot, y el de cualquier tipo sin entrada. */
|
|
39
|
+
const SIN_LIMITE = {};
|
|
40
|
+
/**
|
|
41
|
+
* Qué operaciones ofrecer para esta credencial.
|
|
42
|
+
*
|
|
43
|
+
* Sin tipo de credencial —el nodo todavía no tiene ninguna elegida— se
|
|
44
|
+
* devuelven todas: es un hueco por rellenar, no una restricción, y esconder
|
|
45
|
+
* operaciones ahí haría creer que el nodo no sabe hacerlas.
|
|
46
|
+
*/
|
|
47
|
+
function operacionesPara(todas, mapa, tipoDeCredencial) {
|
|
48
|
+
if (!tipoDeCredencial)
|
|
49
|
+
return todas;
|
|
50
|
+
const cap = mapa[tipoDeCredencial] ?? SIN_LIMITE;
|
|
51
|
+
if (!cap.operaciones)
|
|
52
|
+
return todas;
|
|
53
|
+
/* Se filtra `todas` en vez de devolver la lista del mapa para que el ORDEN
|
|
54
|
+
sea siempre el del nodo. Si no, la pantalla reordenaría sus operaciones al
|
|
55
|
+
cambiar de credencial, que se lee como si hubieran cambiado otras cosas. */
|
|
56
|
+
const permitidas = new Set(cap.operaciones);
|
|
57
|
+
return todas.filter((op) => permitidas.has(op));
|
|
58
|
+
}
|
|
59
|
+
/** Si esta credencial puede ejecutar esta operación. */
|
|
60
|
+
function puedeEjecutar(todas, mapa, tipoDeCredencial, operacion) {
|
|
61
|
+
return operacionesPara(todas, mapa, tipoDeCredencial).includes(operacion);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Campos que esta credencial no deja elegir.
|
|
65
|
+
*
|
|
66
|
+
* Devuelve un `Set` porque quien lo usa siempre pregunta «¿este campo sí o
|
|
67
|
+
* no?», nunca recorre la lista.
|
|
68
|
+
*/
|
|
69
|
+
function camposNoDisponiblesPara(mapa, tipoDeCredencial) {
|
|
70
|
+
if (!tipoDeCredencial)
|
|
71
|
+
return new Set();
|
|
72
|
+
return new Set(mapa[tipoDeCredencial]?.camposNoDisponibles ?? []);
|
|
73
|
+
}
|
package/dist/credentials.js
CHANGED
|
@@ -19,6 +19,23 @@ exports.CREDENTIAL_TYPES = [
|
|
|
19
19
|
{ type: 'llm_anthropic' },
|
|
20
20
|
{ type: 'llm_openai' },
|
|
21
21
|
{ type: 'llm_google' },
|
|
22
|
+
// La clave de API de OpenRouter (`sk-or-v1-…`). Un secreto pegado por el
|
|
23
|
+
// usuario, igual que los tres de arriba: no hay OAuth de por medio.
|
|
24
|
+
//
|
|
25
|
+
// El sufijo es `openrouter` y no `open_router` porque de aquí sale
|
|
26
|
+
// `getModelsFor`/`getDefaultModel` quitando el prefijo `llm_` — el resto
|
|
27
|
+
// tiene que ser LITERALMENTE el `LlmProvider`, y ése es `'openrouter'`.
|
|
28
|
+
//
|
|
29
|
+
// ⚠️ Se anota aquí ANTES de que exista nada en la api, por lo que cuenta el
|
|
30
|
+
// bloque de Mailchimp más abajo: de esta lista salen el `enum` de Mongoose y
|
|
31
|
+
// el validador del DTO, y un tipo que falte ahí no rompe al compilar — mata
|
|
32
|
+
// el `create` de la credencial en runtime, con el usuario delante.
|
|
33
|
+
//
|
|
34
|
+
// ⚠️ Y falta un vecino, que no es cosa de este cambio pero conviene que esté
|
|
35
|
+
// escrito: `groq` es un `LlmProvider` desde hace tiempo y NO tiene
|
|
36
|
+
// `llm_groq` en esta lista. O sea que hoy se puede elegir Groq como
|
|
37
|
+
// proveedor y no hay tipo de credencial con el que guardar su clave.
|
|
38
|
+
{ type: 'llm_openrouter' },
|
|
22
39
|
{ type: 'llm_ollama' },
|
|
23
40
|
{ type: 'firecrawl' },
|
|
24
41
|
{ type: 'http_auth' },
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* forum-post create) extend this list — bump the package and re-install
|
|
18
18
|
* in consumers, same pattern as Gmail / Calendar / Drive / Telegram.
|
|
19
19
|
*/
|
|
20
|
+
import { type CapacidadesPorCredencial } from './capacidad-de-credencial';
|
|
20
21
|
export declare const DISCORD_OPERATIONS: readonly ["sendMessage", "editMessage", "deleteMessage", "getMessage", "addReaction", "removeReaction", "pinMessage", "createChannel", "editChannel", "deleteChannel", "getChannel", "listChannels", "createThread", "sendDM", "addRole", "removeRole", "getMember"];
|
|
21
22
|
export type DiscordOperation = (typeof DISCORD_OPERATIONS)[number];
|
|
22
23
|
/** Type guard — useful when validating untrusted input (DTOs, tool calls). */
|
|
@@ -71,3 +72,33 @@ export interface DiscordOperationSpec {
|
|
|
71
72
|
params: DiscordParamSpec[];
|
|
72
73
|
}
|
|
73
74
|
export declare const DISCORD_OPERATION_SPECS: Record<DiscordOperation, DiscordOperationSpec>;
|
|
75
|
+
/**
|
|
76
|
+
* Lo que puede hacer una credencial de Discord que NO es de bot.
|
|
77
|
+
*
|
|
78
|
+
* Medido contra la documentación de Discord, no de memoria:
|
|
79
|
+
* https://docs.discord.com/developers/resources/webhook
|
|
80
|
+
*
|
|
81
|
+
* `Execute Webhook` publica, y `Get/Edit/Delete Webhook Message` leen, editan y
|
|
82
|
+
* borran mensajes — pero **sólo los que envió ese mismo webhook**, y sólo en el
|
|
83
|
+
* canal para el que se creó. Las otras 13 (reacciones, pins, CRUD de canales,
|
|
84
|
+
* crear hilos, DMs, roles, miembros) piden un Bot Token: la propia doc las
|
|
85
|
+
* marca con `MANAGE_WEBHOOKS` o con permisos de guild.
|
|
86
|
+
*
|
|
87
|
+
* Los tres campos que se caen de `sendMessage`, uno por uno:
|
|
88
|
+
*
|
|
89
|
+
* - `channelId`: la URL del webhook YA dice el canal. El endpoint ni siquiera
|
|
90
|
+
* acepta `channel_id`.
|
|
91
|
+
* - `replyToMessageId`: `Execute Webhook` no acepta `message_reference`. No
|
|
92
|
+
* es que venga fijado — es que responder no existe por esta vía.
|
|
93
|
+
* - `interactionReply`: contestar a un slash command es cosa de la
|
|
94
|
+
* aplicación, no de un webhook.
|
|
95
|
+
*
|
|
96
|
+
* `threadId` SÍ se queda: `?thread_id=` es parámetro de query del endpoint.
|
|
97
|
+
*/
|
|
98
|
+
export declare const DISCORD_CAPACIDADES_POR_CREDENCIAL: CapacidadesPorCredencial<DiscordOperation>;
|
|
99
|
+
/** Las operaciones que ofrecer para una credencial de Discord. */
|
|
100
|
+
export declare function operacionesDeDiscordPara(tipoDeCredencial: string | null | undefined): readonly DiscordOperation[];
|
|
101
|
+
/** Si esa credencial puede ejecutar esa operación de Discord. */
|
|
102
|
+
export declare function discordPuedeEjecutar(tipoDeCredencial: string | null | undefined, operacion: DiscordOperation): boolean;
|
|
103
|
+
/** Los campos que esa credencial de Discord no deja elegir. */
|
|
104
|
+
export declare function camposDeDiscordNoDisponibles(tipoDeCredencial: string | null | undefined): ReadonlySet<string>;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DISCORD_OPERATION_SPECS = exports.DISCORD_OPERATIONS = void 0;
|
|
3
|
+
exports.DISCORD_CAPACIDADES_POR_CREDENCIAL = exports.DISCORD_OPERATION_SPECS = exports.DISCORD_OPERATIONS = void 0;
|
|
4
4
|
exports.isDiscordOperation = isDiscordOperation;
|
|
5
|
+
exports.operacionesDeDiscordPara = operacionesDeDiscordPara;
|
|
6
|
+
exports.discordPuedeEjecutar = discordPuedeEjecutar;
|
|
7
|
+
exports.camposDeDiscordNoDisponibles = camposDeDiscordNoDisponibles;
|
|
5
8
|
/**
|
|
6
9
|
* Discord Bot API operation enum — single source of truth across the
|
|
7
10
|
* API, Dashboard, and any future consumers (Message Broker, MCP server).
|
|
@@ -21,6 +24,7 @@ exports.isDiscordOperation = isDiscordOperation;
|
|
|
21
24
|
* forum-post create) extend this list — bump the package and re-install
|
|
22
25
|
* in consumers, same pattern as Gmail / Calendar / Drive / Telegram.
|
|
23
26
|
*/
|
|
27
|
+
const capacidad_de_credencial_1 = require("./capacidad-de-credencial");
|
|
24
28
|
exports.DISCORD_OPERATIONS = [
|
|
25
29
|
// Messages
|
|
26
30
|
'sendMessage',
|
|
@@ -358,3 +362,53 @@ exports.DISCORD_OPERATION_SPECS = {
|
|
|
358
362
|
params: [guildId(), userId()],
|
|
359
363
|
},
|
|
360
364
|
};
|
|
365
|
+
/**
|
|
366
|
+
* Lo que puede hacer una credencial de Discord que NO es de bot.
|
|
367
|
+
*
|
|
368
|
+
* Medido contra la documentación de Discord, no de memoria:
|
|
369
|
+
* https://docs.discord.com/developers/resources/webhook
|
|
370
|
+
*
|
|
371
|
+
* `Execute Webhook` publica, y `Get/Edit/Delete Webhook Message` leen, editan y
|
|
372
|
+
* borran mensajes — pero **sólo los que envió ese mismo webhook**, y sólo en el
|
|
373
|
+
* canal para el que se creó. Las otras 13 (reacciones, pins, CRUD de canales,
|
|
374
|
+
* crear hilos, DMs, roles, miembros) piden un Bot Token: la propia doc las
|
|
375
|
+
* marca con `MANAGE_WEBHOOKS` o con permisos de guild.
|
|
376
|
+
*
|
|
377
|
+
* Los tres campos que se caen de `sendMessage`, uno por uno:
|
|
378
|
+
*
|
|
379
|
+
* - `channelId`: la URL del webhook YA dice el canal. El endpoint ni siquiera
|
|
380
|
+
* acepta `channel_id`.
|
|
381
|
+
* - `replyToMessageId`: `Execute Webhook` no acepta `message_reference`. No
|
|
382
|
+
* es que venga fijado — es que responder no existe por esta vía.
|
|
383
|
+
* - `interactionReply`: contestar a un slash command es cosa de la
|
|
384
|
+
* aplicación, no de un webhook.
|
|
385
|
+
*
|
|
386
|
+
* `threadId` SÍ se queda: `?thread_id=` es parámetro de query del endpoint.
|
|
387
|
+
*/
|
|
388
|
+
exports.DISCORD_CAPACIDADES_POR_CREDENCIAL = {
|
|
389
|
+
discord_webhook: {
|
|
390
|
+
operaciones: [
|
|
391
|
+
'sendMessage',
|
|
392
|
+
'editMessage',
|
|
393
|
+
'deleteMessage',
|
|
394
|
+
'getMessage',
|
|
395
|
+
],
|
|
396
|
+
camposNoDisponibles: [
|
|
397
|
+
'channelId',
|
|
398
|
+
'replyToMessageId',
|
|
399
|
+
'interactionReply',
|
|
400
|
+
],
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
/** Las operaciones que ofrecer para una credencial de Discord. */
|
|
404
|
+
function operacionesDeDiscordPara(tipoDeCredencial) {
|
|
405
|
+
return (0, capacidad_de_credencial_1.operacionesPara)(exports.DISCORD_OPERATIONS, exports.DISCORD_CAPACIDADES_POR_CREDENCIAL, tipoDeCredencial);
|
|
406
|
+
}
|
|
407
|
+
/** Si esa credencial puede ejecutar esa operación de Discord. */
|
|
408
|
+
function discordPuedeEjecutar(tipoDeCredencial, operacion) {
|
|
409
|
+
return (0, capacidad_de_credencial_1.puedeEjecutar)(exports.DISCORD_OPERATIONS, exports.DISCORD_CAPACIDADES_POR_CREDENCIAL, tipoDeCredencial, operacion);
|
|
410
|
+
}
|
|
411
|
+
/** Los campos que esa credencial de Discord no deja elegir. */
|
|
412
|
+
function camposDeDiscordNoDisponibles(tipoDeCredencial) {
|
|
413
|
+
return (0, capacidad_de_credencial_1.camposNoDisponiblesPara)(exports.DISCORD_CAPACIDADES_POR_CREDENCIAL, tipoDeCredencial);
|
|
414
|
+
}
|
|
@@ -45,3 +45,20 @@ export interface DiscordToolkitSpec {
|
|
|
45
45
|
}
|
|
46
46
|
export declare const DISCORD_TOOLKIT_SPECS: DiscordToolkitSpec[];
|
|
47
47
|
export declare const DISCORD_TOOLKIT_BY_TOOL_NAME: Record<string, DiscordToolkitSpec>;
|
|
48
|
+
/**
|
|
49
|
+
* Las herramientas que ofrecerle al modelo con ESTA credencial.
|
|
50
|
+
*
|
|
51
|
+
* Vive aquí y no en cada consumidor porque son dos —la expansión MCP de la api
|
|
52
|
+
* y el selector del AI Node del dashboard— y filtrar «casi igual» en dos sitios
|
|
53
|
+
* es exactamente la duplicación que costó tres PR quitar de este paquete.
|
|
54
|
+
*
|
|
55
|
+
* Filtra en los dos niveles, que es lo que hace falta y no es obvio:
|
|
56
|
+
*
|
|
57
|
+
* 1. **Operaciones**: sin esto, a un nodo con credencial de webhook se le
|
|
58
|
+
* entregan al modelo 17 herramientas de las que 13 fallan siempre. El
|
|
59
|
+
* modelo no tiene forma de saberlo: las ve anunciadas.
|
|
60
|
+
* 2. **Parámetros**: una herramienta que sigue pidiendo `channelId` invita al
|
|
61
|
+
* modelo a inventarse un canal que el webhook va a ignorar. Peor que
|
|
62
|
+
* fallar, porque parece que funcionó.
|
|
63
|
+
*/
|
|
64
|
+
export declare function herramientasDeDiscordPara(tipoDeCredencial: string | null | undefined): DiscordToolkitSpec[];
|
package/dist/discord-toolkit.js
CHANGED
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
*/
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
27
|
exports.DISCORD_TOOLKIT_BY_TOOL_NAME = exports.DISCORD_TOOLKIT_SPECS = void 0;
|
|
28
|
+
exports.herramientasDeDiscordPara = herramientasDeDiscordPara;
|
|
29
|
+
const discord_operations_1 = require("./discord-operations");
|
|
28
30
|
const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
|
|
29
31
|
exports.DISCORD_TOOLKIT_SPECS = [
|
|
30
32
|
// ── Messages ───────────────────────────────────────────────────
|
|
@@ -233,3 +235,30 @@ exports.DISCORD_TOOLKIT_SPECS = [
|
|
|
233
235
|
},
|
|
234
236
|
];
|
|
235
237
|
exports.DISCORD_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(exports.DISCORD_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
238
|
+
/**
|
|
239
|
+
* Las herramientas que ofrecerle al modelo con ESTA credencial.
|
|
240
|
+
*
|
|
241
|
+
* Vive aquí y no en cada consumidor porque son dos —la expansión MCP de la api
|
|
242
|
+
* y el selector del AI Node del dashboard— y filtrar «casi igual» en dos sitios
|
|
243
|
+
* es exactamente la duplicación que costó tres PR quitar de este paquete.
|
|
244
|
+
*
|
|
245
|
+
* Filtra en los dos niveles, que es lo que hace falta y no es obvio:
|
|
246
|
+
*
|
|
247
|
+
* 1. **Operaciones**: sin esto, a un nodo con credencial de webhook se le
|
|
248
|
+
* entregan al modelo 17 herramientas de las que 13 fallan siempre. El
|
|
249
|
+
* modelo no tiene forma de saberlo: las ve anunciadas.
|
|
250
|
+
* 2. **Parámetros**: una herramienta que sigue pidiendo `channelId` invita al
|
|
251
|
+
* modelo a inventarse un canal que el webhook va a ignorar. Peor que
|
|
252
|
+
* fallar, porque parece que funcionó.
|
|
253
|
+
*/
|
|
254
|
+
function herramientasDeDiscordPara(tipoDeCredencial) {
|
|
255
|
+
const permitidas = new Set((0, discord_operations_1.operacionesDeDiscordPara)(tipoDeCredencial));
|
|
256
|
+
const fuera = (0, discord_operations_1.camposDeDiscordNoDisponibles)(tipoDeCredencial);
|
|
257
|
+
return exports.DISCORD_TOOLKIT_SPECS.filter((s) => permitidas.has(s.operation)).map((s) =>
|
|
258
|
+
/* Se devuelve una copia sólo cuando hay algo que quitar: así el camino
|
|
259
|
+
normal —el bot, que puede con todo— sigue entregando las MISMAS
|
|
260
|
+
referencias de siempre y nadie paga por una función que no le afecta. */
|
|
261
|
+
fuera.size === 0
|
|
262
|
+
? s
|
|
263
|
+
: { ...s, parameters: s.parameters.filter((p) => !fuera.has(p.name)) });
|
|
264
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -22,9 +22,11 @@ export { TELEGRAM_TOOLKIT_SPECS, TELEGRAM_TOOLKIT_BY_TOOL_NAME, } from './telegr
|
|
|
22
22
|
export type { TelegramToolkitSpec, TelegramToolkitParameter, } from './telegram-toolkit';
|
|
23
23
|
export { WHATSAPP_OPERATIONS, isWhatsAppOperation, } from './whatsapp-operations';
|
|
24
24
|
export type { WhatsAppOperation } from './whatsapp-operations';
|
|
25
|
-
export {
|
|
25
|
+
export { operacionesPara, puedeEjecutar, camposNoDisponiblesPara, } from './capacidad-de-credencial';
|
|
26
|
+
export type { CapacidadDeCredencial, CapacidadesPorCredencial, } from './capacidad-de-credencial';
|
|
27
|
+
export { DISCORD_OPERATIONS, DISCORD_OPERATION_SPECS, DISCORD_CAPACIDADES_POR_CREDENCIAL, operacionesDeDiscordPara, discordPuedeEjecutar, camposDeDiscordNoDisponibles, isDiscordOperation, } from './discord-operations';
|
|
26
28
|
export type { DiscordOperation, DiscordParamSpec, DiscordOperationSpec, } from './discord-operations';
|
|
27
|
-
export { DISCORD_TOOLKIT_SPECS, DISCORD_TOOLKIT_BY_TOOL_NAME, } from './discord-toolkit';
|
|
29
|
+
export { DISCORD_TOOLKIT_SPECS, DISCORD_TOOLKIT_BY_TOOL_NAME, herramientasDeDiscordPara, } from './discord-toolkit';
|
|
28
30
|
export type { DiscordToolkitSpec, DiscordToolkitParameter, } from './discord-toolkit';
|
|
29
31
|
export { MAILCHIMP_OPERATIONS, MAILCHIMP_OPERATION_SPECS, MAILCHIMP_CONTACT_STATUSES, isMailchimpOperation, } from './mailchimp-operations';
|
|
30
32
|
export type { MailchimpOperation, MailchimpContactStatus, MailchimpParamSpec, MailchimpOperationSpec, } from './mailchimp-operations';
|
|
@@ -34,9 +36,9 @@ export { GITHUB_OPERATIONS, GITHUB_OPERATION_SPECS, GITHUB_DROPDOWN_OPERATIONS,
|
|
|
34
36
|
export type { GithubOperation, GithubParamType, GithubParamSpec, GithubOperationSpec, } from './github-operations';
|
|
35
37
|
export { JIRA_OPERATIONS, JIRA_OPERATION_SPECS, JIRA_DROPDOWN_OPERATIONS, JIRA_ITERABLE_OPERATIONS, isJiraOperation, } from './jira-operations';
|
|
36
38
|
export type { JiraOperation, JiraParamType, JiraParamSpec, JiraOperationSpec, } from './jira-operations';
|
|
37
|
-
export { SLACK_OPERATIONS, SLACK_OPERATION_SPECS, isSlackOperation, } from './slack-operations';
|
|
39
|
+
export { SLACK_OPERATIONS, SLACK_OPERATION_SPECS, SLACK_CAPACIDADES_POR_CREDENCIAL, operacionesDeSlackPara, slackPuedeEjecutar, camposDeSlackNoDisponibles, isSlackOperation, } from './slack-operations';
|
|
38
40
|
export type { SlackOperation, SlackParamSpec, SlackOperationSpec, } from './slack-operations';
|
|
39
|
-
export { SLACK_TOOLKIT_SPECS, SLACK_TOOLKIT_BY_TOOL_NAME, } from './slack-toolkit';
|
|
41
|
+
export { SLACK_TOOLKIT_SPECS, SLACK_TOOLKIT_BY_TOOL_NAME, herramientasDeSlackPara, } from './slack-toolkit';
|
|
40
42
|
export type { SlackToolkitSpec, SlackToolkitParameter, } from './slack-toolkit';
|
|
41
43
|
export { SHEETS_OPERATIONS, SHEETS_OPERATION_SPECS, isSheetsOperation, } from './sheets-operations';
|
|
42
44
|
export type { SheetsOperation, SheetsParamSpec, SheetsOperationSpec, } from './sheets-operations';
|
|
@@ -58,5 +60,7 @@ export { DOCS_TOOLKIT_SPECS, DOCS_TOOLKIT_BY_TOOL_NAME, DOCS_TOOLKIT_DEFAULTABLE
|
|
|
58
60
|
export type { DocsToolkitSpec, DocsToolkitParameter, } from './docs-toolkit';
|
|
59
61
|
export type { LlmProvider, LlmProviderOption, LlmModelOption, } from './llm-models';
|
|
60
62
|
export { LLM_PROVIDERS, LLM_MODELS, MODEL_CONTEXT_WINDOWS, getModelsFor, getDefaultModel, getModelLabel, } from './llm-models';
|
|
63
|
+
export type { ModeloDeOpenRouter, PrecioDeOpenRouter, RespuestaDeModelosDeOpenRouter, } from './openrouter';
|
|
64
|
+
export { URL_DE_MODELOS_DE_OPENROUTER, opcionesDeModelosDeOpenRouter, ventanaDeContextoDeOpenRouter, } from './openrouter';
|
|
61
65
|
export type { CredentialTypeRegistration, CredentialType } from './credentials';
|
|
62
66
|
export { CREDENTIAL_TYPES, CREDENTIAL_TYPE_VALUES, credentialTypeValues, getCredentialType, isCredentialType, } from './credentials';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DRIVE_OPERATION_SPECS = exports.DRIVE_OPERATIONS = exports.GOOGLE_CALENDAR_TOOLKIT_BY_TOOL_NAME = exports.GOOGLE_CALENDAR_TOOLKIT_SPECS = exports.isGoogleCalendarOperation = exports.GOOGLE_CALENDAR_OPERATION_SPECS = exports.GOOGLE_CALENDAR_OPERATIONS = exports.isGmailOperation = exports.resolveGmailSendFields = exports.GMAIL_SEND_LEGACY_FIELDS = exports.NATIVE_EMAIL_TOOLKIT_BY_TOOL_NAME = exports.GMAIL_TOOLKIT_BY_TOOL_NAME = exports.NATIVE_EMAIL_TOOLKIT_SPECS = exports.GMAIL_SEND_AND_WAIT_TOOL_SPEC = exports.GMAIL_ALL_TOOLKIT_SPECS = exports.GMAIL_TOOLKIT_SPECS = exports.GMAIL_TOOLKIT_OPERATIONS = exports.GMAIL_DROPDOWN_OPERATIONS = exports.GMAIL_OPERATION_GROUPS = exports.GMAIL_OPERATION_SPECS = exports.GMAIL_OPERATIONS = exports.versionCatalogErrors = exports.fieldsLost = exports.fieldsLostBetween = exports.currentVersion = exports.versionSpec = exports.versionsOf = exports.isVersioned = exports.NODE_TYPE_TO_PREFIX = exports.PREFIX_TO_NODE_TYPE = exports.NODE_STATE_KEYS = exports.NODE_COLORS = exports.NODE_DETAIL_PATHS = exports.getNodeRegistryEntry = exports.NODE_REGISTRY = exports.getNodeDispatchConfig = exports.getAllNodeCollections = exports.NODE_DISPATCH = exports.resolveNodeId = exports.PREFIX_TO_TYPE = exports.NODE_UI = exports.ALL_NODE_TYPES = exports.isNodeType = exports.isTerminal = exports.canSendToNodes = exports.canReceiveFromNodes = exports.canReceiveFrom = exports.NODE_CONNECTIONS = exports.iterableMeta = exports.singleMeta = void 0;
|
|
4
|
-
exports.
|
|
5
|
-
exports.isCredentialType = exports.getCredentialType = exports.credentialTypeValues = exports.CREDENTIAL_TYPE_VALUES = exports.CREDENTIAL_TYPES = exports.getModelLabel = exports.getDefaultModel = exports.getModelsFor = exports.MODEL_CONTEXT_WINDOWS = exports.LLM_MODELS = exports.LLM_PROVIDERS = exports.DOCS_TOOLKIT_DEFAULTABLE = exports.DOCS_TOOLKIT_BY_TOOL_NAME = exports.DOCS_TOOLKIT_SPECS = exports.isDocsOperation = exports.DOCS_OPERATION_SPECS = exports.DOCS_OPERATIONS = exports.isMongoOperation = exports.MONGO_OPERATION_SPECS = exports.MONGO_OPERATIONS = exports.isPostgresOperation = exports.POSTGRES_OPERATION_SPECS = exports.POSTGRES_MODES = exports.POSTGRES_OPERATIONS = exports.isNotionOperation = exports.NOTION_DROPDOWN_OPERATIONS = exports.NOTION_OPERATION_SPECS = exports.NOTION_OPERATIONS = exports.isGoogleAnalyticsOperation = exports.GOOGLE_ANALYTICS_DROPDOWN_OPERATIONS = exports.GOOGLE_ANALYTICS_OPERATION_SPECS = exports.GOOGLE_ANALYTICS_OPERATIONS = exports.isGoogleContactsOperation = exports.GOOGLE_CONTACTS_DEFAULT_PERSON_FIELDS = void 0;
|
|
4
|
+
exports.SLACK_TOOLKIT_SPECS = exports.isSlackOperation = exports.camposDeSlackNoDisponibles = exports.slackPuedeEjecutar = exports.operacionesDeSlackPara = exports.SLACK_CAPACIDADES_POR_CREDENCIAL = exports.SLACK_OPERATION_SPECS = exports.SLACK_OPERATIONS = exports.isJiraOperation = exports.JIRA_ITERABLE_OPERATIONS = exports.JIRA_DROPDOWN_OPERATIONS = exports.JIRA_OPERATION_SPECS = exports.JIRA_OPERATIONS = exports.isGithubOperation = exports.GITHUB_ITERABLE_OPERATIONS = exports.GITHUB_DROPDOWN_OPERATIONS = exports.GITHUB_OPERATION_SPECS = exports.GITHUB_OPERATIONS = exports.isShopifyOperation = exports.SHOPIFY_SEARCHABLE_RESOURCES = exports.SHOPIFY_TAGGABLE_RESOURCES = exports.SHOPIFY_OPERATION_SPECS = exports.SHOPIFY_OPERATIONS = exports.isMailchimpOperation = exports.MAILCHIMP_CONTACT_STATUSES = exports.MAILCHIMP_OPERATION_SPECS = exports.MAILCHIMP_OPERATIONS = exports.herramientasDeDiscordPara = exports.DISCORD_TOOLKIT_BY_TOOL_NAME = exports.DISCORD_TOOLKIT_SPECS = exports.isDiscordOperation = exports.camposDeDiscordNoDisponibles = exports.discordPuedeEjecutar = exports.operacionesDeDiscordPara = exports.DISCORD_CAPACIDADES_POR_CREDENCIAL = exports.DISCORD_OPERATION_SPECS = exports.DISCORD_OPERATIONS = exports.camposNoDisponiblesPara = exports.puedeEjecutar = exports.operacionesPara = exports.isWhatsAppOperation = exports.WHATSAPP_OPERATIONS = exports.TELEGRAM_TOOLKIT_BY_TOOL_NAME = exports.TELEGRAM_TOOLKIT_SPECS = exports.isTelegramOperation = exports.TELEGRAM_OPERATION_SPECS = exports.TELEGRAM_OPERATIONS = exports.DRIVE_TOOLKIT_BY_TOOL_NAME = exports.DRIVE_TOOLKIT_SPECS = exports.isDriveOperation = void 0;
|
|
5
|
+
exports.isCredentialType = exports.getCredentialType = exports.credentialTypeValues = exports.CREDENTIAL_TYPE_VALUES = exports.CREDENTIAL_TYPES = exports.ventanaDeContextoDeOpenRouter = exports.opcionesDeModelosDeOpenRouter = exports.URL_DE_MODELOS_DE_OPENROUTER = exports.getModelLabel = exports.getDefaultModel = exports.getModelsFor = exports.MODEL_CONTEXT_WINDOWS = exports.LLM_MODELS = exports.LLM_PROVIDERS = exports.DOCS_TOOLKIT_DEFAULTABLE = exports.DOCS_TOOLKIT_BY_TOOL_NAME = exports.DOCS_TOOLKIT_SPECS = exports.isDocsOperation = exports.DOCS_OPERATION_SPECS = exports.DOCS_OPERATIONS = exports.isMongoOperation = exports.MONGO_OPERATION_SPECS = exports.MONGO_OPERATIONS = exports.isPostgresOperation = exports.POSTGRES_OPERATION_SPECS = exports.POSTGRES_MODES = exports.POSTGRES_OPERATIONS = exports.isNotionOperation = exports.NOTION_DROPDOWN_OPERATIONS = exports.NOTION_OPERATION_SPECS = exports.NOTION_OPERATIONS = exports.isGoogleAnalyticsOperation = exports.GOOGLE_ANALYTICS_DROPDOWN_OPERATIONS = exports.GOOGLE_ANALYTICS_OPERATION_SPECS = exports.GOOGLE_ANALYTICS_OPERATIONS = exports.isGoogleContactsOperation = exports.GOOGLE_CONTACTS_DEFAULT_PERSON_FIELDS = exports.GOOGLE_CONTACTS_OPERATION_GROUPS = exports.GOOGLE_CONTACTS_OPERATION_SPECS = exports.GOOGLE_CONTACTS_OPERATIONS_V2 = exports.GOOGLE_CONTACTS_OPERATIONS_V1 = exports.GOOGLE_CONTACTS_OPERATIONS = exports.SHEETS_TOOLKIT_DEFAULTABLE = exports.SHEETS_TOOLKIT_BY_TOOL_NAME = exports.SHEETS_TOOLKIT_SPECS = exports.isSheetsOperation = exports.SHEETS_OPERATION_SPECS = exports.SHEETS_OPERATIONS = exports.herramientasDeSlackPara = exports.SLACK_TOOLKIT_BY_TOOL_NAME = void 0;
|
|
6
6
|
var types_1 = require("./types");
|
|
7
7
|
Object.defineProperty(exports, "singleMeta", { enumerable: true, get: function () { return types_1.singleMeta; } });
|
|
8
8
|
Object.defineProperty(exports, "iterableMeta", { enumerable: true, get: function () { return types_1.iterableMeta; } });
|
|
@@ -83,9 +83,20 @@ Object.defineProperty(exports, "TELEGRAM_TOOLKIT_BY_TOOL_NAME", { enumerable: tr
|
|
|
83
83
|
var whatsapp_operations_1 = require("./whatsapp-operations");
|
|
84
84
|
Object.defineProperty(exports, "WHATSAPP_OPERATIONS", { enumerable: true, get: function () { return whatsapp_operations_1.WHATSAPP_OPERATIONS; } });
|
|
85
85
|
Object.defineProperty(exports, "isWhatsAppOperation", { enumerable: true, get: function () { return whatsapp_operations_1.isWhatsAppOperation; } });
|
|
86
|
+
/* La forma del mapa de capacidades. Los datos de cada proveedor viven en su
|
|
87
|
+
propio fichero de operaciones, que es donde se mira cuando uno se pregunta
|
|
88
|
+
qué sabe hacer ese nodo. */
|
|
89
|
+
var capacidad_de_credencial_1 = require("./capacidad-de-credencial");
|
|
90
|
+
Object.defineProperty(exports, "operacionesPara", { enumerable: true, get: function () { return capacidad_de_credencial_1.operacionesPara; } });
|
|
91
|
+
Object.defineProperty(exports, "puedeEjecutar", { enumerable: true, get: function () { return capacidad_de_credencial_1.puedeEjecutar; } });
|
|
92
|
+
Object.defineProperty(exports, "camposNoDisponiblesPara", { enumerable: true, get: function () { return capacidad_de_credencial_1.camposNoDisponiblesPara; } });
|
|
86
93
|
var discord_operations_1 = require("./discord-operations");
|
|
87
94
|
Object.defineProperty(exports, "DISCORD_OPERATIONS", { enumerable: true, get: function () { return discord_operations_1.DISCORD_OPERATIONS; } });
|
|
88
95
|
Object.defineProperty(exports, "DISCORD_OPERATION_SPECS", { enumerable: true, get: function () { return discord_operations_1.DISCORD_OPERATION_SPECS; } });
|
|
96
|
+
Object.defineProperty(exports, "DISCORD_CAPACIDADES_POR_CREDENCIAL", { enumerable: true, get: function () { return discord_operations_1.DISCORD_CAPACIDADES_POR_CREDENCIAL; } });
|
|
97
|
+
Object.defineProperty(exports, "operacionesDeDiscordPara", { enumerable: true, get: function () { return discord_operations_1.operacionesDeDiscordPara; } });
|
|
98
|
+
Object.defineProperty(exports, "discordPuedeEjecutar", { enumerable: true, get: function () { return discord_operations_1.discordPuedeEjecutar; } });
|
|
99
|
+
Object.defineProperty(exports, "camposDeDiscordNoDisponibles", { enumerable: true, get: function () { return discord_operations_1.camposDeDiscordNoDisponibles; } });
|
|
89
100
|
Object.defineProperty(exports, "isDiscordOperation", { enumerable: true, get: function () { return discord_operations_1.isDiscordOperation; } });
|
|
90
101
|
/* Ojo con los dos nombres parecidos, que vienen de dos ficheros y NO son lo
|
|
91
102
|
mismo: `DiscordOperationSpec` (arriba) describe el FORMULARIO —qué control
|
|
@@ -94,6 +105,7 @@ Object.defineProperty(exports, "isDiscordOperation", { enumerable: true, get: fu
|
|
|
94
105
|
var discord_toolkit_1 = require("./discord-toolkit");
|
|
95
106
|
Object.defineProperty(exports, "DISCORD_TOOLKIT_SPECS", { enumerable: true, get: function () { return discord_toolkit_1.DISCORD_TOOLKIT_SPECS; } });
|
|
96
107
|
Object.defineProperty(exports, "DISCORD_TOOLKIT_BY_TOOL_NAME", { enumerable: true, get: function () { return discord_toolkit_1.DISCORD_TOOLKIT_BY_TOOL_NAME; } });
|
|
108
|
+
Object.defineProperty(exports, "herramientasDeDiscordPara", { enumerable: true, get: function () { return discord_toolkit_1.herramientasDeDiscordPara; } });
|
|
97
109
|
var mailchimp_operations_1 = require("./mailchimp-operations");
|
|
98
110
|
Object.defineProperty(exports, "MAILCHIMP_OPERATIONS", { enumerable: true, get: function () { return mailchimp_operations_1.MAILCHIMP_OPERATIONS; } });
|
|
99
111
|
Object.defineProperty(exports, "MAILCHIMP_OPERATION_SPECS", { enumerable: true, get: function () { return mailchimp_operations_1.MAILCHIMP_OPERATION_SPECS; } });
|
|
@@ -120,12 +132,17 @@ Object.defineProperty(exports, "isJiraOperation", { enumerable: true, get: funct
|
|
|
120
132
|
var slack_operations_1 = require("./slack-operations");
|
|
121
133
|
Object.defineProperty(exports, "SLACK_OPERATIONS", { enumerable: true, get: function () { return slack_operations_1.SLACK_OPERATIONS; } });
|
|
122
134
|
Object.defineProperty(exports, "SLACK_OPERATION_SPECS", { enumerable: true, get: function () { return slack_operations_1.SLACK_OPERATION_SPECS; } });
|
|
135
|
+
Object.defineProperty(exports, "SLACK_CAPACIDADES_POR_CREDENCIAL", { enumerable: true, get: function () { return slack_operations_1.SLACK_CAPACIDADES_POR_CREDENCIAL; } });
|
|
136
|
+
Object.defineProperty(exports, "operacionesDeSlackPara", { enumerable: true, get: function () { return slack_operations_1.operacionesDeSlackPara; } });
|
|
137
|
+
Object.defineProperty(exports, "slackPuedeEjecutar", { enumerable: true, get: function () { return slack_operations_1.slackPuedeEjecutar; } });
|
|
138
|
+
Object.defineProperty(exports, "camposDeSlackNoDisponibles", { enumerable: true, get: function () { return slack_operations_1.camposDeSlackNoDisponibles; } });
|
|
123
139
|
Object.defineProperty(exports, "isSlackOperation", { enumerable: true, get: function () { return slack_operations_1.isSlackOperation; } });
|
|
124
140
|
/* Misma pareja que en Discord: `SlackOperationSpec` es el formulario,
|
|
125
141
|
`SlackToolkitSpec` es la herramienta que ve el LLM. */
|
|
126
142
|
var slack_toolkit_1 = require("./slack-toolkit");
|
|
127
143
|
Object.defineProperty(exports, "SLACK_TOOLKIT_SPECS", { enumerable: true, get: function () { return slack_toolkit_1.SLACK_TOOLKIT_SPECS; } });
|
|
128
144
|
Object.defineProperty(exports, "SLACK_TOOLKIT_BY_TOOL_NAME", { enumerable: true, get: function () { return slack_toolkit_1.SLACK_TOOLKIT_BY_TOOL_NAME; } });
|
|
145
|
+
Object.defineProperty(exports, "herramientasDeSlackPara", { enumerable: true, get: function () { return slack_toolkit_1.herramientasDeSlackPara; } });
|
|
129
146
|
var sheets_operations_1 = require("./sheets-operations");
|
|
130
147
|
Object.defineProperty(exports, "SHEETS_OPERATIONS", { enumerable: true, get: function () { return sheets_operations_1.SHEETS_OPERATIONS; } });
|
|
131
148
|
Object.defineProperty(exports, "SHEETS_OPERATION_SPECS", { enumerable: true, get: function () { return sheets_operations_1.SHEETS_OPERATION_SPECS; } });
|
|
@@ -176,6 +193,10 @@ Object.defineProperty(exports, "MODEL_CONTEXT_WINDOWS", { enumerable: true, get:
|
|
|
176
193
|
Object.defineProperty(exports, "getModelsFor", { enumerable: true, get: function () { return llm_models_1.getModelsFor; } });
|
|
177
194
|
Object.defineProperty(exports, "getDefaultModel", { enumerable: true, get: function () { return llm_models_1.getDefaultModel; } });
|
|
178
195
|
Object.defineProperty(exports, "getModelLabel", { enumerable: true, get: function () { return llm_models_1.getModelLabel; } });
|
|
196
|
+
var openrouter_1 = require("./openrouter");
|
|
197
|
+
Object.defineProperty(exports, "URL_DE_MODELOS_DE_OPENROUTER", { enumerable: true, get: function () { return openrouter_1.URL_DE_MODELOS_DE_OPENROUTER; } });
|
|
198
|
+
Object.defineProperty(exports, "opcionesDeModelosDeOpenRouter", { enumerable: true, get: function () { return openrouter_1.opcionesDeModelosDeOpenRouter; } });
|
|
199
|
+
Object.defineProperty(exports, "ventanaDeContextoDeOpenRouter", { enumerable: true, get: function () { return openrouter_1.ventanaDeContextoDeOpenRouter; } });
|
|
179
200
|
var credentials_1 = require("./credentials");
|
|
180
201
|
Object.defineProperty(exports, "CREDENTIAL_TYPES", { enumerable: true, get: function () { return credentials_1.CREDENTIAL_TYPES; } });
|
|
181
202
|
Object.defineProperty(exports, "CREDENTIAL_TYPE_VALUES", { enumerable: true, get: function () { return credentials_1.CREDENTIAL_TYPE_VALUES; } });
|
package/dist/llm-models.d.ts
CHANGED
|
@@ -25,8 +25,18 @@
|
|
|
25
25
|
* - OpenAI: https://developers.openai.com/api/docs/models
|
|
26
26
|
* - Google: https://ai.google.dev/gemini-api/docs/models
|
|
27
27
|
* - Groq: https://console.groq.com/docs/models
|
|
28
|
+
*
|
|
29
|
+
* NOT verified against docs, and on purpose: OpenRouter. Its catalog is not a
|
|
30
|
+
* list anybody types — see `LLM_MODELS.openrouter` and `openrouter.ts`.
|
|
31
|
+
*/
|
|
32
|
+
export type LlmProvider = 'anthropic' | 'openai' | 'google' | 'groq'
|
|
33
|
+
/**
|
|
34
|
+
* A router, not a lab: OpenRouter resells ~425 models from everybody else
|
|
35
|
+
* behind one key. That is why it is the first provider here whose catalog
|
|
36
|
+
* is EMPTY below and fetched live instead — the shape of the entry is in
|
|
37
|
+
* `openrouter.ts`, and the price of each model travels with the model.
|
|
28
38
|
*/
|
|
29
|
-
|
|
39
|
+
| 'openrouter';
|
|
30
40
|
export interface LlmProviderOption {
|
|
31
41
|
value: LlmProvider;
|
|
32
42
|
label: string;
|
|
@@ -58,6 +68,13 @@ export declare const LLM_MODELS: Record<LlmProvider, ReadonlyArray<LlmModelOptio
|
|
|
58
68
|
*
|
|
59
69
|
* Includes ids the pickers no longer offer: the AI node's model field is
|
|
60
70
|
* a free-text datalist, so a node may hold one by hand.
|
|
71
|
+
*
|
|
72
|
+
* ⚠️ NOT here: OpenRouter's ids. Same reason its models are not in
|
|
73
|
+
* `LLM_MODELS` — its API publishes `context_length` per model, so the number
|
|
74
|
+
* travels with the model instead of being copied 425 times into this table.
|
|
75
|
+
* Whoever chunks for an OpenRouter model reads it from the fetched entry
|
|
76
|
+
* (`ModeloDeOpenRouter.context_length`); a lookup here misses and falls back
|
|
77
|
+
* to the conservative 32k, which still summarizes, just in more calls.
|
|
61
78
|
*/
|
|
62
79
|
export declare const MODEL_CONTEXT_WINDOWS: Record<string, number>;
|
|
63
80
|
/**
|
|
@@ -71,6 +88,13 @@ export declare function getModelsFor(provider: string): ReadonlyArray<LlmModelOp
|
|
|
71
88
|
* The suggested default model for a provider, or `''` for one we do not
|
|
72
89
|
* catalog (Ollama runs whatever the user pulled, so it has no entry —
|
|
73
90
|
* callers fall back to the node's own model there).
|
|
91
|
+
*
|
|
92
|
+
* ⚠️ `'openrouter'` is the second `''`, and unlike Ollama it IS a provider in
|
|
93
|
+
* `LLM_PROVIDERS`, so callers that assumed "every provider in the list has a
|
|
94
|
+
* default" now have a case to handle. It is deliberate: its catalog is live
|
|
95
|
+
* (see `LLM_MODELS.openrouter`) and no static pick would survive. Treat `''`
|
|
96
|
+
* as "the user must choose", not as "fall back to something" — a node born
|
|
97
|
+
* with an empty model must not be sent to the API as-is.
|
|
74
98
|
*/
|
|
75
99
|
export declare function getDefaultModel(provider: string): string;
|
|
76
100
|
/** The friendly label for a model value, or the value itself. */
|
package/dist/llm-models.js
CHANGED
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
* - OpenAI: https://developers.openai.com/api/docs/models
|
|
27
27
|
* - Google: https://ai.google.dev/gemini-api/docs/models
|
|
28
28
|
* - Groq: https://console.groq.com/docs/models
|
|
29
|
+
*
|
|
30
|
+
* NOT verified against docs, and on purpose: OpenRouter. Its catalog is not a
|
|
31
|
+
* list anybody types — see `LLM_MODELS.openrouter` and `openrouter.ts`.
|
|
29
32
|
*/
|
|
30
33
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
34
|
exports.MODEL_CONTEXT_WINDOWS = exports.LLM_MODELS = exports.LLM_PROVIDERS = void 0;
|
|
@@ -37,6 +40,7 @@ exports.LLM_PROVIDERS = [
|
|
|
37
40
|
{ value: 'openai', label: 'OpenAI' },
|
|
38
41
|
{ value: 'google', label: 'Google' },
|
|
39
42
|
{ value: 'groq', label: 'Groq' },
|
|
43
|
+
{ value: 'openrouter', label: 'OpenRouter' },
|
|
40
44
|
];
|
|
41
45
|
exports.LLM_MODELS = {
|
|
42
46
|
// ── Anthropic ──────────────────────────────────────────────────────────
|
|
@@ -106,6 +110,38 @@ exports.LLM_MODELS = {
|
|
|
106
110
|
{ value: 'groq/compound-mini', label: 'Compound Mini' },
|
|
107
111
|
{ value: 'qwen/qwen3.6-27b', label: 'Qwen 3.6 27B (preview)' },
|
|
108
112
|
],
|
|
113
|
+
// ── OpenRouter ─────────────────────────────────────────────────────────
|
|
114
|
+
// EMPTY ON PURPOSE. Not a gap, not a TODO — read this before filling it.
|
|
115
|
+
//
|
|
116
|
+
// Every other provider above is a lab with a dozen models, each with a
|
|
117
|
+
// price we look up in `MODEL_PRICING` over in platform-contracts. OpenRouter
|
|
118
|
+
// is a router: ~425 models from everybody else, and the set moves on its own
|
|
119
|
+
// — models appear, get deprecated and change price without anyone here
|
|
120
|
+
// touching a file. Typing them out has three separate costs:
|
|
121
|
+
//
|
|
122
|
+
// 1. It goes stale silently. That is the exact failure this whole file
|
|
123
|
+
// exists to kill (the picker offering a model the api had retired),
|
|
124
|
+
// only this time with 425 chances to happen instead of eight.
|
|
125
|
+
// 2. The price would have to be hand-copied into `MODEL_PRICING` too —
|
|
126
|
+
// 425 rows of a number the API already hands us with each model. A
|
|
127
|
+
// wrong row there does not fail loudly: it makes a dollar spending cap
|
|
128
|
+
// cut in the wrong place, or never.
|
|
129
|
+
// 3. Nobody wants a 425-entry dropdown anyway. The dashboard has to
|
|
130
|
+
// search/filter it live regardless of what we ship here.
|
|
131
|
+
//
|
|
132
|
+
// So the catalog is FETCHED: `GET https://openrouter.ai/api/v1/models` is
|
|
133
|
+
// open, needs no key, and each entry carries id, name, context_length AND
|
|
134
|
+
// its own pricing. `openrouter.ts` types that payload and maps it to the
|
|
135
|
+
// very same `LlmModelOption` the pickers already render; the pricing half
|
|
136
|
+
// is `tarifaDeOpenRouter` in `@hostwebhook/platform-contracts`, which turns
|
|
137
|
+
// it into a `ModelPricing` you hand to `calculateCost(..., tarifa)`.
|
|
138
|
+
//
|
|
139
|
+
// Consequence, stated out loud because it is the surprising part:
|
|
140
|
+
// `getDefaultModel('openrouter')` is `''`. There is no honest default among
|
|
141
|
+
// 425 models we do not curate — any pick here would be a guess that can be
|
|
142
|
+
// deprecated out from under us — so choosing a model is REQUIRED when the
|
|
143
|
+
// provider is OpenRouter. See `getDefaultModel` below.
|
|
144
|
+
openrouter: [],
|
|
109
145
|
};
|
|
110
146
|
/**
|
|
111
147
|
* Effective context window per model, in TOKENS. The api sizes
|
|
@@ -116,6 +152,13 @@ exports.LLM_MODELS = {
|
|
|
116
152
|
*
|
|
117
153
|
* Includes ids the pickers no longer offer: the AI node's model field is
|
|
118
154
|
* a free-text datalist, so a node may hold one by hand.
|
|
155
|
+
*
|
|
156
|
+
* ⚠️ NOT here: OpenRouter's ids. Same reason its models are not in
|
|
157
|
+
* `LLM_MODELS` — its API publishes `context_length` per model, so the number
|
|
158
|
+
* travels with the model instead of being copied 425 times into this table.
|
|
159
|
+
* Whoever chunks for an OpenRouter model reads it from the fetched entry
|
|
160
|
+
* (`ModeloDeOpenRouter.context_length`); a lookup here misses and falls back
|
|
161
|
+
* to the conservative 32k, which still summarizes, just in more calls.
|
|
119
162
|
*/
|
|
120
163
|
exports.MODEL_CONTEXT_WINDOWS = {
|
|
121
164
|
// Anthropic — the 4.6 generation onward is 1M; Haiku and the 4.5 line
|
|
@@ -169,6 +212,13 @@ function getModelsFor(provider) {
|
|
|
169
212
|
* The suggested default model for a provider, or `''` for one we do not
|
|
170
213
|
* catalog (Ollama runs whatever the user pulled, so it has no entry —
|
|
171
214
|
* callers fall back to the node's own model there).
|
|
215
|
+
*
|
|
216
|
+
* ⚠️ `'openrouter'` is the second `''`, and unlike Ollama it IS a provider in
|
|
217
|
+
* `LLM_PROVIDERS`, so callers that assumed "every provider in the list has a
|
|
218
|
+
* default" now have a case to handle. It is deliberate: its catalog is live
|
|
219
|
+
* (see `LLM_MODELS.openrouter`) and no static pick would survive. Treat `''`
|
|
220
|
+
* as "the user must choose", not as "fall back to something" — a node born
|
|
221
|
+
* with an empty model must not be sent to the API as-is.
|
|
172
222
|
*/
|
|
173
223
|
function getDefaultModel(provider) {
|
|
174
224
|
const models = getModelsFor(provider);
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* El catálogo VIVO de OpenRouter: la forma de lo que devuelve su API y cómo se
|
|
3
|
+
* convierte en las mismas opciones que ya pintan los desplegables.
|
|
4
|
+
*
|
|
5
|
+
* ## Por qué este proveedor no tiene lista en `llm-models.ts`
|
|
6
|
+
*
|
|
7
|
+
* Porque no es un laboratorio, es un router: revende ~425 modelos de otros
|
|
8
|
+
* detrás de una sola clave, y el conjunto se mueve solo. La lista entera está
|
|
9
|
+
* en `GET https://openrouter.ai/api/v1/models`, que es **abierto y sin clave**
|
|
10
|
+
* —se puede pedir antes de que el usuario haya pegado ninguna— y cada entrada
|
|
11
|
+
* trae su `context_length` y **su propio precio**. Copiar eso a mano a
|
|
12
|
+
* `LLM_MODELS` y a `MODEL_PRICING` sería mantener a mano lo que la API ya da,
|
|
13
|
+
* con 425 oportunidades de que se quede viejo en silencio.
|
|
14
|
+
*
|
|
15
|
+
* ## El reparto, que es lo que hay que entender antes de tocar esto
|
|
16
|
+
*
|
|
17
|
+
* De la MISMA respuesta salen dos cosas, y viven en paquetes distintos porque
|
|
18
|
+
* son de dueños distintos:
|
|
19
|
+
*
|
|
20
|
+
* - **el catálogo** (id, nombre, ventana de contexto) → aquí, porque el
|
|
21
|
+
* catálogo de modelos es de este fichero desde siempre;
|
|
22
|
+
* - **la tarifa** (`pricing`) → `tarifaDeOpenRouter` en
|
|
23
|
+
* `@hostwebhook/platform-contracts`, porque el precio de un token es de
|
|
24
|
+
* ese paquete y no de éste.
|
|
25
|
+
*
|
|
26
|
+
* Y no al revés: este paquete NO puede importar `ModelPricing`
|
|
27
|
+
* —`platform-contracts` depende de éste, no al contrario—, así que el tipo que
|
|
28
|
+
* cruza es el crudo `ModeloDeOpenRouter`. Quien pinte el selector hace UN solo
|
|
29
|
+
* fetch y pasa cada entrada por las dos funciones.
|
|
30
|
+
*
|
|
31
|
+
* ## ⚠️ Esto es una respuesta de red, no un fichero nuestro
|
|
32
|
+
*
|
|
33
|
+
* Todo lo que no sea `id` va opcional a propósito. No porque OpenRouter lo
|
|
34
|
+
* omita hoy, sino porque nada nuestro impide que lo omita mañana, y un campo
|
|
35
|
+
* declarado obligatorio que llega `undefined` no falla al parsear —TypeScript
|
|
36
|
+
* no valida en runtime—: falla más tarde y más lejos, leyendo una propiedad de
|
|
37
|
+
* algo que no está. `id` es la única excepción porque sin él la entrada no
|
|
38
|
+
* identifica a ningún modelo y no hay nada que ofrecer.
|
|
39
|
+
*
|
|
40
|
+
* Verificado contra la respuesta real el 2026-08-31: 425 modelos, los 425 con
|
|
41
|
+
* `pricing.prompt` y `pricing.completion`, y algunos con un
|
|
42
|
+
* `top_provider.context_length` MENOR que su `context_length` anunciado.
|
|
43
|
+
*/
|
|
44
|
+
import type { LlmModelOption } from './llm-models';
|
|
45
|
+
/** El endpoint del catálogo. Abierto: no lleva `Authorization`. */
|
|
46
|
+
export declare const URL_DE_MODELOS_DE_OPENROUTER = "https://openrouter.ai/api/v1/models";
|
|
47
|
+
/**
|
|
48
|
+
* El bloque `pricing` de un modelo.
|
|
49
|
+
*
|
|
50
|
+
* ⚠️ Dos trampas, las dos verificadas contra la respuesta real:
|
|
51
|
+
*
|
|
52
|
+
* 1. Los valores son **cadenas**, no números: `"0.0000001"`.
|
|
53
|
+
* 2. Son **por token**, no por millón. `"0.0000001"` = $0,10 por millón.
|
|
54
|
+
*
|
|
55
|
+
* O sea que ninguno de estos números se puede meter en un `ModelPricing` sin
|
|
56
|
+
* pasar por `tarifaDeOpenRouter`, que hace las dos conversiones.
|
|
57
|
+
*
|
|
58
|
+
* Se tipa como índice abierto porque OpenRouter publica más claves de las que
|
|
59
|
+
* usamos (`request`, `image`, `web_search`, `internal_reasoning`, y las de
|
|
60
|
+
* caché) y añade más sin avisar.
|
|
61
|
+
*/
|
|
62
|
+
export interface PrecioDeOpenRouter {
|
|
63
|
+
/** USD por token de ENTRADA, como cadena. */
|
|
64
|
+
prompt?: string | null;
|
|
65
|
+
/** USD por token de SALIDA, como cadena. */
|
|
66
|
+
completion?: string | null;
|
|
67
|
+
/** USD por token leído de caché. Hoy no se usa: ver `tarifaDeOpenRouter`. */
|
|
68
|
+
input_cache_read?: string | null;
|
|
69
|
+
/** USD por token escrito en caché. Hoy no se usa. */
|
|
70
|
+
input_cache_write?: string | null;
|
|
71
|
+
/** Caché de una hora, cuando el modelo la ofrece. Hoy no se usa. */
|
|
72
|
+
input_cache_write_1h?: string | null;
|
|
73
|
+
[otras: string]: unknown;
|
|
74
|
+
}
|
|
75
|
+
/** Una entrada del catálogo de OpenRouter. */
|
|
76
|
+
export interface ModeloDeOpenRouter {
|
|
77
|
+
/**
|
|
78
|
+
* Lo que se le manda a la API como `model`, con el laboratorio delante:
|
|
79
|
+
* `"anthropic/claude-sonnet-5"`, `"openai/gpt-5.6-luna"`.
|
|
80
|
+
*
|
|
81
|
+
* ⚠️ Ese prefijo es parte del id y NO se quita. Un `"anthropic/..."`
|
|
82
|
+
* recortado a `"claude-sonnet-5"` cobraría la tarifa de la tabla estática
|
|
83
|
+
* —la de comprarle a Anthropic directamente— y OpenRouter no cobra eso.
|
|
84
|
+
*/
|
|
85
|
+
id: string;
|
|
86
|
+
/** El id sin el sufijo de variante (`:free`, `:nitro`, `:floor`). */
|
|
87
|
+
canonical_slug?: string;
|
|
88
|
+
/** Nombre para humanos: `"Anthropic: Claude Sonnet 5"`. */
|
|
89
|
+
name?: string;
|
|
90
|
+
/** Ventana efectiva en TOKENS, tal y como la publica el proveedor. */
|
|
91
|
+
context_length?: number | null;
|
|
92
|
+
pricing?: PrecioDeOpenRouter | null;
|
|
93
|
+
architecture?: {
|
|
94
|
+
input_modalities?: string[];
|
|
95
|
+
output_modalities?: string[];
|
|
96
|
+
tokenizer?: string;
|
|
97
|
+
[otras: string]: unknown;
|
|
98
|
+
} | null;
|
|
99
|
+
top_provider?: {
|
|
100
|
+
context_length?: number | null;
|
|
101
|
+
max_completion_tokens?: number | null;
|
|
102
|
+
is_moderated?: boolean;
|
|
103
|
+
[otras: string]: unknown;
|
|
104
|
+
} | null;
|
|
105
|
+
/** Qué parámetros acepta: `"tools"`, `"reasoning"`, `"structured_outputs"`… */
|
|
106
|
+
supported_parameters?: string[] | null;
|
|
107
|
+
[otras: string]: unknown;
|
|
108
|
+
}
|
|
109
|
+
/** El sobre: `{ data: [...] }`. */
|
|
110
|
+
export interface RespuestaDeModelosDeOpenRouter {
|
|
111
|
+
data?: ModeloDeOpenRouter[] | null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Las opciones del desplegable a partir de la respuesta cruda.
|
|
115
|
+
*
|
|
116
|
+
* Devuelve `LlmModelOption`, el MISMO tipo que `LLM_MODELS`, para que el
|
|
117
|
+
* selector no tenga dos formas de modelo según el proveedor: la única
|
|
118
|
+
* diferencia entre un catálogo y el otro es de dónde salió la lista.
|
|
119
|
+
*
|
|
120
|
+
* ⚠️ Ninguna opción sale `recommended`. En los catálogos estáticos esa marca
|
|
121
|
+
* la pone una persona que ha mirado los precios; aquí no hay nadie mirando, y
|
|
122
|
+
* una recomendación automática —«el primero», «el más barato»— sería una
|
|
123
|
+
* decisión de producto tomada por accidente. Sin `recommended`,
|
|
124
|
+
* `getDefaultModel('openrouter')` sigue siendo `''` y elegir es del usuario.
|
|
125
|
+
*
|
|
126
|
+
* Acepta el sobre entero o el array suelto porque quien llama a veces ya lo ha
|
|
127
|
+
* desenvuelto, y tolera basura (`null`, entradas sin `id`) devolviendo lo que
|
|
128
|
+
* sí sirve: un catálogo a medias es utilizable, una excepción a media pantalla
|
|
129
|
+
* no.
|
|
130
|
+
*/
|
|
131
|
+
export declare function opcionesDeModelosDeOpenRouter(respuesta: RespuestaDeModelosDeOpenRouter | ModeloDeOpenRouter[] | null | undefined): LlmModelOption[];
|
|
132
|
+
/**
|
|
133
|
+
* La ventana de contexto de un modelo de OpenRouter, en tokens, o `undefined`.
|
|
134
|
+
*
|
|
135
|
+
* Aparte y con nombre propio porque hay DOS sitios donde viene y no siempre
|
|
136
|
+
* coinciden: `context_length` es lo que anuncia el modelo, y
|
|
137
|
+
* `top_provider.context_length` lo que sirve de verdad el proveedor que
|
|
138
|
+
* OpenRouter va a usar. Gana el más PEQUEÑO de los dos: quien trocea para
|
|
139
|
+
* resumir prefiere quedarse corto —más llamadas— a que el proveedor le
|
|
140
|
+
* rechace la petición por pasarse.
|
|
141
|
+
*/
|
|
142
|
+
export declare function ventanaDeContextoDeOpenRouter(modelo: ModeloDeOpenRouter | null | undefined): number | undefined;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* El catálogo VIVO de OpenRouter: la forma de lo que devuelve su API y cómo se
|
|
4
|
+
* convierte en las mismas opciones que ya pintan los desplegables.
|
|
5
|
+
*
|
|
6
|
+
* ## Por qué este proveedor no tiene lista en `llm-models.ts`
|
|
7
|
+
*
|
|
8
|
+
* Porque no es un laboratorio, es un router: revende ~425 modelos de otros
|
|
9
|
+
* detrás de una sola clave, y el conjunto se mueve solo. La lista entera está
|
|
10
|
+
* en `GET https://openrouter.ai/api/v1/models`, que es **abierto y sin clave**
|
|
11
|
+
* —se puede pedir antes de que el usuario haya pegado ninguna— y cada entrada
|
|
12
|
+
* trae su `context_length` y **su propio precio**. Copiar eso a mano a
|
|
13
|
+
* `LLM_MODELS` y a `MODEL_PRICING` sería mantener a mano lo que la API ya da,
|
|
14
|
+
* con 425 oportunidades de que se quede viejo en silencio.
|
|
15
|
+
*
|
|
16
|
+
* ## El reparto, que es lo que hay que entender antes de tocar esto
|
|
17
|
+
*
|
|
18
|
+
* De la MISMA respuesta salen dos cosas, y viven en paquetes distintos porque
|
|
19
|
+
* son de dueños distintos:
|
|
20
|
+
*
|
|
21
|
+
* - **el catálogo** (id, nombre, ventana de contexto) → aquí, porque el
|
|
22
|
+
* catálogo de modelos es de este fichero desde siempre;
|
|
23
|
+
* - **la tarifa** (`pricing`) → `tarifaDeOpenRouter` en
|
|
24
|
+
* `@hostwebhook/platform-contracts`, porque el precio de un token es de
|
|
25
|
+
* ese paquete y no de éste.
|
|
26
|
+
*
|
|
27
|
+
* Y no al revés: este paquete NO puede importar `ModelPricing`
|
|
28
|
+
* —`platform-contracts` depende de éste, no al contrario—, así que el tipo que
|
|
29
|
+
* cruza es el crudo `ModeloDeOpenRouter`. Quien pinte el selector hace UN solo
|
|
30
|
+
* fetch y pasa cada entrada por las dos funciones.
|
|
31
|
+
*
|
|
32
|
+
* ## ⚠️ Esto es una respuesta de red, no un fichero nuestro
|
|
33
|
+
*
|
|
34
|
+
* Todo lo que no sea `id` va opcional a propósito. No porque OpenRouter lo
|
|
35
|
+
* omita hoy, sino porque nada nuestro impide que lo omita mañana, y un campo
|
|
36
|
+
* declarado obligatorio que llega `undefined` no falla al parsear —TypeScript
|
|
37
|
+
* no valida en runtime—: falla más tarde y más lejos, leyendo una propiedad de
|
|
38
|
+
* algo que no está. `id` es la única excepción porque sin él la entrada no
|
|
39
|
+
* identifica a ningún modelo y no hay nada que ofrecer.
|
|
40
|
+
*
|
|
41
|
+
* Verificado contra la respuesta real el 2026-08-31: 425 modelos, los 425 con
|
|
42
|
+
* `pricing.prompt` y `pricing.completion`, y algunos con un
|
|
43
|
+
* `top_provider.context_length` MENOR que su `context_length` anunciado.
|
|
44
|
+
*/
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.URL_DE_MODELOS_DE_OPENROUTER = void 0;
|
|
47
|
+
exports.opcionesDeModelosDeOpenRouter = opcionesDeModelosDeOpenRouter;
|
|
48
|
+
exports.ventanaDeContextoDeOpenRouter = ventanaDeContextoDeOpenRouter;
|
|
49
|
+
/** El endpoint del catálogo. Abierto: no lleva `Authorization`. */
|
|
50
|
+
exports.URL_DE_MODELOS_DE_OPENROUTER = 'https://openrouter.ai/api/v1/models';
|
|
51
|
+
/**
|
|
52
|
+
* Las opciones del desplegable a partir de la respuesta cruda.
|
|
53
|
+
*
|
|
54
|
+
* Devuelve `LlmModelOption`, el MISMO tipo que `LLM_MODELS`, para que el
|
|
55
|
+
* selector no tenga dos formas de modelo según el proveedor: la única
|
|
56
|
+
* diferencia entre un catálogo y el otro es de dónde salió la lista.
|
|
57
|
+
*
|
|
58
|
+
* ⚠️ Ninguna opción sale `recommended`. En los catálogos estáticos esa marca
|
|
59
|
+
* la pone una persona que ha mirado los precios; aquí no hay nadie mirando, y
|
|
60
|
+
* una recomendación automática —«el primero», «el más barato»— sería una
|
|
61
|
+
* decisión de producto tomada por accidente. Sin `recommended`,
|
|
62
|
+
* `getDefaultModel('openrouter')` sigue siendo `''` y elegir es del usuario.
|
|
63
|
+
*
|
|
64
|
+
* Acepta el sobre entero o el array suelto porque quien llama a veces ya lo ha
|
|
65
|
+
* desenvuelto, y tolera basura (`null`, entradas sin `id`) devolviendo lo que
|
|
66
|
+
* sí sirve: un catálogo a medias es utilizable, una excepción a media pantalla
|
|
67
|
+
* no.
|
|
68
|
+
*/
|
|
69
|
+
function opcionesDeModelosDeOpenRouter(respuesta) {
|
|
70
|
+
const modelos = Array.isArray(respuesta) ? respuesta : respuesta?.data;
|
|
71
|
+
if (!Array.isArray(modelos))
|
|
72
|
+
return [];
|
|
73
|
+
const opciones = [];
|
|
74
|
+
for (const modelo of modelos) {
|
|
75
|
+
if (!modelo || typeof modelo.id !== 'string' || modelo.id === '')
|
|
76
|
+
continue;
|
|
77
|
+
opciones.push({
|
|
78
|
+
value: modelo.id,
|
|
79
|
+
label: typeof modelo.name === 'string' && modelo.name !== ''
|
|
80
|
+
? modelo.name
|
|
81
|
+
: modelo.id,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return opciones;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* La ventana de contexto de un modelo de OpenRouter, en tokens, o `undefined`.
|
|
88
|
+
*
|
|
89
|
+
* Aparte y con nombre propio porque hay DOS sitios donde viene y no siempre
|
|
90
|
+
* coinciden: `context_length` es lo que anuncia el modelo, y
|
|
91
|
+
* `top_provider.context_length` lo que sirve de verdad el proveedor que
|
|
92
|
+
* OpenRouter va a usar. Gana el más PEQUEÑO de los dos: quien trocea para
|
|
93
|
+
* resumir prefiere quedarse corto —más llamadas— a que el proveedor le
|
|
94
|
+
* rechace la petición por pasarse.
|
|
95
|
+
*/
|
|
96
|
+
function ventanaDeContextoDeOpenRouter(modelo) {
|
|
97
|
+
const candidatas = [
|
|
98
|
+
modelo?.context_length,
|
|
99
|
+
modelo?.top_provider?.context_length,
|
|
100
|
+
].filter((n) => typeof n === 'number' && Number.isFinite(n) && n > 0);
|
|
101
|
+
if (candidatas.length === 0)
|
|
102
|
+
return undefined;
|
|
103
|
+
return Math.min(...candidatas);
|
|
104
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* publish, scheduled.list, etc.) extend this list — bump the package and
|
|
12
12
|
* re-install in consumers, same pattern as Gmail / Calendar / Discord.
|
|
13
13
|
*/
|
|
14
|
+
import { type CapacidadesPorCredencial } from './capacidad-de-credencial';
|
|
14
15
|
export declare const SLACK_OPERATIONS: readonly ["sendMessage", "updateMessage", "deleteMessage", "sendEphemeral", "scheduleMessage", "getMessage", "listChannels", "getChannelHistory", "getThreadReplies", "createChannel", "inviteToChannel", "addReaction", "removeReaction", "listUsers", "getUserInfo", "uploadFile"];
|
|
15
16
|
export type SlackOperation = (typeof SLACK_OPERATIONS)[number];
|
|
16
17
|
/** Type guard — useful when validating untrusted input (DTOs, AI tool calls). */
|
|
@@ -51,3 +52,30 @@ export interface SlackOperationSpec {
|
|
|
51
52
|
params: SlackParamSpec[];
|
|
52
53
|
}
|
|
53
54
|
export declare const SLACK_OPERATION_SPECS: Record<SlackOperation, SlackOperationSpec>;
|
|
55
|
+
/**
|
|
56
|
+
* Lo que puede hacer una credencial de Slack que NO es OAuth.
|
|
57
|
+
*
|
|
58
|
+
* Medido contra la documentación de Slack, no de memoria:
|
|
59
|
+
* https://docs.slack.dev/messaging/sending-messages-using-incoming-webhooks
|
|
60
|
+
*
|
|
61
|
+
* Es el caso extremo, y conviene que se lea así de crudo: **una** operación de
|
|
62
|
+
* las 16. Un incoming webhook publica y nada más. Textualmente: «Incoming
|
|
63
|
+
* webhooks do not allow you to delete a message after it's been posted», no
|
|
64
|
+
* lee, no sube ficheros, y editar exige `chat.update`, que es token.
|
|
65
|
+
*
|
|
66
|
+
* Y el campo que se cae es el que más duele, porque no parece una restricción
|
|
67
|
+
* hasta que lo es: **`channel` no se puede elegir**. «You cannot override the
|
|
68
|
+
* default channel (chosen by the user who installed your app)». El destino se
|
|
69
|
+
* decide al crear la credencial, así que ofrecer el campo sería ofrecer una
|
|
70
|
+
* pregunta cuya respuesta se ignora — que es peor que no ofrecerla.
|
|
71
|
+
*
|
|
72
|
+
* `text` y `blocks` se quedan (Block Kit está soportado), y `threadTs` también:
|
|
73
|
+
* la doc lo admite si ya tienes el `ts` del padre por otra vía.
|
|
74
|
+
*/
|
|
75
|
+
export declare const SLACK_CAPACIDADES_POR_CREDENCIAL: CapacidadesPorCredencial<SlackOperation>;
|
|
76
|
+
/** Las operaciones que ofrecer para una credencial de Slack. */
|
|
77
|
+
export declare function operacionesDeSlackPara(tipoDeCredencial: string | null | undefined): readonly SlackOperation[];
|
|
78
|
+
/** Si esa credencial puede ejecutar esa operación de Slack. */
|
|
79
|
+
export declare function slackPuedeEjecutar(tipoDeCredencial: string | null | undefined, operacion: SlackOperation): boolean;
|
|
80
|
+
/** Los campos que esa credencial de Slack no deja elegir. */
|
|
81
|
+
export declare function camposDeSlackNoDisponibles(tipoDeCredencial: string | null | undefined): ReadonlySet<string>;
|
package/dist/slack-operations.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SLACK_OPERATION_SPECS = exports.SLACK_OPERATIONS = void 0;
|
|
3
|
+
exports.SLACK_CAPACIDADES_POR_CREDENCIAL = exports.SLACK_OPERATION_SPECS = exports.SLACK_OPERATIONS = void 0;
|
|
4
4
|
exports.isSlackOperation = isSlackOperation;
|
|
5
|
+
exports.operacionesDeSlackPara = operacionesDeSlackPara;
|
|
6
|
+
exports.slackPuedeEjecutar = slackPuedeEjecutar;
|
|
7
|
+
exports.camposDeSlackNoDisponibles = camposDeSlackNoDisponibles;
|
|
5
8
|
/**
|
|
6
9
|
* Slack Web API operation enum — single source of truth across the
|
|
7
10
|
* api, dashboard, and downstream consumers (Message Broker, MCP server).
|
|
@@ -15,6 +18,7 @@ exports.isSlackOperation = isSlackOperation;
|
|
|
15
18
|
* publish, scheduled.list, etc.) extend this list — bump the package and
|
|
16
19
|
* re-install in consumers, same pattern as Gmail / Calendar / Discord.
|
|
17
20
|
*/
|
|
21
|
+
const capacidad_de_credencial_1 = require("./capacidad-de-credencial");
|
|
18
22
|
exports.SLACK_OPERATIONS = [
|
|
19
23
|
// Messages
|
|
20
24
|
'sendMessage',
|
|
@@ -207,3 +211,41 @@ exports.SLACK_OPERATION_SPECS = {
|
|
|
207
211
|
],
|
|
208
212
|
},
|
|
209
213
|
};
|
|
214
|
+
/**
|
|
215
|
+
* Lo que puede hacer una credencial de Slack que NO es OAuth.
|
|
216
|
+
*
|
|
217
|
+
* Medido contra la documentación de Slack, no de memoria:
|
|
218
|
+
* https://docs.slack.dev/messaging/sending-messages-using-incoming-webhooks
|
|
219
|
+
*
|
|
220
|
+
* Es el caso extremo, y conviene que se lea así de crudo: **una** operación de
|
|
221
|
+
* las 16. Un incoming webhook publica y nada más. Textualmente: «Incoming
|
|
222
|
+
* webhooks do not allow you to delete a message after it's been posted», no
|
|
223
|
+
* lee, no sube ficheros, y editar exige `chat.update`, que es token.
|
|
224
|
+
*
|
|
225
|
+
* Y el campo que se cae es el que más duele, porque no parece una restricción
|
|
226
|
+
* hasta que lo es: **`channel` no se puede elegir**. «You cannot override the
|
|
227
|
+
* default channel (chosen by the user who installed your app)». El destino se
|
|
228
|
+
* decide al crear la credencial, así que ofrecer el campo sería ofrecer una
|
|
229
|
+
* pregunta cuya respuesta se ignora — que es peor que no ofrecerla.
|
|
230
|
+
*
|
|
231
|
+
* `text` y `blocks` se quedan (Block Kit está soportado), y `threadTs` también:
|
|
232
|
+
* la doc lo admite si ya tienes el `ts` del padre por otra vía.
|
|
233
|
+
*/
|
|
234
|
+
exports.SLACK_CAPACIDADES_POR_CREDENCIAL = {
|
|
235
|
+
slack_webhook: {
|
|
236
|
+
operaciones: ['sendMessage'],
|
|
237
|
+
camposNoDisponibles: ['channel'],
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
/** Las operaciones que ofrecer para una credencial de Slack. */
|
|
241
|
+
function operacionesDeSlackPara(tipoDeCredencial) {
|
|
242
|
+
return (0, capacidad_de_credencial_1.operacionesPara)(exports.SLACK_OPERATIONS, exports.SLACK_CAPACIDADES_POR_CREDENCIAL, tipoDeCredencial);
|
|
243
|
+
}
|
|
244
|
+
/** Si esa credencial puede ejecutar esa operación de Slack. */
|
|
245
|
+
function slackPuedeEjecutar(tipoDeCredencial, operacion) {
|
|
246
|
+
return (0, capacidad_de_credencial_1.puedeEjecutar)(exports.SLACK_OPERATIONS, exports.SLACK_CAPACIDADES_POR_CREDENCIAL, tipoDeCredencial, operacion);
|
|
247
|
+
}
|
|
248
|
+
/** Los campos que esa credencial de Slack no deja elegir. */
|
|
249
|
+
function camposDeSlackNoDisponibles(tipoDeCredencial) {
|
|
250
|
+
return (0, capacidad_de_credencial_1.camposNoDisponiblesPara)(exports.SLACK_CAPACIDADES_POR_CREDENCIAL, tipoDeCredencial);
|
|
251
|
+
}
|
package/dist/slack-toolkit.d.ts
CHANGED
|
@@ -45,3 +45,16 @@ export interface SlackToolkitSpec {
|
|
|
45
45
|
}
|
|
46
46
|
export declare const SLACK_TOOLKIT_SPECS: SlackToolkitSpec[];
|
|
47
47
|
export declare const SLACK_TOOLKIT_BY_TOOL_NAME: Record<string, SlackToolkitSpec>;
|
|
48
|
+
/**
|
|
49
|
+
* Las herramientas que ofrecerle al modelo con ESTA credencial.
|
|
50
|
+
*
|
|
51
|
+
* Gemelo de `herramientasDeDiscordPara`, y por la misma razón: los dos
|
|
52
|
+
* consumidores —la expansión MCP de la api y el selector del AI Node del
|
|
53
|
+
* dashboard— filtrarían por su cuenta y acabarían discrepando.
|
|
54
|
+
*
|
|
55
|
+
* En Slack el recorte es brutal y conviene verlo escrito: con un webhook el
|
|
56
|
+
* modelo pasa de **16 herramientas a una**, y esa una pierde el `channel`,
|
|
57
|
+
* porque el destino lo fijó quien instaló la credencial. Dejarle el campo sería
|
|
58
|
+
* invitarle a elegir un canal que Slack va a ignorar sin decir nada.
|
|
59
|
+
*/
|
|
60
|
+
export declare function herramientasDeSlackPara(tipoDeCredencial: string | null | undefined): SlackToolkitSpec[];
|
package/dist/slack-toolkit.js
CHANGED
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
*/
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
27
|
exports.SLACK_TOOLKIT_BY_TOOL_NAME = exports.SLACK_TOOLKIT_SPECS = void 0;
|
|
28
|
+
exports.herramientasDeSlackPara = herramientasDeSlackPara;
|
|
29
|
+
const slack_operations_1 = require("./slack-operations");
|
|
28
30
|
const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
|
|
29
31
|
exports.SLACK_TOOLKIT_SPECS = [
|
|
30
32
|
// ── Messages ─────────────────────────────────────────────────────
|
|
@@ -216,3 +218,22 @@ exports.SLACK_TOOLKIT_SPECS = [
|
|
|
216
218
|
},
|
|
217
219
|
];
|
|
218
220
|
exports.SLACK_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(exports.SLACK_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
221
|
+
/**
|
|
222
|
+
* Las herramientas que ofrecerle al modelo con ESTA credencial.
|
|
223
|
+
*
|
|
224
|
+
* Gemelo de `herramientasDeDiscordPara`, y por la misma razón: los dos
|
|
225
|
+
* consumidores —la expansión MCP de la api y el selector del AI Node del
|
|
226
|
+
* dashboard— filtrarían por su cuenta y acabarían discrepando.
|
|
227
|
+
*
|
|
228
|
+
* En Slack el recorte es brutal y conviene verlo escrito: con un webhook el
|
|
229
|
+
* modelo pasa de **16 herramientas a una**, y esa una pierde el `channel`,
|
|
230
|
+
* porque el destino lo fijó quien instaló la credencial. Dejarle el campo sería
|
|
231
|
+
* invitarle a elegir un canal que Slack va a ignorar sin decir nada.
|
|
232
|
+
*/
|
|
233
|
+
function herramientasDeSlackPara(tipoDeCredencial) {
|
|
234
|
+
const permitidas = new Set((0, slack_operations_1.operacionesDeSlackPara)(tipoDeCredencial));
|
|
235
|
+
const fuera = (0, slack_operations_1.camposDeSlackNoDisponibles)(tipoDeCredencial);
|
|
236
|
+
return exports.SLACK_TOOLKIT_SPECS.filter((s) => permitidas.has(s.operation)).map((s) => fuera.size === 0
|
|
237
|
+
? s
|
|
238
|
+
: { ...s, parameters: s.parameters.filter((p) => !fuera.has(p.name)) });
|
|
239
|
+
}
|
package/package.json
CHANGED