OpenResponses.Adapter behaviour
(OpenResponses v0.1.1)
View Source
Behaviour that all provider adapters must implement.
An adapter is responsible for three things:
- Building the request — translate the loop state into the provider's native request format.
- Streaming — make the HTTP request and return a lazy
Streamof raw provider-native events. - Normalising events — translate each raw provider event into an Open Responses spec event map.
API key handling
API keys are supplied per-request by the caller in the "api_key" field
of the request body. The server never uses a shared key for client
requests. The resolved key is passed to stream/2 via the config
keyword list as api_key: "sk-...".
Server-side config (via config :open_responses, :provider_config) can
set a base_url override or other adapter-specific options, but the
api_key from the request always takes precedence.
Built-in adapters
| Module | Provider |
|---|---|
OpenResponses.Adapters.OpenAI | OpenAI |
OpenResponses.Adapters.Anthropic | Anthropic / z.ai |
OpenResponses.Adapters.Gemini | Google Gemini |
OpenResponses.Adapters.Ollama | Ollama (local) |
OpenResponses.Adapters.Mock | Testing |
Writing a custom adapter
defmodule MyApp.Adapters.MyProvider do
@behaviour OpenResponses.Adapter
@impl OpenResponses.Adapter
def build_request(%{response: response, input: input}) do
%{model: response.model, messages: input}
end
@impl OpenResponses.Adapter
def stream(request, config) do
api_key = Keyword.fetch!(config, :api_key)
{:ok, MyProvider.stream(request, api_key)}
end
@impl OpenResponses.Adapter
def normalize_event(%{"type" => "my.delta", "text" => t}),
do: %{"type" => "response.output_text.delta", "delta" => t}
def normalize_event(%{"type" => "my.done"}),
do: %{"type" => "response.completed"}
def normalize_event(event), do: event
endRegister it via routing config:
config :open_responses, :routing, %{
~r/^myprovider-/ => MyApp.Adapters.MyProvider
}See the Providers guide for full details.