@hostwebhook/node-types 1.69.0 → 1.70.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 +1 -1
- package/dist/connections.d.ts +1 -1
- package/dist/discord-operations.d.ts +1 -1
- package/dist/discord-operations.js +4 -4
- package/dist/discord-toolkit.d.ts +1 -1
- package/dist/discord-toolkit.js +3 -3
- package/dist/dispatch.d.ts +1 -1
- package/dist/docs-toolkit.d.ts +1 -1
- package/dist/drive-toolkit.d.ts +1 -1
- package/dist/esm/calendar-operations.d.ts +67 -0
- package/dist/esm/calendar-operations.js +176 -0
- package/dist/esm/calendar-toolkit.d.ts +50 -0
- package/dist/esm/calendar-toolkit.js +152 -0
- package/dist/esm/capacidad-de-credencial.d.ts +75 -0
- package/dist/esm/capacidad-de-credencial.js +68 -0
- package/dist/esm/connections.d.ts +17 -0
- package/dist/esm/connections.js +106 -0
- package/dist/esm/credentials.d.ts +144 -0
- package/dist/esm/credentials.js +199 -0
- package/dist/esm/discord-operations.d.ts +104 -0
- package/dist/esm/discord-operations.js +407 -0
- package/dist/esm/discord-toolkit.d.ts +64 -0
- package/dist/esm/discord-toolkit.js +260 -0
- package/dist/esm/dispatch.d.ts +16 -0
- package/dist/esm/dispatch.js +76 -0
- package/dist/esm/docs-operations.d.ts +99 -0
- package/dist/esm/docs-operations.js +127 -0
- package/dist/esm/docs-toolkit.d.ts +42 -0
- package/dist/esm/docs-toolkit.js +97 -0
- package/dist/esm/drive-operations.d.ts +103 -0
- package/dist/esm/drive-operations.js +319 -0
- package/dist/esm/drive-toolkit.d.ts +54 -0
- package/dist/esm/drive-toolkit.js +177 -0
- package/dist/esm/github-operations.d.ts +147 -0
- package/dist/esm/github-operations.js +551 -0
- package/dist/esm/gmail-operations.d.ts +190 -0
- package/dist/esm/gmail-operations.js +560 -0
- package/dist/esm/google-analytics-operations.d.ts +99 -0
- package/dist/esm/google-analytics-operations.js +222 -0
- package/dist/esm/google-contacts-operations.d.ts +93 -0
- package/dist/esm/google-contacts-operations.js +363 -0
- package/dist/esm/index.d.ts +66 -0
- package/dist/esm/index.js +50 -0
- package/dist/esm/jira-operations.d.ts +164 -0
- package/dist/esm/jira-operations.js +470 -0
- package/dist/esm/llm-models.d.ts +101 -0
- package/dist/esm/llm-models.js +230 -0
- package/dist/esm/mailchimp-operations.d.ts +56 -0
- package/dist/esm/mailchimp-operations.js +155 -0
- package/dist/esm/mongo-operations.d.ts +61 -0
- package/dist/esm/mongo-operations.js +120 -0
- package/dist/esm/notion-operations.d.ts +125 -0
- package/dist/esm/notion-operations.js +511 -0
- package/dist/esm/openrouter.d.ts +142 -0
- package/dist/esm/openrouter.js +99 -0
- package/dist/esm/package.json +4 -0
- package/dist/esm/postgres-operations.d.ts +60 -0
- package/dist/esm/postgres-operations.js +75 -0
- package/dist/esm/registry.d.ts +160 -0
- package/dist/esm/registry.js +555 -0
- package/dist/esm/sheets-operations.d.ts +78 -0
- package/dist/esm/sheets-operations.js +150 -0
- package/dist/esm/sheets-toolkit.d.ts +49 -0
- package/dist/esm/sheets-toolkit.js +127 -0
- package/dist/esm/shopify-operations.d.ts +95 -0
- package/dist/esm/shopify-operations.js +259 -0
- package/dist/esm/slack-operations.d.ts +81 -0
- package/dist/esm/slack-operations.js +244 -0
- package/dist/esm/slack-toolkit.d.ts +60 -0
- package/dist/esm/slack-toolkit.js +235 -0
- package/dist/esm/telegram-operations.d.ts +104 -0
- package/dist/esm/telegram-operations.js +351 -0
- package/dist/esm/telegram-toolkit.d.ts +52 -0
- package/dist/esm/telegram-toolkit.js +183 -0
- package/dist/esm/types.d.ts +149 -0
- package/dist/esm/types.js +8 -0
- package/dist/esm/ui.d.ts +13 -0
- package/dist/esm/ui.js +150 -0
- package/dist/esm/whatsapp-operations.d.ts +23 -0
- package/dist/esm/whatsapp-operations.js +36 -0
- package/dist/index.d.ts +66 -66
- package/dist/index.js +185 -185
- package/dist/openrouter.d.ts +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/sheets-toolkit.d.ts +1 -1
- package/dist/slack-operations.d.ts +1 -1
- package/dist/slack-operations.js +4 -4
- package/dist/slack-toolkit.d.ts +1 -1
- package/dist/slack-toolkit.js +3 -3
- package/dist/telegram-toolkit.d.ts +1 -1
- package/dist/ui.d.ts +1 -1
- package/package.json +21 -3
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* El array se generó desde la copia de la api para que las descripciones largas
|
|
29
29
|
* salieran idénticas, no tecleadas.
|
|
30
30
|
*/
|
|
31
|
-
import type { GoogleCalendarOperation } from './calendar-operations';
|
|
31
|
+
import type { GoogleCalendarOperation } from './calendar-operations.js';
|
|
32
32
|
export interface GoogleCalendarToolkitParameter {
|
|
33
33
|
name: string;
|
|
34
34
|
type: 'string' | 'number' | 'boolean';
|
package/dist/connections.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Adding a new node type = add 1 entry here. All repos import from this package.
|
|
8
8
|
*/
|
|
9
|
-
import type { NodeType, NodeConnectionConfig } from './types';
|
|
9
|
+
import type { NodeType, NodeConnectionConfig } from './types.js';
|
|
10
10
|
export declare const NODE_CONNECTIONS: Record<NodeType, NodeConnectionConfig>;
|
|
11
11
|
export declare function canReceiveFrom(targetType: NodeType, sourceType: NodeType): boolean;
|
|
12
12
|
export declare function canReceiveFromNodes(nodeType: NodeType): boolean;
|
|
@@ -17,7 +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
|
+
import { type CapacidadesPorCredencial } from './capacidad-de-credencial.js';
|
|
21
21
|
export declare const DISCORD_OPERATIONS: readonly ["sendMessage", "editMessage", "deleteMessage", "getMessage", "addReaction", "removeReaction", "pinMessage", "createChannel", "editChannel", "deleteChannel", "getChannel", "listChannels", "createThread", "sendDM", "addRole", "removeRole", "getMember"];
|
|
22
22
|
export type DiscordOperation = (typeof DISCORD_OPERATIONS)[number];
|
|
23
23
|
/** Type guard — useful when validating untrusted input (DTOs, tool calls). */
|
|
@@ -24,7 +24,7 @@ exports.camposDeDiscordNoDisponibles = camposDeDiscordNoDisponibles;
|
|
|
24
24
|
* forum-post create) extend this list — bump the package and re-install
|
|
25
25
|
* in consumers, same pattern as Gmail / Calendar / Drive / Telegram.
|
|
26
26
|
*/
|
|
27
|
-
const
|
|
27
|
+
const capacidad_de_credencial_js_1 = require("./capacidad-de-credencial.js");
|
|
28
28
|
exports.DISCORD_OPERATIONS = [
|
|
29
29
|
// Messages
|
|
30
30
|
'sendMessage',
|
|
@@ -402,13 +402,13 @@ exports.DISCORD_CAPACIDADES_POR_CREDENCIAL = {
|
|
|
402
402
|
};
|
|
403
403
|
/** Las operaciones que ofrecer para una credencial de Discord. */
|
|
404
404
|
function operacionesDeDiscordPara(tipoDeCredencial) {
|
|
405
|
-
return (0,
|
|
405
|
+
return (0, capacidad_de_credencial_js_1.operacionesPara)(exports.DISCORD_OPERATIONS, exports.DISCORD_CAPACIDADES_POR_CREDENCIAL, tipoDeCredencial);
|
|
406
406
|
}
|
|
407
407
|
/** Si esa credencial puede ejecutar esa operación de Discord. */
|
|
408
408
|
function discordPuedeEjecutar(tipoDeCredencial, operacion) {
|
|
409
|
-
return (0,
|
|
409
|
+
return (0, capacidad_de_credencial_js_1.puedeEjecutar)(exports.DISCORD_OPERATIONS, exports.DISCORD_CAPACIDADES_POR_CREDENCIAL, tipoDeCredencial, operacion);
|
|
410
410
|
}
|
|
411
411
|
/** Los campos que esa credencial de Discord no deja elegir. */
|
|
412
412
|
function camposDeDiscordNoDisponibles(tipoDeCredencial) {
|
|
413
|
-
return (0,
|
|
413
|
+
return (0, capacidad_de_credencial_js_1.camposNoDisponiblesPara)(exports.DISCORD_CAPACIDADES_POR_CREDENCIAL, tipoDeCredencial);
|
|
414
414
|
}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* pueda usarse sin adaptador. Los textos van en inglés porque los lee el modelo
|
|
23
23
|
* y quien mire la lista de herramientas del servidor MCP.
|
|
24
24
|
*/
|
|
25
|
-
import type { DiscordOperation } from './discord-operations';
|
|
25
|
+
import type { DiscordOperation } from './discord-operations.js';
|
|
26
26
|
export interface DiscordToolkitParameter {
|
|
27
27
|
name: string;
|
|
28
28
|
type: 'string' | 'number' | 'boolean';
|
package/dist/discord-toolkit.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
27
|
exports.DISCORD_TOOLKIT_BY_TOOL_NAME = exports.DISCORD_TOOLKIT_SPECS = void 0;
|
|
28
28
|
exports.herramientasDeDiscordPara = herramientasDeDiscordPara;
|
|
29
|
-
const
|
|
29
|
+
const discord_operations_js_1 = require("./discord-operations.js");
|
|
30
30
|
const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
|
|
31
31
|
exports.DISCORD_TOOLKIT_SPECS = [
|
|
32
32
|
// ── Messages ───────────────────────────────────────────────────
|
|
@@ -252,8 +252,8 @@ exports.DISCORD_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(exports.DISCORD_TOOLKI
|
|
|
252
252
|
* fallar, porque parece que funcionó.
|
|
253
253
|
*/
|
|
254
254
|
function herramientasDeDiscordPara(tipoDeCredencial) {
|
|
255
|
-
const permitidas = new Set((0,
|
|
256
|
-
const fuera = (0,
|
|
255
|
+
const permitidas = new Set((0, discord_operations_js_1.operacionesDeDiscordPara)(tipoDeCredencial));
|
|
256
|
+
const fuera = (0, discord_operations_js_1.camposDeDiscordNoDisponibles)(tipoDeCredencial);
|
|
257
257
|
return exports.DISCORD_TOOLKIT_SPECS.filter((s) => permitidas.has(s.operation)).map((s) =>
|
|
258
258
|
/* Se devuelve una copia sólo cuando hay algo que quitar: así el camino
|
|
259
259
|
normal —el bot, que puede con todo— sigue entregando las MISMAS
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* orphan the node (the symptom Vector Store / AI / Markdown / Code /
|
|
9
9
|
* File Transform all hit before this refactor).
|
|
10
10
|
*/
|
|
11
|
-
import type { NodeType, NodeDispatchConfig } from './types';
|
|
11
|
+
import type { NodeType, NodeDispatchConfig } from './types.js';
|
|
12
12
|
export declare const NODE_DISPATCH: Record<NodeType, NodeDispatchConfig>;
|
|
13
13
|
/** Get all MongoDB collection names for cascade cleanup */
|
|
14
14
|
export declare function getAllNodeCollections(): string[];
|
package/dist/docs-toolkit.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* usarse sin adaptador. Los textos van en inglés porque los lee el modelo y
|
|
14
14
|
* quien mire la lista de herramientas del servidor MCP.
|
|
15
15
|
*/
|
|
16
|
-
import type { DocsOperation } from './docs-operations';
|
|
16
|
+
import type { DocsOperation } from './docs-operations.js';
|
|
17
17
|
export interface DocsToolkitParameter {
|
|
18
18
|
name: string;
|
|
19
19
|
/** El esquema MCP sólo admite estos tres. */
|
package/dist/drive-toolkit.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* herramientas del mismo grupo tienen que ir seguidas. Los tres grupos son los
|
|
20
20
|
* que ya inventaba el JSX que sustituye.
|
|
21
21
|
*/
|
|
22
|
-
import type { DriveOperation } from './drive-operations';
|
|
22
|
+
import type { DriveOperation } from './drive-operations.js';
|
|
23
23
|
export interface DriveToolkitParameter {
|
|
24
24
|
name: string;
|
|
25
25
|
type: 'string' | 'number' | 'boolean';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Calendar operation enum — single source of truth across the API,
|
|
3
|
+
* Dashboard, and Message Broker. Used by:
|
|
4
|
+
* - calendarAction entity / DTO (api): operation field + validation
|
|
5
|
+
* - dashboard CalendarActionGoogleOperation type
|
|
6
|
+
* - broker hostwebhook types + tool schemas
|
|
7
|
+
* - any future calendar-related node
|
|
8
|
+
*
|
|
9
|
+
* Adding a new Calendar operation = add it here, bump this package's
|
|
10
|
+
* version, publish to npm, and re-install in the consuming repos.
|
|
11
|
+
* Each consumer still owns its operation-specific config schema (the
|
|
12
|
+
* dashboard owns the UI form schema, the api owns the dispatch logic),
|
|
13
|
+
* but the canonical list of valid operation strings lives here.
|
|
14
|
+
*/
|
|
15
|
+
export declare const GOOGLE_CALENDAR_OPERATIONS: readonly ["createEvent", "updateEvent", "deleteEvent", "listEvents", "getEvent", "listCalendars", "findFreeSlots", "proposeEvent", "confirmEvent"];
|
|
16
|
+
export type GoogleCalendarOperation = (typeof GOOGLE_CALENDAR_OPERATIONS)[number];
|
|
17
|
+
/** Type guard — useful when validating untrusted input (DTOs, tool calls). */
|
|
18
|
+
export declare function isGoogleCalendarOperation(value: unknown): value is GoogleCalendarOperation;
|
|
19
|
+
export type GoogleCalendarParamTarget = 'eventConfig' | 'listConfig' | 'root';
|
|
20
|
+
export type GoogleCalendarParamType =
|
|
21
|
+
/** Campo de texto con autocompletado de `{{payload.*}}`. */
|
|
22
|
+
'template' | 'number' | 'select'
|
|
23
|
+
/** El `TimezonePicker` que ya existe en el dashboard. */
|
|
24
|
+
| 'timezone';
|
|
25
|
+
export interface GoogleCalendarParamSpec {
|
|
26
|
+
/** La clave DENTRO de `target`. Es la del cable, no un nombre de UI. */
|
|
27
|
+
name: string;
|
|
28
|
+
/** Dónde vive en la entidad. */
|
|
29
|
+
target: GoogleCalendarParamTarget;
|
|
30
|
+
label: string;
|
|
31
|
+
type: GoogleCalendarParamType;
|
|
32
|
+
required?: boolean;
|
|
33
|
+
/** Texto de ayuda. Llano: el paquete no lleva React. */
|
|
34
|
+
description?: string;
|
|
35
|
+
placeholder?: string;
|
|
36
|
+
default?: string | number;
|
|
37
|
+
options?: ReadonlyArray<{
|
|
38
|
+
value: string;
|
|
39
|
+
label: string;
|
|
40
|
+
}>;
|
|
41
|
+
min?: number;
|
|
42
|
+
max?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Cómo se llama esta misma cosa en el `config` que espera el ejecutor
|
|
45
|
+
* compartido (`google-calendar-operations.service.ts`). El ejecutor está
|
|
46
|
+
* escrito para la ruta del toolkit, donde el LLM manda los nombres **sin**
|
|
47
|
+
* sufijo, así que `summaryTemplate` viaja como `summary`. Sólo lo llevan los
|
|
48
|
+
* params de las operaciones que van por ese despachador.
|
|
49
|
+
*/
|
|
50
|
+
execKey?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface GoogleCalendarOperationSpec {
|
|
53
|
+
/** Etiqueta del desplegable, y la misma que pinta el lienzo y el panel. */
|
|
54
|
+
label: string;
|
|
55
|
+
/** Sub-línea del desplegable. */
|
|
56
|
+
description: string;
|
|
57
|
+
/** Método de la API de Google al que corresponde. */
|
|
58
|
+
apiMethod: string;
|
|
59
|
+
/**
|
|
60
|
+
* Si se ejecuta por el despachador genérico (`calendarOps.run`) en vez de por
|
|
61
|
+
* un `case` escrito a mano. Son las cuatro que se abrieron el 2026-08-11.
|
|
62
|
+
*/
|
|
63
|
+
viaExecutor?: boolean;
|
|
64
|
+
/** Orden de pantalla. */
|
|
65
|
+
params: GoogleCalendarParamSpec[];
|
|
66
|
+
}
|
|
67
|
+
export declare const GOOGLE_CALENDAR_OPERATION_SPECS: Record<GoogleCalendarOperation, GoogleCalendarOperationSpec>;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Calendar operation enum — single source of truth across the API,
|
|
3
|
+
* Dashboard, and Message Broker. Used by:
|
|
4
|
+
* - calendarAction entity / DTO (api): operation field + validation
|
|
5
|
+
* - dashboard CalendarActionGoogleOperation type
|
|
6
|
+
* - broker hostwebhook types + tool schemas
|
|
7
|
+
* - any future calendar-related node
|
|
8
|
+
*
|
|
9
|
+
* Adding a new Calendar operation = add it here, bump this package's
|
|
10
|
+
* version, publish to npm, and re-install in the consuming repos.
|
|
11
|
+
* Each consumer still owns its operation-specific config schema (the
|
|
12
|
+
* dashboard owns the UI form schema, the api owns the dispatch logic),
|
|
13
|
+
* but the canonical list of valid operation strings lives here.
|
|
14
|
+
*/
|
|
15
|
+
export const GOOGLE_CALENDAR_OPERATIONS = [
|
|
16
|
+
'createEvent',
|
|
17
|
+
'updateEvent',
|
|
18
|
+
'deleteEvent',
|
|
19
|
+
'listEvents',
|
|
20
|
+
'getEvent',
|
|
21
|
+
/** List all calendars the user can write to. Lets the LLM discover
|
|
22
|
+
* ids before passing `calendarId` to other ops. */
|
|
23
|
+
'listCalendars',
|
|
24
|
+
/** freebusy.query — returns free windows in a date range. Optionally
|
|
25
|
+
* combine across attendees to find common availability. */
|
|
26
|
+
'findFreeSlots',
|
|
27
|
+
/** Create a tentative event (status: tentative, no invites sent). The
|
|
28
|
+
* user sees it greyed out in their calendar; LLM follows up with
|
|
29
|
+
* confirmEvent to promote. Mirrors emailAction's createDraft → sendDraft. */
|
|
30
|
+
'proposeEvent',
|
|
31
|
+
/** Promote a tentative event to confirmed + send invites. Mirrors
|
|
32
|
+
* emailAction's sendDraft. */
|
|
33
|
+
'confirmEvent',
|
|
34
|
+
];
|
|
35
|
+
/** Type guard — useful when validating untrusted input (DTOs, tool calls). */
|
|
36
|
+
export function isGoogleCalendarOperation(value) {
|
|
37
|
+
return (typeof value === 'string' &&
|
|
38
|
+
GOOGLE_CALENDAR_OPERATIONS.includes(value));
|
|
39
|
+
}
|
|
40
|
+
/* Fábricas de los campos que se repiten entre operaciones. */
|
|
41
|
+
const eventIdParam = (label, description) => ({
|
|
42
|
+
name: 'eventIdTemplate',
|
|
43
|
+
target: 'root',
|
|
44
|
+
label,
|
|
45
|
+
type: 'template',
|
|
46
|
+
required: true,
|
|
47
|
+
placeholder: '{{payload.eventId}}',
|
|
48
|
+
description,
|
|
49
|
+
execKey: 'eventId',
|
|
50
|
+
});
|
|
51
|
+
/** Los siete de `eventConfig`, que comparten `createEvent`, `updateEvent` y
|
|
52
|
+
`proposeEvent`. */
|
|
53
|
+
const eventConfigParams = () => [
|
|
54
|
+
{ name: 'summaryTemplate', target: 'eventConfig', label: 'Summary', type: 'template', placeholder: '{{payload.title}}', execKey: 'summary' },
|
|
55
|
+
{ name: 'descriptionTemplate', target: 'eventConfig', label: 'Description', type: 'template', placeholder: 'Event description... (supports {{templates}})', execKey: 'description' },
|
|
56
|
+
{ name: 'locationTemplate', target: 'eventConfig', label: 'Location', type: 'template', placeholder: '{{payload.location}}', execKey: 'location' },
|
|
57
|
+
{ name: 'startTemplate', target: 'eventConfig', label: 'Start Date', type: 'template', placeholder: '{{payload.startTime}}', execKey: 'start' },
|
|
58
|
+
{ name: 'endTemplate', target: 'eventConfig', label: 'End Date', type: 'template', placeholder: '{{payload.endTime}}', execKey: 'end' },
|
|
59
|
+
{
|
|
60
|
+
name: 'attendeesTemplate',
|
|
61
|
+
target: 'eventConfig',
|
|
62
|
+
label: 'Attendees (comma-separated emails)',
|
|
63
|
+
type: 'template',
|
|
64
|
+
placeholder: '{{payload.attendees}}',
|
|
65
|
+
description: 'e.g. user@example.com, other@example.com',
|
|
66
|
+
execKey: 'attendees',
|
|
67
|
+
},
|
|
68
|
+
{ name: 'timeZone', target: 'eventConfig', label: 'Time Zone', type: 'timezone', execKey: 'timeZone' },
|
|
69
|
+
];
|
|
70
|
+
export const GOOGLE_CALENDAR_OPERATION_SPECS = {
|
|
71
|
+
createEvent: {
|
|
72
|
+
label: 'Create Event',
|
|
73
|
+
description: 'Create a new calendar event',
|
|
74
|
+
apiMethod: 'events.insert',
|
|
75
|
+
params: eventConfigParams(),
|
|
76
|
+
},
|
|
77
|
+
updateEvent: {
|
|
78
|
+
label: 'Update Event',
|
|
79
|
+
description: 'Update an existing event by ID',
|
|
80
|
+
apiMethod: 'events.patch',
|
|
81
|
+
params: [
|
|
82
|
+
eventIdParam('Event ID', 'Template to resolve the Google Calendar event ID'),
|
|
83
|
+
...eventConfigParams(),
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
deleteEvent: {
|
|
87
|
+
label: 'Delete Event',
|
|
88
|
+
description: 'Delete an event by ID',
|
|
89
|
+
apiMethod: 'events.delete',
|
|
90
|
+
params: [eventIdParam('Event ID', 'Template to resolve the Google Calendar event ID')],
|
|
91
|
+
},
|
|
92
|
+
listEvents: {
|
|
93
|
+
label: 'List Events',
|
|
94
|
+
description: 'List events in a date range',
|
|
95
|
+
apiMethod: 'events.list',
|
|
96
|
+
params: [
|
|
97
|
+
{ name: 'timeMinTemplate', target: 'listConfig', label: 'Start Date', type: 'template', placeholder: '{{payload.from}}', execKey: 'timeMin' },
|
|
98
|
+
{ name: 'timeMaxTemplate', target: 'listConfig', label: 'End Date', type: 'template', placeholder: '{{payload.to}}', execKey: 'timeMax' },
|
|
99
|
+
{ name: 'maxResults', target: 'listConfig', label: 'Max Results', type: 'number', min: 1, max: 2500, default: 10 },
|
|
100
|
+
{ name: 'query', target: 'listConfig', label: 'Search Query', type: 'template', placeholder: 'meeting' },
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
getEvent: {
|
|
104
|
+
label: 'Get Event',
|
|
105
|
+
description: 'Get a single event by ID',
|
|
106
|
+
apiMethod: 'events.get',
|
|
107
|
+
params: [eventIdParam('Event ID', 'Template to resolve the Google Calendar event ID')],
|
|
108
|
+
},
|
|
109
|
+
/* ── Las cuatro que se abrieron al modo directo el 2026-08-11 ── */
|
|
110
|
+
listCalendars: {
|
|
111
|
+
label: 'List Calendars',
|
|
112
|
+
description: 'List the calendars you can write to (iterable output)',
|
|
113
|
+
apiMethod: 'calendarList.list',
|
|
114
|
+
viaExecutor: true,
|
|
115
|
+
/* Sin campos: no toma nada. Es de descubrimiento, así que en un pipeline
|
|
116
|
+
determinista aporta poco; está por completitud del enum. */
|
|
117
|
+
params: [],
|
|
118
|
+
},
|
|
119
|
+
findFreeSlots: {
|
|
120
|
+
label: 'Find Free Slots',
|
|
121
|
+
description: 'Find open windows in a date range (iterable output)',
|
|
122
|
+
apiMethod: 'freebusy.query',
|
|
123
|
+
viaExecutor: true,
|
|
124
|
+
params: [
|
|
125
|
+
{ name: 'timeMinTemplate', target: 'listConfig', label: 'Window Start', type: 'template', required: true, placeholder: '{{payload.from}}', description: 'ISO 8601. Start of the window to search.', execKey: 'timeMin' },
|
|
126
|
+
{ name: 'timeMaxTemplate', target: 'listConfig', label: 'Window End', type: 'template', required: true, placeholder: '{{payload.to}}', description: 'ISO 8601. End of the window to search.', execKey: 'timeMax' },
|
|
127
|
+
{ name: 'durationMinutes', target: 'listConfig', label: 'Slot Length (minutes)', type: 'number', min: 15, max: 480, default: 30, description: 'Only windows at least this long are returned.', execKey: 'durationMinutes' },
|
|
128
|
+
{ name: 'calendarIds', target: 'listConfig', label: 'Extra Calendars (comma-separated ids)', type: 'template', placeholder: 'primary, team@example.com', description: 'Combine availability across these. Empty = just the calendar configured above.', execKey: 'calendarIds' },
|
|
129
|
+
{ name: 'timeZone', target: 'listConfig', label: 'Time Zone', type: 'timezone', description: 'IANA zone used to read the window bounds.', execKey: 'timeZone' },
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
proposeEvent: {
|
|
133
|
+
label: 'Propose Event (tentative)',
|
|
134
|
+
description: 'Create a tentative event — no invites sent',
|
|
135
|
+
apiMethod: 'events.insert (status: tentative)',
|
|
136
|
+
viaExecutor: true,
|
|
137
|
+
params: [
|
|
138
|
+
...eventConfigParams(),
|
|
139
|
+
/* `recurrence` sólo entra aquí, que va por el ejecutor. `createEvent` y
|
|
140
|
+
`updateEvent` siguen sin él porque su ruta es el `buildEventBody`
|
|
141
|
+
escrito a mano del servicio: es una asimetría entre modos que ya
|
|
142
|
+
existía y que esto no crea ni arregla. */
|
|
143
|
+
{
|
|
144
|
+
name: 'recurrenceTemplate',
|
|
145
|
+
target: 'eventConfig',
|
|
146
|
+
label: 'Recurrence (RRULE)',
|
|
147
|
+
type: 'template',
|
|
148
|
+
placeholder: 'RRULE:FREQ=WEEKLY;BYDAY=MO',
|
|
149
|
+
description: 'One RFC 5545 rule. Empty = a one-off event.',
|
|
150
|
+
execKey: 'recurrence',
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
confirmEvent: {
|
|
155
|
+
label: 'Confirm Proposed Event',
|
|
156
|
+
description: 'Promote a tentative event and send invites',
|
|
157
|
+
apiMethod: 'events.patch (status: confirmed)',
|
|
158
|
+
viaExecutor: true,
|
|
159
|
+
params: [
|
|
160
|
+
eventIdParam('Proposal ID', 'The proposalId a Propose Event run returned. Normally {{payload.proposalId}} from an upstream node — this op is meant to sit downstream of a Propose Event.'),
|
|
161
|
+
{
|
|
162
|
+
name: 'sendUpdates',
|
|
163
|
+
target: 'root',
|
|
164
|
+
label: 'Invite Policy',
|
|
165
|
+
type: 'select',
|
|
166
|
+
default: 'all',
|
|
167
|
+
options: [
|
|
168
|
+
{ value: 'all', label: 'All attendees' },
|
|
169
|
+
{ value: 'externalOnly', label: 'External attendees only' },
|
|
170
|
+
{ value: 'none', label: "Don't send invites" },
|
|
171
|
+
],
|
|
172
|
+
execKey: 'sendUpdates',
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar AI Toolkit — las nueve herramientas que un calendarAction expone
|
|
3
|
+
* cuando `aiEnabled` está encendido.
|
|
4
|
+
*
|
|
5
|
+
* **Se escribe una sola vez.** Antes vivía dos veces —aquí y en
|
|
6
|
+
* `api/src/mcp-servers/toolkit-specs.ts`— y las dos copias YA habían derivado:
|
|
7
|
+
* las **siete** operaciones que aceptan `calendarId` describían el parámetro de
|
|
8
|
+
* dos maneras distintas. Gana la de la api, que es la única que dice cuál es el
|
|
9
|
+
* defecto:
|
|
10
|
+
*
|
|
11
|
+
* api "Optional calendar id. Defaults to the configured calendar
|
|
12
|
+
* (usually 'primary'). Use list_my_calendars to discover ids."
|
|
13
|
+
* dashboard "Optional override of the configured calendar. Use
|
|
14
|
+
* list_my_calendars first to discover ids when the user
|
|
15
|
+
* mentions a non-default calendar."
|
|
16
|
+
*
|
|
17
|
+
* Esa deriva estaba en la descripción de un PARÁMETRO, así que el conteo de la
|
|
18
|
+
* auditoría del 2026-08-10 no la veía y daba Calendar por limpio. Con las
|
|
19
|
+
* descripciones de parámetro incluidas, la deriva real de los ocho toolkits
|
|
20
|
+
* duplicados eran 32 y no 18.
|
|
21
|
+
*
|
|
22
|
+
* Dos cosas que **no** se añaden, a propósito:
|
|
23
|
+
* - `group`: Calendar nunca tuvo cabeceras de grupo en su lista, y meterlas
|
|
24
|
+
* es estructura visible nueva.
|
|
25
|
+
* - `destructive` en `delete_calendar_event`: cambiaría el comportamiento de
|
|
26
|
+
* `requireConfirmationForDestructive`. Mismo criterio que en Telegram.
|
|
27
|
+
*
|
|
28
|
+
* El array se generó desde la copia de la api para que las descripciones largas
|
|
29
|
+
* salieran idénticas, no tecleadas.
|
|
30
|
+
*/
|
|
31
|
+
import type { GoogleCalendarOperation } from './calendar-operations.js';
|
|
32
|
+
export interface GoogleCalendarToolkitParameter {
|
|
33
|
+
name: string;
|
|
34
|
+
type: 'string' | 'number' | 'boolean';
|
|
35
|
+
description: string;
|
|
36
|
+
required: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface GoogleCalendarToolkitSpec {
|
|
39
|
+
operation: GoogleCalendarOperation;
|
|
40
|
+
/** Etiqueta corta de la fila en la lista de herramientas. */
|
|
41
|
+
label: string;
|
|
42
|
+
/** El nombre con el que el LLM llama a la herramienta. */
|
|
43
|
+
toolName: string;
|
|
44
|
+
/** Descripción y reglas de uso que ve el LLM. */
|
|
45
|
+
description: string;
|
|
46
|
+
parameters: GoogleCalendarToolkitParameter[];
|
|
47
|
+
}
|
|
48
|
+
export declare const GOOGLE_CALENDAR_TOOLKIT_SPECS: GoogleCalendarToolkitSpec[];
|
|
49
|
+
/** Índice por nombre de herramienta, para enrutar un `tools/call` sin recorrer. */
|
|
50
|
+
export declare const GOOGLE_CALENDAR_TOOLKIT_BY_TOOL_NAME: Record<string, GoogleCalendarToolkitSpec>;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar AI Toolkit — las nueve herramientas que un calendarAction expone
|
|
3
|
+
* cuando `aiEnabled` está encendido.
|
|
4
|
+
*
|
|
5
|
+
* **Se escribe una sola vez.** Antes vivía dos veces —aquí y en
|
|
6
|
+
* `api/src/mcp-servers/toolkit-specs.ts`— y las dos copias YA habían derivado:
|
|
7
|
+
* las **siete** operaciones que aceptan `calendarId` describían el parámetro de
|
|
8
|
+
* dos maneras distintas. Gana la de la api, que es la única que dice cuál es el
|
|
9
|
+
* defecto:
|
|
10
|
+
*
|
|
11
|
+
* api "Optional calendar id. Defaults to the configured calendar
|
|
12
|
+
* (usually 'primary'). Use list_my_calendars to discover ids."
|
|
13
|
+
* dashboard "Optional override of the configured calendar. Use
|
|
14
|
+
* list_my_calendars first to discover ids when the user
|
|
15
|
+
* mentions a non-default calendar."
|
|
16
|
+
*
|
|
17
|
+
* Esa deriva estaba en la descripción de un PARÁMETRO, así que el conteo de la
|
|
18
|
+
* auditoría del 2026-08-10 no la veía y daba Calendar por limpio. Con las
|
|
19
|
+
* descripciones de parámetro incluidas, la deriva real de los ocho toolkits
|
|
20
|
+
* duplicados eran 32 y no 18.
|
|
21
|
+
*
|
|
22
|
+
* Dos cosas que **no** se añaden, a propósito:
|
|
23
|
+
* - `group`: Calendar nunca tuvo cabeceras de grupo en su lista, y meterlas
|
|
24
|
+
* es estructura visible nueva.
|
|
25
|
+
* - `destructive` en `delete_calendar_event`: cambiaría el comportamiento de
|
|
26
|
+
* `requireConfirmationForDestructive`. Mismo criterio que en Telegram.
|
|
27
|
+
*
|
|
28
|
+
* El array se generó desde la copia de la api para que las descripciones largas
|
|
29
|
+
* salieran idénticas, no tecleadas.
|
|
30
|
+
*/
|
|
31
|
+
const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
|
|
32
|
+
export const GOOGLE_CALENDAR_TOOLKIT_SPECS = [
|
|
33
|
+
{
|
|
34
|
+
operation: "createEvent",
|
|
35
|
+
label: "Create event",
|
|
36
|
+
toolName: "create_calendar_event",
|
|
37
|
+
description: "Create a new event on the user's calendar. USAGE RULES: (1) Always include start AND end (ISO 8601 datetime or YYYY-MM-DD for all-day). (2) For ALL-DAY events the `end` date is EXCLUSIVE — to cover Apr 19+20 send start=2026-04-19 end=2026-04-21. A single-day all-day event needs end = start + 1 day. (3) Confirm date + time + timezone in your reply (the user lives in Mexico City UTC-6 unless told otherwise). (4) Compose the summary fresh from the user's CURRENT request — never reuse content recalled from memory unless the user explicitly references it. (5) For events with external attendees or significant impact, prefer propose_calendar_event (tentative, no invites) so the user can preview before invites go out.",
|
|
38
|
+
parameters: [
|
|
39
|
+
p("summary", "Short event title.", true),
|
|
40
|
+
p("start", "Event start. ISO 8601 datetime (e.g. 2026-04-19T15:00:00) or date (YYYY-MM-DD) for all-day.", true),
|
|
41
|
+
p("end", "Event end. Same format as start. For all-day events this is EXCLUSIVE: an event that covers Apr 19+20 needs end=2026-04-21.", true),
|
|
42
|
+
p("description", "Optional longer description.", false),
|
|
43
|
+
p("location", "Optional physical or virtual location.", false),
|
|
44
|
+
p("attendees", "Comma-separated emails to invite.", false),
|
|
45
|
+
p("timeZone", "IANA timezone (e.g. America/Mexico_City). Defaults to UTC.", false),
|
|
46
|
+
p("recurrence", "Optional RFC 5545 RRULE string for repeating events (e.g. \"RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10\"). Daily=\"RRULE:FREQ=DAILY\"; weekly Mon=\"RRULE:FREQ=WEEKLY;BYDAY=MO\"; monthly first=\"RRULE:FREQ=MONTHLY;BYDAY=1MO\". Confirm the recurrence pattern in your reply.", false),
|
|
47
|
+
p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
operation: "updateEvent",
|
|
52
|
+
label: "Update event",
|
|
53
|
+
toolName: "update_calendar_event",
|
|
54
|
+
description: "Update an existing event by id. Only fields you provide are changed (PATCH semantics). USAGE RULES: (1) Use eventId from a getEvent / listEvents call earlier in THIS conversation, never from memory. (2) When changing time, confirm the new time + timezone in your reply. (3) EXTENDING an all-day event across more days: send the new `end` as the day AFTER the last day (Google's all-day end is EXCLUSIVE). To make an event cover Apr 19+20, set end=2026-04-21. (4) When you change one of start/end on an all-day event, send BOTH so the new range is unambiguous (otherwise PATCH may leave a stale boundary).",
|
|
55
|
+
parameters: [
|
|
56
|
+
p("eventId", "Event id from listEvents / getEvent in THIS conversation.", true),
|
|
57
|
+
p("summary", "Optional new title.", false),
|
|
58
|
+
p("start", "Optional new start. For all-day events use YYYY-MM-DD.", false),
|
|
59
|
+
p("end", "Optional new end. For all-day events this is EXCLUSIVE: to cover through Apr 20 send end=2026-04-21.", false),
|
|
60
|
+
p("description", "Optional new description.", false),
|
|
61
|
+
p("location", "Optional new location.", false),
|
|
62
|
+
p("attendees", "Optional new attendee list (REPLACES existing).", false),
|
|
63
|
+
p("timeZone", "Optional timezone.", false),
|
|
64
|
+
p("recurrence", "Optional RFC 5545 RRULE string for repeating events (e.g. \"RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10\"). Daily=\"RRULE:FREQ=DAILY\"; weekly Mon=\"RRULE:FREQ=WEEKLY;BYDAY=MO\"; monthly first=\"RRULE:FREQ=MONTHLY;BYDAY=1MO\". Confirm the recurrence pattern in your reply.", false),
|
|
65
|
+
p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
operation: "deleteEvent",
|
|
70
|
+
label: "Delete event",
|
|
71
|
+
toolName: "delete_calendar_event",
|
|
72
|
+
description: "Permanently delete an event. USAGE RULES: (1) ALWAYS confirm with the user before calling this — calendar deletes are silent and irreversible. (2) Use eventId from a tool call earlier in THIS conversation.",
|
|
73
|
+
parameters: [
|
|
74
|
+
p("eventId", "Event id to delete.", true),
|
|
75
|
+
p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
operation: "listEvents",
|
|
80
|
+
label: "List events",
|
|
81
|
+
toolName: "list_calendar_events",
|
|
82
|
+
description: "Search the user's calendar. Returns headers (summary, start, end, attendees) per match. USAGE RULES: (1) Default to next 7 days when the user doesn't specify a window. (2) Use ISO datetimes for timeMin / timeMax. (3) For full event details (description, location), call getEvent with the specific id.",
|
|
83
|
+
parameters: [
|
|
84
|
+
p("timeMin", "Start of window (ISO 8601). Defaults to now.", false),
|
|
85
|
+
p("timeMax", "End of window (ISO 8601). Defaults to 7 days from now.", false),
|
|
86
|
+
p("maxResults", "Default 25, max 250.", false, "number"),
|
|
87
|
+
p("query", "Free-text search across summary/description/attendees.", false),
|
|
88
|
+
p("timeZone", "IANA timezone for parsing timeMin/timeMax.", false),
|
|
89
|
+
p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
operation: "getEvent",
|
|
94
|
+
label: "Get event",
|
|
95
|
+
toolName: "get_calendar_event",
|
|
96
|
+
description: "Fetch a single event by id. Returns full details including description, attendees, organizer, recurrence.",
|
|
97
|
+
parameters: [
|
|
98
|
+
p("eventId", "Event id to fetch.", true),
|
|
99
|
+
p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
operation: "listCalendars",
|
|
104
|
+
label: "List my calendars",
|
|
105
|
+
toolName: "list_my_calendars",
|
|
106
|
+
description: "Return all calendars the user can write to (primary + shared + secondary). USAGE RULES: (1) Call this when the user mentions a non-default calendar by name (e.g. 'add this to my Work calendar') and you don't yet know its id. (2) After listing, pass the matching `id` as `calendarId` on subsequent ops to target that calendar.",
|
|
107
|
+
parameters: [],
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
operation: "findFreeSlots",
|
|
111
|
+
label: "Find free slots",
|
|
112
|
+
toolName: "find_calendar_free_slots",
|
|
113
|
+
description: "Return open windows in a date range across one or more calendars. USAGE RULES: (1) Call this BEFORE proposing / creating an event when the user asks 'when am I free' or wants you to pick a time. (2) Default window: next 7 days, business hours 8am-6pm in the user's timezone. (3) Suggest the top 2-3 slots in your reply, then ask which they prefer.",
|
|
114
|
+
parameters: [
|
|
115
|
+
p("timeMin", "Start of window (ISO 8601).", true),
|
|
116
|
+
p("timeMax", "End of window (ISO 8601).", true),
|
|
117
|
+
p("durationMinutes", "Required slot length in minutes. Default 30, min 15, max 480.", false, "number"),
|
|
118
|
+
p("calendarIds", "Comma-separated calendar ids to combine availability across. Defaults to the configured calendar.", false),
|
|
119
|
+
p("timeZone", "IANA timezone for parsing timeMin/timeMax.", false),
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
operation: "proposeEvent",
|
|
124
|
+
label: "Propose event (tentative)",
|
|
125
|
+
toolName: "propose_calendar_event",
|
|
126
|
+
description: "Create a TENTATIVE event (status: tentative, NO invites sent). The user sees it greyed out in their calendar. USAGE RULES: (1) Use this instead of create_calendar_event for events with external attendees or significant impact — the user previews before invites fire. (2) Show the proposalId in your reply ('I drafted: <details>. Confirm with proposalId X to send invites.'). (3) After the user confirms, call confirm_calendar_event with that proposalId. If they reject, call delete_calendar_event with it.",
|
|
127
|
+
parameters: [
|
|
128
|
+
p("summary", "Short event title.", true),
|
|
129
|
+
p("start", "Event start (ISO 8601 or YYYY-MM-DD for all-day).", true),
|
|
130
|
+
p("end", "Event end. For all-day events this is EXCLUSIVE: to cover through Apr 20 send end=2026-04-21.", true),
|
|
131
|
+
p("description", "Optional longer description.", false),
|
|
132
|
+
p("location", "Optional location.", false),
|
|
133
|
+
p("attendees", "Optional comma-separated emails (NOT invited yet — only saved on the tentative event).", false),
|
|
134
|
+
p("timeZone", "IANA timezone.", false),
|
|
135
|
+
p("recurrence", "Optional RFC 5545 RRULE string for repeating events (e.g. \"RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10\"). Daily=\"RRULE:FREQ=DAILY\"; weekly Mon=\"RRULE:FREQ=WEEKLY;BYDAY=MO\"; monthly first=\"RRULE:FREQ=MONTHLY;BYDAY=1MO\". Confirm the recurrence pattern in your reply.", false),
|
|
136
|
+
p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
operation: "confirmEvent",
|
|
141
|
+
label: "Confirm proposed event",
|
|
142
|
+
toolName: "confirm_calendar_event",
|
|
143
|
+
description: "Promote a tentative event to confirmed and (by default) send invites to attendees. Pairs with propose_calendar_event for the preview-then-commit flow. USAGE RULES: (1) Use the proposalId from your most recent propose_calendar_event call in THIS conversation — never from memory. (2) sendUpdates default 'all' fires invites; pass 'externalOnly' for just non-org attendees, or 'none' to silently confirm.",
|
|
144
|
+
parameters: [
|
|
145
|
+
p("eventId", "Proposal id (returned by propose_calendar_event as proposalId).", true),
|
|
146
|
+
p("sendUpdates", "Invite policy: 'all' (default), 'externalOnly', or 'none'.", false),
|
|
147
|
+
p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
/** Índice por nombre de herramienta, para enrutar un `tools/call` sin recorrer. */
|
|
152
|
+
export const GOOGLE_CALENDAR_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(GOOGLE_CALENDAR_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
@@ -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>;
|