Protocol Translation
Relevant source files
The following files were used as context for generating this wiki page:
Protocol Translation is a core domain-layer system within the shunt gateway responsible for mediating between the Anthropic Messages API (the format expected by the client, such as Claude Code) and the OpenAI Responses API (the format used by various upstream providers). This system ensures that tools, streaming responses, and reasoning content are faithfully represented across protocol boundaries without the client being aware of the underlying provider change.
The translation logic is primarily housed within the src/model/ directory, specifically handling the transformation of requests from Anthropic to OpenAI shapes and the re-mapping of OpenAI's Server-Sent Events (SSE) back into Anthropic-compatible message fragments.
Sources: ARCHITECTURE.md:12-25, src/model/mod.rs
Architecture and Data Flow
The translation process operates as a bidirectional pipeline between the inbound client request and the outbound upstream provider request. When a request is routed to a provider using the responses adapter, the gateway invokes the translation module to prepare the payload.
The diagram shows the end-to-end flow where Anthropic requests are converted to OpenAI format for the upstream, and the resulting stream is translated back for the client.
Sources: ARCHITECTURE.md:27-45, src/proxy.rs
Request Translation
Request translation converts an Anthropic MessageRequest into an OpenAI ChatCompletionRequest. This involves mapping roles, collapsing message structures, and converting tool definitions.
Key Translation Logic
- Message Mapping: Anthropic roles (user, assistant) are mapped to OpenAI roles. Multiple consecutive messages of the same role may be combined or handled according to provider constraints.
- Tool Conversion: Anthropic tool definitions, including JSON schemas for input parameters, are transformed into OpenAI-compatible tool specifications.
- System Prompts: Anthropic's top-level system prompt is moved into the messages array as a
systemrole message for OpenAI.
Sources: src/model/responses_request.rs:10-50, tests/responses_translate.rs:20-45
Data Structure Comparison
| Anthropic Field | OpenAI Field | Transformation Logic |
|---|---|---|
model | model | Direct pass-through or mapped via routing. |
messages | messages | Array of objects; roles mapped; content reshaped. |
system | messages[0] | System string converted to a message with role: system. |
tools | tools | Tool definitions converted to OpenAI tool object format. |
stream | stream | Boolean flag preserved to maintain streaming semantics. |
Sources: src/model/responses_request.rs, ARCHITECTURE.md:105-115
Response and Stream Translation
The translation of responses is more complex because it must handle real-time streaming events (SSE). The responses.rs module parses OpenAI chunks and emits corresponding Anthropic events.
Stream Event Mapping
The gateway maintains an internal state machine to track message IDs and block types during a stream.
The sequence shows how incremental OpenAI updates are transformed into specific Anthropic message lifecycle events.
Sources: src/model/responses.rs:100-250, tests/responses_translate.rs:150-180
Handling Specialized Content
- Tool Calls: OpenAI's tool call chunks are accumulated and translated into Anthropic's
tool_useblocks. The translator ensures that the JSON input fragments are correctly streamed as deltas. - Reasoning Blocks: For models that support reasoning (like certain xAI or DeepSeek variants), reasoning tokens are captured and potentially redirected or wrapped in tags depending on configuration.
- Usage Accounting: Token counts from OpenAI's
usagefield at the end of a stream are mapped to Anthropic'susageobject (input_tokens, output_tokens).
Sources: src/model/responses.rs:300-350, src/model/mod.rs, ARCHITECTURE.md:148-155
Error Reshaping
A critical requirement of the translation system is maintaining the "Anthropic error envelope." If an upstream provider returns an error, or if the gateway itself encounters an issue during translation, the error must be reshaped so the client can parse it.
| Component | Source Format | Target Format |
|---|---|---|
| Upstream Error | OpenAI Error JSON | Anthropic type: error |
| Gateway Error | Rust ShuntError | Anthropic error.type (e.g., api_error) |
| Transport Failure | HTTP Status | Anthropic 502 api_error |
Sources: src/model/responses.rs:50-80, ARCHITECTURE.md:142-146
Implementation Details
The translation modules use serde_json for high-performance manipulation of JSON payloads. The logic is designed to be "zero-buffer" for streaming content; as soon as a valid OpenAI chunk is parsed, the corresponding Anthropic fragment is written to the output stream.
// Example of error type mapping in src/model/responses.rs
pub fn anthropic_error_type(openai_type: &str) -> &'static str {
match openai_type {
"invalid_request_error" => "invalid_request_error",
"authentication_error" => "authentication_error",
"permission_error" => "permission_error",
"rate_limit_error" => "rate_limit_error",
_ => "api_error",
}
}
Sources: src/model/responses.rs:40-55
Conclusion
Protocol Translation in shunt allows for high fidelity when using non-Anthropic models within tools designed for the Anthropic ecosystem. By meticulously mapping request fields, streaming events, and error shapes, the gateway preserves the interactive and tool-calling capabilities of Claude Code while enabling the use of diverse upstream providers like OpenAI, xAI, and Codex.