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 4, 00:00 UTC
[KV Connector] Remove compat support for pre-v0.12.0 constructor signatures without `KVCacheConfig` (#39832)
The v0.12.0 release contained initial support for HMA in KV Connectors. As part of these changes, a KVCacheConfig argument was added to KV connector constructors. Backwards compatibility support for out-of-tree connectors was included in this change, with a very prominent warning. See #25712 and #27887. Since the warning has been around for over 5 months, we can safely remove the support of it. Signed-off-by: yewentao256 <zhyanwentao@126.com>
Wentao Ye committed
May 9, 2026 at 19:39 UTC
ea0e501bb18c12b80acc05ff8c7f013db515ba80
22 files changed
+119
-341
examples/disaggregated/kv_load_failure_recovery_offline/load_recovery_example_connector.py
+12
-2
@@ -20,6 +20,7 @@ from vllm.v1.request import Request
20
21
if TYPE_CHECKING:
22
from vllm.v1.core.sched.output import SchedulerOutput
23
+ from vllm.v1.kv_cache_interface import KVCacheConfig
24
25
logger = logging.getLogger()
26
logging.basicConfig(level=logging.INFO)
@@ -35,8 +36,17 @@ class LoadRecoveryExampleConnectorMetadata(ExampleConnectorMetadata):
36
37
38
class LoadRecoveryExampleConnector(ExampleConnector):
38
- def __init__(self, vllm_config: "VllmConfig", role: KVConnectorRole):
39
- super().__init__(vllm_config=vllm_config, role=role)
39
+ def __init__(
40
+ self,
41
+ vllm_config: "VllmConfig",
42
+ role: KVConnectorRole,
43
+ kv_cache_config: "KVCacheConfig",
44
+ ):
45
+ super().__init__(
46
+ vllm_config=vllm_config,
47
+ role=role,
48
+ kv_cache_config=kv_cache_config,
49
+ )
50
self._async_load = vllm_config.kv_transfer_config.get_from_extra_config(
51
"async_load", False
52
)
tests/v1/engine/test_abort_final_step.py
+1
-1
@@ -66,7 +66,7 @@ class DummyKVConnector(KVConnectorBase_V1):
66
self,
67
vllm_config: VllmConfig,
68
role: KVConnectorRole,
69
- kv_cache_config: KVCacheConfig | None = None,
69
+ kv_cache_config: KVCacheConfig,
70
):
71
super().__init__(vllm_config, role, kv_cache_config)
72
# Get the status file path from extra config
tests/v1/kv_connector/unit/test_backwards_compatibility.py
deleted
-275
@@ -1,275 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""
4
-Unit tests for backwards compatibility with external KV connector implementations.
5
-
6
-This test ensures that external connectors (loaded via kv_connector_module_path)
7
-implemented with the old signature continue to work:
8
-- Old signature: __init__(self, vllm_config, role)
9
-- New signature: __init__(self, vllm_config, role, kv_cache_config)
10
-"""
11
-
12
-from typing import TYPE_CHECKING
13
-from unittest.mock import patch
14
-
15
-import pytest
16
-
17
-from vllm.distributed.kv_transfer.kv_connector.factory import KVConnectorFactory
18
-from vllm.distributed.kv_transfer.kv_connector.v1 import (
19
- KVConnectorBase_V1,
20
- KVConnectorRole,
21
-)
22
-from vllm.v1.attention.backend import AttentionMetadata
23
-from vllm.v1.core.sched.output import SchedulerOutput
24
-
25
-from .utils import create_scheduler, create_vllm_config
26
-
27
-if TYPE_CHECKING:
28
- from vllm.config import VllmConfig
29
- from vllm.forward_context import ForwardContext
30
- from vllm.v1.core.kv_cache_manager import KVCacheBlocks
31
- from vllm.v1.kv_cache_interface import KVCacheConfig
32
- from vllm.v1.request import Request
33
-
34
-
35
-class OldStyleTestConnector(KVConnectorBase_V1):
36
- """
37
- Test connector using the old signature with 2 required arguments.
38
- This simulates external connectors that haven't been updated yet.
39
- """
40
-
41
- def __init__(self, vllm_config: "VllmConfig", role: KVConnectorRole):
42
- # Old-style call to super().__init__ with only 2 arguments
43
- super().__init__(vllm_config=vllm_config, role=role)
44
-
45
- def get_num_new_matched_tokens(
46
- self, request: "Request", num_computed_tokens: int
47
- ) -> tuple[int | None, bool]:
48
- return 0, False
49
-
50
- def update_state_after_alloc(
51
- self,
52
- request: "Request",
53
- blocks: "KVCacheBlocks",
54
- num_external_tokens: int,
55
- ):
56
- pass
57
-
58
- def build_connector_meta(self, scheduler_output: SchedulerOutput):
59
- return None
60
-
61
- def start_load_kv(self, forward_context: "ForwardContext", **kwargs) -> None:
62
- pass
63
-
64
- def wait_for_layer_load(self, layer_name: str) -> None:
65
- pass
66
-
67
- def save_kv_layer(
68
- self,
69
- layer_name: str,
70
- kv_layer,
71
- attn_metadata: AttentionMetadata,
72
- **kwargs,
73
- ) -> None:
74
- pass
75
-
76
- def wait_for_save(self):
77
- pass
78
-
79
-
80
-class NewStyleTestConnector(KVConnectorBase_V1):
81
- """
82
- Test connector using the new signature with 3 required arguments.
83
- """
84
-
85
- def __init__(
86
- self,
87
- vllm_config: "VllmConfig",
88
- role: KVConnectorRole,
89
- kv_cache_config: "KVCacheConfig",
90
- ):
91
- # New-style call to super().__init__ with all 3 arguments
92
- super().__init__(
93
- vllm_config=vllm_config, role=role, kv_cache_config=kv_cache_config
94
- )
95
-
96
- def get_num_new_matched_tokens(
97
- self, request: "Request", num_computed_tokens: int
98
- ) -> tuple[int | None, bool]:
99
- return 0, False
100
-
101
- def update_state_after_alloc(
102
- self,
103
- request: "Request",
104
- blocks: "KVCacheBlocks",
105
- num_external_tokens: int,
106
- ):
107
- pass
108
-
109
- def build_connector_meta(self, scheduler_output: SchedulerOutput):
110
- return None
111
-
112
- def start_load_kv(self, forward_context: "ForwardContext", **kwargs) -> None:
113
- pass
114
-
115
- def wait_for_layer_load(self, layer_name: str) -> None:
116
- pass
117
-
118
- def save_kv_layer(
119
- self,
120
- layer_name: str,
121
- kv_layer,
122
- attn_metadata: AttentionMetadata,
123
- **kwargs,
124
- ) -> None:
125
- pass
126
-
127
- def wait_for_save(self):
128
- pass
129
-
130
-
131
-@pytest.mark.parametrize("role", [KVConnectorRole.SCHEDULER, KVConnectorRole.WORKER])
132
-def test_external_old_signature_factory_instantiation(role):
133
- """
134
- Test that external connectors with old signature (2 required args) loaded
135
- via kv_connector_module_path are correctly instantiated with backwards
136
- compatibility support.
137
- """
138
- vllm_config = create_vllm_config()
139
- vllm_config.kv_transfer_config.kv_connector = "OldStyleTestConnector"
140
- vllm_config.kv_transfer_config.kv_connector_module_path = (
141
- "tests.v1.kv_connector.unit.test_backwards_compatibility"
142
- )
143
-
144
- scheduler = create_scheduler(vllm_config)
145
- kv_cache_config = scheduler.kv_cache_config
146
-
147
- connector = KVConnectorFactory.create_connector(vllm_config, role, kv_cache_config)
148
-
149
- assert connector is not None
150
- assert isinstance(connector, OldStyleTestConnector)
151
- assert connector.role == role
152
- assert connector._kv_cache_config is None
153
-
154
-
155
-@pytest.mark.parametrize("role", [KVConnectorRole.SCHEDULER, KVConnectorRole.WORKER])
156
-def test_external_new_signature_factory_instantiation(role):
157
- """
158
- Test that external connectors with new signature (3 required args) loaded
159
- via kv_connector_module_path are correctly instantiated.
160
- """
161
- vllm_config = create_vllm_config()
162
- vllm_config.kv_transfer_config.kv_connector = "NewStyleTestConnector"
163
- vllm_config.kv_transfer_config.kv_connector_module_path = (
164
- "tests.v1.kv_connector.unit.test_backwards_compatibility"
165
- )
166
-
167
- scheduler = create_scheduler(vllm_config)
168
- kv_cache_config = scheduler.kv_cache_config
169
-
170
- connector = KVConnectorFactory.create_connector(vllm_config, role, kv_cache_config)
171
-
172
- assert connector is not None
173
- assert isinstance(connector, NewStyleTestConnector)
174
- assert connector.role == role
175
- assert connector._kv_cache_config is not None
176
- assert connector._kv_cache_config == kv_cache_config
177
-
178
-
179
-@pytest.mark.parametrize("role", [KVConnectorRole.SCHEDULER, KVConnectorRole.WORKER])
180
-def test_old_signature_super_init(role):
181
- """
182
- Test that old-style connectors can call super().__init__() without
183
- kv_cache_config parameter.
184
- """
185
- vllm_config = create_vllm_config()
186
-
187
- connector = OldStyleTestConnector(vllm_config, role)
188
-
189
- assert connector is not None
190
- assert connector.role == role
191
- assert connector._kv_cache_config is None
192
-
193
-
194
-def test_old_signature_super_init_with_kwargs():
195
- """
196
- Test that old-style connectors can call super().__init__() with keyword
197
- arguments in different orders.
198
- """
199
- vllm_config = create_vllm_config()
200
-
201
- # Test with vllm_config= and role= kwargs
202
- connector1 = OldStyleTestConnector(
203
- vllm_config=vllm_config, role=KVConnectorRole.SCHEDULER
204
- )
205
- assert connector1 is not None
206
- assert connector1._kv_cache_config is None
207
-
208
- # Test with role= and vllm_config= in reversed order
209
- connector2 = OldStyleTestConnector(
210
- role=KVConnectorRole.WORKER, vllm_config=vllm_config
211
- )
212
- assert connector2 is not None
213
- assert connector2._kv_cache_config is None
214
-
215
-
216
-def test_internal_connector_uses_new_signature():
217
- """
218
- Test that internal connectors (registered in factory) always use the new
219
- signature and get kv_cache_config.
220
- """
221
- from vllm.distributed.kv_transfer.kv_connector.v1.example_connector import (
222
- ExampleConnector,
223
- )
224
-
225
- vllm_config = create_vllm_config()
226
- vllm_config.kv_transfer_config.kv_connector = "ExampleConnector"
227
-
228
- scheduler = create_scheduler(vllm_config)
229
- kv_cache_config = scheduler.kv_cache_config
230
-
231
- connector = KVConnectorFactory.create_connector(
232
- vllm_config, KVConnectorRole.SCHEDULER, kv_cache_config
233
- )
234
-
235
- assert connector is not None
236
- assert isinstance(connector, ExampleConnector)
237
- assert connector._kv_cache_config is not None
238
- assert connector._kv_cache_config == kv_cache_config
239
-
240
-
241
-def test_signature_detection_with_mocking():
242
- """
243
- Test that the factory correctly applies compat_sig flag returned from
244
- _get_connector_class_with_compat.
245
- """
246
- vllm_config = create_vllm_config()
247
- scheduler = create_scheduler(vllm_config)
248
- kv_cache_config = scheduler.kv_cache_config
249
-
250
- # Mock _get_connector_class_with_compat to return old-style connector
251
- with patch.object(
252
- KVConnectorFactory,
253
- "_get_connector_class_with_compat",
254
- return_value=(OldStyleTestConnector, True),
255
- ):
256
- old_connector = KVConnectorFactory.create_connector(
257
- vllm_config, KVConnectorRole.SCHEDULER, kv_cache_config
258
- )
259
- assert old_connector is not None
260
- assert isinstance(old_connector, OldStyleTestConnector)
261
- assert old_connector._kv_cache_config is None
262
-
263
- # Mock _get_connector_class_with_compat to return new-style connector
264
- with patch.object(
265
- KVConnectorFactory,
266
- "_get_connector_class_with_compat",
267
- return_value=(NewStyleTestConnector, False),
268
- ):
269
- new_connector = KVConnectorFactory.create_connector(
270
- vllm_config, KVConnectorRole.SCHEDULER, kv_cache_config
271
- )
272
- assert new_connector is not None
273
- assert isinstance(new_connector, NewStyleTestConnector)
274
- assert new_connector._kv_cache_config is not None
275
- assert new_connector._kv_cache_config == kv_cache_config
tests/v1/kv_connector/unit/test_decode_bench_connector.py
+3
-1
@@ -58,7 +58,9 @@ class DecodeBenchTestRunner:
58
59
# Create worker-side connector
60
self.worker_connector = DecodeBenchConnector(
61
- vllm_config, KVConnectorRole.WORKER
61
+ vllm_config,
62
+ KVConnectorRole.WORKER,
63
+ self.scheduler.kv_cache_config,
64
)
65
66
# Create dummy KV caches for testing
tests/v1/kv_connector/unit/test_kv_connector_lifecycle.py
+5
-1
@@ -10,6 +10,7 @@ from vllm.distributed.kv_transfer.kv_transfer_state import (
10
get_kv_transfer_group,
11
)
12
from vllm.v1.core.sched.output import CachedRequestData, SchedulerOutput
13
+from vllm.v1.kv_cache_interface import KVCacheConfig
14
from vllm.v1.worker.kv_connector_model_runner_mixin import KVConnectorModelRunnerMixin
15
16
# Importing utils registers TestExampleConnector with the factory
@@ -38,7 +39,10 @@ def test_kv_connector_mixin_clears_metadata():
39
vllm_config.kv_transfer_config.kv_connector_extra_config["name"] = "unit"
40
41
# Initialize the global connector instance
41
- ensure_kv_transfer_initialized(vllm_config)
42
+ kv_cache_config = KVCacheConfig(
43
+ num_blocks=0, kv_cache_tensors=[], kv_cache_groups=[]
44
+ )
45
+ ensure_kv_transfer_initialized(vllm_config, kv_cache_config)
46
47
try:
48
# Minimal scheduler output with empty metadata; mixin should still
tests/v1/kv_connector/unit/test_mooncake_connector.py
+35
-6
@@ -26,11 +26,16 @@ from vllm.distributed.kv_transfer.kv_connector.v1.mooncake.mooncake_utils import
26
)
27
from vllm.utils.network_utils import get_open_port
28
from vllm.v1.attention.backends.flash_attn import FlashAttentionBackend
29
+from vllm.v1.kv_cache_interface import KVCacheConfig
30
from vllm.v1.request import RequestStatus
31
32
from .utils import create_request, create_scheduler, create_vllm_config
33
34
35
+def _make_test_kv_cache_config() -> KVCacheConfig:
36
+ return KVCacheConfig(num_blocks=0, kv_cache_tensors=[], kv_cache_groups=[])
37
+
38
+
39
class FakeMooncakeWrapper:
40
"""Mock Mooncake TransferEngine for unit testing environments."""
41
@@ -321,7 +326,11 @@ async def test_kv_producer(monkeypatch):
326
)
327
328
with set_current_vllm_config(vllm_config), patch_worker_dependencies():
324
- prefill_connector = MooncakeConnector(vllm_config, KVConnectorRole.WORKER)
329
+ prefill_connector = MooncakeConnector(
330
+ vllm_config,
331
+ KVConnectorRole.WORKER,
332
+ _make_test_kv_cache_config(),
333
+ )
334
prefill_worker = prefill_connector.connector_worker
335
prefill_worker.kv_caches_base_addr = [0x1000]
336
block_len = 4096
@@ -473,7 +482,11 @@ async def test_kv_consumuer(monkeypatch):
482
)
483
484
with set_current_vllm_config(vllm_config), patch_worker_dependencies() as mocks:
476
- decode_connector = MooncakeConnector(vllm_config, KVConnectorRole.WORKER)
485
+ decode_connector = MooncakeConnector(
486
+ vllm_config,
487
+ KVConnectorRole.WORKER,
488
+ _make_test_kv_cache_config(),
489
+ )
490
decode_worker = decode_connector.connector_worker
491
decode_worker.kv_caches_base_addr = [0x1000]
492
decode_worker.rpc_port = 54321
@@ -533,7 +546,11 @@ async def test_worker_get_finished_timeout(monkeypatch):
546
kv_connector="MooncakeConnector", kv_role="kv_producer"
547
)
548
with set_current_vllm_config(vllm_config), patch_worker_dependencies():
536
- prefill_connector = MooncakeConnector(vllm_config, KVConnectorRole.WORKER)
549
+ prefill_connector = MooncakeConnector(
550
+ vllm_config,
551
+ KVConnectorRole.WORKER,
552
+ _make_test_kv_cache_config(),
553
+ )
554
prefill_worker = prefill_connector.connector_worker
555
556
# Add an expired request (expire_time is in the past).
@@ -579,7 +596,11 @@ def test_register_kv_caches():
596
"vllm.distributed.kv_transfer.kv_connector.v1.mooncake.mooncake_connector.threading.Thread"
597
) as mock_thread,
598
):
582
- connector = MooncakeConnector(vllm_config, KVConnectorRole.WORKER)
599
+ connector = MooncakeConnector(
600
+ vllm_config,
601
+ KVConnectorRole.WORKER,
602
+ _make_test_kv_cache_config(),
603
+ )
604
worker = connector.connector_worker
605
mock_thread.return_value.is_alive.return_value = False
606
@@ -628,7 +649,11 @@ def test_register_kv_caches_supports_mixed_mla_and_eagle_shapes():
649
"vllm.distributed.kv_transfer.kv_connector.v1.mooncake.mooncake_connector.threading.Thread"
650
) as mock_thread,
651
):
631
- connector = MooncakeConnector(vllm_config, KVConnectorRole.WORKER)
652
+ connector = MooncakeConnector(
653
+ vllm_config,
654
+ KVConnectorRole.WORKER,
655
+ _make_test_kv_cache_config(),
656
+ )
657
worker = connector.connector_worker
658
mock_thread.return_value.is_alive.return_value = False
659
@@ -688,7 +713,11 @@ async def test_kv_producer_heterogeneous_tp(monkeypatch, d_tp_size):
713
)
714
715
with set_current_vllm_config(vllm_config), patch_worker_dependencies():
691
- prefill_connector = MooncakeConnector(vllm_config, KVConnectorRole.WORKER)
716
+ prefill_connector = MooncakeConnector(
717
+ vllm_config,
718
+ KVConnectorRole.WORKER,
719
+ _make_test_kv_cache_config(),
720
+ )
721
prefill_worker = prefill_connector.connector_worker
722
723
# Override TP rank/size to simulate P TP=2
tests/v1/kv_connector/unit/test_mooncake_connector_hma.py
+12
-2
@@ -221,9 +221,14 @@ async def test_build_transfer_params_multi_group_trimming(monkeypatch):
221
vllm_config = create_vllm_config(
222
kv_connector="MooncakeConnector", kv_role="kv_producer"
223
)
224
+ kv_cache_config = make_kv_cache_config(
225
+ block_size=vllm_config.cache_config.block_size, swa_enabled=True
226
+ )
227
228
with set_current_vllm_config(vllm_config), patch_worker_dependencies():
226
- connector = MooncakeConnector(vllm_config, KVConnectorRole.WORKER)
229
+ connector = MooncakeConnector(
230
+ vllm_config, KVConnectorRole.WORKER, kv_cache_config
231
+ )
232
worker = connector.connector_worker
233
234
block_len = 4096
@@ -304,9 +309,14 @@ async def test_build_transfer_params_group_count_mismatch(monkeypatch):
309
vllm_config = create_vllm_config(
310
kv_connector="MooncakeConnector", kv_role="kv_producer"
311
)
312
+ kv_cache_config = make_kv_cache_config(
313
+ block_size=vllm_config.cache_config.block_size, swa_enabled=True
314
+ )
315
316
with set_current_vllm_config(vllm_config), patch_worker_dependencies():
309
- connector = MooncakeConnector(vllm_config, KVConnectorRole.WORKER)
317
+ connector = MooncakeConnector(
318
+ vllm_config, KVConnectorRole.WORKER, kv_cache_config
319
+ )
320
worker = connector.connector_worker
321
322
block_len = 4096
tests/v1/kv_connector/unit/test_moriio_connector.py
+16
-2
@@ -37,9 +37,15 @@ from vllm.utils.network_utils import (
37
get_ip,
38
make_zmq_path,
39
)
40
+from vllm.v1.kv_cache_interface import KVCacheConfig
41
42
from .utils import create_request, create_scheduler
43
44
+
45
+def _make_test_kv_cache_config() -> KVCacheConfig:
46
+ return KVCacheConfig(num_blocks=0, kv_cache_tensors=[], kv_cache_groups=[])
47
+
48
+
49
aiter_available = importlib.util.find_spec("aiter") is not None
50
mori_available = importlib.util.find_spec("mori") is not None
51
@@ -462,7 +468,11 @@ def test_register_kv_caches(mock_parallel_groups):
468
)
469
470
with set_current_vllm_config(vllm_config):
465
- connector = MoRIIOConnector(vllm_config, KVConnectorRole.WORKER)
471
+ connector = MoRIIOConnector(
472
+ vllm_config,
473
+ KVConnectorRole.WORKER,
474
+ _make_test_kv_cache_config(),
475
+ )
476
connector.connector_worker = FakeMoRIIOConnectorWorker(
477
vllm_config, connector.engine_id, hand_shake_latency=0
478
)
@@ -554,7 +564,11 @@ def test_moriio_handshake_returns_metadata(mock_parallel_groups):
564
}
565
)
566
with set_current_vllm_config(vllm_config):
557
- connector = MoRIIOConnector(vllm_config, KVConnectorRole.WORKER)
567
+ connector = MoRIIOConnector(
568
+ vllm_config,
569
+ KVConnectorRole.WORKER,
570
+ _make_test_kv_cache_config(),
571
+ )
572
573
# Execute register_kv_caches
574
connector.register_kv_caches(kv_caches)
tests/v1/kv_connector/unit/test_scheduler_kv_connector_override.py
+2
-1
@@ -17,6 +17,7 @@ from vllm.v1.core.kv_cache_manager import KVCacheBlocks
17
from vllm.v1.core.kv_cache_utils import BlockHash
18
from vllm.v1.core.sched.output import SchedulerOutput
19
from vllm.v1.core.sched.scheduler import Scheduler
20
+from vllm.v1.kv_cache_interface import KVCacheConfig
21
from vllm.v1.request import Request
22
23
@@ -26,7 +27,7 @@ class DummyConnectorMetadata(KVConnectorMetadata):
27
28
29
class DummyKVConnector(KVConnectorBase_V1):
29
- def __init__(self, vllm_config, role, kv_cache_config=None):
30
+ def __init__(self, vllm_config, role, kv_cache_config: KVCacheConfig):
31
super().__init__(vllm_config, role, kv_cache_config)
32
33
def get_num_new_matched_tokens(
tests/v1/kv_connector/unit/utils.py
+8
-3
@@ -293,9 +293,14 @@ def create_model_runner_output(
293
294
295
class TestExampleConnector(ExampleConnector):
296
- def __init__(self, config: VllmConfig, role, kv_cache_config):
296
+ def __init__(
297
+ self,
298
+ config: VllmConfig,
299
+ role: KVConnectorRole,
300
+ kv_cache_config: KVCacheConfig,
301
+ ):
302
self.name = config.kv_transfer_config.kv_connector_extra_config["name"]
298
- self._connector = ExampleConnector(config, role)
303
+ self._connector = ExampleConnector(config, role, kv_cache_config)
304
self.call_record: dict[str, int] = defaultdict(int)
305
# Use a unique temp file per connector
306
self._event_file = (
@@ -368,7 +373,7 @@ class MockKVConnector(KVConnectorBase_V1):
373
self,
374
vllm_config: VllmConfig,
375
role: KVConnectorRole,
371
- kv_cache_config: KVCacheConfig | None = None,
376
+ kv_cache_config: KVCacheConfig,
377
):
378
super().__init__(vllm_config, role, kv_cache_config)
379
extra_config = self._kv_transfer_config.kv_connector_extra_config
vllm/distributed/kv_transfer/kv_connector/factory.py
+12
-26
@@ -44,14 +44,12 @@ class KVConnectorFactory:
44
cls,
45
config: "VllmConfig",
46
role: KVConnectorRole,
47
- kv_cache_config: "KVCacheConfig | None" = None,
47
+ kv_cache_config: "KVCacheConfig",
48
) -> KVConnectorBase:
49
kv_transfer_config = config.kv_transfer_config
50
if kv_transfer_config is None:
51
raise ValueError("kv_transfer_config must be set to create a connector")
52
- connector_cls, compat_sig = cls._get_connector_class_with_compat(
53
- kv_transfer_config
54
- )
52
+ connector_cls = cls.get_connector_class(kv_transfer_config)
53
54
# check if the connector supports HMA
55
hma_enabled = not config.scheduler_config.disable_hybrid_kv_cache_manager
@@ -74,12 +72,7 @@ class KVConnectorFactory:
72
# - Co-locate with worker process
73
# - Should only be used inside the forward context & attention layer
74
# We build separately to enforce strict separation
77
- if compat_sig:
78
- # Old signature: __init__(self, vllm_config, role)
79
- return connector_cls(config, role)
80
- else:
81
- # New signature: __init__(self, vllm_config, role, kv_cache_config)
82
- return connector_cls(config, role, kv_cache_config)
75
+ return connector_cls(config, role, kv_cache_config)
76
77
@classmethod
78
def get_connector_class_by_name(
@@ -100,13 +93,12 @@ class KVConnectorFactory:
93
return cls._registry[connector_name]()
94
95
@classmethod
103
- def _get_connector_class_with_compat(
96
+ def get_connector_class(
97
cls, kv_transfer_config: "KVTransferConfig"
105
- ) -> tuple[type[KVConnectorBaseType], bool]:
98
+ ) -> type[KVConnectorBaseType]:
99
connector_name = kv_transfer_config.kv_connector
100
if connector_name is None:
101
raise ValueError("Connector name is not set in KVTransferConfig")
109
- compat_sig = False
102
connector_module_path = kv_transfer_config.kv_connector_module_path
103
if connector_module_path is not None and not connector_module_path:
104
raise ValueError("kv_connector_module_path cannot be an empty string.")
@@ -121,24 +113,18 @@ class KVConnectorFactory:
113
) from e
114
connector_cls = cast(type[KVConnectorBaseType], connector_cls)
115
if not supports_kw(connector_cls, "kv_cache_config"):
124
- compat_sig = True
125
- logger.warning(
126
- "Connector %s uses deprecated signature with 2 required arguments. "
127
- "Please update to include kv_cache_config as the second argument.",
128
- connector_cls.__name__,
116
+ msg = (
117
+ f"Connector {connector_cls.__name__} uses deprecated "
118
+ "2-argument constructor signature. External v1 KV "
119
+ "connectors must accept kv_cache_config as the third "
120
+ "constructor argument and pass it to super().__init__()."
121
)
122
+ logger.error(msg)
123
+ raise ValueError(msg)
124
elif connector_name in cls._registry:
125
connector_cls = cls._registry[connector_name]()
126
else:
127
raise ValueError(f"Unsupported connector type: {connector_name}")
134
- return connector_cls, compat_sig
135
-
136
- @classmethod
137
- def get_connector_class(
138
- cls, kv_transfer_config: "KVTransferConfig"
139
- ) -> type[KVConnectorBaseType]:
140
- """Get the connector class by name."""
141
- connector_cls, _ = cls._get_connector_class_with_compat(kv_transfer_config)
128
return connector_cls
129
130
vllm/distributed/kv_transfer/kv_connector/v1/base.py
+1
-8
@@ -184,7 +184,7 @@ class KVConnectorBase_V1(ABC):
184
self,
185
vllm_config: "VllmConfig",
186
role: KVConnectorRole,
187
- kv_cache_config: "KVCacheConfig | None" = None,
187
+ kv_cache_config: "KVCacheConfig",
188
):
189
logger.warning(
190
"Initializing KVConnectorBase_V1. This API is experimental and "
@@ -197,13 +197,6 @@ class KVConnectorBase_V1(ABC):
197
else:
198
raise ValueError("kv_transfer_config must be set for KVConnectorBase_V1")
199
self._kv_cache_config = kv_cache_config
200
- if self._kv_cache_config is None:
201
- logger.warning(
202
- "KVConnectorBase_V1 initialized without kv_cache_config. "
203
- "This is deprecated - please update your connector to accept "
204
- "kv_cache_config as the third constructor argument and pass it "
205
- "to super().__init__()."
206
- )
200
self._role = role
201
202
@property
vllm/distributed/kv_transfer/kv_connector/v1/decode_bench_connector.py
+1
-1
@@ -87,7 +87,7 @@ class DecodeBenchConnector(KVConnectorBase_V1, SupportsHMA):
87
self,
88
vllm_config: "VllmConfig",
89
role: KVConnectorRole,
90
- kv_cache_config: "KVCacheConfig | None" = None,
90
+ kv_cache_config: "KVCacheConfig",
91
):
92
super().__init__(vllm_config, role, kv_cache_config)
93
vllm/distributed/kv_transfer/kv_connector/v1/example_connector.py
+1
-1
@@ -92,7 +92,7 @@ class ExampleConnector(KVConnectorBase_V1):
92
self,
93
vllm_config: "VllmConfig",
94
role: KVConnectorRole,
95
- kv_cache_config: "KVCacheConfig | None" = None,
95
+ kv_cache_config: "KVCacheConfig",
96
):
97
super().__init__(
98
vllm_config=vllm_config,
vllm/distributed/kv_transfer/kv_connector/v1/example_hidden_states_connector.py
+2
-2
@@ -2,7 +2,7 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
import os
4
from dataclasses import dataclass, field
5
-from typing import TYPE_CHECKING, Any, Optional
5
+from typing import TYPE_CHECKING, Any
6
7
import safetensors
8
import torch
@@ -120,7 +120,7 @@ class ExampleHiddenStatesConnector(KVConnectorBase_V1):
120
self,
121
vllm_config: "VllmConfig",
122
role: KVConnectorRole,
123
- kv_cache_config: Optional["KVCacheConfig"] = None,
123
+ kv_cache_config: "KVCacheConfig",
124
):
125
super().__init__(
126
vllm_config=vllm_config,
vllm/distributed/kv_transfer/kv_connector/v1/lmcache_mp_connector.py
+1
-1
@@ -476,7 +476,7 @@ class LMCacheMPConnector(KVConnectorBase_V1):
476
self,
477
vllm_config: "VllmConfig",
478
role: KVConnectorRole,
479
- kv_cache_config: "KVCacheConfig | None" = None,
479
+ kv_cache_config: "KVCacheConfig",
480
):
481
super().__init__(vllm_config, role, kv_cache_config)
482
vllm/distributed/kv_transfer/kv_connector/v1/mooncake/mooncake_connector.py
+1
-1
@@ -342,7 +342,7 @@ class MooncakeConnector(KVConnectorBase_V1, SupportsHMA):
342
self,
343
vllm_config: VllmConfig,
344
role: KVConnectorRole,
345
- kv_cache_config: "KVCacheConfig | None" = None,
345
+ kv_cache_config: "KVCacheConfig",
346
):
347
super().__init__(vllm_config, role, kv_cache_config)
348
vllm/distributed/kv_transfer/kv_connector/v1/moriio/moriio_connector.py
+2
-2
@@ -93,9 +93,9 @@ class MoRIIOConnector(KVConnectorBase_V1):
93
self,
94
vllm_config: VllmConfig,
95
role: KVConnectorRole,
96
- kv_cache_config: "KVCacheConfig | None" = None,
96
+ kv_cache_config: "KVCacheConfig",
97
):
98
- super().__init__(vllm_config, role)
98
+ super().__init__(vllm_config, role, kv_cache_config)
99
assert vllm_config.kv_transfer_config is not None, (
100
"kv_transfer_config must be set for MoRIIOConnector"
101
)
vllm/distributed/kv_transfer/kv_connector/v1/offloading_connector.py
+1
-2
@@ -52,11 +52,10 @@ class OffloadingConnector(KVConnectorBase_V1, SupportsHMA):
52
self,
53
vllm_config: VllmConfig,
54
role: KVConnectorRole,
55
- kv_cache_config: KVCacheConfig | None = None,
55
+ kv_cache_config: KVCacheConfig,
56
):
57
super().__init__(vllm_config, role, kv_cache_config)
58
59
- assert kv_cache_config is not None
59
spec = OffloadingSpecFactory.create_spec(vllm_config, kv_cache_config)
60
61
self.connector_scheduler: OffloadingConnectorScheduler | None = None
vllm/distributed/kv_transfer/kv_connector/v1/p2p/p2p_nccl_connector.py
+1
-1
@@ -76,7 +76,7 @@ class P2pNcclConnector(KVConnectorBase_V1):
76
self,
77
vllm_config: "VllmConfig",
78
role: KVConnectorRole,
79
- kv_cache_config: "KVCacheConfig | None" = None,
79
+ kv_cache_config: "KVCacheConfig",
80
):
81
super().__init__(
82
vllm_config=vllm_config,
vllm/distributed/kv_transfer/kv_connector/v1/simple_cpu_offload_connector.py
+1
-1
@@ -49,7 +49,7 @@ class SimpleCPUOffloadConnector(KVConnectorBase_V1, SupportsHMA):
49
self,
50
vllm_config: VllmConfig,
51
role: KVConnectorRole,
52
- kv_cache_config: "KVCacheConfig | None" = None,
52
+ kv_cache_config: "KVCacheConfig",
53
):
54
super().__init__(vllm_config, role, kv_cache_config)
55
vllm/distributed/kv_transfer/kv_transfer_state.py
+1
-1
@@ -49,7 +49,7 @@ def is_v1_kv_transfer_group(connector: KVConnectorBaseType | None = None) -> boo
49
50
51
def ensure_kv_transfer_initialized(
52
- vllm_config: "VllmConfig", kv_cache_config: "KVCacheConfig | None" = None
52
+ vllm_config: "VllmConfig", kv_cache_config: "KVCacheConfig"
53
) -> None:
54
"""
55
Initialize KV cache transfer parallel group.