
# Przekazania asynchroniczne

Użyj `start_workflows()`, gdy przepływ pracy musi przekazać wykryte zadania do niezależnych przepływów pracy najwyższego poziomu, zamiast wykonywać wszystko w ramach jednego uruchomienia.

Jeśli jawnie modelujesz uruchomienia agentów, `start_agents()` i `wait_for_agents()` są aliasami semantycznymi z ustawieniami domyślnymi dostosowanymi do agentów.

Więcej przykładów obejmujących cały proces znajdziesz w sekcji [Orkiestracja agentów](https://queuety.inline0.dev/pl/docs/workflows/agent-orchestration).

To przydatne podejście do orkiestracji w stylu agentowym:

- przepływ pracy planisty wykrywa zadania w czasie wykonywania
- każde zadanie staje się osobnym trwałym przepływem pracy
- przepływ nadrzędny zapisuje identyfikatory tych przepływów w stanie
- przepływ nadrzędny może później czekać na `all`, `any`, `quorum` lub nazwaną uruchomioną grupę

## Metoda `->start_workflows()`

```php
use Queuety\Enums\WaitMode;
use Queuety\Queuety;

$agent_task = Queuety::workflow( 'agent_task' )
    ->then( ResearchTopicStep::class )
    ->then( SummarizeTopicStep::class );

Queuety::workflow( 'brief_research' )
    ->then( PlanTopicsStep::class )
    ->start_workflows(
        items_key: 'topics',
        workflow_builder: $agent_task,
        result_key: 'child_workflow_ids',
        group_key: 'researchers',
    )
    ->wait_for_workflow_group( 'researchers', WaitMode::All, result_key: 'child_results' )
    ->then( SynthesizeBriefStep::class )
    ->dispatch( [ 'brief_id' => 42 ] );
```

W tym przykładzie:

1. `PlanTopicsStep` zapisuje tablicę ładunków tematów w `$state['topics']`
2. `start_workflows()` uruchamia jeden przepływ pracy `agent_task` dla każdego tematu
3. identyfikatory uruchomionych przepływów są zapisywane w `$state['child_workflow_ids']`
4. `wait_for_workflow_group()` wstrzymuje działanie do czasu spełnienia przez tę uruchomioną grupę wybranego warunku zakończenia
5. `SynthesizeBriefStep` otrzymuje ukończone stany przepływów podrzędnych w `$state['child_results']`

## Ładunki przepływów podrzędnych

Każdy element w `items_key` staje się początkowym ładunkiem jednego uruchomionego przepływu pracy.

Jeśli element jest tablicą, jego klucze publiczne zostają połączone z ładunkiem przepływu podrzędnego:

```php
[
    [ 'topic' => 'pricing', 'source' => 'competitors' ],
    [ 'topic' => 'reviews', 'source' => 'customers' ],
]
```

Jeśli element jest skalarem, Queuety zapisuje go pod kluczem `payload_key`:

```php
->start_workflows(
    items_key: 'topic_names',
    workflow_builder: $agent_task,
    payload_key: 'topic',
)
```

## Dziedziczenie stanu przepływu nadrzędnego

Domyślnie `start_workflows()` łączy publiczny stan przepływu nadrzędnego z ładunkiem każdego przepływu podrzędnego.

Dzięki temu wspólny kontekst, taki jak `brief_id`, `account_id` lub `campaign`, jest automatycznie dostępny w każdym uruchomionym przepływie pracy.

Źródłowe `items_key` i `result_key` są wykluczane z dziedziczenia, aby każdy przepływ podrzędny nie otrzymywał całej listy zadań ani tablicy końcowych identyfikatorów przepływów pracy.

Ustaw `inherit_state: false`, jeśli każdy przepływ podrzędny ma otrzymywać wyłącznie ładunek swojego elementu.

## Dlaczego nie `run_workflow()`?

`run_workflow()` tworzy relację nadrzędny–podrzędny, w której przepływ nadrzędny zatrzymuje się na tym kroku do czasu zakończenia przepływu podrzędnego.

`start_workflows()` zapewnia większą niezależność:

- uruchomione przepływy pracy są niezależnymi przepływami najwyższego poziomu
- każdy z nich można osobno sprawdzać, ponawiać lub eksportować
- przepływ nadrzędny później decyduje, czy i jak na nie czekać

Dlatego `start_workflows()` lepiej sprawdza się przy asynchronicznym przekazywaniu zadań agentom, a `run_workflow()` lepiej nadaje się do zagnieżdżonego komponowania w ramach jednego drzewa orkiestracji.

## Oczekiwanie w późniejszym terminie

`start_workflows()` zaprojektowano do współpracy z sekcją [Zależności między przepływami pracy](https://queuety.inline0.dev/pl/docs/workflows/dependencies):

```php
use Queuety\Enums\WaitMode;

Queuety::workflow( 'review_board' )
    ->start_workflows( 'review_tasks', $review_task_workflow, 'review_workflow_ids' )
    ->wait_for_workflows( 'review_workflow_ids', WaitMode::Any, 'winner' )
    ->then( FinalizeDecisionStep::class )
    ->dispatch( $payload );
```

- `WaitMode::All` zbiera wszystkie ukończone stany przepływów podrzędnych
- `WaitMode::Any` wznawia działanie po pierwszym pomyślnie zakończonym przepływie podrzędnym

Dzięki temu można orkiestrwać planistę i wykonawcę bez potrzeby używania pełnego silnika DAG, który można edytować w czasie wykonywania.

## Aliasy przyjazne agentom

`start_agents()` jest aliasem `start_workflows()` z ustawieniami domyślnymi dostosowanymi do przepływów pracy planisty i wykonawcy:

- `result_key` domyślnie przyjmuje wartość `agent_workflow_ids`
- `payload_key` domyślnie przyjmuje wartość `agent_task`
- `name` domyślnie przyjmuje wartość `start_agents`

`wait_for_agents()` jest aliasem `wait_for_workflows()` z ustawieniami domyślnymi dostosowanymi do zbierania wyników agentów:

- `workflows` domyślnie przyjmuje wartość `agent_workflow_ids`
- `result_key` domyślnie przyjmuje wartość `agent_results`
- `name` domyślnie przyjmuje wartość `wait_for_agents`

`wait_for_agent_group()` jest aliasem `wait_for_workflow_group()` z ustawieniami domyślnymi dostosowanymi do grup agentów.

```php
use Queuety\Enums\WaitMode;

$agent_run = Queuety::workflow( 'agent_run' )
    ->then( ResearchTopicStep::class )
    ->then( SummarizeTopicStep::class );

Queuety::workflow( 'brief_research' )
    ->then( PlanTopicsStep::class )
    ->start_agents( 'agent_tasks', $agent_run, group_key: 'researchers' )
    ->wait_for_agent_group( 'researchers', WaitMode::Quorum, 2 )
    ->then( SynthesizeBriefStep::class )
    ->dispatch( [ 'brief_id' => 42 ] );
```
