Skip to content

Use region from boto3 session when possible #299

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

Merged
merged 3 commits into from
Jun 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions src/strands/models/bedrock.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
logger = logging.getLogger(__name__)

DEFAULT_BEDROCK_MODEL_ID = "us.anthropic.claude-3-7-sonnet-20250219-v1:0"
DEFAULT_BEDROCK_REGION = "us-west-2"

BEDROCK_CONTEXT_WINDOW_OVERFLOW_MESSAGES = [
"Input is too long for requested model",
Expand Down Expand Up @@ -117,18 +118,7 @@ def __init__(

logger.debug("config=<%s> | initializing", self.config)

region_for_boto = region_name or os.getenv("AWS_REGION")
if region_for_boto is None:
region_for_boto = "us-west-2"
logger.warning("defaulted to us-west-2 because no region was specified")
logger.warning(
"issue=<%s> | this behavior will change in an upcoming release",
"https://github.com/strands-agents/sdk-python/issues/238",
)

session = boto_session or boto3.Session(
region_name=region_for_boto,
)
session = boto_session or boto3.Session()

# Add strands-agents to the request user agent
if boto_client_config:
Expand All @@ -144,11 +134,16 @@ def __init__(
else:
client_config = BotocoreConfig(user_agent_extra="strands-agents")

resolved_region = region_name or session.region_name or os.environ.get("AWS_REGION") or DEFAULT_BEDROCK_REGION

self.client = session.client(
service_name="bedrock-runtime",
config=client_config,
region_name=resolved_region,
)

logger.debug("region=<%s> | bedrock client created", self.client.meta.region_name)

@override
def update_config(self, **model_config: Unpack[BedrockConfig]) -> None: # type: ignore
"""Update the Bedrock Model configuration with the provided arguments.
Expand Down
97 changes: 64 additions & 33 deletions tests/strands/models/test_bedrock.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import sys
import unittest.mock
from unittest.mock import ANY

import boto3
import pydantic
Expand All @@ -10,17 +11,30 @@

import strands
from strands.models import BedrockModel
from strands.models.bedrock import DEFAULT_BEDROCK_MODEL_ID
from strands.models.bedrock import DEFAULT_BEDROCK_MODEL_ID, DEFAULT_BEDROCK_REGION
from strands.types.exceptions import ModelThrottledException


@pytest.fixture
def bedrock_client():
def session_cls():
# Mock the creation of a Session so that we don't depend on environment variables or profiles
with unittest.mock.patch.object(strands.models.bedrock.boto3, "Session") as mock_session_cls:
mock_client = mock_session_cls.return_value.client.return_value
mock_client.meta = unittest.mock.MagicMock()
mock_client.meta.region_name = "us-west-2"
yield mock_client
mock_session_cls.return_value.region_name = None
yield mock_session_cls


@pytest.fixture
def mock_client_method(session_cls):
# the boto3.Session().client(...) method
return session_cls.return_value.client


@pytest.fixture
def bedrock_client(session_cls):
mock_client = session_cls.return_value.client.return_value
mock_client.meta = unittest.mock.MagicMock()
mock_client.meta.region_name = "us-west-2"
yield mock_client


@pytest.fixture
Expand Down Expand Up @@ -105,41 +119,58 @@ def test__init__default_model_id(bedrock_client):
assert tru_model_id == exp_model_id


def test__init__with_default_region(bedrock_client):
def test__init__with_default_region(session_cls, mock_client_method):
"""Test that BedrockModel uses the provided region."""
_ = bedrock_client
default_region = "us-west-2"
BedrockModel()

with unittest.mock.patch("strands.models.bedrock.boto3.Session") as mock_session_cls:
with unittest.mock.patch("strands.models.bedrock.logger.warning") as mock_warning:
_ = BedrockModel()
mock_session_cls.assert_called_once_with(region_name=default_region)
# Assert that warning logs are emitted
mock_warning.assert_any_call("defaulted to us-west-2 because no region was specified")
mock_warning.assert_any_call(
"issue=<%s> | this behavior will change in an upcoming release",
"https://github.com/strands-agents/sdk-python/issues/238",
)


def test__init__with_custom_region(bedrock_client):
session_cls.return_value.client.assert_called_with(region_name=DEFAULT_BEDROCK_REGION, config=ANY, service_name=ANY)


def test__init__with_session_region(session_cls, mock_client_method):
"""Test that BedrockModel uses the provided region."""
_ = bedrock_client
custom_region = "us-east-1"
session_cls.return_value.region_name = "eu-blah-1"

with unittest.mock.patch("strands.models.bedrock.boto3.Session") as mock_session_cls:
_ = BedrockModel(region_name=custom_region)
mock_session_cls.assert_called_once_with(region_name=custom_region)
BedrockModel()

mock_client_method.assert_called_with(region_name="eu-blah-1", config=ANY, service_name=ANY)

def test__init__with_environment_variable_region(bedrock_client):

def test__init__with_custom_region(mock_client_method):
"""Test that BedrockModel uses the provided region."""
_ = bedrock_client
os.environ["AWS_REGION"] = "eu-west-1"
custom_region = "us-east-1"
BedrockModel(region_name=custom_region)
mock_client_method.assert_called_with(region_name=custom_region, config=ANY, service_name=ANY)

with unittest.mock.patch("strands.models.bedrock.boto3.Session") as mock_session_cls:
_ = BedrockModel()
mock_session_cls.assert_called_once_with(region_name="eu-west-1")

def test__init__with_default_environment_variable_region(mock_client_method):
"""Test that BedrockModel uses the AWS_REGION since we code that in."""
with unittest.mock.patch.object(os, "environ", {"AWS_REGION": "eu-west-2"}):
BedrockModel()

mock_client_method.assert_called_with(region_name="eu-west-2", config=ANY, service_name=ANY)


def test__init__region_precedence(mock_client_method, session_cls):
"""Test that BedrockModel uses the correct ordering of precedence when determining region."""
with unittest.mock.patch.object(os, "environ", {"AWS_REGION": "us-environment-1"}):
session_cls.return_value.region_name = "us-session-1"

# specifying a region always wins out
BedrockModel(region_name="us-specified-1")
mock_client_method.assert_called_with(region_name="us-specified-1", config=ANY, service_name=ANY)

# other-wise uses the session's
BedrockModel()
mock_client_method.assert_called_with(region_name="us-session-1", config=ANY, service_name=ANY)

# environment variable next
session_cls.return_value.region_name = None
BedrockModel()
mock_client_method.assert_called_with(region_name="us-environment-1", config=ANY, service_name=ANY)

# Finally default
BedrockModel()
mock_client_method.assert_called_with(region_name=DEFAULT_BEDROCK_REGION, config=ANY, service_name=ANY)


def test__init__with_region_and_session_raises_value_error():
Expand Down