# `Mead.Router.Interaction`
[🔗](https://github.com/albertosca/mead/blob/main/lib/mead/router/interaction.ex#L1)

What the router asks of a person (or of a policy standing in for one) around each tool call.

A turn that carries `interaction: {module, context}` in its options makes `Mead.Router` call this
behaviour for every tool the model asks for, in this order: `tool_updated/2` with status
`:pending`, `request_permission/2`, and, when the answer is `:allow`, `tool_updated/2` with
`register_call/3` and `:in_progress` (with `cancellable: true`), the tool itself, then `tool_updated/2` with `:completed` or `:failed`. A denied
call never reaches the hub; the model receives an error result that says why. A tool the model
named wrongly is reported `:failed` without asking anyone.

The callbacks run in the process that runs the turn, one call at a time, so `request_permission/2`
may block for as long as it takes to get an answer. A turn without `:interaction` never touches
this module.

# `choice`

```elixir
@type choice() :: %{
  tool_call_id: String.t(),
  prompt: String.t(),
  options: [%{id: String.t(), label: String.t()}]
}
```

# `request`

```elixir
@type request() :: %{
  tool_call_id: String.t(),
  tool: String.t(),
  server: String.t(),
  class: :read | :effect,
  arguments: term()
}
```

# `update`

```elixir
@type update() :: %{
  tool_call_id: String.t(),
  title: String.t(),
  status: :pending | :in_progress | :completed | :failed,
  current_step: String.t() | nil,
  progress: float() | nil,
  cancellable: boolean()
}
```

# `ask_choice`

```elixir
@callback ask_choice(context :: term(), choice()) ::
  {:ok, String.t()} | {:error, :expired | :no_answer}
```

Puts a multiple-choice question (the `ask_user` tool) to the person. Returns the `id` of the
option they picked, `{:error, :expired}` when the time ran out and `{:error, :no_answer}` when
nobody could answer. Like `request_permission/2` it may block until there is an answer.

# `register_call`

```elixir
@callback register_call(context :: term(), tool_call_id :: String.t(), pid :: pid()) ::
  :ok
```

Called once an allowed tool call is running in its own process, before the `:in_progress`
update, so whoever can cancel the call (by killing `pid`) knows which process to kill.

# `request_permission`

```elixir
@callback request_permission(context :: term(), request()) ::
  :allow | {:deny, :rejected | :expired}
```

# `text_delta`

```elixir
@callback text_delta(context :: term(), text :: String.t()) :: :ok
```

Called with each fragment of text a streaming provider produces while it answers, in order. The
fragments are a preview of the answer the turn returns; a provider that cannot stream never
calls it.

# `tool_updated`

```elixir
@callback tool_updated(context :: term(), update()) :: :ok
```

# `valid?`

```elixir
@spec valid?(term()) :: boolean()
```

Whether `value` is a `{module, context}` pair whose module implements this behaviour.

---

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