refactor!: confine reqwest to one transport module; auth flows go through HttpClientExt - #2396
Merged
Merged
Conversation
…ough HttpClientExt Bevy-prep PR 3. After this change the only non-test code in rig-core that calls reqwest lives in http_client/reqwest_transport.rs; the remaining mentions elsewhere are the H = reqwest::Client type defaults and pinned constructors, which move to the facade in the next PR. - http_client: the reqwest-driven pieces (ReqwestClient re-export, From<NoBody> for reqwest::Body, from_reqwest, into_lazy_response, the non-success shim, the MultipartForm renderer, the impls and their tests) move to a new reqwest_transport module. The impl_http_client_ext! macro is deleted in favour of two plain impls (reqwest::Client, reqwest_middleware::ClientWithMiddleware) sharing one private request-driving path over a tiny ReqwestLike trait. The transport-agnostic half of the non-success constructor is now Error::non_success_with_details(status, headers, body) so other transports can build the headers-preserving error. HttpClientExt itself is unchanged — it was already expressed in http types. - auth: the copilot/chatgpt OAuth, device-code and token-refresh flows drove ad-hoc reqwest::Client::new() instances (five sites across the native and wasm halves). They now run through HttpClientExt: the client's own transport is passed at call time (Authenticator::auth_context(http)) via the new Client::http_client() accessor, so CopilotExt/ChatGPTExt stay non-generic. Shared request/send_json/send_bytes helpers live in providers::internal::auth. Status-dependent branches (device-flow pending 403/404, refresh invalid_grant) read the status off the http_client::Error. - AuthError::Http(reqwest::Error) -> Http(http_client::Error); it is public via copilot::auth / chatgpt::auth (MIGRATING.md entries). - reqwest::header::* / reqwest::StatusCode re-export uses in the auth modules and sse.rs now import from http. Deviation from the plan: reqwest stays a non-optional dependency of rig-core for now — the 107 H = reqwest::Client defaults still name the crate, so --no-default-features cannot drop it until those move to the facade in the next PR (which will also gate the transport module). Verification: cargo check/clippy --workspace --all-features --all-targets clean; rig-core 1799 + rig-agent 598 tests pass; CI's wasm32 rig-core check passes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bevy-prep PR 3 (follows #2394, #2395). After this change the only non-test code in rig-core that calls reqwest lives in one module,
http_client/reqwest_transport.rs; every remaining mention elsewhere is anH = reqwest::Clienttype-parameter default or a pinned constructor, which the next PR relocates into therigfacade so rig-core can drop the dependency entirely.Auditing for this PR showed the transport trait needed no redesign:
HttpClientExtwas already expressed inhttp::Request/Response<LazyBody>,Response<BoxedStream>andRequest<MultipartForm>, and providers were already generic overH. The genuine reqwest usage outsidehttp_client/was small and is fully handled here.Changes
http_client— one reqwest module. The reqwest-driven pieces (ReqwestClientre-export,From<NoBody> for reqwest::Body,from_reqwest,into_lazy_response, the non-success shim, theMultipartForm→reqwest::multipart::Formrenderer, the twoHttpClientExtimpls and their tests) move toreqwest_transport.rs. Theimpl_http_client_ext!macro is deleted in favour of two plainimplblocks (reqwest::Client, andreqwest_middleware::ClientWithMiddlewareunder its feature) that share a single private request-driving path over a tinyReqwestLiketrait. The transport-agnostic half of the non-success constructor is nowError::non_success_with_details(status, headers, body), so anyHttpClientExtimplementation can build the headers-preserving error (rig#2210/#2314) without reqwest.sse.rs'sreqwest::header::CONTENT_TYPEnow comes fromhttp.http_client::ReqwestClient/from_reqwestkeep resolving at their current paths via re-export.Auth flows through
HttpClientExt. The copilot/chatgpt OAuth, device-code and token-refresh flows built ad-hocreqwest::Client::new()instances — five sites across the native and wasm halves, bypassing the transport abstraction entirely. They now run throughHttpClientExt. The client's own transport is passed at call time (Authenticator::auth_context(http)) through a newClient::http_client()accessor, which keepsCopilotExt/ChatGPTExtnon-generic; sharedrequest/send_json/send_byteshelpers live inproviders::internal::auth. Status-dependent branches (device-flow "pending" 403/404, refreshinvalid_grant, copilot's retry-with-fresh-token on 401/403) read the status off thehttp_client::Error, preserving behaviour. The chatgpt/copilot model impls gain an explicitH: HttpClientExtbound alongside the existingClient<H>: HttpClientExtone.AuthError::Http(reqwest::Error)→Http(http_client::Error). Public viacopilot::auth::AuthError/chatgpt::auth::AuthError; MIGRATING.md shows how to read the status off the new shape.Re-export slips.
reqwest::header::*/reqwest::StatusCodeuses in the auth modules now import fromhttp.Deviation from the plan, stated plainly
reqwest stays a non-optional dependency of rig-core in this PR and the transport module is ungated. The plan wanted
--no-default-featuresto drop reqwest here, but the 107H = reqwest::Clientdefaults across the providers still name the crate, so that only becomes possible once the next PR moves the default transport to the facade (that PR will also make the dependency optional and gate the module).Remaining reqwest mentions in rig-core outside
reqwest_transport.rs(all defaults / pinned constructors / tests, cataloged for the next PR):client/mod.rsClient<Ext = Nothing, H = reqwest::Client>,Capabilities<H = …>, theimpl<Ext> Client<Ext, reqwest::Client>constructors andClientBuilder<…, Missing>::build();client/model_listing.rsModelLister<H = …>;providers/openai/client.rs:149pinnedimpl Client<reqwest::Client>; and the per-providerpub type X<H = reqwest::Client>aliases.Verification
cargo check --workspace --all-features --all-targetsandcargo clippy(same flags): clean.cargo test -p rig-core --all-features: 1799 passed;-p rig-agent: 598 passed; 0 failures (whole provider test binaries, cassettes included). The rig#2210/feat: carry the provider transport request id on completion errors (error-path identity capture) #2314 header-preservation tests moved with the transport module and pass; thenon_success_headers_absent_when_not_capturedtest stays inmod.rs.cargo check -p rig-core --all-features --target wasm32-unknown-unknown: clean — the copilot wasm auth half is one of the rerouted sites.0.41 → next):AuthError::Httpchange +auth_context(http)signature;ReqwestClient/from_reqwestmodule move; the newError::non_success_with_detailsconstructor for custom transports.