127 lines
3.9 KiB
Python
127 lines
3.9 KiB
Python
"""``MultimodalLLMCapability`` + ``get_multimodal_llm_capability`` accessor.
|
|
|
|
Contract: MultimodalLLMCapability mirrors RerankCapability exactly — 2 methods
|
|
(available + require), frozen dataclass, no soft-degrade variant.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
|
|
import pytest
|
|
from pydantic import SecretStr
|
|
|
|
from everos.component.multimodal import (
|
|
MultimodalLLMCapability,
|
|
get_multimodal_llm_capability,
|
|
)
|
|
from everos.config import Settings
|
|
from everos.config.settings import MultimodalSettings
|
|
from everos.core.errors import ProviderNotConfiguredError
|
|
|
|
_accessor_mod = importlib.import_module("everos.component.multimodal.accessor")
|
|
_llm_client_mod = importlib.import_module("everos.component.llm.client")
|
|
|
|
|
|
class _MockMultimodalLLM:
|
|
async def chat(self, messages):
|
|
return {}
|
|
|
|
|
|
def _reset_capability(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setattr(_accessor_mod, "_capability", None, raising=False)
|
|
monkeypatch.setattr(_llm_client_mod, "_multimodal_client", None, raising=False)
|
|
|
|
|
|
def _patch_settings(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
*,
|
|
model: str | None = None,
|
|
api_key: str | None = None,
|
|
base_url: str | None = None,
|
|
) -> None:
|
|
kwargs = {"api_key": SecretStr(api_key) if api_key is not None else None}
|
|
if base_url is not None:
|
|
kwargs["base_url"] = base_url
|
|
else:
|
|
kwargs["base_url"] = None
|
|
if model is not None:
|
|
kwargs["model"] = model
|
|
cfg = Settings(multimodal=MultimodalSettings(**kwargs))
|
|
monkeypatch.setattr(_llm_client_mod, "load_settings", lambda: cfg)
|
|
|
|
|
|
def test_capability_available_false_when_provider_none() -> None:
|
|
cap = MultimodalLLMCapability(provider=None)
|
|
assert cap.available is False
|
|
|
|
|
|
def test_capability_available_true_when_provider_present() -> None:
|
|
cap = MultimodalLLMCapability(provider=_MockMultimodalLLM())
|
|
assert cap.available is True
|
|
|
|
|
|
def test_require_raises_when_unavailable() -> None:
|
|
cap = MultimodalLLMCapability(provider=None)
|
|
with pytest.raises(ProviderNotConfiguredError) as excinfo:
|
|
cap.require()
|
|
assert excinfo.value.provider == "multimodal_llm"
|
|
|
|
|
|
def test_require_returns_provider_when_available() -> None:
|
|
provider = _MockMultimodalLLM()
|
|
cap = MultimodalLLMCapability(provider=provider)
|
|
assert cap.require() is provider
|
|
|
|
|
|
def test_capability_is_frozen() -> None:
|
|
cap = MultimodalLLMCapability(provider=None)
|
|
with pytest.raises((AttributeError, TypeError)):
|
|
cap.provider = _MockMultimodalLLM() # type: ignore[misc]
|
|
|
|
|
|
def test_capability_has_no_soft_degrade_method() -> None:
|
|
"""Multimodal LLM has no soft-degrade write path, unlike
|
|
EmbeddingCapability's ``embed_or_none`` — callers either require it or
|
|
skip multimodal parsing entirely."""
|
|
cap = MultimodalLLMCapability(provider=None)
|
|
assert not hasattr(cap, "embed_or_none")
|
|
assert not hasattr(cap, "parse_or_none")
|
|
|
|
|
|
def test_get_multimodal_llm_capability_empty_when_not_configured(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
_reset_capability(monkeypatch)
|
|
_patch_settings(monkeypatch, model=None, api_key=None, base_url=None)
|
|
|
|
cap = get_multimodal_llm_capability()
|
|
|
|
assert isinstance(cap, MultimodalLLMCapability)
|
|
assert cap.available is False
|
|
|
|
|
|
def test_get_multimodal_llm_capability_populated_when_configured(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
_reset_capability(monkeypatch)
|
|
_patch_settings(
|
|
monkeypatch, model="m", api_key="sk-test", base_url="https://example.test"
|
|
)
|
|
|
|
cap = get_multimodal_llm_capability()
|
|
|
|
assert cap.available is True
|
|
|
|
|
|
def test_get_multimodal_llm_capability_caches_singleton(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
_reset_capability(monkeypatch)
|
|
_patch_settings(monkeypatch, model=None, api_key=None, base_url=None)
|
|
|
|
first = get_multimodal_llm_capability()
|
|
second = get_multimodal_llm_capability()
|
|
|
|
assert first is second
|