@@ -13,7 +13,7 @@ import hashlib |
| 13 | 13 | from dataclasses import dataclass |
| 14 | 14 | from pathlib import Path |
| 15 | 15 | |
| 16 | | -from dlm_sway.core.errors import SwayError |
| 16 | +from dlm_sway.core.errors import DlmCompatError, SwayError |
| 17 | 17 | from dlm_sway.core.sections import ( |
| 18 | 18 | Section, |
| 19 | 19 | SectionKind, |
@@ -22,6 +22,22 @@ from dlm_sway.core.sections import ( |
| 22 | 22 | ) |
| 23 | 23 | |
| 24 | 24 | |
| 25 | +def _installed_dlm_version() -> str | None: |
| 26 | + """Best-effort lookup of the installed ``dlm`` package version. |
| 27 | + |
| 28 | + Returns ``None`` when dlm isn't installed or metadata is missing; |
| 29 | + the returned string is informational (attached to |
| 30 | + ``DlmCompatError`` messages), never used for programmatic |
| 31 | + branching. |
| 32 | + """ |
| 33 | + try: |
| 34 | + from importlib.metadata import version |
| 35 | + |
| 36 | + return version("dlm") |
| 37 | + except Exception: # noqa: BLE001 — metadata lookup is best-effort |
| 38 | + return None |
| 39 | + |
| 40 | + |
| 25 | 41 | @dataclass(frozen=True, slots=True) |
| 26 | 42 | class DlmHandle: |
| 27 | 43 | """Everything the sway bridge pulls out of a ``.dlm`` file. |
@@ -87,6 +103,14 @@ def _resolve_base_model_to_hf_id(base_model: str) -> str: |
| 87 | 103 | resolve to ``HuggingFaceTB/SmolLM2-135M-Instruct``. sway's backends |
| 88 | 104 | call ``AutoModelForCausalLM.from_pretrained`` directly and need the |
| 89 | 105 | HF id. The ``hf:org/name`` escape hatch passes through unchanged. |
| 106 | + |
| 107 | + Behavior when ``dlm`` is not installed: return the raw key |
| 108 | + unchanged; the downstream backend load will surface a clean "not |
| 109 | + a valid HF id" error. Behavior when ``dlm`` is installed but its |
| 110 | + public surface drifts (e.g. ``.hf_id`` renamed to ``.repo_id``): |
| 111 | + raise :class:`DlmCompatError` — silent fallback here would hand |
| 112 | + the backend the raw registry key and produce a confusing |
| 113 | + "model not found" error far from the root cause. |
| 90 | 114 | """ |
| 91 | 115 | if base_model.startswith("hf:"): |
| 92 | 116 | return base_model[len("hf:") :] |
@@ -96,9 +120,19 @@ def _resolve_base_model_to_hf_id(base_model: str) -> str: |
| 96 | 120 | return base_model |
| 97 | 121 | try: |
| 98 | 122 | spec = resolve_base(base_model) |
| 99 | | - except Exception: # noqa: BLE001 — unknown dlm errors |
| 100 | | - return base_model |
| 101 | | - hf_id = getattr(spec, "hf_id", None) |
| 123 | + except Exception as exc: # noqa: BLE001 — unknown dlm errors |
| 124 | + raise DlmCompatError( |
| 125 | + f"dlm.base_models.resolve({base_model!r}) raised {type(exc).__name__}: {exc}", |
| 126 | + installed_dlm_version=_installed_dlm_version(), |
| 127 | + ) from exc |
| 128 | + if not hasattr(spec, "hf_id"): |
| 129 | + raise DlmCompatError( |
| 130 | + f"dlm.base_models.resolve({base_model!r}) returned " |
| 131 | + f"{type(spec).__name__} without the expected 'hf_id' attribute " |
| 132 | + f"(attrs seen: {sorted(a for a in dir(spec) if not a.startswith('_'))[:8]!r})", |
| 133 | + installed_dlm_version=_installed_dlm_version(), |
| 134 | + ) |
| 135 | + hf_id = spec.hf_id |
| 102 | 136 | return str(hf_id) if hf_id else base_model |
| 103 | 137 | |
| 104 | 138 | |