refactor: regenerate model_prices backup at build time

The local backup `litellm/model_prices_and_context_window_backup.json`
was a hand-edited mirror of the root `model_prices_and_context_window.json`.
The two routinely drifted (xAI grok-3 prompt-caching, deepseek capability
flags, etc.), masking real bugs in CI. Make the backup a generated build
artefact instead of a committed file:

- `get_model_cost_map.load_local_model_cost_map()` now reads the root JSON
  when available (source checkout / editable install) and falls back to
  the bundled package copy in installed wheels.
- The release pipeline already copies root -> backup before build
  (`publish_to_pypi.yml`); add the same step to the 5 Dockerfiles that
  build a wheel from source (`Dockerfile`, `docker/Dockerfile.{alpine,non_root,dev,database}`).
- Delete the committed backup JSON and `ci_cd/check_files_match.py`,
  gitignore the backup path.
- Tests that opened the backup directly now go through the helper.

Closes #27124
This commit is contained in:
Chesars 2026-05-04 21:35:10 -03:00
parent 934ecdca78
commit aadf54f994
11 changed files with 35 additions and 39656 deletions

1
.gitignore vendored
View file

@ -93,6 +93,7 @@ litellm_config.yaml
.vscode/launch.json
litellm/proxy/to_delete_loadtest_work/*
update_model_cost_map.py
litellm/model_prices_and_context_window_backup.json
tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py
scripts/test_vertex_ai_search.py
LAZY_LOADING_IMPROVEMENTS.md

View file

@ -47,6 +47,9 @@ RUN uv sync --frozen --no-install-project --no-install-workspace --no-default-gr
# Copy full source tree
COPY . .
# Generate the model-cost backup artefact inside the package before the wheel build (mirrors publish_to_pypi.yml).
RUN cp model_prices_and_context_window.json litellm/model_prices_and_context_window_backup.json
# Build Admin UI before final sync
RUN sed -i 's/\r$//' docker/build_admin_ui.sh && chmod +x docker/build_admin_ui.sh && ./docker/build_admin_ui.sh

View file

@ -1,32 +0,0 @@
import sys
import filecmp
import shutil
def main(argv=None):
print(
"Comparing model_prices_and_context_window and litellm/model_prices_and_context_window_backup.json files... checking if they match."
)
file1 = "model_prices_and_context_window.json"
file2 = "litellm/model_prices_and_context_window_backup.json"
cmp_result = filecmp.cmp(file1, file2, shallow=False)
if cmp_result:
print(f"Passed! Files {file1} and {file2} match.")
return 0
else:
print(
f"Failed! Files {file1} and {file2} do not match. Copying content from {file1} to {file2}."
)
copy_content(file1, file2)
return 1
def copy_content(source, destination):
shutil.copy2(source, destination)
if __name__ == "__main__":
sys.exit(main())

View file

@ -38,6 +38,9 @@ RUN uv sync --frozen --no-install-project --no-install-workspace --no-default-gr
# Copy full source tree
COPY . .
# Generate the model-cost backup artefact inside the package before the wheel build (mirrors publish_to_pypi.yml).
RUN cp model_prices_and_context_window.json litellm/model_prices_and_context_window_backup.json
# Install project and workspace packages (fast - deps already cached)
RUN uv sync --frozen --no-default-groups --no-editable \
--extra proxy \

View file

@ -46,6 +46,9 @@ RUN uv sync --frozen --no-install-project --no-install-workspace --no-default-gr
# Copy full source tree
COPY . .
# Generate the model-cost backup artefact inside the package before the wheel build (mirrors publish_to_pypi.yml).
RUN cp model_prices_and_context_window.json litellm/model_prices_and_context_window_backup.json
# Build Admin UI before final sync
RUN sed -i 's/\r$//' docker/build_admin_ui.sh && chmod +x docker/build_admin_ui.sh && ./docker/build_admin_ui.sh

View file

@ -47,6 +47,9 @@ RUN uv sync --frozen --no-install-project --no-install-workspace --no-default-gr
# Copy full source tree
COPY . .
# Generate the model-cost backup artefact inside the package before the wheel build (mirrors publish_to_pypi.yml).
RUN cp model_prices_and_context_window.json litellm/model_prices_and_context_window_backup.json
# Build Admin UI before final sync
RUN sed -i 's/\r$//' docker/build_admin_ui.sh && chmod +x docker/build_admin_ui.sh && ./docker/build_admin_ui.sh

View file

@ -52,6 +52,9 @@ RUN --mount=type=cache,target=/app/.cache/uv,id=litellm-uv-cache \
# Copy full source tree
COPY . .
# Generate the model-cost backup artefact inside the package before the wheel build (mirrors publish_to_pypi.yml).
RUN cp model_prices_and_context_window.json litellm/model_prices_and_context_window_backup.json
# Set non-root flag for build time consistency
ENV LITELLM_NON_ROOT=true

View file

@ -11,6 +11,7 @@ export LITELLM_LOCAL_MODEL_COST_MAP=True
import json
import os
from importlib.resources import files
from pathlib import Path
from typing import Dict, List, Optional
import httpx
@ -35,13 +36,18 @@ class GetModelCostMap:
@staticmethod
def load_local_model_cost_map() -> dict:
"""Load the local backup model cost map bundled with the package."""
content = json.loads(
"""Load the local model cost map: repo-root JSON in a source checkout, bundled package copy in an installed wheel."""
repo_root_json = (
Path(__file__).resolve().parents[2] / "model_prices_and_context_window.json"
)
if repo_root_json.is_file():
return json.loads(repo_root_json.read_text(encoding="utf-8"))
return json.loads(
files("litellm")
.joinpath("model_prices_and_context_window_backup.json")
.read_text(encoding="utf-8")
)
return content
@classmethod
def _get_backup_model_count(cls) -> int:

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,4 @@
import os, sys, traceback
import importlib.resources
import json
sys.path.insert(
0, os.path.abspath("../..")
@ -8,6 +6,8 @@ sys.path.insert(
import litellm
import pytest
from litellm.litellm_core_utils.get_model_cost_map import GetModelCostMap
def test_get_model_cost_map():
try:
@ -16,10 +16,8 @@ def test_get_model_cost_map():
pytest.fail(f"An exception occurred: {e}")
def test_get_backup_model_cost_map():
with importlib.resources.open_text(
"litellm", "model_prices_and_context_window_backup.json"
) as f:
print("inside backup")
content = json.load(f)
print("content", content)
def test_load_local_model_cost_map():
content = GetModelCostMap.load_local_model_cost_map()
assert (
isinstance(content, dict) and content
), "load_local_model_cost_map must return a non-empty dict"

View file

@ -18,6 +18,7 @@ sys.path.insert(
) # Adds the parent directory to the system path
import litellm
from litellm.litellm_core_utils.get_model_cost_map import GetModelCostMap
from litellm.utils import (
_supports_factory,
supports_response_schema,
@ -30,13 +31,8 @@ from litellm.utils import (
def _load_backup_json() -> dict:
"""Load the backup JSON directly from disk."""
backup_path = os.path.join(
os.path.dirname(litellm.__file__),
"model_prices_and_context_window_backup.json",
)
with open(backup_path, encoding="utf-8") as f:
return json.load(f)
"""Load the local model-cost JSON via the public helper (resolves to repo root in dev, bundled copy in wheel)."""
return GetModelCostMap.load_local_model_cost_map()
class TestDeepSeekModelCostEntries: