From ed7cc145273973cb5fc2e9a926daeca5d8572092 Mon Sep 17 00:00:00 2001 From: Mairaarshad19 Date: Sat, 5 Sep 2026 02:13:33 +0500 Subject: [PATCH] feat(llm): add Gemini 3.8 Flash support - Register Gemini 3.8 Flash in CrewAI and CLI model catalogs - Add 1,048,576-token context window mapping - Add native Gemini provider support - Add Gemini 3.8 Flash to the CLI model picker - Add native model detection coverage for gemini/ and google/ formats - Add context window regression coverage Closes #7241 --- lib/cli/src/crewai_cli/constants.py | 1 + lib/cli/src/crewai_cli/create_json_crew.py | 1 + lib/crewai/src/crewai/constants.py | 1 + lib/crewai/src/crewai/llm.py | 1 + lib/crewai/src/crewai/llms/constants.py | 2 + .../llms/providers/gemini/completion.py | 1 + lib/crewai/tests/llms/google/test_google.py | 46 ++++++++++++++----- lib/crewai/tests/test_llm.py | 1 + 8 files changed, 42 insertions(+), 12 deletions(-) diff --git a/lib/cli/src/crewai_cli/constants.py b/lib/cli/src/crewai_cli/constants.py index c587147b3f..c7b902b2a5 100644 --- a/lib/cli/src/crewai_cli/constants.py +++ b/lib/cli/src/crewai_cli/constants.py @@ -177,6 +177,7 @@ "claude-haiku-4-5-20251001", ], "gemini": [ + "gemini/gemini-3.8-flash", "gemini/gemini-3-pro-preview", "gemini/gemini-1.5-flash", "gemini/gemini-1.5-pro", diff --git a/lib/cli/src/crewai_cli/create_json_crew.py b/lib/cli/src/crewai_cli/create_json_crew.py index a4b04975f1..e060549a59 100644 --- a/lib/cli/src/crewai_cli/create_json_crew.py +++ b/lib/cli/src/crewai_cli/create_json_crew.py @@ -72,6 +72,7 @@ ("claude-sonnet-4-6", "Claude Sonnet 4.6"), ], "gemini": [ + ("gemini-3.8-flash", "Gemini 3.8 Flash"), ("gemini-3.5-flash", "Gemini 3.5 Flash"), ("gemini-3.1-pro-preview", "Gemini 3.1 Pro (preview)"), ("gemini-3-flash-preview", "Gemini 3 Flash (preview)"), diff --git a/lib/crewai/src/crewai/constants.py b/lib/crewai/src/crewai/constants.py index 237a54dbcd..84a10642dd 100644 --- a/lib/crewai/src/crewai/constants.py +++ b/lib/crewai/src/crewai/constants.py @@ -173,6 +173,7 @@ "claude-haiku-4-5-20251001", ], "gemini": [ + "gemini/gemini-3.8-flash", "gemini/gemini-3-pro-preview", "gemini/gemini-1.5-flash", "gemini/gemini-1.5-pro", diff --git a/lib/crewai/src/crewai/llm.py b/lib/crewai/src/crewai/llm.py index c2924e5427..4ba7508288 100644 --- a/lib/crewai/src/crewai/llm.py +++ b/lib/crewai/src/crewai/llm.py @@ -181,6 +181,7 @@ def _ensure_litellm() -> bool: "o1-mini": 128000, "o3-mini": 200000, "o4-mini": 200000, + "gemini-3.8-flash": 1048576, "gemini-3-pro-preview": 1048576, "gemini-2.0-flash": 1048576, "gemini-2.0-flash-thinking-exp-01-21": 32768, diff --git a/lib/crewai/src/crewai/llms/constants.py b/lib/crewai/src/crewai/llms/constants.py index 20697f6a53..b26a9e3e21 100644 --- a/lib/crewai/src/crewai/llms/constants.py +++ b/lib/crewai/src/crewai/llms/constants.py @@ -213,6 +213,7 @@ ] GeminiModels: TypeAlias = Literal[ + "gemini-3.8-flash", "gemini-3-pro-preview", "gemini-3-flash-preview", "gemini-2.5-pro", @@ -268,6 +269,7 @@ "learnlm-2.0-flash-experimental", ] GEMINI_MODELS: list[GeminiModels] = [ + "gemini-3.8-flash", "gemini-3-pro-preview", "gemini-3-flash-preview", "gemini-2.5-pro", diff --git a/lib/crewai/src/crewai/llms/providers/gemini/completion.py b/lib/crewai/src/crewai/llms/providers/gemini/completion.py index 98edc12383..68238a0e1b 100644 --- a/lib/crewai/src/crewai/llms/providers/gemini/completion.py +++ b/lib/crewai/src/crewai/llms/providers/gemini/completion.py @@ -1386,6 +1386,7 @@ def get_context_window_size(self) -> int: ) context_windows = { + "gemini-3.8-flash": 1048576, # 1M tokens "gemini-3-pro-preview": 1048576, # 1M tokens "gemini-2.0-flash": 1048576, # 1M tokens "gemini-2.0-flash-thinking": 32768, diff --git a/lib/crewai/tests/llms/google/test_google.py b/lib/crewai/tests/llms/google/test_google.py index 48c9f32247..71f8785138 100644 --- a/lib/crewai/tests/llms/google/test_google.py +++ b/lib/crewai/tests/llms/google/test_google.py @@ -20,27 +20,44 @@ def mock_google_api_key(): yield -def test_gemini_completion_is_used_when_google_provider(): +@pytest.mark.parametrize( + "model, expected_model", + [ + ("google/gemini-2.0-flash-001", "gemini-2.0-flash-001"), + ("google/gemini-3.8-flash", "gemini-3.8-flash"), + ], +) +def test_gemini_completion_is_used_when_google_provider(model, expected_model): """ - Test that GeminiCompletion from completion.py is used when LLM uses provider 'google' + Test that GeminiCompletion is used when LLM uses provider 'google' """ - llm = LLM(model="google/gemini-2.0-flash-001") + llm = LLM(model=model) assert llm.__class__.__name__ == "GeminiCompletion" assert llm.provider == "gemini" - assert llm.model == "gemini-2.0-flash-001" + assert llm.model == expected_model + -def test_gemini_completion_is_used_when_gemini_provider(): +@pytest.mark.parametrize( + "model, expected_model", + [ + ("gemini/gemini-2.0-flash-001", "gemini-2.0-flash-001"), + ("gemini/gemini-3.8-flash", "gemini-3.8-flash"), + ], +) +def test_gemini_completion_is_used_when_gemini_provider(model, expected_model): """ Test that GeminiCompletion is used when provider is 'gemini' """ - llm = LLM(model="gemini/gemini-2.0-flash-001") - from crewai.llms.providers.gemini.completion import GeminiCompletion + + llm = LLM(model=model) + assert isinstance(llm, GeminiCompletion) assert llm.provider == "gemini" - assert llm.model == "gemini-2.0-flash-001" + assert llm.model == expected_model + def test_gemini_completion_module_is_imported(): """ @@ -350,10 +367,8 @@ def test_gemini_raises_error_when_model_not_supported(): mock_client.models.generate_content.side_effect = ClientError(404, mock_response) - llm = LLM(model="google/model-doesnt-exist") - - with pytest.raises(Exception): # Should raise some error for unsupported model - llm.call("Hello") + with pytest.raises(ImportError, match="Unable to initialize LLM"): + LLM(model="google/model-doesnt-exist") def test_gemini_vertex_ai_setup(): @@ -440,6 +455,8 @@ def test_gemini_model_detection(): """ # Test Gemini model naming patterns that actually work with provider detection gemini_test_cases = [ + "gemini/gemini-3.8-flash", + "google/gemini-3.8-flash", "google/gemini-2.0-flash-001", "gemini/gemini-2.0-flash-001", "google/gemini-1.5-pro", @@ -469,6 +486,11 @@ def test_gemini_context_window_size(): context_size_2_0 = llm_2_0.get_context_window_size() assert context_size_2_0 > 500000 + # Test Gemini 3.8 Flash + llm_3_8 = LLM(model="google/gemini-3.8-flash") + context_size_3_8 = llm_3_8.get_context_window_size() + assert context_size_3_8 == 891289 + # Test Gemini 1.5 Pro llm_1_5 = LLM(model="google/gemini-1.5-pro") context_size_1_5 = llm_1_5.get_context_window_size() diff --git a/lib/crewai/tests/test_llm.py b/lib/crewai/tests/test_llm.py index ec15e8a3c2..dde38fb9d7 100644 --- a/lib/crewai/tests/test_llm.py +++ b/lib/crewai/tests/test_llm.py @@ -254,6 +254,7 @@ def test_validate_call_params_no_response_format(): @pytest.mark.parametrize( "model", [ + "gemini/gemini-3.8-flash", "gemini/gemini-3-pro-preview", "gemini/gemini-2.0-flash-thinking-exp-01-21", "gemini/gemini-2.0-flash-001",