.agents/references/model-provider-boundaries.md
Use this reference for changes to model resolution, ModelSettings, provider adapters, Responses versus Chat Completions behavior, request conversion, streaming terminal events, transport reuse, or model retries.
The run loop depends on the Model interface, not on one provider's request or response schema.
Model.get_response() returns a normalized ModelResponse.Model.stream_response() yields normalized response stream events while preserving provider payloads needed by public raw-event consumers.ModelProvider.get_model() resolves names to model implementations and owns provider-level caches or connections.Model.close() and ModelProvider.aclose() release persistent transport resources when an implementation owns them.Provider adapters own request construction, provider feature validation, terminal event interpretation, usage conversion, and translation into SDK item shapes. Keep provider-specific branching out of the core run loop unless it represents a shared SDK contract.
RunConfig.model overrides the agent model. A model instance is used directly; a model name is resolved through the configured ModelProvider.None values. Preserve the documented merge behavior for structured fields such as extra_args and retry settings.ModelSettings.to_traceable_dict() is the boundary for settings considered safe and meaningful in traces.Do not infer that a feature available in one adapter is supported by every Model implementation.
Model contract. New provider-specific fields need an explicit conversion and fallback policy.Validate capabilities at the adapter boundary where the resolved model and complete request are known. Avoid public flags that appear accepted by the SDK but are silently dropped before the provider request.
Do not duplicate provider-side request validation in the SDK merely to fail earlier. When the provider already rejects an invalid value with an actionable error, preserve that single source of truth instead of copying provider grammar, length limits, enum membership, or other request constraints into SDK runtime code. Duplicated validation can drift as provider contracts evolve, can reject values accepted by another provider, and can turn a provider-neutral SDK type into an accidental provider-specific contract.
Add SDK-side validation only when it enforces an SDK-owned invariant or prevents a concrete risk that provider validation cannot address. Examples include ambiguous local routing, collisions before request serialization, invalid persisted state, unsafe local side effects, or a provider error that cannot identify the offending SDK input. A generic preference for earlier failure or a different error message is not sufficient.
When local validation is justified and the constraint is provider-specific, keep it at the owning adapter boundary and derive it from an authoritative provider contract. Do not apply it to shared Model interfaces, provider-neutral tool types, or third-party adapters. Tests should distinguish the SDK-owned invariant from values that are intentionally left for the provider to validate.
None, make that field-specific contract explicit in the normalization, documentation, and tests rather than applying a generic optional-number rule.failed and incomplete terminals, explicit error events, and a missing terminal payload must produce the documented failure behavior in both HTTP and websocket paths.ModelResponse, errors, request IDs, and usage.asyncio.Lock across loops.aclose() close every unique cached model and clear its caches. Close on a still-running owner loop when possible; do not drive an inactive foreign loop inside asyncio.to_thread().src/agents/models/interface.pysrc/agents/model_settings.pysrc/agents/run_internal/turn_preparation.pysrc/agents/models/openai_responses.pysrc/agents/models/openai_chatcompletions.pysrc/agents/models/multi_provider.pysrc/agents/models/_response_terminal.pysrc/agents/run_internal/model_retry.pytests/models/tests/test_config.py