Mead.Router.Interaction behaviour (mead v0.1.1)

Copy Markdown View Source

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.

Summary

Callbacks

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.

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.

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.

Functions

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

Types

choice()

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

request()

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

update()

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

Callbacks

ask_choice(context, choice)

@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(context, tool_call_id, pid)

@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(context, request)

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

text_delta(context, text)

@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(context, update)

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

Functions

valid?(arg1)

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

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