diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 8c8b909493a..1dc84f06aa7 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -14614,7 +14614,7 @@ "supports_reasoning": true, "supports_sampling_params": false, "supports_tool_choice": true, - "supports_vision": false, + "supports_vision": true, "thinking_always_on": true }, "databricks/databricks-claude-haiku-4-5": { diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 8c8b909493a..1dc84f06aa7 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -14614,7 +14614,7 @@ "supports_reasoning": true, "supports_sampling_params": false, "supports_tool_choice": true, - "supports_vision": false, + "supports_vision": true, "thinking_always_on": true }, "databricks/databricks-claude-haiku-4-5": { diff --git a/tests/test_litellm/llms/databricks/test_databricks_cost_calculator.py b/tests/test_litellm/llms/databricks/test_databricks_cost_calculator.py index 0f1652b1b2a..81517e23b53 100644 --- a/tests/test_litellm/llms/databricks/test_databricks_cost_calculator.py +++ b/tests/test_litellm/llms/databricks/test_databricks_cost_calculator.py @@ -28,12 +28,45 @@ PRICE_FIELDS: Final = ( "cache_read_input_token_cost", ) PUBLISHED_DBU_PER_MILLION: Final = { - "databricks/databricks-claude-opus-4-7": ("71.429", "357.143", "89.286", "7.143"), - "databricks/databricks-claude-opus-4-8": ("71.429", "357.143", "89.286", "7.143"), - "databricks/databricks-claude-opus-5": ("71.429", "357.143", "89.286", "7.143"), - "databricks/databricks-claude-sonnet-5": ("42.857", "214.286", "53.571", "4.286"), "databricks/databricks-claude-fable-5": ("142.858", "714.286", "178.572", "14.286"), + "databricks/databricks-claude-opus-5": ("71.429", "357.143", "89.286", "7.143"), + "databricks/databricks-claude-opus-4-8": ("71.429", "357.143", "89.286", "7.143"), + "databricks/databricks-claude-opus-4-7": ("71.429", "357.143", "89.286", "7.143"), + "databricks/databricks-claude-opus-4-6": ("71.429", "357.143", "89.286", "7.143"), + "databricks/databricks-claude-opus-4-5": ("71.429", "357.143", "89.286", "7.143"), + "databricks/databricks-claude-opus-4-1": ("214.286", "1071.429", "267.857", "21.429"), + "databricks/databricks-claude-opus-4": ("214.286", "1071.429", "267.857", "21.429"), + "databricks/databricks-claude-sonnet-5": ("42.857", "214.286", "53.571", "4.286"), + "databricks/databricks-claude-sonnet-4-6": ("42.857", "214.286", "53.571", "4.286"), + "databricks/databricks-claude-sonnet-4-5": ("42.857", "214.286", "53.571", "4.286"), + "databricks/databricks-claude-sonnet-4-1": ("42.857", "214.286", "53.571", "4.286"), + "databricks/databricks-claude-sonnet-4": ("42.857", "214.286", "53.571", "4.286"), + "databricks/databricks-claude-3-7-sonnet": ("42.857", "214.286", "53.571", "4.286"), + "databricks/databricks-claude-haiku-4-5": ("14.286", "71.429", "17.857", "1.429"), + "databricks/databricks-gpt-5": ("17.857", "142.857", "17.857", "1.786"), + "databricks/databricks-gpt-5-1": ("17.857", "142.857", "17.857", "1.786"), + "databricks/databricks-gpt-5-1-codex-max": ("17.857", "142.857", "17.857", "1.786"), + "databricks/databricks-gpt-5-1-codex-mini": ("3.571", "28.571", "3.571", "0.357"), + "databricks/databricks-gpt-5-mini": ("3.571", "28.571", "3.571", "0.357"), + "databricks/databricks-gpt-5-nano": ("0.714", "5.714", "0.714", "0.071"), + "databricks/databricks-gpt-5-2": ("25.000", "200.000", "25.000", "2.500"), + "databricks/databricks-gpt-5-2-codex": ("25.000", "200.000", "25.000", "2.500"), + "databricks/databricks-gpt-5-3-codex": ("25.000", "200.000", "25.000", "2.500"), + "databricks/databricks-gpt-5-4": ("35.714", "214.286", "35.714", "3.571"), + "databricks/databricks-gpt-5-4-mini": ("10.714", "64.286", "10.714", "1.071"), + "databricks/databricks-gpt-5-4-nano": ("2.857", "17.857", "2.857", "0.286"), + "databricks/databricks-gemini-3-1-pro": ("35.714", "214.286", "35.714", "3.571"), + "databricks/databricks-gemini-3-pro": ("35.714", "214.286", "35.714", "3.571"), + "databricks/databricks-gemini-3-flash": ("8.929", "53.571", "8.929", "0.893"), + "databricks/databricks-gemini-3-1-flash-lite": ("4.464", "26.786", "4.464", "0.446"), + "databricks/databricks-gemini-2-5-pro": ("22.321", "178.571", "22.321", "2.232"), + "databricks/databricks-gemini-2-5-flash": ("5.357", "44.643", "5.357", "0.536"), } +OLDER_VINTAGE_MODELS: Final = ( + "databricks/databricks-gemini-2-5-pro", + "databricks/databricks-gemini-2-5-flash", +) +CACHE_FIELDS: Final = ("cache_creation_input_token_cost", "cache_read_input_token_cost") def _model_info(model: str) -> ModelInfo: @@ -102,6 +135,15 @@ def test_new_models_price_at_published_dbu_rates(local_model_cost_map: None, mod assert info[field] == _dollars_per_token(dbu_per_million), field +@pytest.mark.parametrize("model", sorted(set(PUBLISHED_DBU_PER_MILLION) - set(OLDER_VINTAGE_MODELS))) +def test_cache_rates_derive_from_published_cache_dbu(local_model_cost_map: None, model: str) -> None: + info: Final = _model_info(model) + cache_dbu_per_million: Final = PUBLISHED_DBU_PER_MILLION[model][2:] + + for field, dbu_per_million in zip(CACHE_FIELDS, cache_dbu_per_million): + assert info[field] == _dollars_per_token(dbu_per_million), field + + @pytest.mark.parametrize("model", NEW_MODELS) def test_new_models_carry_cache_pricing(local_model_cost_map: None, model: str) -> None: info: Final = _model_info(model) @@ -119,7 +161,7 @@ def test_every_priced_databricks_model_declares_cache_rates(local_model_cost_map for model, info in litellm.model_cost.items() if model.startswith("databricks/") and info.get("input_cost_per_token") is not None - and info.get("cache_read_input_token_cost") is None + and any(info.get(field) is None for field in CACHE_FIELDS) ] assert undeclared == [] @@ -139,12 +181,28 @@ def test_models_without_a_cache_discount_bill_cache_tokens_at_the_input_rate( prompt_cost, _ = cost_per_token(model=model, usage=usage) - assert info["cache_read_input_token_cost"] == info["input_cost_per_token"] - assert info["cache_creation_input_token_cost"] == info["input_cost_per_token"] assert prompt_cost == pytest.approx(10000 * info["input_cost_per_token"]) assert prompt_cost > 8000 * info["input_cost_per_token"] +def test_every_model_without_published_cache_dbu_bills_cache_at_its_own_input_rate( + local_model_cost_map: None, +) -> None: + without_published_rates: Final = [ + model + for model, info in litellm.model_cost.items() + if model.startswith("databricks/") + and info.get("input_cost_per_token") + and model not in PUBLISHED_DBU_PER_MILLION + ] + + assert len(without_published_rates) == 14 + for model in without_published_rates: + info = _model_info(model) + for field in CACHE_FIELDS: + assert info[field] == pytest.approx(info["input_cost_per_token"]), (model, field) + + @pytest.mark.parametrize("model", NEW_MODELS) def test_backup_price_map_matches_main(model: str) -> None: main_cost: Final = json.loads(MAIN_PRICES.read_text()) @@ -163,13 +221,7 @@ def test_sonnet_5_ships_standard_rates_not_introductory(local_model_cost_map: No assert sonnet_5[field] == pytest.approx(sonnet_4_6[field]), field -@pytest.mark.parametrize( - "model", - [ - "databricks/databricks-gemini-2-5-pro", - "databricks/databricks-gemini-2-5-flash", - ], -) +@pytest.mark.parametrize("model", OLDER_VINTAGE_MODELS) def test_entries_priced_at_an_older_vintage_keep_cache_rates_tied_to_their_own_input( local_model_cost_map: None, model: str,