> 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/descripcion-general/upgrade.md).

# Actualizar

## Actualizar a la v3 desde la v2

En esta nueva versión mayor, las APIs públicas de los componentes de Neuron no cambiaron drásticamente (minimizamos el impacto tanto como fue posible), pero la arquitectura subyacente de Agent, RAG y el sistema de mensajes se ha reconstruido por completo sobre el componente Workflow, que ahora impulsa todo el framework.

Ahora Agent y RAG ya no son objetos simples, sino flujos de trabajo. Heredan funciones que eran imposibles de integrar en la implementación independiente anterior, como:

* El sistema unificado de [mensajería](/neuron-v3-es/agente/messages.md#the-unified-messaging-layer) para agentes multimodales
* Compatibilidad nativa con [aprobación de herramientas](/neuron-v3-es/agente/middleware.md#human-in-the-loop) y flujos human-in-the-loop totalmente personalizables
* Multiagente [streaming](https://docs.neuron-ai.dev/workflow/streaming) y colaboración.

También aprovechamos esta versión para corregir otros problemas críticos de diseño surgidos en la v2, como **la compatibilidad completa con modelos de razonamiento en todos los proveedores**y otras mejoras de diseño para tener más libertad de evolucionar el framework con menos cambios incompatibles en el futuro.

Seguimos trabajando para ofrecer la mejor experiencia posible para desarrolladores, y ayudarte a crear productos de IA exitosos en PHP.

## Actualización de dependencias

Debes actualizar las siguientes dependencias en el `composer.json` archivo de tu aplicación:

* **neuron-core/neuron-ai** a **^3.0**

## Cambios de alto impacto

### Nuevo espacio de nombres de Agent

La clase Agent y las clases y traits relacionados se han movido del directorio raíz al espacio de nombres dedicado `NeuronAI\Agent`.

Debes actualizar el espacio de nombres en los archivos donde uses la clase Agent, de:

```php
use NeuronAI\Agent;
```

A:

```php
use NeuronAI\Agent\Agent;
```

Lo mismo para la clase SystemPrompt. El nuevo espacio de nombres es `NeuronAI\Agent\SystemPrompt`.

### Eliminar chatAsync()

El `chatAsync()` el método fue eliminado por completo de `AgentInterface`. Si estás usando este método en tu aplicación, tienes que cambiar al nuevo patrón asíncrono.

<a href="/pages/1b8bc4e0ca14c69d16d2a127a3b1ef57782941c4" class="button primary" data-icon="arrow-right-long">Aprende sobre Async</a>

### Tipo de retorno de Agent

Como Agent ahora es un flujo de trabajo, tienes APIs ligeramente diferentes para ejecutar realmente el agente y recuperar la respuesta del LLM.

Anteriormente obtenías directamente una instancia de Message desde el `chat()` método. Ahora el método chat devuelve un estado de flujo de trabajo que puedes usar para recuperar la respuesta final del agente.

El estado del agente devuelto te permite acceder fácilmente a la respuesta del LLM, pero también hace posible inspeccionar otros aspectos de la ejecución interna del agente. Aquí tienes un ejemplo de la nueva sintaxis para ejecutar un agente y mostrar el contenido generado por el LLM.

```php
// Las versiones anteriores de chat() devuelven la respuesta del LLM
$message = MyAgent::make()->chat(new UserMessage("Hola, ¿quién eres?"));

// V3 - necesitas llamar a "getMessage()"
$message = MyAgent::make()
    ->chat(new UserMessage("Hola, ¿quién eres?"))
    ->getMessage();

echo $message->getContent();
```

### Bloques de contenido de mensajes

Los bloques de contenido ahora reemplazan el antiguo enfoque basado en "adjuntos". El sistema heredado de adjuntos ha sido eliminado. Para migrar:

**Enfoque antiguo** (ya no disponible):

```php
$message = new UserMessage('Analiza esto');
$message->addAttachment(new Image($url, AttachmentContentType::URL));
```

**Nuevo enfoque**:

```php
// Mensaje de texto simple (compatible con versiones anteriores)
$message = new UserMessage("Hola");

// Nuevo formato para pasar imágenes, archivos, etc.
$message = new UserMessage([
    new TextBlock('Analiza esto'),
    new ImageBlock($url, SourceType::URL)
]);

// Añadir más bloques
$message->addContent(
    new TextBlock('Recuerda responder como si fueras un conserje profesional.')
);

// Imprimir todos los bloques de contenido de texto
echo $message->getContent();
```

El método `getContent()` no cambió, pero ahora devuelve todos los bloques de texto concatenados, omitiendo los tipos multimedia.

La composición de bloques desbloquea la compatibilidad multimodal y puede ser muy útil si necesitas inyectar instrucciones o indicaciones adicionales de forma dinámica durante la ejecución.

<a href="/pages/486423c4246cb85a9e7816bfb932ace3778a684a" class="button primary" data-icon="arrow-right-long">Aprende sobre Mensajes</a>

### Fragmentos de streaming

En versiones anteriores, la interfaz de streaming devolverá una cadena simple para cada fragmento de respuesta del LLM, y `ToolCallMessage`, o `ToolCallResultMessage` instancias directamente para operaciones relacionadas con herramientas. Esto crea un acoplamiento demasiado directo entre las instancias de mensaje y tu aplicación al leer el stream.

Implementamos clases de fragmento dedicadas `TextChunk`, `ReasoningChunk`, `ToolCallChunk`, `ToolResultChunk`y otras, para tener contenedores dedicados para cada tipo de delta del stream. Esta separación más clara de responsabilidades abrió la puerta a la implementación del [sistema de adaptadores](#streaming-adapters)y nos da más libertad para mejorar esta capa en el futuro con menos cambios incompatibles en el sistema unificado de mensajes.

#### ToolCallChunk

En la versión anterior, Neuron transmitía directamente el `ToolCallMessage` instancia con la lista de herramientas involucradas en la iteración. Ahora obtienes una `ToolCallChunk` dedicada para cada herramienta que el modelo está solicitando ejecutar.

<a href="/pages/fad08628c623aa0057c38c6113132463efcd394b" class="button primary" data-icon="arrow-right-long">Leer más sobre streaming</a>

### Salida estructurada

Ampliamos el papel del `SchemaProperty` atributo para que sea la fuente de verdad de la definición del esquema JSON de una propiedad de clase. Ahora admite `mín`, `máx`, `longitud mínima`, `longitud máxima`, `anyOf`.

```php
use NeuronAI\StructuredOutput\SchemaProperty;

class Person 
{
    #[SchemaProperty(
        description: 'El nombre de usuario.',
        required: true,
        minLength: 3,
        maxLength: 255,
    )]
    public string $name;
    
    #[SchemaProperty(
        description: 'Lo que al usuario le encanta comer.', 
        required: false,
        min: 18,
        max: 64,
    )]
    public ?int $age = null;
}
```

#### Array de objetos

Si una propiedad es un array de un objeto estructurado, ya no necesitas especificar el doc-block de los tipos de propiedad; solo tienes que listarlos en el `anyOf` argumento:

```php
class Report
{
    #[SchemaProperty(
        description: 'El contenido del informe', 
        required: true,
        anyOf: [TextBlock::class, TableBlock::class, ImageBlock::class]
    )]
    public array $content;
}
```

<a href="/pages/c87b9f52c53c6b45396cda3d4cda8008e405d5cc" class="button primary" data-icon="arrow-right-long">Salida estructurada</a>

### Solicitud de interrupción del flujo de trabajo (humano en el proceso)

En la versión anterior, cuando solicitabas una interrupción dentro de un Node, podías pasar un array de datos para informar al cliente sobre el motivo y las acciones detrás de la interrupción.

{% code title="Sintaxis antigua" %}

```php
$feedback = $this->interrupt(['message' => '¿quieres aprobarlo?']);
```

{% endcode %}

Este método con tipado perezoso provocó inconsistencias y errores. Introdujimos el `InterruptRequest` primitivo para ayudarte a crear flujos de interrupción con una estructura tipada para una integración segura en la UI.

{% code title="Nueva sintaxis" %}

```php
$feedback = $this->interrupt(new ApprovalRequest(
    reason: '¿Quieres aprobarlo?',
    actions: [
        new Action(...)
    ]
));
```

{% endcode %}

Aprende más en la sección dedicada de la documentación.

<a href="/pages/85f30a9c4c916961e20c4c46843dfe445efbc151" class="button primary" data-icon="arrow-right-long">Interrupción del flujo de trabajo</a>

### Cambio en la persistencia de la base de datos del flujo de trabajo

El nombre de las columnas de la tabla de persistencia de la base de datos del flujo de trabajo cambió:

* data -> interrupt

<a href="/pages/9ca4dd9fb4eab92642a1236070e81e9f0bc2c7b4" class="button primary" data-icon="arrow-right-long">Persistencia del flujo de trabajo</a>

## Impacto medio

### Renombrar ToolCallResultMessage

Esta clase fue renombrada a `ToolResultMessage`.

### Monitorización y observadores

Las entidades Agent, RAG y Workflow ya no implementan la interfaz de PHP `\SplSubject` y las clases observer ya no implementan la `\SplObserver` interfaz. Introdujimos la nueva `ObserverInterface` que debe ser implementada solo por escuchadores de eventos como `LogObserver`. Esta estructura más ligera nos ayudó a hacer observables los bloques de construcción del flujo de trabajo, como Workflow, node y middleware. Esto significa que puedes emitir eventos desde tus nodos personalizados, y solo necesitas crear y registrar tu observer personalizado para escuchar estos eventos.

Lee más en la [sección de Monitorización](/neuron-v3-es/agente/observability.md).

### Eliminar HttpClientOptions

Esta clase fue eliminada a favor de una abstracción completa del HttpClient dentro del framework. Adoptamos un patrón de adaptadores para permitirte inyectar clientes HTTP personalizados en los componentes del framework y personalizar su configuración. El adaptador del cliente Guzzle también admite stack de handlers, encabezados personalizados, etc.

Puedes ver un ejemplo de cómo personalizar la configuración del cliente HTTP en la [Async](/neuron-v3-es/agente/async.md) sección.

### Qdrant 1.10.x

Los componentes del almacén vectorial de Qdrant se actualizaron para admitir las nuevas [APIs de consulta](https://api.qdrant.tech/api-reference/search/query-points) que están incluidas a partir de la versión 1.10.x. Si usas una versión anterior de la base de datos Qdrant, necesitas actualizar tu instancia.

### Firma de los métodos de AbstractChatHistory

Si has implementado un componente personalizado de historial de chat, necesitas ajustar la firma de los métodos hook. Cambiaron el nivel de visibilidad, de public a protected, y ya no tienen tipo de retorno:

```php
class MyChatHistory extends AbstractChatHistory
{
    protected function setMessages(array $messages): void
    {
        // Gestiona el guardado de todo el historial de una vez.
    }

    protected function onNewMessage(Message $message): void
    {
        // Gestiona la adición de un solo mensaje.
    }

    protected function onTrimHistory(int $index): void
    {
        // Cuando se activa el recorte, los mensajes en la posición desde cero hasta $index deben eliminarse.
    }

    protected function clear(): void
    {
        // Elimina todos los mensajes.
    }
}
```

## Nuevas funciones

### Aprobación de herramientas y aprobación condicional

Gracias al patrón human in the loop compatible con la arquitectura subyacente del flujo de trabajo, creamos un middleware integrado para habilitar la aprobación de herramientas en tu agente como una función plug and play:

```php
new ToolApproval(
    tools: [
        BuyTicketTool::class => function (array $args): bool {
            return $args['amount'] > 100;
        }
    ]
)
```

<a href="/pages/b17ff1200828767959e6ec06f777645020907a3a#tool-approval-human-in-the-loop" class="button primary" data-icon="arrow-right-long">Aprobación de herramientas</a>

### Proveedor dedicado de Mistral

El proveedor de Mistral ya no es una implementación pura de OpenAI, sino que evolucionó con su propia implementación de formato de API para admitir entrada multimodal y modelos de razonamiento.

<a href="/pages/3f7d9680752b9f27f17164c1d23ad7e0dd0de062#mistral" class="button primary" data-icon="arrow-right-long">Proveedor de Mistral AI</a>

### Proveedor de Cohere AI

Esta versión incluye un proveedor totalmente nuevo para admitir la plataforma de inferencia de Cohere tanto en la nube como desplegada de forma privada.

<a href="/pages/3f7d9680752b9f27f17164c1d23ad7e0dd0de062#cohere" class="button primary" data-icon="arrow-right-long">Proveedor de Cohere AI</a>

### Proveedores de texto a voz

Gracias a la nueva composición de bloques de los mensajes, ahora es fácil tratar con la multimodalidad de entrada y salida. En esta versión incluimos un par de proveedores que puedes usar para procesar contenidos de audio.

<a href="/pages/385f6abb457778c4b125c787af4c8402baf57965" class="button primary" data-icon="arrow-right-long">Proveedores de texto a voz</a>

### Adaptadores de streaming

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

Esta arquitectura te permite integrar sin problemas los agentes de Neuron con varios frameworks de frontend (React, Vue, etc.) sin modificar la lógica principal de tu agente.

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

<a href="/pages/fad08628c623aa0057c38c6113132463efcd394b#stream-adapters" class="button primary" data-icon="arrow-right-long">Aprende más sobre Adaptadores</a>

### Bloque de contenido de ID de archivo

Normalmente puedes adjuntar archivos a tu mensaje (imágenes o documentos) como URLs, o codificados en formato base64. Muchos proveedores te permiten subir archivos a su plataforma una vez y referenciar esos archivos con un simple ID en el mensaje. Esto puede generar un gran ahorro en el consumo de tokens y puede mejorar el tiempo de respuesta del modelo.

Después de recibir el ID del archivo de la plataforma del proveedor, puedes agregar un bloque de archivo a tu mensaje con `SourceType::ID`.

```php
// Haz referencia a un ID de archivo cargado previamente en la plataforma del proveedor
$message = new UserMessage([
    new TextBlock('Analiza esto'),
    new FileBlock("file_id_xxxx", SourceType::ID)
]);
```

Puedes hacer lo mismo con Image, Video, etc., según las especificaciones de tu proveedor.

### Middleware

Middleware proporciona una forma de controlar de cerca lo que ocurre dentro del flujo de trabajo y, por lo tanto, también en tus Agents y RAGs, ya que ahora también son flujos de trabajo.

La ejecución central del Workflow implica llamar a nodos según los eventos devueltos por otros nodos. Middleware expone ganchos para intervenir en `antes` y `después` la ejecución de los nodos:

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

Esta arquitectura se ha utilizado para crear los [middlewares integrados](/neuron-v3-es/agente/middleware.md) para la clase Agent, como la resumización del contexto o la aprobación de herramientas.

<a href="/pages/076be1deecea7c3886b4771953421600ed869dbd" class="button primary" data-icon="arrow-right-long">Aprende más sobre Middleware</a>
