Providers
The standalone proxy speaks provider protocols through adapters under public/proxy/providers. Each adapter owns route matching, upstream URL resolution, auth/header mapping, request inspection, optional transforms, and usage parsing.
The proxy is BSL 1.1. Adapters keep provider-specific behavior isolated, so lifecycle code stays generic.
The seven adapters
All seven live under public/proxy/providers/ and are wired in public/proxy/internal/standalone/standalone.go. Anthropic, OpenAI, and Gemini get public defaults. Azure OpenAI, Bedrock, Vertex, and OpenAI-compatible adapters are added only when caveman.yaml gives them a base URL.
| Provider | Default upstream | Notes |
|---|---|---|
anthropic | https://api.anthropic.com | Carries both prefixed /anthropic/v1/messages and the bare /v1/messages (plus count_tokens). Sets x-api-key + a default anthropic-version. |
openai | https://api.openai.com | Carries both prefixed /openai/v1/... and the bare /v1/chat/completions, /v1/responses, /v1/embeddings. Bearer auth. |
gemini | https://generativelanguage.googleapis.com | Routes /gemini/v1beta/models/...; auth via x-goog-api-key. |
azure_openai | (none — set base_url) | Routes /azure/... to your Azure resource; auth via api-key, passes api-version through. |
bedrock | (none — set base_url) | Routes /bedrock/model/...; AWS SigV4 per request, signed against the resolved upstream Host. |
vertex | (none — set base_url) | Routes /vertex/...; a bearer pass-through for both Gemini and Claude on Vertex AI — no signing, no custom usage parser. |
openai_compatible | (none — set base_url) | Routes /compat/... to any OpenAI-compatible endpoint. Bearer auth. |
Anthropic and OpenAI include bare routes (/v1/messages, /v1/chat/completions, /v1/responses, /v1/embeddings) so base-URL-only agents can be routed without path rewriting in the agent.
Bytes the model sees are never touched
In record mode the proxy never transforms a body. In compress mode, only adapters that can extract and reassemble safe text segments participate; adapters that cannot do that pass through. If a transform fails, original bytes go upstream. Savings are inferred.
Adapter seam
RouteContext carries resolved routing hints, not service objects:
type RouteContext struct {
BaseURL string
}ResolveUpstreamURL takes RouteContext and the HTTP request. Standalone passes the base URL from caveman.yaml.
Adding a provider
A new provider is a package under public/proxy/providers/ that embeds providers.Base and satisfies Adapter. Base already implements common route matching, URL resolution, header mapping, JSON usage parsing, and default pass-through behavior.
Embed Base
Base carries the provider name, default base URL, and route prefixes, and gives you a
working MatchRoute/ResolveUpstreamURL/SanitizeAndMapHeaders for free:
func New(baseURL string) providers.Adapter {
return Adapter{Base: providers.Base{
Provider: "openai",
BaseURL: baseURL,
Routes: []string{"/v1/chat/completions", "/openai/v1/chat/completions"},
}}
}Override only the differences
Implement just the methods your provider needs differently — for example a SigV4 signer
in SanitizeAndMapHeaders, or a parse function for a non-JSON usage shape via
NewExternalUsageScanner. Leave the rest to Base.
Register it
Add it to buildAdapters in public/proxy/internal/standalone/standalone.go. Registration is the standalone wiring step.