Ir al contenido

Control del navegador

Cuando wu.ai se inicializa en un navegador, registra 10 acciones que permiten a cualquier modelo ver y manejar la página. Sin extensión, sin CDP, sin Playwright: solo APIs del DOM.

const ai = await wu.aiReady();
ai.tools().map(t => t.name);
// [... 'browser_screenshot', 'browser_click', 'browser_type', ...]

Son acciones corrientes, así que pasan por la misma validación, las mismas comprobaciones de permisos y el mismo registro de auditoría que las tuyas.

Acción Parámetros Permisos Qué hace
browser_info readStore URL, título, viewport, apps montadas, claves del store, tamaños de los logs. El modelo debería llamarla primero
browser_snapshot selector?, depth? (5) Árbol de accesibilidad en texto del DOM. Entra en los shadow roots. Más barata que una captura
browser_screenshot selector? PNG en base64 mediante Canvas + foreignObject de SVG
browser_click selector?, text? emitEvents Hace clic por selector CSS o por texto visible
browser_type selector, text, clear?, submit? emitEvents Escribe en inputs/textareas/contenteditable, compatible con frameworks
browser_select selector, value emitEvents Elige una opción de un <select>; el prefijo text: busca por texto visible
browser_scroll direction, selector?, amount? (500) up, down, top, bottom
browser_navigate route emitEvents, writeStore Emite shell:navigate y define currentPath
browser_network method?, status?, limit? (30) Peticiones fetch + XHR capturadas
browser_console level?, limit? (30) Mensajes de consola capturados
wu.ai.init({ permissions: { writeStore: true } });

Una vez activado, el api.setState de la acción queda disponible porque ella misma declara writeStore en sus permissions: la doble puerta se satisface por ambos lados.

Si prefieres no abrir las escrituras globales al store, registra tu propia acción de navegación que capture tu router por clausura:

wu.ai.action('goTo', {
description: 'Navigate to a route in the app',
parameters: { route: { type: 'string', required: true } },
handler: (p) => { router.push(p.route); return { navigated: p.route }; },
});

browser_snapshot es la que conviene usar. Renderiza cada elemento como <tag id role aria-label class> "text", desciende a los shadowRoot (así que las micro-apps de wu son visibles, a diferencia de lo que ocurre con la mayoría de scrapers del DOM) y se corta en profundidad 5 y 50 hijos por nodo. Acótala a una sola app:

await wu.ai.execute('browser_snapshot', { selector: '[data-wu-app="cart"]', depth: 3 });

browser_screenshot serializa el elemento en un foreignObject de SVG y lo rasteriza en un canvas.

wu.ai instala interceptores de fetch, XMLHttpRequest y console una sola vez, de forma idempotente: el puente MCP reutiliza los mismos búferes en vez de envolverlos por duplicado.

Búfer Tope
Log de red 300 entradas
Log de consola 500 entradas

Ambos son búferes circulares: se descartan las entradas más antiguas. browser_network filtra por método y por clase de estado ("2", "4", "5", o "error" para todos los fallos); browser_console filtra por log/warn/error. Ambas devuelven las últimas N coincidencias junto con el total.

La captura empieza cuando wu.ai se inicializa. Las peticiones anteriores son invisibles: si quieres que un agente depure la carga de la página, fuerza la carga temprano con await wu.aiReady().

browser_type no se limita a asignar .value: React y Vue lo ignorarían. Escribe a través del setter nativo de value y despacha eventos input y change, que es lo que escuchan los componentes controlados. clear: true vacía el campo primero; submit: true envía el formulario o pulsa Enter después.

browser_click busca primero por selector, y recurre a rastrear botones, enlaces y elementos clicables por texto visible, lo que hace que los pasos escritos por el modelo sean bastante más robustos que los selectores CSS a secas.

  • No es un sandbox. Estas acciones operan sobre la página real con la sesión del usuario. Un modelo que puede llamar a browser_click puede pulsar cualquier cosa que pudiera pulsar el usuario, incluido “Eliminar cuenta”.
  • No cruza orígenes. Nada de iframes de otros orígenes, ni de otras pestañas, ni del chrome del navegador. Para eso usa el servidor MCP o un driver de automatización de verdad.
  • No es gratis. Las capturas son cargas base64 enormes. Prefiere los snapshots.

Protege las vías destructivas con confirm: true en tus propias acciones, y plantéate desactivar el permiso global emitEvents en contextos donde un agente autónomo no tenga por qué pulsar nada.