A lightweight Elixir client for AI APIs, built on Req.
Provides consistent generation, streaming, and telemetry with provider-native
requests and responses. Call generate/2 or stream/4 with a provider module
and a provider-native request body. Use ReqAI.Provider.new/2 to configure
a provider explicitly when additional options are needed.
Optional ReqAI.Translator callbacks let applications define their own shared
representations while retaining access to the full Req.Response.
Summary
Functions
@spec generate(provider :: ReqAI.Provider.t() | module(), request :: term()) :: {:ok, Req.Response.t(), term()} | {:error, Req.Response.t(), term()} | {:error, Exception.t()}
Generates a response.
Accepts a configured provider or a provider module. Passing a module calls
ReqAI.Provider.new/2 with no additional options on each invocation, reading
the provider's application-configured HTTP options at that time.
The configured provider builds the request with streaming disabled. The
Req.Response is always returned unchanged as the second element when the
request completes at the HTTP level. The third element is an
application-owned value produced from that response.
For successful responses, the third element is produced by
ReqAI.Translator.response/2; for non-successful responses, it is produced
by ReqAI.Translator.error/2. Both default to response.body when their
callback is not implemented. Transport and decoding failures return
{:error, exception} because no HTTP response or provider-native body is
available.
@spec stream( provider :: ReqAI.Provider.t() | module(), request :: term(), acc, fun :: (term(), Req.Response.t(), acc -> {:cont, acc} | {:halt, acc}) ) :: {:ok, Req.Response.t(), acc} | {:error, Req.Response.t(), acc} | {:error, Exception.t(), Req.Response.t() | nil, acc} when acc: term()
Streams a response into an accumulator.
Accepts a configured provider or a provider module. Passing a module calls
ReqAI.Provider.new/2 with no additional options on each invocation, reading
the provider's application-configured HTTP options at that time.
Raises ArgumentError if the provider does not implement
ReqAI.Provider.decode_event/3.
The provider builds the request with streaming enabled. fun receives each
provider-native event, the response as it is being received, and the current
accumulator. It must return {:cont, acc} to continue or {:halt, acc} to
stop consuming the response.
Req handles transport formats such as SSE and NDJSON, then the provider
decodes the resulting values and drops protocol-only events. For the built-in
providers, an SSE event remains a map and its JSON payload is decoded in the
:data field. When a translator implements ReqAI.Translator.event/3, fun
receives its return value. The accompanying response remains the in-progress
Req.Response.
The completed Req.Response remains available. For a successful
stream, the accumulator is the application-owned result of consuming the
translated events. For a non-successful stream, the third element is produced
by ReqAI.Translator.error/2, defaulting to the buffered response body.
Non-successful HTTP responses are not passed to fun. Their streamed data is
instead collected into response.body; JSON error bodies are decoded when
possible.
Returns {:ok, response, acc} for a successful HTTP response,
{:error, response, error} for a non-successful HTTP response, or
{:error, exception, response, acc} for a transport or decoding error.