# `ExAthena.Loop.Parallel`
[🔗](https://github.com/udin-io/ex_athena/blob/v0.7.1/lib/ex_athena/loop/parallel.ex#L1)

Parallel tool-call dispatcher.

When a model emits multiple tool calls in a single response, the kernel
groups them:

  * **Read-only calls** (tool's `parallel_safe?/0` returns `true`) run
    concurrently via `Task.async_stream/3`.
  * **Mutating calls** run serially in the order the model emitted them,
    to preserve deterministic side-effect ordering.

Regardless of execution order, results are returned in the same order as
the input tool calls — the model always sees results aligned with its
calls.

# `emit_events`

```elixir
@spec emit_events(
  map(),
  ExAthena.Messages.ToolCall.t(),
  ExAthena.Messages.Message.t()
) :: :ok
```

Emit tool-call / tool-result events and update counters.

# `pre_tool_gate`

```elixir
@spec pre_tool_gate(ExAthena.Messages.ToolCall.t(), map()) ::
  :allow | {:deny, term()} | {:halt, term()}
```

Run the pre-tool gate (permissions + PreToolUse hooks) for a single call.

Returns `:allow`, `{:deny, reason}`, or `{:halt, reason}`.

# `run`

```elixir
@spec run([ExAthena.Messages.ToolCall.t()], map(), (ExAthena.Messages.ToolCall.t(),
                                              map() -&gt;
                                                {term(), map()})) ::
  {:ok, [term()], map()} | {:halt, term(), map()}
```

Execute a list of tool calls.

`runner_fn` is `(ToolCall.t(), state -> {result, updated_state})`. The
`result` is whatever the single-call runner returns (typically a
tool-result message tuple or a `:halt` tuple). Updated state threads the
phase transitions, mistake counter, and budget.

Returns `{:ok, results_in_order, final_state}` or
`{:halt, reason, final_state}` when any call returns a halt.

Ordering guarantee: `results_in_order` is ordered the same as the input
`calls`, even though parallel-safe calls may execute out-of-order.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
