[Config] Infer HiSparse attention config from HiSparseConnector (#57041)

Signed-off-by: NickLucche <nicolo.lucchesi@mistral.ai>

Nicolò Lucchesi committed Sep 15, 2026 at 21:44 UTC df42d112ee88dd4a9b64efbad55621af6a66a44b
3 files changed +113 -2
tests/test_config.py
+102
@@ -337,6 +337,108 @@ def test_hisparse_rejects_non_cuda(monkeypatch):
337 VllmConfig(attention_config=AttentionConfig(hisparse_config=HiSparseConfig()))
338
339
340 +@pytest.mark.parametrize(
341 + "kv_transfer_config",
342 + [
343 + KVTransferConfig(
344 + kv_connector="HiSparseConnector",
345 + kv_role="kv_both",
346 + kv_connector_extra_config={"host_pool_gib": 128},
347 + ),
348 + KVTransferConfig(
349 + kv_connector="MultiConnector",
350 + kv_role="kv_both",
351 + kv_connector_extra_config={
352 + "connectors": [
353 + {
354 + "kv_connector": "OffloadingConnector",
355 + "kv_role": "kv_both",
356 + "kv_connector_extra_config": {"cpu_bytes_to_use": 1 << 30},
357 + },
358 + {
359 + "kv_connector": "HiSparseConnector",
360 + "kv_role": "kv_both",
361 + "kv_connector_extra_config": {"host_pool_gib": 128},
362 + },
363 + ]
364 + },
365 + ),
366 + KVTransferConfig(
367 + kv_connector="MultiConnector",
368 + kv_role="kv_consumer",
369 + kv_connector_extra_config={
370 + "connectors": [
371 + {"kv_connector": "NixlConnector", "kv_role": "kv_consumer"},
372 + {
373 + "kv_connector": "HiSparseConnector",
374 + "kv_role": "kv_both",
375 + "kv_connector_extra_config": {"host_pool_gib": 128},
376 + },
377 + ]
378 + },
379 + ),
380 + ],
381 + ids=["standalone", "multi-connector", "pd-decode"],
382 +)
383 +def test_hisparse_connector_implies_attention_config(monkeypatch, kv_transfer_config):
384 + monkeypatch.setattr(current_platform, "is_cuda", lambda: True)
385 + monkeypatch.setattr("vllm.config.vllm.HAS_TRITON", True)
386 + config = VllmConfig(
387 + kv_transfer_config=kv_transfer_config,
388 + # Skip the HMA auto-detect block: it imports the connector class,
389 + # which pulls the platform's compiled attention extensions.
390 + scheduler_config=SchedulerConfig(
391 + max_model_len=2048,
392 + is_encoder_decoder=False,
393 + disable_hybrid_kv_cache_manager=False,
394 + ),
395 + )
396 + assert isinstance(config.attention_config.hisparse_config, HiSparseConfig)
397 +
398 +
399 +def test_hisparse_connector_preserves_explicit_attention_config(monkeypatch):
400 + monkeypatch.setattr(current_platform, "is_cuda", lambda: True)
401 + monkeypatch.setattr("vllm.config.vllm.HAS_TRITON", True)
402 + config = VllmConfig(
403 + attention_config=AttentionConfig(
404 + hisparse_config=HiSparseConfig(device_buffer_size=512)
405 + ),
406 + kv_transfer_config=KVTransferConfig(
407 + kv_connector="HiSparseConnector",
408 + kv_role="kv_both",
409 + kv_connector_extra_config={"host_pool_gib": 128},
410 + ),
411 + scheduler_config=SchedulerConfig(
412 + max_model_len=2048,
413 + is_encoder_decoder=False,
414 + disable_hybrid_kv_cache_manager=False,
415 + ),
416 + )
417 + assert config.attention_config.hisparse_config.device_buffer_size == 512
418 +
419 +
420 +def test_hisparse_connector_without_cuda_still_rejected(monkeypatch):
421 + monkeypatch.setattr(current_platform, "is_cuda", lambda: False)
422 + with pytest.raises(ValueError, match="requires NVIDIA CUDA"):
423 + VllmConfig(
424 + kv_transfer_config=KVTransferConfig(
425 + kv_connector="HiSparseConnector",
426 + kv_role="kv_both",
427 + kv_connector_extra_config={"host_pool_gib": 128},
428 + )
429 + )
430 +
431 +
432 +def test_no_hisparse_connector_keeps_attention_config_unset(monkeypatch):
433 + monkeypatch.setattr(current_platform, "is_cuda", lambda: True)
434 + config = VllmConfig(
435 + kv_transfer_config=KVTransferConfig(
436 + kv_connector="OffloadingConnector", kv_role="kv_both"
437 + )
438 + )
439 + assert config.attention_config.hisparse_config is None
440 +
441 +
442 def test_rocm_keeps_compiled_deepseek_defaults(monkeypatch):
443 """ROCm keeps the DSA models (DeepSeek V3.2/V4, GLM-5.2) on their compiled
444 MRV1 paths and off breakable cudagraphs by default."""
vllm/config/attention.py
+3 -1
@@ -88,7 +88,9 @@ class AttentionConfig:
88
89 hisparse_config: HiSparseConfig | None = None
90 """HiSparse host-resident KV configuration. Setting this enables experimental
91 - Model Runner V2-only HiSparse sparse-MLA decode hot-buffering."""
91 + Model Runner V2-only HiSparse sparse-MLA decode hot-buffering. It is inferred
92 + with defaults when HiSparseConnector is configured (directly or via
93 + MultiConnector); set it explicitly only to tune its fields."""
94
95 use_non_causal: bool = False
96 """Whether to use non-causal (bidirectional) attention."""
vllm/config/vllm.py
+8 -1
@@ -27,7 +27,7 @@ from vllm.triton_utils import HAS_TRITON
27 from vllm.utils import random_uuid
28 from vllm.utils.hashing import safe_hash
29
30 -from .attention import AttentionConfig
30 +from .attention import AttentionConfig, HiSparseConfig
31 from .cache import CacheConfig
32 from .compilation import CompilationConfig, CompilationMode, CUDAGraphMode
33 from .device import DeviceConfig
@@ -1630,6 +1630,13 @@ class VllmConfig:
1630 self._maybe_disable_dynamic_sd_for_data_parallel()
1631 self._maybe_override_dynamic_sd_cudagraph_mode()
1632
1633 + if (
1634 + self.attention_config.hisparse_config is None
1635 + and self.kv_transfer_config is not None
1636 + and self.kv_transfer_config.has_connector("HiSparseConnector")
1637 + ):
1638 + self.attention_config.hisparse_config = HiSparseConfig()
1639 +
1640 if self.attention_config.hisparse_config is not None:
1641 if not current_platform.is_cuda():
1642 raise ValueError("HiSparse currently requires NVIDIA CUDA.")