[Transformer] add Bedrock transformer#228
Conversation
Dependency Validation ResultsDependency name: github.com/wso2/api-platform/sdk/core Dependency name: github.com/wso2/api-platform/sdk/core Dependency name: github.com/wso2/api-platform/sdk/core Dependency name: github.com/wso2/api-platform/sdk/core Dependency name: github.com/wso2/api-platform/sdk/core Dependency name: github.com/wso2/api-platform/sdk/core |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughSummaryAdds the Highlights
WalkthroughAdds the OpenAI to Bedrock Transformer policy. It converts Chat Completions requests into Bedrock Converse requests, including messages, tools, images, inference settings, and provider routing. Buffered Converse responses become OpenAI-compatible JSON, while Bedrock event streams become SSE with deltas, tool calls, usage, errors, and completion markers. The change also adds event-stream framing utilities, policy configuration, versioned documentation, metadata, module setup, and comprehensive tests. Sequence Diagram(s)sequenceDiagram
participant Client
participant TransformerPolicy
participant BedrockConverse
Client->>TransformerPolicy: Send OpenAI Chat Completions request
TransformerPolicy->>BedrockConverse: Send translated Converse request
BedrockConverse-->>TransformerPolicy: Return JSON or event-stream response
TransformerPolicy-->>Client: Return OpenAI JSON or SSE response
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" 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. Comment |
5ce7ee2 to
bfbd36f
Compare
Dependency Validation ResultsDependency name: github.com/wso2/api-platform/sdk/core |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (8)
policies/llm-header-router/llmheaderrouter_test.go (1)
27-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd tests for request processing and idempotent publish behavior.
The test suite covers
parseParamsandselectProviderbut does not testOnRequestHeaders,OnRequestBody, orpublishSelection. The idempotent behavior — where an existingselected_provideris left untouched — is a documented feature (llmheaderrouter.go lines 146-149) and a key part of the cross-policy contract, but has no test coverage. NilSharedContextearly-return paths are also untested.🧪 Suggested test cases
func TestSelectProvider(t *testing.T) { p := &RouterPolicy{params: mustParse(t)} // Exact match. if got, src := p.selectProvider("anthropic"); got != "anthropic-provider" || src != "header" { t.Errorf("expected anthropic-provider/header, got %s/%s", got, src) } // Case-insensitive match. if got, src := p.selectProvider("GEMINI"); got != "gemini-provider" || src != "header" { t.Errorf("expected gemini-provider/header, got %s/%s", got, src) } // Unknown value falls back to default. if got, src := p.selectProvider("unknown"); got != "openai-provider" || src != "default" { t.Errorf("expected openai-provider/default, got %s/%s", got, src) } // Empty header falls back to default. if got, src := p.selectProvider(""); got != "openai-provider" || src != "default" { t.Errorf("expected openai-provider/default, got %s/%s", got, src) } } + +func TestOnRequestHeaders_PublishesSelection(t *testing.T) { + p := &RouterPolicy{params: mustParse(t)} + meta := map[string]interface{}{} + reqCtx := &policy.RequestHeaderContext{ + SharedContext: &policy.SharedContext{Metadata: meta}, + Metadata: meta, + Headers: policy.NewHeaders(map[string][]string{"x-provider": {"anthropic"}}), + } + p.OnRequestHeaders(context.Background(), reqCtx, nil) + if got := meta[MetadataKeySelectedProvider]; got != "anthropic-provider" { + t.Fatalf("expected anthropic-provider, got %v", got) + } +} + +func TestOnRequestBody_IdempotentPublish(t *testing.T) { + p := &RouterPolicy{params: mustParse(t)} + meta := map[string]interface{}{MetadataKeySelectedProvider: "existing-provider"} + reqCtx := &policy.RequestContext{ + SharedContext: &policy.SharedContext{Metadata: meta}, + Metadata: meta, + Headers: policy.NewHeaders(map[string][]string{"x-provider": {"anthropic"}}), + } + p.OnRequestBody(context.Background(), reqCtx, nil) + if got := meta[MetadataKeySelectedProvider]; got != "existing-provider" { + t.Fatalf("expected existing-provider to be preserved, got %v", got) + } +} + +func TestOnRequestHeaders_NilSharedContext(t *testing.T) { + p := &RouterPolicy{params: mustParse(t)} + reqCtx := &policy.RequestHeaderContext{} // SharedContext is nil + action := p.OnRequestHeaders(context.Background(), reqCtx, nil) + if _, ok := action.(policy.UpstreamRequestHeaderModifications); !ok { + t.Fatalf("expected UpstreamRequestHeaderModifications, got %T", action) + } +}Note: The
policy.NewHeadersconstructor and exactRequestHeaderContext/RequestContextfield names should be verified against the SDK v0.2.14 API.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@policies/llm-header-router/llmheaderrouter_test.go` around lines 27 - 107, Add tests covering RouterPolicy.OnRequestHeaders, OnRequestBody, and publishSelection, including nil SharedContext early returns and the idempotent case where an existing selected_provider remains unchanged. Verify and use the SDK v0.2.14 RequestHeaderContext, RequestContext, and policy.NewHeaders APIs, while preserving assertions for provider selection and publication behavior.Source: Learnings
policies/openai-to-azure-openai/openaitoazureopenai_test.go (1)
102-122: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding a test for
OnRequestBodywith a non-matching provider.
TestShouldRun_RoutingGatesverifiesshouldRundirectly, but no test confirms thatOnRequestBodyreturns a no-opUpstreamRequestModifications{}when the selected provider doesn't match. Adding this would close the loop between the routing gate and the request body handler.💡 Suggested test
+func TestOnRequestBody_NonMatchingProviderSkips(t *testing.T) { + p := &TranslatorPolicy{params: PolicyParams{ + APIVersion: "2024-02-15-preview", + Model: "gpt-4o", + PathSuffix: DefaultPathSuffix, + Id: "azure-openai-provider", + }} + action := p.OnRequestBody(context.Background(), + newReqCtx(`{"messages":[]}`, map[string]interface{}{"selected_provider": "gemini-provider"}), nil) + + mods, ok := action.(policy.UpstreamRequestModifications) + if !ok { + t.Fatalf("expected UpstreamRequestModifications, got %T", action) + } + if mods.Path != nil { + t.Errorf("expected no path rewrite for non-matching provider, got %v", mods.Path) + } + if mods.UpstreamName != nil { + t.Errorf("expected no upstream name for non-matching provider, got %v", mods.UpstreamName) + } +}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@policies/openai-to-azure-openai/openaitoazureopenai_test.go` around lines 102 - 122, Add a test alongside TestOnRequestBody_RewritesPathAndSetsUpstream that configures a non-matching provider, invokes OnRequestBody, and verifies it returns an empty policy.UpstreamRequestModifications with no path or upstream name set. Reuse the existing request context and policy setup patterns while preserving the current matching-provider assertions.policies/openai-to-anthropic/openaitoanthropic.go (1)
402-411: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueNon-string assistant content falls back to raw passthrough.
When an assistant message has no
tool_callsand non-stringcontent(e.g. a content-parts array), the function returnsmessage["content"]unconverted instead of mapping it into Anthropic content blocks likeconvertUserContentdoes. Low-impact edge case, but worth normalizing for consistency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@policies/openai-to-anthropic/openaitoanthropic.go` around lines 402 - 411, Update convertAssistantContent so assistant messages without tool_calls normalize non-string content through the same content-block conversion used by convertUserContent, while preserving the existing direct return for non-empty extracted text and raw passthrough only where appropriate.policies/openai-to-anthropic/openaitoanthropic_test.go (1)
1-207: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for the routing gate and remaining translation paths.
This file doesn't test
shouldRun/shouldRunResponse(the routing-gate logic flagged separately inopenaitoanthropic.go), nortranslateErrorResponse, thetool_use→tool_callsresponse mapping,convertImage, orconvertToolChoice. A routing-gate test analogous to the Mistral policy'sTestShouldRun_RoutingGateswould likely have caught the metadata-source concern flagged inopenaitoanthropic.go.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@policies/openai-to-anthropic/openaitoanthropic_test.go` around lines 1 - 207, Add tests in the existing openaitoanthropic test suite covering shouldRun and shouldRunResponse routing gates, following the analogous Mistral TestShouldRun_RoutingGates pattern; also cover translateErrorResponse, tool_use-to-tool_calls response mapping in translateResponse, convertImage, and convertToolChoice. Reuse the visible policy types and translation helpers, asserting both successful conversions and relevant routing/error edge cases.policies/openai-to-mistral/openaitomistral.go (1)
180-193: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
sharedparameter inselectedProviderFromMetadatais unused for reads.The function accepts
shared *policy.SharedContextbut only nil-checks it — all metadata access goes through the separatemetadataparameter. IfRequestContext/ResponseContextembed*SharedContext(making.Metadataresolve toSharedContext.Metadata), thesharedparameter is redundant. Consider removing it and relying solely onmetadata, or ifsharedis needed for future use, document why.♻️ Proposed refactor
-func selectedProviderFromMetadata(shared *policy.SharedContext, metadata map[string]interface{}) string { - if shared == nil || metadata == nil { +func selectedProviderFromMetadata(metadata map[string]interface{}) string { + if metadata == nil { return "" } raw, ok := metadata[MetadataKeySelectedProvider]And update call sites:
func (p *TranslatorPolicy) shouldRun(reqCtx *policy.RequestContext) bool { - return p.shouldRunForSelected(selectedProviderFromMetadata(reqCtx.SharedContext, reqCtx.Metadata)) + return p.shouldRunForSelected(selectedProviderFromMetadata(reqCtx.Metadata)) } func (p *TranslatorPolicy) shouldRunResponse(respCtx *policy.ResponseContext) bool { - return p.shouldRunForSelected(selectedProviderFromMetadata(respCtx.SharedContext, respCtx.Metadata)) + return p.shouldRunForSelected(selectedProviderFromMetadata(respCtx.Metadata)) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@policies/openai-to-mistral/openaitomistral.go` around lines 180 - 193, Remove the unused shared parameter and its nil check from selectedProviderFromMetadata, making the function depend solely on metadata while preserving the existing missing, non-string, and whitespace-trimming behavior. Update every selectedProviderFromMetadata call site to pass only the metadata argument.policies/openai-to-mistral/openaitomistral_test.go (2)
38-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd test for
UpstreamNamewhenIdis configured.
TestOnRequestBody_PinsModelAndStripsUnsupportedFieldsconstructsTranslatorPolicywithoutId, somods.UpstreamNameis never asserted. The multi-provider routing path (lines 125-128 inopenaitomistral.go) is untested at the modification level.💚 Suggested test addition
func TestOnRequestBody_SetsUpstreamNameWhenIdConfigured(t *testing.T) { p := &TranslatorPolicy{params: PolicyParams{Model: "mistral-large-latest", Id: "mistral-provider"}} reqBody := `{"model":"gpt-4o","messages":[{"role":"user","content":"hi"}]}` reqCtx := &policy.RequestContext{ SharedContext: &policy.SharedContext{Metadata: map[string]interface{}{}}, Body: &policy.Body{Present: true, Content: []byte(reqBody)}, } action := p.OnRequestBody(context.Background(), reqCtx, nil) mods, ok := action.(policy.UpstreamRequestModifications) if !ok { t.Fatalf("expected UpstreamRequestModifications, got %T", action) } if mods.UpstreamName == nil || *mods.UpstreamName != "mistral-provider" { t.Fatalf("expected UpstreamName 'mistral-provider', got %v", mods.UpstreamName) } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@policies/openai-to-mistral/openaitomistral_test.go` around lines 38 - 82, Add a focused test alongside TestOnRequestBody_PinsModelAndStripsUnsupportedFields that configures TranslatorPolicy.params.Id, invokes OnRequestBody, and asserts the returned policy.UpstreamRequestModifications has a non-nil UpstreamName matching the configured provider ID. Reuse the existing request context and type assertion patterns.
155-174: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd test coverage for
translateErrorResponse.
TestTranslateResponse_JSONShapeonly covers the success path. Error envelope translation (translateErrorResponseinresponse.go) — including both flat{"message":"..."}and nested{"error":{"message":"..."}}Mistral shapes, status-to-type mapping, and raw-body fallback — is untested.💚 Suggested test additions
func TestTranslateResponse_ErrorNestedShape(t *testing.T) { mistralErr := `{"error":{"type":"invalid_request_error","message":"bad request","code":"400"}}` action := translateResponse([]byte(mistralErr), 400, "mistral-large-latest") mods, ok := action.(policy.DownstreamResponseModifications) if !ok { t.Fatalf("expected DownstreamResponseModifications, got %T", action) } var out map[string]interface{} if err := json.Unmarshal(mods.Body, &out); err != nil { t.Fatalf("translated body not JSON: %v", err) } errObj, _ := out["error"].(map[string]interface{}) if errObj == nil || errObj["message"] != "bad request" { t.Errorf("expected nested error message 'bad request', got %v", out) } } func TestTranslateResponse_ErrorFlatShape(t *testing.T) { mistralErr := `{"message":"unauthorized","type":"authentication_error","code":"401"}` action := translateResponse([]byte(mistralErr), 401, "mistral-large-latest") mods, ok := action.(policy.DownstreamResponseModifications) if !ok { t.Fatalf("expected DownstreamResponseModifications, got %T", action) } var out map[string]interface{} if err := json.Unmarshal(mods.Body, &out); err != nil { t.Fatalf("translated body not JSON: %v", err) } errObj, _ := out["error"].(map[string]interface{}) if errObj == nil || errObj["message"] != "unauthorized" { t.Errorf("expected flat error message 'unauthorized', got %v", out) } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@policies/openai-to-mistral/openaitomistral_test.go` around lines 155 - 174, Add tests covering translateErrorResponse through translateResponse for nested and flat Mistral error envelopes, asserting the result is DownstreamResponseModifications with the expected nested error message. Also cover status-to-type mapping and invalid or non-JSON input to verify the raw-body fallback, reusing existing response translation helpers and test conventions.policies/openai-to-bedrock/openaitobedrock.go (1)
335-344: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRedundant nil guard on
headers.
policy.Headers.Get()is nil-safe, so theif headers == nilcheck here is unnecessary.♻️ Optional simplification
func headerValue(headers *policy.Headers, name string) string { - if headers == nil { - return "" - } values := headers.Get(name)Based on learnings, "the Get() and Iterate() methods perform built-in nil checks and return safely (nil/empty) when called on a nil receiver."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@policies/openai-to-bedrock/openaitobedrock.go` around lines 335 - 344, Remove the redundant nil check from headerValue and rely on policy.Headers.Get’s nil-safe behavior. Preserve the existing empty-string result when Get returns no values, including for a nil headers receiver.Source: Learnings
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@policies/openai-to-anthropic/response.go`:
- Around line 221-235: Update stopReasonToFinish to handle Anthropic refusal and
pause_turn stop reasons explicitly, mapping both to the appropriate distinct
OpenAI-compatible finish reason rather than openaiFinishStop. Preserve existing
tool-call, max-token, tool-use, end-turn, stop-sequence, and default mappings.
In `@policies/openai-to-bedrock/openaitobedrock.go`:
- Line 93: Update all call sites of selectedProvider, including the guard in the
request flow, to validate reqCtx.SharedContext before accessing its promoted
Metadata field. Ensure nil SharedContext is handled without panicking, either by
guarding before dereference or by passing the context into selectedProvider and
checking it there.
In `@policies/openai-to-bedrock/response.go`:
- Around line 338-354: Update stopReasonToFinish so known Bedrock stop reasons
are evaluated before applying the hasToolCalls fallback. Preserve mappings for
max_tokens and content_filtered/guardrail_intervened, returning tool_calls from
hasToolCalls only when the stop reason does not have a more specific mapping,
keeping streaming and non-streaming behavior consistent.
In `@policies/openai-to-gemini/openaitogemini.go`:
- Around line 376-397: The content-part loop in the []interface{} branch must
not panic on missing or non-string type values. Update the switch in the content
conversion logic to use a guarded two-value string assertion for m["type"],
skipping the item when the assertion fails, while preserving the existing text
and image_url handling.
- Around line 308-341: Update the message conversion loop and related state so
assistant tool calls record each tool_call_id-to-function-name mapping; in the
"tool" case, use the mapped function name for functionResponse.name and forward
the original tool_call_id in the separate identifier field expected by Gemini.
Preserve existing tool response text handling and support matching results from
preceding assistant turns.
---
Nitpick comments:
In `@policies/llm-header-router/llmheaderrouter_test.go`:
- Around line 27-107: Add tests covering RouterPolicy.OnRequestHeaders,
OnRequestBody, and publishSelection, including nil SharedContext early returns
and the idempotent case where an existing selected_provider remains unchanged.
Verify and use the SDK v0.2.14 RequestHeaderContext, RequestContext, and
policy.NewHeaders APIs, while preserving assertions for provider selection and
publication behavior.
In `@policies/openai-to-anthropic/openaitoanthropic_test.go`:
- Around line 1-207: Add tests in the existing openaitoanthropic test suite
covering shouldRun and shouldRunResponse routing gates, following the analogous
Mistral TestShouldRun_RoutingGates pattern; also cover translateErrorResponse,
tool_use-to-tool_calls response mapping in translateResponse, convertImage, and
convertToolChoice. Reuse the visible policy types and translation helpers,
asserting both successful conversions and relevant routing/error edge cases.
In `@policies/openai-to-anthropic/openaitoanthropic.go`:
- Around line 402-411: Update convertAssistantContent so assistant messages
without tool_calls normalize non-string content through the same content-block
conversion used by convertUserContent, while preserving the existing direct
return for non-empty extracted text and raw passthrough only where appropriate.
In `@policies/openai-to-azure-openai/openaitoazureopenai_test.go`:
- Around line 102-122: Add a test alongside
TestOnRequestBody_RewritesPathAndSetsUpstream that configures a non-matching
provider, invokes OnRequestBody, and verifies it returns an empty
policy.UpstreamRequestModifications with no path or upstream name set. Reuse the
existing request context and policy setup patterns while preserving the current
matching-provider assertions.
In `@policies/openai-to-bedrock/openaitobedrock.go`:
- Around line 335-344: Remove the redundant nil check from headerValue and rely
on policy.Headers.Get’s nil-safe behavior. Preserve the existing empty-string
result when Get returns no values, including for a nil headers receiver.
In `@policies/openai-to-mistral/openaitomistral_test.go`:
- Around line 38-82: Add a focused test alongside
TestOnRequestBody_PinsModelAndStripsUnsupportedFields that configures
TranslatorPolicy.params.Id, invokes OnRequestBody, and asserts the returned
policy.UpstreamRequestModifications has a non-nil UpstreamName matching the
configured provider ID. Reuse the existing request context and type assertion
patterns.
- Around line 155-174: Add tests covering translateErrorResponse through
translateResponse for nested and flat Mistral error envelopes, asserting the
result is DownstreamResponseModifications with the expected nested error
message. Also cover status-to-type mapping and invalid or non-JSON input to
verify the raw-body fallback, reusing existing response translation helpers and
test conventions.
In `@policies/openai-to-mistral/openaitomistral.go`:
- Around line 180-193: Remove the unused shared parameter and its nil check from
selectedProviderFromMetadata, making the function depend solely on metadata
while preserving the existing missing, non-string, and whitespace-trimming
behavior. Update every selectedProviderFromMetadata call site to pass only the
metadata argument.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3ff45764-89fb-4d19-8c57-1913d5815377
⛔ Files ignored due to path filters (6)
policies/llm-header-router/go.sumis excluded by!**/*.sumpolicies/openai-to-anthropic/go.sumis excluded by!**/*.sumpolicies/openai-to-azure-openai/go.sumis excluded by!**/*.sumpolicies/openai-to-bedrock/go.sumis excluded by!**/*.sumpolicies/openai-to-gemini/go.sumis excluded by!**/*.sumpolicies/openai-to-mistral/go.sumis excluded by!**/*.sum
📒 Files selected for processing (43)
docs/README.mddocs/llm-header-router/v0.9/docs/llm-header-router.mddocs/llm-header-router/v0.9/metadata.jsondocs/openai-to-anthropic/v0.9/docs/openai-to-anthropic.mddocs/openai-to-anthropic/v0.9/metadata.jsondocs/openai-to-azure-openai/v0.9/docs/openai-to-azure-openai.mddocs/openai-to-azure-openai/v0.9/metadata.jsondocs/openai-to-bedrock/v0.9/docs/openai-to-bedrock.mddocs/openai-to-bedrock/v0.9/metadata.jsondocs/openai-to-gemini/v0.9/docs/openai-to-gemini.mddocs/openai-to-gemini/v0.9/metadata.jsondocs/openai-to-mistral/v0.9/docs/openai-to-mistral.mddocs/openai-to-mistral/v0.9/metadata.jsonpolicies/llm-header-router/go.modpolicies/llm-header-router/llmheaderrouter.gopolicies/llm-header-router/llmheaderrouter_test.gopolicies/llm-header-router/policy-definition.yamlpolicies/openai-to-anthropic/go.modpolicies/openai-to-anthropic/openaitoanthropic.gopolicies/openai-to-anthropic/openaitoanthropic_test.gopolicies/openai-to-anthropic/policy-definition.yamlpolicies/openai-to-anthropic/response.gopolicies/openai-to-azure-openai/go.modpolicies/openai-to-azure-openai/openaitoazureopenai.gopolicies/openai-to-azure-openai/openaitoazureopenai_test.gopolicies/openai-to-azure-openai/policy-definition.yamlpolicies/openai-to-bedrock/bedrock_test.gopolicies/openai-to-bedrock/eventstream.gopolicies/openai-to-bedrock/go.modpolicies/openai-to-bedrock/openaitobedrock.gopolicies/openai-to-bedrock/policy-definition.yamlpolicies/openai-to-bedrock/request.gopolicies/openai-to-bedrock/response.gopolicies/openai-to-gemini/go.modpolicies/openai-to-gemini/openaitogemini.gopolicies/openai-to-gemini/openaitogemini_test.gopolicies/openai-to-gemini/policy-definition.yamlpolicies/openai-to-gemini/response.gopolicies/openai-to-mistral/go.modpolicies/openai-to-mistral/openaitomistral.gopolicies/openai-to-mistral/openaitomistral_test.gopolicies/openai-to-mistral/policy-definition.yamlpolicies/openai-to-mistral/response.go
bfbd36f to
3adc0cc
Compare
Dependency Validation ResultsDependency name: github.com/wso2/api-platform/sdk/core |
Dependency Validation ResultsDependency name: github.com/wso2/api-platform/sdk/core |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@policies/openai-to-bedrock-transformer/eventstream.go`:
- Around line 169-186: Update the header parsing loop around valueType in the
event-stream decoder to skip non-string headers rather than breaking. Advance
offset according to each AWS event-stream header type’s defined encoding length,
including fixed-width numeric, boolean, byte, and variable-length byte/string
types, while retaining bounds checks; continue parsing until :event-type is
reached or malformed data is detected.
In `@policies/openai-to-bedrock-transformer/response.go`:
- Around line 169-184: Update eventStreamToSSE so that when
decodeEventStreamFrames fails, it preserves and returns the original data
instead of leaving out empty; retain framed conversion and endOfStream
sseDonePayload behavior unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: cc72b2c1-ea88-40d7-8b32-f9d7dc289482
⛔ Files ignored due to path filters (1)
policies/openai-to-bedrock-transformer/go.sumis excluded by!**/*.sum
📒 Files selected for processing (10)
docs/README.mddocs/openai-to-bedrock-transformer/v0.9/docs/openai-to-bedrock-transformer.mddocs/openai-to-bedrock-transformer/v0.9/metadata.jsonpolicies/openai-to-bedrock-transformer/bedrock_test.gopolicies/openai-to-bedrock-transformer/eventstream.gopolicies/openai-to-bedrock-transformer/go.modpolicies/openai-to-bedrock-transformer/openaitobedrock.gopolicies/openai-to-bedrock-transformer/policy-definition.yamlpolicies/openai-to-bedrock-transformer/request.gopolicies/openai-to-bedrock-transformer/response.go
Dependency Validation ResultsDependency name: github.com/wso2/api-platform/sdk/core |
Dependency Validation ResultsDependency name: github.com/wso2/api-platform/sdk/core |
Dependency Validation ResultsDependency name: github.com/wso2/api-platform/sdk/core |
Dependency Validation ResultsDependency name: github.com/wso2/api-platform/sdk/core |
Purpose
Add AWS Bedrock as a supported target for OpenAI-compatible LLM proxies. Clients should be able to send OpenAI Chat Completions requests while the gateway communicates with AWS Bedrock using the Converse API.
This also enables AWS Bedrock to participate in the existing multi-provider routing flow.
No linked issue.
Goals
openai-to-bedrock-transformerpolicy.Approach
The policy implements request, response-header, buffered-response, and streaming-response processing.
The implementation:
/model/{modelId}/converseor/model/{modelId}/converse-stream.image_urlcontent into Bedrock image blocks.inferenceConfig.selected_providermetadata to participate in multi-provider routing.This change does not affect the UI.
User stories
Release note
Added an OpenAI-to-AWS-Bedrock transformer policy that converts OpenAI Chat Completions traffic to the AWS Bedrock Converse API, including support for streaming responses, tool calling, multimodal input, and multi-provider routing.
Documentation
Documentation is included in this PR:
docs/openai-to-bedrock/v0.9/docs/openai-to-bedrock.mddocs/openai-to-bedrock/v0.9/metadata.jsondocs/README.mdpolicy catalogTraining
N/A — no training-content changes are required for this policy addition.
Certification
N/A — this policy addition does not currently require changes to certification exams.
Marketing
N/A — no marketing-content changes are included in this PR.
Automation tests
Unit tests
go test -race ./...passed.go vet ./...passed.Integration tests
Security checks
Samples
The policy documentation includes configuration examples for:
openai-to-bedrock-transformerto an additional provider in a multi-provider LLM proxy.No credentials or functional API keys are included in the samples.
Related PRs
N/A.
This branch is based on
multi-provider-transformers, which introduces the common multi-provider transformer functionality used by this policy.Migrations (if applicable)
N/A — this is a new policy and does not change existing policy configurations or stored data.
Existing users can opt in by adding
openai-to-bedrock-transformerto a single-provider proxy or to an AWS Bedrock entry underadditionalProviders.Test environment
github.com/wso2/api-platform/sdk/core v0.2.14Learning
The implementation was informed by:
api-platform-main/gateway.selected_providermulti-provider routing convention.