Merge pull request #40179 from BerriAI/litellm_lit_2133_cost_map_provenance

feat(cost_map): report which revision of the price map the proxy is serving
This commit is contained in:
Mateo Wang 2026-09-08 18:42:19 -07:00 committed by GitHub
commit d75aa4445d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 372 additions and 28 deletions

View file

@ -9,17 +9,19 @@ export LITELLM_LOCAL_MODEL_COST_MAP=True
"""
import asyncio
import hashlib
import json
import os
import random
import time
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from dataclasses import dataclass, replace
from datetime import datetime, timezone
from importlib.resources import files
from typing import Final, Protocol
import httpx
from typing_extensions import ReadOnly, TypedDict
from litellm import verbose_logger
from litellm.constants import (
@ -42,6 +44,10 @@ def _count_model_entries(model_cost: dict) -> int:
return sum(1 for key in model_cost if key not in RESERVED_TOP_LEVEL_KEYS)
def git_blob_id(body: bytes) -> str:
return hashlib.sha1(b"blob %d\0" % len(body) + body, usedforsecurity=False).hexdigest()
class GetModelCostMap:
"""
Handles fetching, validating, and loading the model cost map.
@ -53,15 +59,24 @@ class GetModelCostMap:
_backup_model_count: int = -1 # -1 = not yet loaded
@staticmethod
def read_local_model_cost_map_bytes() -> bytes:
return files("litellm").joinpath("model_prices_and_context_window_backup.json").read_bytes()
@staticmethod
def read_local_model_cost_map_text() -> str:
return files("litellm").joinpath("model_prices_and_context_window_backup.json").read_text(encoding="utf-8")
return GetModelCostMap.read_local_model_cost_map_bytes().decode("utf-8")
@staticmethod
def load_local_model_cost_map_with_revision() -> "ModelCostMapReloaded":
body: Final = GetModelCostMap.read_local_model_cost_map_bytes()
content: Final = json.loads(body)
return ModelCostMapReloaded(model_cost_map=content, revision=git_blob_id(body))
@staticmethod
def load_local_model_cost_map() -> dict:
"""Load the local backup model cost map bundled with the package."""
content: Final = json.loads(GetModelCostMap.read_local_model_cost_map_text())
return content
return GetModelCostMap.load_local_model_cost_map_with_revision().model_cost_map
@classmethod
def _get_backup_model_count(cls) -> int:
@ -166,6 +181,8 @@ MODEL_COST_MAP_FETCH_MAX_WAIT_SECONDS: Final = 30.0
@dataclass(frozen=True, slots=True)
class ModelCostMapReloaded:
model_cost_map: dict # mutable-ok: adopted as litellm.model_cost, whose consumer contract is a plain mutable dict
revision: str | None = None
etag: str | None = None
@dataclass(frozen=True, slots=True)
@ -254,7 +271,9 @@ def _classify_fetch_response(response: httpx.Response, url: str) -> _FetchAttemp
return ModelCostMapReloadUnavailable(reason=f"invalid JSON from {url}: {e}")
if not isinstance(parsed, dict):
return ModelCostMapReloadUnavailable(reason=f"expected a JSON object from {url}, got {type(parsed).__name__}")
return ModelCostMapReloaded(model_cost_map=parsed)
return ModelCostMapReloaded(
model_cost_map=parsed, revision=git_blob_id(response.content), etag=response.headers.get("etag")
)
def _next_retry_wait(
@ -328,13 +347,12 @@ async def refetch_model_cost_map(
map they already have.
"""
if os.getenv("LITELLM_LOCAL_MODEL_COST_MAP", "").lower() == "true":
_cost_map_source_info.loaded_at = datetime.now(timezone.utc)
_cost_map_source_info.source = "local"
_cost_map_source_info.url = None
_cost_map_source_info.is_env_forced = True
_cost_map_source_info.fallback_reason = None
return ModelCostMapReloaded(
model_cost_map=_finalize_model_cost_map(GetModelCostMap.load_local_model_cost_map())
)
return _finalize_loaded_model_cost_map(GetModelCostMap.load_local_model_cost_map_with_revision())
result: Final = await _fetch_remote_model_cost_map_with_retry(
url=url,
@ -355,11 +373,12 @@ async def refetch_model_cost_map(
backup_model_count=GetModelCostMap._get_backup_model_count(),
):
return ModelCostMapReloadUnavailable(reason=f"model cost map from {url} failed integrity validation")
_cost_map_source_info.loaded_at = datetime.now(timezone.utc)
_cost_map_source_info.source = "remote"
_cost_map_source_info.url = url
_cost_map_source_info.is_env_forced = False
_cost_map_source_info.fallback_reason = None
return ModelCostMapReloaded(model_cost_map=_finalize_model_cost_map(result.model_cost_map))
return _finalize_loaded_model_cost_map(result)
class ModelCostMapSourceInfo:
@ -370,13 +389,35 @@ class ModelCostMapSourceInfo:
is_env_forced: bool = False
fallback_reason: str | None = None
loaded_at: "datetime | None" = None
source_revision: str | None = None
etag: str | None = None
# Module-level singleton tracking the source of the current cost map
_cost_map_source_info: Final = ModelCostMapSourceInfo()
def get_model_cost_map_source_info() -> dict:
class CostMapProvenance(TypedDict):
source_revision: ReadOnly[str | None]
etag: ReadOnly[str | None]
class CostMapSourceInfo(CostMapProvenance):
source: ReadOnly[str]
url: ReadOnly[str | None]
is_env_forced: ReadOnly[bool]
fallback_reason: ReadOnly[str | None]
loaded_at: ReadOnly[str | None]
def get_model_cost_map_provenance() -> CostMapProvenance:
return {
"source_revision": _cost_map_source_info.source_revision,
"etag": _cost_map_source_info.etag,
}
def get_model_cost_map_source_info() -> CostMapSourceInfo:
"""
Return metadata about where the current model cost map was loaded from.
@ -385,12 +426,19 @@ def get_model_cost_map_source_info() -> dict:
- url: the remote URL attempted (or None for local-only)
- is_env_forced: True if LITELLM_LOCAL_MODEL_COST_MAP=True forced local usage
- fallback_reason: human-readable reason if remote failed and local was used
- loaded_at: ISO 8601 time this process last loaded the map
- source_revision: git blob id of the loaded file's bytes
- etag: the ETag of the remote fetch (None for the bundled backup)
"""
loaded_at: Final = _cost_map_source_info.loaded_at
return {
"source": _cost_map_source_info.source,
"url": _cost_map_source_info.url,
"is_env_forced": _cost_map_source_info.is_env_forced,
"fallback_reason": _cost_map_source_info.fallback_reason,
"loaded_at": loaded_at.isoformat() if loaded_at is not None else None,
"source_revision": _cost_map_source_info.source_revision,
"etag": _cost_map_source_info.etag,
}
@ -466,6 +514,12 @@ def _finalize_model_cost_map(model_cost: dict) -> dict:
return _expand_model_aliases(model_cost)
def _finalize_loaded_model_cost_map(loaded: ModelCostMapReloaded) -> ModelCostMapReloaded:
_cost_map_source_info.source_revision = loaded.revision
_cost_map_source_info.etag = loaded.etag
return replace(loaded, model_cost_map=_finalize_model_cost_map(loaded.model_cost_map))
def get_model_cost_map(
url: str,
timeout: int = 5,
@ -494,7 +548,7 @@ def get_model_cost_map(
_cost_map_source_info.url = None
_cost_map_source_info.is_env_forced = True
_cost_map_source_info.fallback_reason = None
return _finalize_model_cost_map(GetModelCostMap.load_local_model_cost_map())
return _finalize_loaded_model_cost_map(GetModelCostMap.load_local_model_cost_map_with_revision()).model_cost_map
_cost_map_source_info.url = url
_cost_map_source_info.is_env_forced = False
@ -515,7 +569,7 @@ def get_model_cost_map(
)
_cost_map_source_info.source = "local"
_cost_map_source_info.fallback_reason = f"Remote fetch failed: {result.reason}"
return _finalize_model_cost_map(GetModelCostMap.load_local_model_cost_map())
return _finalize_loaded_model_cost_map(GetModelCostMap.load_local_model_cost_map_with_revision()).model_cost_map
content: Final = result.model_cost_map
# Validate using cached count (cheap int comparison, no file I/O)
@ -529,8 +583,8 @@ def get_model_cost_map(
)
_cost_map_source_info.source = "local"
_cost_map_source_info.fallback_reason = "Remote data failed integrity validation"
return _finalize_model_cost_map(GetModelCostMap.load_local_model_cost_map())
return _finalize_loaded_model_cost_map(GetModelCostMap.load_local_model_cost_map_with_revision()).model_cost_map
_cost_map_source_info.source = "remote"
_cost_map_source_info.fallback_reason = None
return _finalize_model_cost_map(content)
return _finalize_loaded_model_cost_map(result).model_cost_map

View file

@ -17750,6 +17750,7 @@ async def reload_model_cost_map(
# Immediately reload the model cost map in the current pod
from litellm.litellm_core_utils.get_model_cost_map import (
ModelCostMapReloadUnavailable,
get_model_cost_map_provenance,
refetch_model_cost_map,
)
@ -17763,6 +17764,7 @@ async def reload_model_cost_map(
models_count = _swap_in_model_cost_map(reload_result.model_cost_map)
current_time = utc_now()
proxy_config.model_cost_map_loaded_at = current_time
provenance: Final = get_model_cost_map_provenance()
# Publish a new revision so every other pod reloads on its next poll; this pod has
# already served it, so adopt it here rather than reloading again a tick later
@ -17777,6 +17779,7 @@ async def reload_model_cost_map(
"status": "success",
"models_count": models_count,
"timestamp": current_time.isoformat(),
**provenance,
}
except HTTPException:
raise
@ -17897,12 +17900,17 @@ async def get_model_cost_map_reload_status(
try:
global prisma_client
from litellm.litellm_core_utils.get_model_cost_map import (
get_model_cost_map_provenance,
)
provenance: Final = get_model_cost_map_provenance()
if prisma_client is None:
verbose_proxy_logger.info("No database connection, returning not scheduled")
return reload_schedule_status(None)
return {**reload_schedule_status(None), **provenance}
return reload_schedule_status(await read_reload_schedule(prisma_client, MODEL_COST_MAP_RELOAD_PARAM_NAME))
schedule: Final = await read_reload_schedule(prisma_client, MODEL_COST_MAP_RELOAD_PARAM_NAME)
return {**reload_schedule_status(schedule), **provenance}
except Exception as e:
verbose_proxy_logger.exception("Failed to get model cost map reload status: %s", e)
raise HTTPException(
@ -17930,6 +17938,9 @@ async def get_model_cost_map_source(
- url: the remote URL that was attempted (null when env-forced local)
- is_env_forced: true if LITELLM_LOCAL_MODEL_COST_MAP=True forced local usage
- fallback_reason: human-readable reason why remote failed (null on success)
- loaded_at: when this pod last loaded the map
- source_revision: git blob id of the loaded file, what git rev-parse <commit>:<path> prints for it
- etag: the ETag of the remote fetch (null for the bundled backup)
- model_count: number of models in the currently loaded cost map
"""
# Read-only source info — admin viewers can read.

View file

@ -20,6 +20,8 @@ from litellm.litellm_core_utils.get_model_cost_map import (
GetModelCostMap,
_count_model_entries,
_finalize_model_cost_map,
get_model_cost_map_provenance,
git_blob_id,
)
@ -31,6 +33,16 @@ def _load_root_cost_map() -> dict:
return json.load(f)
def _bundled_blob_id() -> str:
path = os.path.join(os.path.dirname(__file__), "../../../litellm/model_prices_and_context_window_backup.json")
with open(path, "rb") as f:
return git_blob_id(f.read())
def test_git_blob_id_is_what_git_hash_object_prints():
assert git_blob_id(b'{"gpt-5.4-mini": {"mode": "chat"}}\n') == "18b9a8381e13a3b38a2128f184f631f95829e987"
def _make_models(n: int) -> dict:
return {
f"model-{i}": {"litellm_provider": "openai", "mode": "chat"} for i in range(n)
@ -298,14 +310,13 @@ def test_openrouter_catalog_costs_match_live_headline_rates(cost_map: dict):
assert entry["output_cost_per_token"] != stale_out, model
def test_get_model_cost_map_stamps_loaded_at(monkeypatch):
def test_get_model_cost_map_stamps_loaded_at():
"""The load time feeds each pod's reload-due decision; a load that does not stamp it
would make manual reload requests race the proxy's startup"""
from datetime import datetime, timezone
from litellm.litellm_core_utils import get_model_cost_map as module
monkeypatch.setattr(module._cost_map_source_info, "loaded_at", None)
client, _calls = _mock_client(
[httpx.Response(200, content=_real_map_bytes())], client_cls=httpx.Client
)
@ -323,6 +334,7 @@ def test_get_model_cost_map_stamps_loaded_at(monkeypatch):
import functools
import random
from datetime import datetime, timezone
import httpx
@ -500,6 +512,67 @@ async def test_refetch_respects_local_env_override(monkeypatch):
assert len(result.model_cost_map) > 100
@pytest.mark.asyncio
async def test_refetch_records_the_blob_id_of_the_bytes_served_and_the_fetch_etag():
body = _real_map_bytes()
client, _ = _mock_client([httpx.Response(200, headers={"ETag": 'W/"abc123"'}, content=body)])
result = await refetch_model_cost_map(url=_URL, sleep=_SleepRecorder(), rng=random.Random(0), client=client)
assert isinstance(result, ModelCostMapReloaded)
assert result.revision == git_blob_id(body)
assert result.etag == 'W/"abc123"'
assert get_model_cost_map_provenance() == {"source_revision": git_blob_id(body), "etag": 'W/"abc123"'}
@pytest.mark.asyncio
async def test_refetch_revision_follows_the_bytes_not_the_url():
edited = json.loads(_real_map_bytes())
edited["gpt-5.4-mini"]["input_cost_per_token"] = 0.5
client, _ = _mock_client(
[httpx.Response(200, content=_real_map_bytes()), httpx.Response(200, content=json.dumps(edited).encode())]
)
first = await refetch_model_cost_map(url=_URL, sleep=_SleepRecorder(), rng=random.Random(0), client=client)
second = await refetch_model_cost_map(url=_URL, sleep=_SleepRecorder(), rng=random.Random(0), client=client)
assert isinstance(first, ModelCostMapReloaded) and isinstance(second, ModelCostMapReloaded)
assert first.revision != second.revision
assert get_model_cost_map_provenance()["source_revision"] == second.revision
@pytest.mark.asyncio
async def test_refetch_local_override_reports_the_bundled_blob_id_without_an_etag(monkeypatch):
remote, _ = _mock_client([httpx.Response(200, headers={"ETag": 'W/"remote"'}, content=_real_map_bytes())])
await refetch_model_cost_map(url=_URL, sleep=_SleepRecorder(), rng=random.Random(0), client=remote)
monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True")
result = await refetch_model_cost_map(url=_URL, sleep=_SleepRecorder(), rng=random.Random(0))
assert isinstance(result, ModelCostMapReloaded)
assert result.revision == _bundled_blob_id()
assert get_model_cost_map_provenance() == {"source_revision": _bundled_blob_id(), "etag": None}
@pytest.mark.asyncio
async def test_refetch_stamps_loaded_at_on_remote_and_local_reloads(monkeypatch):
from litellm.litellm_core_utils import get_model_cost_map as module
client, _ = _mock_client([httpx.Response(200, content=_real_map_bytes())])
before_remote = datetime.now(timezone.utc)
await refetch_model_cost_map(url=_URL, sleep=_SleepRecorder(), rng=random.Random(0), client=client)
remote_loaded_at = module.get_model_cost_map_loaded_at()
assert remote_loaded_at is not None
assert before_remote <= remote_loaded_at <= datetime.now(timezone.utc)
monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True")
before_local = datetime.now(timezone.utc)
await refetch_model_cost_map(url=_URL, sleep=_SleepRecorder(), rng=random.Random(0))
local_loaded_at = module.get_model_cost_map_loaded_at()
assert local_loaded_at is not None
assert before_local <= local_loaded_at <= datetime.now(timezone.utc)
# ---------------------------------------------------------------------------
# get_model_cost_map: the boot-time load retries transient failures like a reload does
# ---------------------------------------------------------------------------
@ -592,3 +665,49 @@ def test_boot_load_respects_local_env_override(monkeypatch):
)
assert len(cost_map) > 100
assert get_model_cost_map_source_info()["is_env_forced"] is True
def test_boot_load_records_the_blob_id_of_the_bytes_served_and_the_fetch_etag():
body = _real_map_bytes()
client, _ = _mock_client([httpx.Response(200, headers={"ETag": 'W/"boot"'}, content=body)], client_cls=httpx.Client)
get_model_cost_map(url=_URL, sleep=_SyncSleepRecorder(), rng=random.Random(0), client=client)
source = get_model_cost_map_source_info()
assert source["source"] == "remote"
assert source["etag"] == 'W/"boot"'
assert source["source_revision"] == git_blob_id(body)
assert source["loaded_at"] is not None
def test_boot_load_fallback_to_the_backup_reports_its_blob_id_and_drops_the_remote_etag():
remote, _ = _mock_client(
[httpx.Response(200, headers={"ETag": 'W/"boot"'}, content=_real_map_bytes())], client_cls=httpx.Client
)
get_model_cost_map(url=_URL, sleep=_SyncSleepRecorder(), rng=random.Random(0), client=remote)
failing, _ = _mock_client([httpx.Response(404)], client_cls=httpx.Client)
get_model_cost_map(url=_URL, sleep=_SyncSleepRecorder(), rng=random.Random(0), client=failing)
source = get_model_cost_map_source_info()
assert source["source"] == "local"
assert source["etag"] is None
assert source["source_revision"] == _bundled_blob_id()
def test_boot_load_that_fails_the_integrity_check_reports_the_backup_not_the_rejected_fetch():
remote, _ = _mock_client(
[httpx.Response(200, headers={"ETag": 'W/"boot"'}, content=_real_map_bytes())], client_cls=httpx.Client
)
get_model_cost_map(url=_URL, sleep=_SyncSleepRecorder(), rng=random.Random(0), client=remote)
shrunk_body = b'{"gpt-5.4-mini": {"mode": "chat", "input_cost_per_token": 1e-06, "output_cost_per_token": 2e-06}}'
shrunk, _ = _mock_client([httpx.Response(200, headers={"ETag": 'W/"shrunk"'}, content=shrunk_body)], client_cls=httpx.Client)
get_model_cost_map(url=_URL, sleep=_SyncSleepRecorder(), rng=random.Random(0), client=shrunk)
source = get_model_cost_map_source_info()
assert source["source"] == "local"
assert source["fallback_reason"] == "Remote data failed integrity validation"
assert source["etag"] is None
assert source["source_revision"] == _bundled_blob_id()
assert source["source_revision"] != git_blob_id(shrunk_body)

View file

@ -11,15 +11,21 @@ Routes covered:
from __future__ import annotations
import json
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock
from litellm.litellm_core_utils.get_model_cost_map import get_model_cost_map_provenance
from .conftest import VOLATILE_KEYS, normalize
# Some response bodies include a "timestamp" — extend the volatile set so
# dict-equality assertions remain stable.
_VOLATILE = VOLATILE_KEYS | frozenset({"timestamp"})
_SERVED_ETAG = 'W/"cost-map-etag"'
_ROOT_COST_MAP = Path(__file__).resolve().parents[4] / "model_prices_and_context_window.json"
# ---------------------------------------------------------------------------
# Helpers
@ -83,6 +89,7 @@ def test_reload_model_cost_map_happy(client, auth_as, monkeypatch, mock_prisma):
"status": "success",
"models_count": 2,
"timestamp": "<VOLATILE>",
**get_model_cost_map_provenance(),
}
assert table.upsert.await_count == 1
update_payload = table.upsert.await_args.kwargs["data"]["update"]
@ -90,6 +97,54 @@ def test_reload_model_cost_map_happy(client, auth_as, monkeypatch, mock_prisma):
assert update_payload["reload_revision"] == {"increment": 1}
def test_reload_model_cost_map_surfaces_the_blob_id_of_the_bytes_served_on_every_status_surface(
client, auth_as, monkeypatch, mock_prisma
):
import httpx
import litellm
from litellm.litellm_core_utils.get_model_cost_map import git_blob_id
from litellm.proxy import proxy_server as ps
from litellm.proxy._types import LitellmUserRoles
_attach_litellm_config(mock_prisma)
monkeypatch.setattr(ps, "prisma_client", mock_prisma)
monkeypatch.delenv("LITELLM_LOCAL_MODEL_COST_MAP", raising=False)
body = _ROOT_COST_MAP.read_bytes()
expected = {"source_revision": git_blob_id(body), "etag": _SERVED_ETAG}
served = httpx.Response(200, headers={"ETag": _SERVED_ETAG}, content=body)
monkeypatch.setattr(
"litellm.litellm_core_utils.get_model_cost_map._default_reload_client",
lambda: httpx.AsyncClient(transport=httpx.MockTransport(lambda request: served)),
)
monkeypatch.setattr("litellm.add_known_models", lambda model_cost_map=None: None)
monkeypatch.setattr("litellm.model_cost", {}, raising=False)
async def _fake_invalidate(name):
return None
monkeypatch.setattr(ps, "invalidate_config_param", _fake_invalidate)
with auth_as(LitellmUserRoles.PROXY_ADMIN):
reload_response = client.post("/reload/model_cost_map")
source_response = client.get("/model/cost_map/source")
status_response = client.get("/schedule/model_cost_map_reload/status")
public_response = client.get("/public/litellm_model_cost_map")
assert reload_response.status_code == 200
reload_body = reload_response.json()
assert {key: reload_body[key] for key in expected} == expected
assert source_response.status_code == 200
source_body = source_response.json()
assert {key: source_body[key] for key in expected} == expected
assert source_body["source"] == "remote"
assert status_response.status_code == 200
assert {key: status_response.json()[key] for key in expected} == expected
assert public_response.status_code == 200
assert "gpt-4o" in public_response.json()
assert reload_body["models_count"] == len(litellm.model_cost)
def test_reload_model_cost_map_fetch_failure_502_keeps_map(
client, auth_as, monkeypatch, mock_prisma
):
@ -270,7 +325,7 @@ def test_cancel_model_cost_map_reload_no_db_500(client, auth_as, monkeypatch):
def test_get_model_cost_map_reload_status_no_db_not_scheduled(
client, auth_as, monkeypatch
):
"""No prisma client → returns the not-scheduled shape (4 keys, all-null)."""
"""No prisma client → returns the not-scheduled shape (all-null) plus the cost map provenance."""
from litellm.proxy import proxy_server as ps
from litellm.proxy._types import LitellmUserRoles
@ -283,6 +338,7 @@ def test_get_model_cost_map_reload_status_no_db_not_scheduled(
"interval_hours": None,
"last_run": None,
"next_run": None,
**get_model_cost_map_provenance(),
}
@ -309,6 +365,7 @@ def test_get_model_cost_map_reload_status_scheduled(
"interval_hours": 12,
"last_run": None,
"next_run": None,
**get_model_cost_map_provenance(),
}
@ -337,6 +394,7 @@ def test_get_model_cost_map_reload_status_reports_persisted_last_run(
"interval_hours": 6,
"last_run": "2024-01-01T06:00:00+00:00",
"next_run": "2024-01-01T12:00:00+00:00",
**get_model_cost_map_provenance(),
}
@ -365,6 +423,7 @@ def test_get_model_cost_map_reload_status_no_config_not_scheduled(
"interval_hours": None,
"last_run": None,
"next_run": None,
**get_model_cost_map_provenance(),
}
@ -391,6 +450,8 @@ def test_get_model_cost_map_source_happy(client, auth_as, monkeypatch):
"url": "https://example.invalid/cost_map.json",
"is_env_forced": False,
"fallback_reason": None,
"loaded_at": "2026-09-07T01:02:03+00:00",
**get_model_cost_map_provenance(),
}
monkeypatch.setattr(
"litellm.litellm_core_utils.get_model_cost_map.get_model_cost_map_source_info",
@ -406,6 +467,8 @@ def test_get_model_cost_map_source_happy(client, auth_as, monkeypatch):
"url": "https://example.invalid/cost_map.json",
"is_env_forced": False,
"fallback_reason": None,
"loaded_at": "2026-09-07T01:02:03+00:00",
**get_model_cost_map_provenance(),
"model_count": 3,
}

View file

@ -32,8 +32,16 @@ const remoteSource = {
url: "https://pricing.example.test/model_prices.json",
is_env_forced: false,
fallback_reason: null,
loaded_at: null,
source_revision: null,
etag: null,
model_count: 1234,
};
const provenance = {
loaded_at: "2026-09-07T10:00:00Z",
source_revision: "4273ec544726bf255ea920533e209e6022653bb4",
etag: 'W/"eb8e9a53f4cc284b"',
};
describe("PriceDataReload", () => {
beforeEach(() => {
@ -51,6 +59,43 @@ describe("PriceDataReload", () => {
expect(screen.getByText("No periodic reload scheduled")).toBeInTheDocument();
});
it("shows which revision of the cost map is loaded when the source reports one", async () => {
vi.mocked(getModelCostMapSource).mockResolvedValue({ ...remoteSource, ...provenance } as never);
render(<PriceDataReload accessToken="sk-test" />);
expect(await screen.findByText("Source revision:")).toBeInTheDocument();
expect(screen.getByText("4273ec544726")).toBeInTheDocument();
expect(screen.getByText("ETag:")).toBeInTheDocument();
expect(screen.getByText('W/"eb8e9a53f4cc284b"')).toBeInTheDocument();
expect(screen.getByText("Loaded at:")).toBeInTheDocument();
expect(screen.getByText(/worker that answered this request/)).toBeInTheDocument();
expect(screen.getByText(/Last run time is the latest reload any worker recorded/)).toBeInTheDocument();
expect(screen.getByText(new Date(provenance.loaded_at).toLocaleString())).toBeInTheDocument();
});
it("shows a malformed loaded_at as-is instead of Invalid Date", async () => {
vi.mocked(getModelCostMapSource).mockResolvedValue({
...remoteSource,
...provenance,
loaded_at: "yesterday-ish",
} as never);
render(<PriceDataReload accessToken="sk-test" />);
expect(await screen.findByText("Loaded at:")).toBeInTheDocument();
expect(screen.getByText("yesterday-ish")).toBeInTheDocument();
expect(screen.queryByText("Invalid Date")).not.toBeInTheDocument();
});
it("hides the provenance rows when the loaded map carries no stamp", async () => {
render(<PriceDataReload accessToken="sk-test" />);
expect(await screen.findByText("Pricing Data Source")).toBeInTheDocument();
expect(screen.queryByText("Source revision:")).not.toBeInTheDocument();
expect(screen.queryByText("ETag:")).not.toBeInTheDocument();
expect(screen.queryByText("Loaded at:")).not.toBeInTheDocument();
expect(screen.queryByText(/worker that answered this request/)).not.toBeInTheDocument();
});
it("confirms an immediate reload and refreshes dependent data", async () => {
const user = userEvent.setup();
const onReloadSuccess = vi.fn();

View file

@ -49,9 +49,16 @@ interface CostMapSourceInfo {
url: string | null;
is_env_forced: boolean;
fallback_reason: string | null;
loaded_at: string | null;
source_revision: string | null;
etag: string | null;
model_count: number;
}
const SHORT_REVISION_LENGTH = 12;
const shortRevision = (revision: string) => revision.slice(0, SHORT_REVISION_LENGTH);
const EMPTY_RELOAD_STATUS: ReloadStatus = {
scheduled: false,
interval_hours: null,
@ -89,6 +96,55 @@ const isValidReloadInterval = (value: number) => {
return value >= 1 && value <= 168;
};
const formatDateTime = (dateTimeString: string | null) => {
if (!dateTimeString) return "Never";
const parsed = new Date(dateTimeString);
return Number.isNaN(parsed.getTime()) ? dateTimeString : parsed.toLocaleString();
};
const CostMapProvenanceRows: React.FC<{ sourceInfo: CostMapSourceInfo }> = ({ sourceInfo }) => (
<>
{sourceInfo.source_revision && (
<div className="flex items-center justify-between gap-2 text-xs">
<span className="text-muted-foreground">Source revision:</span>
<Tooltip>
<TooltipTrigger render={<code className="font-mono" />}>
{shortRevision(sourceInfo.source_revision)}
</TooltipTrigger>
<TooltipContent>{sourceInfo.source_revision}</TooltipContent>
</Tooltip>
</div>
)}
{sourceInfo.etag && (
<div className="flex items-center justify-between gap-2 text-xs">
<span className="text-muted-foreground">ETag:</span>
<Tooltip>
<TooltipTrigger render={<code className="max-w-60 truncate font-mono" />}>{sourceInfo.etag}</TooltipTrigger>
<TooltipContent>{sourceInfo.etag}</TooltipContent>
</Tooltip>
</div>
)}
{sourceInfo.loaded_at && (
<div className="flex items-center justify-between text-xs">
<span className="text-muted-foreground">Loaded at:</span>
<span className="font-medium">{formatDateTime(sourceInfo.loaded_at)}</span>
</div>
)}
{sourceInfo.loaded_at && (
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
<Info className="size-3.5 shrink-0" />
<span>
Reported by the worker that answered this request. Other workers pick up a reload on their next poll, and the
Last run time is the latest reload any worker recorded
</span>
</div>
)}
</>
);
const PriceDataReload: React.FC<PriceDataReloadProps> = ({
accessToken,
onReloadSuccess,
@ -227,15 +283,6 @@ const PriceDataReload: React.FC<PriceDataReloadProps> = ({
}
};
const formatDateTime = (dateTimeString: string | null) => {
if (!dateTimeString) return "Never";
try {
return new Date(dateTimeString).toLocaleString();
} catch {
return dateTimeString;
}
};
const getStatusText = () => {
if (!reloadStatus?.scheduled) return "Not scheduled";
if (!reloadStatus.last_run) return "Ready";
@ -334,6 +381,8 @@ const PriceDataReload: React.FC<PriceDataReloadProps> = ({
</div>
)}
<CostMapProvenanceRows sourceInfo={sourceInfo} />
{sourceInfo.is_env_forced && (
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
<Info className="size-3.5 shrink-0" />

View file

@ -8745,6 +8745,9 @@ export interface paths {
* - url: the remote URL that was attempted (null when env-forced local)
* - is_env_forced: true if LITELLM_LOCAL_MODEL_COST_MAP=True forced local usage
* - fallback_reason: human-readable reason why remote failed (null on success)
* - loaded_at: when this pod last loaded the map
* - source_revision: git blob id of the loaded file, what git rev-parse <commit>:<path> prints for it
* - etag: the ETag of the remote fetch (null for the bundled backup)
* - model_count: number of models in the currently loaded cost map
*/
get: operations["get_model_cost_map_source_model_cost_map_source_get"];