> For the complete documentation index, see [llms.txt](https://docs.neuron-ai.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.neuron-ai.dev/neuron-v3-es/agente/streaming.md).

# Streaming

El streaming te permite mostrar a los usuarios fragmentos del texto de respuesta a medida que llegan, en lugar de esperar ciegamente la respuesta completa. Puedes ofrecer una experiencia de conversación con el agente en tiempo real.

<figure><img src="/files/7c4a65ef7239090cbcafa1986e6c7bcb75b875a4" alt=""><figcaption></figcaption></figure>

### Agente

Para transmitir la respuesta de la IA debes usar el `stream()` método en el agente, en lugar de `chat()`. Este método prepara el flujo de trabajo del agente para usar el `StreamingNode` en lugar de `ChatNode`.

Llamando al `events()` método en el controlador del agente que devuelve un generador de PHP que puede usarse para consumir el streaming como un objeto iterable.

```php
use App\Neuron\MyAgent;
use NeuronAI\Chat\Messages\UserMessage;

$handler = MyAgent::make()->stream(new UserMessage('How are you?'));

// Imprime la respuesta fragmento por fragmento en tiempo real
foreach ($handler->events() as $chunk) {
    echo $chunk->content;
}

// Estoy bien, ¡gracias! ¿Cómo puedo ayudarte hoy?
```

### Fragmentos de streaming

Cuando procesas la respuesta transmitida del agente, puedes esperar recibir tres tipos de objetos fragmento:

* `TextChunk`: representa una parte de texto
* `ReasoningChunk`: contiene fragmentos del resumen de razonamiento del modelo (solo disponible para modelos de razonamiento)
* `ToolCallChunk`: representa la solicitud del LLM de ejecutar una herramienta
* `ToolResultChunk`: contiene los resultados de la ejecución de la herramienta

Estos objetos son una capa de abstracción entre el flujo subyacente de mensajes dentro del agente para realizar una tarea y los datos necesarios en el lado del cliente para mantenerse informado sobre lo que está ocurriendo entre bastidores.

La composición del stream depende de la implementación de tu agente. Si el agente no tiene herramientas adjuntas, no hay posibilidad de recibir un `ToolCallChunk` o `ToolResultChunk` instancia, así que puedes iterar sobre el flujo de salida esperando solo fragmentos de texto y de razonamiento.

### Streaming y herramientas

Neuron admite herramientas y llamadas a funciones en combinación con la respuesta en streaming. Eres libre de proporcionar herramientas a tus Agentes y estas se manejarán automáticamente en medio del stream para continuar hacia la respuesta final.

Cuando el agente recibe una solicitud de llamada a una herramienta desde el LLM, transmitirá dos tipos de fragmentos: `ToolCallChunk`, `ToolResultChunk`.

Estas clases contienen la instancia de la herramienta llamada por el LLM, de modo que puedas mostrar al cliente una salida informativa sobre lo que el agente está haciendo para responder al mensaje del usuario.

Aquí tienes un ejemplo de cómo puedes manejar este escenario:

```php
use App\Neuron\MyAgent;
use NeuronAI\Chat\Messages\UserMessage;
use NeuronAI\Tools\Tool;

$handler = MyAgent::make()
    ->addTool(
        Tool::make(
            'get_server_configuration',
            'retrieve the server network configuration'
         )->addProperty(...)->setCallable(...)
    )
    ->stream(
        new UserMessage("What's the IP address of the server?")
    );

// Iterar fragmentos
foreach ($handler->events() as $chunk) {
    if ($chunk instanceof ToolCallChunk) {
        // Mostrar la llamada a la herramienta en curso
        echo "\n- Llamando a la herramienta: ".$chunk->tool->getName();
        echo "\n- Entrada: ".json_encode($chunk->tool->getInputs());
        continue;
    }
    
    if ($chunk instanceof ToolResultChunk) {
        echo "\n- Herramienta ".$chunk->tool->getName()." completada";
        echo "\n- Resultado: ".$chunk->tool->getResult();
        continue;
    }
    
    // Manejar TextChunk y ReasoningChunk
    echo $chunk->content;
}

// Déjame recuperar la configuración del servidor. 
// - Llamando a la herramienta: get_server_configuration
// - Herramienta get_server_configuration completada
// La dirección IP del servidor es: 192.168.0.10
```

### Obtener el resultado final

Cuando el modelo termina de transmitir la salida, puedes recuperar el final `AssistantMessage` instancia con el `getMessage()` método en el controlador del flujo de trabajo:

```php
$handler = MyAgent::make()->stream(...);

// Iterar fragmentos
foreach ($handler->events() as $chunk) {
    // ...
}

$message = $handler->getMessage(); // Obtener la instancia del mensaje final
echo $message->getContent();
```

### Monitorización y depuración

Muchas de las aplicaciones que construyas con Neuron contendrán varios pasos con múltiples invocaciones de llamadas a LLM. A medida que estas aplicaciones se vuelven cada vez más complejas, resulta crucial poder inspeccionar exactamente qué está ocurriendo dentro de tu sistema agéntico. La mejor manera de hacerlo es con [Inspector](https://inspector.dev/).

{% embed url="<https://docs.inspector.dev/guides/neuron-ai>" %}

## Adaptadores de stream

El sistema de adaptadores de stream de Neuron ofrece una forma flexible e independiente del protocolo para ayudarte a integrar fácilmente agentes impulsados por Neuron con tu stack frontend.

Los adaptadores de stream actúan como traductores entre los eventos internos de streaming de Neuron (fragmentos de texto, llamadas a herramientas, pasos de razonamiento) y protocolos frontend específicos como Vercel AI SDK o AG-UI.

También puedes conectar adaptadores para enviar datos transmitidos a una capa de transporte externa como [Pusher](https://pusher.com/), si quieres transmitir contenido a la interfaz desde un agente ejecutado en segundo plano.

Esta arquitectura te permite integrar sin problemas agentes de Neuron con varios frameworks frontend sin modificar la lógica principal de tu agente. Los adaptadores gestionan aspectos específicos del protocolo, como eventos del ciclo de vida de los mensajes, formato de eventos y seguimiento de IDs, manteniendo un comportamiento de streaming coherente en todos los proveedores (Anthropic, OpenAI, Gemini, Ollama, etc.). El sistema es altamente extensible; puedes crear adaptadores personalizados extendiendo `SSEAdapter` para implementar transformaciones de datos en streaming, o implementar directamente la `StreamAdapterInterface` para necesidades personalizadas.

<figure><img src="/files/b323b4f0174edfcae88cf01c6e648246fa8d4044" alt=""><figcaption></figcaption></figure>

Solo necesitas proporcionar una instancia del adaptador al `events()` método del controlador del agente usado para transmitir la respuesta del LLM.

### Adaptador AG-UI

Implementa el protocolo basado en eventos de streaming definido por AG-UI para la interacción en tiempo real entre agente e interfaz. Admite mensajes de texto, llamadas a herramientas, razonamiento y eventos del ciclo de vida.

Para más información, visita: <https://docs.ag-ui.com/concepts/events>

```php
use NeuronAI\Chat\Messages\Stream\Adapters\AGUIAdapter;

// Instruir al agente
$handler = MyAgent::make()
    ->stream(
        new UserMessage('What is the square root of 144?')
    );

// Proporcionar la instancia del adaptador al método events()
$stream = $handler->events(new AGUIAdapter());

// Procesar la respuesta
foreach ($stream as $line) {
    echo $line;
}
```

#### Conectar un frontend AG-UI

Un cliente AG-UI (como CopilotKit) no solo abre una conexión. Envía una solicitud POST con un cuerpo JSON llamado `RunAgentInput`, que contiene la conversación y los identificadores de la ejecución actual:

```json
{
  "threadId": "thread_123",
  "runId": "run_456",
  "messages": [
    {
      "id": "msg_1",
      "role": "user",
      "content": "What is the square root of 144?"
    }
  ],
  "tools": [],
  "state": {},
  "context": [],
  "forwardedProps": {}
}
```

Tu endpoint debe leer este payload, mapear los mensajes a objetos de mensaje de Neuron y pasar `threadId` y `runId` al constructor del adaptador. El adaptador los devuelve en los `RUN_STARTED` y `RUN_FINISHED` eventos, para que el cliente pueda correlacionar el stream con la ejecución que solicitó. Si los omites, el adaptador genera sus propios identificadores (útil para pruebas, pero un frontend AG-UI real espera recuperar sus propios IDs).

El adaptador también proporciona los encabezados HTTP requeridos por el transporte SSE a través del `getHeaders()` método. Recuerda enviarlos y vaciar la salida después de cada línea; de lo contrario, el stream puede quedarse atascado en los buffers de salida de PHP o en proxies.

Aquí tienes un ejemplo completo de endpoint:

```php
use NeuronAI\Chat\Messages\Stream\Adapters\AGUIAdapter;
use NeuronAI\Chat\Messages\UserMessage;

// Analizar el payload AG-UI RunAgentInput
$input = json_decode(file_get_contents('php://input'), true);

$messages = [];
foreach ($input['messages'] as $message) {
    if ($message['role'] === 'user') {
        $messages[] = new UserMessage($message['content']);
    }
}

// Devolver al stream los identificadores de thread y run del cliente
$adapter = new AGUIAdapter(
    threadId: $input['threadId'],
    runId: $input['runId'],
);

// Enviar los encabezados SSE requeridos por el protocolo
foreach ($adapter->getHeaders() as $name => $value) {
    header("{$name}: {$value}");
}

$stream = MyAgent::make()->stream($messages)->events($adapter);

foreach ($stream as $line) {
    echo $line;
    flush();
}
```

#### Eventos emitidos

El adaptador traduce los fragmentos de streaming de Neuron en los siguientes eventos AG-UI:

| Fragmento de Neuron           | Eventos AG-UI                                                                                                       |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Ciclo de vida de la ejecución | `RUN_STARTED`, `RUN_FINISHED`                                                                                       |
| `TextChunk`                   | `TEXT_MESSAGE_START`, `TEXT_MESSAGE_CONTENT`, `TEXT_MESSAGE_END`                                                    |
| `ReasoningChunk`              | `REASONING_START`, `REASONING_MESSAGE_START`, `REASONING_MESSAGE_CONTENT`, `REASONING_MESSAGE_END`, `REASONING_END` |
| `ToolCallChunk`               | `TOOL_CALL_START`, `TOOL_CALL_ARGS`, `TOOL_CALL_END`                                                                |
| `ToolResultChunk`             | `TOOL_CALL_RESULT`                                                                                                  |

Las herramientas adjuntas a un agente de Neuron se ejecutan en el servidor. El cliente es informado de la ejecución en curso a través de los `TOOL_CALL_*` eventos y recibe la salida de la herramienta en el `TOOL_CALL_RESULT` evento, seguido del mensaje de texto final del agente. Las herramientas definidas en el frontend y listadas en el campo `tools` de `RunAgentInput` (herramientas ejecutadas por el cliente) no son gestionadas por el adaptador.

El adaptador no emite los eventos de estado compartido de AG-UI (`STATE_SNAPSHOT`, `STATE_DELTA`, `MESSAGES_SNAPSHOT`), por lo que las funciones de sincronización de estado de los clientes AG-UI no están disponibles a través de este adaptador.

### Adaptador de Vercel AI SDK

Adaptador para el protocolo de flujo de datos de Vercel AI SDK: <https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol>

```php
use NeuronAI\Chat\Messages\Stream\Adapters\VercelAIAdapter;

// Instruir al agente
$handler = MyAgent::make()
    ->stream(
        new UserMessage('What is the square root of 144?')
    );

// Proporcionar la instancia del adaptador al método events()
$stream = $handler->events(new VercelAIAdapter());

// Procesar la respuesta
foreach ($stream as $line) {
    echo $line;
}
```

### Adaptadores personalizados

El método events() del controlador del agente acepta una instancia de StreamAdapterInterface. Así que eres libre de implementar esta interfaz con una implementación personalizada y pasarla al controlador. Así es como se ve la interfaz:

```php
interface StreamAdapterInterface
{
    /**
     * Transforma un fragmento de Neuron en una salida específica del protocolo.
     *
     * @param object $chunk Cualquier fragmento de Neuron (TextChunk, ToolCallChunk, etc.)
     * @return iterable<string> Una o más líneas/mensajes de salida
     */
    public function transform(object $chunk): iterable;

    /**
     * Obtiene los encabezados HTTP para este protocolo.
     *
     * @return array<string, string>
     */
    public function getHeaders(): array;

    /**
     * Secuencia de inicialización del protocolo (opcional).
     *
     * @return iterable<string>
     */
    public function start(): iterable;

    /**
     * Secuencia de terminación del protocolo (opcional).
     *
     * @return iterable<string>
     */
    public function end(): iterable;
}
```

Siempre puedes inspirarte en las implementaciones incluidas.
