A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 14, 05:30 UTC
[Multimodal] Consolidate mm inputs into MultiModalFeatureSpec (#23779)
Signed-off-by: sfeng33 <4florafeng@gmail.com>
Flora Feng committed
Aug 29, 2025 at 03:36 UTC
69f46359dd5b36c1a059a0a8b729be1bd86394e8
16 files changed
+143
-146
tests/tokenization/test_detokenize.py
-2
@@ -64,8 +64,6 @@ def _run_incremental_decode(tokenizer,
64
request = EngineCoreRequest("",
65
prompt_token_ids,
66
None,
67
- None,
68
- None,
67
params,
68
None,
69
None,
tests/v1/core/test_kv_cache_utils.py
+13
-9
@@ -7,7 +7,8 @@ import pytest
7
import torch
8
9
from vllm.config import ModelConfig, SchedulerConfig, VllmConfig
10
-from vllm.multimodal.inputs import MultiModalKwargsItem, PlaceholderRange
10
+from vllm.multimodal.inputs import (MultiModalFeatureSpec,
11
+ MultiModalKwargsItem, PlaceholderRange)
12
from vllm.sampling_params import SamplingParams
13
from vllm.utils import GiB_bytes, sha256, sha256_cbor_64bit
14
from vllm.v1.core.kv_cache_manager import KVCacheManager
@@ -37,17 +38,20 @@ def make_request(
38
mm_hashes: Optional[list[str]] = None,
39
cache_salt: Optional[str] = None,
40
):
40
- if mm_positions is None:
41
- mm_kwargs = None
42
- else:
43
- mm_item = MultiModalKwargsItem.dummy("dummy_m")
44
- mm_kwargs = [mm_item] * len(mm_positions)
41
+ mm_features = []
42
+ if mm_positions is not None:
43
+ for j, position in enumerate(mm_positions):
44
+ identifier = mm_hashes[j] if mm_hashes else f"hash_{j}"
45
+ mm_feature = MultiModalFeatureSpec(
46
+ data=MultiModalKwargsItem.dummy("dummy_m"),
47
+ mm_position=position,
48
+ identifier=identifier,
49
+ modality="image")
50
+ mm_features.append(mm_feature)
51
52
return Request(request_id=request_id,
53
prompt_token_ids=prompt_token_ids,
48
- multi_modal_kwargs=mm_kwargs,
49
- multi_modal_hashes=mm_hashes,
50
- multi_modal_placeholders=mm_positions,
54
+ mm_features=mm_features if mm_features else None,
55
sampling_params=SamplingParams(max_tokens=17),
56
pooling_params=None,
57
eos_token_id=100,
tests/v1/core/test_prefix_caching.py
+13
-9
@@ -9,7 +9,8 @@ import pytest
9
import torch
10
11
from vllm.distributed.kv_events import AllBlocksCleared, BlockRemoved
12
-from vllm.multimodal.inputs import MultiModalKwargsItem, PlaceholderRange
12
+from vllm.multimodal.inputs import (MultiModalFeatureSpec,
13
+ MultiModalKwargsItem, PlaceholderRange)
14
from vllm.sampling_params import SamplingParams
15
from vllm.utils import sha256, sha256_cbor_64bit
16
from vllm.v1.core.block_pool import BlockPool
@@ -32,17 +33,20 @@ def make_request(
33
prompt_logprobs: Optional[int] = None,
34
cache_salt: Optional[str] = None,
35
):
35
- if mm_positions is None:
36
- mm_kwargs = None
37
- else:
38
- mm_item = MultiModalKwargsItem.dummy("dummy_m")
39
- mm_kwargs = [mm_item] * len(mm_positions)
36
+ mm_features = []
37
+ if mm_positions is not None:
38
+ for j, position in enumerate(mm_positions):
39
+ identifier = mm_hashes[j] if mm_hashes else f"hash_{j}"
40
+ mm_feature = MultiModalFeatureSpec(
41
+ data=MultiModalKwargsItem.dummy("dummy_m"),
42
+ mm_position=position,
43
+ identifier=identifier,
44
+ modality="image")
45
+ mm_features.append(mm_feature)
46
47
return Request(request_id=request_id,
48
prompt_token_ids=prompt_token_ids,
43
- multi_modal_kwargs=mm_kwargs,
44
- multi_modal_hashes=mm_hashes,
45
- multi_modal_placeholders=mm_positions,
49
+ mm_features=mm_features if mm_features else None,
50
sampling_params=SamplingParams(
51
max_tokens=17, prompt_logprobs=prompt_logprobs),
52
pooling_params=None,
tests/v1/core/test_scheduler.py
+14
-12
@@ -8,7 +8,8 @@ import torch
8
9
from vllm.config import (CacheConfig, KVTransferConfig, ModelConfig,
10
SchedulerConfig, SpeculativeConfig, VllmConfig)
11
-from vllm.multimodal.inputs import MultiModalKwargsItem, PlaceholderRange
11
+from vllm.multimodal.inputs import (MultiModalFeatureSpec,
12
+ MultiModalKwargsItem, PlaceholderRange)
13
from vllm.sampling_params import GuidedDecodingParams, SamplingParams
14
from vllm.v1.core.sched.output import CachedRequestData, SchedulerOutput
15
from vllm.v1.core.sched.scheduler import Scheduler
@@ -1308,21 +1309,24 @@ def create_requests_with_priority(
1309
prompt_logprobs=prompt_logprobs)
1310
requests = []
1311
for i in range(num_requests):
1312
+ mm_features = []
1313
if mm_positions is not None:
1314
mm_position = mm_positions[i]
1313
- mm_item = MultiModalKwargsItem.dummy("dummy_m")
1314
- mm_kwargs = [mm_item] * len(mm_position)
1315
- else:
1316
- mm_position = None
1317
- mm_kwargs = None
1315
+ for j, position in enumerate(mm_position):
1316
+ identifier = f"hash{i}_{j}"
1317
+ mm_feature = MultiModalFeatureSpec(
1318
+ data=MultiModalKwargsItem.dummy("dummy_m"),
1319
+ mm_position=position,
1320
+ identifier=identifier,
1321
+ modality="image")
1322
+ mm_features.append(mm_feature)
1323
+
1324
request = Request(
1325
request_id=f"{i + starting_idx}",
1326
prompt_token_ids=[i + starting_idx] * num_tokens,
1327
sampling_params=sampling_params,
1328
pooling_params=None,
1323
- multi_modal_kwargs=mm_kwargs,
1324
- multi_modal_placeholders=mm_position,
1325
- multi_modal_hashes=None,
1329
+ mm_features=mm_features if mm_features else None,
1330
eos_token_id=EOS_TOKEN_ID,
1331
arrival_time=arrival_times[i],
1332
priority=priorities[i],
@@ -1801,9 +1805,7 @@ def test_schedule_skip_tokenizer_init_structured_output_request():
1805
request = Request(
1806
request_id="0",
1807
prompt_token_ids=[0, 1],
1804
- multi_modal_kwargs=None,
1805
- multi_modal_hashes=None,
1806
- multi_modal_placeholders=None,
1808
+ mm_features=None,
1809
sampling_params=sampling_params,
1810
pooling_params=None,
1811
eos_token_id=EOS_TOKEN_ID,
tests/v1/core/utils.py
+15
-15
@@ -6,7 +6,8 @@ import torch
6
7
from vllm.config import (CacheConfig, KVTransferConfig, ModelConfig,
8
SchedulerConfig, SpeculativeConfig, VllmConfig)
9
-from vllm.multimodal.inputs import MultiModalKwargsItem, PlaceholderRange
9
+from vllm.multimodal.inputs import (MultiModalFeatureSpec,
10
+ MultiModalKwargsItem, PlaceholderRange)
11
from vllm.sampling_params import SamplingParams
12
from vllm.v1.core.kv_cache_utils import (get_request_block_hasher,
13
init_none_hash)
@@ -139,19 +140,20 @@ def create_requests(
140
prompt_logprobs=prompt_logprobs)
141
requests = []
142
for i in range(num_requests):
143
+ mm_features = []
144
if mm_positions is not None:
145
mm_position = mm_positions[i]
144
- mm_item = MultiModalKwargsItem.dummy("dummy_m")
145
- mm_kwargs = [mm_item] * len(mm_position)
146
- # Dummy hash for each mm item should be unique
147
- # since encoder cache tracks entries by hash
148
- mm_hashes = [
149
- "hash" + str(i) + "_" + str(j) for j in range(len(mm_position))
150
- ]
151
- else:
152
- mm_position = None
153
- mm_kwargs = None
154
- mm_hashes = None
146
+ for j, position in enumerate(mm_position):
147
+ # Dummy hash for each mm item should be unique
148
+ # since encoder cache tracks entries by hash
149
+ identifier = f"hash{i}_{j}"
150
+ mm_feature = MultiModalFeatureSpec(
151
+ data=MultiModalKwargsItem.dummy("dummy_m"),
152
+ mm_position=position,
153
+ identifier=identifier,
154
+ modality="image")
155
+ mm_features.append(mm_feature)
156
+
157
prompt_token_ids = ([0] * num_tokens if same_prompt else [i] *
158
num_tokens)
159
request = Request(
@@ -159,9 +161,7 @@ def create_requests(
161
prompt_token_ids=prompt_token_ids,
162
sampling_params=sampling_params,
163
pooling_params=None,
162
- multi_modal_kwargs=mm_kwargs,
163
- multi_modal_placeholders=mm_position,
164
- multi_modal_hashes=mm_hashes,
164
+ mm_features=mm_features if mm_features else None,
165
eos_token_id=EOS_TOKEN_ID,
166
block_hasher=block_hasher,
167
)
tests/v1/engine/test_engine_core.py
+1
-3
@@ -35,9 +35,7 @@ def make_request() -> EngineCoreRequest:
35
return EngineCoreRequest(
36
request_id=str(uuid.uuid4()),
37
prompt_token_ids=PROMPT_TOKENS,
38
- mm_kwargs=None,
39
- mm_hashes=None,
40
- mm_placeholders=None,
38
+ mm_features=None,
39
sampling_params=SamplingParams(),
40
pooling_params=None,
41
eos_token_id=None,
tests/v1/engine/test_engine_core_client.py
+1
-3
@@ -52,9 +52,7 @@ def make_request(
52
return EngineCoreRequest(
53
request_id=str(uuid.uuid4()),
54
prompt_token_ids=prompt_tokens_ids,
55
- mm_kwargs=None,
56
- mm_hashes=None,
57
- mm_placeholders=None,
55
+ mm_features=None,
56
sampling_params=params,
57
pooling_params=None,
58
eos_token_id=None,
tests/v1/engine/test_fast_incdec_prefix_err.py
+8
-10
@@ -26,16 +26,14 @@ def test_fast_inc_detok_invalid_utf8_err_case():
26
prompt_token_ids = [107, 4606, 236787, 107]
27
params = SamplingParams(skip_special_tokens=True)
28
request = EngineCoreRequest(
29
- "test",
30
- prompt_token_ids,
31
- None,
32
- None,
33
- None,
34
- params,
35
- None,
36
- None,
37
- 0.0,
38
- None,
29
+ request_id="test",
30
+ prompt_token_ids=prompt_token_ids,
31
+ mm_features=None,
32
+ sampling_params=params,
33
+ pooling_params=None,
34
+ eos_token_id=None,
35
+ arrival_time=0.0,
36
+ lora_request=None,
37
cache_salt=None,
38
data_parallel_rank=None,
39
)
tests/v1/engine/test_output_processor.py
+10
-20
@@ -52,11 +52,9 @@ def test_incremental_detokenization(request_output_kind: RequestOutputKind,
52
requests = [
53
EngineCoreRequest(request_id=f"request-{idx}",
54
prompt_token_ids=prompt_tokens,
55
- arrival_time=0,
56
- mm_kwargs=None,
57
- mm_hashes=None,
58
- mm_placeholders=None,
55
+ mm_features=None,
56
eos_token_id=None,
57
+ arrival_time=0,
58
lora_request=None,
59
cache_salt=None,
60
data_parallel_rank=None,
@@ -401,11 +399,9 @@ def test_logprobs_processor(request_output_kind: RequestOutputKind,
399
requests = [
400
EngineCoreRequest(request_id=request_id_list[idx],
401
prompt_token_ids=prompt_tokens,
404
- arrival_time=0,
405
- mm_kwargs=None,
406
- mm_hashes=None,
407
- mm_placeholders=None,
402
+ mm_features=None,
403
eos_token_id=None,
404
+ arrival_time=0,
405
lora_request=None,
406
cache_salt=None,
407
data_parallel_rank=None,
@@ -566,11 +562,9 @@ def test_stop_token(include_stop_str_in_output: bool,
562
request = EngineCoreRequest(
563
request_id=request_id,
564
prompt_token_ids=prompt_tokens,
569
- arrival_time=0,
570
- mm_kwargs=None,
571
- mm_hashes=None,
572
- mm_placeholders=None,
565
+ mm_features=None,
566
eos_token_id=eos_token_id,
567
+ arrival_time=0,
568
lora_request=None,
569
cache_salt=None,
570
data_parallel_rank=None,
@@ -665,11 +659,9 @@ def test_stop_string(include_stop_str_in_output: bool,
659
EngineCoreRequest(
660
request_id=request_id_list[idx],
661
prompt_token_ids=prompt_tokens,
668
- arrival_time=0,
669
- mm_kwargs=None,
670
- mm_hashes=None,
671
- mm_placeholders=None,
662
+ mm_features=None,
663
eos_token_id=None,
664
+ arrival_time=0,
665
lora_request=None,
666
cache_salt=None,
667
data_parallel_rank=None,
@@ -781,11 +773,9 @@ def test_iteration_stats(dummy_test_vectors):
773
EngineCoreRequest(
774
request_id=f"request-{idx}",
775
prompt_token_ids=prompt_tokens,
784
- arrival_time=0,
785
- mm_kwargs=None,
786
- mm_hashes=None,
787
- mm_placeholders=None,
776
+ mm_features=None,
777
eos_token_id=None,
778
+ arrival_time=0,
779
lora_request=None,
780
cache_salt=None,
781
data_parallel_rank=None,
tests/v1/kv_connector/unit/utils.py
+1
-3
@@ -162,9 +162,7 @@ def create_request(request_id: int,
162
prompt_token_ids=prompt_token_ids,
163
sampling_params=sampling_params,
164
pooling_params=None,
165
- multi_modal_kwargs=None,
166
- multi_modal_placeholders=None,
167
- multi_modal_hashes=None,
165
+ mm_features=None,
166
eos_token_id=EOS_TOKEN_ID,
167
block_hasher=get_request_block_hasher(block_size, hash_fn),
168
)
vllm/multimodal/cache.py
+13
-3
@@ -12,9 +12,9 @@ from vllm.logger import init_logger
12
from vllm.utils import GiB_bytes, LRUCache
13
from vllm.utils.jsontree import json_map_leaves, json_reduce_leaves
14
15
-from .inputs import (MultiModalFieldElem, MultiModalKwargs,
16
- MultiModalKwargsItem, MultiModalKwargsItems,
17
- NestedTensors)
15
+from .inputs import (MultiModalFeatureSpec, MultiModalFieldElem,
16
+ MultiModalKwargs, MultiModalKwargsItem,
17
+ MultiModalKwargsItems, NestedTensors)
18
19
if TYPE_CHECKING:
20
from vllm.config import ModelConfig, VllmConfig
@@ -418,6 +418,16 @@ class BaseMultiModalReceiverCache(
418
MultiModalKwargsItem]):
419
"""The required interface for caches on P1."""
420
421
+ def get_and_update_features(
422
+ self,
423
+ mm_features: list["MultiModalFeatureSpec"],
424
+ ) -> list["MultiModalFeatureSpec"]:
425
+ """Update multimodal features with cached encoder outputs."""
426
+ for feature in mm_features:
427
+ feature.data = self.get_and_update_item(feature.data,
428
+ feature.identifier)
429
+ return mm_features
430
+
431
432
class MultiModalReceiverCache(BaseMultiModalReceiverCache):
433
"""
vllm/multimodal/inputs.py
+23
@@ -198,6 +198,29 @@ A dictionary containing nested tensors which have been batched via
198
"""
199
200
201
+@dataclass
202
+class MultiModalFeatureSpec:
203
+ """
204
+ Represents a single multimodal input with its processed data and metadata.
205
+
206
+ Used by the V1 engine to track multimodal data through processing and
207
+ caching. A request containing multiple multimodal items will have one
208
+ MultiModalFeatureSpec per item.
209
+ """
210
+
211
+ data: Optional["MultiModalKwargsItem"]
212
+ """Multimodal data for this feature"""
213
+
214
+ modality: str
215
+ """Based on the input, e.g., "image", "audio", "video"."""
216
+
217
+ identifier: str
218
+ """mm_hash or uuid for caching encoder outputs."""
219
+
220
+ mm_position: PlaceholderRange
221
+ """e.g., PlaceholderRange(offset=2, length=336)"""
222
+
223
+
224
@dataclass
225
class MultiModalFieldElem:
226
"""
vllm/v1/engine/__init__.py
+2
-5
@@ -3,14 +3,13 @@
3
4
import enum
5
import time
6
-from collections.abc import Sequence
6
from typing import Any, Optional, Union
7
8
import msgspec
9
import torch
10
11
from vllm.lora.request import LoRARequest
13
-from vllm.multimodal.inputs import MultiModalKwargsItem, PlaceholderRange
12
+from vllm.multimodal.inputs import MultiModalFeatureSpec
13
from vllm.pooling_params import PoolingParams
14
from vllm.sampling_params import SamplingParams
15
from vllm.v1.metrics.stats import SchedulerStats
@@ -48,9 +47,7 @@ class EngineCoreRequest(
47
48
request_id: str
49
prompt_token_ids: list[int]
51
- mm_kwargs: Optional[Sequence[Optional[MultiModalKwargsItem]]]
52
- mm_hashes: Optional[list[str]]
53
- mm_placeholders: Optional[list[PlaceholderRange]]
50
+ mm_features: Optional[list[MultiModalFeatureSpec]]
51
sampling_params: Optional[SamplingParams]
52
pooling_params: Optional[PoolingParams]
53
eos_token_id: Optional[int]
vllm/v1/engine/core.py
+7
-9
@@ -434,15 +434,13 @@ class EngineCore:
434
This function could be directly used in input processing thread to allow
435
request initialization running in parallel with Model forward
436
"""
437
- if request.mm_hashes is not None:
438
- assert request.mm_kwargs is not None
439
-
440
- # Note on thread safety: no race condition.
441
- # `mm_receiver_cache` is reset at the end of LLMEngine init,
442
- # and will only accessed in the input processing thread afterwards.
443
- if self.mm_receiver_cache is not None:
444
- request.mm_kwargs = self.mm_receiver_cache.get_and_update(
445
- request.mm_kwargs, request.mm_hashes)
437
+ # Note on thread safety: no race condition.
438
+ # `mm_receiver_cache` is reset at the end of LLMEngine init,
439
+ # and will only accessed in the input processing thread afterwards.
440
+ if self.mm_receiver_cache is not None and request.mm_features:
441
+ request.mm_features = (
442
+ self.mm_receiver_cache.get_and_update_features(
443
+ request.mm_features))
444
445
req = Request.from_engine_core_request(request,
446
self.request_block_hasher)
vllm/v1/engine/processor.py
+12
-19
@@ -12,7 +12,7 @@ from vllm.inputs.preprocess import InputPreprocessor
12
from vllm.lora.request import LoRARequest
13
from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalRegistry
14
from vllm.multimodal.cache import processor_cache_from_config
15
-from vllm.multimodal.inputs import MultiModalKwargsItem, PlaceholderRange
15
+from vllm.multimodal.inputs import MultiModalFeatureSpec
16
from vllm.multimodal.processing import EncDecMultiModalProcessor
17
from vllm.multimodal.utils import argsort_mm_positions
18
from vllm.pooling_params import PoolingParams
@@ -346,9 +346,8 @@ class Processor:
346
pooling_params = params.clone()
347
348
# Multimodal related.
349
- sorted_mm_inputs: Optional[list[Optional[MultiModalKwargsItem]]] = None
350
- sorted_mm_positions: Optional[list[PlaceholderRange]] = None
351
- sorted_mm_hashes: Optional[list[str]] = None
349
+ mm_features: Optional[list[MultiModalFeatureSpec]] = None
350
+
351
if decoder_inputs["type"] == "multimodal":
352
decoder_mm_inputs = decoder_inputs["mm_kwargs"]
353
decoder_mm_positions = decoder_inputs["mm_placeholders"]
@@ -359,25 +358,19 @@ class Processor:
358
# in the input sequence.
359
sorted_mm_idxs = argsort_mm_positions(decoder_mm_positions)
360
362
- sorted_mm_inputs = [
363
- decoder_mm_inputs[modality][idx]
364
- for modality, idx in sorted_mm_idxs
365
- ]
366
- sorted_mm_positions = [
367
- decoder_mm_positions[modality][idx]
368
- for modality, idx in sorted_mm_idxs
369
- ]
370
- sorted_mm_hashes = [
371
- decoder_mm_hashes[modality][idx]
372
- for modality, idx in sorted_mm_idxs
373
- ]
361
+ mm_features = []
362
+ for modality, idx in sorted_mm_idxs:
363
+ mm_features.append(
364
+ MultiModalFeatureSpec(
365
+ data=decoder_mm_inputs[modality][idx],
366
+ modality=modality,
367
+ identifier=decoder_mm_hashes[modality][idx],
368
+ mm_position=decoder_mm_positions[modality][idx]))
369
370
return decoder_inputs.get("prompt"), EngineCoreRequest(
371
request_id=request_id,
372
prompt_token_ids=decoder_inputs["prompt_token_ids"],
378
- mm_kwargs=sorted_mm_inputs,
379
- mm_hashes=sorted_mm_hashes,
380
- mm_placeholders=sorted_mm_positions,
373
+ mm_features=mm_features,
374
sampling_params=sampling_params,
375
pooling_params=pooling_params,
376
eos_token_id=eos_token_id,
vllm/v1/request.py
+10
-24
@@ -6,10 +6,9 @@ import time
6
from functools import partial
7
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
8
9
-from vllm.multimodal.inputs import MultiModalKwargsItem, PlaceholderRange
9
+from vllm.multimodal.inputs import MultiModalFeatureSpec
10
from vllm.pooling_params import PoolingParams
11
from vllm.sampling_params import SamplingParams
12
-from vllm.utils import is_list_of
12
from vllm.v1.engine import (EngineCoreEvent, EngineCoreEventType,
13
EngineCoreRequest, FinishReason)
14
from vllm.v1.structured_output.request import StructuredOutputRequest
@@ -26,14 +25,12 @@ class Request:
25
self,
26
request_id: str,
27
prompt_token_ids: list[int],
29
- multi_modal_kwargs: Optional[list[MultiModalKwargsItem]],
30
- multi_modal_hashes: Optional[list[str]],
31
- multi_modal_placeholders: Optional[list[PlaceholderRange]],
28
sampling_params: Optional[SamplingParams],
29
pooling_params: Optional[PoolingParams],
30
eos_token_id: Optional[int],
31
client_index: int = 0,
32
arrival_time: Optional[float] = None,
33
+ mm_features: Optional[list[MultiModalFeatureSpec]] = None,
34
lora_request: Optional["LoRARequest"] = None,
35
structured_output_request: Optional["StructuredOutputRequest"] = None,
36
cache_salt: Optional[str] = None,
@@ -89,16 +86,14 @@ class Request:
86
self.cache_salt: Optional[str] = cache_salt
87
88
# Multi-modal related
92
- self.mm_positions = multi_modal_placeholders or []
93
- self.mm_kwargs = multi_modal_kwargs or []
94
- self.mm_hashes: list[str] = multi_modal_hashes or []
95
- self.num_encoder_inputs = len(self.mm_kwargs)
89
+ self.mm_features = mm_features or []
90
+ self.num_encoder_inputs = len(self.mm_features)
91
self.has_encoder_inputs = self.num_encoder_inputs > 0
97
-
98
- # Sanity check
99
- assert len(self.mm_kwargs) == len(self.mm_positions)
100
- if self.mm_hashes:
101
- assert len(self.mm_kwargs) == len(self.mm_hashes)
92
+ # TODO(sfeng33): Remove these legacy fields after clearing out all
93
+ # references in scheduler and model runner
94
+ self.mm_positions = [f.mm_position for f in self.mm_features]
95
+ self.mm_kwargs = [f.data for f in self.mm_features]
96
+ self.mm_hashes = [f.identifier for f in self.mm_features]
97
98
# Read-only views
99
# Prevent directly appending to these lists since
@@ -126,20 +121,11 @@ class Request:
121
cls, request: EngineCoreRequest,
122
block_hasher: Optional[Callable[["Request"], list["BlockHash"]]]
123
) -> "Request":
129
- if request.mm_kwargs is not None:
130
- mm_kwargs_lst = list(request.mm_kwargs)
131
- assert is_list_of(mm_kwargs_lst, MultiModalKwargsItem), (
132
- "mm_kwargs was not updated in EngineCore.add_request")
133
- else:
134
- mm_kwargs_lst = None
135
-
124
return cls(
125
request_id=request.request_id,
126
client_index=request.client_index,
127
prompt_token_ids=request.prompt_token_ids,
140
- multi_modal_kwargs=mm_kwargs_lst,
141
- multi_modal_hashes=request.mm_hashes,
142
- multi_modal_placeholders=request.mm_placeholders,
128
+ mm_features=request.mm_features,
129
sampling_params=request.sampling_params,
130
pooling_params=request.pooling_params,
131
eos_token_id=request.eos_token_id,