Capítulo 3: Dentro del Streaming
React Router v7 es genial, pero esconde los detalles. En este capítulo usamos Hono—un framework mínimo—para ver exactamente qué viaja por el wire.
Cuando tu chat falle en producción a las 3am, este conocimiento te salvará.
Setup
Si aún no tienes el repositorio del taller:
Cambia a la branch bonus:
Esta branch tiene un servidor Hono funcionando. Vamos a entenderlo pieza por pieza.
Por qué Hono (y no RRv7) para este capítulo
Hono pesa ~14kb. No tiene magia. Cuando escribes un endpoint, ves exactamente qué pasa: qué headers se envían, qué bytes viajan, cómo se cierra la conexión.
React Router v7 es más cómodo para producción, pero esconde estos detalles detrás de abstracciones. Primero entenderemos los fundamentos con Hono, luego en el próximo capítulo veremos cómo RRv7 simplifica todo.
Es como aprender JavaScript antes de React: no es estrictamente necesario, pero te hace mejor desarrollador.
Tu primer endpoint
Abre el archivo del servidor y mira el endpoint de chat:
Ejecútalo con npm run dev. Funciona. Pero ¿qué acaba de pasar?
Abre DevTools: El protocolo v1
Abre tu navegador, ve al chat, y abre DevTools → Network. Envía un mensaje y busca la request a /api/chat.
Click en la request → Response. Verás algo como esto:
Esto es lo que useChat parsea. No es magia—es un protocolo de texto estructurado.
Las partes del protocolo
| Parte | Cuándo aparece | Para qué sirve |
|---|---|---|
start | Inicio del mensaje | Asigna un messageId único |
text-start | Antes del texto | Inicia un bloque de texto con ID |
text-delta | Cada fragmento | El texto real, token por token |
text-end | Fin del texto | Cierra el bloque de texto |
reasoning-start/delta/end | Modelos que "piensan" | Claude y o3 exponen su razonamiento |
tool-input-start/delta/available | Tool calls | Cuando el modelo quiere usar una herramienta |
tool-output-available | Resultado de tools | Lo que devolvió la herramienta |
finish-step | Fin de un paso | Importante para agentes multi-step |
finish | Todo terminó | Incluye finishReason |
[DONE] | Cierre del stream | Señal de terminación |
El header x-vercel-ai-ui-message-stream: v1 le dice al cliente qué versión del protocolo usar. Hono lo incluye automáticamente cuando usas toUIMessageStreamResponse().
Callbacks: Tu servidor ahora tiene ojos
El endpoint básico funciona, pero no sabes qué está pasando. Con callbacks, puedes observar cada paso:
¿Por qué onStepFinish importa?
En un chat simple, solo hay un paso. Pero los agentes ejecutan múltiples pasos:
- Modelo recibe pregunta
- Modelo decide usar herramienta
- Herramienta se ejecuta
- Modelo recibe resultado
- Modelo genera respuesta final
Cada uno de estos es un "step". onStepFinish te dice cuándo terminó cada uno.
Datos custom: Más que texto
A veces quieres enviar información adicional al cliente: qué modelo estás usando, cuánto costó, metadata del usuario. Con createUIMessageStream puedes hacerlo:
En el cliente, estos datos llegan como partes del mensaje:
Esto es la base de UI generativa: en lugar de solo texto, puedes enviar componentes, estados, acciones. El cliente decide cómo renderizarlos.
Structured output (AI SDK v6)
En el Capítulo 1 vimos generateObject para obtener datos estructurados. En AI SDK v6, esa función está deprecada. Ahora usas el parámetro output directamente en streamText:
Otras opciones de output
¿Por qué deprecaron generateObject? Porque ahora puedes combinar structured output con tool calling en la misma llamada. Antes tenías que elegir uno u otro.
Preview: El vocabulario de agentes
No vamos a implementar agentes todavía—eso es el Capítulo 6. Pero quiero que veas el código para que el vocabulario no sea nuevo cuando llegues ahí:
Lo que ya conoces
Mira el código anterior. Ya sabes qué son:
instructions— El system prompt (lo vimos en caps anteriores)tools— Las herramientas (lo veremos a fondo en Cap 5)execute— La función que corre cuando el modelo llama la herramientasteps— El array de pasos que vimos enonStepFinishstopWhen— Condición de parada (lo que controla el loop del agente)
Cuando llegues al Capítulo 6, solo estarás conectando piezas que ya conoces.
Preview: Tool approval (human-in-the-loop)
AI SDK v6 introdujo aprobación de herramientas. Esto es crucial para tools peligrosas:
Cuando el modelo quiere usar esta herramienta, el SDK no la ejecuta automáticamente. En su lugar:
- Devuelve un
tool-approval-requestal cliente - Tu UI muestra: "¿Aprobar pago de $500?"
- El usuario aprueba o rechaza
- Envías
tool-approval-responseal servidor - Si aprobado, se ejecuta
Esto lo veremos en detalle en el Capítulo 5.
Un caso práctico: Asistente con contexto dinámico
Juntemos todo en un endpoint real:
Este endpoint:
- Detecta la hora y selecciona el menú apropiado
- Envía metadata al cliente antes del streaming
- Usa un system prompt dinámico
- Loguea costos en pesos mexicanos
- Está listo para guardar en base de datos
En una frase
- Protocolo v1: Cada token tiene nombre y apellido (
text-delta,finish-step). - Callbacks: Tu servidor ahora tiene ojos (
onChunk) y memoria (onFinish). - Datos custom: Puedes mandar lo que quieras al frontend, no solo texto.
- El patrón de agentes: Loop de pasos + herramientas. Ya lo viste. Ya no es misterio.
En el próximo capítulo veremos cómo React Router v7 simplifica todo esto. Spoiler: mucho del código que escribiste aquí desaparece—pero ahora sabes qué está pasando por debajo.
¿Ya compraste el libro?
Si compraste el libro y no encuentras tu email de descarga, ingresa tu email y te enviamos un nuevo enlace.
