Acciones y tool calling
Una acción es una capacidad que le entregas al modelo. Se convierte en una tool dentro de la petición y, cuando el modelo la llama, wu valida los parámetros, comprueba permisos, opcionalmente pregunta al usuario y ejecuta tu handler con una API en sandbox, nunca con wu en sí.
wu.ai.action('addToCart', { description: 'Add an item to the shopping cart', parameters: { productId: { type: 'string', required: true, description: 'SKU of the product' }, quantity: { type: 'number', description: 'Defaults to 1' }, }, handler: async (params, api) => { api.emit('cart:add', params); return { added: params.productId }; }, confirm: true,});function action(name: string, config: { description?: string; parameters?: Record<string, ParamDef> | JSONSchema; handler: (params: object, api: SandboxedApi) => any | Promise<any>; confirm?: boolean; permissions?: string[]; dangerous?: boolean;}): Wu;| Opción | Por defecto | Significado |
|---|---|---|
description |
Execute: <name> |
Se envía al modelo. Es lo único que le indica cuándo llamar a tu acción: escríbela bien |
parameters |
{} |
Forma abreviada o JSON Schema en crudo; se normaliza antes de llegar al modelo |
handler |
obligatorio | async (params, api) => result. Lanzar está bien: el fallo se le informa de vuelta al modelo |
confirm |
false |
Suspende y espera a una persona antes de ejecutar |
permissions |
[] |
Flags que deben estar activos para que esta acción se ejecute siquiera |
dangerous |
false |
Registra un aviso con los parámetros en cada ejecución. Nada más |
Registrar el mismo nombre dos veces reemplaza la definición anterior.
La API en sandbox
Sección titulada «La API en sandbox»Esta es toda la superficie que recibe tu handler:
| Miembro | Presente cuando | Hace |
|---|---|---|
api.getState(path) |
el flag global readStore es true (por defecto) |
Lee del store de wu |
api.setState(path, value) |
el flag global writeStore es true y la acción declara 'writeStore' en permissions |
Escribe en el store de wu |
api.emit(event, data) |
el flag global emitEvents es true (por defecto) |
Emite en el bus de eventos de wu como wu-ai, llevando el traceId/depth causal |
Fíjate en la asimetría: las lecturas solo necesitan el flag global, pero las escrituras necesitan el flag global y una adhesión explícita en la acción. Esa doble puerta es deliberada: activar writeStore globalmente no permite retroactivamente escribir a todas las acciones existentes.
wu.ai.init({ permissions: { writeStore: true } });
wu.ai.action('setTheme', { description: 'Change the UI theme', parameters: { theme: { type: 'string', required: true } }, permissions: ['writeStore'], // ← sin esto, api.setState es undefined handler: (p, api) => { api.setState('ui.theme', p.theme); return { theme: p.theme }; },});Los metadatos causales que viajan en api.emit son lo que permite a la protección de bucles cortar un ciclo IA → evento → trigger → IA. Emitir con tu propio wu.emit en su lugar rompe esa cadena.
Parámetros
Sección titulada «Parámetros»La forma abreviada es por propiedad, y se normaliza a JSON Schema:
parameters: { productId: { type: 'string', required: true, description: 'SKU' }, quantity: { type: 'number' }, gift: { type: 'boolean' },}Pasar un objeto JSON Schema completo también funciona: se reenvía tal cual. La validación corre antes del handler; si algo no cuadra, el modelo recibe { success: false, reason: 'Invalid params: …' } y normalmente reintenta con los argumentos corregidos.
Resultado de la ejecución
Sección titulada «Resultado de la ejecución»Tanto el bucle de tools como las llamadas directas obtienen la misma forma:
{ success: true, result: any } | { success: false, reason: string }reason cubre todas las vías de rechazo: acción no registrada, permiso denegado, parámetros inválidos, denegación del usuario o el mensaje de error del handler. El modelo lo ve como el resultado de la tool y puede reaccionar.
Flujo de confirmación
Sección titulada «Flujo de confirmación»Con confirm: true, la ejecución se suspende y wu emite ai:tool:confirm:
wu.on('ai:tool:confirm', ({ data }) => { const ok = window.confirm(`${data.message}\n${JSON.stringify(data.params)}`); ok ? wu.ai.confirmTool(data.callId) : wu.ai.rejectTool(data.callId);});El evento lleva { callId, action, params, message }.
Llamar a las acciones directamente
Sección titulada «Llamar a las acciones directamente»function execute(name: string, params: object): Promise<{ success: boolean; result?: any; reason?: string }>;function tools(): Array<{ name: string; description: string; parameters: JSONSchema }>;execute() recorre el mismo pipeline que una llamada a tool del modelo, con un trace ID nuevo a profundidad 0. Es lo que usan los agentes externos por CDP o WebMCP:
// Desde la consola de devtools, un script de Playwright, un cliente MCP…await window.wu.ai.execute('addToCart', { productId: 'SKU-42' });Registro de auditoría
Sección titulada «Registro de auditoría»Cada ejecución exitosa se añade a un log en memoria (últimas 100 entradas) con el nombre de la acción, los parámetros, el resultado y el traceId, y emite ai:action:executed. Las denegaciones emiten ai:action:denied; los fallos del handler emiten ai:action:error. wu.ai.getStats().actions muestra los nombres registrados y el tamaño del log.
El log es solo de memoria y está limitado. Si necesitas un registro de auditoría de verdad, escucha los eventos y envíalos a algún sitio.
De dónde vienen las acciones
Sección titulada «De dónde vienen las acciones»Además de las tuyas, hay otras dos fuentes que registran en el mismo registro:
- Browser actions: 10 de ellas, registradas automáticamente cuando existe
window. Consulta Control del navegador. - Capacidades:
wu.ai.capability(app, name, config)registraapp:namey se limpia conwu.ai.removeApp(app). Consulta Agentes.
Todas aparecen en tools() y todas las puede llamar el modelo, así que vigila el total: cada acción registrada son tokens en cada petición.
