# `Jido.Await`
[🔗](https://github.com/agentjido/jido/blob/v2.3.0/lib/jido/await.ex#L1)

Synchronous helpers for waiting on Jido agents from non-agent code.

This module provides utilities for HTTP controllers, CLI tools, and tests
that need to synchronously wait for agents to complete. Agents signal
completion via state, not process death.

## Completion Convention

Agents signal completion by setting a terminal status in their state:

    agent = put_in(agent.state.status, :completed)
    agent = put_in(agent.state.last_answer, result)

The `completion/3` function uses event-driven waiting via `AgentServer.await_completion/2`,
blocking until the agent reaches a terminal state without polling.

## Examples

    # Wait for a single agent
    {:ok, pid} = Jido.start_agent(jido, MyAgent)
    AgentServer.cast(pid, some_signal)
    {:ok, %{status: :completed, result: answer}} = Jido.Await.completion(pid, 10_000)

    # Wait for all agents to complete
    {:ok, results} = Jido.Await.all([pid1, pid2, pid3], 30_000)

    # Wait for the first agent to complete
    {:ok, {winner_pid, result}} = Jido.Await.any([pid1, pid2], 10_000)

    # Wait for a specific child of a parent agent
    {:ok, result} = Jido.Await.child(coordinator, :worker_1, 30_000)

# `completion`

```elixir
@type completion() :: %{status: status(), result: any()}
```

# `server`

```elixir
@type server() :: Jido.AgentServer.server()
```

# `status`

```elixir
@type status() :: :completed | :failed | atom()
```

# `alive?`

```elixir
@spec alive?(server()) :: boolean()
```

Check if an agent process is alive and responding.

## Examples

    if Jido.Await.alive?(agent_pid) do
      # safe to interact
    end

# `all`

```elixir
@spec all([server()], non_neg_integer(), Keyword.t()) ::
  {:ok, %{required(server()) =&gt; completion()}}
  | {:error, :timeout}
  | {:error, {server(), term()}}
```

Wait for all agents to reach terminal status.

Spawns concurrent waiters for each agent and collects results.
Returns when all complete or on first infrastructure error.

## Options

Same as `completion/3`.

## Returns

- `{:ok, %{server => completion()}}` - All agents completed (includes `:failed` status)
- `{:error, :timeout}` - Timeout reached before all completed
- `{:error, {server, reason}}` - Infrastructure error for specific server

## Examples

    {:ok, results} = Jido.Await.all([pid1, pid2, pid3], 30_000)
    # => %{pid1 => %{status: :completed, result: ...}, ...}

# `any`

```elixir
@spec any([server()], non_neg_integer(), Keyword.t()) ::
  {:ok, {server(), completion()}}
  | {:error, :timeout}
  | {:error, {server(), term()}}
```

Wait for any agent to reach terminal status.

Returns as soon as the first agent completes.

## Options

Same as `completion/3`.

## Returns

- `{:ok, {server, completion()}}` - First agent to complete
- `{:error, :timeout}` - Timeout reached before any completed
- `{:error, {server, reason}}` - Infrastructure error

## Examples

    {:ok, {winner, result}} = Jido.Await.any([pid1, pid2], 10_000)

# `cancel`

```elixir
@spec cancel(server(), Keyword.t()) :: :ok | {:error, term()}
```

Request graceful cancellation of an agent.

Sends a cancel signal to the agent. The agent decides how to respond
(e.g., set `state.status = :failed` with `state.error = :cancelled`).

This is advisory - callers should use `completion/3` to wait for
the agent to actually reach a terminal state.

## Options

- `:reason` - Cancellation reason (default: `:client_cancelled`)

## Examples

    :ok = Jido.Await.cancel(agent_pid)
    {:ok, %{status: :failed}} = Jido.Await.completion(agent_pid, 5_000)

# `child`

```elixir
@spec child(server(), term(), non_neg_integer(), Keyword.t()) ::
  {:ok, completion()} | {:error, term()}
```

Wait for a specific child of a parent agent to complete.

First looks up the child by tag in the parent's `children` map,
then polls the child for completion.

## Options

Same as `completion/3`.

## Returns

- `{:ok, %{status: atom(), result: any()}}` - Child completed
- `{:error, :timeout}` - Timeout reached
- `{:error, term()}` - Other error

## Examples

    {:ok, coordinator} = Jido.start_agent(jido, CoordinatorAgent)
    AgentServer.cast(coordinator, %Signal{type: "spawn_worker"})
    {:ok, result} = Jido.Await.child(coordinator, :worker_1, 30_000)

# `completion`

```elixir
@spec completion(server(), non_neg_integer(), Keyword.t()) ::
  {:ok, completion()} | {:error, term()}
```

Wait for an agent to reach a terminal status.

Uses event-driven waiting via GenServer.call - the caller blocks until
the agent's state transitions to `:completed` or `:failed`, then receives
the result immediately. No polling is involved.

## Options

- `:status_path` - Path to status field (default: `[:status]`)
- `:result_path` - Path to result field (default: `[:last_answer]`)
- `:error_path` - Path to error field (default: `[:error]`)

## Returns

- `{:ok, %{status: :completed, result: any()}}` - Agent completed successfully
- `{:ok, %{status: :failed, result: any()}}` - Agent failed
- `{:error, :timeout}` - Timeout reached before completion
- `{:error, :not_found}` - Agent process not found

## Examples

    {:ok, result} = Jido.Await.completion(agent_pid, 10_000)

    # With custom paths for strategy state
    {:ok, result} = Jido.Await.completion(agent_pid, 10_000,
      status_path: [:__strategy__, :status],
      result_path: [:__strategy__, :result]
    )

# `get_child`

```elixir
@spec get_child(server(), term()) ::
  {:ok, pid()} | {:error, :child_not_found | term()}
```

Get a specific child's PID by tag.

## Returns

- `{:ok, pid}` - Child found
- `{:error, :child_not_found}` - Child with given tag not found
- `{:error, term()}` - Error getting parent state

## Examples

    {:ok, worker_pid} = Jido.Await.get_child(coordinator, :worker_1)

# `get_children`

```elixir
@spec get_children(server()) :: {:ok, %{required(term()) =&gt; pid()}} | {:error, term()}
```

Get the PIDs of all children of a parent agent.

## Returns

- `{:ok, %{tag => pid}}` - Map of child tags to PIDs
- `{:error, term()}` - Error getting parent state

## Examples

    {:ok, children} = Jido.Await.get_children(coordinator)
    # => {:ok, %{worker_1: #PID<0.123.0>, worker_2: #PID<0.124.0>}}

