Ir al contenido

Triggers

Un trigger escucha el bus de eventos de wu y llama al modelo cuando ocurre algo. Es la mitad reactiva de wu.ai: la app se vuelve inteligente respondiendo a sus propios eventos.

wu.ai.trigger('cartAnalysis', {
pattern: 'cart:updated',
prompt: 'The cart was updated: {{data}}. Suggest complementary products.',
debounce: 3000,
priority: 'low',
onResult: (result) => wu.emit('ai:suggestions', { text: result.content }),
});
function trigger(name: string, config: {
pattern: string;
prompt: string | ((eventData: object) => string);
condition?: (eventData: object) => boolean | Promise<boolean>;
debounce?: number; // ms, 1000 por defecto
priority?: 'high' | 'medium' | 'low'; // 'medium' por defecto
namespace?: string; // `trigger:<name>` por defecto
systemPrompt?: string;
onResult?: (result: object, eventData: object) => void | Promise<void>;
enabled?: boolean; // true por defecto
maxTokens?: number;
temperature?: number;
}): Wu;
Opción Por defecto Notas
pattern 'cart:updated', 'cart:*' (* coincide dentro de un solo segmento) o '*' para todo
prompt Una plantilla con {{event}}, {{data}}, {{timestamp}}, o una función del evento
condition null Se permite async. Si lanza, se trata como false y el trigger se omite
debounce 1000 Gana el último evento. <= 0 dispara de inmediato
priority 'medium' Ver más abajo
namespace trigger:<name> Historial de conversación propio, aislado de tu chat
onResult null Los errores se tragan y se registran
enabled true Se conmuta con setEnabled(name, bool)
temperature Se lee con ??, así que temperature: 0 funciona como esperas

Registrar un nombre existente desregistra primero el antiguo (y no cuenta contra el límite).

Prioridad Camino
high Disparo con debounce
medium Disparo con debounce
low Encolado y agrupado cada batchIntervalMs (2000 ms), deduplicado para que solo sobreviva el último evento por trigger
wu.ai.init({ triggers: { maxActiveTriggers: 10, batchIntervalMs: 1000, defaultDebounceMs: 500 } });
Ajuste Por defecto
enabled true (interruptor global)
maxActiveTriggers 20
defaultDebounceMs 1000
batchIntervalMs 2000
wu.ai.trigger('x', { … });
await wu.ai.fireTrigger('x', { data: { foo: 1 } }); // salta la coincidencia de eventos y el debounce
const ai = await wu.aiReady();
ai._modules; // no es público — usa la superficie de estadísticas
wu.ai.getStats().triggers; // { totalFired, totalSkipped, totalErrors, triggerCount, triggers: {…} }

Cada trigger informa de pattern, priority, enabled, fireCount y lastFired.

Esta es la parte que importa. Una acción puede emitir un evento; un evento puede disparar un trigger; un trigger llama al modelo, que puede llamar a una acción. Sin más, eso es un bucle infinito.

Wu lo cierra propagando la causalidad. Cuando el handler de una acción llama a api.emit(...), el evento lleva meta: { traceId, depth }. Un trigger que dispara con ese evento continúa la misma cadena: reutiliza el traceId y envía con depth + 1. La protección de bucles rechaza la llamada en cuanto la profundidad o el contador por cadena supera maxDepth (3 por defecto).

Un evento que no vino de la IA no tiene meta, así que el trigger inicia una cadena nueva a profundidad 0, como debe ser.

Una llamada de trigger bloqueada no lanza: la conversación devuelve content: '[blocked] …', que aterriza en onResult como cualquier otro resultado.

Cada disparo emite ai:trigger:result con { trigger, pattern, result }. Un fallo emite ai:trigger:error con { trigger, error } y _executeTrigger devuelve null: un trigger nunca propaga una excepción al bus de eventos.

Un prompt vacío o falsy cuenta como omisión y no se hace ninguna llamada, lo que es una forma barata de filtrar dentro de una función de prompt:

wu.ai.trigger('bigOrders', {
pattern: 'order:created',
prompt: (e) => e.data.total > 1000 ? `Review this large order: ${JSON.stringify(e.data)}` : '',
});

Un trigger sobre un patrón ruidoso es una llamada al LLM por ventana de debounce, para siempre y sin que nadie mire. Antes de poner uno en producción:

  • Prefiere prioridad low para que los eventos se agrupen.
  • Pon un debounce generoso: segundos, no milisegundos.
  • Usa condition para filtrar antes de armar el temporizador de debounce.
  • Recuerda el límite global de peticiones: 20 peticiones/min en total, 10/min por namespace. Un trigger desbocado empezará a recibir [blocked] en vez de generarte una factura, pero también dejará sin oxígeno a tus conversaciones reales.