From 04dcabca0393293ee0e1fbeeb03e7b992dd522bb Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:31:20 +0000 Subject: [PATCH] feat(bedrock): add Anthropic Claude 4 cross-region inference profile models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #5549 — adds Bedrock cross-region inference profile IDs for the Claude 4 family (Sonnet 4/4.5, Opus 4/4.1/4.5, Haiku 4.5) to BEDROCK_MODELS and BedrockModels so provider inference and validation work out-of-the-box for these identifiers. Co-Authored-By: João --- lib/crewai/src/crewai/llms/constants.py | 48 ++++++++++++ lib/crewai/tests/test_llm.py | 98 +++++++++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/lib/crewai/src/crewai/llms/constants.py b/lib/crewai/src/crewai/llms/constants.py index 595a0a30d..29e2749b2 100644 --- a/lib/crewai/src/crewai/llms/constants.py +++ b/lib/crewai/src/crewai/llms/constants.py @@ -494,6 +494,30 @@ BedrockModels: TypeAlias = Literal[ "qwen.qwen3-32b-v1:0", "qwen.qwen3-coder-30b-a3b-v1:0", "twelvelabs.pegasus-1-2-v1:0", + # Cross-region inference profiles for Anthropic Claude 4 models + "apac.anthropic.claude-haiku-4-5-20251001-v1:0", + "apac.anthropic.claude-sonnet-4-20250514-v1:0", + "au.anthropic.claude-haiku-4-5-20251001-v1:0", + "au.anthropic.claude-sonnet-4-5-20250929-v1:0", + "eu.anthropic.claude-haiku-4-5-20251001-v1:0", + "eu.anthropic.claude-opus-4-1-20250805-v1:0", + "eu.anthropic.claude-opus-4-20250514-v1:0", + "eu.anthropic.claude-opus-4-5-20251101-v1:0", + "eu.anthropic.claude-sonnet-4-20250514-v1:0", + "eu.anthropic.claude-sonnet-4-5-20250929-v1:0", + "global.anthropic.claude-haiku-4-5-20251001-v1:0", + "global.anthropic.claude-opus-4-5-20251101-v1:0", + "global.anthropic.claude-sonnet-4-20250514-v1:0", + "global.anthropic.claude-sonnet-4-5-20250929-v1:0", + "jp.anthropic.claude-haiku-4-5-20251001-v1:0", + "jp.anthropic.claude-sonnet-4-5-20250929-v1:0", + "us-gov.anthropic.claude-sonnet-4-5-20250929-v1:0", + "us.anthropic.claude-haiku-4-5-20251001-v1:0", + "us.anthropic.claude-opus-4-1-20250805-v1:0", + "us.anthropic.claude-opus-4-20250514-v1:0", + "us.anthropic.claude-opus-4-5-20251101-v1:0", + "us.anthropic.claude-sonnet-4-20250514-v1:0", + "us.anthropic.claude-sonnet-4-5-20250929-v1:0", ] BEDROCK_MODELS: list[BedrockModels] = [ "ai21.jamba-1-5-large-v1:0", @@ -567,4 +591,28 @@ BEDROCK_MODELS: list[BedrockModels] = [ "qwen.qwen3-32b-v1:0", "qwen.qwen3-coder-30b-a3b-v1:0", "twelvelabs.pegasus-1-2-v1:0", + # Cross-region inference profiles for Anthropic Claude 4 models + "apac.anthropic.claude-haiku-4-5-20251001-v1:0", + "apac.anthropic.claude-sonnet-4-20250514-v1:0", + "au.anthropic.claude-haiku-4-5-20251001-v1:0", + "au.anthropic.claude-sonnet-4-5-20250929-v1:0", + "eu.anthropic.claude-haiku-4-5-20251001-v1:0", + "eu.anthropic.claude-opus-4-1-20250805-v1:0", + "eu.anthropic.claude-opus-4-20250514-v1:0", + "eu.anthropic.claude-opus-4-5-20251101-v1:0", + "eu.anthropic.claude-sonnet-4-20250514-v1:0", + "eu.anthropic.claude-sonnet-4-5-20250929-v1:0", + "global.anthropic.claude-haiku-4-5-20251001-v1:0", + "global.anthropic.claude-opus-4-5-20251101-v1:0", + "global.anthropic.claude-sonnet-4-20250514-v1:0", + "global.anthropic.claude-sonnet-4-5-20250929-v1:0", + "jp.anthropic.claude-haiku-4-5-20251001-v1:0", + "jp.anthropic.claude-sonnet-4-5-20250929-v1:0", + "us-gov.anthropic.claude-sonnet-4-5-20250929-v1:0", + "us.anthropic.claude-haiku-4-5-20251001-v1:0", + "us.anthropic.claude-opus-4-1-20250805-v1:0", + "us.anthropic.claude-opus-4-20250514-v1:0", + "us.anthropic.claude-opus-4-5-20251101-v1:0", + "us.anthropic.claude-sonnet-4-20250514-v1:0", + "us.anthropic.claude-sonnet-4-5-20250929-v1:0", ] diff --git a/lib/crewai/tests/test_llm.py b/lib/crewai/tests/test_llm.py index 60ecca7f0..7f1f20669 100644 --- a/lib/crewai/tests/test_llm.py +++ b/lib/crewai/tests/test_llm.py @@ -992,6 +992,104 @@ def test_validate_model_in_constants(): is True ) + # Bedrock Claude 4 cross-region inference profiles (issue #5549) + assert ( + LLM._validate_model_in_constants( + "us.anthropic.claude-sonnet-4-5-20250929-v1:0", "bedrock" + ) + is True + ) + assert ( + LLM._validate_model_in_constants( + "us.anthropic.claude-opus-4-20250514-v1:0", "bedrock" + ) + is True + ) + assert ( + LLM._validate_model_in_constants( + "eu.anthropic.claude-sonnet-4-20250514-v1:0", "bedrock" + ) + is True + ) + assert ( + LLM._validate_model_in_constants( + "apac.anthropic.claude-haiku-4-5-20251001-v1:0", "bedrock" + ) + is True + ) + assert ( + LLM._validate_model_in_constants( + "global.anthropic.claude-sonnet-4-5-20250929-v1:0", "bedrock" + ) + is True + ) + + +def test_bedrock_claude_4_models_in_constants(): + """Claude 4 Bedrock models (direct IDs and cross-region inference profiles) + must be present in BEDROCK_MODELS so providers can be inferred correctly. + + See issue #5549: Anthropic V4 models were missing from the Bedrock model list. + """ + from crewai.llms.constants import BEDROCK_MODELS + + # Direct Claude 4 model IDs + direct_models = [ + "anthropic.claude-sonnet-4-20250514-v1:0", + "anthropic.claude-sonnet-4-5-20250929-v1:0", + "anthropic.claude-opus-4-20250514-v1:0", + "anthropic.claude-opus-4-1-20250805-v1:0", + "anthropic.claude-opus-4-5-20251101-v1:0", + "anthropic.claude-haiku-4-5-20251001-v1:0", + ] + for model in direct_models: + assert model in BEDROCK_MODELS, ( + f"Expected {model} to be listed in BEDROCK_MODELS" + ) + + # Cross-region inference profiles (required for invoking Claude 4 on Bedrock) + inference_profile_models = [ + "us.anthropic.claude-sonnet-4-20250514-v1:0", + "us.anthropic.claude-sonnet-4-5-20250929-v1:0", + "us.anthropic.claude-opus-4-20250514-v1:0", + "us.anthropic.claude-opus-4-1-20250805-v1:0", + "us.anthropic.claude-opus-4-5-20251101-v1:0", + "us.anthropic.claude-haiku-4-5-20251001-v1:0", + "eu.anthropic.claude-sonnet-4-20250514-v1:0", + "eu.anthropic.claude-sonnet-4-5-20250929-v1:0", + "eu.anthropic.claude-haiku-4-5-20251001-v1:0", + "apac.anthropic.claude-sonnet-4-20250514-v1:0", + "apac.anthropic.claude-haiku-4-5-20251001-v1:0", + "global.anthropic.claude-sonnet-4-5-20250929-v1:0", + "global.anthropic.claude-haiku-4-5-20251001-v1:0", + ] + for model in inference_profile_models: + assert model in BEDROCK_MODELS, ( + f"Expected {model} to be listed in BEDROCK_MODELS" + ) + + +def test_infer_provider_for_bedrock_claude_4_models(): + """Claude 4 Bedrock model IDs should be inferred as the 'bedrock' provider. + + Before the fix for issue #5549, cross-region inference profile IDs (e.g. + 'us.anthropic.claude-sonnet-4-5-20250929-v1:0') were not listed in + BEDROCK_MODELS, so ``_infer_provider_from_model`` incorrectly fell back to + the default 'openai' provider. + """ + claude_4_bedrock_models = [ + "anthropic.claude-sonnet-4-5-20250929-v1:0", + "anthropic.claude-opus-4-1-20250805-v1:0", + "us.anthropic.claude-sonnet-4-5-20250929-v1:0", + "us.anthropic.claude-opus-4-20250514-v1:0", + "eu.anthropic.claude-sonnet-4-20250514-v1:0", + "global.anthropic.claude-haiku-4-5-20251001-v1:0", + ] + for model in claude_4_bedrock_models: + assert LLM._infer_provider_from_model(model) == "bedrock", ( + f"Expected provider for {model} to be inferred as 'bedrock'" + ) + @pytest.mark.vcr(record_mode="once",decode_compressed_response=True) def test_usage_info_non_streaming_with_call(): llm = LLM(model="gpt-4o-mini", is_litellm=True)