From ed876de879757452041308f65844a1cbb9bef451 Mon Sep 17 00:00:00 2001 From: tzhouam Date: Sat, 3 Oct 2026 21:11:54 +0800 Subject: [PATCH] rebase: target the official vLLM 0.31.0 release Use upstream release images at db9527a46873, preserve custom processor conditioning, and include weekly jobs in full Buildkite release validation. Signed-off-by: tzhouam --- .buildkite/cuda/rebase-pipeline.yml | 10 +++ .buildkite/cuda/scripts/check_vllm_runtime.py | 10 +-- docker/Dockerfile.ci | 18 ++--- docker/Dockerfile.cuda | 3 +- docker/Dockerfile.rocm | 7 +- requirements/common.txt | 2 +- tests/buildkite/test_rocm_dockerfile.py | 15 ++-- tests/inputs/test_mm_processor.py | 79 ++++++++++++++++++- .../test_qwen3_omni_streaming_helpers.py | 21 +++++ .../worker_v2/test_capture_query_bound_gpu.py | 1 - vllm_omni/inputs/mm_processor.py | 17 ++-- .../models/cosyvoice3/cosyvoice3.py | 1 - .../model_executor/models/glm_tts/glm_tts.py | 1 - .../models/mimo_audio/mimo_audio.py | 1 - .../models/omnivoice/omnivoice.py | 1 - 15 files changed, 142 insertions(+), 45 deletions(-) diff --git a/.buildkite/cuda/rebase-pipeline.yml b/.buildkite/cuda/rebase-pipeline.yml index 391079c4a..064a7beaf 100644 --- a/.buildkite/cuda/rebase-pipeline.yml +++ b/.buildkite/cuda/rebase-pipeline.yml @@ -33,3 +33,13 @@ steps: - python3 .buildkite/common/scripts/upload_pipeline.py --upload --all .buildkite/cuda/test-nightly.yml agents: queue: "cpu_queue_premerge" + + # Include the slow model cases moved from nightly into weekly for release validation. + - label: "Upload Weekly Pipeline" + depends_on: image-build + key: upload-weekly-pipeline + if: build.env("WEEKLY") == "1" + commands: + - python3 .buildkite/common/scripts/upload_pipeline.py --upload --all .buildkite/cuda/test-weekly.yml + agents: + queue: "cpu_queue_premerge" diff --git a/.buildkite/cuda/scripts/check_vllm_runtime.py b/.buildkite/cuda/scripts/check_vllm_runtime.py index 612761e56..813d9f6d8 100644 --- a/.buildkite/cuda/scripts/check_vllm_runtime.py +++ b/.buildkite/cuda/scripts/check_vllm_runtime.py @@ -12,24 +12,24 @@ from pathlib import Path def main() -> None: dockerfile = Path(__file__).resolve().parents[3] / "docker" / "Dockerfile.ci" match = re.search( - r"^ARG VLLM_PRECOMPILED_WHEEL_COMMIT=([0-9a-f]{40})$", + r"^ARG VLLM_VERSION=([0-9]+\.[0-9]+\.[0-9]+)$", dockerfile.read_text(), re.MULTILINE, ) if match is None: - raise RuntimeError(f"Missing vLLM commit pin in {dockerfile}") - expected_commit = match.group(1) + raise RuntimeError(f"Missing vLLM release version in {dockerfile}") + expected_version = match.group(1) import torch import vllm - assert expected_commit[:8] in vllm.__version__, vllm.__version__ + assert vllm.__version__ == expected_version, vllm.__version__ assert torch.cuda.is_available(), "vLLM runtime check requires a GPU worker" for module in ("flashinfer", "vllm._C_stable_libtorch"): importlib.import_module(module) print( f"Verified vLLM CUDA runtime: vllm={vllm.__version__} " - f"commit={expected_commit} torch={torch.__version__} " + f"expected={expected_version} torch={torch.__version__} " f"cuda={torch.version.cuda} device={torch.cuda.get_device_name()}" ) diff --git a/docker/Dockerfile.ci b/docker/Dockerfile.ci index 42144754b..a98af29c4 100644 --- a/docker/Dockerfile.ci +++ b/docker/Dockerfile.ci @@ -1,11 +1,9 @@ -# Target an unreleased vLLM main commit. The official commit image carries -# the matching CUDA/PyTorch/FlashInfer stack; do not overlay a nightly wheel -# on the previous release image. Copilot updates this commit pin, which also -# selects the image used by CI. The selected commit must have a published -# nightly image as well as a cu130 wheel. -ARG VLLM_PRECOMPILED_WHEEL_COMMIT=ac9126e58aa7bbab1856ba6593ba4d5003fea516 -ARG VLLM_BASE_IMAGE=vllm/vllm-openai -ARG VLLM_BASE_TAG=nightly-${VLLM_PRECOMPILED_WHEEL_COMMIT} +# Use the official release image with its matching CUDA/PyTorch stack. +# The release images are available in upstream ECR before Docker Hub promotion. +ARG VLLM_VERSION=0.31.0 +ARG VLLM_PRECOMPILED_WHEEL_COMMIT=db9527a46873454610df6dbedf79a36d6bf1a7f6 +ARG VLLM_BASE_IMAGE=public.ecr.aws/q9t5s3a7/vllm-release-repo +ARG VLLM_BASE_TAG=${VLLM_PRECOMPILED_WHEEL_COMMIT} # We use registry-based layer caching for the dependencies, # where the tag is determined based on the hash of the contents @@ -13,7 +11,7 @@ ARG VLLM_BASE_TAG=nightly-${VLLM_PRECOMPILED_WHEEL_COMMIT} # everything except the actual project dir, since that should not # change much across branches. FROM ${VLLM_BASE_IMAGE}:${VLLM_BASE_TAG} AS deps -ARG VLLM_PRECOMPILED_WHEEL_COMMIT +ARG VLLM_VERSION # Keep APP_DIR outside /workspace so k8s Buildkite workspace mounts cannot # shadow the editable install target (#5364). Docker WORKDIR creates /opt if # needed. @@ -47,7 +45,7 @@ RUN uv pip install --system -e ".[dev]" # Fail the image build if dependency resolution replaced the selected vLLM. # The CPU builder has no NVIDIA driver; CUDA imports are checked at the start # of each GPU test job by .buildkite/cuda/scripts/check_vllm_runtime.py. -RUN python3 -c "import vllm; assert '${VLLM_PRECOMPILED_WHEEL_COMMIT}'[:8] in vllm.__version__, vllm.__version__" +RUN python3 -c "import vllm; assert vllm.__version__ == '${VLLM_VERSION}', vllm.__version__" # The final stage just copies the working dir on top of the # dependencies image. This uses --link so that we can skip diff --git a/docker/Dockerfile.cuda b/docker/Dockerfile.cuda index cba47dc25..cb9af0753 100644 --- a/docker/Dockerfile.cuda +++ b/docker/Dockerfile.cuda @@ -1,4 +1,5 @@ -ARG BASE_IMAGE=vllm/vllm-openai:v0.30.0 +# Official vLLM v0.31.0 release image, before Docker Hub tag promotion. +ARG BASE_IMAGE=public.ecr.aws/q9t5s3a7/vllm-release-repo:db9527a46873454610df6dbedf79a36d6bf1a7f6 FROM ${BASE_IMAGE} ARG COMMON_WORKDIR=/app diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm index 1639bcfeb..78ddac818 100644 --- a/docker/Dockerfile.rocm +++ b/docker/Dockerfile.rocm @@ -1,7 +1,8 @@ # Keep the ROCm runtime aligned with the vLLM release targeted by # docker/Dockerfile.ci. A stale base image can build successfully while failing # at runtime when vLLM-Omni imports APIs added by the newer vLLM release. -ARG BASE_IMAGE=vllm/vllm-openai-rocm:v0.30.0 +# Official vLLM v0.31.0 release image, before Docker Hub tag promotion. +ARG BASE_IMAGE=public.ecr.aws/q9t5s3a7/vllm-release-repo:db9527a46873454610df6dbedf79a36d6bf1a7f6-rocm # Keep the dependency-heavy portion independent from the source tree. The # registry cache is keyed on these inputs, while the final source copy can be @@ -12,11 +13,11 @@ FROM ${BASE_IMAGE} AS deps # BASE_IMAGE pins the default prebuilt runtime when USE_NIGHTLY_BUILD=0. # VLLM_VERSION_OR_COMMIT_HASH is consumed only by the opt-in source rebuild when # USE_NIGHTLY_BUILD=1. Keep both aligned with docker/Dockerfile.ci's -# VLLM_BASE_TAG. This is enforced by tests/buildkite/test_rocm_dockerfile.py. An +# release version. This is enforced by tests/buildkite/test_rocm_dockerfile.py. An # intentional custom source pin must update that regression in the same change, # and should return to the stable release as soon as one is available. ARG USE_NIGHTLY_BUILD=0 -ARG VLLM_VERSION_OR_COMMIT_HASH=v0.30.0 +ARG VLLM_VERSION_OR_COMMIT_HASH=v0.31.0 ARG ARG_PYTORCH_ROCM_ARCH ENV PYTORCH_ROCM_ARCH=${ARG_PYTORCH_ROCM_ARCH:-${PYTORCH_ROCM_ARCH}} diff --git a/requirements/common.txt b/requirements/common.txt index 9a745cd2c..5a702f66d 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -2,7 +2,7 @@ # kernels==0.16.1 requires the LayerRepository version=/revision= integration # introduced in transformers 5.13. Keep the tested upper bound: 5.15 has # a reported model-construction regression; later versions need validation. -# This range also satisfies vLLM 0.30.0's transformers>=5.10.4 requirement. +# This range also satisfies vLLM 0.31.0's transformers>=5.10.4,<5.18.0 requirement. # MOSS-TTS-Nano's list/set weight-loading compatibility is handled by # transformers_keys_to_ignore_compat in model_executor/models/utils.py. transformers >= 5.13.0, < 5.15 diff --git a/tests/buildkite/test_rocm_dockerfile.py b/tests/buildkite/test_rocm_dockerfile.py index 001772eed..fc42fc478 100644 --- a/tests/buildkite/test_rocm_dockerfile.py +++ b/tests/buildkite/test_rocm_dockerfile.py @@ -11,6 +11,7 @@ REPO_ROOT = Path(__file__).resolve().parents[2] AMD_TEMPLATE = REPO_ROOT / ".buildkite/amd/test-template-amd-omni.j2" AMD_BUILD_SCRIPT = REPO_ROOT / ".buildkite/amd/scripts/build-ci-image.sh" CUDA_RELEASE_DOCKERFILE = REPO_ROOT / "docker/Dockerfile.cuda" +CUDA_CI_DOCKERFILE = REPO_ROOT / "docker/Dockerfile.ci" ROCM_DOCKERFILE = REPO_ROOT / "docker/Dockerfile.rocm" ROCM_DOCKERIGNORE = REPO_ROOT / "docker/Dockerfile.rocm.dockerignore" @@ -31,16 +32,15 @@ def _line_index(lines: list[str], prefix: str) -> int: def test_rocm_base_tracks_cuda_vllm_release() -> None: - # CUDA CI can target a main-branch nightly independently of the stable - # release images used by the CUDA and ROCm distribution Dockerfiles. cuda_base = _docker_arg(CUDA_RELEASE_DOCKERFILE, "BASE_IMAGE") - _, _, cuda_release = cuda_base.rpartition(":") + cuda_image, _, cuda_release = cuda_base.rpartition(":") rocm_base = _docker_arg(ROCM_DOCKERFILE, "BASE_IMAGE") image_ref, separator, image_tag = rocm_base.rpartition(":") assert separator, f"expected a tagged ROCm base image, got {rocm_base}" - assert image_ref.rsplit("/", 1)[-1] == "vllm-openai-rocm", image_ref - assert image_tag == cuda_release + assert image_ref == cuda_image + assert image_tag == f"{cuda_release}-rocm" + assert cuda_release == _docker_arg(CUDA_CI_DOCKERFILE, "VLLM_PRECOMPILED_WHEEL_COMMIT") def test_rocm_defaults_to_prebuilt_base_image() -> None: @@ -107,11 +107,10 @@ def test_rocm_build_context_excludes_git_history() -> None: def test_rocm_source_ref_tracks_cuda_vllm_release() -> None: - cuda_base = _docker_arg(CUDA_RELEASE_DOCKERFILE, "BASE_IMAGE") - _, _, cuda_release = cuda_base.rpartition(":") + cuda_release = _docker_arg(CUDA_CI_DOCKERFILE, "VLLM_VERSION") rocm_source_ref = _docker_arg(ROCM_DOCKERFILE, "VLLM_VERSION_OR_COMMIT_HASH") - assert rocm_source_ref == cuda_release + assert rocm_source_ref == f"v{cuda_release}" def test_rocm_dockerfile_contains_vllm_api_canary() -> None: diff --git a/tests/inputs/test_mm_processor.py b/tests/inputs/test_mm_processor.py index 09bc5aaac..de2de98fb 100644 --- a/tests/inputs/test_mm_processor.py +++ b/tests/inputs/test_mm_processor.py @@ -1,14 +1,17 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project +from importlib import import_module from types import SimpleNamespace from unittest.mock import Mock import pytest from transformers import BatchFeature +from vllm.config.multimodal import MultiModalDummyOptions from vllm.multimodal.parse import AudioProcessorItems, ImageProcessorItems, MultiModalDataItems +from vllm.multimodal.processing import BaseMultiModalProcessor -from vllm_omni.inputs.mm_processor import OmniMultiModalProcessor +from vllm_omni.inputs.mm_processor import OmniDummyInputsBuilder, OmniMultiModalProcessor pytestmark = [pytest.mark.core_model, pytest.mark.cpu] @@ -47,3 +50,77 @@ def test_custom_processor_bridge_preserves_prompt_kwargs_and_passthrough(counts, ) assert dict(result) == ({"features": "processed", "embedding": "preserve"} if counts else {"features": "processed"}) assert kwargs == before + + +@pytest.mark.parametrize( + "module_name,builder_name,processor_name,expected_kwargs", + [ + ( + "cosyvoice3", + "CosyVoice3DummyInputsBuilder", + "CosyVoice3MultiModalProcessor", + {"prompt_text": "Testing my voices. Why should I not?"}, + ), + ( + "glm_tts", + "GLMTTSDummyInputsBuilder", + "GLMTTSMultiModalProcessor", + {"prompt_text": "This is the reference voice."}, + ), + ( + "omnivoice", + "OmniVoiceDummyInputsBuilder", + "OmniVoiceMultiModalProcessor", + {"ref_text": "Testing voice cloning."}, + ), + ("mimo_audio", "MiMoAudioLLMDummyInputsBuilder", "MiMoAudioLLMMultiModalProcessor", {}), + ], +) +def test_dummy_budget_preserves_model_conditioning(module_name, builder_name, processor_name, expected_kwargs): + """The v0.31 budget path must reach each model's custom builder hook.""" + module = import_module(f"vllm_omni.model_executor.models.{module_name}.{module_name}") + builder = object.__new__(getattr(module, builder_name)) + assert isinstance(builder, OmniDummyInputsBuilder) + items = MultiModalDataItems({}) + builder.info = SimpleNamespace(ctx=SimpleNamespace(tokenizer=None), parse_mm_data=Mock(return_value=items)) + builder.get_dummy_mm_data = Mock(return_value={}) + processor = object.__new__(getattr(module, processor_name)) + processor.dummy_inputs = builder + + inputs = processor.get_dummy_inputs(128, {"audio": 1}, MultiModalDummyOptions()) + + assert inputs.mm_data_items is items + assert inputs.hf_processor_mm_kwargs == expected_kwargs + assert inputs.prompt == ("<|empty|>" if module_name == "mimo_audio" else []) + + +def test_dummy_budget_keeps_upstream_path_for_standard_builders(monkeypatch): + class Processor(OmniMultiModalProcessor): + def _get_mm_fields_config(self, *args): + return {} + + def _get_prompt_updates(self, *args): + return [] + + processor = object.__new__(Processor) + processor.dummy_inputs = SimpleNamespace() + expected = object() + upstream = Mock(return_value=expected) + monkeypatch.setattr(BaseMultiModalProcessor, "get_dummy_inputs", upstream) + options = MultiModalDummyOptions() + + assert processor.get_dummy_inputs(128, {"audio": 1}, options) is expected + upstream.assert_called_once_with(128, {"audio": 1}, options) + + +def test_voxtral_dummy_budget_uses_audio_token_prompt(): + from vllm_omni.model_executor.models.voxtral_tts.voxtral_tts_audio_generation import VoxtralTTSMultiModalProcessor + + processor = object.__new__(VoxtralTTSMultiModalProcessor) + expected = SimpleNamespace(prompt=[1, 25, 24, 35]) + builder = SimpleNamespace(get_dummy_processor_inputs=Mock(return_value=expected)) + processor.dummy_inputs = builder + options = MultiModalDummyOptions() + + assert processor.get_dummy_inputs(128, {"audio": 1}, options) is expected + builder.get_dummy_processor_inputs.assert_called_once_with(128, {"audio": 1}, options) diff --git a/tests/model_executor/stage_input_processors/test_qwen3_omni_streaming_helpers.py b/tests/model_executor/stage_input_processors/test_qwen3_omni_streaming_helpers.py index 91a56d1db..e191ddb1e 100644 --- a/tests/model_executor/stage_input_processors/test_qwen3_omni_streaming_helpers.py +++ b/tests/model_executor/stage_input_processors/test_qwen3_omni_streaming_helpers.py @@ -986,6 +986,27 @@ def test_cosyvoice3_full_payload_replace_keys_present() -> None: ) +def test_cosyvoice3_conditioning_replaces_snapshot_while_audio_accumulates() -> None: + from vllm_omni.model_executor.stage_input_processors.cosyvoice3 import _FULL_PAYLOAD_REPLACE_KEYS + from vllm_omni.outputs.mm_outputs import MultimodalPayload + from vllm_omni.outputs.output_modality import OutputModality + + previous = {key: torch.ones(1, 174) for key in _FULL_PAYLOAD_REPLACE_KEYS} + padded = {key: torch.zeros(1, 1500) for key in _FULL_PAYLOAD_REPLACE_KEYS} + previous["embed.speech_token_len"] = torch.tensor([174]) + padded["embed.speech_token_len"] = torch.tensor([174]) + payload = MultimodalPayload.from_dict({**previous, "audio": torch.ones(2)}) + incoming = MultimodalPayload.from_dict({**padded, "audio": torch.ones(3)}) + assert payload is not None and incoming is not None + + payload = payload.merged_with(incoming) + payload.consolidate_tensors(OutputModality.AUDIO) + + for key in _FULL_PAYLOAD_REPLACE_KEYS: + assert torch.equal(payload[key], padded[key]) + assert torch.equal(payload["audio"], torch.ones(5)) + + def test_ming_flash_omni_thinker2talker_token_only_smoke() -> None: """Smoke: ming_flash_omni token-only carries voice metadata.""" from vllm_omni.model_executor.stage_input_processors.ming_flash_omni import ( diff --git a/tests/worker_v2/test_capture_query_bound_gpu.py b/tests/worker_v2/test_capture_query_bound_gpu.py index 122ff0244..2b4c37878 100644 --- a/tests/worker_v2/test_capture_query_bound_gpu.py +++ b/tests/worker_v2/test_capture_query_bound_gpu.py @@ -46,7 +46,6 @@ def _check_prefill(): state = OmniModelState.__new__(OmniModelState) state.model_config = SimpleNamespace(max_model_len=256) state.vllm_config = c - state.max_model_len = 256 state.supports_mm_inputs = False with set_current_vllm_config(c): group = AttentionGroup(FlashAttentionBackend, ["attn"], spec, 0) diff --git a/vllm_omni/inputs/mm_processor.py b/vllm_omni/inputs/mm_processor.py index 297b4d13e..33b870a26 100644 --- a/vllm_omni/inputs/mm_processor.py +++ b/vllm_omni/inputs/mm_processor.py @@ -7,6 +7,7 @@ from collections.abc import Mapping from typing import TypeVar from transformers import BatchFeature +from vllm.config.multimodal import BaseDummyOptions, MultiModalDummyOptions from vllm.multimodal.parse import MultiModalDataItems from vllm.multimodal.processing import ( BaseDummyInputsBuilder, @@ -26,18 +27,14 @@ class OmniDummyInputsBuilder(BaseDummyInputsBuilder[_I]): self, seq_len: int, mm_counts: Mapping[str, int], - mm_options: Mapping[str, object], + mm_options: Mapping[str, BaseDummyOptions] | None = None, ) -> ProcessorInputs: dummy_text = self.get_dummy_text(mm_counts) - dummy_mm_data = self.get_dummy_mm_data(seq_len, mm_counts, mm_options) + dummy_mm_data = self.get_dummy_mm_data(seq_len, mm_counts, MultiModalDummyOptions(mm_options or {})) dummy_mm_items = self.info.parse_mm_data(dummy_mm_data, validate=False) tokenizer = self.info.ctx.tokenizer - dummy_prompt = ( - [] - if tokenizer is None - else cached_encode(tokenizer, dummy_text, truncation=False) - ) + dummy_prompt = [] if tokenizer is None else cached_encode(tokenizer, dummy_text, truncation=False) return ProcessorInputs(prompt=dummy_prompt, mm_data_items=dummy_mm_items) @@ -55,12 +52,10 @@ class OmniMultiModalProcessor(BaseMultiModalProcessor[_I]): self, seq_len: int, mm_counts: Mapping[str, int], - mm_options: Mapping[str, object], + mm_options: MultiModalDummyOptions, ) -> ProcessorInputs: if isinstance(self.dummy_inputs, OmniDummyInputsBuilder): - return self.dummy_inputs.get_dummy_processor_inputs( - seq_len, mm_counts, mm_options - ) + return self.dummy_inputs.get_dummy_processor_inputs(seq_len, mm_counts, mm_options) return super().get_dummy_inputs(seq_len, mm_counts, mm_options) def _apply_hf_processor_main( diff --git a/vllm_omni/model_executor/models/cosyvoice3/cosyvoice3.py b/vllm_omni/model_executor/models/cosyvoice3/cosyvoice3.py index 5552c7360..ab96becf6 100644 --- a/vllm_omni/model_executor/models/cosyvoice3/cosyvoice3.py +++ b/vllm_omni/model_executor/models/cosyvoice3/cosyvoice3.py @@ -28,7 +28,6 @@ from vllm.multimodal import MULTIMODAL_REGISTRY from vllm.multimodal.inputs import MultiModalFieldConfig, MultiModalKwargsItems from vllm.multimodal.parse import MultiModalDataItems, MultiModalDataParser from vllm.multimodal.processing import ( - BaseDummyInputsBuilder, BaseProcessingInfo, ProcessorInputs, PromptIndexTargets, diff --git a/vllm_omni/model_executor/models/glm_tts/glm_tts.py b/vllm_omni/model_executor/models/glm_tts/glm_tts.py index 2eef3aa44..773559339 100644 --- a/vllm_omni/model_executor/models/glm_tts/glm_tts.py +++ b/vllm_omni/model_executor/models/glm_tts/glm_tts.py @@ -38,7 +38,6 @@ from vllm.multimodal import MULTIMODAL_REGISTRY from vllm.multimodal.inputs import MultiModalFieldConfig, MultiModalKwargsItems from vllm.multimodal.parse import MultiModalDataItems, MultiModalDataParser from vllm.multimodal.processing import ( - BaseDummyInputsBuilder, BaseProcessingInfo, ProcessorInputs, PromptIndexTargets, diff --git a/vllm_omni/model_executor/models/mimo_audio/mimo_audio.py b/vllm_omni/model_executor/models/mimo_audio/mimo_audio.py index f364ecf60..338f145ad 100644 --- a/vllm_omni/model_executor/models/mimo_audio/mimo_audio.py +++ b/vllm_omni/model_executor/models/mimo_audio/mimo_audio.py @@ -29,7 +29,6 @@ from vllm.multimodal.inputs import ( ) from vllm.multimodal.parse import AudioProcessorItems, MultiModalDataItems, MultiModalDataParser from vllm.multimodal.processing import ( - BaseDummyInputsBuilder, BaseProcessingInfo, ProcessorInputs, PromptReplacement, diff --git a/vllm_omni/model_executor/models/omnivoice/omnivoice.py b/vllm_omni/model_executor/models/omnivoice/omnivoice.py index f73c6fac8..bca547eb8 100644 --- a/vllm_omni/model_executor/models/omnivoice/omnivoice.py +++ b/vllm_omni/model_executor/models/omnivoice/omnivoice.py @@ -28,7 +28,6 @@ from vllm.multimodal.inputs import ( ) from vllm.multimodal.parse import MultiModalDataItems, MultiModalDataParser from vllm.multimodal.processing import ( - BaseDummyInputsBuilder, BaseProcessingInfo, ProcessorInputs, PromptIndexTargets,