Normalize Lemonade runtime model metadata

This commit is contained in:
Graham Neubig 2026-05-21 08:54:53 -04:00
parent 7b845a93fe
commit aec84020e5
2 changed files with 51 additions and 3 deletions

View file

@ -121,16 +121,31 @@ class LemonadeChatConfig(OpenAILikeChatConfig):
return parsed
return None
@staticmethod
def _get_provider_specific_entry(model_info: dict) -> dict:
provider_specific_entry = model_info.get("provider_specific_entry")
if not isinstance(provider_specific_entry, dict):
provider_specific_entry = {}
else:
provider_specific_entry = provider_specific_entry.copy()
for key in ("recipe_options", "context_window", "max_context_window"):
if key in model_info:
provider_specific_entry[key] = model_info[key]
return provider_specific_entry
def _get_context_window(self, model_info: dict) -> Optional[int]:
recipe_options = model_info.get("recipe_options")
provider_specific_entry = self._get_provider_specific_entry(model_info)
recipe_options = provider_specific_entry.get("recipe_options")
if not isinstance(recipe_options, dict):
recipe_options = {}
for value in (
recipe_options.get("ctx_size"),
model_info.get("max_input_tokens"),
model_info.get("context_window"),
model_info.get("max_context_window"),
provider_specific_entry.get("context_window"),
provider_specific_entry.get("max_context_window"),
):
parsed = self._get_positive_int(value)
if parsed is not None:
@ -172,6 +187,7 @@ class LemonadeChatConfig(OpenAILikeChatConfig):
max_input_tokens = self._get_context_window(model_info)
max_output_tokens = self._get_positive_int(model_info.get("max_output_tokens"))
max_tokens = self._get_positive_int(model_info.get("max_tokens"))
provider_specific_entry = self._get_provider_specific_entry(model_info)
model_info_response = self._get_default_model_info(model)
model_info_response.update(
@ -181,6 +197,8 @@ class LemonadeChatConfig(OpenAILikeChatConfig):
"max_output_tokens": max_output_tokens,
}
)
if provider_specific_entry:
model_info_response["provider_specific_entry"] = provider_specific_entry
return model_info_response
def _get_openai_compatible_provider_info(

View file

@ -109,6 +109,10 @@ def test_get_model_info_uses_loaded_context_size():
assert model_info["key"] == "lemonade/Qwen3.6-35B-A3B-GGUF"
assert model_info["litellm_provider"] == "lemonade"
assert model_info["max_input_tokens"] == 65536
assert model_info["provider_specific_entry"] == {
"recipe_options": {"ctx_size": 65536},
"max_context_window": 262144,
}
assert "supports_function_calling" not in model_info
assert "supports_response_schema" not in model_info
assert "supports_tool_choice" not in model_info
@ -140,6 +144,32 @@ def test_get_model_info_falls_back_when_server_unavailable():
assert "supports_tool_choice" not in model_info
def test_get_model_info_reads_context_from_provider_specific_entry():
"""Test that Lemonade model info uses provider-specific runtime metadata."""
config = LemonadeChatConfig()
response = MagicMock()
response.status_code = 200
response.json.return_value = {
"id": "Qwen3.6-35B-A3B-GGUF",
"provider_specific_entry": {
"recipe_options": {"ctx_size": "32768"},
"max_context_window": 262144,
},
}
with patch.object(litellm.module_level_client, "get", return_value=response):
model_info = config.get_model_info(
model="lemonade/Qwen3.6-35B-A3B-GGUF",
api_base="http://lemonade.test/v1",
)
assert model_info["max_input_tokens"] == 32768
assert model_info["provider_specific_entry"] == {
"recipe_options": {"ctx_size": "32768"},
"max_context_window": 262144,
}
def test_get_model_info_sends_lemonade_api_key(monkeypatch):
"""Test that Lemonade model info uses auth for authenticated servers."""
monkeypatch.setenv("LEMONADE_API_KEY", "test-key")