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.
Las diez
Sección titulada «Las diez»| 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 |
La trampa de browser_navigate
Sección titulada «La trampa de browser_navigate»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 }; },});Ver la página
Sección titulada «Ver la página»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.
Captura de red y consola
Sección titulada «Captura de red y consola»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().
Escritura que los frameworks sí detectan
Sección titulada «Escritura que los frameworks sí detectan»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.
Lo que esto no es
Sección titulada «Lo que esto no es»- 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_clickpuede 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.
