Model resolution
Bridle ships zero default models. Set one of three layers; the highest wins.
Every step has to know which model to call. Bridle never picks one for you — there is no implicit default. You set a model at one of three layers, and Bridle resolves them in order on every step.
The three layers
In order of precedence, highest first:
- Per-call:
with_model(call, "model-id")overrides for one call. - Per-agent:
@agent(model="model-id", ...)becomes the default for every step inside the body. - Process:
bridle.configure(model="model-id")is the fallback for everything.
A step picks the first one that is set. If none is, it raises ConfigurationError with a message that lists all three places to fix it.
Set one
The minimum viable setup — process-wide:
import bridle
from bridle.models.anthropic import install
install()
bridle.configure(model="claude-sonnet-4-6")After that, every step in every agent uses claude-sonnet-4-6 unless something more specific overrides it.
Set one per agent
The right grain when an agent's work warrants a particular model:
@agent(input=Q, output=Brief, model="claude-opus-4-7")
def deep_research(q: Q) -> Brief:
...
@agent(input=str, output=Summary, model="claude-haiku-4-5")
def quick_summary(text: str) -> Summary:
...Inside deep_research, every step runs against opus. Inside quick_summary, every step runs against haiku. Even if bridle.configure(model=...) is also set, the agent-level value wins.
Nested agents inherit the outer agent's model unless they declare one. An agent is allowed to call another agent — the inner one's model= takes over inside its body.
Set one per call
with_model overrides any other layer for a single call:
from bridle import with_model
# Force this one step onto a cheaper model regardless of the agent's default.
quick = with_model(step("classify the topic", schema=Topic, context=text), "claude-haiku-4-5")The override propagates through wrappers — with_model(retry(step(...))) and retry(with_model(step(...))) both work. The model resolution happens when the inner step actually fires.
Fallback chains
The fallback wrapper composes naturally with with_model to build a degradation ladder:
from bridle import fallback, with_model
answer = fallback(
with_model(step(prompt, schema=Out, context=ctx), "claude-opus-4-7"),
with_model(step(prompt, schema=Out, context=ctx), "claude-sonnet-4-6"),
with_model(step(prompt, schema=Out, context=ctx), "claude-haiku-4-5"),
)If opus errors, sonnet runs. If sonnet errors, haiku runs. The first that succeeds wins. See wrappers for the full semantics.
What models are valid
Bridle does not validate the model id — it passes the string straight to the active model client. With the Anthropic adapter installed, valid values are whatever the Anthropic SDK accepts (claude-sonnet-4-6, claude-opus-4-7, claude-haiku-4-5, etc.). Bring your own client if you need to talk to a different surface.