Skip to content

fix: bedrock stop reason - #3506

Merged
akshaydeo merged 1 commit into
devfrom
05-14-fix_bedrock_stop_reason
May 15, 2026
Merged

fix: bedrock stop reason#3506
akshaydeo merged 1 commit into
devfrom
05-14-fix_bedrock_stop_reason

Conversation

@TejasGhatte

@TejasGhatte TejasGhatte commented May 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Stop reason normalization was inconsistent across the Bedrock and Anthropic providers. Unknown or unmappable stop reasons (e.g. guardrail_intervened) were silently coerced to "stop", and the Responses API path for Bedrock was not applying any stop reason conversion at all. This PR fixes both issues and adds a proper reverse mapping for converting Bifrost stop reasons back to Bedrock format.

Changes

  • guardrail_intervened no longer maps to content_filter — it passes through as-is since there is no clean semantic equivalent in the Bifrost format.
  • Unknown stop reasons now pass through unchanged instead of defaulting to "stop".
  • Added convertBifrostToBedrockStopReason and a bifrostToBedrockStopReason reverse lookup map to support converting Bifrost stop reasons back to Bedrock format.
  • BedrockConverseResponse.ToBifrostResponsesResponse now applies stop reason conversion via convertBedrockStopReason, which was previously missing.
  • ToBedrockConverseResponse now prioritizes StopReason over IncompleteDetails when deriving the Bedrock stop reason.
  • AnthropicMessageResponse.ToBifrostResponsesResponse now uses ConvertAnthropicFinishReasonToBifrost instead of passing the raw Anthropic stop reason string through.
  • Added TestBedrockStopReasonMappingResponsesPath and TestBifrostToBedrockStopReasonReverseMapping to cover the Responses API path and reverse mapping behavior.

Type of change

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

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./core/providers/bedrock/... ./core/providers/anthropic/...

Expected: all existing and new tests pass, including TestBedrockStopReasonMapping, TestBedrockStopReasonMappingResponsesPath, and TestBifrostToBedrockStopReasonReverseMapping.

Breaking changes

  • Yes
  • No

guardrail_intervened previously mapped to content_filter in Bedrock stop reason normalization. It now passes through as guardrail_intervened. Consumers relying on the old mapping will need to handle this value explicitly.

Related issues

Security considerations

None.

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

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


tejas ghatte seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 91346463-c301-4dcf-8964-c0ac7450783a

📥 Commits

Reviewing files that changed from the base of the PR and between f4bd3f6 and f231f09.

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

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved stop-reason mapping across AI providers (Anthropic and Bedrock) for more accurate termination reporting.
    • Preserve unknown pass-through reasons and correct guardrail/content-filter normalization; explicit stop-reasons now take priority when present.
  • Tests

    • Added and expanded test coverage for stop-reason normalization and reverse-conversion scenarios.

Walkthrough

Stop-reason handling was unified: Bedrock and Anthropic providers now convert known finish reasons via explicit mapping functions, unmapped reasons pass through unchanged, and tests were added/updated to verify forward and reverse mappings and precedence rules.

Changes

Stop-Reason Conversion Unification

Layer / File(s) Summary
Bedrock stop-reason conversion utilities
core/providers/bedrock/utils.go
bedrockFinishReasonToBifrost mapping table updated to omit guardrail_intervenedcontent_filter; added bifrostToBedrockStopReason reverse map; unmapped reasons now passthrough instead of defaulting to "stop".
Bedrock response handlers
core/providers/bedrock/responses.go
Stream and Converse conversions delegate stop-reason mapping to convertBedrockStopReason; ToBedrockConverseResponse now prefers bifrostResp.StopReason (converted) over IncompleteDetails.Reason, then tool_use, then end_turn.
Anthropic response conversion
core/providers/anthropic/responses.go
ToBifrostResponsesResponse sets bifrostResp.StopReason via ConvertAnthropicFinishReasonToBifrost(response.StopReason) instead of raw string casting.
Stop-reason conversion tests
core/providers/bedrock/bedrock_test.go
Updated TestBedrockStopReasonMapping expectations; added TestBedrockStopReasonMappingResponsesPath and TestBifrostToBedrockStopReasonReverseMapping to cover Responses-path mapping, reverse mapping, and precedence/passthrough behaviors.

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers:

  • akshaydeo

"I hopped through mappings, neat and spry,
Unknown reasons pass on by,
Bedrock, Anthropic—both in tune,
Tests now sing a steady tune,
A rabbit's cheer for refactor boon!" 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: bedrock stop reason' is concise and clearly identifies the primary change—a bug fix addressing Bedrock stop reason handling inconsistencies.
Description check ✅ Passed The description comprehensively covers all template sections with clear explanations of the problem, changes made, affected areas, testing instructions, and breaking changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 05-14-fix_bedrock_stop_reason

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"


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

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@TejasGhatte
TejasGhatte marked this pull request as ready for review May 14, 2026 14:26
@greptile-apps

greptile-apps Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

Safe to merge — all changes are narrowly scoped stop reason normalization fixes with good test coverage on the main paths.

The logic is straightforward and correct: the forward and reverse lookup maps are consistent, the previously missing conversion in ToBifrostResponsesResponse is now present, and the Anthropic path is aligned with every other path in the codebase. The one gap is that the streaming path implicitly picks up two additional mappings (stop_sequence and content_filtered) with no dedicated test, but the behavior is correct and the risk of regression is low.

core/providers/bedrock/responses.go — specifically the ToBifrostResponsesStream streaming path, which gained two additional stop reason conversions without test coverage.

Important Files Changed

Filename Overview
core/providers/bedrock/utils.go Adds bifrostToBedrockStopReason reverse map and convertBifrostToBedrockStopReason helper; removes guardrail_intervened from forward map; unknown reasons now pass through instead of defaulting to "stop"
core/providers/bedrock/responses.go Fixes missing stop reason conversion in ToBifrostResponsesResponse; promotes StopReason over IncompleteDetails in ToBedrockConverseResponse; refactors streaming inline switch to use convertBedrockStopReason (adds stop_sequence→stop and content_filtered→content_filter conversions in streaming path, untested)
core/providers/anthropic/responses.go ToBifrostResponsesResponse now uses ConvertAnthropicFinishReasonToBifrost instead of raw string passthrough — aligns with the existing streaming and chat paths
core/providers/bedrock/bedrock_test.go Updates existing guardrail_intervened and unknown-reason test expectations; adds TestBedrockStopReasonMappingResponsesPath (non-streaming Responses path) and TestBifrostToBedrockStopReasonReverseMapping tests

Reviews (2): Last reviewed commit: "fix: bedrock stop reason" | Re-trigger Greptile

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 14, 2026
@akshaydeo
akshaydeo dismissed coderabbitai[bot]’s stale review May 15, 2026 05:59

The merge-base changed after approval.

@akshaydeo
akshaydeo requested a review from a team as a code owner May 15, 2026 05:59
@TejasGhatte
TejasGhatte force-pushed the 05-14-fix_bedrock_stop_reason branch from f4bd3f6 to f231f09 Compare May 15, 2026 10:01
@coderabbitai
coderabbitai Bot requested a review from akshaydeo May 15, 2026 10:03

akshaydeo commented May 15, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • May 15, 2:03 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 15, 2:04 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit d9a76a3 into dev May 15, 2026
15 of 16 checks passed
@akshaydeo
akshaydeo deleted the 05-14-fix_bedrock_stop_reason branch May 15, 2026 14:04
akshaydeo pushed a commit that referenced this pull request May 15, 2026
## Summary

Stop reason normalization was inconsistent across the Bedrock and Anthropic providers. Unknown or unmappable stop reasons (e.g. `guardrail_intervened`) were silently coerced to `"stop"`, and the Responses API path for Bedrock was not applying any stop reason conversion at all. This PR fixes both issues and adds a proper reverse mapping for converting Bifrost stop reasons back to Bedrock format.

## Changes

- `guardrail_intervened` no longer maps to `content_filter` — it passes through as-is since there is no clean semantic equivalent in the Bifrost format.
- Unknown stop reasons now pass through unchanged instead of defaulting to `"stop"`.
- Added `convertBifrostToBedrockStopReason` and a `bifrostToBedrockStopReason` reverse lookup map to support converting Bifrost stop reasons back to Bedrock format.
- `BedrockConverseResponse.ToBifrostResponsesResponse` now applies stop reason conversion via `convertBedrockStopReason`, which was previously missing.
- `ToBedrockConverseResponse` now prioritizes `StopReason` over `IncompleteDetails` when deriving the Bedrock stop reason.
- `AnthropicMessageResponse.ToBifrostResponsesResponse` now uses `ConvertAnthropicFinishReasonToBifrost` instead of passing the raw Anthropic stop reason string through.
- Added `TestBedrockStopReasonMappingResponsesPath` and `TestBifrostToBedrockStopReasonReverseMapping` to cover the Responses API path and reverse mapping behavior.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./core/providers/bedrock/... ./core/providers/anthropic/...
```

Expected: all existing and new tests pass, including `TestBedrockStopReasonMapping`, `TestBedrockStopReasonMappingResponsesPath`, and `TestBifrostToBedrockStopReasonReverseMapping`.

## Breaking changes

- [x] Yes
- [ ] No

`guardrail_intervened` previously mapped to `content_filter` in Bedrock stop reason normalization. It now passes through as `guardrail_intervened`. Consumers relying on the old mapping will need to handle this value explicitly.

## Related issues

## Security considerations

None.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
akshaydeo pushed a commit that referenced this pull request May 20, 2026
## Summary

Stop reason normalization was inconsistent across the Bedrock and Anthropic providers. Unknown or unmappable stop reasons (e.g. `guardrail_intervened`) were silently coerced to `"stop"`, and the Responses API path for Bedrock was not applying any stop reason conversion at all. This PR fixes both issues and adds a proper reverse mapping for converting Bifrost stop reasons back to Bedrock format.

## Changes

- `guardrail_intervened` no longer maps to `content_filter` — it passes through as-is since there is no clean semantic equivalent in the Bifrost format.
- Unknown stop reasons now pass through unchanged instead of defaulting to `"stop"`.
- Added `convertBifrostToBedrockStopReason` and a `bifrostToBedrockStopReason` reverse lookup map to support converting Bifrost stop reasons back to Bedrock format.
- `BedrockConverseResponse.ToBifrostResponsesResponse` now applies stop reason conversion via `convertBedrockStopReason`, which was previously missing.
- `ToBedrockConverseResponse` now prioritizes `StopReason` over `IncompleteDetails` when deriving the Bedrock stop reason.
- `AnthropicMessageResponse.ToBifrostResponsesResponse` now uses `ConvertAnthropicFinishReasonToBifrost` instead of passing the raw Anthropic stop reason string through.
- Added `TestBedrockStopReasonMappingResponsesPath` and `TestBifrostToBedrockStopReasonReverseMapping` to cover the Responses API path and reverse mapping behavior.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./core/providers/bedrock/... ./core/providers/anthropic/...
```

Expected: all existing and new tests pass, including `TestBedrockStopReasonMapping`, `TestBedrockStopReasonMappingResponsesPath`, and `TestBifrostToBedrockStopReasonReverseMapping`.

## Breaking changes

- [x] Yes
- [ ] No

`guardrail_intervened` previously mapped to `content_filter` in Bedrock stop reason normalization. It now passes through as `guardrail_intervened`. Consumers relying on the old mapping will need to handle this value explicitly.

## Related issues

## Security considerations

None.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
@akshaydeo akshaydeo mentioned this pull request May 20, 2026
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.

3 participants