-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix: support us-gov. and other multi-character Bedrock geo prefixes #3645
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: support us-gov. and other multi-character Bedrock geo prefixes #3645
Conversation
The BedrockProvider.model_profile method previously only handled 2-character regional prefixes (e.g., 'us.', 'eu.'), causing issues with models using longer prefixes like 'us-gov.' (AWS GovCloud) and 'global.'. This caused extended thinking to fail in multi-turn conversations because bedrock_send_back_thinking_parts stayed at its default False value for these models. ThinkingPart blocks from previous turns were converted to text blocks instead of reasoningContent, causing Bedrock to reject requests with: 'Expected thinking or redacted_thinking, but found text' Changes: - Add _strip_geo_prefix() helper function to properly handle all known geo prefixes including us-gov. and global. - Update _AWS_BEDROCK_INFERENCE_GEO_PREFIXES to include us-gov. - Add comprehensive tests for all geo prefixes Fixes cross-region inference for AWS GovCloud environments.
|
|
||
|
|
||
| # Known geo prefixes for cross-region inference profile IDs | ||
| _BEDROCK_GEO_PREFIXES: tuple[str, ...] = ('us.', 'eu.', 'apac.', 'jp.', 'au.', 'ca.', 'global.', 'us-gov.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think at some point it might be worth unifying this and the other private constant in models/bedrock.py
But this just extends it to support govcloud and global. Its been a real issue since Claude 4.5 came out and AWS doing cross-region inferencing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should definitely not duplicate it, since we're already importing the BedrockModelProfile in models/bedrock.py we should make this public and import it there.
| from pydantic_ai.providers.bedrock import BedrockModelProfile |
@DouweM do you agree?
dsfaccini
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you for the PR @Leundai ! I've requested a couple changes, let me know if you have any questions.
|
|
||
|
|
||
| # Known geo prefixes for cross-region inference profile IDs | ||
| _BEDROCK_GEO_PREFIXES: tuple[str, ...] = ('us.', 'eu.', 'apac.', 'jp.', 'au.', 'ca.', 'global.', 'us-gov.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should definitely not duplicate it, since we're already importing the BedrockModelProfile in models/bedrock.py we should make this public and import it there.
| from pydantic_ai.providers.bedrock import BedrockModelProfile |
@DouweM do you agree?
| # Handle regional prefixes (e.g. "us.") | ||
| if len(parts) > 2 and len(parts[0]) == 2: | ||
| parts = parts[1:] | ||
| # Strip regional/geo prefix if present (e.g. "us.", "eu.", "us-gov.", "global.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can remove this comment
| assert unknown_model is None | ||
|
|
||
|
|
||
| @pytest.mark.parametrize('prefix', ['us.', 'eu.', 'apac.', 'jp.', 'au.', 'ca.', 'global.', 'us-gov.']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we use the BEDROCK_GEO_PREFIXES you defined above here?
| assert isinstance(profile, BedrockModelProfile) | ||
| assert profile.bedrock_supports_tool_choice is True | ||
| assert profile.bedrock_send_back_thinking_parts is True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if these don't vary across models we don't need to test them, right? the test just tests that all prefixes are hadnled properly
| def test_bedrock_provider_model_profile_us_gov_anthropic(env: TestEnv, mocker: MockerFixture): | ||
| """Test that us-gov. prefixed Anthropic models get the correct profile. | ||
| This specifically tests the us-gov. prefix which was previously broken | ||
| because the provider only handled 2-character prefixes. | ||
| """ | ||
| env.set('AWS_DEFAULT_REGION', 'us-east-1') | ||
| provider = BedrockProvider() | ||
|
|
||
| ns = 'pydantic_ai.providers.bedrock' | ||
| anthropic_model_profile_mock = mocker.patch(f'{ns}.anthropic_model_profile', wraps=anthropic_model_profile) | ||
|
|
||
| # Test us-gov. prefix (AWS GovCloud cross-region inference) | ||
| profile = provider.model_profile('us-gov.anthropic.claude-sonnet-4-5-20250929-v1:0') | ||
| anthropic_model_profile_mock.assert_called_with('claude-sonnet-4-5-20250929') | ||
| assert isinstance(profile, BedrockModelProfile) | ||
| assert profile.bedrock_supports_tool_choice is True | ||
| assert profile.bedrock_send_back_thinking_parts is True | ||
|
|
||
| # Test global. prefix | ||
| profile = provider.model_profile('global.anthropic.claude-opus-4-5-20251101-v1:0') | ||
| anthropic_model_profile_mock.assert_called_with('claude-opus-4-5-20251101') | ||
| assert isinstance(profile, BedrockModelProfile) | ||
| assert profile.bedrock_supports_tool_choice is True | ||
| assert profile.bedrock_send_back_thinking_parts is True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we're already testing this above, aren't we?
let's add a test to check that we don't have any bedrock shorthand in KnownModelName with a geo prefix that we haven't added in the BEDROCK_GEO_PREFIXES
Summary
The
BedrockProvider.model_profilemethod previously only handled 2-character regional prefixes (e.g.,us.,eu.), causing issues with models using longer prefixes likeus-gov.(AWS GovCloud) andglobal..Problem
When using extended thinking with
us-gov.anthropic.*models via Bedrock, themodel_profilemethod doesn't recognize theus-gov.prefix because it only strips 2-character prefixes:This causes
bedrock_send_back_thinking_partsto stay at its defaultFalsevalue. As a result,ThinkingPartblocks from previous conversation turns are converted to text blocks with thinking tags instead ofreasoningContent, causing Bedrock to reject the request with:Solution
_strip_geo_prefix()helper function that properly handles all known geo prefixes includingus-gov.andglobal._AWS_BEDROCK_INFERENCE_GEO_PREFIXESconstant to includeus-gov.(the comment in the code already suggested this)Affected Models
us-gov.anthropic.claude-sonnet-4-5-20250929-v1:0us-gov.anthropic.claude-3-7-sonnet-20250219-v1:0global.anthropic.claude-opus-4-5-20251101-v1:0Testing
All existing tests pass, plus new parametrized tests for all geo prefixes