feat(registry): reject image-only models in chat model saves
This commit is contained in:
@@ -52,6 +52,7 @@ CAPABILITY_UNSUPPORTED_BY_ADAPTER = "CAPABILITY_UNSUPPORTED_BY_ADAPTER"
|
||||
MODEL_CAPABILITY_UNAVAILABLE = "MODEL_CAPABILITY_UNAVAILABLE"
|
||||
UNSUPPORTED_RUNTIME_PARAMETER = "UNSUPPORTED_RUNTIME_PARAMETER"
|
||||
MODEL_LIMITS_UNCONFIRMED = "MODEL_LIMITS_UNCONFIRMED"
|
||||
IMAGE_MODEL_NOT_CHAT_MODEL = "IMAGE_MODEL_NOT_CHAT_MODEL"
|
||||
CONTEXT_BUDGET_UNSATISFIABLE = "CONTEXT_BUDGET_UNSATISFIABLE"
|
||||
PROVIDER_UNREACHABLE = "PROVIDER_UNREACHABLE"
|
||||
|
||||
@@ -88,6 +89,7 @@ ERROR_HTTP_STATUS: dict[str, int] = {
|
||||
MODEL_CAPABILITY_UNAVAILABLE: 422,
|
||||
UNSUPPORTED_RUNTIME_PARAMETER: 422,
|
||||
MODEL_LIMITS_UNCONFIRMED: 422,
|
||||
IMAGE_MODEL_NOT_CHAT_MODEL: 422,
|
||||
CONTEXT_BUDGET_UNSATISFIABLE: 422,
|
||||
PROVIDER_UNREACHABLE: 422,
|
||||
VALIDATION_FAILED: 422,
|
||||
|
||||
@@ -51,6 +51,7 @@ from .endpoint_policy import EndpointPolicy
|
||||
from .errors import (
|
||||
CREDENTIAL_NOT_CONFIGURED,
|
||||
FORBIDDEN,
|
||||
IMAGE_MODEL_NOT_CHAT_MODEL,
|
||||
INVALID_REQUEST,
|
||||
MODEL_LIMITS_UNCONFIRMED,
|
||||
MODEL_NOT_AVAILABLE,
|
||||
@@ -381,6 +382,26 @@ def validate_registry_save(
|
||||
``resolve_parameters``, and the resolve-time tightening rules are
|
||||
enforced by the resolver/adapter layer.
|
||||
"""
|
||||
from EvoScientist.image_gen import is_image_generation_model
|
||||
|
||||
for provider_index, provider in enumerate(registry.providers):
|
||||
for model_index, model in enumerate(provider.models):
|
||||
if model.enabled and is_image_generation_model(model.upstream_model_id):
|
||||
raise ModelRegistryError(
|
||||
IMAGE_MODEL_NOT_CHAT_MODEL,
|
||||
"Image-only models must be configured in the "
|
||||
"image_generation section of config.yaml, not as chat models.",
|
||||
details=[
|
||||
{
|
||||
"path": (
|
||||
f"providers[{provider_index}].models"
|
||||
f"[{model_index}].upstream_model_id"
|
||||
),
|
||||
"code": IMAGE_MODEL_NOT_CHAT_MODEL,
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
for provider_index, provider in enumerate(registry.providers):
|
||||
provider_path = f"providers[{provider_index}]"
|
||||
try:
|
||||
|
||||
@@ -384,6 +384,17 @@ def test_put_registry_rejects_ssrf_endpoint(active_client):
|
||||
assert body["details"][0]["path"].startswith("providers[0].base_url")
|
||||
|
||||
|
||||
def test_put_registry_rejects_image_only_model(active_client):
|
||||
registry = _current_registry(active_client)["registry"]
|
||||
registry["providers"][0]["models"][0]["upstream_model_id"] = "gpt-image-2"
|
||||
|
||||
response = _put(active_client, registry)
|
||||
assert response.status_code == 422
|
||||
body = response.json()
|
||||
assert body["code"] == "IMAGE_MODEL_NOT_CHAT_MODEL"
|
||||
assert body["details"][0]["path"].endswith("upstream_model_id")
|
||||
|
||||
|
||||
def test_put_registry_rejects_unsupported_parameter(active_client):
|
||||
registry = _current_registry(active_client)["registry"]
|
||||
# The glm-5.2 contract caps temperature at 1.
|
||||
|
||||
Reference in New Issue
Block a user