symfonic.services.models.descriptors¶
descriptors ¶
The provider capability table โ one row per shipped adapter.
Before this module the same facts were spelled out three times: as call-site
literals in providers.py (timeout_kwarg="timeout"), as supports_*
method bodies, and as family comparisons in the cache layer. A row here is the
declaration; tests/services/models/test_provider_contract.py checks each
row against the live adapter, and providers.py reads the kwarg names back
out of the table so the two cannot drift.
Stdlib-only at module scope on purpose โ symfonic.core.providers imports
this module, so any import of symfonic.core from here would close a cycle.
ProviderDescriptor
dataclass
¶
ProviderDescriptor(label: str, family: ProviderFamily, default_model: str | None, thinking: bool, streaming: bool, thinking_blocks_forced_tool_choice: bool, timeouts: TimeoutBinding, sampling: SamplingSupport)
The static half of a provider's capabilities.
default_model = None is an explicit abstention, not an omission: a
gateway adapter (OpenRouter, Bedrock, the OAuth adapters) serves whatever
model the caller names, so declaring one would be a guess. The contract
checker requires the declaration to exist, which is what turns "nobody
thought about it" into a reviewed decision.
cache_dialect_for ¶
The prompt-cache annotation dialect for a wire family.
Total over the closed family set, and derived rather than assigned: an
adapter cannot claim cache_control support without claiming the
Anthropic wire family that actually accepts it.
Source code in src/symfonic/services/models/descriptors.py
descriptor_for_family ¶
The fallback row for a family. Total over the closed family set.
descriptor_for_provider ¶
Best row for provider, descending routing wrappers like the classifier.
Shipped adapters match by class name; everything else falls back to the row
for the family detect_provider_family assigns, so an adopter's own
provider still gets a coherent (if generic) capability answer.