@hostwebhook/node-types 1.86.0 → 1.88.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/calendar-toolkit.d.ts +3 -0
- package/dist/calendar-toolkit.js +3 -2
- package/dist/clase-de-herramienta.d.ts +61 -0
- package/dist/clase-de-herramienta.js +153 -0
- package/dist/discord-toolkit.d.ts +2 -3
- package/dist/discord-toolkit.js +3 -6
- package/dist/docs-toolkit.d.ts +2 -1
- package/dist/docs-toolkit.js +3 -6
- package/dist/drive-toolkit.d.ts +9 -4
- package/dist/drive-toolkit.js +3 -4
- package/dist/esm/calendar-toolkit.d.ts +3 -0
- package/dist/esm/calendar-toolkit.js +3 -2
- package/dist/esm/clase-de-herramienta.d.ts +61 -0
- package/dist/esm/clase-de-herramienta.js +148 -0
- package/dist/esm/discord-toolkit.d.ts +2 -3
- package/dist/esm/discord-toolkit.js +3 -6
- package/dist/esm/docs-toolkit.d.ts +2 -1
- package/dist/esm/docs-toolkit.js +3 -6
- package/dist/esm/drive-toolkit.d.ts +9 -4
- package/dist/esm/drive-toolkit.js +3 -4
- package/dist/esm/gmail-operations.d.ts +2 -0
- package/dist/esm/gmail-operations.js +7 -6
- package/dist/esm/google-contacts-toolkit.d.ts +46 -0
- package/dist/esm/google-contacts-toolkit.js +180 -0
- package/dist/esm/index.d.ts +10 -0
- package/dist/esm/index.js +9 -0
- package/dist/esm/mongo-toolkit.d.ts +47 -0
- package/dist/esm/mongo-toolkit.js +98 -0
- package/dist/esm/postgres-toolkit.d.ts +52 -0
- package/dist/esm/postgres-toolkit.js +85 -0
- package/dist/esm/registry.js +10 -0
- package/dist/esm/sheets-toolkit.d.ts +2 -1
- package/dist/esm/sheets-toolkit.js +3 -6
- package/dist/esm/slack-toolkit.d.ts +2 -3
- package/dist/esm/slack-toolkit.js +3 -4
- package/dist/esm/telegram-toolkit.d.ts +3 -0
- package/dist/esm/telegram-toolkit.js +3 -2
- package/dist/esm/toolkits.d.ts +111 -0
- package/dist/esm/toolkits.js +178 -0
- package/dist/gmail-operations.d.ts +2 -0
- package/dist/gmail-operations.js +11 -10
- package/dist/google-contacts-toolkit.d.ts +46 -0
- package/dist/google-contacts-toolkit.js +183 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +32 -1
- package/dist/mongo-toolkit.d.ts +47 -0
- package/dist/mongo-toolkit.js +101 -0
- package/dist/postgres-toolkit.d.ts +52 -0
- package/dist/postgres-toolkit.js +88 -0
- package/dist/registry.js +10 -0
- package/dist/sheets-toolkit.d.ts +2 -1
- package/dist/sheets-toolkit.js +3 -6
- package/dist/slack-toolkit.d.ts +2 -3
- package/dist/slack-toolkit.js +3 -4
- package/dist/telegram-toolkit.d.ts +3 -0
- package/dist/telegram-toolkit.js +3 -2
- package/dist/toolkits.d.ts +111 -0
- package/dist/toolkits.js +190 -0
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgreSQL AI Toolkit — las herramientas que un postgresAction expone cuando
|
|
3
|
+
* `aiEnabled` está encendido.
|
|
4
|
+
*
|
|
5
|
+
* ## Por qué las escrituras NO reciben SQL (2026-09-24, decisión de Ariel)
|
|
6
|
+
*
|
|
7
|
+
* El nodo, en modo de una operación, ejecuta el SQL que se le escribe: sus
|
|
8
|
+
* cinco operaciones son una etiqueta encima del mismo SQL crudo. Si el toolkit
|
|
9
|
+
* hiciera lo mismo, bloquear una herramienta no bloquearía nada — un
|
|
10
|
+
* `insert_rows` puede llevar un `DELETE` dentro de un `WITH`, y quien bloqueó
|
|
11
|
+
* `delete_rows` seguiría viendo desaparecer filas.
|
|
12
|
+
*
|
|
13
|
+
* Así que las tres escrituras reciben la tabla del nodo y JSON, y el SQL lo
|
|
14
|
+
* genera el handler, parametrizado y con los identificadores entrecomillados:
|
|
15
|
+
* el modelo no escribe SQL que se ejecute como escritura.
|
|
16
|
+
*
|
|
17
|
+
* ## Lo que queda con SQL, y cómo se contiene
|
|
18
|
+
*
|
|
19
|
+
* - `query_rows` recibe SQL, y corre dentro de una transacción **READ ONLY**:
|
|
20
|
+
* un `DELETE`, un `UPDATE` o un `CREATE` los rechaza el propio Postgres, no
|
|
21
|
+
* una expresión regular nuestra. Puede leer otras tablas —un JOIN hace
|
|
22
|
+
* falta a menudo—; el límite ahí lo pone el usuario de base de datos de la
|
|
23
|
+
* credencial.
|
|
24
|
+
* - `execute_sql` recibe SQL cualquiera, DDL incluido. Es la excepción
|
|
25
|
+
* consciente a «sólo la tabla del nodo»: SQL crudo no se puede vallar a una
|
|
26
|
+
* tabla. La contienen tres cosas: es siempre destructiva (el gate del AI
|
|
27
|
+
* Node la para si está encendido), se puede bloquear en el nodo, y el
|
|
28
|
+
* usuario de base de datos.
|
|
29
|
+
*
|
|
30
|
+
* Los textos van en inglés porque los lee el modelo.
|
|
31
|
+
*/
|
|
32
|
+
import type { PostgresOperation } from './postgres-operations';
|
|
33
|
+
export interface PostgresToolkitParameter {
|
|
34
|
+
name: string;
|
|
35
|
+
/** El esquema MCP sólo admite estos tres; lo estructurado viaja como JSON
|
|
36
|
+
* en un `string`. */
|
|
37
|
+
type: 'string' | 'number' | 'boolean';
|
|
38
|
+
description: string;
|
|
39
|
+
required: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface PostgresToolkitSpec {
|
|
42
|
+
operation: PostgresOperation;
|
|
43
|
+
label: string;
|
|
44
|
+
toolName: string;
|
|
45
|
+
description: string;
|
|
46
|
+
parameters: PostgresToolkitParameter[];
|
|
47
|
+
/** Pisa o borra. Lo pone `marcarDestructivas`, no se escribe a mano. */
|
|
48
|
+
destructive?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export declare const POSTGRES_TOOLKIT_SPECS: PostgresToolkitSpec[];
|
|
51
|
+
/** Las herramientas por nombre, para despachar una llamada del modelo. */
|
|
52
|
+
export declare const POSTGRES_TOOLKIT_BY_TOOL_NAME: Record<string, PostgresToolkitSpec>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgreSQL AI Toolkit — las herramientas que un postgresAction expone cuando
|
|
3
|
+
* `aiEnabled` está encendido.
|
|
4
|
+
*
|
|
5
|
+
* ## Por qué las escrituras NO reciben SQL (2026-09-24, decisión de Ariel)
|
|
6
|
+
*
|
|
7
|
+
* El nodo, en modo de una operación, ejecuta el SQL que se le escribe: sus
|
|
8
|
+
* cinco operaciones son una etiqueta encima del mismo SQL crudo. Si el toolkit
|
|
9
|
+
* hiciera lo mismo, bloquear una herramienta no bloquearía nada — un
|
|
10
|
+
* `insert_rows` puede llevar un `DELETE` dentro de un `WITH`, y quien bloqueó
|
|
11
|
+
* `delete_rows` seguiría viendo desaparecer filas.
|
|
12
|
+
*
|
|
13
|
+
* Así que las tres escrituras reciben la tabla del nodo y JSON, y el SQL lo
|
|
14
|
+
* genera el handler, parametrizado y con los identificadores entrecomillados:
|
|
15
|
+
* el modelo no escribe SQL que se ejecute como escritura.
|
|
16
|
+
*
|
|
17
|
+
* ## Lo que queda con SQL, y cómo se contiene
|
|
18
|
+
*
|
|
19
|
+
* - `query_rows` recibe SQL, y corre dentro de una transacción **READ ONLY**:
|
|
20
|
+
* un `DELETE`, un `UPDATE` o un `CREATE` los rechaza el propio Postgres, no
|
|
21
|
+
* una expresión regular nuestra. Puede leer otras tablas —un JOIN hace
|
|
22
|
+
* falta a menudo—; el límite ahí lo pone el usuario de base de datos de la
|
|
23
|
+
* credencial.
|
|
24
|
+
* - `execute_sql` recibe SQL cualquiera, DDL incluido. Es la excepción
|
|
25
|
+
* consciente a «sólo la tabla del nodo»: SQL crudo no se puede vallar a una
|
|
26
|
+
* tabla. La contienen tres cosas: es siempre destructiva (el gate del AI
|
|
27
|
+
* Node la para si está encendido), se puede bloquear en el nodo, y el
|
|
28
|
+
* usuario de base de datos.
|
|
29
|
+
*
|
|
30
|
+
* Los textos van en inglés porque los lee el modelo.
|
|
31
|
+
*/
|
|
32
|
+
import { marcarDestructivas } from './clase-de-herramienta.js';
|
|
33
|
+
const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
|
|
34
|
+
const donde = (que) => p('where', `JSON object selecting the rows ${que}: each key is a column and each value the value it must equal, all of them at once, e.g. {"id": 42} or {"status": "pending", "customer_id": 7}. It cannot be empty — an empty condition would touch every row.`);
|
|
35
|
+
const parametros = () => p('params', 'Optional JSON array with the values for the $1, $2… placeholders in the SQL, e.g. ["paid", 100]. Always pass values this way instead of writing them into the SQL.', false);
|
|
36
|
+
export const POSTGRES_TOOLKIT_SPECS = marcarDestructivas([
|
|
37
|
+
{
|
|
38
|
+
operation: 'query',
|
|
39
|
+
label: 'Query rows',
|
|
40
|
+
toolName: 'query_rows',
|
|
41
|
+
description: 'Run a read-only SQL query (SELECT, WITH … SELECT) and return its rows, at most 200. It runs inside a READ ONLY transaction: a statement that writes is rejected by the database. Use it for lookups, counts, sums and joins.',
|
|
42
|
+
parameters: [
|
|
43
|
+
p('sql', 'The SELECT statement, with $1, $2… placeholders for values, e.g. SELECT * FROM orders WHERE status = $1 LIMIT 20.'),
|
|
44
|
+
parametros(),
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
operation: 'insertOne',
|
|
49
|
+
label: 'Insert rows',
|
|
50
|
+
toolName: 'insert_rows',
|
|
51
|
+
description: "Insert one or more rows into this node's table and return them as stored, with the values the database filled in (ids, defaults). It does not check for duplicates.",
|
|
52
|
+
parameters: [
|
|
53
|
+
p('rows', 'JSON object with one row, or a JSON array of rows. Keys are column names, e.g. {"name": "Ariel", "email": "a@b.c"}. A key that is not a column makes the call fail.'),
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
operation: 'update',
|
|
58
|
+
label: 'Update rows',
|
|
59
|
+
toolName: 'update_rows',
|
|
60
|
+
description: "Update the rows of this node's table that match a condition, overwriting the columns you set, and return them after the update. When no row matches it changes nothing.",
|
|
61
|
+
parameters: [
|
|
62
|
+
p('set', 'JSON object with the columns to overwrite and their new values, e.g. {"status": "shipped"}.'),
|
|
63
|
+
donde('to update'),
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
operation: 'delete',
|
|
68
|
+
label: 'Delete rows',
|
|
69
|
+
toolName: 'delete_rows',
|
|
70
|
+
description: "Delete the rows of this node's table that match a condition and return them as they were. This cannot be undone: when you are not sure which rows match, check with query_rows first.",
|
|
71
|
+
parameters: [donde('to delete')],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
operation: 'execute',
|
|
75
|
+
label: 'Execute SQL',
|
|
76
|
+
toolName: 'execute_sql',
|
|
77
|
+
description: 'Run any SQL statement — including ones that change the schema (CREATE, ALTER, DROP) — and return what it produces. It is not limited to this node\'s table. Prefer query_rows, insert_rows, update_rows or delete_rows whenever one of them can do the job.',
|
|
78
|
+
parameters: [
|
|
79
|
+
p('sql', 'The SQL statement, with $1, $2… placeholders for values.'),
|
|
80
|
+
parametros(),
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
]);
|
|
84
|
+
/** Las herramientas por nombre, para despachar una llamada del modelo. */
|
|
85
|
+
export const POSTGRES_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(POSTGRES_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
package/dist/esm/registry.js
CHANGED
|
@@ -401,6 +401,11 @@ export const NODE_REGISTRY = {
|
|
|
401
401
|
allStateKey: "allMongoActions",
|
|
402
402
|
color: "#34d399",
|
|
403
403
|
testable: true,
|
|
404
|
+
/* Modo AI toolkit (2026-09-24): con `aiEnabled` el nodo sólo lo llama un
|
|
405
|
+
AI Node —como el resto de toolkits—, y una arista del lienzo no le
|
|
406
|
+
llevaría nada. Hasta que la api y el dashboard le den `aiEnabled`, el
|
|
407
|
+
campo no existe y esto devuelve `false`: no cambia nada. */
|
|
408
|
+
isToolOnly: (e) => e.aiEnabled === true,
|
|
404
409
|
},
|
|
405
410
|
postgresAction: {
|
|
406
411
|
type: "postgresAction",
|
|
@@ -413,6 +418,11 @@ export const NODE_REGISTRY = {
|
|
|
413
418
|
allStateKey: "allPostgresActions",
|
|
414
419
|
color: "#336791",
|
|
415
420
|
testable: true,
|
|
421
|
+
/* Modo AI toolkit (2026-09-24): con `aiEnabled` el nodo sólo lo llama un
|
|
422
|
+
AI Node —como el resto de toolkits—, y una arista del lienzo no le
|
|
423
|
+
llevaría nada. Hasta que la api y el dashboard le den `aiEnabled`, el
|
|
424
|
+
campo no existe y esto devuelve `false`: no cambia nada. */
|
|
425
|
+
isToolOnly: (e) => e.aiEnabled === true,
|
|
416
426
|
},
|
|
417
427
|
notificationAction: {
|
|
418
428
|
type: "notificationAction",
|
|
@@ -34,7 +34,8 @@ export interface SheetsToolkitSpec {
|
|
|
34
34
|
toolName: string;
|
|
35
35
|
description: string;
|
|
36
36
|
parameters: SheetsToolkitParameter[];
|
|
37
|
-
/**
|
|
37
|
+
/** Pisa o borra. Lo pone `marcarDestructivas` leyendo el verbo del
|
|
38
|
+
* nombre (ver `clase-de-herramienta.ts`), no se escribe a mano. */
|
|
38
39
|
destructive?: boolean;
|
|
39
40
|
}
|
|
40
41
|
export declare const SHEETS_TOOLKIT_SPECS: SheetsToolkitSpec[];
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* pueda usarse sin adaptador. Los textos van en inglés porque los lee el modelo
|
|
20
20
|
* y quien mire la lista de herramientas del servidor MCP.
|
|
21
21
|
*/
|
|
22
|
+
import { marcarDestructivas } from './clase-de-herramienta.js';
|
|
22
23
|
const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
|
|
23
24
|
/*
|
|
24
25
|
* La hoja y la pestaña del nodo van como **defecto**, y el modelo puede
|
|
@@ -41,14 +42,13 @@ const p = (name, description, required = true, type = 'string') => ({ name, type
|
|
|
41
42
|
const hoja = () => p('spreadsheetId', "Id of the Google Sheets document — the long chunk of its URL, between /d/ and /edit.");
|
|
42
43
|
const pestana = () => p('sheetName', 'Name of the tab inside the document, exactly as it reads on its tab strip.');
|
|
43
44
|
const fila = (que) => p('row', `JSON object holding ${que}. Keys are the sheet's **header names**, spelled exactly as they appear in its title row: {"Name": "Ariel", "Email": "a@b.c"}. A key that is not a header makes the call fail, so when you do not know the headers, call get_rows first.`);
|
|
44
|
-
export const SHEETS_TOOLKIT_SPECS = [
|
|
45
|
+
export const SHEETS_TOOLKIT_SPECS = marcarDestructivas([
|
|
45
46
|
{
|
|
46
47
|
operation: 'appendRow',
|
|
47
48
|
label: 'Append row',
|
|
48
49
|
toolName: 'append_row',
|
|
49
50
|
description: 'Add a new row at the bottom of the tab. It does not check whether the row already exists — when it might, use append_or_update_row instead so you do not duplicate it.',
|
|
50
51
|
parameters: [fila('the values of the new row'), hoja(), pestana()],
|
|
51
|
-
destructive: true,
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
operation: 'updateRow',
|
|
@@ -62,7 +62,6 @@ export const SHEETS_TOOLKIT_SPECS = [
|
|
|
62
62
|
hoja(),
|
|
63
63
|
pestana(),
|
|
64
64
|
],
|
|
65
|
-
destructive: true,
|
|
66
65
|
},
|
|
67
66
|
{
|
|
68
67
|
operation: 'appendOrUpdateRow',
|
|
@@ -76,7 +75,6 @@ export const SHEETS_TOOLKIT_SPECS = [
|
|
|
76
75
|
hoja(),
|
|
77
76
|
pestana(),
|
|
78
77
|
],
|
|
79
|
-
destructive: true,
|
|
80
78
|
},
|
|
81
79
|
{
|
|
82
80
|
operation: 'readRange',
|
|
@@ -113,9 +111,8 @@ export const SHEETS_TOOLKIT_SPECS = [
|
|
|
113
111
|
* en el nodo, y la api la aplica.
|
|
114
112
|
*/
|
|
115
113
|
parameters: [p('title', 'Name of the new document.')],
|
|
116
|
-
destructive: true,
|
|
117
114
|
},
|
|
118
|
-
];
|
|
115
|
+
]);
|
|
119
116
|
/** Las herramientas por nombre, para despachar una llamada del modelo. */
|
|
120
117
|
export const SHEETS_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(SHEETS_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
121
118
|
/**
|
|
@@ -38,9 +38,8 @@ export interface SlackToolkitSpec {
|
|
|
38
38
|
/** Descripción (más reglas de uso) que ve el LLM. */
|
|
39
39
|
description: string;
|
|
40
40
|
parameters: SlackToolkitParameter[];
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
* salvo que la llamada traiga confirmación explícita. */
|
|
41
|
+
/** Pisa o borra. Lo pone `marcarDestructivas` leyendo el verbo del
|
|
42
|
+
* nombre (ver `clase-de-herramienta.ts`), no se escribe a mano. */
|
|
44
43
|
destructive?: boolean;
|
|
45
44
|
}
|
|
46
45
|
export declare const SLACK_TOOLKIT_SPECS: SlackToolkitSpec[];
|
|
@@ -23,8 +23,9 @@
|
|
|
23
23
|
* y quien mire la lista de herramientas del servidor MCP.
|
|
24
24
|
*/
|
|
25
25
|
import { camposDeSlackNoDisponibles, operacionesDeSlackPara, } from './slack-operations.js';
|
|
26
|
+
import { marcarDestructivas } from './clase-de-herramienta.js';
|
|
26
27
|
const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
|
|
27
|
-
export const SLACK_TOOLKIT_SPECS = [
|
|
28
|
+
export const SLACK_TOOLKIT_SPECS = marcarDestructivas([
|
|
28
29
|
// ── Messages ─────────────────────────────────────────────────────
|
|
29
30
|
{
|
|
30
31
|
operation: 'sendMessage',
|
|
@@ -63,7 +64,6 @@ export const SLACK_TOOLKIT_SPECS = [
|
|
|
63
64
|
p('channel', 'Channel where the message lives.'),
|
|
64
65
|
p('ts', 'Timestamp of the message to delete.'),
|
|
65
66
|
],
|
|
66
|
-
destructive: true,
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
operation: 'sendEphemeral',
|
|
@@ -142,7 +142,6 @@ export const SLACK_TOOLKIT_SPECS = [
|
|
|
142
142
|
p('name', 'Channel name — lowercase, no spaces, max 80 chars.'),
|
|
143
143
|
p('isPrivate', 'Create a private channel instead of public. Default false.', false, 'boolean'),
|
|
144
144
|
],
|
|
145
|
-
destructive: true,
|
|
146
145
|
},
|
|
147
146
|
{
|
|
148
147
|
operation: 'inviteToChannel',
|
|
@@ -212,7 +211,7 @@ export const SLACK_TOOLKIT_SPECS = [
|
|
|
212
211
|
p('threadTs', 'Thread to attach the file to.', false),
|
|
213
212
|
],
|
|
214
213
|
},
|
|
215
|
-
];
|
|
214
|
+
]);
|
|
216
215
|
export const SLACK_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(SLACK_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
217
216
|
/**
|
|
218
217
|
* Las herramientas que ofrecerle al modelo con ESTA credencial.
|
|
@@ -39,6 +39,9 @@ export interface TelegramToolkitSpec {
|
|
|
39
39
|
/** Descripción (más reglas de uso) que ve el LLM. */
|
|
40
40
|
description: string;
|
|
41
41
|
parameters: TelegramToolkitParameter[];
|
|
42
|
+
/** Pisa o borra. Lo pone `marcarDestructivas` leyendo el verbo del
|
|
43
|
+
* nombre (ver `clase-de-herramienta.ts`), no se escribe a mano. */
|
|
44
|
+
destructive?: boolean;
|
|
42
45
|
/**
|
|
43
46
|
* Encabezado de grupo para la lista de la página de detalle. Las filas
|
|
44
47
|
* consecutivas que comparten grupo se pintan bajo un único título, así que el
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* usarse sin adaptador. Los textos van en inglés porque los lee el modelo y
|
|
20
20
|
* quien mire la lista de herramientas del servidor MCP.
|
|
21
21
|
*/
|
|
22
|
+
import { marcarDestructivas } from './clase-de-herramienta.js';
|
|
22
23
|
const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
|
|
23
24
|
/*
|
|
24
25
|
* `sendAndWaitForResponse` NO está aquí, y es una decisión, no un olvido: la op
|
|
@@ -33,7 +34,7 @@ const p = (name, description, required = true, type = 'string') => ({ name, type
|
|
|
33
34
|
* campo en ninguna de las dos capas, y añadirlo cambiaría cuándo el AI Node pide
|
|
34
35
|
* confirmación. Eso es otra decisión, no parte de mudar el esquema de sitio.
|
|
35
36
|
*/
|
|
36
|
-
export const TELEGRAM_TOOLKIT_SPECS = [
|
|
37
|
+
export const TELEGRAM_TOOLKIT_SPECS = marcarDestructivas([
|
|
37
38
|
{
|
|
38
39
|
operation: 'sendMessage',
|
|
39
40
|
label: 'Send message',
|
|
@@ -178,6 +179,6 @@ export const TELEGRAM_TOOLKIT_SPECS = [
|
|
|
178
179
|
p('showAlert', 'Optional. true = modal alert; false (default) = toast notification.', false, 'boolean'),
|
|
179
180
|
],
|
|
180
181
|
},
|
|
181
|
-
];
|
|
182
|
+
]);
|
|
182
183
|
/** Las herramientas por nombre, para despachar una llamada del modelo. */
|
|
183
184
|
export const TELEGRAM_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(TELEGRAM_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Los toolkits por tipo de nodo: qué herramientas expone cada nodo en modo
|
|
3
|
+
* AI toolkit, en un solo sitio.
|
|
4
|
+
*
|
|
5
|
+
* ## Para qué (2026-09-24)
|
|
6
|
+
*
|
|
7
|
+
* Para que el gate «Block destructive tool calls» del AI Node pueda preguntar
|
|
8
|
+
* por la OPERACIÓN y no sólo por el nombre. Hasta hoy sólo miraba el nombre
|
|
9
|
+
* contra unos patrones (`delete_*`, `drop_*`…), así que `update_row` de Sheets
|
|
10
|
+
* —que pisa una fila— pasaba con el gate encendido. Con esto, la herramienta
|
|
11
|
+
* que el AI Node guardó al conectar (`nodeRefType` + `operationOverride`) se
|
|
12
|
+
* resuelve aquí a su operación, y su `destructive` —que sale del verbo, ver
|
|
13
|
+
* `clase-de-herramienta.ts`— decide.
|
|
14
|
+
*
|
|
15
|
+
* ## Lo que falta aquí, a propósito
|
|
16
|
+
*
|
|
17
|
+
* WhatsApp y Social siguen con sus specs fuera de este paquete (WhatsApp
|
|
18
|
+
* escrito a mano en la api y el dashboard; Social armado por entidad desde el
|
|
19
|
+
* registro de proveedores). Quien consulte este registro tiene que componerlos
|
|
20
|
+
* por su lado — {@link esOperacionDestructiva} devuelve `null` para ellos, que
|
|
21
|
+
* significa «no lo sé», no «no es destructiva». Contacts se mudó el
|
|
22
|
+
* 2026-09-24.
|
|
23
|
+
*
|
|
24
|
+
* ## El bloqueo por nodo y la puerta sin herramienta (2026-09-24)
|
|
25
|
+
*
|
|
26
|
+
* Abajo viven también las dos reglas que se aplican a TODA llamada a un nodo en
|
|
27
|
+
* modo toolkit, en un solo sitio para que la api, hw-nodes, node-sdk y el
|
|
28
|
+
* dashboard pregunten lo mismo:
|
|
29
|
+
*
|
|
30
|
+
* - «Block these tool calls»: el dueño bloquea herramientas en el nodo
|
|
31
|
+
* (`blockedTools`, por nombre). Vale para todo tipo de este registro
|
|
32
|
+
* ({@link admiteBloqueo}).
|
|
33
|
+
* - Sin herramienta no se corre: en modo toolkit un nodo sólo ejecuta la
|
|
34
|
+
* herramienta que le nombran en `operation`. Un evento sin ella —una arista
|
|
35
|
+
* vieja del lienzo— ya no corre la operación de «Single operation», que en
|
|
36
|
+
* ese modo no se ve. Decisión de Ariel para los catorce toolkits
|
|
37
|
+
* ({@link TIPOS_CON_TOOLKIT}), no sólo los de este registro.
|
|
38
|
+
*
|
|
39
|
+
* {@link motivoParaNoCorrer} junta las dos y la llama node-sdk al registrar
|
|
40
|
+
* cada handler, así que cubre todo camino que acabe en `handler.execute`.
|
|
41
|
+
*/
|
|
42
|
+
/** Lo mínimo de una herramienta de toolkit que hace falta para decidir. */
|
|
43
|
+
export interface OperacionDeToolkit {
|
|
44
|
+
operation: string;
|
|
45
|
+
toolName: string;
|
|
46
|
+
label: string;
|
|
47
|
+
destructive?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare const TOOLKITS_POR_TIPO: Readonly<Record<string, readonly OperacionDeToolkit[]>>;
|
|
50
|
+
/**
|
|
51
|
+
* La operación de un toolkit, buscada por su nombre interno (`updateRow`) O
|
|
52
|
+
* por el nombre de su herramienta (`update_row`).
|
|
53
|
+
*
|
|
54
|
+
* Las dos formas porque las dos llegan: el AI Node guarda `operationOverride`
|
|
55
|
+
* con el nombre interno, y el servidor MCP recibe el nombre de la herramienta.
|
|
56
|
+
*/
|
|
57
|
+
export declare function operacionDeToolkit(nodeType: string | undefined | null, operacionONombre: string | undefined | null): OperacionDeToolkit | null;
|
|
58
|
+
/**
|
|
59
|
+
* ¿Es destructiva esta operación de toolkit?
|
|
60
|
+
*
|
|
61
|
+
* `null` cuando no se sabe —el tipo no es un toolkit de este paquete, o la
|
|
62
|
+
* operación no existe en él—. Quien llama decide qué hace con el «no sé»; el
|
|
63
|
+
* gate del AI Node lo combina con los patrones de nombre, que siguen ahí para
|
|
64
|
+
* las herramientas que no son de toolkit (MCP, HTTP…).
|
|
65
|
+
*/
|
|
66
|
+
export declare function esOperacionDestructiva(nodeType: string | undefined | null, operacionONombre: string | undefined | null): boolean | null;
|
|
67
|
+
/**
|
|
68
|
+
* Los tipos con modo AI toolkit de VARIAS herramientas: los de este registro
|
|
69
|
+
* más WhatsApp y Social, cuyas herramientas aún no viven aquí. Es la lista de
|
|
70
|
+
* quién se niega a correr sin herramienta pedida.
|
|
71
|
+
*
|
|
72
|
+
* RSS, Mailchimp o Shopify también tienen `aiEnabled`, pero exponen el nodo
|
|
73
|
+
* como UNA herramienta sin `operation`: no están aquí a propósito.
|
|
74
|
+
*/
|
|
75
|
+
export declare const TIPOS_CON_TOOLKIT: readonly string[];
|
|
76
|
+
export declare function tieneModoToolkit(nodeType: string | undefined | null): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* ¿Admite «Block these tool calls»? Los de este registro: para bloquear hay
|
|
79
|
+
* que saber traducir la operación que guarda el AI Node al nombre de la
|
|
80
|
+
* herramienta que guarda el nodo, y eso sólo se sabe aquí.
|
|
81
|
+
*/
|
|
82
|
+
export declare function admiteBloqueo(nodeType: string | undefined | null): boolean;
|
|
83
|
+
/** Los nombres de herramienta de un toolkit: lo único que `blockedTools` acepta. */
|
|
84
|
+
export declare function nombresDeHerramientas(nodeType: string | undefined | null): string[];
|
|
85
|
+
/** Los nombres bloqueados de un nodo, tolerando documentos sin el campo. */
|
|
86
|
+
export declare function bloqueadasDe(entidad: unknown): string[];
|
|
87
|
+
/**
|
|
88
|
+
* ¿Está bloqueada en este nodo? Acepta la operación (`deleteOne`, lo que guarda
|
|
89
|
+
* el AI Node en `operationOverride`) o el nombre (`delete_document`, lo que
|
|
90
|
+
* recibe el servidor MCP).
|
|
91
|
+
*/
|
|
92
|
+
export declare function herramientaBloqueadaEn(entidad: unknown, nodeType: string | undefined | null, operacionONombre: string | undefined | null): boolean;
|
|
93
|
+
/** Lo que se contesta a una llamada sin herramienta. Lo lee una persona en el
|
|
94
|
+
* historial —una arista vieja— o el modelo, así que dice qué hacer. */
|
|
95
|
+
export declare const MENSAJE_SIN_HERRAMIENTA = "This node is an AI toolkit: it only runs the tool an AI Node or an MCP client names, and this call named none. If a connection in the flow leads here, remove it \u2014 in toolkit mode the node is not part of the pipeline.";
|
|
96
|
+
export declare function mensajeDeHerramientaBloqueada(toolName: string): string;
|
|
97
|
+
/**
|
|
98
|
+
* Por qué una llamada NO debe correr en este nodo, o `null` si puede.
|
|
99
|
+
*
|
|
100
|
+
* Sólo mira nodos en modo toolkit (`aiEnabled` y un tipo de
|
|
101
|
+
* {@link TIPOS_CON_TOOLKIT}); cualquier otro nodo corre como siempre. En modo
|
|
102
|
+
* toolkit:
|
|
103
|
+
* - sin `operation` → {@link MENSAJE_SIN_HERRAMIENTA};
|
|
104
|
+
* - con una herramienta bloqueada en el nodo → su mensaje.
|
|
105
|
+
*
|
|
106
|
+
* Una operación que el registro no conoce NO se rechaza aquí: cada servicio
|
|
107
|
+
* sabe qué operaciones acepta (Mongo y Postgres las validan con más detalle),
|
|
108
|
+
* y rechazar lo desconocido aquí rompería operaciones legítimas que no son
|
|
109
|
+
* herramientas.
|
|
110
|
+
*/
|
|
111
|
+
export declare function motivoParaNoCorrer(nodeType: string | undefined | null, entidad: unknown, payload: unknown): string | null;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Los toolkits por tipo de nodo: qué herramientas expone cada nodo en modo
|
|
3
|
+
* AI toolkit, en un solo sitio.
|
|
4
|
+
*
|
|
5
|
+
* ## Para qué (2026-09-24)
|
|
6
|
+
*
|
|
7
|
+
* Para que el gate «Block destructive tool calls» del AI Node pueda preguntar
|
|
8
|
+
* por la OPERACIÓN y no sólo por el nombre. Hasta hoy sólo miraba el nombre
|
|
9
|
+
* contra unos patrones (`delete_*`, `drop_*`…), así que `update_row` de Sheets
|
|
10
|
+
* —que pisa una fila— pasaba con el gate encendido. Con esto, la herramienta
|
|
11
|
+
* que el AI Node guardó al conectar (`nodeRefType` + `operationOverride`) se
|
|
12
|
+
* resuelve aquí a su operación, y su `destructive` —que sale del verbo, ver
|
|
13
|
+
* `clase-de-herramienta.ts`— decide.
|
|
14
|
+
*
|
|
15
|
+
* ## Lo que falta aquí, a propósito
|
|
16
|
+
*
|
|
17
|
+
* WhatsApp y Social siguen con sus specs fuera de este paquete (WhatsApp
|
|
18
|
+
* escrito a mano en la api y el dashboard; Social armado por entidad desde el
|
|
19
|
+
* registro de proveedores). Quien consulte este registro tiene que componerlos
|
|
20
|
+
* por su lado — {@link esOperacionDestructiva} devuelve `null` para ellos, que
|
|
21
|
+
* significa «no lo sé», no «no es destructiva». Contacts se mudó el
|
|
22
|
+
* 2026-09-24.
|
|
23
|
+
*
|
|
24
|
+
* ## El bloqueo por nodo y la puerta sin herramienta (2026-09-24)
|
|
25
|
+
*
|
|
26
|
+
* Abajo viven también las dos reglas que se aplican a TODA llamada a un nodo en
|
|
27
|
+
* modo toolkit, en un solo sitio para que la api, hw-nodes, node-sdk y el
|
|
28
|
+
* dashboard pregunten lo mismo:
|
|
29
|
+
*
|
|
30
|
+
* - «Block these tool calls»: el dueño bloquea herramientas en el nodo
|
|
31
|
+
* (`blockedTools`, por nombre). Vale para todo tipo de este registro
|
|
32
|
+
* ({@link admiteBloqueo}).
|
|
33
|
+
* - Sin herramienta no se corre: en modo toolkit un nodo sólo ejecuta la
|
|
34
|
+
* herramienta que le nombran en `operation`. Un evento sin ella —una arista
|
|
35
|
+
* vieja del lienzo— ya no corre la operación de «Single operation», que en
|
|
36
|
+
* ese modo no se ve. Decisión de Ariel para los catorce toolkits
|
|
37
|
+
* ({@link TIPOS_CON_TOOLKIT}), no sólo los de este registro.
|
|
38
|
+
*
|
|
39
|
+
* {@link motivoParaNoCorrer} junta las dos y la llama node-sdk al registrar
|
|
40
|
+
* cada handler, así que cubre todo camino que acabe en `handler.execute`.
|
|
41
|
+
*/
|
|
42
|
+
import { GMAIL_ALL_TOOLKIT_SPECS, NATIVE_EMAIL_TOOLKIT_SPECS } from './gmail-operations.js';
|
|
43
|
+
import { GOOGLE_CALENDAR_TOOLKIT_SPECS } from './calendar-toolkit.js';
|
|
44
|
+
import { DRIVE_TOOLKIT_SPECS } from './drive-toolkit.js';
|
|
45
|
+
import { TELEGRAM_TOOLKIT_SPECS } from './telegram-toolkit.js';
|
|
46
|
+
import { DISCORD_TOOLKIT_SPECS } from './discord-toolkit.js';
|
|
47
|
+
import { SLACK_TOOLKIT_SPECS } from './slack-toolkit.js';
|
|
48
|
+
import { SHEETS_TOOLKIT_SPECS } from './sheets-toolkit.js';
|
|
49
|
+
import { DOCS_TOOLKIT_SPECS } from './docs-toolkit.js';
|
|
50
|
+
import { MONGO_TOOLKIT_SPECS } from './mongo-toolkit.js';
|
|
51
|
+
import { POSTGRES_TOOLKIT_SPECS } from './postgres-toolkit.js';
|
|
52
|
+
import { GOOGLE_CONTACTS_TOOLKIT_SPECS } from './google-contacts-toolkit.js';
|
|
53
|
+
export const TOOLKITS_POR_TIPO = Object.freeze({
|
|
54
|
+
gmailAction: GMAIL_ALL_TOOLKIT_SPECS,
|
|
55
|
+
emailAction: NATIVE_EMAIL_TOOLKIT_SPECS,
|
|
56
|
+
calendarAction: GOOGLE_CALENDAR_TOOLKIT_SPECS,
|
|
57
|
+
driveAction: DRIVE_TOOLKIT_SPECS,
|
|
58
|
+
telegramAction: TELEGRAM_TOOLKIT_SPECS,
|
|
59
|
+
discordAction: DISCORD_TOOLKIT_SPECS,
|
|
60
|
+
slackAction: SLACK_TOOLKIT_SPECS,
|
|
61
|
+
sheetsAction: SHEETS_TOOLKIT_SPECS,
|
|
62
|
+
docsAction: DOCS_TOOLKIT_SPECS,
|
|
63
|
+
mongoAction: MONGO_TOOLKIT_SPECS,
|
|
64
|
+
postgresAction: POSTGRES_TOOLKIT_SPECS,
|
|
65
|
+
googleContactsAction: GOOGLE_CONTACTS_TOOLKIT_SPECS,
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* La operación de un toolkit, buscada por su nombre interno (`updateRow`) O
|
|
69
|
+
* por el nombre de su herramienta (`update_row`).
|
|
70
|
+
*
|
|
71
|
+
* Las dos formas porque las dos llegan: el AI Node guarda `operationOverride`
|
|
72
|
+
* con el nombre interno, y el servidor MCP recibe el nombre de la herramienta.
|
|
73
|
+
*/
|
|
74
|
+
export function operacionDeToolkit(nodeType, operacionONombre) {
|
|
75
|
+
if (!nodeType || !operacionONombre)
|
|
76
|
+
return null;
|
|
77
|
+
const toolkit = TOOLKITS_POR_TIPO[nodeType];
|
|
78
|
+
if (!toolkit)
|
|
79
|
+
return null;
|
|
80
|
+
return (toolkit.find((s) => s.operation === operacionONombre) ??
|
|
81
|
+
toolkit.find((s) => s.toolName === operacionONombre) ??
|
|
82
|
+
null);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* ¿Es destructiva esta operación de toolkit?
|
|
86
|
+
*
|
|
87
|
+
* `null` cuando no se sabe —el tipo no es un toolkit de este paquete, o la
|
|
88
|
+
* operación no existe en él—. Quien llama decide qué hace con el «no sé»; el
|
|
89
|
+
* gate del AI Node lo combina con los patrones de nombre, que siguen ahí para
|
|
90
|
+
* las herramientas que no son de toolkit (MCP, HTTP…).
|
|
91
|
+
*/
|
|
92
|
+
export function esOperacionDestructiva(nodeType, operacionONombre) {
|
|
93
|
+
const op = operacionDeToolkit(nodeType, operacionONombre);
|
|
94
|
+
return op ? op.destructive === true : null;
|
|
95
|
+
}
|
|
96
|
+
/* ── Quién tiene toolkit, el bloqueo por nodo y la puerta ───────────────── */
|
|
97
|
+
/**
|
|
98
|
+
* Los tipos con modo AI toolkit de VARIAS herramientas: los de este registro
|
|
99
|
+
* más WhatsApp y Social, cuyas herramientas aún no viven aquí. Es la lista de
|
|
100
|
+
* quién se niega a correr sin herramienta pedida.
|
|
101
|
+
*
|
|
102
|
+
* RSS, Mailchimp o Shopify también tienen `aiEnabled`, pero exponen el nodo
|
|
103
|
+
* como UNA herramienta sin `operation`: no están aquí a propósito.
|
|
104
|
+
*/
|
|
105
|
+
export const TIPOS_CON_TOOLKIT = Object.freeze([
|
|
106
|
+
...Object.keys(TOOLKITS_POR_TIPO),
|
|
107
|
+
'whatsappAction',
|
|
108
|
+
'socialMediaAction',
|
|
109
|
+
]);
|
|
110
|
+
export function tieneModoToolkit(nodeType) {
|
|
111
|
+
return !!nodeType && TIPOS_CON_TOOLKIT.includes(nodeType);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* ¿Admite «Block these tool calls»? Los de este registro: para bloquear hay
|
|
115
|
+
* que saber traducir la operación que guarda el AI Node al nombre de la
|
|
116
|
+
* herramienta que guarda el nodo, y eso sólo se sabe aquí.
|
|
117
|
+
*/
|
|
118
|
+
export function admiteBloqueo(nodeType) {
|
|
119
|
+
return !!nodeType && Object.prototype.hasOwnProperty.call(TOOLKITS_POR_TIPO, nodeType);
|
|
120
|
+
}
|
|
121
|
+
/** Los nombres de herramienta de un toolkit: lo único que `blockedTools` acepta. */
|
|
122
|
+
export function nombresDeHerramientas(nodeType) {
|
|
123
|
+
if (!admiteBloqueo(nodeType))
|
|
124
|
+
return [];
|
|
125
|
+
return TOOLKITS_POR_TIPO[nodeType].map((s) => s.toolName);
|
|
126
|
+
}
|
|
127
|
+
/** Los nombres bloqueados de un nodo, tolerando documentos sin el campo. */
|
|
128
|
+
export function bloqueadasDe(entidad) {
|
|
129
|
+
const lista = entidad?.blockedTools;
|
|
130
|
+
return Array.isArray(lista) ? lista.filter((x) => typeof x === 'string') : [];
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* ¿Está bloqueada en este nodo? Acepta la operación (`deleteOne`, lo que guarda
|
|
134
|
+
* el AI Node en `operationOverride`) o el nombre (`delete_document`, lo que
|
|
135
|
+
* recibe el servidor MCP).
|
|
136
|
+
*/
|
|
137
|
+
export function herramientaBloqueadaEn(entidad, nodeType, operacionONombre) {
|
|
138
|
+
if (!operacionONombre)
|
|
139
|
+
return false;
|
|
140
|
+
const bloqueadas = bloqueadasDe(entidad);
|
|
141
|
+
if (bloqueadas.length === 0)
|
|
142
|
+
return false;
|
|
143
|
+
const op = operacionDeToolkit(nodeType, operacionONombre);
|
|
144
|
+
return bloqueadas.includes(op?.toolName ?? operacionONombre);
|
|
145
|
+
}
|
|
146
|
+
/** Lo que se contesta a una llamada sin herramienta. Lo lee una persona en el
|
|
147
|
+
* historial —una arista vieja— o el modelo, así que dice qué hacer. */
|
|
148
|
+
export const MENSAJE_SIN_HERRAMIENTA = 'This node is an AI toolkit: it only runs the tool an AI Node or an MCP client names, and this call named none. If a connection in the flow leads here, remove it — in toolkit mode the node is not part of the pipeline.';
|
|
149
|
+
export function mensajeDeHerramientaBloqueada(toolName) {
|
|
150
|
+
return `The tool "${toolName}" is blocked on this node by its owner. Do not retry it; tell the user it is not allowed here.`;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Por qué una llamada NO debe correr en este nodo, o `null` si puede.
|
|
154
|
+
*
|
|
155
|
+
* Sólo mira nodos en modo toolkit (`aiEnabled` y un tipo de
|
|
156
|
+
* {@link TIPOS_CON_TOOLKIT}); cualquier otro nodo corre como siempre. En modo
|
|
157
|
+
* toolkit:
|
|
158
|
+
* - sin `operation` → {@link MENSAJE_SIN_HERRAMIENTA};
|
|
159
|
+
* - con una herramienta bloqueada en el nodo → su mensaje.
|
|
160
|
+
*
|
|
161
|
+
* Una operación que el registro no conoce NO se rechaza aquí: cada servicio
|
|
162
|
+
* sabe qué operaciones acepta (Mongo y Postgres las validan con más detalle),
|
|
163
|
+
* y rechazar lo desconocido aquí rompería operaciones legítimas que no son
|
|
164
|
+
* herramientas.
|
|
165
|
+
*/
|
|
166
|
+
export function motivoParaNoCorrer(nodeType, entidad, payload) {
|
|
167
|
+
const e = entidad;
|
|
168
|
+
if (!e || e.aiEnabled !== true || !tieneModoToolkit(nodeType))
|
|
169
|
+
return null;
|
|
170
|
+
const pedida = payload?.operation;
|
|
171
|
+
if (typeof pedida !== 'string' || !pedida.trim())
|
|
172
|
+
return MENSAJE_SIN_HERRAMIENTA;
|
|
173
|
+
if (herramientaBloqueadaEn(entidad, nodeType, pedida)) {
|
|
174
|
+
const op = operacionDeToolkit(nodeType, pedida);
|
|
175
|
+
return mensajeDeHerramientaBloqueada(op?.toolName ?? pedida);
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
@@ -151,6 +151,8 @@ export interface GmailToolkitSpec {
|
|
|
151
151
|
toolName: string;
|
|
152
152
|
description: string;
|
|
153
153
|
parameters: GmailToolkitParameter[];
|
|
154
|
+
/** Pisa o borra. Lo pone `marcarDestructivas` leyendo el verbo del
|
|
155
|
+
* nombre (ver `clase-de-herramienta.ts`), no se escribe a mano. */
|
|
154
156
|
destructive?: boolean;
|
|
155
157
|
}
|
|
156
158
|
export declare const GMAIL_TOOLKIT_SPECS: GmailToolkitSpec[];
|