The seam between the public image API and one provider's HTTP shape.
Consumers never see a provider: they call PhoenixKitAI.process_image/4,
PhoenixKitAI.edit_image/4 or PhoenixKitAI.generate_image/3 with an
endpoint, and the endpoint's provider picks the adapter. Switching a
module from OpenRouter to xAI, OpenAI or a provider added later is a
change of endpoint, not of code.
An adapter implements this behaviour and is selected by the endpoint's
base provider key (PhoenixKitAI.Endpoint.base_provider/1):
| provider key | adapter |
|---|---|
"openrouter" | PhoenixKitAI.Providers.OpenRouter — the unified Images API |
"xai" | PhoenixKitAI.Providers.XAI — JSON /images/edits |
"openai" | PhoenixKitAI.Providers.OpenAI — multipart /images/edits |
| anything else | PhoenixKitAI.Providers.OpenAICompatible — chat completions with image parts |
Vision (describe / compare) goes through the adapter's optional
vision/3, falling back to the chat-completions implementation.
A host adds or replaces adapters without touching this module:
config :phoenix_kit_ai, provider_adapters: %{"fal" => MyApp.FalAdapter}The key is the Integrations provider key the endpoint carries; the value is a module implementing this behaviour.
Contract
Every adapter receives already-normalised inputs: reference images as
data URLs (bytes inlined) or http(s) URLs, and options as a map with
the canonical keys from PhoenixKitAI.Images (:aspect_ratio,
:resolution, :size, :quality, :background, :output_format,
:output_compression, :n, :seed, :response_format), plus
:model (an override of the endpoint's model), :transport (an
adapter-specific hint) and :provider_options (a map passed through
to the provider untouched). It returns the uniform image result or one
of the module's error atoms/tuples.
Summary
Callbacks
Image-in, image-out: edit refs (first = the image to change) per prompt.
The request option names image_edit/4 actually sends for these
options. Optional — defaults to image_options/1. An adapter whose
edit transport sends less than its generation one (a chat-completions
edit carries only an aspect ratio) implements this, so
PhoenixKitAI.Images.process/4 drops the rest with a warning and picks
the operations' fallback wording instead of sending them nowhere.
Text-to-image.
The provider's image models with their constraints, when it publishes them.
Option names the adapter can send when no per-model listing exists.
Vision: a chat-shaped question about images. Optional — adapters that
do not implement it get PhoenixKitAI.Providers.OpenAICompatible.vision/3
(chat completions with image_url parts), which is right for every
OpenAI-shaped API. A provider with its own vision shape implements this.
Functions
Provider key → adapter module, built-ins under the host's :provider_adapters.
The adapter used when a provider has no dedicated one.
The request options adapter's image_edit/4 sends for options: its
image_edit_options/2 when it has one, image_options/1 otherwise.
The adapter for an endpoint's provider (the default one when unknown).
The adapter for a provider key.
Types
@type image() :: %{ :data => binary() | nil, :url => String.t() | nil, :content_type => String.t() | nil, optional(:width) => pos_integer(), optional(:height) => pos_integer() }
Callbacks
@callback image_edit(PhoenixKitAI.Endpoint.t(), String.t(), [String.t()], options()) :: {:ok, image_result()} | {:error, term()}
Image-in, image-out: edit refs (first = the image to change) per prompt.
@callback image_edit_options(PhoenixKitAI.Endpoint.t(), options()) :: [atom()]
The request option names image_edit/4 actually sends for these
options. Optional — defaults to image_options/1. An adapter whose
edit transport sends less than its generation one (a chat-completions
edit carries only an aspect ratio) implements this, so
PhoenixKitAI.Images.process/4 drops the rest with a warning and picks
the operations' fallback wording instead of sending them nowhere.
@callback image_generate(PhoenixKitAI.Endpoint.t(), String.t(), options()) :: {:ok, image_result()} | {:error, term()}
Text-to-image.
@callback image_models(PhoenixKitAI.Endpoint.t()) :: {:ok, [PhoenixKitAI.Images.ImageModel.t()]} | {:error, term()}
The provider's image models with their constraints, when it publishes them.
@callback image_options(PhoenixKitAI.Endpoint.t()) :: [atom()]
Option names the adapter can send when no per-model listing exists.
@callback vision(PhoenixKitAI.Endpoint.t(), [map()], options()) :: {:ok, map()} | {:error, term()}
Vision: a chat-shaped question about images. Optional — adapters that
do not implement it get PhoenixKitAI.Providers.OpenAICompatible.vision/3
(chat completions with image_url parts), which is right for every
OpenAI-shaped API. A provider with its own vision shape implements this.
Functions
Provider key → adapter module, built-ins under the host's :provider_adapters.
@spec default() :: module()
The adapter used when a provider has no dedicated one.
@spec edit_options(module(), PhoenixKitAI.Endpoint.t(), options()) :: [atom()]
The request options adapter's image_edit/4 sends for options: its
image_edit_options/2 when it has one, image_options/1 otherwise.
@spec for_endpoint(PhoenixKitAI.Endpoint.t() | map()) :: module()
The adapter for an endpoint's provider (the default one when unknown).
The adapter for a provider key.