> 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).

# Transmisión

Presentando la respuesta de la IA a tu usuario en tiempo real.

La transmisión 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="https://content.gitbook.com/content/GHx4l2LknIex7vFIUg1R/blobs/IYATPZdfnIJTqksj9NAy/ChatGPT-stream.gif" 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 `StreamingNode` en lugar de `ChatNode`.

Al llamar a `events()` método en el controlador del agente devuelto, obtienes 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('¿Cómo estás?'));

// 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 un fragmento de texto
* `ReasoningChunk`: contiene fragmentos del resumen de razonamiento del modelo (solo disponible para modelos de razonamiento)
* `ToolCallChunk`: representa que el LLM solicita la ejecución de 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 del 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` una instancia, por lo que puedes iterar sobre el flujo de salida esperando solo fragmentos de texto y razonamiento.

### Streaming y herramientas

Neuron admite herramientas y llamadas a funciones en combinación con la respuesta en streaming. Puedes proporcionar herramientas a tus agentes libremente y se manejarán automáticamente en medio del stream para continuar hacia la respuesta final.

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

Estas clases contienen la instancia de la herramienta llamada detrás por el LLM, de modo que puedas mostrar al cliente una salida informativa sobre lo que el agente está haciendo para responder al prompt 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',
            'recuperar la configuración de red del servidor'
        )->addProperty(...)->setCallable(...)
    )
    ->stream(
        new UserMessage("¿Cuál es la dirección IP del servidor?")
    );

// 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- La herramienta ".$chunk->tool->getName()." se completó";
        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
// - La herramienta get_server_configuration se completó
// 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();
```

### Monitoreo y depuración

Muchas de las aplicaciones que construyes con Neuron contendrán varios pasos con múltiples invocaciones de llamadas al 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 flujo

El sistema de adaptadores de flujo de Neuron proporciona una forma flexible, agnóstica del protocolo, para ayudarte a integrar fácilmente agentes impulsados por Neuron con tu stack de frontend.

Los adaptadores de flujo traducen los eventos internos de streaming de Neuron (fragmentos de texto, llamadas a herramientas, pasos de razonamiento) en eventos de protocolos frontend específicos como AG-UI.

Esta arquitectura te permite integrar sin problemas los agentes de Neuron con varios frameworks de frontend sin modificar la lógica central de tu agente. Los adaptadores manejan aspectos específicos del protocolo, como los eventos del ciclo de vida de los mensajes, el formato de los eventos y el seguimiento de IDs, mientras mantienen un comportamiento de streaming consistente 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 de streaming, o implementar directamente la `StreamAdapterInterface` para necesidades personalizadas.

<figure><img src="https://4076695836-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGHx4l2LknIex7vFIUg1R%2Fuploads%2F0Vv4CSAloxu40vUoZddx%2Fstreaming-adapter.png?alt=media&amp;token=eb8846c3-eef5-415a-bb2e-108f1ecd0cf2" alt=""><figcaption></figcaption></figure>

Solo necesitas proporcionar una instancia del adaptador al `events()` método del controlador del agente que se usa 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 y frontend. 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;

// Instruye al agente
$handler = MyAgent::make()
    ->stream(
        new UserMessage('¿Cuál es la raíz cuadrada de 144?')
    );

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

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

#### Conectando 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": "¿Cuál es la raíz cuadrada de 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 flujo puede quedar atascado en los búferes 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;

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

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

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

// Envía 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 a los siguientes eventos de AG-UI:

| Fragmento de Neuron           | Eventos de 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 `tools` campo de `RunAgentInput` (herramientas ejecutadas por el cliente) no son manejadas 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 Data Stream de Vercel AI SDK: <https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol>

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

// Instruye al agente
$handler = MyAgent::make()
    ->stream(
        new UserMessage('¿Cuál es la raíz cuadrada de 144?')
    );

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

// Procesa 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 puedes implementar libremente 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;

    /**
     * Obtén 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 integradas.
