Files
vllm-omni/vllm_omni/host_weight_runtime/protocols.py
T
2026-08-21 08:50:59 +08:00

229 lines
7.1 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Provider and consumer protocols for Host Weight Runtime extensions."""
from __future__ import annotations
import math
from dataclasses import dataclass, field
from enum import Enum
from types import TracebackType
from typing import TYPE_CHECKING, Protocol
import torch
from .identity import CanonicalJson, WeightArtifactIdentity
from .manifest import TensorKind
if TYPE_CHECKING:
from .config import ValidationLevel
from .lease import HostWeightLease
from .outcomes import StoreResult
class ProductionSourceMode(str, Enum):
FINALIZED_MODEL = "finalized_model"
CHECKPOINT_STREAM = "checkpoint_stream"
class CoordinationScope(str, Enum):
SINGLE_PROCESS = "single_process"
GROUP_COHORT = "group_cohort"
ARTIFACT_BUNDLE = "artifact_bundle"
class LookupPhase(str, Enum):
PRE_LOAD_SAFE = "pre_load_safe"
POST_LOAD_ONLY = "post_load_only"
@dataclass(frozen=True)
class TensorWriteSpec:
name: str
shape: tuple[int, ...]
dtype: torch.dtype
kind: TensorKind = TensorKind.PARAMETER
role: str = "weight"
def __post_init__(self) -> None:
if not isinstance(self.name, str) or not self.name or not isinstance(self.role, str) or not self.role:
raise ValueError("tensor write name and role must not be empty")
if not isinstance(self.shape, tuple) or any(
isinstance(dimension, bool) or not isinstance(dimension, int) or dimension < 0 for dimension in self.shape
):
raise ValueError(f"tensor {self.name!r} has a negative shape dimension")
if not isinstance(self.dtype, torch.dtype):
raise ValueError(f"tensor {self.name!r} must declare one torch dtype")
if not isinstance(self.kind, TensorKind):
raise ValueError(f"tensor {self.name!r} must use TensorKind")
@property
def numel(self) -> int:
return math.prod(self.shape) if self.shape else 1
@property
def nbytes(self) -> int:
return self.numel * torch.empty((), dtype=self.dtype).element_size()
class TensorFileWriter(Protocol):
def write_tensor(self, name: str, tensor: torch.Tensor) -> None: ...
def write_rows(self, name: str, start_row: int, tensor: torch.Tensor) -> None: ...
def close(self) -> None: ...
def __enter__(self) -> TensorFileWriter: ...
def __exit__(
self,
exc_type: type[BaseException] | None,
exc: BaseException | None,
_traceback: TracebackType | None,
) -> bool | None: ...
class ArtifactWriter(Protocol):
def open_tensor_file(
self,
relative_name: str,
specs: tuple[TensorWriteSpec, ...],
) -> TensorFileWriter: ...
@dataclass(frozen=True)
class WeightProductionSpec:
producer_id: str
outputs: tuple[WeightArtifactIdentity, ...]
source_mode: ProductionSourceMode
coordination_scope: CoordinationScope = CoordinationScope.SINGLE_PROCESS
lookup_phase: LookupPhase = LookupPhase.PRE_LOAD_SAFE
def __post_init__(self) -> None:
if not isinstance(self.producer_id, str) or not self.producer_id or not self.outputs:
raise ValueError("producer_id and outputs must not be empty")
if not isinstance(self.outputs, tuple) or any(
not isinstance(output, WeightArtifactIdentity) for output in self.outputs
):
raise ValueError("producer outputs must be an immutable tuple of artifact identities")
if not isinstance(self.source_mode, ProductionSourceMode):
raise ValueError("producer source mode must use ProductionSourceMode")
if not isinstance(self.coordination_scope, CoordinationScope):
raise ValueError("producer coordination scope must use CoordinationScope")
if not isinstance(self.lookup_phase, LookupPhase):
raise ValueError("producer lookup phase must use LookupPhase")
if len({output.key for output in self.outputs}) != len(self.outputs):
raise ValueError("producer outputs must have unique semantic identities")
if any(output.producer.producer_id != self.producer_id for output in self.outputs):
raise ValueError("producer outputs must name the declaring producer_id")
@dataclass(frozen=True)
class ProductionMetadata:
producer_schema: str
restorer_schema: str
format_metadata: CanonicalJson = field(default_factory=CanonicalJson.empty)
def __post_init__(self) -> None:
if (
not isinstance(self.producer_schema, str)
or not self.producer_schema
or not isinstance(self.restorer_schema, str)
or not self.restorer_schema
):
raise ValueError("producer and restorer schema identifiers must not be empty")
if not isinstance(self.format_metadata, CanonicalJson):
raise ValueError("production format metadata must use CanonicalJson")
class WeightProducer(Protocol):
"""Synchronous V1 producer; callers do not preempt an active build."""
@property
def spec(self) -> WeightProductionSpec: ...
def produce(self, writer: ArtifactWriter) -> ProductionMetadata:
"""Produce one exact artifact synchronously or raise."""
...
@dataclass(frozen=True)
class BuildRequest:
identity: WeightArtifactIdentity
class WeightRestorePlan(Protocol):
"""A validated, one-shot model mutation plan."""
def commit(self) -> None:
"""Mutate the target model exactly once or raise."""
...
class WeightRestorer(Protocol):
"""Validate a lease-to-model restore without mutating either input."""
@property
def schema(self) -> str: ...
def plan_restore(self, model: object, lease: HostWeightLease) -> WeightRestorePlan:
"""Return a validated plan; all model mutation is deferred to commit()."""
...
class HostWeightStore(Protocol):
"""Exact artifact access whose deadlines bound lock acquisition only."""
def lookup(
self,
identity: WeightArtifactIdentity,
*,
validation: ValidationLevel,
deadline: float | None = None,
) -> StoreResult: ...
def get_or_build(
self,
request: BuildRequest,
producer: WeightProducer,
*,
validation: ValidationLevel,
deadline: float,
) -> StoreResult: ...
@dataclass(frozen=True)
class RemoteArtifactDescriptor:
identity: WeightArtifactIdentity
provider_id: str
manifest_sha256: str
content_sha256: str
class RemoteArtifactProvider(Protocol):
@property
def provider_id(self) -> str: ...
def probe(self, identity: WeightArtifactIdentity) -> RemoteArtifactDescriptor | None: ...
def fetch(self, descriptor: RemoteArtifactDescriptor, writer: ArtifactWriter) -> ProductionMetadata: ...
__all__ = [
"ArtifactWriter",
"BuildRequest",
"CoordinationScope",
"HostWeightStore",
"LookupPhase",
"ProductionMetadata",
"ProductionSourceMode",
"RemoteArtifactDescriptor",
"RemoteArtifactProvider",
"TensorFileWriter",
"TensorWriteSpec",
"WeightProducer",
"WeightProductionSpec",
"WeightRestorePlan",
"WeightRestorer",
]