diff --git a/litellm/llms/bedrock/chat/invoke_transformations/amazon_openai_transformation.py b/litellm/llms/bedrock/chat/invoke_transformations/amazon_openai_transformation.py index f1e1f3e8738..bb87f11b47a 100644 --- a/litellm/llms/bedrock/chat/invoke_transformations/amazon_openai_transformation.py +++ b/litellm/llms/bedrock/chat/invoke_transformations/amazon_openai_transformation.py @@ -82,7 +82,12 @@ class AmazonBedrockOpenAIConfig(OpenAIGPTConfig, BaseAWSLLM): Uses the standard Bedrock invoke endpoint format. """ - model_id = self._get_openai_model_id(model) + model_id = optional_params.pop("model_id", None) or litellm_params.get("model_id") + if model_id is not None: + model_id = CommonUtils.encode_bedrock_runtime_modelid_arn(str(model_id)) + else: + model_id = self._get_openai_model_id(model) + model_id = CommonUtils.encode_bedrock_runtime_modelid_arn(model_id) # Get AWS region aws_region_name: Final = self._get_aws_region_name(optional_params=optional_params, model=model) @@ -95,8 +100,7 @@ class AmazonBedrockOpenAIConfig(OpenAIGPTConfig, BaseAWSLLM): aws_region_name=aws_region_name, ) - # Encode model ID for ARNs (e.g., :imported-model/ -> :imported-model%2F) - model_id = CommonUtils.encode_bedrock_runtime_modelid_arn(model_id) + # Model ID is already encoded above invoke_route: Final = "invoke-with-response-stream" if stream else "invoke" return join_api_base(endpoint_url, f"model/{model_id}/{invoke_route}") @@ -141,8 +145,9 @@ class AmazonBedrockOpenAIConfig(OpenAIGPTConfig, BaseAWSLLM): Removes AWS-specific params and stream param (handled separately in URL), then delegates to parent class for standard OpenAI request transformation. """ - # Remove stream from optional_params as it's handled separately in URL + # Remove stream and model_id from optional_params as they're handled separately in URL optional_params.pop("stream", None) + optional_params.pop("model_id", None) # Remove AWS-specific params that shouldn't be in the request body inference_params: Final = {k: v for k, v in optional_params.items() if k not in self.aws_authentication_params} diff --git a/tests/unit/llms/bedrock/chat/invoke_transformations/test_amazon_openai_transformation.py b/tests/unit/llms/bedrock/chat/invoke_transformations/test_amazon_openai_transformation.py index 147501f01c2..b7460ef59ea 100644 --- a/tests/unit/llms/bedrock/chat/invoke_transformations/test_amazon_openai_transformation.py +++ b/tests/unit/llms/bedrock/chat/invoke_transformations/test_amazon_openai_transformation.py @@ -51,3 +51,29 @@ def test_openai_imported_model_preserves_message_types_and_request_parameters() "https://bedrock-runtime.us-east-1.amazonaws.com/model/" "arn:aws:bedrock:us-east-1:117159858402:imported-model%2Fm4gc1mrfuddy/invoke" ) + + +def test_openai_imported_model_with_model_id_application_inference_profile() -> None: + model: Final = "bedrock/openai/global.openai.gpt-6-luna" + profile_arn: Final = "arn:aws:bedrock:ap-northeast-2:123456789012:application-inference-profile/abc123def456" + config: Final = AmazonBedrockOpenAIConfig() + request: Final = config.transform_request( + model=model, + messages=[{"role": "user", "content": "hi"}], + optional_params={"model_id": profile_arn, "max_tokens": 100}, + litellm_params={"model_id": profile_arn}, + headers={}, + ) + url: Final = config.get_complete_url( + api_base=None, + api_key=None, + model=model, + optional_params={"aws_region_name": "ap-northeast-2", "model_id": profile_arn}, + litellm_params={"model_id": profile_arn}, + stream=False, + ) + assert "model_id" not in request + assert url == ( + "https://bedrock-runtime.ap-northeast-2.amazonaws.com/model/" + "arn:aws:bedrock:ap-northeast-2:123456789012:application-inference-profile%2Fabc123def456/invoke" + )