[Refactor] Remove multiple dead codes (#50285)
Signed-off-by: yewentao256 <zhyanwentao@126.com>
Wentao Ye committed
Aug 3, 2026 at 10:59 UTC
0cf49a5d15d18275972d0cd35c6968731a5d18e1
22 files changed
+1
-405
vllm/compilation/passes/fx_utils.py
-19
@@ -14,10 +14,6 @@ def is_func(node: fx.Node, target: Target) -> bool:
14
return bool(node.op == "call_function" and node.target == target)
15
16
17
-def is_auto_func(node: fx.Node, op: OpOverload) -> bool:
18
- return is_func(node, auto_functionalized) and node.args[0] == op
19
-
20
-
17
# Returns the first auto_functionalized node with the given op (if it exists)
18
def find_auto_fn_maybe(nodes: Iterable[fx.Node], op: OpOverload) -> fx.Node | None:
19
for node in nodes:
@@ -42,13 +38,6 @@ def find_getitem_maybe(node: fx.Node, idx: int) -> fx.Node | None:
38
return None
39
40
45
-# Returns the getitem node that extracts the idx-th element from node
46
-def find_getitem(node: fx.Node, idx: int) -> fx.Node:
47
- ret = find_getitem_maybe(node, idx)
48
- assert ret is not None, f"Could not find getitem {idx} in node {node}"
49
- return ret
50
-
51
-
41
# An auto-functionalization-aware utility for finding nodes with a specific op
42
# Also handles op overload packets and finds all overloads
43
def find_op_nodes(
@@ -67,11 +56,3 @@ def find_op_nodes(
56
for n in graph.find_nodes(op="call_function", target=auto_functionalized):
57
if n.args[0] == op:
58
yield n
70
-
71
-
72
-# Asserts that the node only has one user and returns it
73
-# Even if a node has only 1 user, it might share storage with another node,
74
-# which might need to be taken into account.
75
-def get_only_user(node: fx.Node) -> fx.Node:
76
- assert len(node.users) == 1
77
- return next(iter(node.users))
vllm/compilation/passes/vllm_inductor_pass.py
-9
@@ -333,12 +333,3 @@ class VllmFusionPatternMatcherPass(VllmPatternMatcherPass):
333
def __call__(self, graph: torch.fx.Graph) -> None:
334
self.matched_count = self.pm_pass.apply(graph)
335
VllmPatternMatcherPass.match_table[self.pass_name] += self.matched_count
336
-
337
-
338
-class PrinterInductorPass(VllmInductorPass):
339
- def __init__(self, name: str, config: VllmConfig) -> None:
340
- super().__init__(config)
341
- self.name = name
342
-
343
- def __call__(self, graph: torch.fx.Graph) -> None:
344
- self.dump_graph(graph, self.name)
vllm/distributed/parallel_state.py
-3
@@ -2081,9 +2081,6 @@ def model_parallel_is_initialized():
2081
return _TP is not None and _PP is not None
2082
2083
2084
-_TP_STATE_PATCHED = False
2085
-
2086
-
2084
def get_tensor_model_parallel_world_size() -> int:
2085
"""Return world size for the tensor model parallel group."""
2086
return get_tp_group().world_size
vllm/entrypoints/chat_utils.py
-9
@@ -2029,15 +2029,6 @@ async def parse_chat_messages_async(
2029
return conversation, mm_data, mm_uuids
2030
2031
2032
-def get_history_tool_calls_cnt(conversation: list[ConversationMessage]):
2033
- idx = 0
2034
- for msg in conversation:
2035
- if msg["role"] == "assistant":
2036
- tool_calls = msg.get("tool_calls")
2037
- idx += len(list(tool_calls)) if tool_calls is not None else 0 # noqa
2038
- return idx
2039
-
2040
-
2032
_KIMI_MODEL_TYPES = ("kimi_k2", "kimi_k25", "kimi_k3")
2033
2034
vllm/model_executor/layers/activation.py
-48
@@ -8,14 +8,8 @@ import torch
8
import torch.nn as nn
9
import torch.nn.functional as F
10
11
-from vllm.distributed import (
12
- divide,
13
- get_tensor_model_parallel_rank,
14
- get_tensor_model_parallel_world_size,
15
-)
11
from vllm.logger import init_logger
12
from vllm.model_executor.custom_op import CustomOp
18
-from vllm.model_executor.utils import set_weight_attrs
13
from vllm.platforms import CpuArchEnum, current_platform
14
from vllm.triton_utils import tl, triton
15
from vllm.utils.collection_utils import LazyDict
@@ -788,48 +782,6 @@ class XIELU(CustomOp):
782
return self.forward_native(input)
783
784
791
-class ScaledActivation(nn.Module):
792
- """An activation function with post-scale parameters.
793
-
794
- This is used for some quantization methods like AWQ.
795
- """
796
-
797
- def __init__(
798
- self,
799
- act_module: nn.Module,
800
- intermediate_size: int,
801
- input_is_parallel: bool = True,
802
- params_dtype: torch.dtype | None = None,
803
- ):
804
- super().__init__()
805
- self.act = act_module
806
- self.input_is_parallel = input_is_parallel
807
- if input_is_parallel:
808
- tp_size = get_tensor_model_parallel_world_size()
809
- intermediate_size_per_partition = divide(intermediate_size, tp_size)
810
- else:
811
- intermediate_size_per_partition = intermediate_size
812
- if params_dtype is None:
813
- params_dtype = torch.get_default_dtype()
814
- self.scales = nn.Parameter(
815
- torch.empty(intermediate_size_per_partition, dtype=params_dtype)
816
- )
817
- set_weight_attrs(self.scales, {"weight_loader": self.weight_loader})
818
-
819
- def forward(self, x: torch.Tensor) -> torch.Tensor:
820
- return self.act(x) / self.scales
821
-
822
- def weight_loader(self, param: nn.Parameter, loaded_weight: torch.Tensor):
823
- param_data = param.data
824
- if self.input_is_parallel:
825
- tp_rank = get_tensor_model_parallel_rank()
826
- shard_size = param_data.shape[0]
827
- start_idx = tp_rank * shard_size
828
- loaded_weight = loaded_weight.narrow(0, start_idx, shard_size)
829
- assert param_data.shape == loaded_weight.shape
830
- param_data.copy_(loaded_weight)
831
-
832
-
785
_ACTIVATION_REGISTRY = LazyDict(
786
{
787
"gelu": lambda: GELU(),
vllm/model_executor/layers/conv.py
-52
@@ -155,58 +155,6 @@ class Conv2dLayer(ConvLayerBase):
155
return self._forward_conv(x)
156
157
158
-class CausalConv2dLayer(Conv2dLayer):
159
- """
160
- A causal version of nn.Conv2d where each location in the 2D matrix would
161
- have no access to locations on its right or down
162
- All arguments are the same as nn.Conv2d except padding which should be
163
- set as None
164
- """
165
-
166
- def __init__(
167
- self,
168
- in_channels: int,
169
- out_channels: int,
170
- kernel_size: int,
171
- stride: int,
172
- padding: int = 0,
173
- dilation: int = 1,
174
- groups: int = 1,
175
- bias: bool = True,
176
- padding_mode: str = "zeros",
177
- *,
178
- params_dtype: torch.dtype | None = None,
179
- ) -> None:
180
- if padding is not None:
181
- raise ValueError(
182
- "Argument padding should be set to None for CausalConv2dLayer."
183
- )
184
- self._left_padding: int = kernel_size - 1
185
- self._right_padding: int = stride - 1
186
- padding = 0
187
-
188
- super().__init__(
189
- in_channels,
190
- out_channels,
191
- kernel_size,
192
- stride,
193
- padding,
194
- dilation,
195
- groups,
196
- bias,
197
- padding_mode,
198
- params_dtype=params_dtype,
199
- )
200
-
201
- def forward(
202
- self,
203
- x: torch.Tensor,
204
- ) -> torch.Tensor:
205
- x = F.pad(x, pad=(self._left_padding, self._right_padding, 0, 0))
206
- x = super().forward(x)
207
- return x
208
-
209
-
158
# --8<-- [start:conv3d]
159
@CustomOp.register("conv3d")
160
class Conv3dLayer(ConvLayerBase):
vllm/model_executor/layers/quantization/fp8.py
-21
@@ -4,7 +4,6 @@
4
from typing import TYPE_CHECKING, Any
5
6
import torch
7
-from torch.utils._python_dispatch import TorchDispatchMode
7
8
import vllm.envs as envs
9
import vllm.model_executor.layers.fused_moe.modular_kernel as mk
@@ -234,26 +233,6 @@ class Fp8Config(QuantizationConfig):
233
return cache_scale_mapper | QuantizationConfig.get_cache_scale_mapper()
234
235
237
-class CopyNumelCounter(TorchDispatchMode):
238
- """
239
- Tracks total number of elements modified with `copy_`. Useful for keeping
240
- track of weight loading where underlying weights can be arbitrarily
241
- transformed (such as with `narrow`) before calling copy.
242
- """
243
-
244
- def __init__(self):
245
- super().__init__()
246
- self.copied_numel = 0
247
-
248
- def __torch_dispatch__(self, func, types, args=(), kwargs=None):
249
- if kwargs is None:
250
- kwargs = {}
251
- out = func(*args, **kwargs)
252
- if func == torch.ops.aten.copy_.default:
253
- self.copied_numel += args[0].numel()
254
- return out
255
-
256
-
236
class Fp8LinearMethod(LinearMethodBase):
237
"""Linear method for FP8.
238
Supports loading FP8 checkpoints with static weight scale and
vllm/model_executor/layers/utils.py
-6
@@ -25,12 +25,6 @@ MOE_LAYER_ROUTER_GATE_SUFFIXES = {
25
}
26
27
28
-def is_layer_moe_router_gate(prefix: str) -> bool:
29
- if not prefix:
30
- return False
31
- return prefix.rsplit(".", 1)[-1] in MOE_LAYER_ROUTER_GATE_SUFFIXES
32
-
33
-
28
def get_token_bin_counts_and_mask(
29
tokens: torch.Tensor,
30
vocab_size: int,
vllm/model_executor/models/glm_ocr.py
-4
@@ -242,10 +242,6 @@ class GlmOcrVisionBlock(Glm4vVisionBlock):
242
)
243
244
245
-class GlmOcrVisionPatchEmbed(Glm4vVisionPatchEmbed):
246
- pass
247
-
248
-
245
class GlmOcrPatchMerger(Glm4vPatchMerger):
246
pass
247
vllm/model_executor/models/idefics3.py
-35
@@ -103,41 +103,6 @@ class Idefics3ProcessingInfo(BaseProcessingInfo):
103
def get_supported_mm_limits(self) -> Mapping[str, int | None]:
104
return {"image": None}
105
106
- def _resize_output_size(
107
- self,
108
- *,
109
- height: int,
110
- width: int,
111
- max_len: int | None = None,
112
- min_len: int = 1,
113
- max_size: int | None = None,
114
- ) -> tuple[int, int]:
115
- # Set default value for max_len if not provided
116
- max_len = max(height, width) if max_len is None else max_len
117
- aspect_ratio = width / height
118
-
119
- # Handle the maximum size constraint
120
- if max_size is not None:
121
- max_len = min(max_len, max_size)
122
-
123
- # Adjust dimensions according to the aspect ratio
124
- if width >= height:
125
- width = max_len
126
- height = int(width / aspect_ratio)
127
- else:
128
- height = max_len
129
- width = int(height * aspect_ratio)
130
-
131
- # Ensure both width and height are even (if needed)
132
- height += height % 2
133
- width += width % 2
134
-
135
- # Ensure dimensions are not smaller than the minimum length
136
- height = max(height, min_len)
137
- width = max(width, min_len)
138
-
139
- return height, width
140
-
106
def _get_image_feature_grid_size(
107
self,
108
*,
vllm/model_executor/models/llava_onevision2.py
-7
@@ -1531,13 +1531,6 @@ class LlavaOnevision2MultiModalDataParser(MultiModalDataParser):
1531
class LlavaOnevision2MultiModalProcessor(
1532
BaseMultiModalProcessor[LlavaOnevision2ProcessingInfo]
1533
):
1534
- def _get_data_parser(self) -> MultiModalDataParser:
1535
- # Retained for symmetry; vLLM actually fetches the parser via
1536
- # info.get_data_parser() (see ProcessingInfo override above).
1537
- return LlavaOnevision2MultiModalDataParser(
1538
- self.info.get_hf_config().vision_config.spatial_merge_size
1539
- )
1540
-
1534
def _call_hf_processor(
1535
self,
1536
prompt: str,
vllm/model_executor/models/nemotron_parse.py
-18
@@ -77,24 +77,6 @@ class BartScaledWordEmbedding(VocabParallelEmbedding):
77
return super().forward(input_ids) * self.embed_scale
78
79
80
-class BartParallelLMHead(ParallelLMHead):
81
- """
82
- This module overrides ParallelLMHead's
83
- forward by dividing by embeddings scale,
84
- yielding effectively the inverse of
85
- BartScaledWordEmbedding
86
- """
87
-
88
- def __init__(
89
- self, num_embeddings: int, embedding_dim: int, embed_scale: float = 1.0
90
- ):
91
- super().__init__(num_embeddings, embedding_dim)
92
- self.embed_scale = embed_scale
93
-
94
- def forward(self, input_ids: torch.Tensor) -> torch.Tensor:
95
- return super().forward(input_ids) / self.embed_scale
96
-
97
-
80
class BartDecoderLayer(nn.Module):
81
def __init__(
82
self,
vllm/model_executor/models/phi4mm.py
-26
@@ -521,32 +521,6 @@ class Phi4MMAudioEmbeddingInputs(TensorSchema):
521
Phi4MMAudioInputs: TypeAlias = Phi4MMAudioFeatureInputs | Phi4MMAudioEmbeddingInputs
522
523
524
-def cat_with_pad(tensors, dim, padding_value=0):
525
- """
526
- cat along dim, while pad to max for all other dims
527
- """
528
- ndim = tensors[0].dim()
529
- assert all(t.dim() == ndim for t in tensors[1:]), (
530
- "All tensors must have the same number of dimensions"
531
- )
532
-
533
- out_size = [max(t.shape[i] for t in tensors) for i in range(ndim)]
534
- out_size[dim] = sum(t.shape[dim] for t in tensors)
535
- output = tensors[0].new_full(out_size, padding_value)
536
-
537
- index = 0
538
- for t in tensors:
539
- # Create a slice list where every dimension except dim is full slice
540
- slices = [slice(0, t.shape[d]) for d in range(ndim)]
541
- # Update only the concat dimension slice
542
- slices[dim] = slice(index, index + t.shape[dim])
543
-
544
- output[slices] = t
545
- index += t.shape[dim]
546
-
547
- return output
548
-
549
-
524
def stack_with_pad(
525
tensors: torch.Tensor | list[torch.Tensor],
526
padding_value: int | float = 0,
vllm/model_executor/models/phi4mm_utils.py
-8
@@ -1595,14 +1595,6 @@ class AttModule(nn.Module):
1595
return x, memory, pos_emb, att_mask
1596
1597
1598
-class AttBlock(BlockBase, AttModule):
1599
- """Attention Block module to support both Attention and Block module."""
1600
-
1601
- def memory_dims(self, max_len: bool = False) -> tuple[int, int]:
1602
- """memory dimensions"""
1603
- return (1, self.input_size)
1604
-
1605
-
1598
def masked_softmax(
1599
scores: Tensor,
1600
mask: Tensor | None,
vllm/model_executor/models/skyworkr1v.py
+1
-31
@@ -7,7 +7,7 @@
7
# Copyright (c) 2025 Skywork
8
# Licensed under The MIT License [see LICENSE for details]
9
# --------------------------------------------------------
10
-from collections.abc import Iterable, Mapping
10
+from collections.abc import Iterable
11
from typing import Annotated, Literal, TypeAlias
12
13
import torch
@@ -15,8 +15,6 @@ import torch.nn as nn
15
from transformers import PretrainedConfig
16
17
from vllm.config import VllmConfig
18
-from vllm.config.multimodal import BaseDummyOptions
19
-from vllm.inputs import MultiModalDataDict
18
from vllm.model_executor.layers.linear import ReplicatedLinear
19
from vllm.model_executor.layers.quantization import QuantizationConfig
20
from vllm.model_executor.layers.quantization.auto_awq import AutoAWQConfig
@@ -24,7 +22,6 @@ from vllm.model_executor.models.intern_vit import (
22
InternVisionModel,
23
)
24
from vllm.multimodal import MULTIMODAL_REGISTRY
27
-from vllm.multimodal.processing import BaseDummyInputsBuilder
25
from vllm.sequence import IntermediateTensors
26
from vllm.transformers_utils.processors.internvl import (
27
InternVLImageProcessor,
@@ -117,33 +114,6 @@ class SkyworkR1VProcessingInfo(BaseInternVLProcessingInfo):
114
)
115
116
120
-class SkyworkR1VDummyInputsBuilder(BaseDummyInputsBuilder[SkyworkR1VProcessingInfo]):
121
- def get_dummy_text(self, mm_counts: Mapping[str, int]) -> str:
122
- num_images = mm_counts.get("image", 0)
123
-
124
- return "<image>" * num_images
125
-
126
- def get_dummy_mm_data(
127
- self,
128
- seq_len: int,
129
- mm_counts: Mapping[str, int],
130
- mm_options: Mapping[str, BaseDummyOptions],
131
- ) -> MultiModalDataDict:
132
- target_width, target_height = self.info.get_image_size_with_most_features()
133
- num_images = mm_counts.get("image", 0)
134
-
135
- image_overrides = mm_options.get("image")
136
-
137
- return {
138
- "image": self._get_dummy_images(
139
- width=target_width,
140
- height=target_height,
141
- num_images=num_images,
142
- overrides=image_overrides,
143
- )
144
- }
145
-
146
-
117
@MULTIMODAL_REGISTRY.register_processor(
118
BaseInternVLMultiModalProcessor,
119
info=SkyworkR1VProcessingInfo,
vllm/model_executor/models/utils.py
-12
@@ -27,7 +27,6 @@ from vllm.multimodal import NestedTensors
27
from vllm.sequence import IntermediateTensors
28
from vllm.utils.math_utils import cdiv
29
from vllm.utils.torch_utils import (
30
- async_tensor_h2d,
30
direct_register_custom_op,
31
)
32
@@ -673,17 +672,6 @@ def _merge_multimodal_embeddings(
672
return inputs_embeds
673
674
676
-def isin_list(
677
- elements: torch.Tensor,
678
- test_elements_list: list[int],
679
-) -> torch.Tensor:
680
- test_elements = async_tensor_h2d(
681
- test_elements_list, dtype=torch.int64, device=elements.device
682
- )
683
-
684
- return torch.isin(elements, test_elements)
685
-
686
-
675
class StageMissingLayer(nn.Module):
676
def __init__(self, stage_name: str, module: nn.Module | None = None) -> None:
677
super().__init__()
vllm/model_executor/models/vision.py
-37
@@ -580,40 +580,3 @@ def run_dp_sharded_mrope_vision_model(
580
"Found unassigned embeddings"
581
)
582
return out_embeddings
583
-
584
-
585
-def get_llm_pos_ids_for_vision(
586
- start_idx: int,
587
- vision_idx: int,
588
- spatial_merge_size: int,
589
- t_index: list[int],
590
- grid_hs: torch.Tensor,
591
- grid_ws: torch.Tensor,
592
-) -> torch.Tensor:
593
- llm_pos_ids_list = []
594
- llm_grid_h = grid_hs[vision_idx] // spatial_merge_size
595
- llm_grid_w = grid_ws[vision_idx] // spatial_merge_size
596
- h_index = (
597
- torch.arange(llm_grid_h)
598
- .view(1, -1, 1)
599
- .expand(len(t_index), -1, llm_grid_w)
600
- .flatten()
601
- )
602
- w_index = (
603
- torch.arange(llm_grid_w)
604
- .view(1, 1, -1)
605
- .expand(len(t_index), llm_grid_h, -1)
606
- .flatten()
607
- )
608
- t_index_tensor = (
609
- torch.Tensor(t_index)
610
- .to(llm_grid_h.device)
611
- .view(-1, 1)
612
- .expand(-1, llm_grid_h * llm_grid_w)
613
- .long()
614
- .flatten()
615
- )
616
- _llm_pos_ids = torch.stack([t_index_tensor, h_index, w_index])
617
- llm_pos_ids_list.append(_llm_pos_ids + start_idx)
618
- llm_pos_ids = torch.cat(llm_pos_ids_list, dim=1)
619
- return llm_pos_ids
vllm/models/minimax_m3/common/mm_preprocess.py
-9
@@ -23,7 +23,6 @@ from vllm.multimodal.inputs import (
23
from vllm.multimodal.parse import (
24
ImageSize,
25
MultiModalDataItems,
26
- MultiModalDataParser,
26
)
27
from vllm.multimodal.processing import (
28
BaseDummyInputsBuilder,
@@ -307,14 +306,6 @@ class MiniMaxM3VLDummyInputsBuilder(BaseDummyInputsBuilder[MiniMaxM3VLProcessing
306
class MiniMaxM3VLMultiModalProcessor(
307
BaseMultiModalProcessor[MiniMaxM3VLProcessingInfo]
308
):
310
- def _get_data_parser(self) -> MultiModalDataParser:
311
- # Request video metadata (fps + sampled frame indices) so the HF
312
- # processor can emit per-frame ``]<]X.X seconds[>[`` timestamp markers,
313
- # matching MiniMax's reference video token stream. ``_get_prompt_updates``
314
- # reconstructs the same markers from the metadata to keep the prompt
315
- # replacement aligned with the processor output.
316
- return MultiModalDataParser(video_needs_metadata=True)
317
-
309
def _call_hf_processor(
310
self,
311
prompt: str,
vllm/profiler/utils.py
-9
@@ -12,15 +12,6 @@ from torch._C._profiler import _EventType, _ProfilerEvent, _TensorMetadata
12
#
13
14
15
-def trim_string_front(string: str, width: int) -> str:
16
- if len(string) > width:
17
- offset = len(string) - width + 3
18
- string = string[offset:]
19
- if len(string) > 3:
20
- string = "..." + string[3:]
21
- return string
22
-
23
-
15
def trim_string_back(string: str, width: int) -> str:
16
if len(string) > width:
17
offset = len(string) - width + 3
vllm/utils/cache.py
-4
@@ -182,10 +182,6 @@ class LRUCache(cachetools.LRUCache[_K, _V]):
182
183
self.popitem(remove_pinned=remove_pinned)
184
185
- def _remove_old_if_needed(self) -> None:
186
- while self.currsize > self.capacity:
187
- self.remove_oldest()
188
-
185
def popitem(self, remove_pinned: bool = False):
186
"""Remove and return the `(key, value)` pair least recently used."""
187
if not remove_pinned:
vllm/utils/multi_stream_utils.py
-4
@@ -8,10 +8,6 @@ from typing import Any
8
import torch
9
10
11
-class AuxStreamType(Enum):
12
- Attention = 1
13
-
14
-
11
class EventType(Enum):
12
Main = 0
13
Attention = 1
vllm/v1/core/kv_cache_utils.py
-34
@@ -427,26 +427,6 @@ class FreeKVCacheBlockQueue:
427
curr_block = curr_block.next_free_block
428
429
430
-def need_extra_keys(request: Request) -> bool:
431
- """Check whether the blocks allocated to this request need extra hash keys.
432
-
433
- Args:
434
- request (Request): The request.
435
-
436
- Returns:
437
- bool: Whether blocks allocated to this request need extra hash keys.
438
- """
439
-
440
- # Multimodal requests need to include the MM hash.
441
- # LoRA requests need to include the LoRA name.
442
- # Request with provided cache salt need to include the salt.
443
- return (
444
- bool(request.mm_features)
445
- or (request.lora_request is not None)
446
- or (request.cache_salt is not None)
447
- )
448
-
449
-
430
def _gen_mm_extra_hash_keys(
431
request: Request, start_token_idx: int, end_token_idx: int, start_mm_idx: int
432
) -> tuple[list[Any], int]:
@@ -1053,20 +1033,6 @@ def _get_kv_cache_groups_uniform_type(
1033
return [KVCacheGroupSpec(list(spec.kv_cache_specs.keys()), spec)]
1034
1035
1056
-def is_kv_cache_page_size_uniform(kv_cache_spec: dict[str, KVCacheSpec]) -> bool:
1057
- """
1058
- Whether all layers in the given KVCacheSpec have the same page size.
1059
- Args:
1060
- kv_cache_spec: The KVCacheSpec of each attention layer in the model
1061
-
1062
- Returns:
1063
- True if all layers have the same page size, False otherwise.
1064
- """
1065
-
1066
- page_sizes = {layer.page_size_bytes for layer in kv_cache_spec.values()}
1067
- return len(page_sizes) == 1
1068
-
1069
-
1036
def unify_kv_cache_spec_page_size(
1037
kv_cache_spec: dict[str, KVCacheSpec],
1038
) -> dict[str, KVCacheSpec]: