Merge pull request #40625 from BerriAI/litellm_wandb_reasoning_fallback

feat(wandb): default unmapped W&B models to reasoning-capable
This commit is contained in:
ryan-crabbe-berri 2026-09-10 16:49:27 -07:00 committed by GitHub
commit b294a51834
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 151 additions and 2 deletions

View file

@ -57258,6 +57258,14 @@
"model_info": {
"supports_mid_conversation_system": true
}
},
{
"name": "wandb-reasoning-baseline",
"pattern": "^wandb/",
"description": "Any Weights & Biases Inference model id, anchored to the wandb/ namespace so only that provider's ids match. W&B's serverless catalog is reasoning-first and grows faster than this registry names it, so an id the map has not described yet is treated as reasoning-capable and keeps the caller's reasoning_effort instead of dropping it or raising UnsupportedParamsError. Rules lose to exact entries, so a mapped non-reasoning model such as wandb/meta-llama/Llama-3.1-8B-Instruct is unaffected. Carries no mode and no pricing, so cost stays on the standard unpriced behavior and the deployment does not read as catalog-mapped to the router's reasoning-effort resolver.",
"model_info": {
"supports_reasoning": true
}
}
]
},

View file

@ -3108,7 +3108,10 @@ def register_model(
existing_model = cast(dict, builtin_model_info)
model_cost_key = existing_model["key"]
else:
existing_model = {}
# An exact entry ends the lookup ladder before the capability rules are
# consulted, so seed from them: otherwise registering an unmapped model
# shadows the very defaults it would have resolved to unregistered.
existing_model = dict(match_capability_generalizations(_key_str) or {}) # mutable-ok: merge target
model_cost_key = key
builtin_entry = _resolve_builtin_model_cost_entry(key=_key_str, provider=provider)
if builtin_entry is not None:

View file

@ -57258,6 +57258,14 @@
"model_info": {
"supports_mid_conversation_system": true
}
},
{
"name": "wandb-reasoning-baseline",
"pattern": "^wandb/",
"description": "Any Weights & Biases Inference model id, anchored to the wandb/ namespace so only that provider's ids match. W&B's serverless catalog is reasoning-first and grows faster than this registry names it, so an id the map has not described yet is treated as reasoning-capable and keeps the caller's reasoning_effort instead of dropping it or raising UnsupportedParamsError. Rules lose to exact entries, so a mapped non-reasoning model such as wandb/meta-llama/Llama-3.1-8B-Instruct is unaffected. Carries no mode and no pricing, so cost stays on the standard unpriced behavior and the deployment does not read as catalog-mapped to the router's reasoning-effort resolver.",
"model_info": {
"supports_reasoning": true
}
}
]
},

View file

@ -571,3 +571,109 @@ def test_shipped_mid_conversation_gate_on_bedrock_ids(shipped_cost_map):
):
matched = match_capability_generalizations(unflagged)
assert matched is None or not matched.get("supports_mid_conversation_system"), unflagged
def test_shipped_rules_flag_unmapped_wandb_ids_as_reasoning(shipped_cost_map):
"""W&B ships reasoning models faster than the registry names them, so an unmapped
wandb id resolves as reasoning-capable and its reasoning_effort survives instead of
being dropped. The rule carries no mode and no pricing, so cost stays on the standard
unpriced behavior and the deployment does not read as catalog-mapped."""
model = "wandb/zai-org/GLM-6-Turbo"
assert model not in litellm.model_cost
info = litellm.get_model_info(model, custom_llm_provider="wandb")
assert info["litellm_provider"] == "wandb"
assert info["supports_reasoning"] is True
assert info.get("mode") is None
assert not info.get("input_cost_per_token")
assert not info.get("output_cost_per_token")
assert litellm.supports_reasoning(model="zai-org/GLM-6-Turbo", custom_llm_provider="wandb") is True
def test_shipped_wandb_rule_loses_to_mapped_non_reasoning_entries(shipped_cost_map):
"""The whole point of a fallback is that it only fills gaps. A wandb model the map
describes as non-reasoning must stay non-reasoning, otherwise the rule silently
re-introduces the blanket supports_reasoning it exists to avoid."""
for model in (
"meta-llama/Llama-3.1-8B-Instruct",
"microsoft/Phi-4-mini-instruct",
"moonshotai/Kimi-K2-Instruct",
"Qwen/Qwen3-Coder-480B-A35B-Instruct",
):
assert f"wandb/{model}" in litellm.model_cost, model
assert litellm.supports_reasoning(model=model, custom_llm_provider="wandb") is False, model
def test_shipped_wandb_rule_is_anchored_to_the_wandb_namespace(shipped_cost_map):
"""``^wandb/`` is anchored, so it cannot leak onto another provider's ids."""
assert match_capability_generalizations("wandb/some-new-model") == {"supports_reasoning": True}
for foreign in ("openai/some-new-model", "notwandb/some-new-model", "together_ai/wandb/some-new-model"):
matched = match_capability_generalizations(foreign)
assert matched is None or not matched.get("supports_reasoning"), foreign
def test_shipped_wandb_rule_keeps_reasoning_effort_on_an_unmapped_model(shipped_cost_map):
"""End to end through the provider config: the gate WandbConfig applies reads the
rule, so reasoning_effort is advertised and survives get_optional_params rather than
raising UnsupportedParamsError."""
model = "zai-org/GLM-6-Turbo"
assert f"wandb/{model}" not in litellm.model_cost
supported = litellm.get_supported_openai_params(model=f"wandb/{model}")
assert supported is not None
assert "reasoning_effort" in supported
optional_params = litellm.utils.get_optional_params(
model=model,
custom_llm_provider="wandb",
reasoning_effort="medium",
drop_params=False,
)
assert optional_params["reasoning_effort"] == "medium"
def test_router_registration_does_not_shadow_shipped_rules(shipped_cost_map):
"""Regression: Router writes every configured deployment into ``litellm.model_cost``,
and an exact entry ends the lookup ladder before the rules are consulted. Registering
an unmapped model has to carry the rule defaults forward, or configuring a model on a
proxy silently strips the capabilities the same model resolves to off-proxy."""
from litellm import Router
unmapped_wandb = "wandb/zai-org/GLM-6-Turbo"
unmapped_claude = "anthropic/claude-opus-9"
assert unmapped_wandb not in litellm.model_cost
assert unmapped_claude not in litellm.model_cost
Router(
model_list=[
{"model_name": name, "litellm_params": {"model": name, "api_key": "fake"}}
for name in (unmapped_wandb, unmapped_claude)
]
)
assert unmapped_wandb in litellm.model_cost
assert unmapped_claude in litellm.model_cost
assert litellm.supports_reasoning(model="zai-org/GLM-6-Turbo", custom_llm_provider="wandb") is True
assert litellm.supports_reasoning(model="claude-opus-9", custom_llm_provider="anthropic") is True
def test_deployment_model_info_beats_the_seeded_rule_defaults(shipped_cost_map):
"""Seeding a registration from the rules is a floor, not an override: an explicit
model_info on the deployment still wins, so a non-reasoning model can be configured
under a reasoning-first namespace."""
from litellm import Router
model = "wandb/some-org/NoThink-1"
Router(
model_list=[
{
"model_name": model,
"litellm_params": {"model": model, "api_key": "fake"},
"model_info": {"supports_reasoning": False},
}
]
)
assert litellm.model_cost[model]["supports_reasoning"] is False
assert litellm.supports_reasoning(model="some-org/NoThink-1", custom_llm_provider="wandb") is False

View file

@ -249,7 +249,6 @@ class TestWandbConfig:
"model,explicit_false",
[
("meta-llama/Llama-3.1-8B-Instruct", False),
("unknown-model", False),
("openai/gpt-oss-20b", True),
],
)
@ -290,3 +289,28 @@ class TestWandbConfig:
supported_params = litellm.get_supported_openai_params(model=f"wandb/{model}")
assert supported_params is not None
assert "reasoning_effort" not in supported_params
@pytest.mark.respx()
def test_wandb_completion_keeps_reasoning_effort_for_an_unregistered_model(
self, wandb_test_config, wandb_request_mock: respx.Route
):
"""A wandb id the registry has not named yet resolves through the
wandb-reasoning-baseline fallback generalization, so its reasoning_effort reaches
the provider instead of raising. W&B adds reasoning models faster than this
registry names them, and an exact entry still wins wherever one exists."""
model: Final = "zai-org/GLM-6-Turbo"
assert f"wandb/{model}" not in litellm.model_cost
completion(
model=f"wandb/{model}",
messages=[{"role": "user", "content": "Hello"}],
api_key="fake-wandb-key",
api_base="https://api.inference.wandb.ai/v1",
reasoning_effort="medium",
drop_params=False,
)
assert wandb_request_mock.call_count == 1
request_body = json.loads(wandb_request_mock.calls[0].request.content)
assert request_body["model"] == model
assert request_body["reasoning_effort"] == "medium"