Wire dialects
Which providers cost code to support, which cost a line of config, and what a wire driver owns that a descriptor cannot change.
On this page
Your application speaks one request shape. Your providers between them speak several. A gateway either translates every pair, which multiplies, or it treats the shape as one axis of a provider’s identity and keeps the number of shapes small. This one does the second.
A dialect is a wire format: what a request body looks like, where the model id lives, how a streamed response is framed, and where usage counts appear in the reply. It is not the same thing as a provider. Twelve providers can speak one dialect and still bill under twelve different namespaces.
What the proxy accepts on the way in
The proxy recognises each shipped dialect on its own native paths. A client speaking any of them is
matched, given an endpoint kind, governed and ledgered against that dialect’s default upstream:
Anthropic’s /v1/messages, Bedrock’s /model/{id}/converse and Deepgram’s /v1/listen are each
answered as themselves. The suite drives that last one as a client request, at Deepgram’s own path,
and reads back a priced transcription row.
A path matching no registered dialect and endpoint is forwarded as a ledgered passthrough rather than rejected, so an unusual call still reaches your provider and still lands on a row.
Translation is narrower than recognition, and the difference is where the number two belongs. Two client formats can be translated onto an upstream that speaks something else:
| Client format | Paths | Your client |
|---|---|---|
openai |
/v1/chat/completions, /v1/responses, /v1/embeddings, and the rest of the /v1 surface |
any OpenAI SDK, or anything OpenAI-shaped |
anthropic |
/v1/messages |
the Anthropic SDK, Claude Code |
Those two reach four upstream dialects between them, openai, anthropic, gemini and
bedrock, streaming and not. Gemini- and Bedrock-format
requests are recognised and served on their own dialects, but they are translation targets rather
than translation sources, which is a product decision to defer rather than a gap in the wire
code.
What the drivers speak on the way out
The generated September 6 catalog snapshot counts 15 wire-dialect ids across 95 built-in provider descriptors. The generator resolves the dialect id declared by the compiled Go package; directory spelling is not the identity.
| Driver | Descriptors |
|---|---|
anthropic |
1 |
anthropic_vertex |
1 |
assemblyai |
1 |
bedrock |
2 |
bfl |
1 |
deepgram |
1 |
elevenlabs |
1 |
fal |
1 |
gemini |
3 |
openai |
78 |
replicate |
1 |
runway |
1 |
soniox |
1 |
stability |
1 |
vertex_predict_embed |
1 |
78 descriptors use the openai driver. Mock verification remains per endpoint cell;
the provider reference names the ten descriptors with no gated cell.
What the driver owns and the descriptor cannot change
A descriptor refines a driver; it does not replace it. The split matters when you are deciding whether a provider you want is a config change or a feature request.
The driver owns the body shape it parses and emits, how a stream is framed and flushed, where the model id is spliced when a routing decision rewrites it, and where usage counts are read from in the response.
The descriptor overrides the path templates, any required query parameters, the mandatory headers, the auth scheme and the pricing namespace.
So a provider that speaks OpenAI’s body shape at an unusual URL is data. A provider that speaks a body shape nothing ships is code, and it is the single most common reason a provider appears in the uncovered list.
Where the model id lives
A request can carry its model in four places, and which one it uses decides what a routing rewrite is allowed to touch.
| Where the model comes from | Drivers | What a routing rewrite does |
|---|---|---|
| the request body | openai and anthropic (model), elevenlabs (model_id), assemblyai (speech_model), soniox (model) |
splices the one field |
| the URL path | bedrock, gemini, anthropic_vertex, and stability for all but one of its operations |
rewrites the path and leaves the body byte-identical |
| the URL query | deepgram (?model=) |
nothing to splice; the driver reads the model there for pricing |
| a multipart form field | stability, for the one operation that carries its model in the form instead |
nothing to splice; the field is read for pricing |
The multipart form field is the newest of the four, and it arrived with image generation. Two of
the four carriers are worth knowing about for a different reason: a body with no model field
would be corrupted by a splice, so the proxy checks which kind of driver it is holding and takes
the path route when that is the truthful one. replicate is the case that resists the rule, and it
says so rather than guessing: a submit carrying a version field is rewritable, and a submit whose
model is the URL is relayed unchanged with the enforcement fields cleared.
Only the routable endpoint kinds are rewritten at all. Speech, audio and image requests are priced from wherever their model is carried and are not re-pointed at another model.
Two dialects on one request
A request that arrives in one client format and is routed to an upstream speaking another is a cross-dialect route. It is off out of the box, and streaming across a pair needs a second opt-in on top of the first. Both accepted client formats reach all four of those upstream dialects, and every parameter a translation could not carry across is named on the row it produced.
Because that is a property of the pair of dialects rather than of routing policy, it is documented here rather than under Routing. Cross-dialect translation has the config shape, which client formats reach which upstreams has the grid pair by pair, and what a translation drops has the inventory of what did not survive the crossing.
The dialect: field, and when you still write it
An upstream configured with provider: derives its dialect from the descriptor, so you leave
dialect: out. Setting it anyway is legal as long as it agrees; a mismatch is a validation error
that names both values.
There is one situation today where writing it is not merely legal but necessary. Cross-dialect
translation reads the dialect from the upstream config rather than from the compiled descriptor,
and the descriptor path leaves that field empty. If you are enabling cross-dialect translation,
name both provider: and dialect: on the target upstream. The
cross-dialect page shows what happens when you do not, with
both captures.