refactor: regenerate model_prices backup at build time - #27147
Conversation
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
Congrats! CodSpeed is installed 🎉
You will start to see performance impacts in the reports once the benchmarks are run from your default branch.
|
… litellm_remove_redundant_model_cost_backup_file # Conflicts: # litellm/model_prices_and_context_window_backup.json
Greptile SummaryThis PR treats Confidence Score: 5/5Safe to merge; the implementation is sound and all previous blocking concerns are addressed. No P0 or P1 findings. The single P2 (bundled-backup code path not exercised in CI) is a coverage gap, not a production defect — the backup is still materialised correctly at build time and the FileNotFoundError re-raise makes any omission immediately actionable. tests/local_testing/test_get_model_file.py — the bundled-backup branch of load_local_model_cost_map() lacks a CI test
|
| Filename | Overview |
|---|---|
| litellm/litellm_core_utils/get_model_cost_map.py | load_local_model_cost_map() now resolves to repo-root JSON in dev and bundled backup in wheels; previous thread concerns (missing-file error, depth heuristic, logging) are all addressed |
| Dockerfile | Adds cp step after COPY and before uv sync --no-editable to materialize the backup JSON into the wheel; ordering is correct |
| docker/Dockerfile.non_root | Same cp step at line 56, before the uv sync --no-editable at line 78+; ordering verified correct |
| docker/Dockerfile.alpine | cp step added in correct position before uv sync --no-editable |
| docker/Dockerfile.database | cp step added in correct position before uv sync --no-editable |
| docker/Dockerfile.dev | cp step added in correct position before uv sync --no-editable |
| ci_cd/check_files_match.py | Deleted; confirmed no remaining references in the repo — removal is safe |
| tests/local_testing/test_get_model_file.py | test_get_backup_model_cost_map replaced with test_load_local_model_cost_map; the bundled-backup code path (files("litellm")...) is no longer exercised in CI since the file is gitignored in source checkouts |
| .gitignore | Backup JSON correctly gitignored since it is now a build artifact |
Reviews (2): Last reviewed commit: "fix(get_model_cost_map): give an actiona..." | Re-trigger Greptile
…olved path Address PR feedback: - Witness the repo root with pyproject.toml so moving get_model_cost_map.py cannot silently break detection (parents[2] alone was depth-fragile). - Emit verbose_logger.debug at each branch so the resolved file is observable when diagnosing pricing issues.
… is missing Wrap the package-resource load so that a wheel built without the prerequisite cp step (e.g. a manual `uv build`) surfaces a message that names the missing file, points at the canonical build steps, and shows the one-liner fix. The original FileNotFoundError is preserved via `raise ... from e`. Addresses Greptile review P1.
|
🤖 litellm-agent: This PR's commits have been merged into the staging branch Staging PR: #27162 |
|
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
Title
refactor: regenerate model_prices backup at build time
Relevant issues
Closes #27124
(Replays the design of the reverted #16590 against the current release pipeline.)
Background
litellmships two model-pricing JSONs that must stay byte-identical:model_prices_and_context_window.json(repo root, edited in PRs)litellm/model_prices_and_context_window_backup.json(mirror used as the local fallback)In practice they drift — features land in the root file but the backup is forgotten. The two files are conceptually one piece of data with two storage locations. Treat the second one as a build artefact of the first.
Pre-Submission checklist
tests/(touchedtests/local_testing/test_get_model_file.pyandtests/test_litellm/test_deepseek_model_metadata.pyto load via the public helper)make test-unitpasses locally for the touched suites (40 / 40 green:test_get_model_file,test_deepseek_model_metadata,test_model_cost_map_resilience)Type
🧹 Refactoring
Solution
Stop committing the backup. Make it a generated build artefact instead.
Code
litellm/litellm_core_utils/get_model_cost_map.py—load_local_model_cost_map()now resolves to the repo-root JSON when running from a source checkout (editable install), and falls back to the bundledlitellm/model_prices_and_context_window_backup.jsonin installed wheels. Single source of truth in dev; production behaviour unchanged.Build / packaging
.github/workflows/publish_to_pypi.yml— already copies root → backup beforeuv build(no change needed; line 124-125).uv sync --no-editable) now run the samecpafterCOPY . .and before the wheel-producing sync:Dockerfile,docker/Dockerfile.alpine,docker/Dockerfile.non_root,docker/Dockerfile.dev,docker/Dockerfile.database.Dockerfile.health_check,Dockerfile.custom_ui,deploy/Dockerfile.ghcr_base,docker/build_from_pip/Dockerfile.build_from_pipare unaffected (they don't build a wheel from source — they install another tool, base off a pre-built image, orpip installfrom PyPI).Cleanup
litellm/model_prices_and_context_window_backup.json— deleted; gitignored.ci_cd/check_files_match.py— removed (no longer invoked by any workflow; checked the root JSON against its own generated copy, which is meaningless once one is the artefact of the other).Tests
tests/local_testing/test_get_model_file.pyandtests/test_litellm/test_deepseek_model_metadata.pypreviously bypassed the helper and opened the file directly viaimportlib.resources.open_text(...)/os.path.dirname(litellm.__file__) + "/...". They now go throughGetModelCostMap.load_local_model_cost_map()and so inherit the dev/prod resolution automatically.Resulting flow
publish_to_pypi.ymlbuildcpstepRUN cpsteppip install litellm)The root JSON remains the single editable source of truth; every other "copy" is regenerated automatically wherever a wheel is built. No manual sync, no drift class.
Local verification
make test-unitfor the touched suites: 40 / 40 passing.LITELLM_LOCAL_MODEL_COST_MAP=True python -c "from litellm.litellm_core_utils.get_model_cost_map import GetModelCostMap; print(len(GetModelCostMap.load_local_model_cost_map()))"→2692(and source info reportssource=local, is_env_forced=True).uv run black --checkon the touched files: clean.Test plan
litellm/model_prices_and_context_window_backup.jsonin/app/.venv/.../site-packages/litellm/LITELLM_LOCAL_MODEL_COST_MAP=Trueend-to-end against a built wheel and verify the local fallback resolves