ReqLLM. Images. OpenAICompatible
(ReqLLM v1.21.0)
View Source
Shared codec for providers that speak the OpenAI Images wire format.
Currently used by ReqLLM.Providers.OpenAI (via
ReqLLM.Providers.OpenAI.ImagesAPI) and ReqLLM.Providers.Azure. It owns the
encoding rules — option translation, body/multipart construction, and response
decoding — so no provider has to restate them.
Option pipeline
Options flow through two steps in a fixed order, and each step has exactly one job:
1. validate_options/1 reject what no translation can express
2. translate_options/2 resolve, drop, and warn on validated inputvalidate_options/1 runs before ReqLLM.Provider.Options.process/4, so
translate_options/2 — which process/4 invokes through the provider's
ReqLLM.Provider.translate_options/3 callback — only ever sees input it can
express. That ordering is why translate_options/2 may return {opts, warnings} and never an error: everything unrepresentable was already
rejected, and everything else is a lossy-but-valid transformation reported as
a warning through :on_unsupported.
Wire format
Generation is a JSON POST to path(:generation); editing is a multipart POST
to path(:edit), signalled by a non-nil :source_image.
Summary
Functions
Builds the JSON body map for the generations endpoint.
Decodes an Images API response into a canonical ReqLLM.Response.
Builds the Req :form_multipart keyword list for the edits endpoint.
Normalizes image generation input into a {:ok, context, prompt} tuple.
Returns true when the options describe an image edit rather than a generation.
Endpoint path for an image :generation or :edit.
Image option keys providers should register on the Req request.
Translates generic image options into what the Images API accepts.
Rejects image options the Images API cannot express under any translation.
Functions
Builds the JSON body map for the generations endpoint.
Accepts a map or keyword list with :model, :prompt, and the optional
image generation options (:n, :size, :quality, :style, :user,
:output_format, :response_format).
Expects options that have already been through translate_options/2, which
resolves :aspect_ratio into :size and drops options the Images API has no
field for.
:model must be the catalog model id rather than a provider-side alias: it
decides whether response_format is a legal field for the target model.
Callers that send a different identifier on the wire (e.g. an Azure
deployment name) should replace "model" in the returned map afterwards.
@spec decode_response({Req.Request.t(), Req.Response.t()}) :: {Req.Request.t(), Req.Response.t() | Exception.t()}
Decodes an Images API response into a canonical ReqLLM.Response.
Non-2xx statuses are returned as a ReqLLM.Error.API.Response for the caller
to surface; providers with their own error extraction should route those
through it before reaching here.
Builds the Req :form_multipart keyword list for the edits endpoint.
Required keys in opts: :model, :prompt, :source_image. Optional keys
(:mask, :n, :size, :quality, :output_format, :user, and the
*_media_type companions) are added only when present.
@spec image_context( term(), keyword() ) :: {:ok, ReqLLM.Context.t(), String.t()} | {:error, term()}
Normalizes image generation input into a {:ok, context, prompt} tuple.
Uses an existing :context option when present, otherwise normalizes the
prompt/messages input. The prompt is the text content of the last user
message; an empty prompt is an error.
Returns true when the options describe an image edit rather than a generation.
An edit is signalled by a non-nil :source_image. An explicitly nil
:source_image is treated as a generation, since a multipart edit request
cannot be built without image bytes.
@spec path(:generation | :edit) :: String.t()
Endpoint path for an image :generation or :edit.
Providers that mount the Images API under a different prefix (Azure's deployment-scoped routes) build on top of these suffixes.
@spec request_option_keys() :: [atom()]
Image option keys providers should register on the Req request.
Covers every option that can reach the wire, plus :prompt. Plumbing options
(:provider_options, :receive_timeout, …) are deliberately excluded —
request-building layers register and merge those themselves.
Translates generic image options into what the Images API accepts.
Returns {opts, warnings} in the shape the ReqLLM.Provider.translate_options/3
callback expects, so providers sharing this codec route through it and the
transformations surface through :on_unsupported.
Drops options the API has no field for (:seed, :negative_prompt, and
:style outside DALL-E 3), maps the DALL-E quality names (:standard/:hd)
onto the gpt-image ones, and resolves :aspect_ratio into the nearest :size
the model offers — the only place that resolution happens.
Assumes validate_options/1 has already run: a malformed :aspect_ratio is
left untouched rather than raising, since it should never get this far.
model_id must be the catalog model id, since the accepted fields and sizes
differ between the gpt-image and DALL-E families.
@spec validate_options(keyword()) :: :ok | {:error, Exception.t()}
Rejects image options the Images API cannot express under any translation.
Run this before ReqLLM.Provider.Options.process/4, so that
translate_options/2 receives only representable input. Rejects a malformed
:aspect_ratio and a :mask without a :source_image; a well-formed
:aspect_ratio is left for translate_options/2 to resolve.