diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 9ca8d9e1bac3..7bd629bfc580 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -43373,6 +43373,7 @@ ] }, "xai/grok-2": { + "deprecation_date": "2026-02-28", "input_cost_per_token": 2e-06, "litellm_provider": "xai", "max_input_tokens": 131072, @@ -43385,6 +43386,7 @@ "supports_web_search": true }, "xai/grok-2-1212": { + "deprecation_date": "2026-02-28", "input_cost_per_token": 2e-06, "litellm_provider": "xai", "max_input_tokens": 131072, @@ -43397,6 +43399,7 @@ "supports_web_search": true }, "xai/grok-2-latest": { + "deprecation_date": "2026-02-28", "input_cost_per_token": 2e-06, "litellm_provider": "xai", "max_input_tokens": 131072, @@ -43409,6 +43412,7 @@ "supports_web_search": true }, "xai/grok-2-vision": { + "deprecation_date": "2026-02-28", "input_cost_per_image": 2e-06, "input_cost_per_token": 2e-06, "litellm_provider": "xai", @@ -43438,6 +43442,7 @@ "supports_web_search": true }, "xai/grok-2-vision-latest": { + "deprecation_date": "2026-02-28", "input_cost_per_image": 2e-06, "input_cost_per_token": 2e-06, "litellm_provider": "xai", @@ -43836,7 +43841,7 @@ "max_input_tokens": 1000000, "max_output_tokens": 1000000, "max_tokens": 1000000, - "mode": "chat", + "mode": "responses", "output_cost_per_token": 2.5e-06, "source": "https://docs.x.ai/docs/models", "supports_function_calling": true, @@ -44018,6 +44023,7 @@ "supports_web_search": true }, "xai/grok-beta": { + "deprecation_date": "2026-02-28", "input_cost_per_token": 5e-06, "litellm_provider": "xai", "max_input_tokens": 131072, @@ -44094,6 +44100,7 @@ "deprecation_date": "2026-05-15" }, "xai/grok-vision-beta": { + "deprecation_date": "2026-02-28", "input_cost_per_image": 5e-06, "input_cost_per_token": 5e-06, "litellm_provider": "xai", @@ -50703,7 +50710,7 @@ "max_input_tokens": 1000000, "max_output_tokens": 1000000, "max_tokens": 1000000, - "mode": "chat", + "mode": "responses", "output_cost_per_token": 2.5e-06, "source": "https://docs.x.ai/docs/models", "supports_function_calling": true, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 9ca8d9e1bac3..7bd629bfc580 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -43373,6 +43373,7 @@ ] }, "xai/grok-2": { + "deprecation_date": "2026-02-28", "input_cost_per_token": 2e-06, "litellm_provider": "xai", "max_input_tokens": 131072, @@ -43385,6 +43386,7 @@ "supports_web_search": true }, "xai/grok-2-1212": { + "deprecation_date": "2026-02-28", "input_cost_per_token": 2e-06, "litellm_provider": "xai", "max_input_tokens": 131072, @@ -43397,6 +43399,7 @@ "supports_web_search": true }, "xai/grok-2-latest": { + "deprecation_date": "2026-02-28", "input_cost_per_token": 2e-06, "litellm_provider": "xai", "max_input_tokens": 131072, @@ -43409,6 +43412,7 @@ "supports_web_search": true }, "xai/grok-2-vision": { + "deprecation_date": "2026-02-28", "input_cost_per_image": 2e-06, "input_cost_per_token": 2e-06, "litellm_provider": "xai", @@ -43438,6 +43442,7 @@ "supports_web_search": true }, "xai/grok-2-vision-latest": { + "deprecation_date": "2026-02-28", "input_cost_per_image": 2e-06, "input_cost_per_token": 2e-06, "litellm_provider": "xai", @@ -43836,7 +43841,7 @@ "max_input_tokens": 1000000, "max_output_tokens": 1000000, "max_tokens": 1000000, - "mode": "chat", + "mode": "responses", "output_cost_per_token": 2.5e-06, "source": "https://docs.x.ai/docs/models", "supports_function_calling": true, @@ -44018,6 +44023,7 @@ "supports_web_search": true }, "xai/grok-beta": { + "deprecation_date": "2026-02-28", "input_cost_per_token": 5e-06, "litellm_provider": "xai", "max_input_tokens": 131072, @@ -44094,6 +44100,7 @@ "deprecation_date": "2026-05-15" }, "xai/grok-vision-beta": { + "deprecation_date": "2026-02-28", "input_cost_per_image": 5e-06, "input_cost_per_token": 5e-06, "litellm_provider": "xai", @@ -50703,7 +50710,7 @@ "max_input_tokens": 1000000, "max_output_tokens": 1000000, "max_tokens": 1000000, - "mode": "chat", + "mode": "responses", "output_cost_per_token": 2.5e-06, "source": "https://docs.x.ai/docs/models", "supports_function_calling": true, diff --git a/tests/test_litellm/test_xai_grok_model_metadata.py b/tests/test_litellm/test_xai_grok_model_metadata.py new file mode 100644 index 000000000000..30f8122d20a4 --- /dev/null +++ b/tests/test_litellm/test_xai_grok_model_metadata.py @@ -0,0 +1,85 @@ +import json +from pathlib import Path + +# https://github.com/BerriAI/litellm/issues/38179 +# grok-2-era slugs: xAI deprecated them effective 2026-02-28 (same batch date as +# the pre-existing xai/grok-2-vision-1212 annotation) and they now hard-fail with +# "Model not found — retired by xAI". +RETIRED_GROK2_MODELS = [ + "xai/grok-2", + "xai/grok-2-1212", + "xai/grok-2-latest", + "xai/grok-2-vision", + "xai/grok-2-vision-latest", + "xai/grok-beta", + "xai/grok-vision-beta", +] +GROK2_DEPRECATION_DATE = "2026-02-28" + +# Per https://docs.x.ai/developers/model-capabilities/text/multi-agent (Limitations): +# "The multi-agent model does not work with the OpenAI Chat Completions API." +RESPONSES_ONLY_MODELS = [ + "xai/grok-4.20-multi-agent-0309", + "xai/grok-4.20-multi-agent-beta-0309", +] + +# Slugs still served by xAI (https://docs.x.ai/developers/models) that must not +# be marked deprecated. +ACTIVE_GROK_MODELS = [ + "xai/grok-4.5", + "xai/grok-4.6", + "xai/grok-4.20-0309-reasoning", +] + + +def _load_model_cost(path: Path) -> dict: + with open(path) as f: + return json.load(f) + + +def test_retired_grok2_models_are_annotated(): + json_path = Path(__file__).parents[2] / "model_prices_and_context_window.json" + model_cost = _load_model_cost(json_path) + + for model in RETIRED_GROK2_MODELS: + info = model_cost.get(model) + assert info is not None, f"{model} not found in model_prices_and_context_window.json" + assert ( + info.get("deprecation_date") == GROK2_DEPRECATION_DATE + ), f"{model} should carry deprecation_date {GROK2_DEPRECATION_DATE}" + + +def test_grok_4_20_multi_agent_is_responses_only(): + json_path = Path(__file__).parents[2] / "model_prices_and_context_window.json" + model_cost = _load_model_cost(json_path) + + for model in RESPONSES_ONLY_MODELS: + info = model_cost.get(model) + assert info is not None, f"{model} not found in model_prices_and_context_window.json" + assert ( + info.get("mode") == "responses" + ), f"{model} only works with the xAI Responses API, not Chat Completions" + + +def test_active_grok_models_are_not_marked_deprecated(): + json_path = Path(__file__).parents[2] / "model_prices_and_context_window.json" + model_cost = _load_model_cost(json_path) + + for model in ACTIVE_GROK_MODELS: + info = model_cost.get(model) + assert info is not None, f"{model} not found in model_prices_and_context_window.json" + assert ( + "deprecation_date" not in info + ), f"{model} is still served by xAI and must not be marked deprecated" + + +def test_xai_grok_metadata_backup_matches_main(): + repo_root = Path(__file__).parents[2] + main_path = repo_root / "model_prices_and_context_window.json" + backup_path = repo_root / "litellm" / "model_prices_and_context_window_backup.json" + + main_cost = _load_model_cost(main_path) + backup_cost = _load_model_cost(backup_path) + + for model in RETIRED_GROK2_MODELS + RESPONSES_ONLY_MODELS: + assert backup_cost.get(model) == main_cost.get(model), f"{model} differs between main and backup"