diff --git a/.github/scripts/auto_update_price_and_context_window_file.py b/.github/scripts/auto_update_price_and_context_window_file.py index df1ac738681..e7d7e465f8f 100644 --- a/.github/scripts/auto_update_price_and_context_window_file.py +++ b/.github/scripts/auto_update_price_and_context_window_file.py @@ -171,6 +171,8 @@ def write_to_file(file_path, data): # Update the existing models and add the missing models for OpenRouter def transform_openrouter_data(data): transformed = {} + if not data: + return transformed for row in data: # Add the fields 'max_tokens' and 'input_cost_per_token' obj = { @@ -209,7 +211,14 @@ def transform_openrouter_data(data): # Update the existing models and add the missing models for Vercel AI Gateway def transform_vercel_ai_gateway_data(data): transformed = {} + if not data: + return transformed for row in data: + # Rows without token pricing or token limits (video/embedding models) previously KeyError'd the whole sync + if any(row.get(k) is None for k in ("context_window", "max_tokens")) or any( + row.get("pricing", {}).get(k) is None for k in ("input", "output") + ): + continue obj = { "max_tokens": row["context_window"], "input_cost_per_token": float(row["pricing"]["input"]), diff --git a/tests/test_litellm/test_auto_update_price_and_context_window_file.py b/tests/test_litellm/test_auto_update_price_and_context_window_file.py index 7dbd24a1b81..8dc43100544 100644 --- a/tests/test_litellm/test_auto_update_price_and_context_window_file.py +++ b/tests/test_litellm/test_auto_update_price_and_context_window_file.py @@ -115,9 +115,40 @@ def test_transform_modalities_set_vision_image_and_video_flags(sync_module): assert entry_text["supports_video_input"] is False -def test_transform_survives_failed_fetch(sync_module): +def test_transforms_survive_failed_fetch(sync_module): assert sync_module.transform_friendli_data(None, {}) == {} assert sync_module.transform_friendli_data([], {}) == {} + assert sync_module.transform_openrouter_data(None) == {} + assert sync_module.transform_vercel_ai_gateway_data(None) == {} + + +def test_vercel_transform_skips_rows_without_token_pricing_or_limits(sync_module): + rows = [ + { + "id": "wan-video", + "pricing": {"video_duration_pricing": [{"resolution": "720p", "cost_per_second": "0.1"}]}, + }, + { + "id": "qwen3-embedding", + "context_window": 32768, + "max_tokens": 32768, + "pricing": {"input": "0.00000001"}, + }, + { + "id": "no-limits-chat", + "pricing": {"input": "0.000001", "output": "0.000002"}, + }, + { + "id": "good-chat", + "context_window": 128000, + "max_tokens": 8192, + "pricing": {"input": "0.000001", "output": "0.000002"}, + }, + ] + transformed = sync_module.transform_vercel_ai_gateway_data(rows) + assert list(transformed) == ["vercel_ai_gateway/good-chat"] + assert transformed["vercel_ai_gateway/good-chat"]["input_cost_per_token"] == 1e-06 + assert transformed["vercel_ai_gateway/good-chat"]["output_cost_per_token"] == 2e-06 def test_transform_inherits_allowlisted_keys_from_base_model_entry(sync_module):