Skip to content

feat: migrate Bedrock Claude models to native Anthropic Messages API#1924

Open
Pratham-Mishra04 wants to merge 1 commit intomainfrom
03-05-feat_shifted_to_anthropic_endpoints_in_bedrock_for_claude_models
Open

feat: migrate Bedrock Claude models to native Anthropic Messages API#1924
Pratham-Mishra04 wants to merge 1 commit intomainfrom
03-05-feat_shifted_to_anthropic_endpoints_in_bedrock_for_claude_models

Conversation

@Pratham-Mishra04
Copy link
Collaborator

Summary

Migrated Bedrock provider to use Anthropic's native Messages API format for Claude models instead of the Bedrock Converse API. This change improves compatibility and leverages Anthropic's native streaming format while maintaining backward compatibility for non-Anthropic models.

Changes

  • Added new anthropic_compat.go file with functions to convert requests to Anthropic Messages API format for Bedrock's InvokeModel endpoint
  • Exported Anthropic stream state management functions for use by Bedrock provider
  • Modified Bedrock provider to route Anthropic models through InvokeModel endpoint with native Anthropic format
  • Updated both chat completion and responses endpoints to support dual API paths
  • Enhanced streaming support to handle Anthropic SSE events wrapped in AWS EventStream format
  • Maintained existing Converse API support for all non-Anthropic models

Type of change

  • Feature
  • Bug fix
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

How to test

Test with Claude models on Bedrock to verify native Anthropic API compatibility:

# Core/Transports
go version
go test ./...

# Test Bedrock with Claude models
curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-bedrock-key" \
  -d '{
    "model": "anthropic.claude-3-sonnet-20240229-v1:0",
    "messages": [{"role": "user", "content": "Hello"}]
  }'

# Test streaming
curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-bedrock-key" \
  -d '{
    "model": "anthropic.claude-3-sonnet-20240229-v1:0",
    "messages": [{"role": "user", "content": "Hello"}],
    "stream": true
  }'

Verify non-Anthropic models still use Converse API and function correctly.

Screenshots/Recordings

N/A

Breaking changes

  • Yes
  • No

This change maintains backward compatibility. Existing Bedrock integrations will continue to work without modification.

Related issues

N/A

Security considerations

No new security implications. Uses existing Bedrock authentication and maintains the same security model.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Bedrock provider now uses Anthropic native API for Claude models
    • Added audio format detection from file headers
  • Bug Fixes

    • Fixed async jobs stuck in "processing" state that now correctly transition to "failed" on errors

Walkthrough

The PR routes Anthropic-compatible models in the Bedrock provider to Anthropic-style InvokeModel endpoints while keeping other models on Bedrock's Converse API. It adds Bedrock-specific Anthropic request marshaling helpers and exposes two Anthropic responses stream pool accessors; changelogs and tests updated accordingly.

Changes

Cohort / File(s) Summary
Changelog Updates
core/changelog.md, transports/changelog.md
Updated changelogs: reflect shift to Anthropic native API in Bedrock provider for Claude models and async-job marshal-failure transition fix; removed an audio filename-preservation entry.
Anthropic Response State API
core/providers/anthropic/responses.go
Added two exported wrapper functions: AcquireAnthropicResponsesStreamState() and ReleaseAnthropicResponsesStreamState(state *AnthropicResponsesStreamState) to expose internal pool acquisition/release.
Bedrock Anthropic Compatibility Helpers
core/providers/bedrock/anthropic_compat.go
New unexported helpers (getBedrockAnthropicChatRequestBody, getBedrockAnthropicResponsesRequestBody, marshalBedrockAnthropicBody) to build/marshal Anthropic-style request bodies for Bedrock InvokeModel endpoints, support raw-body passthrough, defaults, and extra-param merging.
Bedrock Provider Routing & Streams
core/providers/bedrock/bedrock.go
Large refactor: resolve deployments early and branch Anthropic vs Converse paths across ChatCompletion, ChatCompletionStream, Responses, ResponsesStream; per-flow request construction, streaming handling, response parsing, and consistent ExtraFields enrichment (Provider, ModelRequested, ModelDeployment, RequestType, Latency, ProviderResponseHeaders) and RAW exposure.
Bedrock Config & Tests
core/providers/bedrock/types.go, core/providers/bedrock/bedrock_test.go
Added DefaultBedrockAnthropicVersion constant; adjusted test flags to disable batch/file operation tests while keeping others (tokens, structured outputs).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant BedrockProvider as Bedrock Provider
    participant DeploymentResolver as Deployment Resolver
    participant AnthropicPath as Anthropic Path
    participant ConverseAPI as Converse API
    participant ResponseParser

    Client->>BedrockProvider: ChatCompletion Request
    BedrockProvider->>DeploymentResolver: Resolve deployment for model
    DeploymentResolver-->>BedrockProvider: Anthropic? / Converse?

    alt Anthropic
        BedrockProvider->>AnthropicPath: Build Anthropic InvokeModel body
        AnthropicPath->>BedrockProvider: Marshaled Request
        BedrockProvider->>BedrockProvider: Call InvokeModel (invoke)
        BedrockProvider->>ResponseParser: Parse Anthropic response
        ResponseParser-->>BedrockProvider: Enriched Bifrost response
    else Converse
        BedrockProvider->>ConverseAPI: Build Converse request
        ConverseAPI->>BedrockProvider: Request ready
        BedrockProvider->>BedrockProvider: Call Converse endpoint
        BedrockProvider->>ResponseParser: Parse Bedrock response
        ResponseParser-->>BedrockProvider: Enriched Bifrost response
    end

    BedrockProvider-->>Client: Bifrost ChatCompletion Response
Loading
sequenceDiagram
    participant Client
    participant BedrockProvider as Bedrock Provider
    participant DeploymentResolver as Deployment Resolver
    participant AnthropicStream as Anthropic Stream
    participant ConverseStream as Converse Stream
    participant ChunkProcessor as Chunk Processor

    Client->>BedrockProvider: ChatCompletionStream Request
    BedrockProvider->>DeploymentResolver: Resolve deployment
    DeploymentResolver-->>BedrockProvider: Anthropic? / Converse?

    alt Anthropic
        BedrockProvider->>AnthropicStream: Invoke invoke-with-response-stream
        loop For each event
            AnthropicStream->>ChunkProcessor: Deliver stream event
            ChunkProcessor->>ChunkProcessor: Parse & accumulate usage
            ChunkProcessor-->>BedrockProvider: Enriched chunk
            BedrockProvider-->>Client: Stream chunk
        end
    else Converse
        BedrockProvider->>ConverseStream: Invoke converse-stream
        loop For each event
            ConverseStream->>ChunkProcessor: Deliver stream event
            ChunkProcessor->>ChunkProcessor: Parse & accumulate usage
            ChunkProcessor-->>BedrockProvider: Enriched chunk
            BedrockProvider-->>Client: Stream chunk
        end
    end

    ChunkProcessor-->>Client: Finalization with metadata
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped through routes both old and new,

InvokeModel lanes and Converse paths too,
Helpers stitched neatly, streams now decide,
Deployments resolved — I munch code with pride! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: migrate Bedrock Claude models to native Anthropic Messages API' clearly and specifically summarizes the main change—migrating Bedrock's Claude model handling from Converse API to native Anthropic Messages API.
Description check ✅ Passed The PR description comprehensively covers all template sections including summary, detailed changes, type of change, affected areas, testing instructions, breaking changes, security considerations, and a completed checklist.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 03-05-feat_shifted_to_anthropic_endpoints_in_bedrock_for_claude_models

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

Copy link
Collaborator Author

Pratham-Mishra04 commented Mar 5, 2026

@akshaydeo akshaydeo marked this pull request as ready for review March 5, 2026 07:08
ImageEdit: true,
ImageVariation: true,
StructuredOutputs: true,
// BatchCreate: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this intentional @Pratham-Mishra04

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

no, it was supposed to be a draft PR mb

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
core/providers/bedrock/anthropic_compat.go (1)

83-85: Avoid mutating the incoming request object in-place.

This helper changes request.Model, which can leak side effects to callers that reuse/log the original request. Use a shallow copy before overriding model.

🛠️ Proposed fix
-	// Mutate the model before conversion so converters see the resolved deployment name
-	request.Model = deployment
-	reqBody, err := anthropic.ToAnthropicResponsesRequest(ctx, request)
+	// Use a copy to avoid mutating caller-owned request state
+	reqCopy := *request
+	reqCopy.Model = deployment
+	reqBody, err := anthropic.ToAnthropicResponsesRequest(ctx, &reqCopy)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/providers/bedrock/anthropic_compat.go` around lines 83 - 85, The code
currently mutates the incoming request by assigning request.Model = deployment
before calling anthropic.ToAnthropicResponsesRequest, which can leak side
effects; fix it by making a shallow copy of the request (e.g., copy := *request)
and set copy.Model = deployment, then pass the copied value (or its pointer)
into anthropic.ToAnthropicResponsesRequest so the original request remains
unchanged.
core/providers/bedrock/bedrock_test.go (1)

160-174: Prefer explicit scenario gating over commented-out test flags.

Commenting these fields out silently disables a large test surface. Please set them explicitly (e.g., based on s3Bucket/roleArn) so intent and coverage are clear.

♻️ Proposed cleanup
-			// BatchCreate:           true,
-			// BatchList:             true,
-			// BatchRetrieve:         true,
-			// BatchCancel:           true,
-			// BatchResults:          true,
-			// FileUpload:            true,
-			// FileList:              true,
-			// FileRetrieve:          true,
-			// FileDelete:            true,
-			// FileContent:           true,
-			// FileBatchInput:        true,
+			BatchCreate:           s3Bucket != "",
+			BatchList:             s3Bucket != "",
+			BatchRetrieve:         s3Bucket != "",
+			BatchCancel:           s3Bucket != "",
+			BatchResults:          s3Bucket != "",
+			FileUpload:            s3Bucket != "",
+			FileList:              s3Bucket != "",
+			FileRetrieve:          s3Bucket != "",
+			FileDelete:            s3Bucket != "",
+			FileContent:           s3Bucket != "",
+			FileBatchInput:        s3Bucket != "",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/providers/bedrock/bedrock_test.go` around lines 160 - 174, The test
flags in the Bedrock provider tests were left commented out (e.g., BatchCreate,
BatchList, FileUpload, etc.), silently disabling many scenarios; update the test
capability map where CountTokens, ImageEdit, ImageVariation, and
StructuredOutputs are defined to explicitly set all relevant flags instead of
commenting them out, using the existing environment checks (s3Bucket and
roleArn) to gate features—for example, set BatchCreate, BatchList,
BatchRetrieve, BatchCancel, BatchResults, FileUpload, FileList, FileRetrieve,
FileDelete, FileContent, and FileBatchInput to true only when s3Bucket/roleArn
indicate tests can run, and false otherwise so intent and coverage are explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/providers/anthropic/responses.go`:
- Around line 158-162: The exported ReleaseAnthropicResponsesStreamState wrapper
currently calls releaseAnthropicResponsesStreamState which returns the object to
the pool without fully zeroing fields (e.g., CreatedAt left set and maps
reinitialized rather than nil), so update releaseAnthropicResponsesStreamState
(the underlying release path used by ReleaseAnthropicResponsesStreamState and
any callers) to explicitly reset all AnthropicResponsesStreamState fields to
their zero values before calling pool.Put(): set time fields like CreatedAt to
zero value, set pointer/slice/map fields to nil (not reinitialize), and clear
any buffers; ensure any necessary reinitialization happens in the acquire path
(where New/AcquireAnthropicResponsesStreamState prepares maps/buffers) rather
than on release.

In `@core/providers/bedrock/anthropic_compat.go`:
- Around line 120-125: MergeExtraParams can reintroduce reserved fields like
"model" and "stream" back into requestBody; after calling
providerUtils.MergeExtraParams(requestBody, extraParams) inside the passthrough
branch, remove or re-sanitize those reserved keys (e.g. delete
requestBody["model"] and requestBody["stream"] or call the existing sanitization
helper if one exists) so Bedrock/Anthropic requests cannot be invalidated;
ensure the re-sanitization happens immediately after the MergeExtraParams call
in the same block that checks
ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams).

In `@core/providers/bedrock/bedrock.go`:
- Around line 1003-1004: The pooled Bedrock response objects are returned via
releaseBedrockChatResponse without clearing fields, causing stale-data leaks;
update releaseBedrockChatResponse to explicitly zero all fields of the object
referenced by bedrockResponse (and any nested structs/slices/maps) before
calling pool.Put(), and ensure all call sites (e.g., where
acquireBedrockChatResponse()/releaseBedrockChatResponse() are used at the shown
locations) continue to defer releaseBedrockChatResponse(bedrockResponse) after
using the response so the zeroing always runs.
- Around line 935-963: The routing logic currently calls
schemas.IsAnthropicModel(deployment) directly and can misclassify Anthropic
deployments when resolveBedrockDeployment returns an opaque alias/ARN; update
the Bedrock routing to compute a single isAnthropicRoute boolean (e.g. combine
schemas.IsAnthropicModel(deployment) with the existing model-based anthopic
check used elsewhere) right after resolveBedrockDeployment(request.Model, key)
and then use that isAnthropicRoute flag instead of calling
schemas.IsAnthropicModel(deployment) in the branches that set jsonData/path;
apply the same change in ChatCompletionStream, Responses, and ResponsesStream
(referencing resolveBedrockDeployment, schemas.IsAnthropicModel,
getBedrockAnthropicChatRequestBody, providerUtils.CheckContextAndGetRequestBody,
and provider.getModelPath) so anthopic/Claude traffic follows the invoke path
even when deployment is an alias.

---

Nitpick comments:
In `@core/providers/bedrock/anthropic_compat.go`:
- Around line 83-85: The code currently mutates the incoming request by
assigning request.Model = deployment before calling
anthropic.ToAnthropicResponsesRequest, which can leak side effects; fix it by
making a shallow copy of the request (e.g., copy := *request) and set copy.Model
= deployment, then pass the copied value (or its pointer) into
anthropic.ToAnthropicResponsesRequest so the original request remains unchanged.

In `@core/providers/bedrock/bedrock_test.go`:
- Around line 160-174: The test flags in the Bedrock provider tests were left
commented out (e.g., BatchCreate, BatchList, FileUpload, etc.), silently
disabling many scenarios; update the test capability map where CountTokens,
ImageEdit, ImageVariation, and StructuredOutputs are defined to explicitly set
all relevant flags instead of commenting them out, using the existing
environment checks (s3Bucket and roleArn) to gate features—for example, set
BatchCreate, BatchList, BatchRetrieve, BatchCancel, BatchResults, FileUpload,
FileList, FileRetrieve, FileDelete, FileContent, and FileBatchInput to true only
when s3Bucket/roleArn indicate tests can run, and false otherwise so intent and
coverage are explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 46be53e5-47e1-42c4-98e4-056fde89fb20

📥 Commits

Reviewing files that changed from the base of the PR and between 50e1b1e and 835a59c.

📒 Files selected for processing (7)
  • core/changelog.md
  • core/providers/anthropic/responses.go
  • core/providers/bedrock/anthropic_compat.go
  • core/providers/bedrock/bedrock.go
  • core/providers/bedrock/bedrock_test.go
  • core/providers/bedrock/types.go
  • transports/changelog.md

Comment on lines +158 to +162
// ReleaseAnthropicResponsesStreamState returns an Anthropic responses stream state to the pool.
// Exported for use by providers that wrap Anthropic-compatible endpoints (e.g. Bedrock).
func ReleaseAnthropicResponsesStreamState(state *AnthropicResponsesStreamState) {
releaseAnthropicResponsesStreamState(state)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Release wrapper now exposes a pool reset policy violation.

Line 161 delegates to a release path that does not reset all pooled fields to zero values before pool.Put() (for example, CreatedAt is set to current time and maps are reinitialized instead of zeroed). With this API exported, the risk footprint grows.

🔧 Suggested fix (zero on release, initialize on acquire)
func (state *AnthropicResponsesStreamState) flush() {
  state.ChunkIndex = nil
  state.AccumulatedJSON = ""
  state.ComputerToolID = nil
  state.WebSearchToolID = nil
  state.WebSearchOutputIndex = nil
  state.WebSearchResult = nil
- state.ContentIndexToOutputIndex = make(map[int]int)
- state.ContentIndexToBlockType = make(map[int]AnthropicContentBlockType)
- state.ToolArgumentBuffers = make(map[int]string)
- state.MCPCallOutputIndices = make(map[int]bool)
- state.ItemIDs = make(map[int]string)
- state.ReasoningSignatures = make(map[int]string)
- state.TextContentIndices = make(map[int]bool)
- state.ReasoningContentIndices = make(map[int]bool)
- state.CompactionContentIndices = make(map[int]*schemas.CacheControl)
+ state.ContentIndexToOutputIndex = nil
+ state.ContentIndexToBlockType = nil
+ state.ToolArgumentBuffers = nil
+ state.MCPCallOutputIndices = nil
+ state.ItemIDs = nil
+ state.ReasoningSignatures = nil
+ state.TextContentIndices = nil
+ state.ReasoningContentIndices = nil
+ state.CompactionContentIndices = nil
  state.CurrentOutputIndex = 0
  state.MessageID = nil
  state.StopReason = nil
  state.Model = nil
- state.CreatedAt = int(time.Now().Unix())
+ state.CreatedAt = 0
  state.HasEmittedCreated = false
  state.HasEmittedInProgress = false
  state.StructuredOutputToolName = ""
  state.StructuredOutputIndex = nil
}

As per coding guidelines "Always reset all fields of pooled objects to their zero values before calling pool.Put(). Stale data from previous requests can leak to the next user of the pooled object."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/providers/anthropic/responses.go` around lines 158 - 162, The exported
ReleaseAnthropicResponsesStreamState wrapper currently calls
releaseAnthropicResponsesStreamState which returns the object to the pool
without fully zeroing fields (e.g., CreatedAt left set and maps reinitialized
rather than nil), so update releaseAnthropicResponsesStreamState (the underlying
release path used by ReleaseAnthropicResponsesStreamState and any callers) to
explicitly reset all AnthropicResponsesStreamState fields to their zero values
before calling pool.Put(): set time fields like CreatedAt to zero value, set
pointer/slice/map fields to nil (not reinitialize), and clear any buffers;
ensure any necessary reinitialization happens in the acquire path (where
New/AcquireAnthropicResponsesStreamState prepares maps/buffers) rather than on
release.

Comment on lines +120 to +125
// Merge extra params if passthrough is enabled
if ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) != nil && ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) == true {
if len(extraParams) > 0 {
providerUtils.MergeExtraParams(requestBody, extraParams)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Re-sanitize reserved fields after passthrough merge.

MergeExtraParams runs after removing reserved keys, so model/stream can be reintroduced from extraParams. That can invalidate Bedrock Anthropic requests.

✅ Proposed fix
 	// Merge extra params if passthrough is enabled
 	if ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) != nil && ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) == true {
 		if len(extraParams) > 0 {
 			providerUtils.MergeExtraParams(requestBody, extraParams)
+			// Keep Bedrock Anthropic invariants intact after merge
+			delete(requestBody, "model")
+			delete(requestBody, "stream")
+			delete(requestBody, "fallbacks")
 		}
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Merge extra params if passthrough is enabled
if ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) != nil && ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) == true {
if len(extraParams) > 0 {
providerUtils.MergeExtraParams(requestBody, extraParams)
}
}
// Merge extra params if passthrough is enabled
if ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) != nil && ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) == true {
if len(extraParams) > 0 {
providerUtils.MergeExtraParams(requestBody, extraParams)
// Keep Bedrock Anthropic invariants intact after merge
delete(requestBody, "model")
delete(requestBody, "stream")
delete(requestBody, "fallbacks")
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/providers/bedrock/anthropic_compat.go` around lines 120 - 125,
MergeExtraParams can reintroduce reserved fields like "model" and "stream" back
into requestBody; after calling providerUtils.MergeExtraParams(requestBody,
extraParams) inside the passthrough branch, remove or re-sanitize those reserved
keys (e.g. delete requestBody["model"] and requestBody["stream"] or call the
existing sanitization helper if one exists) so Bedrock/Anthropic requests cannot
be invalidated; ensure the re-sanitization happens immediately after the
MergeExtraParams call in the same block that checks
ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams).

Comment on lines +1003 to +1004
bedrockResponse := acquireBedrockChatResponse()
defer releaseBedrockChatResponse(bedrockResponse)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Pooled Bedrock response reuse now needs zero-before-put enforcement.

These paths add more reliance on releaseBedrockChatResponse, but that helper currently puts objects back without zeroing first.

Suggested fix (in helper)
func releaseBedrockChatResponse(resp *BedrockConverseResponse) {
-	if resp != nil {
-		bedrockChatResponsePool.Put(resp)
-	}
+	if resp == nil {
+		return
+	}
+	*resp = BedrockConverseResponse{}
+	bedrockChatResponsePool.Put(resp)
}

As per coding guidelines **/*.go: "Always reset all fields of pooled objects to their zero values before calling pool.Put(). Stale data from previous requests can leak to the next user of the pooled object."

Also applies to: 1470-1471

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/providers/bedrock/bedrock.go` around lines 1003 - 1004, The pooled
Bedrock response objects are returned via releaseBedrockChatResponse without
clearing fields, causing stale-data leaks; update releaseBedrockChatResponse to
explicitly zero all fields of the object referenced by bedrockResponse (and any
nested structs/slices/maps) before calling pool.Put(), and ensure all call sites
(e.g., where acquireBedrockChatResponse()/releaseBedrockChatResponse() are used
at the shown locations) continue to defer
releaseBedrockChatResponse(bedrockResponse) after using the response so the
zeroing always runs.

@Pratham-Mishra04 Pratham-Mishra04 marked this pull request as draft March 5, 2026 07:53
@akshaydeo akshaydeo marked this pull request as ready for review March 5, 2026 08:34
@akshaydeo akshaydeo changed the base branch from 03-04-fix_async_jobs_stuck_in_processing_on_marshal_failure_now_correctly_transition_to_failed_ to graphite-base/1924 March 5, 2026 08:35
@akshaydeo akshaydeo force-pushed the graphite-base/1924 branch from 50e1b1e to bbf4084 Compare March 5, 2026 08:36
@akshaydeo akshaydeo force-pushed the 03-05-feat_shifted_to_anthropic_endpoints_in_bedrock_for_claude_models branch from 835a59c to ba3d437 Compare March 5, 2026 08:36
@graphite-app graphite-app bot changed the base branch from graphite-base/1924 to main March 5, 2026 08:36
@akshaydeo akshaydeo force-pushed the 03-05-feat_shifted_to_anthropic_endpoints_in_bedrock_for_claude_models branch from ba3d437 to 4139d6f Compare March 5, 2026 08:36
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
core/providers/bedrock/anthropic_compat.go (1)

120-125: ⚠️ Potential issue | 🟠 Major

Re-sanitize reserved fields after passthrough merge.

MergeExtraParams can reintroduce model/stream/fallbacks after they were stripped, which can invalidate Bedrock Anthropic InvokeModel payloads.

✅ Proposed fix
 	// Merge extra params if passthrough is enabled
 	if ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) != nil && ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) == true {
 		if len(extraParams) > 0 {
 			providerUtils.MergeExtraParams(requestBody, extraParams)
+			// Re-enforce Bedrock Anthropic invariants after merge
+			delete(requestBody, "model")
+			delete(requestBody, "stream")
+			delete(requestBody, "fallbacks")
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/providers/bedrock/anthropic_compat.go` around lines 120 - 125, After
merging passthrough extra params (when
ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) is true) re-sanitize
the requestBody to remove any reserved fields that MergeExtraParams may have
reintroduced (specifically "model", "stream", and "fallbacks"); locate the merge
block around MergeExtraParams(requestBody, extraParams) in anthropic_compat.go
and add logic after that call to explicitly delete or unset those keys from
requestBody so the Bedrock Anthropic InvokeModel payload remains valid.
core/providers/bedrock/bedrock.go (2)

941-942: ⚠️ Potential issue | 🟠 Major

Harden Anthropic routing when deployment mappings are aliases/ARN-like identifiers.

Routing only on schemas.IsAnthropicModel(deployment) can misclassify Anthropic traffic if deployment mapping is opaque. Use a unified predicate combining requested model + resolved deployment across all four flows.

✅ Suggested pattern
 	deployment := resolveBedrockDeployment(request.Model, key)
+	isAnthropicRoute := schemas.IsAnthropicModel(request.Model) || schemas.IsAnthropicModel(deployment)

-	if schemas.IsAnthropicModel(deployment) {
+	if isAnthropicRoute {
 		// Anthropic invoke path
 	} else {
 		// Converse path
 	}

Apply the same gate in ChatCompletion, ChatCompletionStream, Responses, and ResponsesStream.

Also applies to: 1063-1064, 1408-1409, 1522-1523

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/providers/bedrock/bedrock.go` around lines 941 - 942, The Anthropic
routing check is too fragile when deployment mappings are opaque; update each of
the four flows (ChatCompletion, ChatCompletionStream, Responses,
ResponsesStream) to use a unified predicate that checks both the requested model
and the resolved deployment identifier (e.g., replace existing
schemas.IsAnthropicModel(deployment) checks with something like
schemas.IsAnthropicModel(requestedModel) ||
schemas.IsAnthropicModel(resolvedDeployment)); locate the branches that
currently test schemas.IsAnthropicModel(deployment) (around the handlers for
ChatCompletion, ChatCompletionStream, Responses, ResponsesStream) and change
them to use the combined predicate so routing is correct for alias/ARN-like
deployment mappings.

1003-1004: ⚠️ Potential issue | 🟠 Major

Pooled Bedrock responses still need zero-before-put enforcement.

These call paths now rely more on releaseBedrockChatResponse, but that helper currently returns objects to the pool without clearing fields first.

✅ Proposed fix in helper
 func releaseBedrockChatResponse(resp *BedrockConverseResponse) {
-	if resp != nil {
-		bedrockChatResponsePool.Put(resp)
-	}
+	if resp == nil {
+		return
+	}
+	*resp = BedrockConverseResponse{}
+	bedrockChatResponsePool.Put(resp)
 }
As per coding guidelines `**/*.go`: "Always reset all fields of pooled objects to their zero values before calling pool.Put(). Stale data from previous requests can leak to the next user of the pooled object."

Also applies to: 1470-1471

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/providers/bedrock/bedrock.go` around lines 1003 - 1004, The pooled
Bedrock response helper releaseBedrockChatResponse currently returns objects to
the pool without clearing fields; update releaseBedrockChatResponse to
explicitly reset every field of the pooled response struct to its zero value
(strings to "", slices to nil/zero-length, maps to nil, pointers to nil, numeric
fields to 0, boolean to false) before calling pool.Put, and ensure any other
callers that return instances (e.g., paths using acquireBedrockChatResponse)
rely on this zero-before-put guarantee so no stale data can leak into subsequent
users.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/providers/bedrock/anthropic_compat.go`:
- Around line 83-85: The code mutates the caller-owned Responses request by
setting request.Model = deployment; instead avoid this side-effect by leaving
request unchanged and applying the resolved deployment to the converted
Anthropic request object returned by anthropic.ToAnthropicResponsesRequest(ctx,
request) (or by passing a shallow copy of request into the converter). Locate
the call site around anthropic.ToAnthropicResponsesRequest and ensure you either
pass a copy of request (so original ModelRequested is preserved) or set the
deployment on the resulting reqBody (e.g., reqBody.Model = deployment) rather
than mutating the original request.

---

Duplicate comments:
In `@core/providers/bedrock/anthropic_compat.go`:
- Around line 120-125: After merging passthrough extra params (when
ctx.Value(schemas.BifrostContextKeyPassthroughExtraParams) is true) re-sanitize
the requestBody to remove any reserved fields that MergeExtraParams may have
reintroduced (specifically "model", "stream", and "fallbacks"); locate the merge
block around MergeExtraParams(requestBody, extraParams) in anthropic_compat.go
and add logic after that call to explicitly delete or unset those keys from
requestBody so the Bedrock Anthropic InvokeModel payload remains valid.

In `@core/providers/bedrock/bedrock.go`:
- Around line 941-942: The Anthropic routing check is too fragile when
deployment mappings are opaque; update each of the four flows (ChatCompletion,
ChatCompletionStream, Responses, ResponsesStream) to use a unified predicate
that checks both the requested model and the resolved deployment identifier
(e.g., replace existing schemas.IsAnthropicModel(deployment) checks with
something like schemas.IsAnthropicModel(requestedModel) ||
schemas.IsAnthropicModel(resolvedDeployment)); locate the branches that
currently test schemas.IsAnthropicModel(deployment) (around the handlers for
ChatCompletion, ChatCompletionStream, Responses, ResponsesStream) and change
them to use the combined predicate so routing is correct for alias/ARN-like
deployment mappings.
- Around line 1003-1004: The pooled Bedrock response helper
releaseBedrockChatResponse currently returns objects to the pool without
clearing fields; update releaseBedrockChatResponse to explicitly reset every
field of the pooled response struct to its zero value (strings to "", slices to
nil/zero-length, maps to nil, pointers to nil, numeric fields to 0, boolean to
false) before calling pool.Put, and ensure any other callers that return
instances (e.g., paths using acquireBedrockChatResponse) rely on this
zero-before-put guarantee so no stale data can leak into subsequent users.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e965c2c5-94e8-4ba4-871b-d536f842dff7

📥 Commits

Reviewing files that changed from the base of the PR and between 835a59c and 4139d6f.

📒 Files selected for processing (7)
  • core/changelog.md
  • core/providers/anthropic/responses.go
  • core/providers/bedrock/anthropic_compat.go
  • core/providers/bedrock/bedrock.go
  • core/providers/bedrock/bedrock_test.go
  • core/providers/bedrock/types.go
  • transports/changelog.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • core/providers/anthropic/responses.go
  • core/providers/bedrock/bedrock_test.go
  • core/changelog.md
  • transports/changelog.md

Comment on lines +83 to +85
// Mutate the model before conversion so converters see the resolved deployment name
request.Model = deployment
reqBody, err := anthropic.ToAnthropicResponsesRequest(ctx, request)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid mutating the inbound Responses request model.

request.Model = deployment introduces side effects on the caller-owned object and can corrupt ModelRequested metadata later in the request flow. Set the deployment on the converted Anthropic request body instead.

✅ Proposed fix
-	// Mutate the model before conversion so converters see the resolved deployment name
-	request.Model = deployment
 	reqBody, err := anthropic.ToAnthropicResponsesRequest(ctx, request)
 	if err != nil {
 		return nil, providerUtils.NewBifrostOperationError(schemas.ErrRequestBodyConversion, err, providerName)
 	}
 	if reqBody == nil {
 		return nil, providerUtils.NewBifrostOperationError("request body is not provided", nil, providerName)
 	}
+	reqBody.Model = deployment
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Mutate the model before conversion so converters see the resolved deployment name
request.Model = deployment
reqBody, err := anthropic.ToAnthropicResponsesRequest(ctx, request)
reqBody, err := anthropic.ToAnthropicResponsesRequest(ctx, request)
if err != nil {
return nil, providerUtils.NewBifrostOperationError(schemas.ErrRequestBodyConversion, err, providerName)
}
if reqBody == nil {
return nil, providerUtils.NewBifrostOperationError("request body is not provided", nil, providerName)
}
reqBody.Model = deployment
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/providers/bedrock/anthropic_compat.go` around lines 83 - 85, The code
mutates the caller-owned Responses request by setting request.Model =
deployment; instead avoid this side-effect by leaving request unchanged and
applying the resolved deployment to the converted Anthropic request object
returned by anthropic.ToAnthropicResponsesRequest(ctx, request) (or by passing a
shallow copy of request into the converter). Locate the call site around
anthropic.ToAnthropicResponsesRequest and ensure you either pass a copy of
request (so original ModelRequested is preserved) or set the deployment on the
resulting reqBody (e.g., reqBody.Model = deployment) rather than mutating the
original request.

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.

2 participants