Skip to content

feat: add Anthropic /messages to AWS Bedrock translator - #2103

Merged
nacx merged 3 commits into
envoyproxy:mainfrom
Killusions:feat/anthropic-awsbedrock-translator
May 12, 2026
Merged

feat: add Anthropic /messages to AWS Bedrock translator#2103
nacx merged 3 commits into
envoyproxy:mainfrom
Killusions:feat/anthropic-awsbedrock-translator

Conversation

@Killusions

@Killusions Killusions commented May 4, 2026

Copy link
Copy Markdown
Contributor

Description

Adds a translator from the Anthropic /messages API to the AWS Bedrock API (anthropic_awsbedrock.go). This is similar to how openai_awsbedrock.go translates OpenAI requests to Bedrock, it lets you use the Anthropic client format to reach any model on Bedrock, not just Anthropic models.

Handles messages, system prompts, tools, thinking config, images, streaming (EventStream unwrapping to SSE), and error translation.

Related:

⚒️ with ❤️ by @siemens

@Killusions
Killusions requested a review from a team as a code owner May 4, 2026 13:29
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label May 4, 2026
@dosubot

dosubot Bot commented May 4, 2026

Copy link
Copy Markdown

Documentation Updates

2 document(s) were updated by changes in this PR:

aws-bedrock
View Changes
@@ -273,10 +273,12 @@
 
 ## Using Anthropic Native API
 
-When using Anthropic models on AWS Bedrock, you have two options:
+When using models on AWS Bedrock, you have two options:
 
 1. **OpenAI-compatible format** (`/v1/chat/completions`) - Works with most models but may not support all Anthropic-specific features. Note that `max_tokens` is required by the Anthropic API — if your clients do not include it, you must inject it via a request body mutation.
-2. **Native Anthropic API** (`/anthropic/v1/messages`) - Provides full access to Anthropic-specific features (only for Anthropic models)
+2. **Native Anthropic API** (`/anthropic/v1/messages`) - Provides full access to Anthropic-specific features with two use cases:
+   - **AWSAnthropic schema**: Use the native Anthropic format for Anthropic models on Bedrock
+   - **AWSBedrock schema**: Use the Anthropic client format with ANY model on AWS Bedrock (the Anthropic /messages API is translated to the Bedrock Converse API, similar to how OpenAI format translation works)
 
 ### Streaming with Native Anthropic API
 
supported-providers
View Changes
@@ -13,7 +13,7 @@
 | Provider Name                                                                                             |                                API Schema Config on [AIServiceBackend]                                 | Upstream Authentication Config on [BackendSecurityPolicy] | Status | Note                                                                                                                                                   |
 | --------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------: | :-------------------------------------------------------: | :----: | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
 | [OpenAI](https://platform.openai.com/docs/api-reference)                                                  |                                   `{"name":"OpenAI","prefix":"/v1"}`                                   |                         [API Key]                         |   ✅   |                                                                                                                                                        |
-| [AWS Bedrock](https://docs.aws.amazon.com/bedrock/latest/APIReference/)                                   |                                        `{"name":"AWSBedrock"}`                                         |                 [AWS Bedrock Credentials]                 |   ✅   |                                                                                                                                                        |
+| [AWS Bedrock](https://docs.aws.amazon.com/bedrock/latest/APIReference/)                                   |                                        `{"name":"AWSBedrock"}`                                         |                 [AWS Bedrock Credentials]                 |   ✅   | Supports translation from both OpenAI format and Anthropic /messages format. You can use either OpenAI or Anthropic client libraries with any model. |
 | [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/reference)                      | `{"name":"AzureOpenAI","version":"2025-01-01-preview"}` or `{"name":"OpenAI", "prefix": "/openai/v1"}` |          [Azure Credentials] or [Azure API Key]           |   ✅   |                                                                                                                                                        |
 | [Google Gemini on AI Studio](https://ai.google.dev/gemini-api/docs/openai)                                |                             `{"name":"OpenAI","prefix":"/v1beta/openai"}`                              |                         [API Key]                         |   ✅   | Only the OpenAI compatible endpoint                                                                                                                    |
 | [Google Vertex AI](https://cloud.google.com/vertex-ai/docs/reference/rest)                                |                                        `{"name":"GCPVertexAI"}`                                        |                     [GCP Credentials]                     |   ✅   | Supports ADC, Service Account Keys, and Workload Identity Federation                                                                                   |

How did I do? Any feedback?  Join Discord

@Killusions
Killusions force-pushed the feat/anthropic-awsbedrock-translator branch from e50c742 to 2c337c1 Compare May 4, 2026 13:32
@gavrissh

gavrissh commented May 5, 2026

Copy link
Copy Markdown
Contributor

Could you add in the documentation and a dataplane test

@Killusions

Copy link
Copy Markdown
Contributor Author

Could you add in the documentation and a dataplane test

@gavrissh Done

@Killusions
Killusions force-pushed the feat/anthropic-awsbedrock-translator branch from 2c337c1 to 21b6d53 Compare May 5, 2026 09:23
@nacx

nacx commented May 6, 2026

Copy link
Copy Markdown
Member

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a translator for the Anthropic Messages API to the AWS Bedrock Converse API, enabling AWS Bedrock as a supported backend. The changes include the core translator logic with support for streaming and tool use, updates to the endpoint specification, and comprehensive unit and integration tests. Feedback was provided to refactor the error response handling in the new translator to eliminate redundant logic when processing different content types.

I am having trouble creating individual review comments. Click here to see my feedback.

internal/translator/anthropic_awsbedrock.go (740-779)

medium

This function contains duplicated logic for handling JSON and non-JSON error responses. You can refactor it to be more concise and improve maintainability by extracting the common parts.

statusCode := respHeaders[statusHeaderName]
	var errorMessage string
	if v, ok := respHeaders[contentTypeHeaderName]; ok && strings.Contains(v, jsonContentType) {
		var bedrockError awsbedrock.BedrockException
		if err = json.NewDecoder(body).Decode(&bedrockError); err != nil {
			return nil, nil, fmt.Errorf("failed to unmarshal error body: %w", err)
		}
		errorMessage = bedrockError.Message
	} else {
		var buf []byte
		buf, err = io.ReadAll(body)
		if err != nil {
			return nil, nil, fmt.Errorf("failed to read error body: %w", err)
		}
		errorMessage = string(buf)
	}
	anthropicError := anthropicschema.ErrorResponse{
		Type: "error",
		Error: anthropicschema.ErrorResponseMessage{
			Type:    a.httpStatusToAnthropicErrorType(statusCode),
			Message: errorMessage,
		},
	}
	mutatedBody, err = json.Marshal(anthropicError)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to marshal error body: %w", err)
	}
	newHeaders = []internalapi.Header{
		{contentTypeHeaderName, jsonContentType},
		{contentLengthHeaderName, strconv.Itoa(len(mutatedBody))},
	}
	return

@Killusions
Killusions force-pushed the feat/anthropic-awsbedrock-translator branch from 21b6d53 to 988a6db Compare May 7, 2026 15:42
@Killusions

Copy link
Copy Markdown
Contributor Author

@nacx Addressed the one review comment and fixed the failing tests/CI

@nacx nacx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Overall LGTM.

The basic e2e tests already use the examples/basic/aws.yaml to validate basic features.

Is it possible to reuse those routes and add a test to the existing basic e2e tests that exercise this translation? It would be great to have real e2e tests for this beyond hte upstream ones.

@Killusions
Killusions force-pushed the feat/anthropic-awsbedrock-translator branch 2 times, most recently from 858a880 to d70800a Compare May 12, 2026 14:22
@Killusions

Copy link
Copy Markdown
Contributor Author

Thanks! Overall LGTM.

The basic e2e tests already use the examples/basic/aws.yaml to validate basic features.

Is it possible to reuse those routes and add a test to the existing basic e2e tests that exercise this translation? It would be great to have real e2e tests for this beyond hte upstream ones.

@nacx Thanks, added some basic ones, though I cannot run them to verify.

@Killusions

Copy link
Copy Markdown
Contributor Author

@nacx Will fix the failures

@nacx

nacx commented May 12, 2026

Copy link
Copy Markdown
Member

I've run the e2e locally and passed:

--- PASS: Test_Examples_Basic (53.56s)
    --- PASS: Test_Examples_Basic/testupsream (0.48s)
    --- PASS: Test_Examples_Basic/with_credentials (11.01s)
        --- SKIP: Test_Examples_Basic/with_credentials/openai (0.00s)
        --- PASS: Test_Examples_Basic/with_credentials/aws (1.75s)
        --- SKIP: Test_Examples_Basic/with_credentials/cohere_v2_rerank (0.00s)
        --- SKIP: Test_Examples_Basic/with_credentials/anthropic (0.00s)
        --- PASS: Test_Examples_Basic/with_credentials/aws_bedrock_anthropic_messages (1.90s)

@nacx

nacx commented May 12, 2026

Copy link
Copy Markdown
Member

/retest

Signed-off-by: Linus Schlumberger <linus.schlumberger@siemens.com>
Signed-off-by: Linus Schlumberger <linus.schlumberger@siemens.com>
Signed-off-by: Linus Schlumberger <linus.schlumberger@siemens.com>
@Killusions
Killusions force-pushed the feat/anthropic-awsbedrock-translator branch from d70800a to 0b88757 Compare May 12, 2026 15:51
@Killusions

Copy link
Copy Markdown
Contributor Author

@nacx Was the coverage gate and a JSON serialization order thing, added more tests and made that one expectation order invariant

@nacx

nacx commented May 12, 2026

Copy link
Copy Markdown
Member

Thanks! Next time, please don't squash commits, just add them incrementally so we can just review the last changes.

@Killusions

Copy link
Copy Markdown
Contributor Author

Thanks! Next time, please don't squash commits, just add them incrementally so we can just review the last changes.

@nacx Will do, thanks for letting me know, in our projects it's usually the opposite, will remember.

@nacx
nacx enabled auto-merge (squash) May 12, 2026 16:32
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.86813% with 99 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.40%. Comparing base (555f803) to head (0b88757).

Files with missing lines Patch % Lines
internal/translator/anthropic_awsbedrock.go 81.76% 79 Missing and 20 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2103      +/-   ##
==========================================
- Coverage   84.48%   84.40%   -0.08%     
==========================================
  Files         133      134       +1     
  Lines       18514    19059     +545     
==========================================
+ Hits        15641    16087     +446     
- Misses       1912     1991      +79     
- Partials      961      981      +20     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nacx
nacx merged commit 28186f5 into envoyproxy:main May 12, 2026
33 of 34 checks passed
aishwaryaraimule21 pushed a commit to aishwaryaraimule21/ai-gateway that referenced this pull request May 13, 2026
)

**Description**

Adds a translator from the Anthropic /messages API to the AWS Bedrock
API (`anthropic_awsbedrock.go`). This is similar to how
`openai_awsbedrock.go` translates OpenAI requests to Bedrock, it lets
you use the Anthropic client format to reach any model on Bedrock, not
just Anthropic models.

Handles messages, system prompts, tools, thinking config, images,
streaming (EventStream unwrapping to SSE), and error translation.

Related:
- envoyproxy#2102

---------

Signed-off-by: Linus Schlumberger <linus.schlumberger@siemens.com>
Signed-off-by: Aishwarya <aishwarya.raimule@nutanix.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants