
# Neuron-Sitzungs-Zustandsmaschine

Dieses Muster eignet sich, wenn sich das, was du entwickelst, eher wie eine Sitzung als wie ein einmaliger Lauf verhält.

Queuety-Zustandsmaschinen verwalten den Sitzungslebenszyklus, Queuety-Workflows erledigen Hintergrundaufgaben, die von Wiederholungen, Modi zur Verarbeitung jedes Elements und zum Abschluss sowie von Zusammenfassungen profitieren, und Neuron übernimmt die eigentlichen Agentenaufrufe und den Gesprächsspeicher.

Diese Aufteilung eignet sich gut für Support-Copiloten, interne Rechercheassistenten, redaktionelle Agenten, die für eine menschliche Prüfung pausieren können, und Chat-Threads, die zwischen Planungs-, Warte- und Antwortphasen wechseln.

## Ablauf des Lebenszyklus

In diesem Beispiel durchläuft eine Support-Sitzung `awaiting_user`, `planning`, `waiting_on_research` und `responding`. Die Maschine bildet diesen Lebenszyklus explizit ab, während ein Hintergrund-Workflow Recherchen sammelt und die Sitzung benachrichtigt, sobald alles bereit ist.

## Die Zustandsmaschine

```php
use Queuety\Queuety;

$session_id = Queuety::machine( 'support_session' )
    ->version( 'support-session.v1' )
    ->state( 'awaiting_user' )
    ->on( 'user_message', 'planning' )
    ->state( 'planning' )
    ->action( DispatchResearchWorkflowAction::class )
    ->on( 'research_dispatched', 'waiting_on_research' )
    ->state( 'waiting_on_research' )
    ->on( 'research_completed', 'responding' )
    ->state( 'responding' )
    ->action( RespondWithNeuronAction::class )
    ->on( 'response_ready', 'awaiting_user' )
    ->dispatch( [
        'thread_id' => 'support:customer-42',
    ] );
```

Wenn ein Benutzer eine Nachricht sendet:

```php
Queuety::machine_event(
    $session_id,
    'user_message',
    [
        'session_machine_id' => $session_id,
        'message' => 'Can you compare our pricing to the main competitors?',
    ]
);
```

Die Maschine wechselt zu `planning`, reiht ihre Aktion ein und startet den Recherche-Workflow.

## Planungsaktion: Workflow starten

```php
namespace App\StateMachines\Actions;

use Queuety\Contracts\StateAction;
use Queuety\Enums\WaitMode;
use Queuety\Queuety;

final class DispatchResearchWorkflowAction implements StateAction
{
    public function handle( array $state, ?string $event = null, array $event_payload = [], array $payload = [] ): array|string
    {
        $message = trim( (string) ( $event_payload['message'] ?? '' ) );

        $agent_workflow = Queuety::workflow( 'support_research_agent' )
            ->then( ResearchTopicStep::class );

        $research_workflow = Queuety::workflow( 'support_research_packet' )
            ->then( PlanResearchTasksStep::class )
            ->start_agents( 'agent_tasks', $agent_workflow )
            ->wait_for_agents( mode: WaitMode::All, result_key: 'agent_results' )
            ->then( SynthesizeResearchPacketStep::class )
            ->then( NotifySessionResearchReadyStep::class );

        $workflow_id = $research_workflow->dispatch( [
            'machine_id'      => $state['session_machine_id'],
            'thread_id'       => $state['thread_id'],
            'customer_prompt' => $message,
        ] );

        return [
            'latest_user_message'  => $message,
            'research_workflow_id' => $workflow_id,
            '_event'               => 'research_dispatched',
        ];
    }
}
```

Diese Zustandsaktion führt die Recherche nicht selbst durch. Sie startet einen Workflow und speichert die Workflow-ID im Maschinenzustand.

## Workflow-Schritt: Die Maschine benachrichtigen, wenn die Recherche bereit ist

```php
namespace App\Workflow\Steps;

use Queuety\Queuety;
use Queuety\Step;

final class NotifySessionResearchReadyStep implements Step
{
    public function handle( array $state ): array
    {
        Queuety::machine_event(
            $state['machine_id'],
            'research_completed',
            [
                'research_packet' => $state['research_packet'],
            ]
        );

        return [];
    }

    public function config(): array
    {
        return [];
    }
}
```

Nach Abschluss des Workflows sendet er `research_completed` zurück an die Maschine und fügt das zusammengestellte Paket als Ereignisdaten hinzu.

## Antwortaktion: Neuron mit Sitzungsspeicher aufrufen

```php
namespace App\StateMachines\Actions;

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

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

        $agent = new SupportAgent(
            threadId: $state['thread_id'],
            pdo: $pdo,
        );

        $message = $agent->chat(
            new UserMessage(
                sprintf(
                    "Answer the user message '%s' using this research packet:\n\n%s",
                    $state['latest_user_message'],
                    json_encode( $state['research_packet'] ?? [], JSON_PRETTY_PRINT )
                )
            )
        )->getMessage();

        return [
            'assistant_reply' => $message->getContent(),
            '_event'          => 'response_ready',
        ];
    }
}
```

Nach dem Erstellen der Antwort wechselt die Maschine mit der aktualisierten Antwort im öffentlichen Zustand zurück zu `awaiting_user`. Dieselbe Sitzung kann dann ein weiteres Ereignis `user_message` annehmen und fortfahren.

## Warum das sauberer ist als ein großer Workflow

Die aufwendige Arbeit folgt weiterhin dem Workflow-Muster, weil die Recherche Planung, spezialisierte Läufe, Zusammenführung und Synthese erfordert. Das langlebige Support-Gespräch folgt dem Zustandsmaschinen-Muster, weil die Sitzung im Blick behalten muss, ob sie auf eine Benutzernachricht, auf Recherche oder auf die Freigabe zum Antworten wartet.

Diese Aufteilung sorgt für eine gut lesbare Laufzeit und ein klar definiertes Sitzungsmodell.

## Verwandte Dokumentation

- [Zustandsmaschinen](https://queuety.inline0.dev/de/docs/state-machines)
- [Agenten-Orchestrierung](https://queuety.inline0.dev/de/docs/workflows/agent-orchestration)
- [Asynchrone Übergaben](https://queuety.inline0.dev/de/docs/workflows/async-handoffs)
- [Workflow-Abhängigkeiten](https://queuety.inline0.dev/de/docs/workflows/dependencies)
