diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 3f77bd49a0d..9569f29aa0e 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -58151,17 +58151,20 @@ } }, { - "name": "gemini-family-baseline", - "pattern": "gemini-(?!.*(?:-tts|-image|-live|-audio|-embedding|-computer-use|-robotics))(?:2\\.[5-9]|[3-9](?:[.-]\\d{1,2})?)-(?:pro|flash)(?:-lite)?(?![a-z])", - "description": "Any Gemini text-chat id at 2.5 or higher under any provider namespace (bare, gemini/, vertex_ai/, databricks-gemini-3-1-pro, ...): gemini-[.minor]-(pro|flash)[-lite] with any trailing preview, date or variant tag. The lookahead excludes the tts, image, live, audio, embedding, computer-use and robotics lines, which are not text-chat models and carry different limits and modes. 2.5 is the floor because every Gemini from 2.5 onward is a thinking model with tool calling and multimodal input; 1.5 and 2.0 are not and are fully mapped. Carries the model-family facts every such Gemini shares, so an unmapped gemini-4-pro keeps reasoning params and tool calling instead of having them dropped; it carries no token limits or pricing, so those stay on the standard unmapped behavior rather than a guessed number.", + "name": "gemini-chat-baseline", + "pattern": "^(?:gemini|vertex_ai)/gemini-(?!.*(?:-tts|-image|-live|-audio|-embedding|-computer-use|-robotics|-transcribe|-translate))(?:2\\.[5-9]|[3-9](?:\\.\\d{1,2})?)-(?:pro|flash)(?:-lite)?(?![a-z])", + "description": "A first-party Gemini text-chat id at 2.5 or higher, as gemini/ or vertex_ai/ (get_model_info tries the provider-prefixed name first, so a bare id under those providers matches too): gemini-[.minor]-(pro|flash)[-lite] with any trailing preview, date or variant tag. Scoped to Google's own namespaces because resellers wrap the same models differently (one exposes them as mode responses without reasoning), so nothing below is certain there. The lookahead excludes the tts, image, live, audio, embedding, computer-use, robotics, transcribe and translate lines, which are different modes with different capabilities. 2.5 is the floor: every first-party text-chat Gemini from 2.5 onward in this map carries all of these fields, 1.5 and 2.0 do not and are fully mapped. Carries no token limits or pricing, so those stay on the standard unmapped behavior rather than a guessed number.", "model_info": { "mode": "chat", + "supports_reasoning": true, "supports_function_calling": true, "supports_tool_choice": true, "supports_system_messages": true, "supports_vision": true, "supports_response_schema": true, - "supports_reasoning": true + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_web_search": true } } ] diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 3f77bd49a0d..9569f29aa0e 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -58151,17 +58151,20 @@ } }, { - "name": "gemini-family-baseline", - "pattern": "gemini-(?!.*(?:-tts|-image|-live|-audio|-embedding|-computer-use|-robotics))(?:2\\.[5-9]|[3-9](?:[.-]\\d{1,2})?)-(?:pro|flash)(?:-lite)?(?![a-z])", - "description": "Any Gemini text-chat id at 2.5 or higher under any provider namespace (bare, gemini/, vertex_ai/, databricks-gemini-3-1-pro, ...): gemini-[.minor]-(pro|flash)[-lite] with any trailing preview, date or variant tag. The lookahead excludes the tts, image, live, audio, embedding, computer-use and robotics lines, which are not text-chat models and carry different limits and modes. 2.5 is the floor because every Gemini from 2.5 onward is a thinking model with tool calling and multimodal input; 1.5 and 2.0 are not and are fully mapped. Carries the model-family facts every such Gemini shares, so an unmapped gemini-4-pro keeps reasoning params and tool calling instead of having them dropped; it carries no token limits or pricing, so those stay on the standard unmapped behavior rather than a guessed number.", + "name": "gemini-chat-baseline", + "pattern": "^(?:gemini|vertex_ai)/gemini-(?!.*(?:-tts|-image|-live|-audio|-embedding|-computer-use|-robotics|-transcribe|-translate))(?:2\\.[5-9]|[3-9](?:\\.\\d{1,2})?)-(?:pro|flash)(?:-lite)?(?![a-z])", + "description": "A first-party Gemini text-chat id at 2.5 or higher, as gemini/ or vertex_ai/ (get_model_info tries the provider-prefixed name first, so a bare id under those providers matches too): gemini-[.minor]-(pro|flash)[-lite] with any trailing preview, date or variant tag. Scoped to Google's own namespaces because resellers wrap the same models differently (one exposes them as mode responses without reasoning), so nothing below is certain there. The lookahead excludes the tts, image, live, audio, embedding, computer-use, robotics, transcribe and translate lines, which are different modes with different capabilities. 2.5 is the floor: every first-party text-chat Gemini from 2.5 onward in this map carries all of these fields, 1.5 and 2.0 do not and are fully mapped. Carries no token limits or pricing, so those stay on the standard unmapped behavior rather than a guessed number.", "model_info": { "mode": "chat", + "supports_reasoning": true, "supports_function_calling": true, "supports_tool_choice": true, "supports_system_messages": true, "supports_vision": true, "supports_response_schema": true, - "supports_reasoning": true + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_web_search": true } } ] diff --git a/tests/test_litellm/litellm_core_utils/test_fallback_generalizations.py b/tests/test_litellm/litellm_core_utils/test_fallback_generalizations.py index 556a23c13be..a4fbd79187e 100644 --- a/tests/test_litellm/litellm_core_utils/test_fallback_generalizations.py +++ b/tests/test_litellm/litellm_core_utils/test_fallback_generalizations.py @@ -453,45 +453,64 @@ def shipped_cost_map(monkeypatch): "model,provider", [ ("gemini-4-pro", "gemini"), - ("gemini-3.9-flash", "vertex_ai"), - ("databricks-gemini-4-1-pro", "databricks"), + ("gemini/gemini-4-pro", None), + ("gemini-3.9-flash-lite-preview-09-2026", "vertex_ai"), + ("vertex_ai/gemini-4-pro", None), ("gemini-4-pro-preview-customtools", "gemini"), ], ) -def test_shipped_gemini_baseline_resolves_unmapped_ids_provider_neutral(shipped_cost_map, model, provider): +def test_shipped_gemini_chat_baseline_resolves_first_party_unmapped_ids(shipped_cost_map, model, provider): assert model not in litellm.model_cost if provider == "gemini": assert f"gemini/{model}" not in litellm.model_cost info = litellm.get_model_info(model, custom_llm_provider=provider) - assert info["litellm_provider"] == provider + assert info["litellm_provider"] == (provider or model.split("/")[0]) assert info["mode"] == "chat" assert not info.get("max_input_tokens") assert info["supports_reasoning"] is True assert info["supports_function_calling"] is True assert info["supports_tool_choice"] is True - assert info["supports_response_schema"] is True + assert info["supports_system_messages"] is True assert info["supports_vision"] is True + assert info["supports_response_schema"] is True + assert info["supports_pdf_input"] is True + assert info["supports_prompt_caching"] is True + assert info["supports_web_search"] is True assert not info.get("input_cost_per_token") assert not info.get("output_cost_per_token") -def test_shipped_gemini_baseline_skips_non_chat_and_pre_2_5_ids(shipped_cost_map): +def test_shipped_gemini_chat_baseline_skips_reseller_namespaces(shipped_cost_map): + for model, provider in ( + ("google/gemini-4-pro", "perplexity"), + ("google/gemini-4-pro", "openrouter"), + ("databricks-gemini-4-1-pro", "databricks"), + ): + with pytest.raises(Exception, match="isn't mapped yet"): + litellm.get_model_info(model, custom_llm_provider=provider) + + assert match_capability_generalizations("google/gemini-4-pro") is None + + +def test_shipped_gemini_chat_baseline_skips_non_chat_and_pre_2_5_ids(shipped_cost_map): for model in ( - "gemini-4-flash-image", - "gemini-3.9-flash-preview-tts", - "gemini-4-flash-live-preview", - "gemini-4-flash-native-audio", - "gemini-embedding-4", - "gemini-2.5-computer-use-preview-12-2026", - "gemini-2.0-flash-new", - "gemini-1.5-pro-new", - "gemini-4-flashy", + "gemini/gemini-4-flash-image", + "gemini/gemini-3.9-flash-preview-tts", + "gemini/gemini-4-flash-live-preview", + "gemini/gemini-4-flash-native-audio", + "gemini/gemini-embedding-4", + "gemini/gemini-2.5-computer-use-preview-12-2026", + "gemini/gemini-2.0-flash-new", + "gemini/gemini-1.5-pro-new", + "gemini/gemini-4-flashy", + "gemini/gemini-4-flash-transcribe", + "gemini/gemini-4-flash-live-translate-preview", ): assert match_capability_generalizations(model) is None, model -def test_shipped_gemini_baseline_keeps_reasoning_effort_on_unmapped_model(shipped_cost_map): +def test_shipped_gemini_chat_baseline_keeps_reasoning_effort_on_unmapped_model(shipped_cost_map): assert litellm.supports_reasoning(model="gemini-4-pro", custom_llm_provider="gemini") is True optional_params = litellm.utils.get_optional_params( @@ -505,7 +524,7 @@ def test_shipped_gemini_baseline_keeps_reasoning_effort_on_unmapped_model(shippe assert optional_params["thinkingConfig"]["includeThoughts"] is True -def test_shipped_gemini_baseline_loses_to_exact_entries(shipped_cost_map): +def test_shipped_gemini_chat_baseline_loses_to_exact_entries(shipped_cost_map): model = "gemini-2.5-flash-lite" info = litellm.get_model_info(model, custom_llm_provider="gemini") entry = litellm.model_cost["gemini/gemini-2.5-flash-lite"] diff --git a/tests/test_litellm/litellm_core_utils/test_get_supported_openai_params.py b/tests/test_litellm/litellm_core_utils/test_get_supported_openai_params.py index 722818598af..f9e285cf9fb 100644 --- a/tests/test_litellm/litellm_core_utils/test_get_supported_openai_params.py +++ b/tests/test_litellm/litellm_core_utils/test_get_supported_openai_params.py @@ -1,7 +1,5 @@ - import pytest - from litellm.litellm_core_utils.get_supported_openai_params import ( get_supported_openai_params, ) @@ -33,9 +31,7 @@ def test_base_model_label_alone_lacks_bedrock_tools(): """The label by itself does not advertise tools; this is what made the union necessary. Guards against the discrepancy disappearing (and the regression test above silently passing for the wrong reason).""" - params = get_supported_openai_params( - model=BEDROCK_LABEL, custom_llm_provider="bedrock" - ) + params = get_supported_openai_params(model=BEDROCK_LABEL, custom_llm_provider="bedrock") assert params is not None assert "tools" not in params @@ -46,14 +42,8 @@ def test_base_model_is_additive_not_replacement(): Bedrock: real id supports ``tools`` but not the label's reasoning hint; the union must contain the real model's ``tools`` regardless of the label being a subset.""" - real_only = set( - get_supported_openai_params( - model=BEDROCK_REAL_MODEL, custom_llm_provider="bedrock" - ) - ) - label_only = set( - get_supported_openai_params(model=BEDROCK_LABEL, custom_llm_provider="bedrock") - ) + real_only = set(get_supported_openai_params(model=BEDROCK_REAL_MODEL, custom_llm_provider="bedrock")) + label_only = set(get_supported_openai_params(model=BEDROCK_LABEL, custom_llm_provider="bedrock")) combined = set( get_supported_openai_params( model=BEDROCK_REAL_MODEL, @@ -70,19 +60,15 @@ def test_base_model_is_additive_not_replacement(): def test_base_model_adds_capabilities_the_real_model_lacks(): """Regression for #27717 (the behavior the union must preserve). - ``gemini-3.1-pro`` isn't in the cost map so it advertises no reasoning support, + ``gemini-exp-9999`` isn't in the cost map so it advertises no reasoning support, but the registered ``gemini-3.1-pro-preview`` base_model does. The hint must add ``reasoning_effort``/``thinking`` without the call erroring.""" - real_only = set( - get_supported_openai_params( - model="gemini-3.1-pro", custom_llm_provider="gemini" - ) - ) + real_only = set(get_supported_openai_params(model="gemini-exp-9999", custom_llm_provider="gemini")) assert "reasoning_effort" not in real_only combined = set( get_supported_openai_params( - model="gemini-3.1-pro", + model="gemini-exp-9999", custom_llm_provider="gemini", base_model="gemini-3.1-pro-preview", ) @@ -93,21 +79,15 @@ def test_base_model_adds_capabilities_the_real_model_lacks(): def test_no_base_model_is_unchanged(): """Omitting ``base_model`` must resolve purely from ``model``.""" - with_none = get_supported_openai_params( - model=BEDROCK_REAL_MODEL, custom_llm_provider="bedrock", base_model=None - ) - plain = get_supported_openai_params( - model=BEDROCK_REAL_MODEL, custom_llm_provider="bedrock" - ) + with_none = get_supported_openai_params(model=BEDROCK_REAL_MODEL, custom_llm_provider="bedrock", base_model=None) + plain = get_supported_openai_params(model=BEDROCK_REAL_MODEL, custom_llm_provider="bedrock") assert with_none == plain def test_base_model_equal_to_model_is_unchanged(): """A ``base_model`` identical to ``model`` must not double-resolve or reorder.""" - plain = get_supported_openai_params( - model=BEDROCK_REAL_MODEL, custom_llm_provider="bedrock" - ) + plain = get_supported_openai_params(model=BEDROCK_REAL_MODEL, custom_llm_provider="bedrock") same = get_supported_openai_params( model=BEDROCK_REAL_MODEL, custom_llm_provider="bedrock", @@ -152,14 +132,10 @@ def test_bedrock_converse_alias_resolves_like_bedrock(): params saw no Bedrock capabilities for a Converse model invoked via the alias.""" anthropic_model = "bedrock/converse/us.anthropic.claude-sonnet-4-6" - via_alias = get_supported_openai_params( - model=anthropic_model, custom_llm_provider="bedrock_converse" - ) + via_alias = get_supported_openai_params(model=anthropic_model, custom_llm_provider="bedrock_converse") assert via_alias is not None - assert via_alias == get_supported_openai_params( - model=anthropic_model, custom_llm_provider="bedrock" - ) + assert via_alias == get_supported_openai_params(model=anthropic_model, custom_llm_provider="bedrock") assert "web_search_options" not in via_alias assert "tools" in via_alias @@ -167,9 +143,7 @@ def test_bedrock_converse_alias_resolves_like_bedrock(): def test_bedrock_converse_alias_keeps_nova_web_search_options(): """Nova on the ``bedrock_converse`` alias still advertises web_search_options, proving the alias routes through the model-aware config rather than a blanket Bedrock default.""" - nova_params = get_supported_openai_params( - model="amazon.nova-pro-v1:0", custom_llm_provider="bedrock_converse" - ) + nova_params = get_supported_openai_params(model="amazon.nova-pro-v1:0", custom_llm_provider="bedrock_converse") assert nova_params is not None assert "web_search_options" in nova_params