From acd64e929c9f42dbe77e5560611dd6f80656f09e Mon Sep 17 00:00:00 2001 From: ian-at-strix Date: Wed, 7 Oct 2026 15:58:43 -0400 Subject: [PATCH] feat(llm): detect whether a model accepts image input (#1460) * feat(llm): detect whether a model accepts image input Add model_supports_images(): OpenRouter models are checked against architecture.input_modalities from OpenRouter's public model list (fetched once per process), others against LiteLLM's supports_vision. Unknown models and lookup failures count as image-capable. Not wired in yet. * refactor(llm): read image support from litellm's catalog, assuming it for unknown models * style: drop a trailing space in the image-support docstring --- strix/config/models.py | 6 ++++++ tests/test_models.py | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/strix/config/models.py b/strix/config/models.py index 4ce6dc86..b2d6f9d0 100644 --- a/strix/config/models.py +++ b/strix/config/models.py @@ -905,6 +905,12 @@ def model_supports_reasoning(model_name: str) -> bool: return bool(entry and entry.get("supports_reasoning")) +def model_supports_images(model_name: str) -> bool: + """Return whether the model accepts image input. Assume yes until proven otherwise.""" + entry = _catalog_entry(model_name) + return entry is None or bool(entry.get("supports_vision")) + + def _bare_openai_name(model_name: str) -> str: name = model_name.strip().lower() for prefix in ("litellm/", "any-llm/", "openai/"): diff --git a/tests/test_models.py b/tests/test_models.py index 82cf8ac4..aafbaf40 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -16,6 +16,7 @@ from strix.config.models import ( _NonStreamingModel, _TurnGuardModel, configure_sdk_model_defaults, + model_supports_images, request_timeout_extra_args, resolve_api_type, routes_through_litellm, @@ -202,3 +203,11 @@ def test_configure_sdk_api_route_follows_the_given_model( models.configure_sdk_api_route("my-private-model", settings) assert routes == ["responses", "chat_completions"] + + +def test_image_support_follows_the_catalog(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setitem(litellm.model_cost, "acme-text", {}) + monkeypatch.setitem(litellm.model_cost, "acme-vision", {"supports_vision": True}) + assert model_supports_images("acme-text") is False + assert model_supports_images("litellm/openai/acme-vision") is True + assert model_supports_images("acme-unknown-model") is True