<!-- GENERATED translation. Edit the English source or glossary.json, not this file. -->

Paso mis semanas de trabajo dentro de grandes instituciones financieras, viendo a equipos hacer demostraciones de "agentes de IA" que, al inspeccionarlos, son cajas de chat con un *system prompt*. La interfaz es un flujo de texto. El usuario ve *tokens*. El agente ve *tokens* de vuelta. No existe nada más. Y entonces alguien del lado de operaciones hace la pregunta que mata la demostración: "¿Dónde ocurre la aprobación?"

Porque el trabajo real no es una conversación. Un flujo de *onboarding* de patrimonio no es "háblame de ti". Es verificación de identidad, luego evaluación de riesgos, luego una decisión de enrutamiento, luego una revisión de un asesor para los casos que la necesiten, y luego la apertura de cuenta. Cada paso tiene un estado, una salida y una decisión. En el momento en que un agente calcula una puntuación de riesgo, el usuario no quiere una frase que describa la puntuación. Quiere el indicador. Cuando propone una asignación, quiere el gráfico de anillos en el que pueda hacer clic, no un párrafo que lo aproxime.

Esta guía trata sobre AG-UI, el protocolo que cierra esa brecha: un flujo de eventos tipado entre un *backend* agéntico y un *frontend* orientado al usuario. Construí una implementación de referencia completa para ello (AURUM, una demostración ficticia de *onboarding* de banca privada, *repo* público enlazado al final), con un motor de procesos como orquestador en lugar de un bucle de chat. Esa elección arquitectónica resultó ser más importante que el propio protocolo, y la segunda mitad de esta guía trata sobre el porqué. Los patrones aquí son agnósticos al *framework*. Usé Camunda 8 porque lo conozco bien; todo lo que afirmo sobre el estado externalizado se aplica igualmente a Temporal, LangGraph con un *checkpointer*, o una máquina de estados que hayas escrito tú mismo.

## El problema: los *tokens* no son una interfaz

El *streaming* de *tokens* resolvió un problema de latencia, no un problema de interfaz. El *streaming* de *tokens* hace que un modelo lento se sienta receptivo. No hace nada por la forma real del trabajo.

Considera lo que un agente nativo de chat no puede mostrarte:

- **Progreso a través de un proceso.** "Paso 3 de 6" es un concepto de UI. Un flujo de *tokens* no tiene pasos, solo más *tokens*.
- **Una llamada a herramienta como objeto de primera clase.** El agente llamó a `verifyIdentity` y obtuvo `{status: "verified", method: "document+biometric"}`. Eso es una tarjeta con una marca de verificación verde, no una frase que el modelo parafrasea (y ocasionalmente parafrasea mal).
- **Una pausa.** Un humano necesita aprobar esto. En un bucle de chat, "esperando a un humano" significa que la solicitud se mantiene abierta o se pierde. Ninguna de las dos es una pausa real.
- **Estado estructurado.** El registro de *onboarding* tiene 40 campos que tanto el agente como la UI necesitan. Serializarlo en prosa en cada turno es una pérdida de información en ambas direcciones.

Cada equipo que he visto chocar con este muro lo resuelve de la misma manera: inventan un vocabulario de eventos privado entre su *backend* y su *frontend*. Un *blob* JSON con un campo `type`, una sentencia *switch* en React. Funciona, y luego se calcifica. Los eventos no están documentados, el *frontend* y el *backend* se desincronizan, y el segundo cliente (la aplicación móvil, el *dashboard* de operaciones) tiene que hacer ingeniería inversa del dialecto.

AG-UI es ese vocabulario privado, estandarizado. Esa es toda la propuesta, y es suficiente.

## Qué es AG-UI

AG-UI (Protocolo de Interacción Agente-Usuario) es un protocolo abierto, basado en eventos, que estandariza cómo un *backend* agéntico se comunica con una aplicación orientada al usuario. Surgió de CopilotKit, desarrollado en asociación con LangGraph y CrewAI, y ahora reside en código abierto bajo la organización `ag-ui-protocol` en GitHub. El lado del agente emite eventos tipados a través de un flujo. El lado de la aplicación renderiza cada evento. La entrada del usuario fluye de vuelta como mensajes estructurados. Ese es todo el modelo.

| Hecho | Detalle |
|---|---|
| Origen | CopilotKit, con LangGraph y CrewAI; de código abierto bajo `ag-ui-protocol` |
| Forma | Flujo de eventos unidireccional agente-a-aplicación, más un canal de entrada estructurada aplicación-a-agente |
| Vocabulario de eventos central | ~16 tipos de eventos en la especificación original en cinco categorías: ciclo de vida de la ejecución, mensajes de texto, llamadas a herramientas, gestión de estado y especiales (RAW, CUSTOM). La especificación actual ha crecido más allá de eso con eventos de fragmentos de conveniencia y eventos de razonamiento |
| Modelo de estado | Almacén tipado compartido: `STATE_SNAPSHOT` para el estado completo, `STATE_DELTA` para las diferencias de JSON Patch RFC 6902 |
| Transporte | Agóstico al transporte. Server-Sent Events (SSE) es el transporte predeterminado y de referencia; HTTP plano y WebSockets también funcionan |
| Humano en el bucle | De primera clase: pausar, aprobar, editar, reintentar a mitad de ejecución sin perder el estado |
| Qué estandariza | Los tipos de eventos, las formas de sus cargas útiles, la semántica de ordenación y el mecanismo de sincronización de estado |
| Qué deja abierto | Cómo renderizar cualquier cosa, esquemas de componentes para UI generativa, autenticación, autorización, persistencia |
| Integraciones | Más de 16 *bindings* de *frameworks*: LangGraph, CrewAI, Microsoft Agent Framework, Google ADK, AWS Strands, Pydantic AI, LlamaIndex y otros |

La apuesta de diseño es la "coincidencia de formato flexible": AG-UI estandariza el flujo del estado del agente y la intención de la UI, no los píxeles. Un evento `TOOL_CALL_START` no le dice a tu *frontend* que renderice un *spinner* en una tarjeta con esquinas redondeadas. Le dice a tu *frontend* que una llamada a herramienta comenzó, con un nombre y un ID, y el resto es tu problema. Esta es la decisión correcta. Cada intento que he visto de estandarizar la capa de renderizado en sí misma muere bajo el peso de su propia biblioteca de componentes.

## Dónde se sitúa en la pila de protocolos

El panorama de los protocolos agénticos se organizó, a lo largo de unos dieciocho meses, en cuatro capas por contraparte. Encuentro que este es el único marco que hace que los acrónimos se queden:

| Protocolo | Conecta el agente a... | Origen | Tarea en una línea |
|---|---|---|---|
| MCP | Herramientas y contexto | Anthropic | Dar manos al agente: acceso estandarizado a sistemas y datos |
| A2A | Otros agentes | Google | Permitir que los agentes deleguen y coordinen entre proveedores y entornos de ejecución |
| AG-UI | El humano | CopilotKit | La última milla: convertir la actividad del agente en algo que una persona pueda ver y hacer clic |
| AP2 | Dinero | Google + socios de pagos | Mandatos criptográficamente responsables para pagos iniciados por agentes |

![La pila de protocolos agénticos de cuatro capas por contraparte: MCP para herramientas, A2A para otros agentes, AG-UI para el humano resaltado como la capa que cubre esta guía, y AP2 para dinero](/diagrams/agui-protocol-stack.svg)

Un sistema de producción frecuentemente usa tres de estos a la vez, y cada vez más los cuatro. En AURUM, el agente accede a sus herramientas a través de la capa de orquestación (el AI Agent Connector de Camunda desempeña el papel de intermediación de herramientas de MCP), y todo lo que el usuario ve se basa en AG-UI. Cubro las otras capas en profundidad en la [guía de campo de A2A](/es/guides/a2a-field-guide/) y la [guía de campo de AP2](/es/guides/ap2-field-guide/); este documento se centra en la capa humana.

Las capas son genuinamente ortogonales. Nada en AG-UI asume que MCP está debajo, y nada en A2A asume que existe una superficie AG-UI. Esa ortogonalidad es la razón por la que puedes adoptarlos de forma independiente, que es como realmente ocurre la adopción dentro de las empresas: un protocolo por ciclo presupuestario.

## Anatomía de los eventos

Los eventos AG-UI son objetos JSON planos con un discriminador `type`. Cinco categorías realizan el trabajo.

#### Ciclo de vida de la ejecución

`RUN_STARTED`, `RUN_FINISHED`, `RUN_ERROR`, más `STEP_STARTED` / `STEP_FINISHED` para fases nombradas dentro de una ejecución. Estos son los eventos de los que depende tu UI de progreso. Una ejecución lleva un `threadId` y `runId`; los pasos llevan un `stepName`. En AURUM, la consola del operador es esencialmente un *renderer* para eventos de ciclo de vida: cada actividad BPMN se mapea a un paso, por lo que el cable en bruto se lee como un registro de proceso porque lo es.

#### *Streaming* de texto

Tres eventos por mensaje, correlacionados por `messageId`:

```json
{ "type": "TEXT_MESSAGE_START", "messageId": "msg_042", "role": "assistant" }
{ "type": "TEXT_MESSAGE_CONTENT", "messageId": "msg_042", "delta": "Your risk profile " }
{ "type": "TEXT_MESSAGE_CONTENT", "messageId": "msg_042", "delta": "suggests a balanced allocation." }
{ "type": "TEXT_MESSAGE_END", "messageId": "msg_042" }
```

El triple inicio/contenido/fin parece burocrático al lado de "simplemente *stream* la cadena", pero los límites explícitos son lo que permite a un cliente intercalar múltiples mensajes concurrentes y saber, de forma determinista, cuándo un mensaje está completo en lugar de estancado.

#### Llamadas a herramientas

`TOOL_CALL_START` (nombre e ID), `TOOL_CALL_ARGS` (deltas de argumentos *streamed*), `TOOL_CALL_END` y `TOOL_CALL_RESULT`. Esta es la categoría que separa una UI de agente de una UI de chat. El *frontend* puede renderizar la llamada como un objeto con su propio ciclo de vida: pendiente, en ejecución, resuelto, con argumentos y resultados inspeccionables. En AURUM, `parseApplicationForm → {fieldsParsed: 12}` se renderiza como un *chip* de paso completado en la vista del cliente y como un evento en bruto en la vista del operador. Mismo evento, dos renderizados.

#### Sincronización de estado

`STATE_SNAPSHOT` lleva todo el objeto de estado compartido. `STATE_DELTA` lleva un array de JSON Patch RFC 6902:

```json
{ "type": "STATE_DELTA", "delta": [
  { "op": "replace", "path": "/application/riskScore", "value": 72 },
  { "op": "add", "path": "/application/flags/-", "value": "PEP_SCREEN_REQUIRED" }
] }
```

*Snapshots* al conectar, deltas mientras se hace *streaming*. El patrón es *event-sourcing* aplicado al estado de la UI, y es la parte que la mayoría de los dialectos caseros hacen mal al enviar el estado completo en cada cambio y preguntarse por qué el flujo es 40 veces más grande de lo necesario.

#### UI generativa

Aquí la especificación es deliberadamente poco dogmática: la UI generativa se basa en eventos de llamada a herramientas renderizados como componentes, o en eventos `CUSTOM`. Mi dialecto de demostración lo nombra explícitamente, lo que la especificación clasificaría como un evento personalizado:

```json
{ "type": "GENERATIVE_UI", "pid": "2251799813737463", "ts": 1719849302144,
  "component": "PortfolioAllocationChart",
  "props": { "equities": 60, "fixedIncome": 30, "alternatives": 10 } }
```

El *frontend* mantiene un registro que mapea los nombres `component` a componentes React reales (`IdentityResultCard`, `PortfolioAllocationChart`, `ProjectedGrowthChart`, `AccountOpenedCard`). ¿Nombre de componente desconocido? Renderiza una tarjeta de reserva con las *props* en bruto. Esa única decisión defensiva salvó la demostración dos veces durante el desarrollo, y es la diferencia entre un dialecto que se degrada y uno que muestra una pantalla en blanco.

Las reglas de ordenación son simples y fundamentales: procesar los eventos en orden de llegada, y tratar los eventos que comparten un ID (`messageId`, `toolCallId`) como un único flujo lógico. Todo lo demás en un cliente se deriva de esas dos reglas.

## El patrón que probé: UI generativa orquestada por procesos

Aquí está la parte que más me importa, porque es la parte que la documentación del protocolo no puede decirte.

AG-UI estandariza el cable. No dice nada sobre quién posee el estado detrás del cable. En cada inicio rápido al estilo CopilotKit, la respuesta es el propio bucle del agente: un *runtime* de chat mantiene la conversación, llama al modelo, emite eventos. Eso funciona hasta que el proceso falla, o un humano necesita tres días para decidir, o un auditor pregunta qué pasó el 14 de marzo.

En AURUM lo invertí. El orquestador es un motor de procesos (Camunda 8, BPMN), y el flujo AG-UI es una proyección del estado del proceso. El *backend* es un Node BFF con un *hub* SSE; los *workers* de Zeebe y un *task poller* traducen los eventos del motor en eventos AG-UI. El agente (el AI Agent Connector de Camunda ejecutando un subproceso *ad-hoc*, con Claude en Bedrock y Gemini como modelos intercambiables) elige por turno entre 13 herramientas heterogéneas: tareas de servicio, un *script* FEEL, un conector HTTP para tasas de cambio en vivo, una transferencia a un humano. El flujo es admisión, identidad, riesgo, una tabla de decisión DMN para el enrutamiento, y luego la apertura directa de la cuenta o una revisión de un asesor.

Cuando el orquestador posee el estado, el flujo de la UI hereda tres propiedades que las arquitecturas nativas de chat no pueden tener:

**Reanudable.** Si el BFF o el agente fallan a mitad del flujo, la instancia del proceso sigue en el motor en la actividad exacta que alcanzó. Reinicia el *backend*, reproduce un `STATE_SNAPSHOT` desde las variables del proceso, y el flujo continúa. El estado reside en el motor, no en la ventana de contexto del LLM y no en el *heap* de un proceso Node.

**Pausable.** La tabla DMN enruta los casos superiores a $1.5M a una tarea de usuario humana. En ese momento, el *token* del proceso se detiene. No "el agente sondea en un bucle", no "mantenemos una solicitud HTTP abierta con un tiempo de espera largo". El *token* está estacionado, de forma duradera, por un minuto o un mes. El flujo AG-UI emite el evento `USER_TASK`, el cliente ve una tarjeta honesta de "su asesor está revisando esto", el asesor ve una tarjeta de aprobación en su cola. Cuando el asesor decide, el *token* se mueve y el flujo se reanuda. El <dfn class="term" data-en="human-in-the-loop">humano en el bucle</dfn> es una construcción de primera clase del orquestador, no un *hack* atornillado a un bucle de chat. Críticamente, la IA no decidió esperar. El proceso lo hizo. No quieres que "pausar para revisión de cumplimiento" sea un comportamiento que solicites con un *prompt*.

**Auditable.** Cada transición de estado, cada invocación de herramienta, cada decisión de enrutamiento es registrada por el motor como un efecto secundario de la ejecución. En Camunda, ese <dfn class="term" data-en="audit trail">registro de auditoría</dfn> es visible en Operate con cero código de registro personalizado. Cuando el auditor pregunta por qué la solicitud de James Rodríguez fue a revisión manual y la de Sarah Chen no, la respuesta es una tabla DMN con semántica de política de aciertos y un historial de *tokens* con marca de tiempo, no un *grep* a través de transcripciones de modelos.

> Comentario de revisión: si tu historia de auditoría depende de que un desarrollador recuerde añadir una línea de registro junto a cada llamada a herramienta, no tienes una historia de auditoría. Tienes un diario.

Nada de esto es específico de Camunda. La propiedad proviene de externalizar el estado en algo duradero que no es el contexto del modelo ni la capa web. Temporal te da la misma reanudabilidad a través de historiales de flujo de trabajo basados en eventos. LangGraph te da una versión más débil pero real a través de *checkpointers*. Una máquina de estados respaldada por Postgres que escribiste tú mismo califica. La regla de diseño es: **el flujo AG-UI debe ser una vista sobre un estado duradero, nunca el sistema de registro.** Haz eso bien y la elección del protocolo en el cable es casi incidental. Hazlo mal y ningún protocolo te salvará.

## Un flujo, muchas superficies

El flujo de eventos es tipado y semántico, por lo que nada en él asume un único lector. AURUM ejecuta tres personas desde el mismo cable:

| Superficie | Ruta | Qué renderiza del flujo |
|---|---|---|
| Cliente | `#/customer` | Texto de conserjería, tarjetas generativas que se transmiten una por una, estados honestos de "esperando revisión" |
| Asesor | `#/advisor` | La cola de aprobación: los eventos `USER_TASK` se convierten en tarjetas accionables; las decisiones fluyen de vuelta al proceso |
| Operador | `#/operator/{pid}` | El registro de eventos en bruto, sin renderizar: cada evento de ciclo de vida, llamada a herramienta y delta de estado a medida que llega |

![Un backend agéntico que emite un flujo de eventos AG-UI tipado sobre SSE, con eventos TEXT_MESSAGE, TOOL_CALL, STATE_DELTA y de UI generativa fluyendo por el cable y distribuyéndose a las vistas de cliente, asesor y operador](/diagrams/agui-event-stream.svg)

La vista del operador existe como la vista de "no me creas". Ábrela junto a una sesión de cliente y verás cómo el cable en bruto produce la UI pulida en tiempo real. En las demostraciones para clientes, esto impacta más que cualquier diapositiva de arquitectura, porque demuestra que las tarjetas no son un teatro *frontend* coreografiado. Son renderizaciones de los mismos eventos que la consola de operaciones muestra en bruto.

El punto más profundo: en la mayoría de las empresas, la UI del cliente, la cola de *back-office* y el *dashboard* de operaciones son tres equipos, tres bases de código y tres proyectos de integración. Un flujo de eventos tipado reduce eso a un contrato con tres *renderers*. Las vistas del escritorio del asesor (`#/desk`, `#/pipeline`) surgieron casi de forma gratuita una vez que existió el vocabulario, y "casi de forma gratuita" no es una frase que use a la ligera.

## Honestidad de implementación: lo que te dan ~150 líneas

El *frontend* de AURUM no tiene *framework* de agente. Ni CopilotKit, ni ChatKit. El cliente AG-UI es un pequeño *wrapper* `EventSource` más un *hook* React `useAGUI`, unas 150 líneas en total. Hice esto deliberadamente, para encontrar el verdadero mínimo de lo que necesita un cliente. Aquí está el recuento honesto.

**Lo que las ~150 líneas realmente manejan:** abrir la conexión SSE por instancia de proceso, analizar cada evento, despachar en `type` al estado de React (añadir delta de texto, *upsert* de llamada a herramienta por ID, empujar una tarjeta generativa, establecer el indicador de tarea de usuario), y apoyarse en la reconexión automática incorporada de `EventSource`. Eso es genuinamente todo lo que necesita un cliente de demostración, y es por eso que les digo a los equipos que el costo del lado del cliente de la adopción de AG-UI es bajo. La parte costosa de la UX del agente es la semántica del *backend*, no el manejo del *socket*.

**Lo que no manejan, y lo que yo endurecería para producción:**

- **Reconexión con continuidad.** `EventSource` se reconecta, pero mi servidor no implementa `Last-Event-ID`, por lo que los eventos emitidos durante una desconexión simplemente se pierden. La solución es estándar: asignar IDs de evento monotónicos, mantener un búfer de reproducción corto (o volver a derivar del motor, que es el verdadero sistema de registro), y reproducir desde el último ID del cliente al reconectar. Volver a un `STATE_SNAPSHOT` nuevo cuando el búfer ha caducado cubre el resto.
- **Contrapresión.** SSE no tiene ninguna. Un cliente lento significa que el servidor almacena en búfer. Con un navegador de demostración esto es invisible; con miles de flujos concurrentes es un problema de memoria. Soluciones de producción: límites de cola por conexión con *snapshot* y reinicio en caso de desbordamiento, o coalescencia de deltas de estado (JSON Patch se compone, por lo que N deltas pueden colapsar en uno).
- **Ordenación entre fuentes.** Dentro de una conexión SSE, la ordenación está garantizada. Pero mi BFF recibe eventos de múltiples *workers* y un *task poller*. Dos *workers* que emiten casi simultáneamente pueden intercalarse en un orden que difiere del orden del motor. La demostración ignora esto; la producción debería secuenciar en el *hub* usando la ordenación del lado del motor (posición o marca de tiempo de la instancia del proceso) antes de escribir en el *socket*.
- **Renderizado idempotente.** La reproducción más la entrega al menos una vez significa duplicados. El *upsert* por `messageId`/`toolCallId` te lleva la mayor parte del camino; mi manejador de tarjetas generativas añade, por lo que un evento `GENERATIVE_UI` reproducido se renderiza dos veces. Las tarjetas también necesitan IDs estables.
- **Autenticación de flujo.** Las personas de la demostración son rutas *hash*. No hay autenticación en el *endpoint* SSE en absoluto. La producción necesita un *token* de corta duración vinculado a la instancia del proceso y a la persona, verificado en el momento de la suscripción y vuelto a verificar al reconectar.

Una pieza más de honestidad sobre la propia demostración: se ejecuta sin ninguna clave API. Sin `ANTHROPIC_API_KEY`, los *workers* del agente reproducen un escenario *scripted* determinista ("modo sombra"), por lo que el flujo AG-UI completo, la pausa de <dfn class="term" data-en="human-in-the-loop">humano en el bucle</dfn> y la coreografía del motor funcionan antes de que gastes un céntimo en *tokens*. Lo construí para la fiabilidad de la demostración, pero se ganó su valor como arnés de prueba: toda la tubería de eventos se ejercita con cero varianza del modelo, que es exactamente lo que quieres en CI. Si adoptas una idea de esta sección, adopta esa.

> Comentario de revisión: un "modo sombra" *scripted* no es una demostración menor. Es un *fixture* para tu contrato de eventos, y detectará más regresiones de *frontend* que cualquier evaluación de *prompt*.

## Lo que AG-UI no resuelve

Los protocolos ganan confianza al ser claros sobre sus límites. Tres brechas de las que te encargarás tú mismo:

**Autorización de acciones mostradas en la UI.** AG-UI puede transmitir una tarjeta de aprobación a un asesor. No tiene opinión sobre si ese asesor está autorizado a aprobar. El evento es una instrucción de renderizado, no una concesión de permiso, y un *frontend* que trata "la tarjeta apareció" como autorización tiene un agujero con forma de IDOR. La verificación debe residir donde se ejecuta la acción. En AURUM, ese es el motor: la API de finalización de tareas de usuario impone quién puede completarla, y la UI es solo una cara bonita de ese hecho. Dondequiera que se ejecuten tus acciones, impón la autorización allí, y trata cada mensaje entrante de "el usuario decidió X" como entrada no confiable.

**Gobernanza de esquemas de componentes generativos.** El contrato `component` + `props` entre los emisores del *backend* y el registro del *frontend* es tan fuerte como tu disciplina. Nada en AG-UI valida que `PortfolioAllocationChart` siga aceptando `alternatives` después de la refactorización de la semana pasada. Necesitas lo que necesitarías para cualquier API: definiciones de esquema compartidas (yo usaría zod o JSON Schema, validadas en la emisión y en el renderizado), un *renderer* de reserva para componentes desconocidos, y tratar las *props* de los componentes como una API pública versionada, porque eso es lo que son.

**Versionado de eventos entre despliegues.** Los flujos son de larga duración; los despliegues no. Durante un despliegue continuo, un cliente construido con las formas de eventos de ayer puede recibir los eventos de hoy, y una instancia de proceso iniciada la semana pasada puede reanudar el *streaming* en un *frontend* rediseñado. La especificación te da vías de escape `RAW` y `CUSTOM` pero no una historia de versionado. Respuesta mínima viable: cambios solo aditivos en las cargas útiles de los eventos, un campo de versión en tus eventos personalizados y una política para agotar los flujos de larga duración antes de los cambios disruptivos. Las configuraciones orquestadas por procesos sienten esto más, no menos, porque una tarea de usuario estacionada puede esperar felizmente a través de seis despliegues.

Añadiría un cuarto punto más suave: AG-UI no hace que tu agente sea bueno. Un flujo tipado de un proceso malo es un proceso malo bien formateado. El protocolo movió mi problema de "¿cómo llevo la estructura al *frontend*?" a "¿qué estructura necesita realmente este flujo de trabajo?", que es el problema correcto, pero sigue siendo trabajo.

## La versión de un párrafo

AG-UI es un protocolo de eventos abierto y tipado entre un *backend* agéntico y un *frontend* orientado al usuario: ciclo de vida de la ejecución, texto transmitido, llamadas a herramientas con resultados, deltas de estado de JSON Patch y un carril abierto para componentes de UI generativa, generalmente sobre SSE. Ocupa la capa de agente a humano de la pila, junto con MCP (herramientas), A2A (otros agentes) y AP2 (pagos), y un cliente capaz es pequeño (el mío tiene unas 150 líneas, sin *framework*). El protocolo estandariza el cable y deliberadamente no el renderizado, la autorización o la gobernanza del esquema, por lo que esas siguen siendo tu responsabilidad. La decisión de mayor impacto no está en el cable en absoluto: haz que el flujo sea una proyección de un estado duradero y externalizado (un motor de procesos, Temporal, un grafo con puntos de control), y la UI se vuelve reanudable después de fallos, pausable para la aprobación humana como una construcción de primera clase y auditable como un efecto secundario de la ejecución. Probé el patrón con AURUM, un flujo de *onboarding* de banca privada ficticio donde un flujo de eventos alimenta una vista de cliente, una cola de aprobación de asesor y una consola de operador en bruto, y donde la pausa de aprobación de $1.5M es un *token* de proceso estacionado, no un *prompt*.

## Referencias

- Documentación del protocolo AG-UI: [https://docs.ag-ui.com](https://docs.ag-ui.com/introduction)
- Protocolo AG-UI en GitHub: [https://github.com/ag-ui-protocol/ag-ui](https://github.com/ag-ui-protocol/ag-ui)
- Repositorio de demostración de AURUM (ejecutable, el modo sombra no necesita claves API): [https://github.com/letmereviewyourcode/camunda-agui-wealth-demo](https://github.com/letmereviewyourcode/camunda-agui-wealth-demo)
- El video de demostración EP02 y la discusión en LinkedIn: [https://www.linkedin.com/posts/zishanalikhan_agenticai-agui-camunda-ugcPost-7480344185674313728-ffd8](https://www.linkedin.com/posts/zishanalikhan_agenticai-agui-camunda-ugcPost-7480344185674313728-ffd8)
- Guías complementarias de esta serie: [guía de campo de A2A](/es/guides/a2a-field-guide/) · [guía de campo de AP2](/es/guides/ap2-field-guide/)
- RFC 6902 (JSON Patch), el mecanismo detrás de `STATE_DELTA`: [https://datatracker.ietf.org/doc/html/rfc6902](https://datatracker.ietf.org/doc/html/rfc6902)