Models¶
fireflyframework_agentic.models builds a pydantic-ai Model from a description — provider,
model id, credential, settings — and translates a parameter profile into the ModelSettings a
provider will actually accept. A host that keeps its model choice in a catalogue, a tenant account
or a worker profile hands the framework the row; the framework knows the SDK classes, the provider
arguments, and the rules that otherwise surface as a 400 on the first real turn.
Describe¶
from fireflyframework_agentic.models import Credential, ModelSpec
spec = ModelSpec(
provider="anthropic",
model="claude-sonnet-5",
credential=Credential.reference("llm-account-42", version=3), # or Credential.api_key("...")
settings={"maxTokens": 4096, "thinkingBudgetTokens": 8192, "temperature": 0.2},
)
| Field | Meaning |
|---|---|
provider |
anthropic, openai, azure, bedrock, google, google-vertex, mistral, or any OpenAI-compatible endpoint (ollama, openrouter, deepseek, …) with a base_url. |
model |
The provider's id, as the provider names it (anthropic.claude-opus-5 and the cross-region us.anthropic.claude-opus-5-v1:0 on Bedrock, claude-opus-5@… on Vertex are recognised). |
credential |
Credential.api_key(secret), Credential.reference(id, version) redeemed through a CredentialResolver, or Credential.none(). |
settings |
The parameter profile, in the console vocabulary (maxTokens, thinkingBudgetTokens, topP, effort, serviceTier) or pydantic-ai's (max_tokens, …). |
capabilities |
Optional ModelCapabilities; derived from the model id when omitted. |
model_class |
When the provider alone does not decide it: OpenAIResponsesModel beside the default OpenAIChatModel. |
profile_overrides |
Measured corrections to the SDK's derived ModelProfile, applied with dataclasses.replace. |
base_url, api_version, region, project |
Provider arguments where they apply. |
Specs are frozen values: a host may cache built models by them.
Build¶
from fireflyframework_agentic.models import ModelFactory
class Vault:
async def resolve(self, reference: str, version: int) -> str: ...
factory = ModelFactory(credentials=Vault())
model = await factory.build(spec) # a pydantic_ai Model
settings = factory.settings_for(spec) # ModelSettings for FireflyAgent(model_settings=...)
A spec that cannot be followed — an unknown class, a reference with no resolver, a Bedrock
credential of the wrong shape, Azure without an API version — raises ModelBuildError naming
what is wrong. It is a configuration error, so the message says what would fix it and nothing
retries.
What the framework knows about Claude¶
pydantic-ai 1.107's Anthropic profile table predates Claude Opus 5 and Claude Sonnet 5, and no
1.x release carries them. The factory corrects the derived profile for those ids
(fireflyframework_agentic.models.claude) — always with dataclasses.replace, never by
constructing a profile, so the SDK's own thinking_tags and tool versions survive:
| Family | Thinking | budget_tokens |
temperature / top_p / top_k |
Effort levels |
|---|---|---|---|---|
| Opus 5, Sonnet 5 | {"type": "adaptive"} (on by default) |
refused (400) | refused (400) | low … xhigh, max |
| Opus 4.7 / 4.8 | adaptive | refused | refused | low … xhigh, max |
| Opus 4.6 / Sonnet 4.6 | adaptive | deprecated | allowed | low … max |
| Haiku 4.5 and earlier | {"type": "enabled", "budget_tokens": N} |
required for thinking | allowed, except with thinking on | — |
model_settings_for applies those rules to a profile:
>>> model_settings_for(ModelSpec("anthropic", "claude-sonnet-5", settings={"temperature": 0.2, "thinkingBudgetTokens": 8192}))
{'anthropic_thinking': {'type': 'adaptive'}, 'anthropic_effort': 'medium'}
>>> model_settings_for(ModelSpec("anthropic", "claude-haiku-4-5", settings={"temperature": 0.2, "thinkingBudgetTokens": 64000}))
{'anthropic_thinking': {'type': 'enabled', 'budget_tokens': 32000}}
>>> model_settings_for(ModelSpec("openai", "gpt-5", settings={"thinkingBudgetTokens": 8192}))
{'openai_reasoning_effort': 'medium'}
- A model that refuses the sampling knobs loses them whether or not a budget was set — thinking is on by default on the Claude 5 family, so the model turns the rule on, not the budget.
- A budget-style thinking turn also loses them (Anthropic: "
temperaturemay only be set to 1 when thinking is enabled") and the budget is clamped to the model's ceiling. - A budget on an adaptive model is folded onto an effort level through
EFFORT_BUDGETS(minimal1024,low4096,medium8192,high16384,xhigh32768); an expliciteffortwins. An effort-style model takes the label. A model without thinking drops the budget rather than sending a key the provider would reject or ignore. serviceTieris passed only for a model whose capabilities declare it.
Claude on Bedrock¶
Bedrock names the same Claude three ways — anthropic.claude-opus-5 (single region),
us.anthropic.claude-opus-5 / global.anthropic.claude-sonnet-5 / eu. / apac. /
us-gov. (a cross-region inference profile, what a production account calls) and the dated
us.anthropic.claude-haiku-4-5-20251001-v1:0 — and every one is recognised as that Claude.
BedrockConverseModel reads thinking from bedrock_additional_model_requests_fields, never
from anthropic_thinking / anthropic_effort, so for provider="bedrock" the translation
writes the Anthropic wire shape into that key:
>>> model_settings_for(ModelSpec("bedrock", "us.anthropic.claude-opus-5", settings={"temperature": 0.2, "effort": "xhigh"}))
{'bedrock_additional_model_requests_fields': {'thinking': {'type': 'adaptive'}, 'output_config': {'effort': 'xhigh'}}}
>>> model_settings_for(ModelSpec("bedrock", "us.anthropic.claude-haiku-4-5-20251001-v1:0", settings={"thinkingBudgetTokens": 2048}))
{'bedrock_additional_model_requests_fields': {'thinking': {'type': 'enabled', 'budget_tokens': 2048}}}
The built model's profile is the Bedrock provider's own (tool choice, prompt caching, the
Bedrock JSON-schema transformer all kept) with the Claude 5 corrections mapped onto Bedrock's
flags (bedrock_supports_adaptive_thinking, bedrock_supports_effort), not an Anthropic
profile put in its place.
Cost¶
genai-prices does not price the Claude 5 ids yet, so the default resolver chain carries a
framework price table (framework_price_table_cost, before genai_prices_cost) with the
Anthropic first-party rates for claude-opus-5, claude-sonnet-5 and claude-fable-5, cache
writes at 1.25× and cache reads at 0.10× input. A row is removed the day genai-prices carries it.