
# Neuron Пам’ять і автомат станів перевірки

Цей шаблон корисний, коли агент має зберігати контекст розмови між повторними раундами перевірки людиною, а загальним життєвим циклом і далі керує Queuety.

Queuety керує автоматом станів перевірки, а Neuron — пам’яттю агента для потоку створення тексту.

## Чим тут корисна пам’ять Neuron

Якщо перевіряльник відхиляє чернетку й просить внести зміни, наступному виклику агента не доведеться відновлювати весь контекст із нуля.

Neuron добре підходить для цього завдяки `SQLChatHistory`: агент може продовжувати роботу в тій самій гілці розмови, а Queuety керує рішеннями перевіряльника й раундами правок.

## Агент Neuron з історією на основі SQL

```php
namespace App\Neuron;

use NeuronAI\Agent\Agent;
use NeuronAI\Chat\History\ChatHistoryInterface;
use NeuronAI\Chat\History\SQLChatHistory;
use NeuronAI\Providers\AIProviderInterface;
use NeuronAI\Providers\Anthropic\Anthropic;
use NeuronAI\SystemPrompt;

final class EditorAgent extends Agent
{
    public function __construct(
        private readonly string $threadId,
        private readonly \PDO $pdo,
    ) {}

    protected function provider(): AIProviderInterface
    {
        return new Anthropic(
            key: $_ENV['ANTHROPIC_API_KEY'],
            model: $_ENV['ANTHROPIC_MODEL'],
        );
    }

    protected function chatHistory(): ChatHistoryInterface
    {
        return new SQLChatHistory(
            thread_id: $this->threadId,
            pdo: $this->pdo,
            table: 'neuron_chat_history',
            contextWindow: 50000,
        );
    }

    public function instructions(): string
    {
        return (string) new SystemPrompt(
            background: [
                'You are an editorial agent for long-form product briefs.',
                'Apply reviewer notes without losing the original intent.',
            ],
        );
    }
}
```

## Створіть чернетку, а потім доопрацюйте її з тією самою гілкою пам’яті

```php
namespace App\StateMachines\Actions;

use App\Neuron\EditorAgent;
use NeuronAI\Chat\Messages\UserMessage;
use Queuety\Contracts\StateAction;

final class DraftBriefAction implements StateAction
{
    public function handle(array $state, ?string $event = null, array $event_payload = [], array $payload = []): array|string
    {
        // Queuety creates actions with `new DraftBriefAction()`, so build dependencies here.
        $pdo = new \PDO($_ENV['NEURON_DB_DSN'], $_ENV['NEURON_DB_USER'], $_ENV['NEURON_DB_PASSWORD']);

        $threadId = $state['neuron_thread_id'] ?? sprintf(
            'brief:%d:editor',
            $state['brief_id'],
        );

        $prompt = "Write the first draft for brief {$state['brief_id']}.";

        if ('reject' === $event) {
            $prompt = sprintf(
                'Revise the draft using these review notes: %s',
                $event_payload['reason'] ?? 'Tighten the draft and address reviewer concerns.',
            );
        }

        $agent = new EditorAgent($threadId, $pdo);
        $message = $agent->chat(
            new UserMessage($prompt)
        )->getMessage();

        return [
            'neuron_thread_id' => $threadId,
            'draft_markdown' => $message->getContent(),
            'review_round' => (int) ($state['review_round'] ?? 0) + 1,
            '_event' => 'draft_ready',
        ];
    }
}
```

## Автомат станів Queuety

```php
use Queuety\Enums\StateMachineStatus;
use Queuety\Queuety;

$machine_id = Queuety::machine('brief_review_session')
    ->version('brief-review-session.v1')
    ->state('drafting')
    ->action(DraftBriefAction::class)
    ->on('draft_ready', 'awaiting_review')
    ->state('awaiting_review')
    ->on('approve', 'completed')
    ->on('reject', 'drafting')
    ->state('completed', StateMachineStatus::Completed)
    ->dispatch([
        'brief_id' => 42,
    ]);

// Later, once the draft action has finished and the machine waits in `awaiting_review`:
Queuety::machine_event(
    $machine_id,
    'reject',
    [ 'reason' => 'Tighten the introduction and add pricing context.' ]
);

Queuety::machine_event(
    $machine_id,
    'approve',
    [ 'reviewer' => 'editor@example.com' ]
);
```

Перший прохід переходить у `drafting`, виконує дію з черги й переходить у `awaiting_review`.

Якщо перевіряльник відхиляє чернетку, автомат повертається до `drafting`. Оскільки дані події `reject` передаються в `DraftBriefAction`, наступна чернетка може врахувати примітки перевіряльника, не втрачаючи початкової історії гілки Neuron.

## Чому це зручніше за повторення робочого процесу

Ця задача стосується життєвого циклу. Чернетка очікує на перевірку людиною, перевіряльник може схвалити або відхилити її, після відхилення сеанс повертається до створення чернетки, а після схвалення завершується. Це краще описується автоматом станів, ніж лінійним робочим процесом із циклічним переходом назад.

Стан робочого процесу добре підходить для фактів оркестрації, як-от кількість раундів перевірки, ID артефактів і робочих процесів, а також рішень щодо маршрутизації. Пам’ять Neuron краще підходить для контексту розмови: попередніх запитів, ітеративних правок і відповідей моделі, які мають залишатися в гілці створення тексту.

Використання обох систем дає змогу доручити кожній те, що вона робить найкраще.

## Коли краще залишити це робочим процесом

Віддавайте перевагу робочому процесу, якщо етап перевірки чітко обмежений і орієнтований на виконання, наприклад:

Створити одну чернетку, дочекатися одного схвалення й опублікувати.

Віддавайте перевагу автомату станів, якщо сеанс може кілька разів повертатися до тих самих станів, а його життєвим циклом керують зовнішні події.

## Пов’язана документація

- [Автомати станів](https://queuety.inline0.dev/uk/docs/state-machines)
- [Сигнали робочих процесів](https://queuety.inline0.dev/uk/docs/workflows/signals)
- [Оркестрація агентів](https://queuety.inline0.dev/uk/docs/workflows/agent-orchestration)
