ReqLLM.Provider.Defaults (ReqLLM v1.5.0)

View Source

Default implementations for common provider behavior patterns.

This module extracts shared logic between OpenAI-compatible providers (OpenAI, Groq, etc.) into reusable runtime functions and a __using__ macro that provides default callback implementations.

Usage

defmodule MyProvider do
  @behaviour ReqLLM.Provider
  use ReqLLM.Provider.DSL, [...]
  use ReqLLM.Provider.Defaults

  # All default implementations are available and overridable
  # Override only what you need to customize
end

Design Principles

  • Runtime functions are pure and testable
  • Provider module is passed as first argument to access attributes
  • All defaults are defoverridable for selective customization
  • Providers can override individual methods or use helper functions directly

Default Implementations

The following methods get default implementations:

  • prepare_request/4 - Standard chat/object/embedding request preparation
  • attach/3 - OAuth Bearer authentication and standard pipeline steps
  • build_body/1 - OpenAI-compatible request body construction
  • encode_body/1 - OpenAI-compatible request body encoding
  • decode_response/1 - Standard response decoding with error handling
  • extract_usage/2 - Usage extraction from standard usage field
  • translate_options/3 - No-op translation (pass-through)
  • decode_stream_event/2 - OpenAI-compatible SSE event decoding
  • attach_stream/4 - OpenAI-compatible streaming request building
  • display_name/0 - Human-readable provider name from provider_id

Runtime Functions

All default implementations delegate to pure runtime functions that can be called independently:

Customization Examples

# Override just the body encoding while keeping everything else
def build_body(request) do
  request
  |> ReqLLM.Provider.Defaults.default_build_body()
  |> Map.put(:my_provider_field, request.options[:my_provider_field])
end

def encode_body(request) do
  request
  |> ReqLLM.Provider.Defaults.encode_body_from_map(build_body(request))
  |> add_custom_headers()
end

# Use runtime functions directly for testing
test "encoding produces correct format" do
  request = build_test_request()
  body = ReqLLM.Provider.Defaults.default_build_body(request)
  assert body[:model]
end

Summary

Functions

Provides default implementations for common provider patterns.

Build a complete OpenAI-style chat body from a Req request.

Decodes OpenAI-format response body to ReqLLM.Response.

Default body building for OpenAI-compatible APIs.

Default response decoding with success/error handling.

Default SSE event decoding for OpenAI-compatible providers.

Default display name implementation.

Default body encoding for OpenAI-compatible APIs.

Default usage extraction from standard usage field.

Default options translation (pass-through).

Encode a request body map as JSON and attach it to the Req request.

Encodes ReqLLM.Context to OpenAI-compatible format.

Fetches API key and extra common option keys

Filters out internal ReqLLM keys that should not be passed to Req.

Prepares an embedding generation request.

Prepares an object generation request using tool calling.

Runtime implementation of prepare_request/4.

Validates that a context contains only image file attachments.

Functions

__using__(opts)

(macro)

Provides default implementations for common provider patterns.

All methods are defoverridable, so providers can selectively override only the methods they need to customize.

build_openai_chat_body(request)

Build a complete OpenAI-style chat body from a Req request.

This helper function encodes context, adds common options (temperature, max_tokens, etc.), converts tools to OpenAI schema, and handles stream flags. Providers can use this as a starting point and add provider-specific fields.

Example

def encode_body(req) do
  body = Defaults.build_openai_chat_body(req)
  |> Map.put(:my_provider_field, req.options[:my_provider_field])

  req
  |> Req.Request.put_header("content-type", "application/json")
  |> Map.put(:body, Jason.encode!(body))
end

decode_response_body_openai_format(data, model)

@spec decode_response_body_openai_format(map(), LLMDB.Model.t()) ::
  {:ok, ReqLLM.Response.t()} | {:error, term()}

Decodes OpenAI-format response body to ReqLLM.Response.

This function moves the logic from ReqLLM.Response.Codec.Map directly into Provider.Defaults for the protocol removal refactoring.

default_attach(provider_mod, request, model_input, user_opts)

@spec default_attach(module(), Req.Request.t(), term(), keyword()) :: Req.Request.t()

default_attach_stream(provider_mod, model, context, opts, finch_name)

@spec default_attach_stream(
  module(),
  LLMDB.Model.t(),
  ReqLLM.Context.t(),
  keyword(),
  atom()
) :: {:ok, Finch.Request.t()} | {:error, Exception.t()}

Default implementation of attach_stream/4.

Builds complete streaming requests using OpenAI-compatible format and returns a complete Finch.Request.t() ready for streaming execution.

default_build_body(request)

@spec default_build_body(Req.Request.t()) :: map()

Default body building for OpenAI-compatible APIs.

default_decode_response(arg)

@spec default_decode_response({Req.Request.t(), Req.Response.t()}) ::
  {Req.Request.t(), Req.Response.t() | Exception.t()}

Default response decoding with success/error handling.

default_decode_stream_event(arg1, model)

@spec default_decode_stream_event(map(), LLMDB.Model.t()) :: [ReqLLM.StreamChunk.t()]

Default SSE event decoding for OpenAI-compatible providers.

This function moves the logic from ReqLLM.Response.Codec.Map directly into Provider.Defaults for the protocol removal refactoring.

default_display_name(provider_mod)

@spec default_display_name(module()) :: String.t()

Default display name implementation.

Returns a human-readable display name based on the provider_id from DSL, or falls back to capitalizing the module name.

default_encode_body(request)

@spec default_encode_body(Req.Request.t()) :: Req.Request.t()

Default body encoding for OpenAI-compatible APIs.

default_extract_usage(body, arg2)

@spec default_extract_usage(term(), LLMDB.Model.t() | nil) ::
  {:ok, map()} | {:error, term()}

Default usage extraction from standard usage field.

default_translate_options(operation, model, opts)

@spec default_translate_options(atom(), LLMDB.Model.t(), keyword()) ::
  {keyword(), [String.t()]}

Default options translation (pass-through).

encode_body_from_map(request, body)

@spec encode_body_from_map(Req.Request.t(), map()) :: Req.Request.t()

Encode a request body map as JSON and attach it to the Req request.

encode_context_to_openai_format(context, model_name)

@spec encode_context_to_openai_format(ReqLLM.Context.t(), String.t()) :: map()

Encodes ReqLLM.Context to OpenAI-compatible format.

This function moves the logic from ReqLLM.Context.Codec.Map directly into Provider.Defaults for the protocol removal refactoring.

fetch_api_key_and_extra_options(provider_mod, model, user_opts)

@spec fetch_api_key_and_extra_options(module(), LLMDB.Model.t(), keyword()) ::
  {binary(), [atom()]}

Fetches API key and extra common option keys

filter_req_opts(opts)

@spec filter_req_opts(keyword()) :: keyword()

Filters out internal ReqLLM keys that should not be passed to Req.

These keys are used by ReqLLM for internal processing but are not valid Req options.

prepare_chat_request(provider_mod, model_spec, prompt, opts)

@spec prepare_chat_request(module(), term(), term(), keyword()) ::
  {:ok, Req.Request.t()} | {:error, Exception.t()}

Prepares a chat completion request.

prepare_embedding_request(provider_mod, model_spec, text, opts)

@spec prepare_embedding_request(module(), term(), term(), keyword()) ::
  {:ok, Req.Request.t()} | {:error, Exception.t()}

Prepares an embedding generation request.

prepare_object_request(provider_mod, model_spec, prompt, opts)

@spec prepare_object_request(module(), term(), term(), keyword()) ::
  {:ok, Req.Request.t()} | {:error, Exception.t()}

Prepares an object generation request using tool calling.

prepare_request(provider_mod, operation, model_spec, input, opts)

@spec prepare_request(module(), atom(), term(), term(), keyword()) ::
  {:ok, Req.Request.t()} | {:error, Exception.t()}

Runtime implementation of prepare_request/4.

Delegates to operation-specific preparation functions.

validate_image_only_attachments(arg1)

@spec validate_image_only_attachments(ReqLLM.Context.t()) ::
  :ok | {:error, String.t()}

Validates that a context contains only image file attachments.

Returns :ok if all file attachments are images (JPEG, PNG, GIF, WebP), or {:error, reason} with a descriptive message if non-image files are found.

This is used by providers like OpenAI and xAI that only support image attachments via their Chat Completions API.