Shared implementation for any provider that speaks the OpenAI Chat
Completions wire format (/v1/chat/completions). This covers OpenAI itself
and OpenRouter (and DeepSeek, Groq, Together, etc.).
The two directions every provider needs:
- encode — our
Messagehistory → themessagesarray the API expects (rolessystem/user/assistant/tool), and ourToollist → thetoolsarray. - decode — the API JSON response back into our
Message.ResponsewithTextPart/ToolCallPartparts andUsage.
Providers are thin structs carrying {:model, :api_key, :base_url, :extra_headers}; request/4 reads those fields generically, so the same code
drives %OpenAI{} and %OpenRouter{}.
Summary
Functions
Encode a list of Tool into the OpenAI tools payload (or nil).
Perform a (non-streaming) chat-completions request.
Perform a streaming chat-completions request. Returns a lazy stream of
Functions
@spec encode_tools([ExAgent.Tool.t()]) :: [map()] | nil
Encode a list of Tool into the OpenAI tools payload (or nil).
@spec parse_response( map(), struct() ) :: ExAgent.Message.Response.t()
@spec request( struct(), [ExAgent.Message.t()], ExAgent.ModelSettings.t() | nil, ExAgent.ModelRequestParameters.t() ) :: {:ok, ExAgent.Message.Response.t(), struct()} | {:error, term()}
Perform a (non-streaming) chat-completions request.
@spec request_stream( struct(), [ExAgent.Message.t()], ExAgent.ModelSettings.t() | nil, ExAgent.ModelRequestParameters.t() ) :: Enumerable.t() | {:error, term()}
Perform a streaming chat-completions request. Returns a lazy stream of:
{:text_delta, binary}— incremental text,{:response, Response.t()}— the final assembled response,{:error, reason}on failure.
@spec to_openai_messages([ExAgent.Message.t()]) :: [map()]