| 1 | # SPDX-License-Identifier: Apache-2.0 |
| 2 | # SPDX-FileCopyrightText: Copyright contributors to the vLLM project |
| 3 | |
| 4 | |
| 5 | import msgspec |
| 6 | |
| 7 | |
| 8 | class LoRARequest( |
| 9 | msgspec.Struct, |
| 10 | omit_defaults=True, # type: ignore[call-arg] |
| 11 | array_like=True, |
| 12 | ): # type: ignore[call-arg] |
| 13 | """Request for a LoRA adapter. |
| 14 | |
| 15 | lora_int_id must be globally unique for a given adapter. |
| 16 | This is currently not enforced in vLLM. |
| 17 | |
| 18 | load_inplace: If True, forces reloading the adapter even if one |
| 19 | with the same lora_int_id already exists in the cache. This replaces |
| 20 | the existing adapter in-place. If False (default), only loads if the |
| 21 | adapter is not already loaded. |
| 22 | """ |
| 23 | |
| 24 | lora_name: str |
| 25 | lora_int_id: int |
| 26 | lora_path: str = "" |
| 27 | base_model_name: str | None = msgspec.field(default=None) |
| 28 | tensorizer_config_dict: dict | None = None |
| 29 | load_inplace: bool = False |
| 30 | is_3d_lora_weight: bool = False |
| 31 | """Whether this adapter's MoE weights are stored in the 3D fused |
| 32 | `gate_up_proj` / `down_proj` layout (one fused tensor per layer) or the |
| 33 | 2D per-expert split layout (separate `gate_proj` / `up_proj` / `down_proj` |
| 34 | tensors per expert). Only consulted when the engine is started with |
| 35 | `enable_mixed_moe_lora_format=True`; otherwise it is ignored and the |
| 36 | on-disk format is inferred from the base model.""" |
| 37 | |
| 38 | def __post_init__(self): |
| 39 | if self.lora_int_id < 1: |
| 40 | raise ValueError(f"id must be > 0, got {self.lora_int_id}") |
| 41 | |
| 42 | # Ensure lora_path is not empty |
| 43 | assert self.lora_path, "lora_path cannot be empty" |
| 44 | |
| 45 | @property |
| 46 | def adapter_id(self): |
| 47 | return self.lora_int_id |
| 48 | |
| 49 | @property |
| 50 | def name(self): |
| 51 | return self.lora_name |
| 52 | |
| 53 | @property |
| 54 | def path(self): |
| 55 | return self.lora_path |
| 56 | |
| 57 | def __eq__(self, value: object) -> bool: |
| 58 | """Overrides the equality method to compare LoRARequest |
| 59 | instances based on lora_name. This allows for identification |
| 60 | and comparison lora adapter across engines. |
| 61 | """ |
| 62 | return isinstance(value, self.__class__) and self.lora_name == value.lora_name |
| 63 | |
| 64 | def __hash__(self) -> int: |
| 65 | """Overrides the hash method to hash LoRARequest instances |
| 66 | based on lora_name. This ensures that LoRARequest instances |
| 67 | can be used in hash-based collections such as sets and dictionaries, |
| 68 | identified by their names across engines. |
| 69 | """ |
| 70 | return hash(self.lora_name) |