From a9d2f85c947904b4db179a50728db3c0b6ede488 Mon Sep 17 00:00:00 2001 From: C1-BA-B1-F3 Date: Thu, 25 Jun 2026 13:29:20 +0800 Subject: [PATCH 1/2] fix: support custom model naming prefixes for anthropic provider (#5893) The model prefix filtering was too strict, only matching 'claude-' and 'anthropic.' prefixes. Custom deployments with non-standard naming (e.g., 'anthropic--claude-...') were incorrectly filtered out. Now uses substring matching for 'claude' and 'anthropic' to support any naming convention. Also adds pattern-based inference in _infer_provider_from_model for custom model names. Closes #5893 --- lib/crewai/src/crewai/llm.py | 16 ++++++++++++++-- lib/crewai/tests/test_llm.py | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/crewai/src/crewai/llm.py b/lib/crewai/src/crewai/llm.py index 153bbd2d73..75178486af 100644 --- a/lib/crewai/src/crewai/llm.py +++ b/lib/crewai/src/crewai/llm.py @@ -508,8 +508,11 @@ def _matches_provider_pattern(cls, model: str, provider: str) -> bool: ) if provider == "anthropic" or provider == "claude": - return any( - model_lower.startswith(prefix) for prefix in ["claude-", "anthropic."] + # Match standard prefixes and any model containing "claude" or "anthropic" + # to support custom deployments with non-standard naming (e.g., "anthropic--claude-...") + return ( + "claude" in model_lower + or "anthropic" in model_lower ) if provider == "gemini" or provider == "google": @@ -619,6 +622,15 @@ def _infer_provider_from_model(cls, model: str) -> str: if model in AZURE_MODELS: return "azure" + # Pattern-based inference for custom deployments + model_lower = model.lower() + if "claude" in model_lower or "anthropic" in model_lower: + return "anthropic" + if model_lower.startswith("gpt-") or model_lower.startswith("o1") or model_lower.startswith("o3"): + return "openai" + if "gemini" in model_lower: + return "gemini" + return "openai" @classmethod diff --git a/lib/crewai/tests/test_llm.py b/lib/crewai/tests/test_llm.py index 1c98d751ef..92f58355c4 100644 --- a/lib/crewai/tests/test_llm.py +++ b/lib/crewai/tests/test_llm.py @@ -1177,3 +1177,27 @@ async def _ret(*args, **kwargs): assert isinstance(result, list) assert len(result) == 1 assert result[0].function.name == "search" + + +class TestModelPrefixFiltering: + """Test that model prefix filtering supports custom deployments.""" + + def test_anthropic_custom_prefix(self): + """Models with 'anthropic--claude' prefix should be recognized.""" + from crewai.llm import LLM + assert LLM._matches_provider_pattern("anthropic--claude-3-sonnet", "anthropic") + + def test_anthropic_standard_prefix(self): + """Standard claude- prefix should still work.""" + from crewai.llm import LLM + assert LLM._matches_provider_pattern("claude-3-sonnet", "anthropic") + + def test_anthropic_dot_prefix(self): + """Standard anthropic. prefix should still work.""" + from crewai.llm import LLM + assert LLM._matches_provider_pattern("anthropic.claude-3-sonnet", "anthropic") + + def test_infer_anthropic_from_custom_name(self): + """Should infer anthropic provider from custom model names.""" + from crewai.llm import LLM + assert LLM._infer_provider_from_model("anthropic--claude-3-sonnet") == "anthropic" From cdb9327054d97fea45439c5bbc06cc19598bdb83 Mon Sep 17 00:00:00 2001 From: C1-BA-B1-F3 Date: Fri, 26 Jun 2026 01:46:42 +0800 Subject: [PATCH 2/2] fix: align provider detection between helper methods - Add o4 and whisper- prefixes to OpenAI inference branch to match _matches_provider_pattern - Broaden _is_anthropic_model to use substring matching consistent with _matches_provider_pattern, so custom deployments like 'anthropic-custom' are detected correctly by both methods Addresses CodeRabbit review comments on PR #6333. --- lib/crewai/src/crewai/llm.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/crewai/src/crewai/llm.py b/lib/crewai/src/crewai/llm.py index 75178486af..104eeddaa9 100644 --- a/lib/crewai/src/crewai/llm.py +++ b/lib/crewai/src/crewai/llm.py @@ -626,7 +626,10 @@ def _infer_provider_from_model(cls, model: str) -> str: model_lower = model.lower() if "claude" in model_lower or "anthropic" in model_lower: return "anthropic" - if model_lower.startswith("gpt-") or model_lower.startswith("o1") or model_lower.startswith("o3"): + if any( + model_lower.startswith(prefix) + for prefix in ["gpt-", "o1", "o3", "o4", "whisper-"] + ): return "openai" if "gemini" in model_lower: return "gemini" @@ -714,8 +717,8 @@ def _is_anthropic_model(model: str) -> bool: Returns: bool: True if the model is from Anthropic, False otherwise. """ - anthropic_prefixes = ("anthropic/", "claude-", "claude/") - return any(prefix in model.lower() for prefix in anthropic_prefixes) + model_lower = model.lower() + return "claude" in model_lower or "anthropic" in model_lower def _prepare_completion_params( self,