Resolves the provider and per-call options for an ExAthena request.
Resolution order (per key, highest to lowest priority):
opts[:key]— per-call override always wins.- For atom-named providers:
Application.get_env(:ex_athena, provider)[:key]— provider-specificconfig.exsentry. For string-named providers: the matching JSON file loaded from~/.config/ex_athena/providers/byExAthena.ProviderRegistry. Application.get_env(:ex_athena, :key)— top-level library config.- Provider default (if the provider declares one).
Matches the stripity_stripe / ex_aws pattern: per-call overrides win,
application config is the default, no global mutable state.
String provider names (e.g. provider: "my-groq") are resolved through
ExAthena.ProviderRegistry, which loads *.json files from
~/.config/ex_athena/providers/ at application startup. See the
Providers guide for the full JSON schema, security
notes, and ready-to-copy examples.
Known providers
| Atom | Module |
|---|---|
:ollama | ExAthena.Providers.ReqLLM |
:openai_compatible | ExAthena.Providers.ReqLLM |
:openai | ExAthena.Providers.ReqLLM |
:llamacpp | ExAthena.Providers.ReqLLM |
:claude | ExAthena.Providers.ReqLLM |
:anthropic | ExAthena.Providers.ReqLLM |
:gemini | ExAthena.Providers.ReqLLM |
:openrouter | ExAthena.Providers.ReqLLM |
:req_llm | ExAthena.Providers.ReqLLM |
:mock | ExAthena.Providers.Mock |
You may also pass any module that implements ExAthena.Provider directly, or
define custom providers by placing JSON files in ~/.config/ex_athena/providers/
(loaded at startup by ExAthena.ProviderRegistry).
Request queue
ExAthena.RequestQueue is an opt-in semaphore that caps concurrent in-flight
requests per provider. Enable it with:
config :ex_athena, :request_queue, enabled: truePer-provider depth limits can be set inside provider config blocks:
config :ex_athena, :ollama, request_queue: [max_depth: 3]A global max_depth applies to all providers that don't have a per-provider
override:
config :ex_athena, :request_queue, enabled: true, max_depth: 5Built-in defaults (used when no application config is set):
| Provider | Default max_depth |
|---|---|
:ollama | 2 |
:llamacpp | 1 |
:exo | 3 |
:openai, :anthropic, :claude, :gemini, :openrouter, :req_llm | 10 |
| unknown | 10 |
Summary
Functions
Look up a single configuration value for provider_module with the tiered
resolution order. opts wins, then provider-specific config, then top-level
config, then the supplied default.
Return all known providers: built-in atoms plus any specs loaded by
ExAthena.ProviderRegistry.
Pop :provider from opts and return {provider_module, remaining_opts}.
Resolve a provider atom (or module) to its implementing module.
Build the keyword list passed to a provider's query/2 / stream/3 callback.
Translate an ExAthena provider atom into the req_llm provider tag used in
"tag:model-id" specs. Returns nil when the atom doesn't map to req_llm
(e.g. :mock, or a user-supplied module).
Return true when the request queue feature is enabled via application config.
Return the maximum concurrent request depth for provider_atom.
Functions
Look up a single configuration value for provider_module with the tiered
resolution order. opts wins, then provider-specific config, then top-level
config, then the supplied default.
The provider atom is derived from the module name: Providers.Ollama → :ollama.
@spec list_providers() :: [ %{ name: String.t(), display_name: String.t(), module: module(), source: :builtin | :registry } ]
Return all known providers: built-in atoms plus any specs loaded by
ExAthena.ProviderRegistry.
Each entry is a map with:
:name— string name of the provider:module— the implementing module:source—:builtinor:registry
Pop :provider from opts and return {provider_module, remaining_opts}.
Raises ArgumentError if no provider is set in opts or in application env.
For registry-loaded providers the following spec fields are threaded into opts
using Keyword.put_new/3 so per-call overrides always win:
:req_llm_provider_tag— fromspec.req_llm_provider_tag:base_url— fromspec.base_url:extra_headers— fromspec.extra_headers(non-empty maps only):api_key— fromspec.api_key, or resolved fromspec.api_key_env
Resolve a provider atom (or module) to its implementing module.
Resolution order:
- Built-in provider map (compile-time constant, fastest path).
ExAthena.ProviderRegistry— for providers loaded from JSON config files.- Module check — accepts any atom that is a loaded module implementing
ExAthena.Provider.
Build the keyword list passed to a provider's query/2 / stream/3 callback.
Flattens per-call overrides + application env for this provider into one
keyword list. Providers use Keyword.get/3 on the result.
Translate an ExAthena provider atom into the req_llm provider tag used in
"tag:model-id" specs. Returns nil when the atom doesn't map to req_llm
(e.g. :mock, or a user-supplied module).
Resolution order: a registry-loaded JSON spec wins (its req_llm_provider_tag
field), with the static built-in map as fallback when no spec is loaded for
the atom or the spec's tag is unset. This matters when a JSON-defined
provider's name collides with a built-in atom (e.g. :openrouter, which is
also present in the built-in map for config.exs users) — the user's JSON
file is authoritative.
@spec request_queue_enabled?() :: boolean()
Return true when the request queue feature is enabled via application config.
Opt-in: defaults to false. Enable with:
config :ex_athena, :request_queue, enabled: true
@spec request_queue_max_depth(atom()) :: pos_integer()
Return the maximum concurrent request depth for provider_atom.
Resolution order:
config :ex_athena, provider_atom, request_queue: [max_depth: N]config :ex_athena, :request_queue, max_depth: N- Built-in per-provider default (ollama: 2, llamacpp: 1, exo: 3, cloud: 10).
10for unrecognised providers.