From d7711484efe0772e4266be8df3ebbac63eb129e9 Mon Sep 17 00:00:00 2001 From: m4 Date: Tue, 28 Jul 2026 17:42:16 +0800 Subject: [PATCH] feat(registry): expose generation defaults on selectable models --- EvoScientist/model_registry/http_api.py | 15 +++++++++++++++ EvoScientist/model_registry/openapi.json | 24 ++++++++++++++++++++++++ tests/test_model_registry_http.py | 8 ++++++++ 3 files changed, 47 insertions(+) diff --git a/EvoScientist/model_registry/http_api.py b/EvoScientist/model_registry/http_api.py index 9376841..bba5072 100644 --- a/EvoScientist/model_registry/http_api.py +++ b/EvoScientist/model_registry/http_api.py @@ -171,6 +171,11 @@ class SelectableModel(BaseModel): name: str provider_name: str effective_capabilities: Capabilities + # Registry-effective generation defaults (model value wins over the + # provider default; both unset -> null). Lets chat UIs anchor their + # temperature/top_p sliders without a registry read. + default_temperature: float | None = None + default_top_p: float | None = None class GetSelectableModelsResponse(BaseModel): @@ -855,6 +860,16 @@ class ModelRegistryHttpApi: name=model.name, provider_name=provider.name, effective_capabilities=item.effective_capabilities, + default_temperature=( + model.runtime.temperature + if model.runtime.temperature is not None + else provider.runtime.default_temperature + ), + default_top_p=( + model.runtime.top_p + if model.runtime.top_p is not None + else provider.runtime.default_top_p + ), ) ) return GetSelectableModelsResponse(models=models, defaults=registry.defaults) diff --git a/EvoScientist/model_registry/openapi.json b/EvoScientist/model_registry/openapi.json index eb375e3..c140551 100644 --- a/EvoScientist/model_registry/openapi.json +++ b/EvoScientist/model_registry/openapi.json @@ -1178,6 +1178,30 @@ "SelectableModel": { "description": "One entry of the section 9.1 model selector response.", "properties": { + "default_temperature": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Default Temperature" + }, + "default_top_p": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Default Top P" + }, "effective_capabilities": { "$ref": "#/components/schemas/Capabilities" }, diff --git a/tests/test_model_registry_http.py b/tests/test_model_registry_http.py index 910fa0d..2704e7a 100644 --- a/tests/test_model_registry_http.py +++ b/tests/test_model_registry_http.py @@ -669,6 +669,14 @@ def test_get_models_returns_only_selectable(active_client, store): "vision": False, "structured_output": True, } + # Generation defaults ride the catalog so the chat-bar sliders can show + # the registry-effective values before any override (model value wins + # over the provider default; qwen3 inherits nothing -> null). + assert glm["default_temperature"] == 0.7 + assert glm["default_top_p"] == 0.95 + qwen = next(m for m in models if m["model_ref"]["model_key"] == "qwen3") + assert qwen["default_temperature"] is None + assert qwen["default_top_p"] is None # The selector echoes the registry defaults so clients can label the # `inherit` choice before the first turn. assert response.json()["defaults"]["primary"] == {