Models
The two provider dialects, API keys, local models, and retry behavior.
Every agent names its model in the required model: block; there is no fleet-wide default. The provider field is a dialect: two dialects cover effectively every hosted and local endpoint, and swapping providers is a one-line change. The short version lives in Agent Config; this page covers the details.
model:
provider: openai-compatible # or: anthropic
id: gpt-5.4-miniThe two dialects
openai-compatible | anthropic | |
|---|---|---|
| Speaks to | OpenAI, Ollama, vLLM, LiteLLM, OpenRouter — anything serving the chat-completions API | The native Anthropic Messages API |
| Default endpoint | https://api.openai.com/v1 | https://api.anthropic.com |
| Default key env var | OPENAI_API_KEY | ANTHROPIC_API_KEY |
base_url | Any compatible endpoint — this is how local models work | Anthropic-compatible proxies |
id is the plain model identifier the endpoint expects — gpt-5.4-mini, claude-sonnet-5, llama3.1. There is no combined provider/model string syntax; the two fields stay separate, which is what makes base_url proxies transparent.
API keys
The config names an environment variable; the key itself stays out of the file. At startup the runtime reads the key from the environment variable named by api_key_env, defaulting to OPENAI_API_KEY / ANTHROPIC_API_KEY per provider:
model:
provider: openai-compatible
id: gpt-5.4-mini
api_key_env: OPENROUTER_API_KEY # optional: which env var holds the keySupply the variable the way your deployment supplies env: export locally, --env-file .env with docker run, env_file: in compose. One subtlety: the provider key is read straight from the process environment — unlike ${VAR} references in the env: block, it does not fall back to /run/secrets/<VAR> files.
A missing key fails at startup, before any event is handled:
missing API key: set OPENAI_API_KEY (or point model.api_key_env at the right env var)The one exception: openai-compatible with an explicit base_url needs no key, because local models usually don't have one.
Local models
model:
provider: openai-compatible
id: llama3.1
base_url: http://localhost:11434/v1 # Ollamabase_url points the dialect at any compatible endpoint — Ollama, vLLM, a LiteLLM proxy — and with it set, no API key is required. af init --provider local scaffolds exactly this shape.
When the agent runs in a container, remember localhost is the container itself: use http://host.docker.internal:11434/v1 to reach a model server on the host (on Linux, add --add-host=host.docker.internal:host-gateway).
The small model
model:
provider: openai-compatible
id: gpt-5.4-mini
small: gpt-5.4-nanosmall routes the framework's cheap internal calls — today, the naming step on first boot — to a smaller model. It defaults to the main id; set it to a small model and those calls cost close to nothing.
When the provider fails
Transient failures retry themselves: rate limits (HTTP 429), overload (5xx), and network errors get up to three attempts with exponential backoff (500 ms, then 1 s). Auth failures (401/403) and malformed requests (other 4xx) fail immediately — retrying wouldn't change the answer.
A call that still fails ends the run with status error_provider and a one-line reason. The run fails; the service stays up, waiting for the next event — statuses are in the limits table.
fallbacks declares model ids to try in order when the primary fails. The schema accepts and validates the field today, but the runtime chain hasn't landed yet — until it does, a failed primary ends the run error_provider regardless of the list.
What is deliberately not configurable
There are no temperature or max-output-token fields; requests use the provider's defaults (the anthropic dialect caps output at 4096 tokens per call). If you need one of these controls, put a rewriting proxy such as LiteLLM behind base_url. The exhaustive field list is the JSON Schema, enforced in your editor as you type.
Are you an AI? Visit llms.txt — these docs as plain markdown.