Overview
View SourceOpenResponses is a production-grade Elixir implementation of the Open Responses specification — a provider-agnostic API for interacting with large language models.
What it does
At its simplest: you send a request, you get a response. Behind the scenes, OpenResponses manages the agentic loop, routes to the right provider, streams events back to your client, dispatches tool calls, and tracks conversation history — all without you writing any of that infrastructure.
POST /v1/responses
{
"model": "gpt-4o",
"input": [{"role": "user", "content": "What's the weather in London?"}],
"tools": [{"type": "function", "name": "get_weather", "parameters": {...}}]
}Your client receives a stream of Server-Sent Events, or a single JSON response — your choice.
Why Elixir?
The Open Responses spec describes a system that maps directly onto what the BEAM was built for:
| Spec requirement | BEAM advantage |
|---|---|
| Agentic loop with tool dispatch | One GenServer per request — crash isolation, OTP supervision |
| Semantic SSE streaming | Phoenix handles chunked HTTP natively; PubSub fans out to multiple consumers |
| Multi-provider concurrency | Thousands of simultaneous loops on a single node without threads |
| State machine on responses | AshStateMachine enforces valid transitions at compile time |
| Extensible provider routing | Pattern-match on model names in config — no code changes |
Supported providers
| Provider | Model pattern | Notes |
|---|---|---|
| OpenAI | gpt-* | Near pass-through |
| Anthropic | claude-* | Full event translation |
| Google Gemini | gemini-* | contents/parts format |
| Ollama | llama*, mistral*, phi*, qwen* | Local models, no API key |
| z.ai | Any | Use Anthropic adapter with custom base_url |
| Custom | Anything | Implement OpenResponses.Adapter |
Architecture in one diagram
Client
│
▼
POST /v1/responses
│
▼
ResponseController
│ creates Response (Ash / ETS)
▼
LoopSupervisor.start_loop/1
│
▼
Loop (GenServer, one per request)
│ resolves adapter from model name
│ applies middleware before_sample
│ calls adapter.stream/2
│ processes events
│ dispatches tool calls
│ applies middleware after_sample
│ transitions state machine
│ caches completed response
│
├──── broadcasts events via PubSub ────► SSE chunks to client
│
└──── stores in ResponseCache ────► available for previous_response_idNext steps
- Installation — add OpenResponses to your Phoenix app
- Getting Started — make your first request
- Providers — configure API keys and routing