HF cache config mixin

A dataclass mixin adding HuggingFace Hub cache / revision / air-gap / security fields to a capability’s config, with RELOAD_TRIGGER + JSON-schema metadata pre-set.

Capabilities that load models from the HuggingFace Hub compose HFCacheConfig into their config dataclass by inheritance. All four fields are RELOAD_TRIGGER-tagged ("model"): changing any of them invalidates a loaded model, so the substrate’s CR-4 reconfigure path fires _release_model before re-applying config.

Dataclass inheritance places these (defaulted) fields FIRST in __init__ order, so the consuming capability’s own fields must also carry defaults (they generally do).


HFCacheConfig


def HFCacheConfig(
    cache_dir:Optional=None, revision:Optional=None, local_files_only:bool=False, trust_remote_code:bool=False
)->None:

Mixin adding HuggingFace Hub cache/revision/air-gap/security fields to a capability config.

Compose by inheritance:

@dataclass
class MyCapabilityConfig(HFCacheConfig):
    model_id: str = field(default="org/model", metadata={RELOAD_TRIGGER: "model"})
    # ... capability-specific fields (all defaulted) ...

Each field is RELOAD_TRIGGER-tagged "model" (a change invalidates a loaded model) and carries SCHEMA_TITLE/SCHEMA_DESC so the capability-config UI renders it. trust_remote_code defaults to False and is flagged DANGER in its help text.

Tests.

import dataclasses
from cjm_substrate.utils.validation import (
    config_to_dict, dict_to_config, dataclass_to_jsonschema,
)


@dataclasses.dataclass
class _DemoConfig(HFCacheConfig):
    model_id: str = field(default="org/m", metadata={RELOAD_TRIGGER: "model", SCHEMA_TITLE: "Model ID"})


# Mixin fields are present, defaulted, and RELOAD_TRIGGER-tagged.
_fields = {f.name: f for f in dataclasses.fields(_DemoConfig)}
for _n in ("cache_dir", "revision", "local_files_only", "trust_remote_code", "model_id"):
    assert _n in _fields, _n
for _n in ("cache_dir", "revision", "local_files_only", "trust_remote_code"):
    assert _fields[_n].metadata[RELOAD_TRIGGER] == "model"

# Defaults are safe (no cache override, no remote-code execution).
_c = _DemoConfig()
assert _c.cache_dir is None and _c.revision is None
assert _c.local_files_only is False and _c.trust_remote_code is False

# Round-trips through the substrate's config helpers.
_d = config_to_dict(_DemoConfig(cache_dir="/tmp/hf", trust_remote_code=True))
assert _d["cache_dir"] == "/tmp/hf" and _d["trust_remote_code"] is True
_c2 = dict_to_config(_DemoConfig, {"revision": "abc123", "model_id": "org/y"})
assert _c2.revision == "abc123" and _c2.model_id == "org/y"

# JSON-schema picks up the titles for the config UI.
_schema = dataclass_to_jsonschema(_DemoConfig)
assert "cache_dir" in _schema["properties"]
assert _schema["properties"]["cache_dir"]["title"] == "HF Cache Directory"