[Attention] Make sliding-window support an explicit backend capability (#48011)
Signed-off-by: NickLucche <nicolo.lucchesi@mistral.ai> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Andreas Karatzas <akaratza@amd.com>
Nicolò Lucchesi committed
Jul 13, 2026 at 10:07 UTC
bea70c7cfc10303f843cb4bda0e990e88f525f76
10 files changed
+41
vllm/model_executor/layers/attention/attention.py
+1
@@ -355,6 +355,7 @@ class Attention(nn.Module, AttentionLayerBase):
355
use_mm_prefix=self.use_mm_prefix,
356
use_per_head_quant_scales=use_per_head_quant_scales,
357
attn_type=attn_type,
358
+ has_sliding_window=sliding_window is not None,
359
)
360
else:
361
self.attn_backend = attn_backend
vllm/v1/attention/backend.py
+7
@@ -258,6 +258,10 @@ class AttentionBackend(ABC):
258
def supports_per_head_quant_scales(cls) -> bool:
259
return False
260
261
+ @classmethod
262
+ def supports_sliding_window(cls) -> bool:
263
+ return False
264
+
265
@classmethod
266
def supports_non_causal(cls) -> bool:
267
"""Check if backend supports non-causal (bidirectional) attention
@@ -319,6 +323,7 @@ class AttentionBackend(ABC):
323
use_per_head_quant_scales: bool,
324
device_capability: "DeviceCapability",
325
attn_type: str,
326
+ has_sliding_window: bool = False,
327
use_non_causal: bool = False,
328
use_batch_invariant: bool = False,
329
use_kv_connector: bool = False,
@@ -354,6 +359,8 @@ class AttentionBackend(ABC):
359
invalid_reasons.append("compute capability not supported")
360
if not cls.supports_attn_type(attn_type):
361
invalid_reasons.append(f"attention type {attn_type} not supported")
362
+ if has_sliding_window and not cls.supports_sliding_window():
363
+ invalid_reasons.append("sliding window not supported")
364
if use_non_causal and not cls.supports_non_causal():
365
invalid_reasons.append("non-causal attention not supported")
366
if use_batch_invariant and not cls.supports_batch_invariance():
vllm/v1/attention/backends/cpu_attn.py
+4
@@ -67,6 +67,10 @@ class CPUAttentionBackend(AttentionBackend):
67
def supports_non_causal(cls) -> bool:
68
return True
69
70
+ @classmethod
71
+ def supports_sliding_window(cls) -> bool:
72
+ return True
73
+
74
@classmethod
75
def supports_attn_type(cls, attn_type: str) -> bool:
76
"""CPU attention supports decoder,
vllm/v1/attention/backends/flash_attn.py
+4
@@ -92,6 +92,10 @@ class FlashAttentionBackend(AttentionBackend):
92
def get_name() -> str:
93
return "FLASH_ATTN"
94
95
+ @classmethod
96
+ def supports_sliding_window(cls) -> bool:
97
+ return True
98
+
99
@classmethod
100
def supports_batch_invariance(cls) -> bool:
101
return True
vllm/v1/attention/backends/flashinfer.py
+4
@@ -380,6 +380,10 @@ class FlashInferBackend(AttentionBackend):
380
def supports_non_causal(cls) -> bool:
381
return True
382
383
+ @classmethod
384
+ def supports_sliding_window(cls) -> bool:
385
+ return True
386
+
387
@staticmethod
388
def get_impl_cls() -> type["FlashInferImpl"]:
389
return FlashInferImpl
vllm/v1/attention/backends/flex_attention.py
+4
@@ -100,6 +100,10 @@ class FlexAttentionBackend(AttentionBackend):
100
def get_name() -> str:
101
return "FLEX_ATTENTION"
102
103
+ @classmethod
104
+ def supports_sliding_window(cls) -> bool:
105
+ return True
106
+
107
@classmethod
108
def supports_non_causal(cls) -> bool:
109
return True
vllm/v1/attention/backends/rocm_aiter_fa.py
+4
@@ -750,6 +750,10 @@ class AiterFlashAttentionBackend(AttentionBackend):
750
def get_name() -> str:
751
return "FLASH_ATTN"
752
753
+ @classmethod
754
+ def supports_sliding_window(cls) -> bool:
755
+ return True
756
+
757
@staticmethod
758
def get_impl_cls() -> type["AiterFlashAttentionImpl"]:
759
return AiterFlashAttentionImpl
vllm/v1/attention/backends/rocm_attn.py
+4
@@ -220,6 +220,10 @@ class RocmAttentionBackend(AttentionBackend):
220
def get_name() -> str:
221
return "ROCM_ATTN"
222
223
+ @classmethod
224
+ def supports_sliding_window(cls) -> bool:
225
+ return True
226
+
227
@staticmethod
228
def get_impl_cls() -> type["RocmAttentionImpl"]:
229
return RocmAttentionImpl
vllm/v1/attention/backends/triton_attn.py
+4
@@ -306,6 +306,10 @@ class TritonAttentionBackend(AttentionBackend):
306
def get_name() -> str:
307
return "TRITON_ATTN"
308
309
+ @classmethod
310
+ def supports_sliding_window(cls) -> bool:
311
+ return True
312
+
313
@classmethod
314
def supports_batch_invariance(cls) -> bool:
315
return True
vllm/v1/attention/selector.py
+5
@@ -29,6 +29,7 @@ class AttentionSelectorConfig(NamedTuple):
29
use_mm_prefix: bool = False
30
use_per_head_quant_scales: bool = False
31
attn_type: str = AttentionType.DECODER
32
+ has_sliding_window: bool = False
33
use_non_causal: bool = False
34
use_batch_invariant: bool = False
35
use_kv_connector: bool = False
@@ -45,6 +46,7 @@ class AttentionSelectorConfig(NamedTuple):
46
f"use_mm_prefix={self.use_mm_prefix}, "
47
f"use_per_head_quant_scales={self.use_per_head_quant_scales}, "
48
f"attn_type={self.attn_type}, "
49
+ f"has_sliding_window={self.has_sliding_window}, "
50
f"use_non_causal={self.use_non_causal}, "
51
f"use_batch_invariant={self.use_batch_invariant}, "
52
f"use_kv_connector={self.use_kv_connector})"
@@ -62,6 +64,7 @@ def get_attn_backend(
64
use_per_head_quant_scales: bool = False,
65
attn_type: str | None = None,
66
num_heads: int | None = None,
67
+ has_sliding_window: bool = False,
68
) -> type[AttentionBackend]:
69
"""Selects which attention backend to use and lazily imports it."""
70
@@ -77,6 +80,7 @@ def get_attn_backend(
80
vllm_config = get_current_vllm_config()
81
82
cache_config = vllm_config.cache_config
83
+ block_size: int | None
84
if cache_config is not None and cache_config.user_specified_block_size:
85
block_size = cache_config.block_size
86
else:
@@ -98,6 +102,7 @@ def get_attn_backend(
102
use_mm_prefix=use_mm_prefix,
103
use_per_head_quant_scales=use_per_head_quant_scales,
104
attn_type=attn_type or AttentionType.DECODER,
105
+ has_sliding_window=has_sliding_window,
106
use_non_causal=vllm_config.attention_config.use_non_causal,
107
use_batch_invariant=envs.VLLM_BATCH_INVARIANT,
108
use_kv_connector=use_kv_connector,