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

# Actualización

{% hint style="warning" %}

### Actualización agéntica (recomendada)

Documentamos todo el proceso de actualización en un directorio dedicado **`vendor/neuron-core/neuron-ai/upgrade`**. Puedes indicar a tu agente de programación que use este directorio y recibirá automáticamente instrucciones precisas para actualizar tu código. Aquí tienes el prompt que puedes usar:

```
Actualicé la dependencia `neuron-core/neuron-ai` de la versión 3.x a la 4.x. 
Por favor, consulta la guía de actualización en `vendor/neuron-core/neuron-ai/upgrade` 
y actualiza el código de mi aplicación si es necesario.
```

{% endhint %}

## Actualizar a v4 desde v3

En esta nueva versión mayor, las API públicas de los componentes de Neuron no cambiaron drásticamente (minimizamos el impacto tanto como fue posible). Nos hemos centrado en mejorar el componente más importante sobre el que se construye todo el framework. Workflow es la base de toda la arquitectura; los cambios implementados en esta nueva versión pueden afectar tu código, especialmente si usas patrones como aprobación de herramientas, interrupción y adaptadores de streaming. Recomendamos usar las guías de actualización para agentes de programación.

También aprovechamos este lanzamiento para corregir otros problemas críticos surgidos en v3, como el flujo de aprobación de herramientas en el Agent, 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, para ayudarte a crear productos de IA exitosos en PHP.

## Actualizando dependencias

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

```json
{
    "require": {
        ...,
        "neuron-core/neuron-ai": "^4.0",
    },
}
```

El `inspector-php` el paquete se eliminó de las dependencias predeterminadas. Así que tienes que instalarlo en tu aplicación si quieres conectar tu agente al [Inspector](https://inspector.dev/) panel de monitoreo:

```shellscript
composer require inspector-apm/inspector-php
```

## Cambios de alto impacto

### Nuevas habilidades agénticas

Las habilidades para agentes de programación se han reescrito y reorganizado por completo para reflejar las mejoras y las nuevas funciones de esta nueva versión mayor. Recomendamos eliminar el directorio skills dentro de la carpeta de tu agente de programación (p. ej. `.claude`, `.agent`) y seguir de nuevo la guía de instalación.

<a class="button primary" data-icon="arrow-right-long">Habilidades agénticas</a>

### Tipo de retorno del Agent

En esta nueva versión mayor, la entidad Agent fue objeto de una importante refactorización para eliminar muchas fricciones en casos de uso avanzados y hacer que la clase del agente sea más utilizable como un Workflow normal del que hereda.

El impacto más importante es el tipo de retorno. El Agent devuelve una instancia de `AgentState` que es una extensión del `WorkflowState` subyacente con un par de métodos auxiliares para mantener lo más posible sin cambios las API externas vistas por tu aplicación.

El cambio más impactante está en el `stream()` método. Sin el `AgentHandler` el método devuelve directamente el generador.

```php
foreach ($agent->stream(new UserMessage("Hello")) as $event) {
    if ($event instanceof TextChunk) {
        echo $event->content;
    }
}
```

Si interactúas con el protocolo del frontend, debes registrar el adaptador de streaming en la instancia del agente.

```php
$generator = MyAgent::make()
    ->setStreamAdapter(new AGUIAdapter('thread_id'))
    ->stream(
        new UserMessage("Hello")
    );

foreach ($generator as $event) {
    echo $event;
    ob_flush();
    flush();
}
```

no cambia nada para `structured()` y `chat()`.

### La herramienta se vuelve completamente abstracta

El `Tool` La clase ahora es abstracta y ya no puede usarse directamente. Su diseño ahora está pensado para ser extensible, permitiéndote implementar tus propias herramientas con menos código y más flexibilidad.

También eliminamos el constructor de la clase abstracta para que puedas especificar el nombre y la descripción de la herramienta como propiedades normales de la clase en lugar de llamar al constructor padre. Puedes usar libremente un constructor de clase solo si quieres pasar dependencias externas a la herramienta:

```php
class MyTool extends Tool
{
    protected string $name = 'my_tool';
    
    protected ?string $description = 'What the tool does.';
    
    public function __construct(protected string $apiKey){}
    
    public function __invoke()
    {
        ...
    }
}
```

### Eliminar WorkflowHandler

El componente Workflow fue objeto de una importante refactorización para simplificar su uso y sus API públicas. Al trabajar con Workflow en la versión anterior, debías llamar al `init()` método para obtener la instancia de `WorkflowHandler` y luego llamar a `run()` o `events()` en el handler para ejecutar finalmente el flujo de trabajo:

```php
$handler = MyWorkflow::make()->init();

// Ejecución de una sola pasada
$finalState = $handler->run();

// Transmitir eventos
foreach($handler->events() as $chunk) {
    // ...
}
$finalState = $handler->getResult();
```

Tras una simplificación drástica de la lógica de ejecución del flujo de trabajo, el handler ya no es necesario y es posible invocar los dos métodos `run()` y `events()` directamente sobre el workflow.

```php
// Ejecución de una sola pasada
$finalState = MyWorkflow::make()->run();

// Transmitir eventos
$generator = MyWorkflow::make()->events();
foreach($generator as $chunk) {
    // ...
}
$finalState = $generator->getResult();
```

### Interrupción/Reanudación del Workflow

La arquitectura de la ejecución del workflow y sus capacidades de interrupción se rediseñó para facilitar la gestión de interrupciones y la aprobación de herramientas, pero también abrir la puerta a la implementación de workflows agénticos duraderos y resistentes a fallos.

#### Eliminar la excepción WorkflowInterrupt

En caso de interrupción, el Workflow no lanza la especial `WorkflowException` para informar al script llamador sobre la interrupción. Simplemente devuelve un estado "interrumpido":

```php
$state = $workflow->run();

if ($state->isInterrupted()) {
    // Usa la información de la solicitud
    $request = $state->getInterruptRequest();
    // El token de reanudación se genera automáticamente y está disponible en la instancia del workflow
    $workflowId = $workflow->getWorkflowId();
}
```

No más bloque try/catch.

Esto cambia el [Aprobación de herramientas](/neuron-v3-es/agente/tool-approval.md) flujo. Consulta la documentación en caso de que uses este middleware en tus agentes.

#### Carga útil de reanudación como array simple

La solicitud de interrupción que propagas desde el nodo ahora solo es una señal para llevar información del nodo al script llamador externo. Para reanudar el workflow ya no necesitas devolver la solicitud al workflow. La carga útil de reanudación ahora es simplemente un array:

```php
// Ejemplo de un nodo que llama a interrupt()
class InterruptableNode extends Node
{
    public function __invoke(FirstEvent $event, WorkflowState $state): NextEvent
    {
        $payload = $this->interrupt(new ApprovalRequest('human input needed'));
        $state->set('received_feedback', $payload);
        return new NextEvent();
    }
}

// Define la carga útil de entrada — será devuelta por el método interrupt()
$payload = ['action_id' => 'approve'];

$finalState = $workflow->resume($payload);
```

### Instrucciones del Agent

Las instrucciones del Agent deben ser una instancia del nuevo tipo de mensaje `SystemMessage`. Puedes pasar simplemente la cadena al constructor para hacerla compatible con esta nueva versión:

```php
use NeuronAI\\Chat\\Messages\\SystemMessage;

class YouTubeAgent extends Agent
{
    protected function provider(): AIProviderInterface
    {
        ...
    }
    
    protected function instructions(): SystemMessage
    {
        return new SystemMessage(
            "Eres un agente de IA especializado en escribir resúmenes de videos de YouTube"
        );
    }
}
```

### Aprobación de herramientas

El flujo de aprobación de herramientas fue reescrito por completo. La clase Agent ahora gestiona todo el proceso. Solo necesitas ocuparte de renderizar la interfaz para que los usuarios puedan decidir si aprobar o rechazar una llamada a una herramienta.

El estado de las herramientas que requieren aprobación se almacena en el historial del chat dentro de los últimos `ToolCallMessage`. Esto te permite diseñar la interfaz para que solo renderice los mensajes del historial del chat, y cuando encuentre una `ToolCallMessage` puedes comprobar el estado de aprobación de las herramientas para mostrar las acciones Aprobar/Denegar, o la llamada normal a la herramienta ya se realizó.

<a href="/neuron-v3-es/agente/tool-approval.md" class="button primary" data-icon="arrow-right-long">Aprobación de herramientas</a>

#### Nueva herramienta `requiresApproval()` método

Introdujimos el `requiresApproval()` método en la clase Tool para determinar si se necesita aprobación en función de los argumentos de la llamada a la herramienta:

```php
class MyTool extends Tool
{
    ...,
    
    public function requiresApproval(array $inputs): bool
    {
        return $inputs['amount'] > 100;
    }
}
```

Para activar el flujo de aprobación de herramientas siempre necesitas adjuntar el [ToolApproval](/neuron-v3-es/agente/tools.md#tool-approval) middleware al Agent. La política de aprobación personalizada en el middleware tiene precedencia sobre la definida en la `requiresApproval()` método.

### Esquema de base de datos para la persistencia del workflow

Debido a los cambios en el modelo de ejecución del workflow, el esquema de base de datos para la persistencia entre interrupciones se ha cambiado para admitir las nuevas funciones. Consulta la sección dedicada para estar preparado para ejecutar consultas SQL y empezar con el nuevo formato de base de datos.

<a href="/neuron-v3-es/flujo-de-trabajo/persistence.md" class="button primary" data-icon="arrow-right-long">Persistencia</a>

### Dependencia de Guzzle eliminada

En la versión anterior, guzzle era una dependencia obligatoria de composer para impulsar el predeterminado del framework `GuzzleHttpClient`. Esta nueva versión mayor incluye por defecto `CurlHttpClient` que no requiere ninguna dependencia de paquete, solo `ext-curl` que debería estar ya disponible en cualquier instalación de PHP.

Si estás pasando una instancia personalizada de GuzzleHttpClient a los componentes del framework, tienes que requerir explícitamente guzzle en tu aplicación.

```shellscript
composer require guzzlehttp/guzzle
```

### Filtrado integrado del almacén vectorial

`VectorStoreInterface` se cambió para admitir capacidades de filtrado integradas. Los métodos cambiaron su nombre y su firma. Si estás implementando `VectorStoreInterface` por tu cuenta, debes migrar tu implementación al nuevo contrato.

<a href="/neuron-v3-es/rag/vector-store.md" class="button primary" data-icon="arrow-right-long">Almacenes vectoriales</a>

### Kit de herramientas de calculadora

Resultó que los modelos tenían muchas dificultades para componer múltiples llamadas a herramientas para resolver expresiones matemáticas y, en cambio, son realmente buenos representando expresiones. El CalculatorToolkit se refactorizó con una principal `Evaluate` herramienta, eliminando las herramientas que representaban operaciones matemáticas individuales: `sumar`, `restar`, `multiplicar`, etc. Ahora el modelo puede describir la fórmula que quiere resolver y la herramienta evaluate interpretará esta expresión y devolverá el resultado, todo en una sola pasada, sin importar lo compleja que sea la expresión. Esta estrategia también ahorra muchos tokens, ya que se envían menos herramientas a la API del proveedor.

<a href="/neuron-v3-es/agente/tools.md#toolkits" class="button primary" data-icon="arrow-right-long">Kit de herramientas de calculadora</a>

### Historial del chat

El historial del chat fue objeto de una importante refactorización para lograr dos objetivos:

* Separar el almacén de mensajes de la gestión del historial y la ventana de contexto
* Facilitar la integración de Neuron en tu aplicación

`ChatHistoryInterface` fue eliminada. Las nuevas API públicas están respaldadas por la nueva `MessageStoreInterface`. Como su nombre indica, el almacén de mensajes es responsable solo de guardar tus mensajes en una capa de persistencia. Marca los mensajes que salen de la ventana de contexto como `archivados` en lugar de eliminarlos, para que el modelo vea un hilo recortado mientras tu almacenamiento conserva el historial completo.

{% hint style="warning" %}
Recomendamos confiar en el proceso de actualización agéntica para migrar tu implementación de Agent y del historial a las nuevas API.
{% endhint %}

<a href="/neuron-v3-es/agente/chat-history-and-memory.md" class="button primary" data-icon="arrow-right-long">Historial del chat</a>

### Firma del middleware

El motor de Workflow te permite declarar `recursos` que quieres transportar durante la ejecución y que no será necesario guardar durante las interrupciones. El middleware también recibe recursos, así que puedes interactuar con estos elementos durante la ejecución del workflow. En un Agent, por ejemplo, los recursos contienen herramientas, instrucciones del agente y el historial del chat. Los métodos del middleware ahora reciben un argumento adicional `$resources`.

```php
interface WorkflowMiddleware
{
    public function before(
        NodeInterface $node, 
        Event $event, 
        WorkflowState $state, 
        WorkflowResources $resources, // El middleware recibe recursos junto al estado.
    ): void;

    public function after(
        NodeInterface $node, 
        Event $result, 
        WorkflowState $state, 
        WorkflowResources $resources, // El middleware recibe recursos junto al estado.
    ): void;
}
```

### Cambio del contrato de ReaderInterface

El contrato tenía un único método estático `getText()`. El método estático hace que las verdaderas instancias de lectores con construcciones personalizadas no tengan sentido. La interfaz ahora exige la implementación de instancias concretas en lugar de las estáticas:

{% hint style="warning" %}
**Los lectores personalizados deben ajustarse en consecuencia**. La actualización agéntica cubrirá esta refactorización.
{% endhint %}

```php
interface ReaderInterface
{
    public function read(string $filePath): string;
}
```

## Impacto medio

### Monitorización

El framework está migrando al [dispatcher de eventos PSR-14](https://www.php-fig.org/psr/psr-14/) interfaz, en lugar del \SplObserver nativo de PHP. Hemos mantenido las interfaces existentes, y también el `LogObserver` usando adaptadores, pero están marcados como `@deprecated`.

Esto facilitará integrar los agentes de Neuron y los workflows agénticos en general con otros frameworks y aplicaciones existentes.

<a href="/neuron-v3-es/agente/observability.md" class="button primary" data-icon="arrow-right-long">Monitorización</a>

### Los proveedores devuelven ProviderResponse

Los métodos del proveedor de IA `chat()` y `stream()` ahora devuelven `ProviderResponse` en lugar de `Mensaje`. El `ProviderResponse` envuelve el mensaje del asistente y proporciona acceso al cuerpo bruto de la respuesta HTTP y a los encabezados.

**Esto solo afecta al uso independiente del proveedor.** Cuando los proveedores se usan dentro de un Agent (a través de `chat()`, `stream()`, o `structured()` en el propio Agent), no se necesita ningún cambio — el Agent gestiona el `ProviderResponse` internamente.

Solo necesitas refactorizar el código que llama directamente a métodos del proveedor, como en scripts, controladores, comandos o workflows personalizados.

```php
$response = $provider->chat(new UserMessage(...));

// Obtén el mensaje de asistencia
$response->message();

// Obtén el cuerpo bruto del proveedor
$response->body();

// Obtén los encabezados
$response->headers();
```

### Cambios en AIProviderInterface

Eliminamos `messageMapper()` y `toolPayloadMapper()` de la `AIProviderInterface`, y se introdujo el nuevo `getModel()` método. Si tienes alguna implementación personalizada de proveedor que use directamente esta interfaz, necesitas ajustarla correctamente.

```php
interface AIProviderInterface
{
    public function getModel(): string;

    public function systemPrompt(string|array|null $prompt): AIProviderInterface;

    public function setTools(array $tools): AIProviderInterface;

    public function chat(Message ...$messages): ProviderResponse;

    public function stream(Message ...$messages): Generator;

    public function structured(array|Message $messages, string $class, array $response_schema): ProviderResponse;

    public function setHttpClient(HttpClientInterface $client): AIProviderInterface;
}
```

## Nuevas funciones

### Eventos personalizados de AG-UI

AG-UI usa sus nativos `STEP_STARTED`, `STEP_FINISHED`, `ACTIVITY_SNAPSHOT`, y `CUSTOM` eventos. Vercel emite `data-*` fragmentos transitorios, de modo que la información intermedia del dominio está disponible para la interfaz sin añadirse al historial de mensajes del asistente.

Puedes asignar eventos de la aplicación por su clase exacta cuando el código del dominio deba permanecer independiente de los objetos portátiles de eventos de Neuron.

<a href="/neuron-v3-es/agente/streaming.md#custom-events" class="button primary" data-icon="arrow-right-long">Eventos personalizados del protocolo de UI</a>

### Canales de streaming

A medida que los agentes se vuelven más interactivos y capaces, los desarrolladores de aplicaciones se ven cada vez más obligados a ejecutarlos fuera del ciclo de vida de la petición HTTP debido a sus límites de tiempo de espera, lo que deja la salida transmitida sin forma de llegar a la interfaz. Los canales entregan la salida transmitida de los Agents y Workflows a la interfaz de usuario a través de sistemas de streaming externos como [Pusher](https://pusher.com/), websockets, una cola de Redis o lo que sea que tu aplicación ya use.

<a href="/neuron-v3-es/agente/streaming.md#delivery-channels" class="button primary" data-icon="arrow-right-long">Canales de streaming</a>

### Transmisión parcial de eventos

Los servidores en tiempo real como Pusher, Socketi o cualquier servidor compatible con Pusher suelen poner un límite al tamaño de la carga útil. Pusher limita un evento a 10 KB; Reverb usa por defecto lo mismo, Soketi 100 KB.

Para admitir el streaming cuando tu servidor en tiempo real tiene ese límite, un evento que no cabe en el tamaño máximo — normalmente un resultado de herramienta o una instantánea de mensaje — se divide en fragmentos consecutivos. Además, los servidores no garantizan que los fragmentos lleguen en orden ni que nunca se entremezclen. Por eso el navegador debe poder reconciliar esta fragmentación y el orden para ofrecer un streaming coherente a los componentes de tu interfaz.

Neuron 4 incorpora un módulo TypeScript de primera parte que lleva esta capacidad a tu frontend.

<a href="/neuron-v3-es/agente/streaming.md#event-fragmentation" class="button primary" data-icon="npm">@neuron-core/streaming</a>

### Memoria semántica

Tu agente ahora puede recordar lo que importa a una persona a lo largo de múltiples conversaciones. Los usuarios con varios hilos activos pueden ver cómo el agente recuerda sus conversaciones y preferencias pasadas.

V4 introduce el componente `SemanticMemoryRetrieval` que almacena y recupera automáticamente recuerdos a lo largo de las sesiones del usuario. Pertenece al agente RAG y puede personalizarse o reemplazarse para adaptarse a la lógica de tu aplicación.

<a href="/neuron-v3-es/rag/retrieval.md#semantic-memory" class="button primary" data-icon="arrow-right-long">Memoria semántica</a>

### StoppableHttpClient

Detén una respuesta transmitida en mitad del proceso, para un botón de "dejar de generar". El proveedor mantiene el texto transmitido hasta ese momento como contenido parcial y lo guarda en el historial del chat.

<a href="/neuron-v3-es/agente/async.md#stoppablehttpclient" class="button primary" data-icon="arrow-right-long">Cliente HTTP</a>

### Clasificador

En Neuron AI ya podías responderles con [salida estructurada](https://docs.neuron-ai.dev/agent/structured-output): describe las respuestas permitidas, obliga la respuesta a una clase PHP, lee la propiedad. Es el mismo mecanismo detrás de la [IA como juez](https://docs.neuron-ai.dev/agent/evaluation#ai-as-a-judge) patrón en las evaluaciones de agentes. Funciona bien cuando la decisión se toma de vez en cuando. El problema empieza cuando lo quieres en cada turno de cada conversación, porque un modelo generativo produce texto un token tras otro, y estás pagando a un escritor de propósito general, con su latencia y su precio, para obtener una palabra. Una barrera de seguridad que duplica el tiempo de respuesta del agente se desactiva ante la primera queja. Un juez que cuesta tanto como el agente que evalúa se ejecuta sobre una muestra del tráfico, si es que se ejecuta.

Un clasificador no tiene conversación ni texto que transmitir. El clasificador de IA de Neuron tiene su propio contrato, `ClassifierInterface`, para hacer preguntas cerradas sobre alguna entrada y recibir probabilidades a cambio. Puedes usarlo para tomar decisiones dentro de tus Agents o Workflows, como guardrails, inyecciones de prompt, puntuar la calidad de una respuesta, etc.

<a href="/neuron-v3-es/proveedores/classifier.md" class="button primary" data-icon="arrow-right-long">Clasificador</a>
