defmodule AgentSea.Crew.Delegation do
@moduledoc """
Strategy behaviour for assigning a task to an agent. Each strategy is a module
implementing `c:delegate/3`; the coordinator selects one by config.
"""
defmodule Result do
@moduledoc "The outcome of a delegation decision."
@enforce_keys [:selected_agent]
defstruct [:selected_agent, :reason, :confidence, alternatives: [], decision_time_ms: 0]
@type t :: %__MODULE__{
selected_agent: term(),
reason: String.t() | nil,
confidence: float() | nil,
alternatives: [term()],
decision_time_ms: non_neg_integer()
}
end
@typedoc "A candidate agent: its name, pid, and (optional) role."
@type agent_ref :: %{
required(:name) => term(),
required(:pid) => pid() | nil,
optional(:role) => AgentSea.Role.t() | nil
}
@typedoc "Strategy context, e.g. `:counter`, `:bidding_time_ms`, `:minimum_bid`, `:selection_criteria`."
@type ctx :: map()
@callback delegate(task :: term(), [agent_ref()], ctx()) ::
{:ok, Result.t()} | {:error, term()}
@doc "Run a delegation strategy, timing the decision."
@spec select(module(), term(), [agent_ref()], ctx()) ::
{:ok, Result.t()} | {:error, term()}
def select(strategy, task, agents, ctx \\ %{}) do
started = System.monotonic_time(:millisecond)
case strategy.delegate(task, agents, ctx) do
{:ok, %Result{} = result} ->
{:ok, %{result | decision_time_ms: System.monotonic_time(:millisecond) - started}}
other ->
other
end
end
end