diff --git a/chatlas/_provider_bedrock.py b/chatlas/_provider_bedrock.py index 12fdd603..5436df5b 100644 --- a/chatlas/_provider_bedrock.py +++ b/chatlas/_provider_bedrock.py @@ -109,7 +109,8 @@ def ChatBedrock( base_url Override the endpoint URL. The default is the standard endpoint for the selected `api` and your region, honoring the official AWS SDKs' - endpoint override environment variables: + endpoint override environment variables (a service-specific variable + outranks the generic `AWS_ENDPOINT_URL`): `AWS_ENDPOINT_URL_BEDROCK_RUNTIME` for `"converse"`, and `AWS_ENDPOINT_URL_BEDROCK_MANTLE` for `"messages"` and `"responses"` (which append their API-specific path to the override). For the @@ -464,17 +465,23 @@ def aws_endpoint_url(var: str, default: str) -> str: def bedrock_base_url(api: BedrockAPI, region: str) -> str: - # Match the official AWS SDKs, which read service-specific endpoint - # overrides: AWS_ENDPOINT_URL_BEDROCK_RUNTIME for the runtime (converse) - # service and AWS_ENDPOINT_URL_BEDROCK_MANTLE for mantle. + # Match the official AWS SDKs' endpoint resolution precedence: the + # service-specific override (AWS_ENDPOINT_URL_BEDROCK_RUNTIME for the + # runtime (converse) service, AWS_ENDPOINT_URL_BEDROCK_MANTLE for mantle) + # outranks the generic AWS_ENDPOINT_URL, which outranks the regional + # endpoint computed from `region`. if api == "converse": return aws_endpoint_url( "AWS_ENDPOINT_URL_BEDROCK_RUNTIME", - f"https://bedrock-runtime.{region}.amazonaws.com", + aws_endpoint_url( + "AWS_ENDPOINT_URL", + f"https://bedrock-runtime.{region}.amazonaws.com", + ), ) host = aws_endpoint_url( - "AWS_ENDPOINT_URL_BEDROCK_MANTLE", MANTLE_HOST.format(region=region) + "AWS_ENDPOINT_URL_BEDROCK_MANTLE", + aws_endpoint_url("AWS_ENDPOINT_URL", MANTLE_HOST.format(region=region)), ) if api == "messages": # The Anthropic SDK appends "/v1/messages" itself, so the "/v1" is diff --git a/tests/test_provider_bedrock_mantle.py b/tests/test_provider_bedrock_mantle.py index 63545ded..b006f462 100644 --- a/tests/test_provider_bedrock_mantle.py +++ b/tests/test_provider_bedrock_mantle.py @@ -103,6 +103,25 @@ def test_converse_uses_the_runtime_endpoint(self): "https://bedrock-runtime.us-west-2.amazonaws.com" ) + def test_generic_endpoint_url_applies_to_converse(self, monkeypatch): + monkeypatch.delenv("AWS_ENDPOINT_URL_BEDROCK_RUNTIME", raising=False) + monkeypatch.setenv("AWS_ENDPOINT_URL", "https://proxy.example") + assert bedrock_base_url("converse", "us-west-2") == "https://proxy.example" + + def test_generic_endpoint_url_applies_to_mantle(self, monkeypatch): + monkeypatch.delenv("AWS_ENDPOINT_URL_BEDROCK_MANTLE", raising=False) + monkeypatch.setenv("AWS_ENDPOINT_URL", "https://proxy.example") + assert bedrock_base_url("messages", "us-west-2") == ( + "https://proxy.example/anthropic" + ) + + def test_service_specific_var_outranks_generic(self, monkeypatch): + monkeypatch.setenv("AWS_ENDPOINT_URL", "https://generic.example") + monkeypatch.setenv( + "AWS_ENDPOINT_URL_BEDROCK_RUNTIME", "https://specific.example" + ) + assert bedrock_base_url("converse", "us-west-2") == "https://specific.example" + class TestChatBedrockDispatch: def test_responses_model_builds_an_openai_backed_provider(self):