Skip to content

refactor!: confine reqwest to one transport module; auth flows go through HttpClientExt - #2396

Merged
gold-silver-copper merged 1 commit into
mainfrom
bevy-prep/confine-reqwest
Aug 21, 2026
Merged

refactor!: confine reqwest to one transport module; auth flows go through HttpClientExt#2396
gold-silver-copper merged 1 commit into
mainfrom
bevy-prep/confine-reqwest

Conversation

@gold-silver-copper

Copy link
Copy Markdown
Contributor

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 an H = reqwest::Client type-parameter default or a pinned constructor, which the next PR relocates into the rig facade so rig-core can drop the dependency entirely.

Auditing for this PR showed the transport trait needed no redesign: HttpClientExt was already expressed in http::Request/Response<LazyBody>, Response<BoxedStream> and Request<MultipartForm>, and providers were already generic over H. The genuine reqwest usage outside http_client/ was small and is fully handled here.

Changes

http_client — one reqwest module. The reqwest-driven pieces (ReqwestClient re-export, From<NoBody> for reqwest::Body, from_reqwest, into_lazy_response, the non-success shim, the MultipartFormreqwest::multipart::Form renderer, the two HttpClientExt impls and their tests) move to reqwest_transport.rs. The impl_http_client_ext! macro is deleted in favour of two plain impl blocks (reqwest::Client, and reqwest_middleware::ClientWithMiddleware under its feature) that share a single 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 any HttpClientExt implementation can build the headers-preserving error (rig#2210/#2314) without reqwest. sse.rs's reqwest::header::CONTENT_TYPE now comes from http. http_client::ReqwestClient / from_reqwest keep resolving at their current paths via re-export.

Auth flows through HttpClientExt. The copilot/chatgpt OAuth, device-code and token-refresh flows built ad-hoc reqwest::Client::new() instances — five sites across the native and wasm halves, bypassing the transport abstraction entirely. They now run through HttpClientExt. The client's own transport is passed at call time (Authenticator::auth_context(http)) through a new Client::http_client() accessor, which keeps CopilotExt/ChatGPTExt 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, copilot's retry-with-fresh-token on 401/403) read the status off the http_client::Error, preserving behaviour. The chatgpt/copilot model impls gain an explicit H: HttpClientExt bound alongside the existing Client<H>: HttpClientExt one.

AuthError::Http(reqwest::Error)Http(http_client::Error). Public via copilot::auth::AuthError / chatgpt::auth::AuthError; MIGRATING.md shows how to read the status off the new shape.

Re-export slips. reqwest::header::* / reqwest::StatusCode uses in the auth modules now import from http.

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-features to drop reqwest here, but the 107 H = reqwest::Client defaults 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.rs Client<Ext = Nothing, H = reqwest::Client>, Capabilities<H = …>, the impl<Ext> Client<Ext, reqwest::Client> constructors and ClientBuilder<…, Missing>::build(); client/model_listing.rs ModelLister<H = …>; providers/openai/client.rs:149 pinned impl Client<reqwest::Client>; and the per-provider pub type X<H = reqwest::Client> aliases.

Verification

  • cargo check --workspace --all-features --all-targets and cargo 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; the non_success_headers_absent_when_not_captured test stays in mod.rs.
  • CI's cargo check -p rig-core --all-features --target wasm32-unknown-unknown: clean — the copilot wasm auth half is one of the rerouted sites.
  • MIGRATING.md (0.41 → next): AuthError::Http change + auth_context(http) signature; ReqwestClient/from_reqwest module move; the new Error::non_success_with_details constructor for custom transports.

…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.
@gold-silver-copper
gold-silver-copper added this pull request to the merge queue Aug 21, 2026
Merged via the queue into main with commit ce2652e Aug 21, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant