Skip to content

Conversation

@secustor
Copy link
Contributor

@secustor secustor commented Oct 23, 2025

Description

This PR implement adds a translator from the Anthropic API to AWS Bedrock for Anthropic.

Related Issues/PRs (if applicable)

Closes #1371

Special notes for reviewers (if applicable)

Has been tested on our side together with #1394 successfully E2E using Claude Code

Using following setup

export ANTHROPIC_BASE_URL=http://localhost:8080/anthropic 
export ANTHROPIC_AUTH_TOKEN=dummy
export ANTHROPIC_MODEL=eu.anthropic.claude-haiku-4-5-20251001-v1:0
export CLAUDE_CODE_MAX_OUTPUT_TOKENS=4096
export MAX_THINKING_TOKENS=1024

claude

The implementation is more or less a copy of the Anthropic to GCP implementation, so it would make sense to include it in the planned refactor with the Anthropic to Anthropic translator

@secustor secustor requested a review from a team as a code owner October 23, 2025 15:28
Signed-off-by: secustor <sebastian@poxhofer.at>
@secustor secustor force-pushed the feat/add-anthropic-to-bedrock branch from 45c6171 to 82f752f Compare October 23, 2025 15:29
@codecov-commenter
Copy link

codecov-commenter commented Oct 23, 2025

Codecov Report

❌ Patch coverage is 86.66667% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.67%. Comparing base (f547bad) to head (c6c6aad).
⚠️ Report is 83 commits behind head on main.

Files with missing lines Patch % Lines
internal/extproc/messages_processor.go 33.33% 2 Missing ⚠️
...ernal/extproc/translator/anthropic_awsanthropic.go 92.59% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1418      +/-   ##
==========================================
- Coverage   83.67%   83.67%   -0.01%     
==========================================
  Files         138      139       +1     
  Lines       12268    12297      +29     
==========================================
+ Hits        10265    10289      +24     
- Misses       1395     1400       +5     
  Partials      608      608              

☔ 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.

Signed-off-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
@mathetake mathetake self-assigned this Oct 23, 2025
Signed-off-by: secustor <sebastian@poxhofer.at>
Signed-off-by: secustor <sebastian@poxhofer.at>
Signed-off-by: secustor <sebastian@poxhofer.at>
# Conflicts:
#	site/docs/capabilities/llm-integrations/supported-endpoints.md
#	site/docs/getting-started/connect-providers/aws-bedrock.md
Copy link
Contributor

@seluard seluard left a comment

Choose a reason for hiding this comment

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

Latest refactor changes tested already at our setup 🧪 ✅

# Conflicts:
#	manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_aiservicebackends.yaml
Copy link
Member

@mathetake mathetake left a comment

Choose a reason for hiding this comment

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

Thanks, this is exciting and thank you for testing locally. can you add tests in here after you resolve my comments?

{
name: "gcp-anthropicai - /anthropic/v1/messages",
backend: "gcp-anthropicai",
path: "/anthropic/v1/messages",
method: http.MethodPost,
requestBody: `{"model":"claude-3-sonnet","max_tokens":100,"messages":[{"role":"user","content":[{"type":"text","text":"Hello, just a simple test message."}]}],"stream":false}`,
expRequestBody: `{"anthropic_version":"vertex-2023-10-16","max_tokens":100,"messages":[{"content":[{"text":"Hello, just a simple test message.","type":"text"}],"role":"user"}],"stream":false}`,
expHost: "gcp-region-aiplatform.googleapis.com",
expPath: "/v1/projects/gcp-project-name/locations/gcp-region/publishers/anthropic/models/claude-3-sonnet:rawPredict",
expRequestHeaders: map[string]string{"Authorization": "Bearer " + fakeGCPAuthToken},
responseStatus: strconv.Itoa(http.StatusOK),
responseBody: `{"id":"msg_123","type":"message","role":"assistant","stop_reason": "end_turn", "content":[{"type":"text","text":"Hello from native Anthropic API!"}],"usage":{"input_tokens":8,"output_tokens":15}}`,
expStatus: http.StatusOK,
expResponseBody: `{"id":"msg_123","type":"message","role":"assistant","stop_reason": "end_turn", "content":[{"type":"text","text":"Hello from native Anthropic API!"}],"usage":{"input_tokens":8,"output_tokens":15}}`,
},
{
name: "gcp-anthropicai - /anthropic/v1/messages - streaming",
backend: "gcp-anthropicai",
path: "/anthropic/v1/messages",
method: http.MethodPost,
responseType: "sse",
requestBody: `{"model":"claude-3-sonnet","max_tokens":100,"messages":[{"role":"user","content":[{"type":"text","text":"Tell me a short joke"}]}],"stream":true}`,
expRequestBody: `{"anthropic_version":"vertex-2023-10-16","max_tokens":100,"messages":[{"content":[{"text":"Tell me a short joke","type":"text"}],"role":"user"}],"stream":true}`,
expHost: "gcp-region-aiplatform.googleapis.com",
expPath: "/v1/projects/gcp-project-name/locations/gcp-region/publishers/anthropic/models/claude-3-sonnet:streamRawPredict",
expRequestHeaders: map[string]string{"Authorization": "Bearer " + fakeGCPAuthToken},
responseStatus: strconv.Itoa(http.StatusOK),
responseBody: `event: message_start
data: {"type": "message_start", "message": {"id": "msg_789", "usage": {"input_tokens": 8}}}
event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "text", "text": ""}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "Why don't scientists trust atoms? Because they make up everything!"}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 0}
event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn"}, "usage": {"output_tokens": 15}}
event: message_stop
data: {"type": "message_stop"}
`,
expStatus: http.StatusOK,
expResponseBody: `event: message_start
data: {"type": "message_start", "message": {"id": "msg_789", "usage": {"input_tokens": 8}}}
event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "text", "text": ""}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "Why don't scientists trust atoms? Because they make up everything!"}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 0}
event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn"}, "usage": {"output_tokens": 15}}
event: message_stop
data: {"type": "message_stop"}
`,
},

… and GCP"

This reverts commit bf5ded2.

Signed-off-by: secustor <sebastian@poxhofer.at>
This reverts commit 460c72e.

Signed-off-by: secustor <sebastian@poxhofer.at>
Signed-off-by: secustor <sebastian@poxhofer.at>
Signed-off-by: secustor <sebastian@poxhofer.at>
@secustor secustor force-pushed the feat/add-anthropic-to-bedrock branch from 6cdd4eb to 7d6cd47 Compare October 25, 2025 19:01
Copy link
Contributor Author

@secustor secustor left a comment

Choose a reason for hiding this comment

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

yet not validated e2e, but should work based on the tests

require.Equal(t, "bearer token123", headers["authorization"])
})

t.Run("multiple header mutations with same key - last one wins", func(t *testing.T) {
Copy link
Contributor Author

@secustor secustor Oct 25, 2025

Choose a reason for hiding this comment

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

My implementation relies on the ( current ) behaviour that when setting the same multiple headers with the same keys the last one wins.

I have added this test to ensure that behaviour in the future isn't broken by accident

Copy link
Member

Choose a reason for hiding this comment

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

sorry can you remove this? it's irrelevant here in this PR. As I noted we do not want to mess up the commit trees with a conflated change. You wouldn't want to end up finding completely unrelated commit in a file that you are debugging

@secustor secustor requested a review from mathetake October 25, 2025 19:10
@seluard
Copy link
Contributor

seluard commented Oct 27, 2025

yet not validated e2e, but should work based on the tests

e2e failed in our side with the latest changes. The duplicated content-length header seems to break the AWS signature, let us work to fix in our side before you take a look.

}

// update content length after changing the body
setContentLength(headerMutation, preparedBody)
Copy link
Member

Choose a reason for hiding this comment

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

you would need to dedup content-length here @secustor @seluard

Signed-off-by: secustor <sebastian@poxhofer.at>
@mathetake
Copy link
Member

kindly ping @seluard @secustor -- we are planning to cut v0.4 very soon, but I would love to see this land. Would it be possible to do the follow here to reach the finish line, or can I just do the clean up and push the changes here for you? Thank you!

Signed-off-by: secustor <sebastian@poxhofer.at>
Signed-off-by: secustor <sebastian@poxhofer.at>
@secustor
Copy link
Contributor Author

@mathetake Added the requested changes, but we couldn't test e2e so far because of unrelated constraints.

Looking forward to v0.4.0 then.

@secustor secustor requested a review from mathetake October 29, 2025 17:28
secustor and others added 3 commits October 29, 2025 18:35
Signed-off-by: secustor <sebastian@poxhofer.at>
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
Copy link
Member

@mathetake mathetake left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution @secustor (and @seluard too)!

I cleaned up and added the e2e tests too, and verified it's working in my AWS env. good to go!

@mathetake mathetake enabled auto-merge (squash) October 29, 2025 21:32
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
@mathetake mathetake merged commit a55f468 into envoyproxy:main Oct 29, 2025
47 of 49 checks passed
mathetake added a commit that referenced this pull request Oct 29, 2025
**Description**

The extproc test's envoy config was missing TLS config for AWS Bedrock
sicne #1418. Since the test is using credentials, hence only running on
the main branch, this was not caught before merging it.


**Related Issues/PRs (if applicable)**

Follow up on #1418

Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
@secustor secustor deleted the feat/add-anthropic-to-bedrock branch October 30, 2025 07:41
hustxiayang pushed a commit to hustxiayang/ai-gateway that referenced this pull request Oct 31, 2025
…ion (envoyproxy#1418)

**Description**

This PR implement adds a translator from the Anthropic API to AWS
Bedrock for Anthropic.

**Related Issues/PRs (if applicable)**

Closes envoyproxy#1371

---------

Signed-off-by: secustor <sebastian@poxhofer.at>
Signed-off-by: yxia216 <yxia216@bloomberg.net>
hustxiayang pushed a commit to hustxiayang/ai-gateway that referenced this pull request Oct 31, 2025
**Description**

The extproc test's envoy config was missing TLS config for AWS Bedrock
sicne envoyproxy#1418. Since the test is using credentials, hence only running on
the main branch, this was not caught before merging it.

**Related Issues/PRs (if applicable)**

Follow up on envoyproxy#1418

Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
Signed-off-by: yxia216 <yxia216@bloomberg.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Anthropic to Anthropic on AWS Bedrock translator for /messages endpoint

5 participants