From 044e6c28bdad165b3948156f4c302eae86698294 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Mon, 31 Aug 2026 16:05:43 -0700 Subject: [PATCH] fix(price-sync): skip Friendli rows without valid token prices so priced entries never get wiped --- ...to_update_price_and_context_window_file.py | 18 +++++++++++ ...to_update_price_and_context_window_file.py | 32 +++++++++++++++++++ 2 files changed, 50 insertions(+) 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 928452ee8d7..4c9a05bd4f0 100644 --- a/.github/scripts/auto_update_price_and_context_window_file.py +++ b/.github/scripts/auto_update_price_and_context_window_file.py @@ -1,6 +1,7 @@ import asyncio import aiohttp import json +import math from typing import Any # Asynchronously fetch data from a given URL @@ -60,6 +61,19 @@ def _reasoning_effort_levels(reasoning_options: list) -> list: return [level for level in REASONING_EFFORT_LEVEL_ORDER if level in offered] +def _valid_token_price(value: object) -> bool: + try: + price = float(value) # pyright: ignore[reportArgumentType] # non-numeric values are rejected via the except + except (TypeError, ValueError): + return False + return math.isfinite(price) and price >= 0 + + +def _has_valid_token_prices(pricing: dict | None) -> bool: + prices = pricing or {} + return _valid_token_price(prices.get("input")) and _valid_token_price(prices.get("output")) + + def _pricing(pricing: dict) -> dict: out: dict[str, Any] = {} if not pricing: @@ -88,6 +102,10 @@ def transform_friendli_data(data: list, local_data: dict) -> dict: if not data: return transformed for model in data: + # An unpriced row must never wholesale-replace an already priced local entry: + # missing prices cost-calculate as zero, silently zeroing tracked spend + if not _has_valid_token_prices(model.get("pricing")): + continue model_id = model["id"] base_model = model.get("base_model") or "" entry: dict[str, Any] = { 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 9766e54e9ff..435747e9a09 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,6 +115,38 @@ def test_transform_modalities_set_vision_image_and_video_flags(sync_module): assert entry_text["supports_video_input"] is False +def test_transform_skips_rows_without_valid_token_prices_so_priced_local_entries_survive(sync_module): + local = { + "friendliai/zai-org/GLM-Test": { + "litellm_provider": "friendliai", + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 5e-07, + } + } + unpriced_rows = [ + _reasoning_model(pricing={}), + _reasoning_model(pricing=None), + _reasoning_model(pricing={"input": "0.00000015"}), + _reasoning_model(pricing={"output": "0.0000005"}), + _reasoning_model(pricing={"input": "not-a-number", "output": "0.0000005"}), + _reasoning_model(pricing={"input": "-0.00000015", "output": "0.0000005"}), + _reasoning_model(pricing={"input": "inf", "output": "0.0000005"}), + _reasoning_model(pricing={"input": "nan", "output": "0.0000005"}), + ] + remote = sync_module.transform_friendli_data(unpriced_rows, local) + assert remote == {} + sync_module.sync_local_data_with_remote(local, remote, replace_keys=frozenset(remote)) + assert local["friendliai/zai-org/GLM-Test"]["input_cost_per_token"] == 1.5e-07 + assert local["friendliai/zai-org/GLM-Test"]["output_cost_per_token"] == 5e-07 + + +def test_transform_keeps_zero_priced_rows(sync_module): + free_model = _reasoning_model(pricing={"input": "0", "output": "0"}) + entry = sync_module.transform_friendli_data([free_model], {})["friendliai/zai-org/GLM-Test"] + assert entry["input_cost_per_token"] == 0.0 + assert entry["output_cost_per_token"] == 0.0 + + def test_transforms_survive_failed_fetch(sync_module): assert sync_module.transform_friendli_data(None, {}) == {} assert sync_module.transform_friendli_data([], {}) == {}