Model capability negotiation¶
Treelang keeps model feature discovery separate from Arborist request
orchestration. A model transport may implement CapabilityAwareTransport and
return ModelCapabilities for each model or deployment:
from treelang import ModelCapabilities
class CustomTransport:
def capabilities(self, model: str) -> ModelCapabilities:
return ModelCapabilities(
strict_json_schema=model == "strict-deployment",
temperature=True,
)
Transports that do not implement capability discovery receive conservative defaults: strict JSON Schema and temperature are both disabled. Capability claims must reflect the model as exposed through that transport, not just a similarly named model offered elsewhere.
DefaultModelCapabilityNegotiator converts declared capabilities and
ArboristConfig.structured_output_mode into a StructuredOutputSelection. It
owns strict/compatibility selection, required-mode rejection, and the one allowed
automatic downgrade after a provider explicitly rejects strict output.
OpenAIArborist only applies that decision and records redacted observability
events.
Applications and future provider adapters can inject a custom
ModelCapabilityNegotiator into OpenAIArborist when deployments need different
policy. A negotiator must:
- discover capabilities without making model requests;
- return a complete response-format selection;
- refuse unsupported required capabilities before a request is sent;
- allow fallback only when its policy explicitly permits it; and
- avoid using authentication, rate-limit, timeout, cancellation, or unrelated provider errors as evidence that a capability is unavailable.
OpenAI model-name heuristics are confined to OpenAITransport. They are not part
of provider-neutral Arborist orchestration.
The generated provider compatibility matrix publishes these claims from a machine-readable manifest. Normal CI checks every representative model profile against the adapter capability functions and rejects stale output.