[Frontend] Lazily initialize chat media connectors (#49914)
Signed-off-by: Andreas Karatzas <akaratza@amd.com>
Andreas Karatzas committed
Jul 30, 2026 at 01:56 UTC
e04a30a77cb17d5a9753c53c51ee30bba887053c
2 files changed
+43
-11
tests/entrypoints/unit_tests/test_chat_utils.py
+24
@@ -15,6 +15,7 @@ from vllm.assets.image import ImageAsset
15
from vllm.assets.video import VideoAsset
16
from vllm.config import ModelConfig
17
from vllm.entrypoints.chat_utils import (
18
+ MEDIA_CONNECTOR_REGISTRY,
19
AsyncMultiModalItemTracker,
20
ConversationMessage,
21
_postprocess_messages,
@@ -709,6 +710,29 @@ def test_parse_chat_messages_empty_system(
710
]
711
712
713
+@pytest.mark.asyncio
714
+async def test_text_only_chat_does_not_initialize_media_connector(
715
+ mistral_model_config,
716
+ monkeypatch,
717
+):
718
+ load_connector = MagicMock()
719
+ monkeypatch.setattr(MEDIA_CONNECTOR_REGISTRY, "load", load_connector)
720
+ messages = [{"role": "user", "content": "Who are you?"}]
721
+
722
+ parse_chat_messages(
723
+ messages,
724
+ mistral_model_config,
725
+ content_format="string",
726
+ )
727
+ await parse_chat_messages_async(
728
+ messages,
729
+ mistral_model_config,
730
+ content_format="string",
731
+ )
732
+
733
+ load_connector.assert_not_called()
734
+
735
+
736
@pytest.mark.asyncio
737
async def test_parse_chat_messages_single_image_async(
738
phi3v_model_config,
vllm/entrypoints/chat_utils.py
+19
-11
@@ -945,16 +945,19 @@ class MultiModalContentParser(BaseMultiModalContentParser):
945
super().__init__()
946
947
self._tracker = tracker
948
+ self._mm_processor_kwargs = mm_processor_kwargs
949
949
- self._connector: MediaConnector = MEDIA_CONNECTOR_REGISTRY.load(
950
+ @cached_property
951
+ def _connector(self) -> MediaConnector:
952
+ # Connector setup may probe VLLM_MEDIA_CACHE. Defer it until a request
953
+ # actually contains media so text-only parsing never blocks on that I/O.
954
+ return MEDIA_CONNECTOR_REGISTRY.load(
955
envs.VLLM_MEDIA_CONNECTOR,
951
- media_io_kwargs=tracker.media_io_kwargs,
952
- allowed_local_media_path=tracker.allowed_local_media_path,
953
- allowed_media_domains=tracker.allowed_media_domains,
956
+ media_io_kwargs=self._tracker.media_io_kwargs,
957
+ allowed_local_media_path=self._tracker.allowed_local_media_path,
958
+ allowed_media_domains=self._tracker.allowed_media_domains,
959
)
960
956
- self._mm_processor_kwargs = mm_processor_kwargs
957
-
961
@property
962
def model_config(self) -> ModelConfig:
963
return self._tracker.model_config
@@ -1097,13 +1100,18 @@ class AsyncMultiModalContentParser(BaseMultiModalContentParser):
1100
super().__init__()
1101
1102
self._tracker = tracker
1100
- self._connector: MediaConnector = MEDIA_CONNECTOR_REGISTRY.load(
1103
+ self._mm_processor_kwargs: dict[str, Any] | None = mm_processor_kwargs
1104
+
1105
+ @cached_property
1106
+ def _connector(self) -> MediaConnector:
1107
+ # Connector setup may probe VLLM_MEDIA_CACHE. Defer it until a request
1108
+ # actually contains media so text-only parsing never blocks on that I/O.
1109
+ return MEDIA_CONNECTOR_REGISTRY.load(
1110
envs.VLLM_MEDIA_CONNECTOR,
1102
- media_io_kwargs=tracker.media_io_kwargs,
1103
- allowed_local_media_path=tracker.allowed_local_media_path,
1104
- allowed_media_domains=tracker.allowed_media_domains,
1111
+ media_io_kwargs=self._tracker.media_io_kwargs,
1112
+ allowed_local_media_path=self._tracker.allowed_local_media_path,
1113
+ allowed_media_domains=self._tracker.allowed_media_domains,
1114
)
1106
- self._mm_processor_kwargs: dict[str, Any] | None = mm_processor_kwargs
1115
1116
@property
1117
def model_config(self) -> ModelConfig: