mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-12 08:42:18 +00:00
fix(cost-map): let alias lists win over alias_of rows in both loaders and never serve a malformed pointer
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
91e6cf2c27
commit
a54c42218a
4 changed files with 38 additions and 12 deletions
|
|
@ -159,13 +159,16 @@ impl Catalog {
|
|||
}
|
||||
};
|
||||
let row = read_row(&fields);
|
||||
let readable = row.problems.is_empty();
|
||||
problems.extend(
|
||||
row.problems
|
||||
.into_iter()
|
||||
.map(|problem| problem.prepend(&name)),
|
||||
);
|
||||
if let Some(target) = row.alias_of {
|
||||
pointer_rows.push((name.clone(), target));
|
||||
if readable {
|
||||
pointer_rows.push((name.clone(), target));
|
||||
}
|
||||
sections.push(Section {
|
||||
index,
|
||||
key: name,
|
||||
|
|
|
|||
|
|
@ -451,6 +451,19 @@ fn a_dangling_alias_of_row_is_rejected_and_dropped_from_the_written_document() {
|
|||
assert_eq!(written(&catalog), r#"{"Real":{"litellm_provider":"t"}}"#);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn an_alias_of_row_with_other_fields_is_never_served() {
|
||||
let parsed = loaded(json!({
|
||||
"Real": {"litellm_provider": "t"},
|
||||
"real-latest": {"alias_of": "Real", "mode": "chat"}
|
||||
}));
|
||||
assert!(parsed.value.lookup("real-latest").is_none());
|
||||
let (catalog, removed) = parsed.value.without_rejected(&parsed.errors);
|
||||
assert_eq!(removed.len(), 1);
|
||||
assert!(catalog.lookup("real-latest").is_none());
|
||||
assert_eq!(written(&catalog), r#"{"Real":{"litellm_provider":"t"}}"#);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn a_pointer_row_that_repeats_a_listed_alias_is_dropped_and_the_model_is_kept() {
|
||||
let parsed = loaded(json!({
|
||||
|
|
|
|||
|
|
@ -596,14 +596,6 @@ def _expand_model_aliases(model_cost: dict[str, dict[str, object]]) -> dict[str,
|
|||
alias_owners: Final[dict[str, str]] = {}
|
||||
keys_with_aliases: Final[list[str]] = []
|
||||
|
||||
for alias, target in pointer_rows.items():
|
||||
if target not in model_cost or target in pointer_rows:
|
||||
verbose_logger.warning(
|
||||
"LiteLLM model alias '%s' points at '%s', which is not a model entry, dropping it.", alias, target
|
||||
)
|
||||
continue
|
||||
alias_owners[alias] = target
|
||||
|
||||
for model_name, model_info in model_cost.items():
|
||||
aliases: object = model_info.get("aliases")
|
||||
if aliases is None or model_name in pointer_rows:
|
||||
|
|
@ -619,7 +611,7 @@ def _expand_model_aliases(model_cost: dict[str, dict[str, object]]) -> dict[str,
|
|||
if not aliases:
|
||||
continue
|
||||
for alias in aliases:
|
||||
if alias in model_cost:
|
||||
if alias in model_cost and alias not in pointer_rows:
|
||||
verbose_logger.warning(
|
||||
"LiteLLM model alias conflict: alias '%s' (from '%s') "
|
||||
"already exists as a canonical entry — skipping.",
|
||||
|
|
@ -637,6 +629,21 @@ def _expand_model_aliases(model_cost: dict[str, dict[str, object]]) -> dict[str,
|
|||
continue
|
||||
alias_owners[alias] = model_name
|
||||
|
||||
for alias, target in pointer_rows.items():
|
||||
if target not in model_cost or target in pointer_rows:
|
||||
verbose_logger.warning(
|
||||
"LiteLLM model alias '%s' points at '%s', which is not a model entry, dropping it.", alias, target
|
||||
)
|
||||
elif alias in alias_owners:
|
||||
verbose_logger.warning(
|
||||
"LiteLLM model alias conflict: alias '%s' (pointing at '%s') "
|
||||
"was already claimed by another entry — skipping.",
|
||||
alias,
|
||||
target,
|
||||
)
|
||||
else:
|
||||
alias_owners[alias] = target
|
||||
|
||||
# Remove the ``aliases`` key from entries so it doesn't pollute model info
|
||||
for key in keys_with_aliases:
|
||||
model_cost[key].pop("aliases", None)
|
||||
|
|
|
|||
|
|
@ -135,7 +135,9 @@ def test_alias_of_rows_are_served_as_their_target_and_dangling_ones_are_dropped(
|
|||
) -> None:
|
||||
raw: Final = {
|
||||
"real": {"litellm_provider": "openai", "mode": "chat", "input_cost_per_token": 1e-6},
|
||||
"other": {"litellm_provider": "openai", "mode": "chat", "aliases": ["twin-latest"]},
|
||||
"real-latest": {"alias_of": "real"},
|
||||
"twin-latest": {"alias_of": "real"},
|
||||
"ghost-latest": {"alias_of": "ghost"},
|
||||
"chain-latest": {"alias_of": "real-latest"},
|
||||
"listed-latest": {"alias_of": "missing", "aliases": ["extra"]},
|
||||
|
|
@ -144,9 +146,10 @@ def test_alias_of_rows_are_served_as_their_target_and_dangling_ones_are_dropped(
|
|||
finalized: Final = _finalize_model_cost_map(raw)
|
||||
assert finalized["real-latest"] == finalized["real"]
|
||||
assert "alias_of" not in finalized["real"]
|
||||
assert set(finalized) == {"real", "real-latest"}
|
||||
assert set(finalized) == {"real", "other", "real-latest", "twin-latest"}
|
||||
assert finalized["real-latest"]["litellm_provider"] == "openai"
|
||||
assert {"ghost-latest", "chain-latest", "listed-latest"} == {
|
||||
assert finalized["twin-latest"] == finalized["other"]
|
||||
assert {"ghost-latest", "chain-latest", "listed-latest", "twin-latest"} == {
|
||||
record.getMessage().split("'")[1] for record in caplog.records
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue