Protocol Conversion
Protocol Conversion and Wire-Model Alignment
Section titled “Protocol Conversion and Wire-Model Alignment”中文版本:协议转换与 Wire Model 对齐
ProxAI keeps protocol conversion explicit and pair-oriented. The conversion rules are split into focused developer topics so each page answers one maintenance question.
This is the developer entry point for
src/translation/. If you are looking for user-facing protocol behavior, start with Protocol Guide.
Boundaries
Section titled “Boundaries”src/protocol/owns protocol-specific Rust wire models.src/ingress/owns inbound parsing and normalization before translation.src/translation/owns pure cross-protocol conversion between an inboundrequest_protocoland an outbound providerprotocol.src/provider/request.rsowns provider request preparation, including model rewrite, projection/summary extraction, and JSON body serialization.src/provider/transport.rsowns outbound HTTP transport, auth headers, upstream URL construction, and send.src/http_support/owns HTTP carrier helpers such asByteStream, content-type/header helpers, and response reconstruction.
Do not hide general cross-protocol conversion inside a provider subtree. Provider code may normalize provider-local quirks, but protocol-to-protocol shape changes belong in src/translation/.
Translation APIs should stay pure at the carrier boundary:
- request translation:
(request_protocol, provider_protocol, normalized_payload) -> payload - non-streaming response translation:
(request_protocol, provider_protocol, payload) -> payload - streaming response translation:
(request_protocol, provider_protocol, ByteStream) -> ByteStream
Do not pass HTTP Response, Body, provider request structs, or route/model rewrite details into src/translation/. This is the carrier-boundary purity required by Behavior Contract C26.
Naming
Section titled “Naming”Use protocol names for wire behavior:
openai_responsesopenai_chat_completionsanthropic_messages
Use pair-oriented conversion module names, for example:
openai_responses -> anthropic_messagesanthropic_messages -> openai_responses
Provider names are user labels and should not be treated as semantic protocol identifiers.
Two-layer translation model
Section titled “Two-layer translation model”Each direction is independently translated. ProxAI never round-trips raw provider structures; Anthropic ToolUseBlock becomes Responses FunctionCall, Anthropic ThinkingBlock becomes Responses ReasoningItem, and provider-specific metadata such as signature or tool_use_id is transformed in the process. This implements Behavior Contract C27.
Routing is not conversion
Section titled “Routing is not conversion”A route may specify request_protocol. If omitted, the route can match any inbound request protocol detected from the actual request path. Provider protocol controls the outbound wire format, so route protocol filtering and protocol conversion are separate decisions.
Set request_protocol only when the same model pattern needs different routing
for different request endpoints. If a model pattern matches but the explicit
request_protocol differs from the inbound request protocol, ProxAI reports a
configuration error instead of silently falling through to a default provider.
Responses ↔ Anthropic translation architecture
Section titled “Responses ↔ Anthropic translation architecture”ProxAI sits between the client and the upstream provider, performing two-layer translation on every request/response cycle:
This means the proxy never passes through raw provider structures. Each direction is independently translated:
- Request (client → Anthropic): client’s Responses or Chat payload is translated into an Anthropic Messages request.
- Response (Anthropic → client): Anthropic’s message response is translated back into a Responses or Chat payload the client understands.
InputItem: EasyMessage vs Item
Section titled “InputItem: EasyMessage vs Item”Responses input accepts Vec<InputItem>, where each item can be one of:
| Variant | Purpose | When used |
|---|---|---|
| EasyInputMessage | Simple role + content message | Client composing new user/developer messages |
| Item | Typed output items (function_call, reasoning, etc.) | Multi-turn: client echoing back response items from a previous turn |
| ItemReference | Reference to a previously returned item by id | Multi-turn: referencing items without repeating full content |
ProxAI’s Anthropic translation only produces EasyInputMessage. This is
because Anthropic’s MessageParam has a simple role + content structure with
no concept of echoing back response items. The Item variant exists for native
Responses clients that preserve the full response structure across turns.
Example of Item usage (native Responses multi-turn, not translated from Anthropic):
Why two-layer translation matters
Section titled “Why two-layer translation matters”Response items from Anthropic (ToolUseBlock, ThinkingBlock, etc.) are
translated into Responses output items (FunctionCall, ReasoningItem, etc.)
when sent back to the client. The original Anthropic-specific metadata
(tool_use_id, signature, etc.) is transformed in the process, so the client
cannot round-trip Anthropic structures verbatim. This is by design — ProxAI
guarantees correct translation in both directions, and the client works with
the target protocol’s types.
Reasoning request controls
Section titled “Reasoning request controls”OpenAI Responses and Anthropic-compatible Messages split reasoning controls differently:
- Responses
reasoning.effortmaps to Anthropicoutput_config.effortfor supported effort values (low,medium,high,xhigh). This is the preferred Anthropic-side effort field. - Responses
reasoning.summary(auto,concise,detailed) only maps lossily to Anthropicthinking.display: "summarized"; Anthropic has no equivalent summary granularity. - Responses
reasoning.summarywithout an effort maps to Anthropicthinking: {"type":"adaptive", "display":"summarized"}. - Responses
reasoning.effortplusreasoning.summarymaps tooutput_config.effortplus adaptivethinking.display; ProxAI does not invent a legacythinking.budget_tokensvalue. - Responses
reasoning.effort: "none" | "minimal"maps to Anthropicthinking: {"type":"disabled"}becauseoutput_config.efforthas no disabled/minimal value. - Anthropic -> Responses and Anthropic -> Chat request translation accept the
manual
thinking.type: "enabled"/budget_tokensmode only as a legacy compatibility fallback. Ifoutput_config.effortis absent, ProxAI maps the budget lossily to an effort enum and logs a warning; ifoutput_config.effortis present, it wins and the legacy budget is ignored with a warning. - Anthropic
thinking.display: "summarized"maps to Responsesreasoning.summary: "auto";display: "omitted"does not request a Responses summary.
Conversion topics
Section titled “Conversion topics”Documentation expectations
Section titled “Documentation expectations”When protocol conversion or wire-model alignment rules change:
- Update this document.
- Update the relevant protocol document under
site/src/content/docs/en/andsite/src/content/docs/zh/if behavior changes for users or examples. - Update
README.mdandREADME_CN.mdwhen the change affects user-facing development workflow or configuration.