Jido.Await (Jido v2.0.0-rc.1)

View Source

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)

Summary

Functions

Check if an agent process is alive and responding.

Wait for all agents to reach terminal status.

Wait for any agent to reach terminal status.

Request graceful cancellation of an agent.

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

Wait for an agent to reach a terminal status.

Get a specific child's PID by tag.

Get the PIDs of all children of a parent agent.

Types

completion()

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

server()

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

status()

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

Functions

alive?(server)

@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(servers, timeout_ms \\ 10000, opts \\ [])

@spec all([server()], non_neg_integer(), Keyword.t()) ::
  {:ok, %{required(server()) => 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(servers, timeout_ms \\ 10000, opts \\ [])

@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(server, opts \\ [])

@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(parent_server, child_tag, timeout_ms \\ 10000, opts \\ [])

@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(server, timeout_ms \\ 10000, opts \\ [])

@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(parent_server, child_tag)

@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(parent_server)

@spec get_children(server()) :: {:ok, %{required(term()) => 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>}}