feat: add OpenAI to Anthropic translator#2127
Conversation
This adds support for translating OpenAI ChatCompletion requests to Anthropic's direct Messages API, completing the bidirectional translation support between OpenAI and Anthropic. Previously, the gateway supported: - Anthropic → OpenAI (anthropic_openai.go) - OpenAI → AWS Anthropic (openai_awsanthropic.go) - OpenAI → GCP Anthropic (openai_gcpanthropic.go) This commit adds: - OpenAI → Anthropic direct API (openai_anthropic.go) Changes: - Add new translator in internal/translator/openai_anthropic.go - Converts OpenAI requests to Anthropic Messages API format - Supports streaming and non-streaming requests - Handles tool use, images, and all message types - Includes response redaction for debug logging - Uses default Anthropic API version 2023-06-01 - Add comprehensive test suite in internal/translator/openai_anthropic_test.go - 14 test cases covering all functionality - Tests request/response translation, streaming, errors, redaction - All tests passing - Register translator in internal/endpointspec/endpointspec.go - Add APISchemaAnthropic case to ChatCompletionsEndpointSpec.GetTranslator - Update internal/endpointspec/endpointspec_test.go - Add APISchemaAnthropic to supported schemas test list The new translator follows the same patterns as existing cloud-based Anthropic translators but is simpler since it targets the direct API: - Uses standard /v1/messages endpoint - Includes model and stream fields in request body - No cloud-specific wrapper handling needed Signed-off-by: Anibal Angulo <ajcardoza2000@gmail.com>
Signed-off-by: Anibal Angulo <ajcardoza2000@gmail.com>
21ae3d7 to
501dbaf
Compare
|
are you still working on this? |
|
I confirm I am still working on this! |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2127 +/- ##
==========================================
+ Coverage 84.85% 84.88% +0.02%
==========================================
Files 151 152 +1
Lines 22086 22131 +45
==========================================
+ Hits 18742 18785 +43
- Misses 2213 2214 +1
- Partials 1131 1132 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
62d94a4 to
d096487
Compare
Signed-off-by: Anibal Angulo <ajcardoza2000@gmail.com>
…or' into add-openai-to-anthropic-translator Signed-off-by: Anibal Angulo <ajcardoza2000@gmail.com>
Signed-off-by: Anibal Angulo <ajcardoza2000@gmail.com>
73ca92b to
0115e3f
Compare
…ve redaction conflicts Merge main (qxqlsrvm) into add-openai-to-anthropic-translator (tqsrmsum). Conflicts were in RedactBody for the AWS Bedrock and GCP Anthropic translators, where a provider-specific inline redaction implementation conflicted with the cleanup that replaced it with the shared redactAnthropicChatCompletionResponse helper. Resolution: use the shared helper in both translators. Also updated anthropic_helper.go to preserve tool function names (keeping only argument redaction), consistent with the approach already used in openai_openai.go, and updated the corresponding test expectation. Signed-off-by: ajac-zero <ajcardoza2000@gmail.com>
OpenAI's chat completions API rejects requests that include a "thinking" field with "thinking is not allowed". The thinking config is an Anthropic-specific concept; OpenAI reasoning models use reasoning_effort instead, which is a separate, backend-specific setting. Remove anthropicThinkingToOpenAI and its usage in buildOpenAIChatCompletionRequest. Thinking blocks in assistant message history (for multi-turn conversations) are intentionally preserved, as they carry context, not backend configuration. Update TestBuildOpenAIChatCompletionRequest_ThinkingConfig and TestAnthropicToOpenAITranslator_RequestBody_ThinkingConfig to assert that thinking config is dropped for all variants (enabled/disabled/adaptive). Signed-off-by: ajac-zero <ajcardoza2000@gmail.com>
Signed-off-by: ajac-zero <ajcardoza2000@gmail.com>
Signed-off-by: ajac-zero <ajcardoza2000@gmail.com>
12c86ec to
3743023
Compare
Signed-off-by: ajac-zero <ajcardoza2000@gmail.com>
Signed-off-by: ajac-zero <ajcardoza2000@gmail.com>
90c56e6 to
443f4c6
Compare
|
@PatilHrushikesh Ready for review when you get the chance! |
|
I've been dogfooding this implementation for a bit in our deployment, and I found some rough edges that I think are worth mentioning here:
from openai import OpenAI
client = OpenAI(
base_url="http://<gateway-host>/v1",
api_key="<gateway-api-key>",
)
response = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[
{
"role": "user",
"content": "Explain why the sky is blue in one paragraph.",
}
],
max_tokens=1024,
extra_body={
"thinking": {
"type": "enabled",
"budget_tokens": 4096,
}
},
) |
Panel review — OpenAI → first-party Anthropic translatorI ran a three-axis panel review (Spec / Standards / Domain) against this PR, with a parallel comparison PR (#2284) as a reference. Overall this is a well-executed translator that slots cleanly into the existing family — the redaction consolidation and streaming-model tracking are the right calls. Below are the findings, ordered by priority. A kind note up front: please add Spec — does this implement what was asked?Issue #1936 asks to stop the Scope creep (all real, flagging for conscious sign-off):
Ship-blockers (1)[High] The
|
…ic-translator Signed-off-by: Anibal Angulo <anibal.angulo.cardoza@banorte.com>
… main The merge from main added a useResponseModel parameter to newAnthropicStreamParser. Update the remaining test call sites that were not part of the conflict resolution. Signed-off-by: Anibal Angulo <anibal.angulo.cardoza@banorte.com>
Implement direct Anthropic as a small adapter around the existing GCP Anthropic translator. Reuse its response, streaming, tracing, and redaction behavior while overriding direct request construction and raw error labeling.\n\nRemove duplicated tests and unrelated changes to established AWS, GCP, and reverse translation paths. Signed-off-by: Anibal Angulo <anibal.angulo.cardoza@banorte.com>
envoyproxy#1936 Add data-plane coverage for non-streaming, streaming, and error responses through the direct Anthropic backend. Document Chat Completions support and correct the runnable Anthropic example.\n\nClarify the shared request builder's model contract and keep API prefix defaulting at the schema boundary. Signed-off-by: Anibal Angulo <anibal.angulo.cardoza@banorte.com>
Signed-off-by: Anibal Angulo <anibal.angulo.cardoza@banorte.com>
Signed-off-by: Anibal Angulo <anibal.angulo.cardoza@banorte.com>
Signed-off-by: Anibal Angulo <anibal.angulo.cardoza@banorte.com>
|
I substantially reworked this PR after recognizing that the existing OpenAI → GCP Anthropic translator already implements almost all the protocol behavior needed for first-party Anthropic. The previous implementation introduced a separate, largely duplicated translator and accumulated several adjacent changes while the branch was open. This made the PR larger than necessary and increased review burden and regression risk. Direct Anthropic is now a small adapter around the established GCP Anthropic translator:
GCP is the practical base because its response body and streaming transport closely match the first-party API: both return Anthropic Longer term, a provider-neutral Anthropic core with separate native, GCP, and AWS transport adapters would be the cleanest architecture. Extracting that abstraction here would increase scope and unnecessarily modify established paths. Reusing the proven GCP implementation is the smallest and safest way to add the requested capability. This pivot also addresses the main concerns raised by @JAORMX:
The effective PR diff is now limited to the direct-provider adapter, the small shared streaming change needed to report Anthropic’s response model, focused tests, endpoint registration, and documentation. Complex behavior remains delegated to established code already exercised by the GCP Anthropic test suite. I believe this version is substantially easier to review and less likely to introduce regressions while still fully resolving #1936. |
Signed-off-by: Anibal Angulo <anibal.angulo.cardoza@banorte.com>
Description
This commit adds OpenAI-compatible Chat Completions support for the native Anthropic provider. It translates
/v1/chat/completionsrequests to Anthropic's/v1/messagesAPI, including non-streaming responses, streaming responses, and errors.The native Anthropic implementation is a small adapter around the established GCP Anthropic translator. It reuses shared request conversion, response translation, streaming, tracing, redaction, and Anthropic JSON error handling while handling the direct provider's transport differences:
/v1/messagesanthropic-versionheaderThe change also adds focused translator and data-plane coverage and updates the supported-provider documentation and Anthropic Chat Completions example.
Related Issues/PRs (if applicable)
Fixes #1936
Special notes for reviewers (if applicable)
GCP Anthropic is used as the implementation base because both providers return Anthropic
MessageJSON and native Anthropic SSE. AWS Anthropic adds Bedrock-specific paths, error headers, and binary EventStream framing, so it is not a suitable base for the direct provider adapter.A provider-neutral Anthropic core with separate native, GCP, and AWS transport adapters may be a useful future refactor, but it is intentionally outside this PR to avoid modifying established provider paths.
This change was developed with assistance from gpt-5.5 and gpt-5.6, with all code reviewed and tested by me.