# `ADK.Runner`
[🔗](https://github.com/zeroasterisk/adk-elixir/blob/main/lib/adk/runner.ex#L1)

Orchestrates agent execution — creates sessions, runs agents, collects events.

# `t`

```elixir
@type t() :: %ADK.Runner{
  agent: ADK.Agent.t(),
  app_name: String.t(),
  artifact_service: {module(), keyword()} | nil,
  memory_store: {module(), keyword()} | nil,
  plugins: [{module(), term()}],
  session_store: {module(), keyword()} | nil
}
```

# `find_active_agent`

```elixir
@spec find_active_agent(ADK.Agent.t(), pid() | nil) :: ADK.Agent.t()
```

Find the agent that should handle the current turn based on transfer history.

Scans session events backward for the last `transfer_to_agent` action.
If found, looks up that agent in the agent tree and returns it.
If not found or the target is a non-LLM agent (SequentialAgent, LoopAgent),
returns the root agent.

This mirrors Python ADK's `Runner._find_agent_to_run()`.

# `new`

```elixir
@spec new(keyword()) :: t()
```

Create a new Runner.

## Options

  * `:app_name` - application name (required)
  * `:agent` - the agent to run (required)
  * `:session_store` - optional `{Module, opts}` tuple for session persistence
  * `:artifact_service` - optional `{Module, opts}` tuple for artifact storage
  * `:memory_store` - optional `{Module, opts}` tuple for long-term memory

## Examples

    iex> agent = ADK.Agent.LlmAgent.new(name: "bot", model: "test", instruction: "Help")
    iex> runner = ADK.Runner.new(app_name: "test", agent: agent)
    iex> runner.app_name
    "test"

# `run`

```elixir
@spec run(t(), String.t(), String.t(), map() | String.t(), keyword()) :: [
  ADK.Event.t()
]
```

Run an agent with a message, returning a list of events.

## Examples

    iex> agent = ADK.Agent.LlmAgent.new(name: "bot", model: "test", instruction: "Help")
    iex> runner = %ADK.Runner{app_name: "test", agent: agent}
    iex> events = ADK.Runner.run(runner, "user1", "sess1", %{text: "hi"})
    iex> is_list(events)
    true

# `run_async`

```elixir
@spec run_async(t(), String.t(), String.t(), map() | String.t(), keyword()) ::
  {:ok, pid()} | {:error, term()}
```

Run an agent with async streaming — non-blocking, events delivered via messages.

Spawns a supervised Task that runs the agent with the given `on_event` callback.
Messages sent to `reply_to` (default: `self()`):
  - `{:adk_event, event}` for each event (via on_event callback)
  - `{:adk_done, events}` when the run completes
  - `{:adk_error, reason}` on failure

Returns `{:ok, task_pid}`.

## Examples

    {:ok, _pid} = ADK.Runner.run_async(runner, "user1", "sess1", "hi")
    receive do
      {:adk_event, event} -> IO.inspect(event, label: "event")
      {:adk_done, events} -> IO.puts("Done, #{length(events)} events")
    end

# `run_streaming`

```elixir
@spec run_streaming(t(), String.t(), String.t(), map() | String.t(), keyword()) :: [
  ADK.Event.t()
]
```

Run an agent with streaming — calls `on_event` callback for each event as it's produced.

Events are delivered in real-time via the agent's execution pipeline. The `on_event`
callback is wired into the execution context so it fires immediately as each event
is generated (model response, tool call, tool result), not after the full run completes.

Runs in a supervised Task under `ADK.RunnerSupervisor` and sends a `{:adk_done, events}`
message to the caller when complete. If the supervisor is not running, falls back to
synchronous execution.

## Options

Same as `run/5` plus:
  * `:on_event` — `(ADK.Event.t() -> any())` callback invoked for each event in real-time
  * `:reply_to` — pid to send `{:adk_done, events}` when complete (default: `self()`)

## Examples

    ADK.Runner.run_streaming(runner, "user1", "sess1", "hi",
      on_event: fn event -> IO.inspect(event) end)

---

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