@hostwebhook/node-types 1.85.0 → 1.87.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/index.d.ts +12 -0
- package/dist/esm/index.js +7 -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/sentiment.d.ts +39 -0
- package/dist/esm/sentiment.js +53 -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 +47 -0
- package/dist/esm/toolkits.js +74 -0
- package/dist/esm/types.d.ts +111 -76
- package/dist/esm/types.js +26 -0
- package/dist/esm/ui.js +10 -1
- package/dist/gmail-operations.d.ts +2 -0
- package/dist/gmail-operations.js +11 -10
- package/dist/index.d.ts +12 -0
- package/dist/index.js +29 -4
- 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/sentiment.d.ts +39 -0
- package/dist/sentiment.js +57 -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 +47 -0
- package/dist/toolkits.js +79 -0
- package/dist/types.d.ts +111 -76
- package/dist/types.js +28 -0
- package/dist/ui.js +10 -1
- package/package.json +1 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentiment analysis en el AI Node — las etiquetas, los puertos y el orden.
|
|
3
|
+
*
|
|
4
|
+
* ## Por qué vive aquí y no en cada repo
|
|
5
|
+
*
|
|
6
|
+
* Las tres etiquetas son a la vez TRES cosas: el `enum` del esquema que se le
|
|
7
|
+
* da al modelo, el nombre de los puertos por los que el nodo despacha, y las
|
|
8
|
+
* pastillas de la tarjeta del lienzo. Si el api, hw-nodes y el dashboard
|
|
9
|
+
* escriben su propia lista, la primera que alguien reordene o rebautice deja
|
|
10
|
+
* una arista apuntando a un puerto que ya no existe — y eso no lo dice ningún
|
|
11
|
+
* compilador. Es el mismo motivo por el que las operaciones de cada nodo
|
|
12
|
+
* viven en este paquete.
|
|
13
|
+
*
|
|
14
|
+
* ## Por qué `unclear` no es una etiqueta más
|
|
15
|
+
*
|
|
16
|
+
* El modelo elige entre las TRES de `SENTIMENT_LABELS`; `unclear` no se le
|
|
17
|
+
* ofrece nunca. Es lo que hace el NODO cuando la confianza queda por debajo
|
|
18
|
+
* del umbral (`sentimentThreshold`) o cuando la respuesta no se puede leer.
|
|
19
|
+
* Ofrecérsela al modelo sería darle una salida cómoda para no mojarse, que es
|
|
20
|
+
* justo lo contrario de lo que se busca al poner un umbral.
|
|
21
|
+
*
|
|
22
|
+
* A diferencia del `other` del clasificador, `unclear` SÍ tiene puerto: el
|
|
23
|
+
* caso de uso es mandar a revisión humana lo que el modelo no ve claro, y sin
|
|
24
|
+
* puerto eso obligaba a adivinar por qué un item no salió por ninguna rama.
|
|
25
|
+
*/
|
|
26
|
+
/** Lo que el modelo puede contestar, en orden de peor a mejor. */
|
|
27
|
+
export const SENTIMENT_LABELS = ['negative', 'neutral', 'positive'];
|
|
28
|
+
/** La salida del nodo cuando no hay etiqueta fiable. No se le ofrece al modelo. */
|
|
29
|
+
export const SENTIMENT_UNCLEAR = 'unclear';
|
|
30
|
+
/** Los cuatro puertos del modo sentiment, en el orden en que se pintan. */
|
|
31
|
+
export const SENTIMENT_PORTS = [
|
|
32
|
+
...SENTIMENT_LABELS,
|
|
33
|
+
SENTIMENT_UNCLEAR,
|
|
34
|
+
];
|
|
35
|
+
/** El nombre que ve la persona, por puerto. */
|
|
36
|
+
export const SENTIMENT_PORT_LABEL = {
|
|
37
|
+
negative: 'Negative',
|
|
38
|
+
neutral: 'Neutral',
|
|
39
|
+
positive: 'Positive',
|
|
40
|
+
unclear: 'Unclear',
|
|
41
|
+
};
|
|
42
|
+
/** Qué significa cada puerto, para el modal de conexión y la doc. */
|
|
43
|
+
export const SENTIMENT_PORT_SUMMARY = {
|
|
44
|
+
negative: 'Complaints, frustration, criticism',
|
|
45
|
+
neutral: 'Factual, mixed, or no clear feeling',
|
|
46
|
+
positive: 'Praise, satisfaction, enthusiasm',
|
|
47
|
+
unclear: 'Below the confidence floor, or unreadable',
|
|
48
|
+
};
|
|
49
|
+
/** ¿Es una de las tres que el modelo puede contestar? */
|
|
50
|
+
export function esEtiquetaDeSentimiento(v) {
|
|
51
|
+
return (typeof v === 'string' &&
|
|
52
|
+
SENTIMENT_LABELS.includes(v));
|
|
53
|
+
}
|
|
@@ -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,47 @@
|
|
|
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 Contacts siguen con sus specs escritos a mano en la api y en el
|
|
18
|
+
* dashboard, no en este paquete. Hasta que se muden, quien consulte este
|
|
19
|
+
* registro tiene que componerlos por su lado — {@link esOperacionDestructiva}
|
|
20
|
+
* devuelve `null` para ellos, que significa «no lo sé», no «no es
|
|
21
|
+
* destructiva».
|
|
22
|
+
*/
|
|
23
|
+
/** Lo mínimo de una herramienta de toolkit que hace falta para decidir. */
|
|
24
|
+
export interface OperacionDeToolkit {
|
|
25
|
+
operation: string;
|
|
26
|
+
toolName: string;
|
|
27
|
+
label: string;
|
|
28
|
+
destructive?: boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare const TOOLKITS_POR_TIPO: Readonly<Record<string, readonly OperacionDeToolkit[]>>;
|
|
31
|
+
/**
|
|
32
|
+
* La operación de un toolkit, buscada por su nombre interno (`updateRow`) O
|
|
33
|
+
* por el nombre de su herramienta (`update_row`).
|
|
34
|
+
*
|
|
35
|
+
* Las dos formas porque las dos llegan: el AI Node guarda `operationOverride`
|
|
36
|
+
* con el nombre interno, y el servidor MCP recibe el nombre de la herramienta.
|
|
37
|
+
*/
|
|
38
|
+
export declare function operacionDeToolkit(nodeType: string | undefined | null, operacionONombre: string | undefined | null): OperacionDeToolkit | null;
|
|
39
|
+
/**
|
|
40
|
+
* ¿Es destructiva esta operación de toolkit?
|
|
41
|
+
*
|
|
42
|
+
* `null` cuando no se sabe —el tipo no es un toolkit de este paquete, o la
|
|
43
|
+
* operación no existe en él—. Quien llama decide qué hace con el «no sé»; el
|
|
44
|
+
* gate del AI Node lo combina con los patrones de nombre, que siguen ahí para
|
|
45
|
+
* las herramientas que no son de toolkit (MCP, HTTP…).
|
|
46
|
+
*/
|
|
47
|
+
export declare function esOperacionDestructiva(nodeType: string | undefined | null, operacionONombre: string | undefined | null): boolean | null;
|
|
@@ -0,0 +1,74 @@
|
|
|
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 Contacts siguen con sus specs escritos a mano en la api y en el
|
|
18
|
+
* dashboard, no en este paquete. Hasta que se muden, quien consulte este
|
|
19
|
+
* registro tiene que componerlos por su lado — {@link esOperacionDestructiva}
|
|
20
|
+
* devuelve `null` para ellos, que significa «no lo sé», no «no es
|
|
21
|
+
* destructiva».
|
|
22
|
+
*/
|
|
23
|
+
import { GMAIL_ALL_TOOLKIT_SPECS, NATIVE_EMAIL_TOOLKIT_SPECS } from './gmail-operations.js';
|
|
24
|
+
import { GOOGLE_CALENDAR_TOOLKIT_SPECS } from './calendar-toolkit.js';
|
|
25
|
+
import { DRIVE_TOOLKIT_SPECS } from './drive-toolkit.js';
|
|
26
|
+
import { TELEGRAM_TOOLKIT_SPECS } from './telegram-toolkit.js';
|
|
27
|
+
import { DISCORD_TOOLKIT_SPECS } from './discord-toolkit.js';
|
|
28
|
+
import { SLACK_TOOLKIT_SPECS } from './slack-toolkit.js';
|
|
29
|
+
import { SHEETS_TOOLKIT_SPECS } from './sheets-toolkit.js';
|
|
30
|
+
import { DOCS_TOOLKIT_SPECS } from './docs-toolkit.js';
|
|
31
|
+
import { MONGO_TOOLKIT_SPECS } from './mongo-toolkit.js';
|
|
32
|
+
import { POSTGRES_TOOLKIT_SPECS } from './postgres-toolkit.js';
|
|
33
|
+
export const TOOLKITS_POR_TIPO = Object.freeze({
|
|
34
|
+
gmailAction: GMAIL_ALL_TOOLKIT_SPECS,
|
|
35
|
+
emailAction: NATIVE_EMAIL_TOOLKIT_SPECS,
|
|
36
|
+
calendarAction: GOOGLE_CALENDAR_TOOLKIT_SPECS,
|
|
37
|
+
driveAction: DRIVE_TOOLKIT_SPECS,
|
|
38
|
+
telegramAction: TELEGRAM_TOOLKIT_SPECS,
|
|
39
|
+
discordAction: DISCORD_TOOLKIT_SPECS,
|
|
40
|
+
slackAction: SLACK_TOOLKIT_SPECS,
|
|
41
|
+
sheetsAction: SHEETS_TOOLKIT_SPECS,
|
|
42
|
+
docsAction: DOCS_TOOLKIT_SPECS,
|
|
43
|
+
mongoAction: MONGO_TOOLKIT_SPECS,
|
|
44
|
+
postgresAction: POSTGRES_TOOLKIT_SPECS,
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* La operación de un toolkit, buscada por su nombre interno (`updateRow`) O
|
|
48
|
+
* por el nombre de su herramienta (`update_row`).
|
|
49
|
+
*
|
|
50
|
+
* Las dos formas porque las dos llegan: el AI Node guarda `operationOverride`
|
|
51
|
+
* con el nombre interno, y el servidor MCP recibe el nombre de la herramienta.
|
|
52
|
+
*/
|
|
53
|
+
export function operacionDeToolkit(nodeType, operacionONombre) {
|
|
54
|
+
if (!nodeType || !operacionONombre)
|
|
55
|
+
return null;
|
|
56
|
+
const toolkit = TOOLKITS_POR_TIPO[nodeType];
|
|
57
|
+
if (!toolkit)
|
|
58
|
+
return null;
|
|
59
|
+
return (toolkit.find((s) => s.operation === operacionONombre) ??
|
|
60
|
+
toolkit.find((s) => s.toolName === operacionONombre) ??
|
|
61
|
+
null);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* ¿Es destructiva esta operación de toolkit?
|
|
65
|
+
*
|
|
66
|
+
* `null` cuando no se sabe —el tipo no es un toolkit de este paquete, o la
|
|
67
|
+
* operación no existe en él—. Quien llama decide qué hace con el «no sé»; el
|
|
68
|
+
* gate del AI Node lo combina con los patrones de nombre, que siguen ahí para
|
|
69
|
+
* las herramientas que no son de toolkit (MCP, HTTP…).
|
|
70
|
+
*/
|
|
71
|
+
export function esOperacionDestructiva(nodeType, operacionONombre) {
|
|
72
|
+
const op = operacionDeToolkit(nodeType, operacionONombre);
|
|
73
|
+
return op ? op.destructive === true : null;
|
|
74
|
+
}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -54,83 +54,15 @@ export interface NodeUIConfig {
|
|
|
54
54
|
connectModal?: 'branch' | 'output-group';
|
|
55
55
|
routerTargetLabel?: string;
|
|
56
56
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
57
|
+
* Los juegos de salidas de un nodo que ramifica: UNO, o VARIOS con su
|
|
58
|
+
* `gate` cada uno [2026-09-22]. Con varios, quien pregunta se queda con
|
|
59
|
+
* el PRIMERO cuya puerta pasa — ver `outputGroupsFor`. El AI Node los
|
|
60
|
+
* necesita porque ramifica de dos maneras según el modo: por las
|
|
61
|
+
* categorías que escribe el usuario (`classifier`) o por los cuatro
|
|
62
|
+
* puertos fijos del análisis de sentimiento (`sentiment`). La forma
|
|
63
|
+
* vieja (un objeto suelto) sigue valiendo y significa «sin alternativas».
|
|
62
64
|
*/
|
|
63
|
-
outputGroups?:
|
|
64
|
-
/** Entity field containing the array of groups (e.g. 'outputs', 'branches') */
|
|
65
|
-
field?: string;
|
|
66
|
-
/** Field within each group for display name (e.g. 'name') */
|
|
67
|
-
nameField?: string;
|
|
68
|
-
/** Field within each group for summary/description (e.g. 'field', 'filterMode') */
|
|
69
|
-
summaryField?: string;
|
|
70
|
-
/**
|
|
71
|
-
* Varios campos del grupo, unidos por espacios, cuando el resumen que
|
|
72
|
-
* de verdad identifica al grupo no cabe en uno solo.
|
|
73
|
-
*
|
|
74
|
-
* Existe por las reglas del router: su condición son TRES campos
|
|
75
|
-
* (`field`, `operator`, `value`) y el modal a medida que se retiró las
|
|
76
|
-
* pintaba juntas — «status eq active». Con un único `summaryField` una
|
|
77
|
-
* regla sin `label` quedaba en «rule 1» y «status», que no dice a qué
|
|
78
|
-
* se está conectando uno.
|
|
79
|
-
*
|
|
80
|
-
* Los campos vacíos se saltan, para que una regla con operador
|
|
81
|
-
* `exists` no salga con un espacio colgando al final.
|
|
82
|
-
*/
|
|
83
|
-
summaryFields?: string[];
|
|
84
|
-
/** Label shown in the modal (e.g. 'output', 'branch') */
|
|
85
|
-
label: string;
|
|
86
|
-
/** Entity field for the fallback/else path (e.g. 'elseOutputNodes') */
|
|
87
|
-
elseField?: string;
|
|
88
|
-
/**
|
|
89
|
-
* Fixed output groups — for nodes with a static set of outputs (e.g. approval: approve/reject).
|
|
90
|
-
* Each entry maps to a top-level entity field that holds outputNodes[].
|
|
91
|
-
* When set, `field`/`nameField` are ignored — modal shows these fixed options.
|
|
92
|
-
*/
|
|
93
|
-
fixedGroups?: Array<{
|
|
94
|
-
name: string;
|
|
95
|
-
field: string;
|
|
96
|
-
}>;
|
|
97
|
-
/**
|
|
98
|
-
* Optional content-aware gate — the output-group modal only opens
|
|
99
|
-
* when `entity[gate.field] === gate.value`. Lets a node opt into
|
|
100
|
-
* multi-branch routing only in some modes (e.g. AI Node in
|
|
101
|
-
* classifier mode) without trapping every connection in the
|
|
102
|
-
* picker the rest of the time. When the gate fails, the
|
|
103
|
-
* FlowCanvas falls through to the universal
|
|
104
|
-
* `entity.outputNodes` connect path.
|
|
105
|
-
*/
|
|
106
|
-
gate?: {
|
|
107
|
-
field: string;
|
|
108
|
-
value: unknown;
|
|
109
|
-
};
|
|
110
|
-
/**
|
|
111
|
-
* Qué es el puerto `main` de este nodo MIENTRAS su contenedor está
|
|
112
|
-
* vacío. Sin esto, conectar a un nodo que ramifica y todavía no tiene
|
|
113
|
-
* ninguna salida escribía una arista en `main` **en silencio**, y el
|
|
114
|
-
* usuario no tenía forma de saber qué había pasado con ella.
|
|
115
|
-
*
|
|
116
|
-
* No hay una respuesta única, y por eso es un dato y no una regla.
|
|
117
|
-
* Medido en `api/src/common/pipeline-run.service.ts`:
|
|
118
|
-
*
|
|
119
|
-
* 'passthrough' — router sin reglas: `rules.length === 0
|
|
120
|
-
* ? refsForPort(entity, MAIN_PORT) : []`. La
|
|
121
|
-
* arista SÍ dispara... hasta que se cree la
|
|
122
|
-
* primera regla, y entonces deja de hacerlo
|
|
123
|
-
* sin avisar.
|
|
124
|
-
* 'never-dispatched' — split: no tiene salida `main`, y el propio
|
|
125
|
-
* despachador registra un warning por cada
|
|
126
|
-
* arista que se quedó en ese puerto.
|
|
127
|
-
*
|
|
128
|
-
* Se declara sólo donde se ha medido. Sin declarar, el lienzo se
|
|
129
|
-
* comporta como siempre: conecta por el camino universal y no dice
|
|
130
|
-
* nada, que es lo que hacía antes de existir este campo.
|
|
131
|
-
*/
|
|
132
|
-
emptyContainerMain?: 'passthrough' | 'never-dispatched';
|
|
133
|
-
};
|
|
65
|
+
outputGroups?: OutputGroupsConfig | OutputGroupsConfig[];
|
|
134
66
|
/**
|
|
135
67
|
* Maps output fields to alternate payload fields on the source entity.
|
|
136
68
|
* When a downstream node is connected via a specific output field,
|
|
@@ -224,3 +156,106 @@ export interface PrefixMapping {
|
|
|
224
156
|
/** Canvas node type used in React Flow nodeTypes map (e.g. "cache-node", "email-action") */
|
|
225
157
|
canvasType: string;
|
|
226
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Un juego de salidas de un nodo que ramifica.
|
|
161
|
+
*
|
|
162
|
+
* Vivía dentro de `NodeUIConfig.special` como un objeto anónimo; sale aquí
|
|
163
|
+
* [2026-09-22] para poder declarar varios por nodo y para que quien los lea
|
|
164
|
+
* nombre el tipo en vez de repetir su forma.
|
|
165
|
+
*/
|
|
166
|
+
export interface OutputGroupsConfig {
|
|
167
|
+
/** Entity field containing the array of groups (e.g. 'outputs', 'branches') */
|
|
168
|
+
field?: string;
|
|
169
|
+
/** Field within each group for display name (e.g. 'name') */
|
|
170
|
+
nameField?: string;
|
|
171
|
+
/** Field within each group for summary/description (e.g. 'field', 'filterMode') */
|
|
172
|
+
summaryField?: string;
|
|
173
|
+
/**
|
|
174
|
+
* Varios campos del grupo, unidos por espacios, cuando el resumen que
|
|
175
|
+
* de verdad identifica al grupo no cabe en uno solo.
|
|
176
|
+
*
|
|
177
|
+
* Existe por las reglas del router: su condición son TRES campos
|
|
178
|
+
* (`field`, `operator`, `value`) y el modal a medida que se retiró las
|
|
179
|
+
* pintaba juntas — «status eq active». Con un único `summaryField` una
|
|
180
|
+
* regla sin `label` quedaba en «rule 1» y «status», que no dice a qué
|
|
181
|
+
* se está conectando uno.
|
|
182
|
+
*
|
|
183
|
+
* Los campos vacíos se saltan, para que una regla con operador
|
|
184
|
+
* `exists` no salga con un espacio colgando al final.
|
|
185
|
+
*/
|
|
186
|
+
summaryFields?: string[];
|
|
187
|
+
/** Label shown in the modal (e.g. 'output', 'branch') */
|
|
188
|
+
label: string;
|
|
189
|
+
/** Entity field for the fallback/else path (e.g. 'elseOutputNodes') */
|
|
190
|
+
elseField?: string;
|
|
191
|
+
/**
|
|
192
|
+
* Fixed output groups — for nodes with a static set of outputs (e.g. approval: approve/reject).
|
|
193
|
+
* When set, `field`/`nameField` are ignored — modal shows these fixed options.
|
|
194
|
+
*
|
|
195
|
+
* Cada entrada nombra su puerto de una de dos formas, y sólo una:
|
|
196
|
+
* · `field` — un campo de primer nivel de los de ANTES de que los puertos
|
|
197
|
+
* existieran (`rejectionOutputNodes` → puerto `rejected`); se traduce
|
|
198
|
+
* con el mapa de campos heredados.
|
|
199
|
+
* · `port` — el puerto, tal cual. Es lo que usan las salidas nacidas ya
|
|
200
|
+
* con puertos (las cuatro de sentiment): inventarles un campo heredado
|
|
201
|
+
* que nunca existió sería mentir en el registro.
|
|
202
|
+
*/
|
|
203
|
+
fixedGroups?: Array<{
|
|
204
|
+
name: string;
|
|
205
|
+
field?: string;
|
|
206
|
+
port?: string;
|
|
207
|
+
/** Una línea de qué entrega ese puerto, para el modal de conexión. */
|
|
208
|
+
summary?: string;
|
|
209
|
+
}>;
|
|
210
|
+
/**
|
|
211
|
+
* Optional content-aware gate — the output-group modal only opens
|
|
212
|
+
* when `entity[gate.field] === gate.value`. Lets a node opt into
|
|
213
|
+
* multi-branch routing only in some modes (e.g. AI Node in
|
|
214
|
+
* classifier mode) without trapping every connection in the
|
|
215
|
+
* picker the rest of the time. When the gate fails, the
|
|
216
|
+
* FlowCanvas falls through to the universal
|
|
217
|
+
* `entity.outputNodes` connect path.
|
|
218
|
+
*/
|
|
219
|
+
gate?: {
|
|
220
|
+
field: string;
|
|
221
|
+
value: unknown;
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* Qué es el puerto `main` de este nodo MIENTRAS su contenedor está
|
|
225
|
+
* vacío. Sin esto, conectar a un nodo que ramifica y todavía no tiene
|
|
226
|
+
* ninguna salida escribía una arista en `main` **en silencio**, y el
|
|
227
|
+
* usuario no tenía forma de saber qué había pasado con ella.
|
|
228
|
+
*
|
|
229
|
+
* No hay una respuesta única, y por eso es un dato y no una regla.
|
|
230
|
+
* Medido en `api/src/common/pipeline-run.service.ts`:
|
|
231
|
+
*
|
|
232
|
+
* 'passthrough' — router sin reglas: `rules.length === 0
|
|
233
|
+
* ? refsForPort(entity, MAIN_PORT) : []`. La
|
|
234
|
+
* arista SÍ dispara... hasta que se cree la
|
|
235
|
+
* primera regla, y entonces deja de hacerlo
|
|
236
|
+
* sin avisar.
|
|
237
|
+
* 'never-dispatched' — split: no tiene salida `main`, y el propio
|
|
238
|
+
* despachador registra un warning por cada
|
|
239
|
+
* arista que se quedó en ese puerto.
|
|
240
|
+
*
|
|
241
|
+
* Se declara sólo donde se ha medido. Sin declarar, el lienzo se
|
|
242
|
+
* comporta como siempre: conecta por el camino universal y no dice
|
|
243
|
+
* nada, que es lo que hacía antes de existir este campo.
|
|
244
|
+
*/
|
|
245
|
+
emptyContainerMain?: 'passthrough' | 'never-dispatched';
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* El juego de salidas que aplica AHORA a esta entidad, o `undefined` si el
|
|
249
|
+
* nodo no ramifica en este momento.
|
|
250
|
+
*
|
|
251
|
+
* Es la única lectura de `special.outputGroups` que entiende las dos formas
|
|
252
|
+
* (uno o varios) y las dos puertas (con `gate` o sin ella). Todo el que
|
|
253
|
+
* pregunte tiene que pasar por aquí: el lienzo, el modal de conexión y el
|
|
254
|
+
* despachador. Escribirlo cada uno a su manera es como el router acabó con un
|
|
255
|
+
* camino propio que nadie arregló al arreglar el de los demás.
|
|
256
|
+
*/
|
|
257
|
+
export declare function outputGroupsFor(config: NodeUIConfig | undefined | null, entity: Record<string, unknown> | undefined | null): OutputGroupsConfig | undefined;
|
|
258
|
+
/** Todos los juegos declarados, pasen o no su puerta. Para quien necesita el
|
|
259
|
+
* UNIVERSO de puertos que un tipo puede emitir (la auditoría de puertos),
|
|
260
|
+
* no el de ahora mismo. */
|
|
261
|
+
export declare function todosLosOutputGroups(config: NodeUIConfig | undefined | null): OutputGroupsConfig[];
|
package/dist/esm/types.js
CHANGED
|
@@ -6,3 +6,29 @@ export function singleMeta() {
|
|
|
6
6
|
export function iterableMeta(field, count) {
|
|
7
7
|
return { iterable: true, iterateField: field, count };
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* El juego de salidas que aplica AHORA a esta entidad, o `undefined` si el
|
|
11
|
+
* nodo no ramifica en este momento.
|
|
12
|
+
*
|
|
13
|
+
* Es la única lectura de `special.outputGroups` que entiende las dos formas
|
|
14
|
+
* (uno o varios) y las dos puertas (con `gate` o sin ella). Todo el que
|
|
15
|
+
* pregunte tiene que pasar por aquí: el lienzo, el modal de conexión y el
|
|
16
|
+
* despachador. Escribirlo cada uno a su manera es como el router acabó con un
|
|
17
|
+
* camino propio que nadie arregló al arreglar el de los demás.
|
|
18
|
+
*/
|
|
19
|
+
export function outputGroupsFor(config, entity) {
|
|
20
|
+
const declarado = config?.special?.outputGroups;
|
|
21
|
+
if (!declarado)
|
|
22
|
+
return undefined;
|
|
23
|
+
const lista = Array.isArray(declarado) ? declarado : [declarado];
|
|
24
|
+
return lista.find((c) => !c.gate || entity?.[c.gate.field] === c.gate.value);
|
|
25
|
+
}
|
|
26
|
+
/** Todos los juegos declarados, pasen o no su puerta. Para quien necesita el
|
|
27
|
+
* UNIVERSO de puertos que un tipo puede emitir (la auditoría de puertos),
|
|
28
|
+
* no el de ahora mismo. */
|
|
29
|
+
export function todosLosOutputGroups(config) {
|
|
30
|
+
const declarado = config?.special?.outputGroups;
|
|
31
|
+
if (!declarado)
|
|
32
|
+
return [];
|
|
33
|
+
return Array.isArray(declarado) ? declarado : [declarado];
|
|
34
|
+
}
|
package/dist/esm/ui.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Dashboard UI config — handle positions, dot visibility, canvas prefixes.
|
|
3
3
|
* Only imported by the Dashboard. Broker and API don't need this.
|
|
4
4
|
*/
|
|
5
|
+
import { SENTIMENT_PORTS, SENTIMENT_PORT_LABEL, SENTIMENT_PORT_SUMMARY, } from './sentiment.js';
|
|
5
6
|
export const NODE_UI = {
|
|
6
7
|
// ── Source nodes ──
|
|
7
8
|
// Una fuente arranca el flujo: `fromNodes: false` significa que nada puede
|
|
@@ -45,7 +46,15 @@ export const NODE_UI = {
|
|
|
45
46
|
// no handle and no route. In any other outputMode the node falls back to
|
|
46
47
|
// the single right-out handle NodeShell renders when no dynamic outputs
|
|
47
48
|
// materialize.
|
|
48
|
-
|
|
49
|
+
// En modo `sentiment` (2026-09-22) el abanico son CUATRO puertos fijos
|
|
50
|
+
// —negative / neutral / positive / unclear— y no un contenedor del usuario:
|
|
51
|
+
// el modelo elige entre las tres primeras y el nodo manda a `unclear` lo que
|
|
52
|
+
// no llega al umbral de confianza. Por eso el AI Node declara DOS juegos de
|
|
53
|
+
// salidas, uno por modo; `outputGroupsFor` elige el que toca.
|
|
54
|
+
ai: { fromNodes: true, toNodes: true, outputHandles: ['right'], special: { loopBackAllowed: true, connectModal: 'output-group', outputGroups: [
|
|
55
|
+
{ field: 'categories', nameField: 'name', summaryField: 'description', label: 'category', gate: { field: 'outputMode', value: 'classifier' } },
|
|
56
|
+
{ label: 'sentiment', gate: { field: 'outputMode', value: 'sentiment' }, fixedGroups: SENTIMENT_PORTS.map((p) => ({ name: SENTIMENT_PORT_LABEL[p], port: p, summary: SENTIMENT_PORT_SUMMARY[p] })) },
|
|
57
|
+
] } },
|
|
49
58
|
markdown: { fromNodes: true, toNodes: true, special: { loopBackAllowed: true } },
|
|
50
59
|
fileTransform: { fromNodes: true, toNodes: true },
|
|
51
60
|
limit: { fromNodes: true, toNodes: true, special: { loopBackAllowed: true } },
|
|
@@ -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[];
|
package/dist/gmail-operations.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
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_ALL_TOOLKIT_SPECS = exports.GMAIL_SEND_AND_WAIT_TOOL_SPEC = exports.GMAIL_TOOLKIT_SPECS = exports.GMAIL_TOOLKIT_OPERATIONS = exports.GMAIL_DROPDOWN_OPERATIONS = exports.GMAIL_OPERATION_SPECS = exports.GMAIL_OPERATION_GROUPS = exports.GMAIL_OPERATIONS = void 0;
|
|
4
|
-
exports.isGmailOperation = isGmailOperation;
|
|
5
|
-
exports.resolveGmailSendFields = resolveGmailSendFields;
|
|
6
2
|
/**
|
|
7
3
|
* Gmail operation enum — single source of truth across the API, Dashboard,
|
|
8
4
|
* and Message Broker. Used by:
|
|
@@ -17,6 +13,11 @@ exports.resolveGmailSendFields = resolveGmailSendFields;
|
|
|
17
13
|
* dashboard owns the UI form schema, the api owns the dispatch logic),
|
|
18
14
|
* but the canonical list of valid operation strings lives here.
|
|
19
15
|
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
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_ALL_TOOLKIT_SPECS = exports.GMAIL_SEND_AND_WAIT_TOOL_SPEC = exports.GMAIL_TOOLKIT_SPECS = exports.GMAIL_TOOLKIT_OPERATIONS = exports.GMAIL_DROPDOWN_OPERATIONS = exports.GMAIL_OPERATION_SPECS = exports.GMAIL_OPERATION_GROUPS = exports.GMAIL_OPERATIONS = void 0;
|
|
18
|
+
exports.isGmailOperation = isGmailOperation;
|
|
19
|
+
exports.resolveGmailSendFields = resolveGmailSendFields;
|
|
20
|
+
const clase_de_herramienta_js_1 = require("./clase-de-herramienta.js");
|
|
20
21
|
exports.GMAIL_OPERATIONS = [
|
|
21
22
|
'send',
|
|
22
23
|
// Pause-the-pipeline op — sends an email with Approve / (optional)
|
|
@@ -301,7 +302,7 @@ const p = (name, description, required = true, type = 'string') => ({ name, type
|
|
|
301
302
|
const ADJUNTOS = p('attachments', 'Optional. Files to attach, taken from the payload: pass the `_file` reference object(s) ' +
|
|
302
303
|
'exactly as they appear (a single `_file`, or the `_files` / `files` array), as a JSON ' +
|
|
303
304
|
'string. Never invent one. Up to 5 files, 25 MB in total.', false);
|
|
304
|
-
exports.GMAIL_TOOLKIT_SPECS = [
|
|
305
|
+
exports.GMAIL_TOOLKIT_SPECS = (0, clase_de_herramienta_js_1.marcarDestructivas)([
|
|
305
306
|
{
|
|
306
307
|
operation: 'send',
|
|
307
308
|
label: 'Send message',
|
|
@@ -510,7 +511,7 @@ exports.GMAIL_TOOLKIT_SPECS = [
|
|
|
510
511
|
p('threadId', 'Gmail thread id.'),
|
|
511
512
|
],
|
|
512
513
|
},
|
|
513
|
-
];
|
|
514
|
+
]);
|
|
514
515
|
/**
|
|
515
516
|
* La op que espera, **fuera** del toolkit y aparte a propósito. Sigue haciendo
|
|
516
517
|
* falta para dos cosas que no son el toolkit: reconocer la operación de una
|
|
@@ -540,12 +541,12 @@ exports.GMAIL_SEND_AND_WAIT_TOOL_SPEC = {
|
|
|
540
541
|
],
|
|
541
542
|
};
|
|
542
543
|
/** Todo lo que el nodo sabe ejecutar, se ofrezca o no como herramienta. */
|
|
543
|
-
exports.GMAIL_ALL_TOOLKIT_SPECS = [
|
|
544
|
+
exports.GMAIL_ALL_TOOLKIT_SPECS = (0, clase_de_herramienta_js_1.marcarDestructivas)([
|
|
544
545
|
...exports.GMAIL_TOOLKIT_SPECS,
|
|
545
546
|
exports.GMAIL_SEND_AND_WAIT_TOOL_SPEC,
|
|
546
|
-
];
|
|
547
|
+
]);
|
|
547
548
|
/** El toolkit del proveedor nativo (Resend): una sola herramienta. */
|
|
548
|
-
exports.NATIVE_EMAIL_TOOLKIT_SPECS = [
|
|
549
|
+
exports.NATIVE_EMAIL_TOOLKIT_SPECS = (0, clase_de_herramienta_js_1.marcarDestructivas)([
|
|
549
550
|
{
|
|
550
551
|
operation: 'send',
|
|
551
552
|
label: 'Send email',
|
|
@@ -564,7 +565,7 @@ exports.NATIVE_EMAIL_TOOLKIT_SPECS = [
|
|
|
564
565
|
p('attachment_file_ids', 'Optional. Comma-separated list of file IDs from `_file.id` refs in the upstream payload (e.g., a File Transform output or a webhook multipart upload). Max 5 files, 30MB total. Do NOT invent IDs — only use values actually present in the current payload.', false),
|
|
565
566
|
],
|
|
566
567
|
},
|
|
567
|
-
];
|
|
568
|
+
]);
|
|
568
569
|
exports.GMAIL_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(exports.GMAIL_ALL_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
569
570
|
exports.NATIVE_EMAIL_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(exports.NATIVE_EMAIL_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
570
571
|
/** Los tres campos que un día vivieron en la raíz. */
|