9.5 KiB
Dynagate LLM gateway (C++ port)
Dynagate is a lightweight, high-performance LLM gateway that acts as a proxy for OpenAI-compatible APIs. This directory is a modern C++20 port of the Go reference implementation (dynagate), using a native RFC 8259 JSON engine (json.cpp) and libcurl for HTTP networking.
It provides seamless model routing, automatic key and model failover, live configuration hot-reloading without restarts, token authentication, and custom header injection.
Features
-
Multi-API Protocol Endpoints (Stateless):
/v1/modelsand/models(GET): Dynamically lists unique active model IDs./v1/chat/completionsand/chat/completions(POST): Proxies non-streaming and streaming (text/event-stream) completions./v1/responsesand/responses(POST): Stateless-style OpenAI Responses API endpoint (automatically routed to upstream chat completions endpoints)./v1/messagesand/messages(POST): Anthropic-compatible Messages API endpoint (automatically routed to upstream chat completions endpoints)./v1/images/generationsand/images/generations(POST): Proxies image generation requests.
Note
Dynagate operates in a completely stateless manner across all API formats (
/v1/chat/completions,/v1/responses,/v1/messages). Dynagate does not store or persist server-side conversation state. Clients must include the full conversation history in each request for multi-turn dialogues. -
Zero-downtime live-reloading:
- Watches
models.csv(overridable via command-line flags) continuously using a background thread and automatically reloads configuration updates without dropping active connections.
- Watches
-
Fallback and retry orchestration:
- Attempts keys configured for the requested model sequentially using Fibonacci backoff delays (
-retry-delay). - Cascades automatically to the next model in the priority chain (wrapping around to cover all entries) if all keys for the requested model fail.
- Updates the
"model"field dynamically in the outgoing request body before proxying, ensuring upstream compatibility.
- Attempts keys configured for the requested model sequentially using Fibonacci backoff delays (
-
Flexible authorization:
- Optional gateway token authentication via command-line key file.
- Key options (
"","-") to strip authorization headers when proxying to local or open upstreams. - Special
"-blank-"key config to pass an emptyAuthorization: Bearerheader.
-
External config updater:
- Executes a periodic CLI command (
-csv-updater) at a custom interval (-csv-update-interval) to fetch, generate, or download fresh model listings.
- Executes a periodic CLI command (
-
Custom header injection (
extrafield):- Sets or overrides custom headers dynamically per model deployment using a JSON configuration string.
Tech stack
- Language: C++20 (
-std=c++20) - Dependencies:
libcurl(HTTP/HTTPS upstream requests and SSE streaming)- Native RFC 8259 JSON parser and serializer in
json.cpp(no extra or vendored third-party JSON dependency) - POSIX sockets and standard C++20 threads/atomics/filesystem
- Target Platforms: Linux, FreeBSD, macOS, Haiku, and any POSIX-compliant OS (64-bit and 32-bit hosts)
Repository layout
dynagate.hpp Shared declarations, data structures, and interfaces
json.cpp Native RFC 8259 JSON parser and serializer
config.cpp RFC 4180 CSV parser, ConfigManager, hot-reloader, CSV updater
handler.cpp Auth, normalization, protocol conversions, libcurl proxying
server.cpp Multi-threaded POSIX HTTP/1.1 server and streaming writer
main.cpp CLI flag parsing, signal handling, server lifecycle
gateway_test.cpp Comprehensive unit and end-to-end test suite
Makefile POSIX-compliant Makefile (bmake, gmake, smake compatible)
models.csv Example model configuration file
free-model-collector.sh Free model discovery and verification script
freekeys.sh Helper script for collecting free keys
Prerequisites
- A C++20 compiler (
c++,g++, orclang++) - Any POSIX
make(bmake,gmake,make) libcurldevelopment headers and library:# Debian / Ubuntu apt-get install build-essential libcurl4-openssl-dev # Fedora / RHEL dnf install gcc-c++ libcurl-devel # FreeBSD pkg install curl # macOS (Xcode Command Line Tools include libcurl, or via Homebrew) xcode-select --install
Getting started
1. Building from source
make # builds ./dynagate
make 32bit # builds a 32-bit ./dynagate binary with large file support
make debug # builds ./dynagate with AddressSanitizer + UBSan
make test # builds and runs the test suite
make clean # removes build artifacts
make install # installs to $(DESTDIR)/usr/local/bin/dynagate
If libcurl or custom headers live in a non-standard prefix, override flags on the make command line:
make CXX=clang++ CPPFLAGS="-I/opt/homebrew/include -I." LDLIBS="-L/opt/homebrew/lib -lcurl -pthread"
2. Configure models
Create a models.csv file in the same directory. The file supports both header and header-less formats.
Example models.csv with Header:
model,key,endpoint,extra
gpt-4o,sk-proj-key1,https://api.openai.com/v1,"{""Openai-Organization"":""org-123""}"
gpt-4o,sk-proj-key2,https://api.openai.com/v1,
gpt-3.5-turbo,-blank-,https://api.openai.com/v1,
deepseek-chat,sk-ds-key,https://api.deepseek.com/v1,"{""X-Custom-Env"":""production""}"
ollama-llama3,-,http://localhost:11434/v1,
3. Setup gateway key (optional)
To restrict access to your gateway, write one or more plaintext keys (one per line) to a file (e.g. gatekey.txt):
my-secure-gateway-token-1
my-secure-gateway-token-2
4. Run the server
./dynagate -port 8080 -csv models.csv -key gatekey.txt
Configuration reference
Command line flags
| Flag | Type | Default | Description |
|---|---|---|---|
-port |
int | 8080 |
Port the gateway listens on. |
-csv |
string | models.csv |
Path to the model configuration CSV. |
-key |
string | "" |
Path to a file containing the gateway's access tokens (one per line). If blank, authentication is disabled. |
-csv-updater |
string | "" |
Command/script to run periodically to update models.csv. |
-csv-update-interval |
int | 10 |
Frequency in minutes to invoke -csv-updater. |
-retry-delay |
int | 100 |
Base delay in milliseconds for Fibonacci failover retries (0 to disable). |
Model CSV format rules
The gateway maps columns dynamically by looking at the header row. If no header is present, it defaults to:
- Column 0:
model(Model ID) - Column 1:
key(API Key / Authorization Token) - Column 2:
endpoint(Upstream base URL endpoint) - Column 3:
extra(Optional JSON string object containing header mappings)
Auth override key values:
""or"-": The gateway will strip theAuthorizationheader completely (useful for local LLM endpoints or unauthenticated proxies)."-blank-": The gateway will attachAuthorization: Bearerwithout any key appended.- Any other string: The gateway will attach
Authorization: Bearer <key>.
Stateless Operation & Multi-Turn Conversations
Dynagate is designed as a lightweight, zero-state proxy gateway. All supported request formats (/v1/chat/completions, /v1/responses, /v1/messages) are processed statelessly without storing session context or conversation state on disk or in memory.
To maintain context in multi-turn conversations, clients must include the entire conversation history in every request payload:
- OpenAI Chat Completions (
/v1/chat/completions): Pass the full array of system, user, and assistant messages inmessages. - OpenAI Responses API (
/v1/responses): Pass previous conversation turns ininput(ormessages) along withinstructions. - Anthropic Messages API (
/v1/messages): Pass the full history of user and assistant messages inmessagesalong withsystem.
Manual testing with curl
1. Model listing (authenticated)
curl -i -H "Authorization: Bearer my-secure-gateway-token" http://localhost:8080/v1/models
2. Chat completions proxying
curl -i -X POST http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer my-secure-gateway-token" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "Explain gravity in one sentence"}]
}'
3. Chat completions streaming
curl -i -X POST http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer my-secure-gateway-token" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"stream": true,
"messages": [{"role": "user", "content": "Count from 1 to 5"}]
}'
4. OpenAI-compatible Responses API (/v1/responses)
curl -i -X POST http://localhost:8080/v1/responses \
-H "Authorization: Bearer my-secure-gateway-token" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"instructions": "Be concise",
"input": "Explain relativity in one sentence"
}'
5. Anthropic-compatible Messages API (/v1/messages)
curl -i -X POST http://localhost:8080/v1/messages \
-H "Authorization: Bearer my-secure-gateway-token" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-3-5-sonnet",
"system": "You are a helpful assistant",
"messages": [{"role": "user", "content": "Hello world"}]
}'
Credits
Created by Luxferre in 2026, released into the public domain with no warranties.