feat!: rig-reqwest — cut the bundled transport into its own crate; rig-core has no default transport and no reqwest/tokio - #2397
Merged
Conversation
…g-core has no default transport and no reqwest/tokio
Bevy-prep PR 4 (final). rig-core is now transport-agnostic all the way
down: it names no default HTTP transport and depends on neither reqwest
nor tokio. The bundled reqwest transport and everything that depends on
it — the default-transport constructors, the aliased provider tree, the
OpenAI Responses websocket — live in the new rig-reqwest crate, which the
rig facade re-exports behind its (default) reqwest feature. Through the
facade, rig::providers::openai::Client::from_env() / ::new(..) /
::builder().build() and Agent<openai::CompletionModel> are unchanged.
rig-core
- No H = reqwest::Client defaults anywhere (107 sites: provider aliases,
Generic*Model structs, the anthropic_compatible!/model_listing macros,
Client<Ext, H>, Capabilities<H>, ModelLister<H>); H is always explicit.
- Construction is generic: Client::new_with(api_key, http), builder() on
Client<Ext, Missing> (single inherent impl, so H infers), and the new
ProviderFromEnv trait on each provider extension type
(from_env_with(http) / from_val_with(input, http)) replaces the 29
reqwest-pinned ProviderClient impls and impl_provider_client!. The
ProviderClient trait stays for companion crates' own client types.
The reqwest-substituting ClientBuilder<.., Missing>::build() is gone;
llamacpp::Client::from_url is from_url_with(url, http).
- reqwest_transport.rs and the openai websocket module move out; a few
streaming internals the websocket needs become #[doc(hidden)] pub.
- Dependencies: reqwest, reqwest-middleware, tokio, tokio-tungstenite
removed; default features are ["derive"]. cargo tree -p rig-core
-e normal shows no tokio and no reqwest (default and no-default).
- Own tests: ~400 construction sites across 61 files now go through the
test_utils mock (rig-core cannot dev-depend on rig-reqwest without a
cycle); 51 doc examples that showed the default transport are ignore.
rig-reqwest (new)
- ReqwestClient(reqwest::Client) newtype implementing HttpClientExt —
a newtype because the orphan rule forbids implementing rig-core's
trait for reqwest's type from a third crate (the plan's "no wrapper"
was wrong); ReqwestMiddlewareClient behind reqwest-middleware.
- DefaultTransportClient / DefaultTransportBuilder: one blanket impl
each, pinned to Client<Ext, ReqwestClient>, giving every provider
client new/from_env/from_val and builder().build() with the transport
inferred (type-alias defaults don't apply in expression position, so
aliases alone could not do this).
- providers: the provider module tree with every transport-generic
type aliased to <ReqwestClient> for type position (114 aliases,
generated; tests/providers_complete.rs cross-checks the rig-core
sources so a missing alias fails the build).
- Runtime bridge: inside tokio, reqwest futures are awaited directly;
outside (Bevy task pools, smol, futures::executor) they run on a
lazily started single-worker runtime and the caller only polls
runtime-agnostic futures — unary bodies are read eagerly on the tokio
side, streamed bodies are forwarded through a bounded futures mpsc
channel. Covered by tests/off_runtime.rs driving a request and a
chunked stream from futures::executor::block_on.
- openai_websocket (feature websocket) with the ResponsesWebSocketExt
trait replacing the inherent impl; the websocket conformance suite
moves here.
Facade / workspace
- rig re-exports rig-reqwest (providers, http_client::ReqwestClient /
from_reqwest, client::{DefaultTransportClient, DefaultTransportBuilder},
prelude) behind the reqwest feature; websocket*/rustls/native-tls/
socks/reqwest-middleware* features forward to rig-reqwest.
cargo check -p rig --no-default-features --features agent,derive is
tokio/reqwest-free.
- rig-agent's tokio is optional (rmcp, discord-bot); companion crates'
examples and rig-agent's tests/docs dev-depend on rig-reqwest.
- CI wasm matrix + nextest package lists include rig-reqwest; the serde
wall allowlist, conformance registry and provider-layout guards follow
the moved code. MIGRATING.md documents the whole change.
Verification: cargo check/clippy --workspace --all-features
--all-targets clean; rig-core 1690, rig-reqwest 62, rig-agent 593 (+ 13
doctests), facade 3394 tests pass; wasm32 checks pass for rig-core,
rig-reqwest and rig; cargo package succeeds for every crate (a full
publish dry-run cannot verify against the registry at the unbumped
0.42.0 version — pre-existing).
…e rig-reqwest prelude, rig-agent test-utils enables tokio
This was referenced Aug 22, 2026
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 4, the last of the series (#2394 → #2395 → #2396 → this). rig-core is now transport-agnostic all the way down: it names no default HTTP transport and depends on neither reqwest nor tokio. The bundled reqwest transport and everything that depends on it — the default-transport constructors, the aliased provider tree, the OpenAI Responses websocket — live in the new
rig-reqwestcrate, which therigfacade re-exports behind its (default)reqwestfeature. Through the facade the common path is unchanged:rig-core
H = reqwest::Clientdefault anywhere (107 sites: provider aliases,Generic*Modelstructs, theanthropic_compatible!/model_listingmacros,Client<Ext, H>,Capabilities<H>,ModelLister<H>);His always explicit.Client::new_with(api_key, http);builder()lives onClient<Ext, Missing>(single inherent impl, soprovider::Client::builder()infersH); and the newProviderFromEnvtrait on each provider extension type (from_env_with(http)/from_val_with(input, http)) replaces the 29 reqwest-pinnedProviderClientimpls andimpl_provider_client!— all the env-var knowledge stays in rig-core, generic over the transport. TheProviderClienttrait stays (rig-bedrock/vertexai/gemini-grpc implement it for their own clients). The reqwest-substitutingClientBuilder<…, Missing>::build()is gone;llamacpp::Client::from_urlisfrom_url_with(url, http).http_client/reqwest_transport.rsand the openai websocket module move out; a handful of streaming internals the websocket needs are#[doc(hidden)] pub.reqwest,reqwest-middleware,tokio,tokio-tungsteniteremoved; default features are["derive"].cargo tree -p rig-core -e normalshows no tokio and no reqwest, with default features and with--no-default-features.test_utilsmock (rig-core cannot dev-depend on rig-reqwest without a dependency cycle). 51 doc examples that demonstrated the default transport are markedignore; three#[ignore]live Azure tests that needed a real transport are deleted.rig-reqwest (new crate)
ReqwestClient(reqwest::Client)newtype implementingHttpClientExt, plusReqwestMiddlewareClientbehindreqwest-middleware. A newtype is forced: the orphan rule forbids implementing rig-core's trait for reqwest's type from a third crate (the plan's "no wrapper newtype" was wrong, andFrom<NoBody> for reqwest::Bodyhad to be deleted for the same reason). It derefs to the inner client and convertsFrom<reqwest::Client>.DefaultTransportClient/DefaultTransportBuilder— one blanket impl each, pinned toClient<Ext, ReqwestClient>, giving every provider clientnew/from_env/from_valandbuilder().build()with the transport inferred. (Type-alias defaults don't apply in expression position, verified with rustc, so an alias tree alone could not do this; rig-core'sProviderClientand these traits coexist in the prelude without ambiguity because their impl sets are disjoint.)providers: the provider module tree with every transport-generic type aliased to…<ReqwestClient>for type position — 114 aliases, generated from the provider sources and guarded bytests/providers_complete.rs, which cross-reads rig-core's sources (incl. the inlineimage_generation/audio_generationmodules and macro-generated types) so a missing alias fails the build.futures::executor) they run on a lazily started single-worker runtime (LazyLock<Result<Runtime, _>>— a start failure surfaces as a transport error, no panic) and the caller only ever polls runtime-agnostic futures: unary bodies are read eagerly on the tokio side, streamed bodies are forwarded through a boundedfutures::channel::mpsc.tests/off_runtime.rsdrives a request and a chunked stream entirely fromfutures::executor::block_on. wasm builds call reqwest's fetch backend directly (no bridge).openai_websocket(featurewebsocket) with theResponsesWebSocketExttrait replacing the former inherentimpl Client<reqwest::Client>; the websocket conformance suite moves here.Facade and workspace
rigre-exports rig-reqwest behind thereqwestfeature:rig::providers,rig::http_client::{ReqwestClient, from_reqwest},rig::client::{DefaultTransportClient, DefaultTransportBuilder}, and the prelude. Thewebsocket*/rustls/native-tls/socks/reqwest-middleware*features now forward to rig-reqwest.cargo check -p rig --no-default-features --features agent,deriveis tokio/reqwest-free — the Bevy configuration.tokiois optional (enabled byrmcp,discord-bot); companion crates' examples and rig-agent's tests/doc examples dev-depend on rig-reqwest.ProviderClientexplicitly for core providers.Verification
cargo check --workspace --all-features --all-targetsandcargo clippy(same flags): clean.cargo checkpasses for rig-core (all features), rig-reqwest, and rig.cargo tree -p rig-core -e normal: no tokio, no reqwest (both feature sets).cargo tree -p rig -e normal --no-default-features --features agent,derive: likewise.cargo packagesucceeds for every crate. A fullcargo publish --workspace --dry-runcannot verify dependents against the registry at the unbumped 0.42.0 version (rig-core 0.42.0 already exists upstream with a different checksum) — a pre-existing property of the unbumped workspace; the release-plz PR is where that check runs.