Skip to content

feat(payload-processing): add AWS Bedrock OpenAI chat completions sup…#601

Draft
srampal wants to merge 1 commit intoopendatahub-io:mainfrom
srampal:bedrock
Draft

feat(payload-processing): add AWS Bedrock OpenAI chat completions sup…#601
srampal wants to merge 1 commit intoopendatahub-io:mainfrom
srampal:bedrock

Conversation

@srampal
Copy link

@srampal srampal commented Mar 24, 2026

…port

Description

  • Add AWSBedrockOpenAI provider constant
  • Implement Bedrock translator for OpenAI-compatible API
  • Support configurable AWS regions (defaults to us-east-1)
  • Add API key injection with Bearer token format
  • Include comprehensive test suite (15 test cases)
  • Maintain full compatibility with existing providers
    Note: The goal here is not to support the Bedrock Converse or Invoke APIs, not the openai responses api. Limiting this PR to just the direct OpenAI endpoint within Bedrock and only the chat completions api for a simple initial implementation. More api translation and interworking combinations can be added in future.

How Has This Been Tested?

All Unit tests pass. Additional e2e/ manual testing to be performed for full verification.

Merge criteria:

  • The commits are squashed in a cohesive manner and have meaningful messages.
  • Testing instructions have been added in the PR body (for PRs involving changes that are not immediately obvious).
  • The developer has manually tested the changes and verified that the changes work

…port

- Add AWSBedrockOpenAI provider constant
- Implement Bedrock translator for OpenAI-compatible API
- Support configurable AWS regions (defaults to us-east-1)
- Add API key injection with Bearer token format
- Include comprehensive test suite (15 test cases)
- Maintain full compatibility with existing providers
@openshift-ci
Copy link

openshift-ci bot commented Mar 24, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci
Copy link

openshift-ci bot commented Mar 24, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: srampal
Once this PR has been reviewed and has the lgtm label, please assign jland-redhat for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 24, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 187354e3-49bd-407c-a7c9-4750a601d2ac

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@srampal
Copy link
Author

srampal commented Mar 24, 2026

@nirrozenbaum PTAL

@nirrozenbaum
Copy link
Contributor

/retest

@@ -0,0 +1,106 @@
/*
Copyright 2026 The opendatahub.io Authors.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: align with the other files in the repo

Suggested change
Copyright 2026 The opendatahub.io Authors.
Copyright 2026.

if region == "" {
region = awsDefaultRegion
}

Copy link
Contributor

Choose a reason for hiding this comment

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

this is not needed. called should set the region. and in the translator we assume it was set properly.

Comment on lines +78 to +81
// Validate this is a Chat Completions request
if _, hasMessages := body["messages"]; !hasMessages {
return nil, nil, nil, fmt.Errorf("only Chat Completions API is supported - 'messages' field required")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

no need - basic assumptions it only OpenAI chat completions for now.
pls remove.

Suggested change
// Validate this is a Chat Completions request
if _, hasMessages := body["messages"]; !hasMessages {
return nil, nil, nil, fmt.Errorf("only Chat Completions API is supported - 'messages' field required")
}

headersToMutate = map[string]string{
":path": bedrockOpenAIPath,
"content-type": "application/json",
"host": fmt.Sprintf("bedrock-runtime.%s.amazonaws.com", t.region),
Copy link
Contributor

Choose a reason for hiding this comment

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

we are not supposed to set host here.
this should be part of MaaSModelRef CR, where the external model should declare:
provider (e.g., bedrock-openai) and endpoint (e.g., bedrock-runtime..amazonaws.com).
this shouldn't be part of the translator.

we should also remove the env var + default region vars.

Comment on lines +103 to +106
// GetRegion returns the AWS region configured for this translator
func (t *BedrockTranslator) GetRegion() string {
return t.region
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

no need to get region.

Comment on lines +27 to +29
func createTestTranslator() *BedrockTranslator {
return NewBedrockTranslator()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: can we remove this function?
just call NewBedrockTranslator()

assert.Nil(t, translatedBody, "body should not be mutated for Bedrock OpenAI-compatible API")
assert.Equal(t, "/v1/chat/completions", headers[":path"])
assert.Equal(t, "application/json", headers["content-type"])
assert.Equal(t, "bedrock-runtime.us-east-1.amazonaws.com", headers["host"])
Copy link
Contributor

Choose a reason for hiding this comment

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

pls remove:

Suggested change
assert.Equal(t, "bedrock-runtime.us-east-1.amazonaws.com", headers["host"])

Comment on lines +49 to +63
func TestTranslateRequest_WithRegion(t *testing.T) {
translator := NewBedrockTranslatorWithRegion("us-west-2")

body := map[string]any{
"model": "nvidia.nemotron-nano-12b-v2",
"messages": []any{
map[string]any{"role": "user", "content": "Hello"},
},
}

_, headers, _, err := translator.TranslateRequest(body)
require.NoError(t, err)

assert.Equal(t, "bedrock-runtime.us-west-2.amazonaws.com", headers["host"])
}
Copy link
Contributor

Choose a reason for hiding this comment

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

no need to add host.
previous test should cover the rest of functionality. can be removed.

Suggested change
func TestTranslateRequest_WithRegion(t *testing.T) {
translator := NewBedrockTranslatorWithRegion("us-west-2")
body := map[string]any{
"model": "nvidia.nemotron-nano-12b-v2",
"messages": []any{
map[string]any{"role": "user", "content": "Hello"},
},
}
_, headers, _, err := translator.TranslateRequest(body)
require.NoError(t, err)
assert.Equal(t, "bedrock-runtime.us-west-2.amazonaws.com", headers["host"])
}

Comment on lines +66 to +80
body := map[string]any{
"model": "nvidia.nemotron-nano-12b-v2",
"messages": []any{
map[string]any{"role": "system", "content": "You are helpful."},
map[string]any{"role": "user", "content": "Hello"},
},
"temperature": 0.7,
"top_p": 0.9,
"max_tokens": 1000,
"stream": true,
"stop": []any{"END"},
"n": 1,
"presence_penalty": 0.5,
"frequency_penalty": 0.3,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

can you just move these fields to the first test and remove duplicated test?

Comment on lines +109 to +117
func TestTranslateRequest_MissingMessages(t *testing.T) {
body := map[string]any{
"model": "nvidia.nemotron-nano-12b-v2",
}

_, _, _, err := createTestTranslator().TranslateRequest(body)
assert.Error(t, err)
assert.Contains(t, err.Error(), "only Chat Completions API is supported")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

remove pls

Suggested change
func TestTranslateRequest_MissingMessages(t *testing.T) {
body := map[string]any{
"model": "nvidia.nemotron-nano-12b-v2",
}
_, _, _, err := createTestTranslator().TranslateRequest(body)
assert.Error(t, err)
assert.Contains(t, err.Error(), "only Chat Completions API is supported")
}

Comment on lines +119 to +128
func TestTranslateRequest_LegacyCompletionsNotSupported(t *testing.T) {
body := map[string]any{
"model": "nvidia.nemotron-nano-12b-v2",
"prompt": "Complete this sentence: The weather today is",
}

_, _, _, err := createTestTranslator().TranslateRequest(body)
assert.Error(t, err)
assert.Contains(t, err.Error(), "only Chat Completions API is supported")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

remove please.

Suggested change
func TestTranslateRequest_LegacyCompletionsNotSupported(t *testing.T) {
body := map[string]any{
"model": "nvidia.nemotron-nano-12b-v2",
"prompt": "Complete this sentence: The weather today is",
}
_, _, _, err := createTestTranslator().TranslateRequest(body)
assert.Error(t, err)
assert.Contains(t, err.Error(), "only Chat Completions API is supported")
}

Comment on lines +130 to +143
func TestTranslateRequest_HeadersSet(t *testing.T) {
body := map[string]any{
"model": "nvidia.nemotron-nano-12b-v2",
"messages": []any{map[string]any{"role": "user", "content": "Hi"}},
}

_, headers, _, err := createTestTranslator().TranslateRequest(body)
require.NoError(t, err)

assert.Len(t, headers, 3)
assert.Contains(t, headers, ":path")
assert.Contains(t, headers, "content-type")
assert.Contains(t, headers, "host")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

covered in first test, pls remove:

Suggested change
func TestTranslateRequest_HeadersSet(t *testing.T) {
body := map[string]any{
"model": "nvidia.nemotron-nano-12b-v2",
"messages": []any{map[string]any{"role": "user", "content": "Hi"}},
}
_, headers, _, err := createTestTranslator().TranslateRequest(body)
require.NoError(t, err)
assert.Len(t, headers, 3)
assert.Contains(t, headers, ":path")
assert.Contains(t, headers, "content-type")
assert.Contains(t, headers, "host")
}

Comment on lines +173 to +193
func TestTranslateResponse_StreamingChunk(t *testing.T) {
body := map[string]any{
"id": "chatcmpl-abc123",
"object": "chat.completion.chunk",
"created": 1700000000,
"model": "nvidia.nemotron-nano-12b-v2",
"choices": []any{
map[string]any{
"index": 0,
"delta": map[string]any{
"content": "Hello",
},
"finish_reason": nil,
},
},
}

translatedBody, err := createTestTranslator().TranslateResponse(body, "nvidia.nemotron-nano-12b-v2")
require.NoError(t, err)
assert.Nil(t, translatedBody)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

doesn't seem to be testing something new. can be removed.

Comment on lines +209 to +211
func TestProviderName(t *testing.T) {
assert.Equal(t, "awsbedrock-openai", provider.AWSBedrockOpenAI)
}
Copy link
Contributor

@nirrozenbaum nirrozenbaum Mar 24, 2026

Choose a reason for hiding this comment

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

remove please. not relevant

Suggested change
func TestProviderName(t *testing.T) {
assert.Equal(t, "awsbedrock-openai", provider.AWSBedrockOpenAI)
}

Comment on lines +219 to +227
func TestGetRegion(t *testing.T) {
translator := NewBedrockTranslatorWithRegion("eu-west-1")
assert.Equal(t, "eu-west-1", translator.GetRegion())
}

func TestNewBedrockTranslatorWithRegion_EmptyRegion(t *testing.T) {
translator := NewBedrockTranslatorWithRegion("")
assert.Equal(t, "us-east-1", translator.GetRegion()) // Should default
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

remove pls:

Suggested change
func TestGetRegion(t *testing.T) {
translator := NewBedrockTranslatorWithRegion("eu-west-1")
assert.Equal(t, "eu-west-1", translator.GetRegion())
}
func TestNewBedrockTranslatorWithRegion_EmptyRegion(t *testing.T) {
translator := NewBedrockTranslatorWithRegion("")
assert.Equal(t, "us-east-1", translator.GetRegion()) // Should default
}

func TestNewBedrockTranslator(t *testing.T) {
translator := NewBedrockTranslator()
assert.NotNil(t, translator)
assert.Equal(t, "us-east-1", translator.GetRegion()) // Default region
Copy link
Contributor

Choose a reason for hiding this comment

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

remove:

Suggested change
assert.Equal(t, "us-east-1", translator.GetRegion()) // Default region

Copy link
Contributor

@nirrozenbaum nirrozenbaum left a comment

Choose a reason for hiding this comment

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

@srampal thanks.
I left minor comments.
most is about cleanup of unnecessary things.
otherwise looks good.

@openshift-ci
Copy link

openshift-ci bot commented Mar 24, 2026

@srampal: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-test-maas 9d2b274 link false /test e2e-test-maas

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@nirrozenbaum
Copy link
Contributor

/retest

@srampal
Copy link
Author

srampal commented Mar 25, 2026

@nirrozenbaum As discussed offline, this PR will be merged into the other repo (ai-gateway-payload-processing). Have made all the changes there so leaving this PR as -is for now. Let us review and merge in that other repo, after which we can close this PR here or update here again if needed.

@openshift-ci
Copy link

openshift-ci bot commented Mar 25, 2026

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants