mirror of
https://github.com/usestrix/strix.git
synced 2026-10-12 03:47:56 +00:00
refactor(llm): read image support from litellm's catalog, assuming it for unknown models
This commit is contained in:
parent
4d1803a72c
commit
49eb38b775
2 changed files with 5 additions and 99 deletions
|
|
@ -10,7 +10,6 @@ import os
|
|||
import time
|
||||
import uuid
|
||||
from collections.abc import AsyncGenerator
|
||||
from functools import cache
|
||||
from typing import TYPE_CHECKING, Any, cast
|
||||
|
||||
from agents import (
|
||||
|
|
@ -906,34 +905,10 @@ def model_supports_reasoning(model_name: str) -> bool:
|
|||
return bool(entry and entry.get("supports_reasoning"))
|
||||
|
||||
|
||||
_OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models"
|
||||
|
||||
|
||||
@cache
|
||||
def _openrouter_input_modalities() -> dict[str, list[str]] | None:
|
||||
import requests
|
||||
|
||||
try:
|
||||
response = requests.get(_OPENROUTER_MODELS_URL, timeout=5)
|
||||
response.raise_for_status()
|
||||
return {
|
||||
model["id"].lower(): model["architecture"]["input_modalities"]
|
||||
for model in response.json()["data"]
|
||||
}
|
||||
except Exception: # noqa: BLE001
|
||||
logger.warning("Could not fetch OpenRouter model modalities", exc_info=True)
|
||||
return None
|
||||
|
||||
|
||||
def model_supports_images(model_name: str) -> bool:
|
||||
"""Return whether the model accepts image input; unknown models are assumed to."""
|
||||
if is_openrouter_model(model_name):
|
||||
slug = model_name.strip().lower().split("openrouter/", 1)[1]
|
||||
modalities = (_openrouter_input_modalities() or {}).get(slug)
|
||||
if modalities is not None:
|
||||
return "image" in modalities
|
||||
"""Return whether the model accepts image input. Assume yes until proven otherwise. """
|
||||
entry = _catalog_entry(model_name)
|
||||
return bool(entry.get("supports_vision", True)) if entry else True
|
||||
return entry is None or bool(entry.get("supports_vision"))
|
||||
|
||||
|
||||
def _bare_openai_name(model_name: str) -> str:
|
||||
|
|
|
|||
|
|
@ -2,11 +2,8 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import litellm
|
||||
import pytest
|
||||
import requests
|
||||
from agents.extensions.models.litellm_model import LitellmModel
|
||||
from agents.model_settings import ModelSettings
|
||||
from agents.models import _openai_shared
|
||||
|
|
@ -30,10 +27,6 @@ from strix.config.settings import Settings
|
|||
from strix.llm.request_log import RequestLoggingModel
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterator
|
||||
|
||||
|
||||
def test_request_timeout_extra_args_positive() -> None:
|
||||
assert request_timeout_extra_args(300) == {"timeout": 300}
|
||||
assert request_timeout_extra_args(10) == {"timeout": 10}
|
||||
|
|
@ -212,71 +205,9 @@ def test_configure_sdk_api_route_follows_the_given_model(
|
|||
assert routes == ["responses", "chat_completions"]
|
||||
|
||||
|
||||
class _FakeOpenRouterResponse:
|
||||
def raise_for_status(self) -> None:
|
||||
pass
|
||||
|
||||
def json(self) -> dict[str, Any]:
|
||||
return {
|
||||
"data": [
|
||||
{"id": "z-ai/glm-5.3", "architecture": {"input_modalities": ["text"]}},
|
||||
{"id": "openai/gpt-5", "architecture": {"input_modalities": ["text", "image"]}},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def openrouter_models(monkeypatch: pytest.MonkeyPatch) -> Iterator[list[str]]:
|
||||
calls: list[str] = []
|
||||
|
||||
def fake_get(url: str, **_kwargs: Any) -> _FakeOpenRouterResponse:
|
||||
calls.append(url)
|
||||
return _FakeOpenRouterResponse()
|
||||
|
||||
monkeypatch.setattr(requests, "get", fake_get)
|
||||
models._openrouter_input_modalities.cache_clear()
|
||||
yield calls
|
||||
models._openrouter_input_modalities.cache_clear()
|
||||
|
||||
|
||||
def test_openrouter_image_support_follows_input_modalities(openrouter_models: list[str]) -> None:
|
||||
assert model_supports_images("openrouter/z-ai/glm-5.3") is False
|
||||
assert model_supports_images("litellm/openrouter/openai/gpt-5") is True
|
||||
assert len(openrouter_models) == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("openrouter_models")
|
||||
def test_openrouter_model_missing_from_listing_falls_back_to_catalog(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setitem(litellm.model_cost, "openrouter/acme/text-only", {"supports_vision": False})
|
||||
assert model_supports_images("openrouter/acme/text-only") is False
|
||||
assert model_supports_images("openrouter/acme/unknown") is True
|
||||
|
||||
|
||||
def test_openrouter_fetch_failure_fails_open(
|
||||
monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
def failing_get(*_args: Any, **_kwargs: Any) -> None:
|
||||
raise requests.ConnectionError("offline")
|
||||
|
||||
monkeypatch.setattr(requests, "get", failing_get)
|
||||
models._openrouter_input_modalities.cache_clear()
|
||||
try:
|
||||
assert model_supports_images("openrouter/acme/unknown") is True
|
||||
assert model_supports_images("openrouter/acme/other") is True
|
||||
finally:
|
||||
models._openrouter_input_modalities.cache_clear()
|
||||
assert caplog.text.count("Could not fetch OpenRouter model modalities") == 1
|
||||
|
||||
|
||||
def test_non_openrouter_image_support_uses_catalog(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def unexpected_get(*_args: Any, **_kwargs: Any) -> None:
|
||||
raise AssertionError("non-OpenRouter models must not fetch the OpenRouter listing")
|
||||
|
||||
monkeypatch.setattr(requests, "get", unexpected_get)
|
||||
monkeypatch.setitem(litellm.model_cost, "acme-text", {"supports_vision": False})
|
||||
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("openai/acme-vision") is True
|
||||
assert model_supports_images("litellm/openai/acme-vision") is True
|
||||
assert model_supports_images("acme-unknown-model") is True
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue