Inicio

Dentro del Streaming

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

ParteCuándo aparecePara qué sirve
startInicio del mensajeAsigna un messageId único
text-startAntes del textoInicia un bloque de texto con ID
text-deltaCada fragmentoEl texto real, token por token
text-endFin del textoCierra el bloque de texto
reasoning-start/delta/endModelos que "piensan"Claude y o3 exponen su razonamiento
tool-input-start/delta/availableTool callsCuando el modelo quiere usar una herramienta
tool-output-availableResultado de toolsLo que devolvió la herramienta
finish-stepFin de un pasoImportante para agentes multi-step
finishTodo terminóIncluye finishReason
[DONE]Cierre del streamSeñ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:

  1. Modelo recibe pregunta
  2. Modelo decide usar herramienta
  3. Herramienta se ejecuta
  4. Modelo recibe resultado
  5. 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 herramienta
  • steps — El array de pasos que vimos en onStepFinish
  • stopWhen — 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:

  1. Devuelve un tool-approval-request al cliente
  2. Tu UI muestra: "¿Aprobar pago de $500?"
  3. El usuario aprueba o rechaza
  4. Envías tool-approval-response al servidor
  5. 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:

  1. Detecta la hora y selecciona el menú apropiado
  2. Envía metadata al cliente antes del streaming
  3. Usa un system prompt dinámico
  4. Loguea costos en pesos mexicanos
  5. 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.