Caveman
The proxyProviders

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.

Fig. — the proxy request path
Agentbase-URL swapcaveman-proxy · 127.0.0.1:8787matchauthtransformbyte-safemeterProviderBYOK upstreambytes intactresponse~/.caveman/caveman.dbinferred spend · SQLite

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.

ProviderDefault upstreamNotes
anthropichttps://api.anthropic.comCarries both prefixed /anthropic/v1/messages and the bare /v1/messages (plus count_tokens). Sets x-api-key + a default anthropic-version.
openaihttps://api.openai.comCarries both prefixed /openai/v1/... and the bare /v1/chat/completions, /v1/responses, /v1/embeddings. Bearer auth.
geminihttps://generativelanguage.googleapis.comRoutes /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:

go
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:

go
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.

See also