Per-task-kind model routing for background agent work.
Not every model call deserves the frontier model. Compression, titling, triage,
curation, and profile description are cheap work a small fast model does well at
a fraction of the cost and latency. This resolver maps a task kind to the
Raxol.Agent.ExecutorConfig for its slot, so a feature asks for "the curation
model" instead of carrying its own backend config.
Config
An auxiliary: map keyed by task kind, passed through the resolver's options.
Each slot is an ExecutorConfig-shaped map plus an optional :fallback (an
ordered list of other slot names or :default):
auxiliary: %{
curation: %{harness: :anthropic, model: "claude-haiku-4-5", fallback: [:default]},
user_model: %{harness: :anthropic, model: "claude-haiku-4-5"},
title: %{harness: :openai, model: "gpt-5-mini"},
default_aux: %{harness: :anthropic, model: "claude-haiku-4-5"}
}default_aux is the catch-all auxiliary slot. :default refers to the agent's
primary executor, passed as :default. A slot accepts :backend as an alias
for :harness.
Precedence
A task kind resolves to its own slot, then default_aux, then the primary
executor (:default). With auxiliary: unset, every kind resolves to the
primary executor. A feature that carries an explicit backend keeps it as an
override; the resolver is consulted only when that explicit config is absent.
Resolution vs selection
resolve/2 returns one ExecutorConfig (the slot's primary). resolve_chain/2
returns the slot's primary followed by its fallback chain, terminating at the
primary executor. select/2 walks that chain through
Raxol.Agent.Backend.Selector, returning the first available backend, so a
cheap slot degrades to another cheap slot rather than failing the task.
Summary
Functions
Resolve a task kind to the ExecutorConfig of its slot.
Resolve a task kind to its ordered fallback chain of ExecutorConfigs.
Resolve and select a backend for a task kind, walking the fallback chain.
Types
Functions
@spec resolve( task_kind(), keyword() ) :: Raxol.Agent.ExecutorConfig.t()
Resolve a task kind to the ExecutorConfig of its slot.
Falls back to the default_aux slot, then to the primary executor passed as
:default (or a :mock config if none is given).
Options
:auxiliary-- the slot map (default%{}).:default-- the primary executorExecutorConfig(the:defaulttarget).
@spec resolve_chain( task_kind(), keyword() ) :: [Raxol.Agent.ExecutorConfig.t()]
Resolve a task kind to its ordered fallback chain of ExecutorConfigs.
The chain is the slot's primary config, then each entry of the slot's
:fallback (a slot name or :default), and finally the primary executor, so a
walk always terminates at :default. Duplicates are removed.
Resolve and select a backend for a task kind, walking the fallback chain.
Returns {:ok, backend_module, backend_opts} for the first config in the chain
that is available and resolves through Backend.Selector, else
{:error, :no_available_backend}.
Options
In addition to resolve/2's options:
:available?-- a(ExecutorConfig.t() -> boolean)predicate deciding whether a config's backend is usable (e.g. has credentials). Defaults to a structural check that the harness resolves to a backend module.