The 500-line rule and the one-line-comment rule were enforced only from
memory, so they drifted. bench/filesize_check.py now checks the budget on
every tracked source file, and it passes.
Split, with behaviour proven unchanged by comparing each moved function body
against HEAD byte for byte (53 training bodies, 21 benchmark bodies, 0
differences):
db.py 503 -> 396 store_search.py 105
bench/run.py 609 -> 351 query_set.py 80, report.py 211
benchmarks.py 619 -> 424 benchmark_scoring.py 262
training.py 1630 -> 94 training_{common,encode,metrics,datasets,lora,retrieval}
TrainingService stays as a thin facade for the CLI; the facade's parameter
lists are pinned against the module functions by inspect, which is what
catches a leaked self.
Deleted the eight top-level functions no file called, after fixing the scan
that had reported 201 false positives by skipping the defining file. The
v1/v2/v3 sweep found nothing to delete and says so: every remaining version
tag is an on-disk format marker, a migration step, a fixture name, or a
third-party model name.
Collapsed 39 multi-line comment blocks (86 lines) to one line each, keeping
the measured facts and error strings that justify the code.
269 tests pass; ruff clean; mypy 24 errors in 9 files against a 24-in-6
baseline, net zero; pyright 4, the same four HEAD measures.
265 lines
9.4 KiB
Python
265 lines
9.4 KiB
Python
"""One place decides which adapter loads, and says out loud why the others do not."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import weakref
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from pydantic import ValidationError
|
|
|
|
from . import cartridge_store
|
|
from .config import Settings
|
|
from .db import Database
|
|
from .runtime_schemas import AdapterChoice, AdapterLoadReport, AdapterOrigin, AdapterState
|
|
from .schemas import AdapterManifest, TrainingAdapterKind
|
|
|
|
logger = logging.getLogger("ely_eye.adapters")
|
|
|
|
MANIFEST_FILE = "adapter_manifest.json"
|
|
WEIGHTS_FILE = "adapter_model.safetensors"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AdapterSource:
|
|
"""One adapter found on disk, plus where it was found."""
|
|
|
|
path: Path
|
|
manifest: AdapterManifest
|
|
origin: AdapterOrigin
|
|
cartridge_id: str | None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class LoadRecord:
|
|
"""One adapter this process attached to one model."""
|
|
|
|
source: AdapterSource
|
|
|
|
@property
|
|
def kind(self) -> TrainingAdapterKind:
|
|
return self.source.manifest.kind
|
|
|
|
@property
|
|
def adapter_id(self) -> str:
|
|
return self.source.manifest.adapter_id
|
|
|
|
@property
|
|
def path(self) -> str:
|
|
return str(self.source.path)
|
|
|
|
@property
|
|
def sha256(self) -> str:
|
|
return self.source.manifest.sha256
|
|
|
|
|
|
_ATTACHMENTS: list[tuple[LoadRecord, weakref.ReferenceType[object]]] = []
|
|
|
|
|
|
def read_manifest(path: Path) -> AdapterManifest:
|
|
try:
|
|
text = path.read_text(encoding="utf-8")
|
|
except OSError as error:
|
|
raise ValueError(f"{path}: the adapter manifest cannot be read ({error})") from error
|
|
try:
|
|
return AdapterManifest.model_validate_json(text)
|
|
except ValidationError as error:
|
|
raise ValueError(
|
|
f"{path}: the adapter manifest is not a valid AdapterManifest ({error})"
|
|
) from error
|
|
|
|
|
|
def cartridge_roots(database: Database) -> dict[str, Path]:
|
|
roots: dict[str, Path] = {}
|
|
for row in database.list_cartridges():
|
|
roots[str(row["cartridge_id"])] = Path(str(row["root_path"]))
|
|
return roots
|
|
|
|
|
|
def library_sources(settings: Settings) -> list[AdapterSource]:
|
|
"""Adapters in the library directory, for callers that have no database open."""
|
|
if settings.adapter_dir is not None:
|
|
pinned = settings.adapter_dir.expanduser()
|
|
if not (pinned / MANIFEST_FILE).exists():
|
|
logger.warning("adapter_dir %s holds no %s", pinned, MANIFEST_FILE)
|
|
return []
|
|
manifest = read_manifest(pinned / MANIFEST_FILE)
|
|
return [
|
|
AdapterSource(
|
|
path=pinned,
|
|
manifest=manifest,
|
|
origin="library",
|
|
cartridge_id=manifest.cartridge_id,
|
|
)
|
|
]
|
|
sources: list[AdapterSource] = []
|
|
for manifest_path in sorted(settings.adapters_dir.glob(f"*/{MANIFEST_FILE}")):
|
|
manifest = read_manifest(manifest_path)
|
|
sources.append(
|
|
AdapterSource(
|
|
path=manifest_path.parent,
|
|
manifest=manifest,
|
|
origin="library",
|
|
cartridge_id=manifest.cartridge_id,
|
|
)
|
|
)
|
|
return sources
|
|
|
|
|
|
def discover(settings: Settings, database: Database) -> tuple[list[AdapterSource], list[str]]:
|
|
"""Every adapter the runtime could use: the library plus the copies inside mounted cartridges."""
|
|
mounted = cartridge_store.mounted_ids(database)
|
|
roots = cartridge_roots(database)
|
|
sources = library_sources(settings)
|
|
for cartridge_id in mounted:
|
|
root = roots.get(cartridge_id)
|
|
if root is None:
|
|
logger.warning(
|
|
"cartridge %s is mounted but its directory is not registered", cartridge_id
|
|
)
|
|
continue
|
|
for manifest_path in sorted((root / "adapters").glob(f"*/{MANIFEST_FILE}")):
|
|
sources.append(
|
|
AdapterSource(
|
|
path=manifest_path.parent,
|
|
manifest=read_manifest(manifest_path),
|
|
origin="cartridge",
|
|
cartridge_id=cartridge_id,
|
|
)
|
|
)
|
|
return sources, mounted
|
|
|
|
|
|
def resolve(
|
|
sources: list[AdapterSource],
|
|
settings: Settings,
|
|
kind: TrainingAdapterKind,
|
|
) -> tuple[AdapterSource | None, AdapterState, str]:
|
|
"""Pick the adapter to load for one kind, or say which state it is stuck in and why."""
|
|
candidates = [source for source in sources if source.manifest.kind == kind]
|
|
if not candidates:
|
|
return None, "missing", f"no adapter of kind {kind.value} is on disk"
|
|
matching = [source for source in candidates if source.manifest.base_model == settings.model_id]
|
|
if not matching:
|
|
trained_on = ", ".join(sorted({source.manifest.base_model for source in candidates}))
|
|
return (
|
|
None,
|
|
"deferred",
|
|
f"every {kind.value} adapter is trained on {trained_on}; the runtime holds {settings.model_id}",
|
|
)
|
|
ready = [source for source in matching if (source.path / WEIGHTS_FILE).exists()]
|
|
if not ready:
|
|
return (
|
|
None,
|
|
"deferred",
|
|
f"the {kind.value} manifests are present but none carries {WEIGHTS_FILE}",
|
|
)
|
|
ready.sort(key=_preference, reverse=True)
|
|
chosen = ready[0]
|
|
if chosen.origin == "cartridge":
|
|
return chosen, "available", f"selected from mounted cartridge {chosen.cartridge_id}"
|
|
return chosen, "available", "selected from the adapter library"
|
|
|
|
|
|
def _preference(source: AdapterSource) -> tuple[bool, bool, float]:
|
|
weights = source.path / WEIGHTS_FILE
|
|
return (
|
|
source.origin == "cartridge",
|
|
source.manifest.cartridge_id is not None,
|
|
weights.stat().st_mtime if weights.exists() else 0.0,
|
|
)
|
|
|
|
|
|
def load_records() -> list[LoadRecord]:
|
|
"""Every adapter still attached, or attached since the last load, in attachment order."""
|
|
return [record for record, _reference in _ATTACHMENTS]
|
|
|
|
|
|
def live_attachments() -> list[LoadRecord]:
|
|
"""Attachments whose model still exists; a dead model cannot be claimed as loaded."""
|
|
return [record for record, reference in _ATTACHMENTS if reference() is not None]
|
|
|
|
|
|
def record_load(source: AdapterSource, model: Any) -> LoadRecord:
|
|
record = LoadRecord(source=source)
|
|
_ATTACHMENTS[:] = [
|
|
(item, reference) for item, reference in _ATTACHMENTS if reference() is not None
|
|
]
|
|
_ATTACHMENTS.append((record, weakref.ref(model)))
|
|
logger.info("loaded adapter %s (%s) from %s", record.adapter_id, record.kind.value, record.path)
|
|
return record
|
|
|
|
|
|
def load_into_model(model: Any, path: Path) -> Any:
|
|
"""Attach one LoRA to a live model; the only place generation imports peft."""
|
|
from .training_metrics import bitsandbytes_gaudi_probe_guard
|
|
|
|
with bitsandbytes_gaudi_probe_guard():
|
|
from peft import PeftModel
|
|
|
|
return PeftModel.from_pretrained(model, str(path))
|
|
|
|
|
|
def plan(settings: Settings, database: Database) -> AdapterLoadReport:
|
|
"""One row per adapter kind, plus a row for every adapter that lost the choice."""
|
|
sources, mounted = discover(settings, database)
|
|
rows: list[AdapterChoice] = []
|
|
winners: dict[str, AdapterSource | None] = {}
|
|
attached = live_attachments()
|
|
for kind in TrainingAdapterKind:
|
|
source, state, reason = resolve(sources, settings, kind)
|
|
winners[kind.value] = source
|
|
live = [record for record in attached if record.kind == kind]
|
|
earlier = next((record for record in reversed(load_records()) if record.kind == kind), None)
|
|
if live:
|
|
newest = live[-1]
|
|
state = "loaded"
|
|
reason = f"attached to the live model from {newest.path}"
|
|
held = sorted({record.adapter_id for record in live[:-1] if record.adapter_id != newest.adapter_id})
|
|
if held:
|
|
subject = "another live model still holds" if len(held) == 1 else "other live models still hold"
|
|
reason = f"{reason}; {subject} {' and '.join(held)}"
|
|
rows.append(_choice(kind, state, reason, newest.source))
|
|
continue
|
|
if earlier is not None and source is not None:
|
|
state = "available"
|
|
reason = f"{reason}; {earlier.adapter_id} was attached earlier in this process and that model is gone"
|
|
rows.append(_choice(kind, state, reason, source))
|
|
for source in sources:
|
|
winner = winners.get(source.manifest.kind.value)
|
|
if winner is None or source.path == winner.path:
|
|
continue
|
|
rows.append(
|
|
_choice(
|
|
source.manifest.kind,
|
|
"deferred",
|
|
f"shadowed by {winner.manifest.adapter_id} for the current mount",
|
|
source,
|
|
shadowed=True,
|
|
)
|
|
)
|
|
return AdapterLoadReport(model_id=settings.model_id, mounted=mounted, adapters=rows)
|
|
|
|
|
|
def _choice(
|
|
kind: TrainingAdapterKind,
|
|
state: AdapterState,
|
|
reason: str,
|
|
source: AdapterSource | None,
|
|
shadowed: bool = False,
|
|
) -> AdapterChoice:
|
|
"""Build one report row from the adapter the row is actually talking about."""
|
|
return AdapterChoice(
|
|
kind=kind,
|
|
state=state,
|
|
reason=reason,
|
|
path=str(source.path) if source else None,
|
|
adapter_id=source.manifest.adapter_id if source else None,
|
|
base_model=source.manifest.base_model if source else None,
|
|
origin=source.origin if source else None,
|
|
cartridge_id=source.cartridge_id if source else None,
|
|
shadowed=shadowed,
|
|
)
|