feat: add opt-in provider runtime abstraction (#17713)

## Summary

- Add `codex-model-provider` as the runtime home for model-provider
behavior that does not belong in `codex-core`, `codex-login`, or
`codex-api`.
- The new crate wraps configured `ModelProviderInfo` in a
`ModelProvider` trait object that can resolve the API provider config,
provider-scoped auth manager, and request auth provider for each call.
- This centralizes provider auth behavior in one place today, and gives
us an extension point for future provider-specific auth, model listing,
request setup, and related runtime behavior.

## Tests
Ran tests manually to make sure that provider auth under different
configs still work as expected.

---------

Co-authored-by: pakrym-oai <pakrym@openai.com>
This commit is contained in:
Celia Chen
2026-04-16 19:27:45 -07:00
committed by GitHub
parent 91e8eebd03
commit a803790a10
45 changed files with 577 additions and 369 deletions

View File

@@ -200,7 +200,7 @@ data: {"id":"resp-1","output":[{"type":"message","role":"assistant","content":[{
async fn responses_client_uses_responses_path() -> Result<()> {
let state = RecordingState::default();
let transport = RecordingTransport::new(state.clone());
let client = ResponsesClient::new(transport, provider("openai"), NoAuth);
let client = ResponsesClient::new(transport, provider("openai"), Arc::new(NoAuth));
let body = serde_json::json!({ "echo": true });
let _stream = client
@@ -221,7 +221,7 @@ async fn responses_client_uses_responses_path() -> Result<()> {
async fn streaming_client_adds_auth_headers() -> Result<()> {
let state = RecordingState::default();
let transport = RecordingTransport::new(state.clone());
let auth = StaticAuth::new("secret-token", "acct-1");
let auth = Arc::new(StaticAuth::new("secret-token", "acct-1"));
let client = ResponsesClient::new(transport, provider("openai"), auth);
let body = serde_json::json!({ "model": "gpt-test" });
@@ -281,7 +281,7 @@ async fn streaming_client_retries_on_transport_error() -> Result<()> {
text: None,
client_metadata: None,
};
let client = ResponsesClient::new(transport.clone(), provider, NoAuth);
let client = ResponsesClient::new(transport.clone(), provider, Arc::new(NoAuth));
let _stream = client
.stream_request(
@@ -300,7 +300,7 @@ async fn streaming_client_retries_on_transport_error() -> Result<()> {
async fn azure_default_store_attaches_ids_and_headers() -> Result<()> {
let state = RecordingState::default();
let transport = RecordingTransport::new(state.clone());
let client = ResponsesClient::new(transport, provider("azure"), NoAuth);
let client = ResponsesClient::new(transport, provider("azure"), Arc::new(NoAuth));
let request = ResponsesApiRequest {
model: "gpt-test".into(),