From 4a9dd213304c18f6da62296207c7665d12c54741 Mon Sep 17 00:00:00 2001 From: lapy Date: Tue, 21 Jul 2026 13:44:48 +0100 Subject: [PATCH 1/3] Keep package catalog in sync with registered loaders Mark Kokoro, Higgs TTS, and Parakeet packages as UnsupportedSource while their loaders stay commented out of registry.cpp, set VieNeu family explicitly, and add maintainer docs plus a CI sync check so installable catalog entries cannot drift from --list-loaders again. --- .github/workflows/linux-build.yml | 3 + .github/workflows/mac-build.yml | 3 + .github/workflows/windows-build.yml | 4 + CONTRIBUTING.md | 6 ++ README.md | 13 +-- docs/maintainers/loader_and_catalog.md | 87 +++++++++++++++++ docs/usage.md | 2 +- src/framework/runtime/registry.cpp | 7 +- tools/check_loader_catalog_sync.py | 128 +++++++++++++++++++++++++ tools/model_manager.py | 38 +++++++- 10 files changed, 279 insertions(+), 12 deletions(-) create mode 100644 docs/maintainers/loader_and_catalog.md create mode 100644 tools/check_loader_catalog_sync.py diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 705978b74..f902ff1dc 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -37,6 +37,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Check loader/catalog sync + run: python3 tools/check_loader_catalog_sync.py + - name: Install dependencies run: | sudo apt-get update diff --git a/.github/workflows/mac-build.yml b/.github/workflows/mac-build.yml index e27e2874b..5efc7ca87 100644 --- a/.github/workflows/mac-build.yml +++ b/.github/workflows/mac-build.yml @@ -26,6 +26,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Check loader/catalog sync + run: python3 tools/check_loader_catalog_sync.py + - name: Configure run: | cmake -S . -B "$BUILD_DIR" \ diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index 55781fd43..9be596b59 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -23,6 +23,10 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Check loader/catalog sync + shell: pwsh + run: python tools/check_loader_catalog_sync.py + - name: Build audiocpp_cli shell: pwsh run: | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a972f697..dd106919f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,6 +20,12 @@ Please check the supported model table in [README.md](README.md) before starting If you want to add support for a model family that is already listed, please focus on improving the existing implementation instead of opening a duplicate port. +When a loader is registered (or parked), keep the **package catalog** in sync. Installable `ModelPackage` entries must not advertise families that `audiocpp_cli --list-loaders` does not expose. Follow the checklist in [docs/maintainers/loader_and_catalog.md](docs/maintainers/loader_and_catalog.md) and run: + +```bash +python3 tools/check_loader_catalog_sync.py +``` + Good follow-up work for existing model families includes: - Better CLI or server examples diff --git a/README.md b/README.md index d8ddd03c0..afb3a88fc 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Community model ports live under `community_models` to make the ownership bounda | **outetts** | TTS, voice cloning | en, ar, zh, nl, fr, de, it, ja, ko, lt, ru, es, pt, be, bn, ka, hu, lv, fa, pl, sw, ta, uk | Mirek [@mirek190](https://github.com/mirek190) | Llama-OuteTTS-1.0-1B TTS and voice cloning support | | **vietneu_tts** | TTS, voice cloning | vi, en | Phuoc [@phuocnguyen90](https://github.com/phuocnguyen90) | [VieNeu-TTS-v3-Turbo](vietneu_tts.md) TTS and voice cloning support | -WIP: Higgs Audio v3 TTS 4B, Fish Audio S2 Pro. +WIP (loaders not registered in this release tree — catalog entries are `UnsupportedSource`): Kokoro 82M bf16, Higgs Audio v3 TTS 4B, Parakeet TDT 0.6B v3, Fish Audio S2 Pro. See [docs/maintainers/loader_and_catalog.md](docs/maintainers/loader_and_catalog.md). PocketTTS language selection is a model-load option. When the model path points at the PocketTTS root, the loader uses `english` unless you pass `--load-option language=`. Kyutai's normal non-English PocketTTS releases are smaller distilled language models intended for the fast PocketTTS path. The `_24l` variants are larger 24-layer, undistilled preview models that can sound better but are slower. Kyutai currently publishes French only as `french_24l`, not as a normal distilled `french` language directory, so French is not listed as a normal PocketTTS language here. @@ -299,7 +299,8 @@ Useful CLI features: - `--help` with `--task` shows task-oriented help - `--help` with `--model ` and optional `--family ` shows model-owned request, session, and load options - `--inspect` prints discovered configs, weights, and capabilities -- `--list-loaders` prints registered model families +- `--list-loaders` prints registered model families (`--json` for the machine-readable contract) +- `python tools/model_manager.py list --json` prints installable packages; keep it synced with loaders ([docs/maintainers/loader_and_catalog.md](docs/maintainers/loader_and_catalog.md)) - `--batch-text-file ` runs one offline request per non-empty line - `--batch-text-dir ` runs one offline request per `.txt`, `.md`, or `.json` file, normalizing each file as one paragraph - `--batch-audio-dir ` runs one offline request per `.wav` @@ -370,7 +371,7 @@ The CLI also exposes the runtime loader catalog with `audiocpp_cli --list-loader Recommended top-level install packages: -`Yes` means Hugging Face has a ready-to-use repo that the framework can download as-is. `No` means the tool must assemble, convert, or post-process files before the framework can use them. +`Yes` means Hugging Face has a ready-to-use repo that the framework can download as-is. `No` means the tool must assemble, convert, or post-process files before the framework can use them. Packages whose loaders are not registered in this release tree are listed as **Unavailable** (see [docs/maintainers/loader_and_catalog.md](docs/maintainers/loader_and_catalog.md)). | Package id | Model | HF ready-to-use repo | |---|---|---| @@ -379,12 +380,12 @@ Recommended top-level install packages: | `citrinet_asr` | Citrinet ASR converted layout | No | | `heartmula` | HeartMuLa | No | | `higgs_audio_stt` | Higgs Audio STT | No | -| `higgs_audio_v3_tts_4b` | Higgs Audio v3 TTS 4B | **Yes** | +| `higgs_audio_v3_tts_4b` | Higgs Audio v3 TTS 4B | Unavailable (loader not in this tree) | | `htdemucs` | HTDemucs | No | | `hviske_asr` | Hviske ASR | **Yes** | | `irodori_tts_500m_v3` | Irodori-TTS 500M v3 | No | | `irodori_tts_600m_v3_voice_design` | Irodori-TTS 600M v3 VoiceDesign | No | -| `kokoro_82m_bf16` | Kokoro 82M bf16 | **Yes** | +| `kokoro_82m_bf16` | Kokoro 82M bf16 | Unavailable (loader not in this tree) | | `marblenet_vad` | MarbleNet VAD converted layout | No | | `mel_band_roformer` | Mel-Band RoFormer MLX | **Yes** | | `miocodec_25hz_44k_v2` | MioCodec 25Hz 44.1kHz v2 | No | @@ -397,7 +398,7 @@ Recommended top-level install packages: | `nemotron_asr` | Nemotron ASR | **Yes** | | `omnivoice` | OmniVoice | **Yes** | | `outetts_1_0_1b` | OuteTTS 1.0 1B with IBM DAC codec and Qwen3-aligned voice cloning | No | -| `parakeet_tdt_0_6b_v3` | Parakeet TDT 0.6B v3 | **Yes** | +| `parakeet_tdt_0_6b_v3` | Parakeet TDT 0.6B v3 | Unavailable (loader not in this tree) | | `pocket_tts` | PocketTTS | **Yes** | | `qwen3_asr_0_6b` | Qwen3 ASR 0.6B | **Yes** | | `qwen3_asr_1_7b_hf` | Qwen3 ASR 1.7B HF | **Yes** | diff --git a/docs/maintainers/loader_and_catalog.md b/docs/maintainers/loader_and_catalog.md new file mode 100644 index 000000000..a998e79c2 --- /dev/null +++ b/docs/maintainers/loader_and_catalog.md @@ -0,0 +1,87 @@ +# Maintaining Loaders and the Package Catalog + +Integrators (CLI users, servers, and UIs such as Studio) treat two exports as +**authoritative**: + +1. **Runtime loaders** — `audiocpp_cli --list-loaders --json` +2. **Install packages** — `python tools/model_manager.py list --json` + +Those surfaces must stay in sync. A package that is installable in the catalog +but whose `family` is missing from `--list-loaders` looks available to users and +then fails at runtime or in search/install UIs. + +## The rule + +For every **installable, standalone** `ModelPackage`: + +| Field | Must match | +|---|---| +| `ModelPackage.family` | The loader family string advertised by the C++ loader | +| `model_specs/.json` | Present when the family uses package-spec loading | +| `registry.cpp` entry | Uncommented `make__loader()` (or the family's actual factory name) | + +Dependency / subcomponent packages (`standalone=False`, with +`parent_package_id`) do **not** need their own loader. + +If a loader is not ready for this release tree: + +1. Keep it **commented out** in `src/framework/runtime/registry.cpp`, and +2. Mark matching catalog packages as `UnsupportedSource(reason=...)`, **or** + remove them from `CATALOG`. + +Do **not** leave a live `SnapshotSource` for a commented-out loader. + +## Checklist: adding a model family + +1. Implement `include/engine/models//` (or `community_models/`) with a + loader that overrides `advertised_capabilities()` so tasks/endpoints are + explicit. +2. Register it in `src/framework/runtime/registry.cpp` (include + + `available_loaders` entry). Prefer the factory name + `make__loader()` so the id matches the advertised family. +3. Add `model_specs/.json` when the family needs package-spec discovery. +4. Add one or more `ModelPackage` entries in `tools/model_manager.py`: + - Set `family=""` explicitly when the package id does not strip cleanly + to the loader id (examples: `kokoro_82m_bf16` → `kokoro_tts`). + - Set `tasks=(...)` when defaults would be ambiguous. + - Use `standalone=False` + `parent_package_id` for tokenizers / subcomponents. +5. Update README supported-model / package tables. +6. Run: + +```bash +python3 tools/check_loader_catalog_sync.py +# after building: +build/.../bin/audiocpp_cli --list-loaders --json +python3 tools/model_manager.py list --json +``` + +Confirm the new family appears in `--list-loaders` and that installable packages +for that family set `"family"` to the same string. + +## Checklist: parking or removing a family + +1. Comment out the include and `make_*_loader()` entry in `registry.cpp`. +2. Convert related **standalone** packages to `UnsupportedSource` with a reason + that names the missing loader and points at this doc (or delete them). +3. Leave `family=` / `tasks=` on unsupported entries if useful for history. +4. Update README so the package is not listed as a ready install target. +5. Run `python3 tools/check_loader_catalog_sync.py`. + +## Family id consistency + +Pick **one** family string and use it everywhere: + +- C++ loader / `advertised_capabilities()` +- `make__loader()` naming (when practical) +- `model_specs/.json` +- `ModelPackage.family` + +Avoid mismatches such as catalog `higgs_audio_tts` with a registry stub named +`higgs_tts`. Integrators match on the string; aliases are not implied. + +## CI + +`tools/check_loader_catalog_sync.py` runs in GitHub Actions. It parses active +(non-commented) loader factories from `registry.cpp` and compares them to +installable standalone packages from `model_manager.py`. It does not require a +compiled binary. diff --git a/docs/usage.md b/docs/usage.md index cbbff9c98..5a02835bc 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -11,7 +11,7 @@ audiocpp_cli --task --family --model --backend & config_path) { const std::vector> available_loaders = { - // Development registry entries from Share/AudioCPP that are not present in this release tree yet: + // Parked loaders — keep catalog packages UnsupportedSource while these stay commented. + // See docs/maintainers/loader_and_catalog.md. // engine::models::kokoro_tts::make_kokoro_tts_loader(), // engine::models::higgs_tts::make_higgs_tts_loader(), // engine::models::parakeet_tdt::make_parakeet_tdt_loader(), diff --git a/tools/check_loader_catalog_sync.py b/tools/check_loader_catalog_sync.py new file mode 100644 index 000000000..9cfedd615 --- /dev/null +++ b/tools/check_loader_catalog_sync.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +"""Fail when installable catalog packages reference unregistered loaders. + +The machine-readable contract from PR #74 makes package ``family`` and +``audiocpp_cli --list-loaders`` authoritative for integrators. Catalog entries +must not advertise installable packages for families that are commented out or +missing from ``src/framework/runtime/registry.cpp``. + +See docs/maintainers/loader_and_catalog.md. +""" + +from __future__ import annotations + +import argparse +import re +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[1] +REGISTRY_PATH = REPO_ROOT / "src" / "framework" / "runtime" / "registry.cpp" +MODEL_MANAGER_PATH = REPO_ROOT / "tools" / "model_manager.py" + +_LOADER_CALL_RE = re.compile(r"\bmake_([a-z0-9_]+)_loader\s*\(\s*\)") + + +def parse_registry_loaders(registry_text: str) -> tuple[set[str], set[str]]: + """Return (active_families, commented_families) from registry.cpp.""" + active: set[str] = set() + commented: set[str] = set() + for raw_line in registry_text.splitlines(): + line = raw_line.strip() + match = _LOADER_CALL_RE.search(line) + if not match: + continue + family = match.group(1) + if line.startswith("//"): + commented.add(family) + else: + active.add(family) + return active, commented + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--registry", + type=Path, + default=REGISTRY_PATH, + help="Path to registry.cpp", + ) + args = parser.parse_args() + + if not args.registry.is_file(): + print(f"error: registry not found: {args.registry}", file=sys.stderr) + return 2 + if not MODEL_MANAGER_PATH.is_file(): + print(f"error: model manager not found: {MODEL_MANAGER_PATH}", file=sys.stderr) + return 2 + + sys.path.insert(0, str(MODEL_MANAGER_PATH.parent)) + import model_manager as mm # noqa: E402 + + active, commented = parse_registry_loaders(args.registry.read_text(encoding="utf-8")) + if not active: + print("error: no active loaders parsed from registry.cpp", file=sys.stderr) + return 2 + + errors: list[str] = [] + warnings: list[str] = [] + + for package in mm.CATALOG: + payload = mm.package_payload(package) + package_id = str(payload.get("id") or "") + family = str(payload.get("family") or "").strip() + installable = bool(payload.get("installable")) + standalone = bool(payload.get("standalone", True)) + source = payload.get("source") if isinstance(payload.get("source"), dict) else {} + source_kind = str(source.get("kind") or "") + + if not family: + errors.append(f"{package_id}: missing family (set ModelPackage.family or fix id)") + continue + + if not installable or source_kind == "unsupported": + # Parked / unavailable packages may keep a family for documentation. + if family in active: + warnings.append( + f"{package_id}: UnsupportedSource but family '{family}' is already " + "registered — restore a real SnapshotSource/Composite/Converter" + ) + continue + + if not standalone: + # Dependency / subcomponent packages do not need their own loader. + continue + + if family not in active: + hint = "" + if family in commented: + hint = " (commented out in registry.cpp)" + elif family == "higgs_audio_tts" and "higgs_tts" in commented: + hint = " (registry stub uses higgs_tts; keep family ids consistent)" + errors.append( + f"{package_id}: installable standalone package family '{family}' " + f"is not registered in registry.cpp{hint}" + ) + + print(f"active_loaders={len(active)} catalog_packages={len(mm.CATALOG)}") + for warning in warnings: + print(f"warning: {warning}") + if errors: + print("loader/catalog sync failed:", file=sys.stderr) + for error in errors: + print(f" - {error}", file=sys.stderr) + print( + "\nFix: either register the loader in registry.cpp + model_specs/, " + "or mark the package UnsupportedSource. See " + "docs/maintainers/loader_and_catalog.md", + file=sys.stderr, + ) + return 1 + + print("ok: installable catalog families match registered loaders") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/model_manager.py b/tools/model_manager.py index fa6930392..8f899fb1c 100644 --- a/tools/model_manager.py +++ b/tools/model_manager.py @@ -220,7 +220,17 @@ def package_usage_examples(package: ModelPackage) -> list[str]: id="kokoro_82m_bf16", display_name="Kokoro 82M bf16", target_directory="Kokoro-82M-bf16", - source=SnapshotSource(repo_id="mlx-community/Kokoro-82M-bf16"), + # Loader is not registered in this release tree (see registry.cpp and + # docs/maintainers/loader_and_catalog.md). Keep the id for docs/history + # but do not advertise an installable HF snapshot. + source=UnsupportedSource( + reason=( + "kokoro_tts loader is not registered in this release tree yet " + "(commented out in src/framework/runtime/registry.cpp). " + "Re-enable the loader, add model_specs/kokoro_tts.json, then " + "restore a SnapshotSource here." + ), + ), required_files=("config.json", "kokoro-v1_0.safetensors", "voices/af_heart.safetensors"), family="kokoro_tts", tasks=("tts",), @@ -515,6 +525,8 @@ def package_usage_examples(package: ModelPackage) -> list[str]: "special_tokens_map.json", ), description="Installs VieNeu-TTS v3 Turbo GGUF model and configuration sidecars for C++ inference.", + family="vietneu_tts", + tasks=("tts",), ), ModelPackage( id="qwen3_tts_1_7b_base", @@ -600,8 +612,17 @@ def package_usage_examples(package: ModelPackage) -> list[str]: id="parakeet_tdt_0_6b_v3", display_name="Parakeet TDT 0.6B v3", target_directory="parakeet-tdt-0.6b-v3", - source=SnapshotSource(repo_id="nvidia/parakeet-tdt-0.6b-v3"), + source=UnsupportedSource( + reason=( + "parakeet_tdt loader is not registered in this release tree yet " + "(commented out in src/framework/runtime/registry.cpp). " + "Re-enable the loader, add model_specs/parakeet_tdt.json, then " + "restore a SnapshotSource here." + ), + ), required_files=("config.json", "model.safetensors", "processor_config.json", "tokenizer.json"), + family="parakeet_tdt", + tasks=("asr",), ), ModelPackage( id="pocket_tts", @@ -828,7 +849,18 @@ def package_usage_examples(package: ModelPackage) -> list[str]: id="higgs_audio_v3_tts_4b", display_name="Higgs Audio v3 TTS 4B", target_directory="higgs-audio-v3-tts-4b", - source=SnapshotSource(repo_id="bosonai/higgs-audio-v3-tts-4b"), + # Catalog family must match the registered loader family id. The parked + # registry stub currently uses higgs_tts; when re-enabling, pick one + # family string and use it in registry, model_specs, and this field. + source=UnsupportedSource( + reason=( + "higgs_tts / higgs_audio_tts loader is not registered in this " + "release tree yet (commented out in " + "src/framework/runtime/registry.cpp). Re-enable the loader with " + "one consistent family id, add the matching model_specs entry, " + "then restore a SnapshotSource here." + ), + ), required_files=( "chat_template.jinja", "config.json", From 11bcc89bffb8a422b8bacbadbaea24f884b3fa5b Mon Sep 17 00:00:00 2001 From: lapy Date: Tue, 21 Jul 2026 13:49:49 +0100 Subject: [PATCH 2/3] Harden loader/catalog sync checks and docs Re-verify parked families have no in-tree loader sources, expand the sync script with parked aliases, README table enforcement, bundled-loader exceptions, and self-tests, and fill missing README package rows so CI keeps catalog, registry, and docs aligned. --- .github/workflows/linux-build.yml | 4 +- .github/workflows/mac-build.yml | 4 +- .github/workflows/windows-build.yml | 4 +- CONTRIBUTING.md | 2 + README.md | 2 + docs/maintainers/loader_and_catalog.md | 48 +++- tools/check_loader_catalog_sync.py | 315 ++++++++++++++++++++++--- 7 files changed, 331 insertions(+), 48 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index f902ff1dc..a277f49db 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -38,7 +38,9 @@ jobs: uses: actions/checkout@v4 - name: Check loader/catalog sync - run: python3 tools/check_loader_catalog_sync.py + run: | + python3 tools/check_loader_catalog_sync.py --self-test + python3 tools/check_loader_catalog_sync.py - name: Install dependencies run: | diff --git a/.github/workflows/mac-build.yml b/.github/workflows/mac-build.yml index 5efc7ca87..99bf8f295 100644 --- a/.github/workflows/mac-build.yml +++ b/.github/workflows/mac-build.yml @@ -27,7 +27,9 @@ jobs: uses: actions/checkout@v4 - name: Check loader/catalog sync - run: python3 tools/check_loader_catalog_sync.py + run: | + python3 tools/check_loader_catalog_sync.py --self-test + python3 tools/check_loader_catalog_sync.py - name: Configure run: | diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index 9be596b59..2b4b145af 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -25,7 +25,9 @@ jobs: - name: Check loader/catalog sync shell: pwsh - run: python tools/check_loader_catalog_sync.py + run: | + python tools/check_loader_catalog_sync.py --self-test + python tools/check_loader_catalog_sync.py - name: Build audiocpp_cli shell: pwsh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dd106919f..d57257436 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,9 +23,11 @@ If you want to add support for a model family that is already listed, please foc When a loader is registered (or parked), keep the **package catalog** in sync. Installable `ModelPackage` entries must not advertise families that `audiocpp_cli --list-loaders` does not expose. Follow the checklist in [docs/maintainers/loader_and_catalog.md](docs/maintainers/loader_and_catalog.md) and run: ```bash +python3 tools/check_loader_catalog_sync.py --self-test python3 tools/check_loader_catalog_sync.py ``` +Do not leave a live Hugging Face `SnapshotSource` for a loader that is commented out of `registry.cpp` — mark it `UnsupportedSource` (or remove it) and update the README package table. Good follow-up work for existing model families includes: - Better CLI or server examples diff --git a/README.md b/README.md index afb3a88fc..3d2c6b724 100644 --- a/README.md +++ b/README.md @@ -385,6 +385,7 @@ Recommended top-level install packages: | `hviske_asr` | Hviske ASR | **Yes** | | `irodori_tts_500m_v3` | Irodori-TTS 500M v3 | No | | `irodori_tts_600m_v3_voice_design` | Irodori-TTS 600M v3 VoiceDesign | No | +| `index_tts2` | IndexTTS-2 | **Yes** | | `kokoro_82m_bf16` | Kokoro 82M bf16 | Unavailable (loader not in this tree) | | `marblenet_vad` | MarbleNet VAD converted layout | No | | `mel_band_roformer` | Mel-Band RoFormer MLX | **Yes** | @@ -414,6 +415,7 @@ Recommended top-level install packages: | `stable_audio_3_small_sfx` | Stable Audio 3 Small SFX | **Yes** | | `supertonic_3` | Supertonic 3 | **Yes** | | `vevo2` | Vevo2 | No | +| `vietneu_tts_v3_turbo` | VieNeu-TTS v3 Turbo | **Yes** | | `vibevoice_1_5b` | VibeVoice 1.5B | No | | `vibevoice_7b` | VibeVoice 7B | No | | `vibevoice_asr` | VibeVoice ASR | No | diff --git a/docs/maintainers/loader_and_catalog.md b/docs/maintainers/loader_and_catalog.md index a998e79c2..a0d0c5e34 100644 --- a/docs/maintainers/loader_and_catalog.md +++ b/docs/maintainers/loader_and_catalog.md @@ -19,15 +19,35 @@ For every **installable, standalone** `ModelPackage`: | `ModelPackage.family` | The loader family string advertised by the C++ loader | | `model_specs/.json` | Present when the family uses package-spec loading | | `registry.cpp` entry | Uncommented `make__loader()` (or the family's actual factory name) | +| README package table | Lists the package; use **Unavailable** when not installable | Dependency / subcomponent packages (`standalone=False`, with `parent_package_id`) do **not** need their own loader. +Bundled loaders without a downloadable package (today: `silero_vad`) are allowed. +If you add another, list it in `BUNDLED_LOADERS_WITHOUT_PACKAGE` inside +`tools/check_loader_catalog_sync.py`. + +## Verified parked families (this release tree) + +These registry stubs are **commented out**, and the loader sources are **not +present** under `src/models/` / `include/engine/models/` (or community paths): + +| Registry stub | Catalog package(s) | Notes | +|---|---|---| +| `kokoro_tts` | `kokoro_82m_bf16` | Warm-bench tests remain; no loader sources | +| `higgs_tts` | `higgs_audio_v3_tts_4b` (`family=higgs_audio_tts`) | Name mismatch: pick one id when re-enabling | +| `parakeet_tdt` | `parakeet_tdt_0_6b_v3` | Warm-bench / docs may remain | + +Matching catalog entries must use `UnsupportedSource` until the loader code is +actually merged and registered. + If a loader is not ready for this release tree: 1. Keep it **commented out** in `src/framework/runtime/registry.cpp`, and 2. Mark matching catalog packages as `UnsupportedSource(reason=...)`, **or** - remove them from `CATALOG`. + remove them from `CATALOG`, and +3. Mark the README package row **Unavailable**. Do **not** leave a live `SnapshotSource` for a commented-out loader. @@ -42,13 +62,15 @@ Do **not** leave a live `SnapshotSource` for a commented-out loader. 3. Add `model_specs/.json` when the family needs package-spec discovery. 4. Add one or more `ModelPackage` entries in `tools/model_manager.py`: - Set `family=""` explicitly when the package id does not strip cleanly - to the loader id (examples: `kokoro_82m_bf16` → `kokoro_tts`). + to the loader id (examples: `kokoro_82m_bf16` → `kokoro_tts`, + `vietneu_tts_v3_turbo` → `vietneu_tts`). - Set `tasks=(...)` when defaults would be ambiguous. - Use `standalone=False` + `parent_package_id` for tokenizers / subcomponents. 5. Update README supported-model / package tables. 6. Run: ```bash +python3 tools/check_loader_catalog_sync.py --self-test python3 tools/check_loader_catalog_sync.py # after building: build/.../bin/audiocpp_cli --list-loaders --json @@ -64,7 +86,7 @@ for that family set `"family"` to the same string. 2. Convert related **standalone** packages to `UnsupportedSource` with a reason that names the missing loader and points at this doc (or delete them). 3. Leave `family=` / `tasks=` on unsupported entries if useful for history. -4. Update README so the package is not listed as a ready install target. +4. Update README so the package row says **Unavailable**. 5. Run `python3 tools/check_loader_catalog_sync.py`. ## Family id consistency @@ -75,13 +97,23 @@ Pick **one** family string and use it everywhere: - `make__loader()` naming (when practical) - `model_specs/.json` - `ModelPackage.family` +- README “Supported Models” family column Avoid mismatches such as catalog `higgs_audio_tts` with a registry stub named -`higgs_tts`. Integrators match on the string; aliases are not implied. +`higgs_tts`. Integrators match on the string; aliases are not implied (the sync +check only knows the small parked alias map for currently parked stubs). ## CI -`tools/check_loader_catalog_sync.py` runs in GitHub Actions. It parses active -(non-commented) loader factories from `registry.cpp` and compares them to -installable standalone packages from `model_manager.py`. It does not require a -compiled binary. +`tools/check_loader_catalog_sync.py` runs in GitHub Actions on Linux/macOS/Windows +builds. It: + +- Parses active vs commented `make_*_loader()` calls in `registry.cpp` +- Compares them to installable standalone packages from `model_manager.py` +- Cross-checks the README recommended package table +- Does **not** require a compiled binary + +```bash +python3 tools/check_loader_catalog_sync.py --self-test +python3 tools/check_loader_catalog_sync.py +``` diff --git a/tools/check_loader_catalog_sync.py b/tools/check_loader_catalog_sync.py index 9cfedd615..bcae3d467 100644 --- a/tools/check_loader_catalog_sync.py +++ b/tools/check_loader_catalog_sync.py @@ -6,6 +6,17 @@ must not advertise installable packages for families that are commented out or missing from ``src/framework/runtime/registry.cpp``. +Verified release-tree facts this check encodes: + +- Parked registry stubs currently include ``kokoro_tts``, ``higgs_tts``, and + ``parakeet_tdt``. Those loader *sources are not in this tree* (no + ``src/models/`` / matching include); only comments + warm-bench tests + remain. Matching catalog packages must be ``UnsupportedSource``. +- ``higgs_audio_tts`` is treated as an alias of the parked ``higgs_tts`` stub + until one family id is chosen when the loader returns. +- ``silero_vad`` is a registered loader without a model_manager package (bundled + asset path). That is allowed; see docs/maintainers/loader_and_catalog.md. + See docs/maintainers/loader_and_catalog.md. """ @@ -14,14 +25,27 @@ import argparse import re import sys +import unittest from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[1] REGISTRY_PATH = REPO_ROOT / "src" / "framework" / "runtime" / "registry.cpp" MODEL_MANAGER_PATH = REPO_ROOT / "tools" / "model_manager.py" +README_PATH = REPO_ROOT / "README.md" _LOADER_CALL_RE = re.compile(r"\bmake_([a-z0-9_]+)_loader\s*\(\s*\)") +# Catalog family strings that refer to a differently named parked registry stub. +# When re-enabling a loader, collapse these to one id everywhere. +PARKED_FAMILY_ALIASES: dict[str, set[str]] = { + "higgs_tts": {"higgs_audio_tts"}, +} + +# Registered loaders that intentionally have no installable ModelPackage. +BUNDLED_LOADERS_WITHOUT_PACKAGE: set[str] = { + "silero_vad", +} + def parse_registry_loaders(registry_text: str) -> tuple[set[str], set[str]]: """Return (active_families, commented_families) from registry.cpp.""" @@ -40,72 +64,289 @@ def parse_registry_loaders(registry_text: str) -> tuple[set[str], set[str]]: return active, commented -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--registry", - type=Path, - default=REGISTRY_PATH, - help="Path to registry.cpp", - ) - args = parser.parse_args() +def family_is_registered(family: str, active: set[str]) -> bool: + return family in active - if not args.registry.is_file(): - print(f"error: registry not found: {args.registry}", file=sys.stderr) - return 2 - if not MODEL_MANAGER_PATH.is_file(): - print(f"error: model manager not found: {MODEL_MANAGER_PATH}", file=sys.stderr) - return 2 - sys.path.insert(0, str(MODEL_MANAGER_PATH.parent)) - import model_manager as mm # noqa: E402 +def family_is_parked(family: str, commented: set[str]) -> bool: + if family in commented: + return True + for stub, aliases in PARKED_FAMILY_ALIASES.items(): + if stub in commented and family in aliases: + return True + return False + + +def parked_hint(family: str, commented: set[str]) -> str: + if family in commented: + return " (commented out in registry.cpp)" + for stub, aliases in PARKED_FAMILY_ALIASES.items(): + if stub in commented and family in aliases: + return ( + f" (parked registry stub is '{stub}'; catalog family '{family}' " + "must stay UnsupportedSource until one id is registered)" + ) + return "" - active, commented = parse_registry_loaders(args.registry.read_text(encoding="utf-8")) - if not active: - print("error: no active loaders parsed from registry.cpp", file=sys.stderr) - return 2 +def parse_readme_package_table(readme_text: str) -> dict[str, str]: + """Map package id -> status cell from the recommended install table.""" + match = re.search( + r"\| Package id \| Model \| HF ready-to-use repo \|\n\|[^\n]+\n((?:\|.*\n)+)", + readme_text, + ) + if not match: + return {} + rows: dict[str, str] = {} + for line in match.group(1).splitlines(): + cols = [c.strip() for c in line.strip().strip("|").split("|")] + if len(cols) < 3 or not cols[0].startswith("`"): + continue + package_id = cols[0].strip("`") + rows[package_id] = cols[2] + return rows + + +def check_catalog( + *, + active: set[str], + commented: set[str], + packages: list, + package_payload, + default_family_from_package_id, +) -> tuple[list[str], list[str]]: errors: list[str] = [] warnings: list[str] = [] + installable_families: set[str] = set() - for package in mm.CATALOG: - payload = mm.package_payload(package) + for package in packages: + payload = package_payload(package) package_id = str(payload.get("id") or "") family = str(payload.get("family") or "").strip() installable = bool(payload.get("installable")) standalone = bool(payload.get("standalone", True)) source = payload.get("source") if isinstance(payload.get("source"), dict) else {} source_kind = str(source.get("kind") or "") + inferred = default_family_from_package_id(package_id) + explicit = getattr(package, "family", None) if not family: - errors.append(f"{package_id}: missing family (set ModelPackage.family or fix id)") + errors.append( + f"{package_id}: missing family (set ModelPackage.family or fix id)" + ) continue if not installable or source_kind == "unsupported": - # Parked / unavailable packages may keep a family for documentation. - if family in active: + if family_is_registered(family, active): warnings.append( f"{package_id}: UnsupportedSource but family '{family}' is already " "registered — restore a real SnapshotSource/Composite/Converter" ) + elif not family_is_parked(family, commented): + warnings.append( + f"{package_id}: UnsupportedSource family '{family}' is neither " + "registered nor a parked registry stub/alias" + ) continue if not standalone: - # Dependency / subcomponent packages do not need their own loader. continue - if family not in active: - hint = "" - if family in commented: - hint = " (commented out in registry.cpp)" - elif family == "higgs_audio_tts" and "higgs_tts" in commented: - hint = " (registry stub uses higgs_tts; keep family ids consistent)" + installable_families.add(family) + + if explicit is None and inferred != family: + errors.append( + f"{package_id}: resolved family '{family}' != id inference " + f"'{inferred}' without ModelPackage.family set" + ) + + if explicit is None and inferred not in active and family in active: + # Should be unreachable if family comes from inference, but keep tight. + errors.append( + f"{package_id}: set ModelPackage.family explicitly " + f"(id inference '{inferred}' is not a registered loader)" + ) + + if not family_is_registered(family, active): errors.append( f"{package_id}: installable standalone package family '{family}' " - f"is not registered in registry.cpp{hint}" + f"is not registered in registry.cpp{parked_hint(family, commented)}" + ) + elif family_is_parked(family, commented): + # Active and commented with same name should not happen; still guard. + errors.append( + f"{package_id}: family '{family}' is both active and commented in registry.cpp" + ) + + for stub in sorted(commented): + aliases = {stub} | PARKED_FAMILY_ALIASES.get(stub, set()) + leaked = sorted(fam for fam in aliases if fam in installable_families) + if leaked: + errors.append( + f"parked loader '{stub}' still has installable catalog families: " + + ", ".join(leaked) + ) + + for family in sorted(active): + if family in BUNDLED_LOADERS_WITHOUT_PACKAGE: + continue + if family not in installable_families: + warnings.append( + f"registered loader '{family}' has no installable standalone " + "ModelPackage (add a package or list it in " + "BUNDLED_LOADERS_WITHOUT_PACKAGE if intentional)" + ) + + return errors, warnings + + +def check_readme( + *, + readme_text: str, + packages: list, + package_payload, +) -> tuple[list[str], list[str]]: + errors: list[str] = [] + warnings: list[str] = [] + table = parse_readme_package_table(readme_text) + if not table: + errors.append("README.md: could not parse recommended package table") + return errors, warnings + + catalog_by_id = {} + for package in packages: + payload = package_payload(package) + catalog_by_id[str(payload["id"])] = payload + + for package_id, status in sorted(table.items()): + payload = catalog_by_id.get(package_id) + if payload is None: + errors.append(f"README.md: package `{package_id}` not in model_manager CATALOG") + continue + installable = bool(payload.get("installable")) + unavailable = "unavailable" in status.lower() + if unavailable and installable: + errors.append( + f"README.md: `{package_id}` marked Unavailable but catalog is installable" + ) + if not unavailable and not installable: + errors.append( + f"README.md: `{package_id}` looks installable in the table but catalog " + "is UnsupportedSource — mark Unavailable or restore a source" + ) + + for package_id, payload in sorted(catalog_by_id.items()): + if not payload.get("installable") or not payload.get("standalone", True): + continue + if package_id not in table: + errors.append( + f"README.md: installable standalone package `{package_id}` missing " + "from recommended package table" + ) + + return errors, warnings + + +class _SyncCheckSelfTests(unittest.TestCase): + def test_parse_active_and_commented(self) -> None: + text = """ + // make_kokoro_tts_loader(), + make_pocket_tts_loader(), + make_higgs_tts_loader(), // trailing comment still active + """ + active, commented = parse_registry_loaders(text) + self.assertEqual(active, {"pocket_tts", "higgs_tts"}) + self.assertEqual(commented, {"kokoro_tts"}) + + def test_parked_alias_blocks_installable(self) -> None: + class Pkg: + def __init__(self, family=None): + self.family = family + + def payload(package): + return { + "id": "higgs_audio_v3_tts_4b", + "family": "higgs_audio_tts", + "installable": True, + "standalone": True, + "source": {"kind": "huggingface_snapshot"}, + } + + errors, _ = check_catalog( + active={"pocket_tts"}, + commented={"higgs_tts"}, + packages=[Pkg(family="higgs_audio_tts")], + package_payload=payload, + default_family_from_package_id=lambda _pid: "higgs_audio_v3_tts", + ) + self.assertTrue(any("higgs_audio_tts" in e for e in errors)) + self.assertTrue(any("parked loader 'higgs_tts'" in e for e in errors)) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--registry", + type=Path, + default=REGISTRY_PATH, + help="Path to registry.cpp", + ) + parser.add_argument( + "--skip-readme", + action="store_true", + help="Skip README package-table cross-check", + ) + parser.add_argument( + "--self-test", + action="store_true", + help="Run built-in unit tests and exit", + ) + args = parser.parse_args() + + if args.self_test: + suite = unittest.defaultTestLoader.loadTestsFromTestCase(_SyncCheckSelfTests) + result = unittest.TextTestRunner(verbosity=2).run(suite) + return 0 if result.wasSuccessful() else 1 + + if not args.registry.is_file(): + print(f"error: registry not found: {args.registry}", file=sys.stderr) + return 2 + if not MODEL_MANAGER_PATH.is_file(): + print(f"error: model manager not found: {MODEL_MANAGER_PATH}", file=sys.stderr) + return 2 + + sys.path.insert(0, str(MODEL_MANAGER_PATH.parent)) + import model_manager as mm # noqa: E402 + + active, commented = parse_registry_loaders(args.registry.read_text(encoding="utf-8")) + if not active: + print("error: no active loaders parsed from registry.cpp", file=sys.stderr) + return 2 + + errors, warnings = check_catalog( + active=active, + commented=commented, + packages=list(mm.CATALOG), + package_payload=mm.package_payload, + default_family_from_package_id=mm._default_family_from_package_id, + ) + + if not args.skip_readme: + if not README_PATH.is_file(): + errors.append(f"README.md not found: {README_PATH}") + else: + readme_errors, readme_warnings = check_readme( + readme_text=README_PATH.read_text(encoding="utf-8"), + packages=list(mm.CATALOG), + package_payload=mm.package_payload, ) + errors.extend(readme_errors) + warnings.extend(readme_warnings) - print(f"active_loaders={len(active)} catalog_packages={len(mm.CATALOG)}") + print( + f"active_loaders={len(active)} commented_loaders={len(commented)} " + f"catalog_packages={len(mm.CATALOG)}" + ) for warning in warnings: print(f"warning: {warning}") if errors: @@ -113,8 +354,8 @@ def main() -> int: for error in errors: print(f" - {error}", file=sys.stderr) print( - "\nFix: either register the loader in registry.cpp + model_specs/, " - "or mark the package UnsupportedSource. See " + "\nFix: register the loader in registry.cpp (with sources in-tree), " + "or mark the package UnsupportedSource / update README. See " "docs/maintainers/loader_and_catalog.md", file=sys.stderr, ) From ded3d6230eec47f105bff5e5c0161bdaaf44ddef Mon Sep 17 00:00:00 2001 From: lapy Date: Tue, 21 Jul 2026 13:51:16 +0100 Subject: [PATCH 3/3] Keep mismatch examples out of code and docs Leave concrete catalog/loader mismatch cases in the PR description; keep in-repo sync tooling and maintainer docs generic aside from required config maps. --- docs/maintainers/loader_and_catalog.md | 29 ++++---------- tools/check_loader_catalog_sync.py | 52 ++++++++++---------------- tools/model_manager.py | 6 --- 3 files changed, 28 insertions(+), 59 deletions(-) diff --git a/docs/maintainers/loader_and_catalog.md b/docs/maintainers/loader_and_catalog.md index a0d0c5e34..f7e7db0c1 100644 --- a/docs/maintainers/loader_and_catalog.md +++ b/docs/maintainers/loader_and_catalog.md @@ -24,24 +24,10 @@ For every **installable, standalone** `ModelPackage`: Dependency / subcomponent packages (`standalone=False`, with `parent_package_id`) do **not** need their own loader. -Bundled loaders without a downloadable package (today: `silero_vad`) are allowed. -If you add another, list it in `BUNDLED_LOADERS_WITHOUT_PACKAGE` inside +Registered loaders that ship as bundled assets (no downloadable package) are +allowed. List them in `BUNDLED_LOADERS_WITHOUT_PACKAGE` inside `tools/check_loader_catalog_sync.py`. -## Verified parked families (this release tree) - -These registry stubs are **commented out**, and the loader sources are **not -present** under `src/models/` / `include/engine/models/` (or community paths): - -| Registry stub | Catalog package(s) | Notes | -|---|---|---| -| `kokoro_tts` | `kokoro_82m_bf16` | Warm-bench tests remain; no loader sources | -| `higgs_tts` | `higgs_audio_v3_tts_4b` (`family=higgs_audio_tts`) | Name mismatch: pick one id when re-enabling | -| `parakeet_tdt` | `parakeet_tdt_0_6b_v3` | Warm-bench / docs may remain | - -Matching catalog entries must use `UnsupportedSource` until the loader code is -actually merged and registered. - If a loader is not ready for this release tree: 1. Keep it **commented out** in `src/framework/runtime/registry.cpp`, and @@ -51,6 +37,9 @@ If a loader is not ready for this release tree: Do **not** leave a live `SnapshotSource` for a commented-out loader. +Optional catalog↔registry family renames for parked stubs go in +`PARKED_FAMILY_ALIASES` in the sync check (collapse to one id when re-enabling). + ## Checklist: adding a model family 1. Implement `include/engine/models//` (or `community_models/`) with a @@ -62,8 +51,7 @@ Do **not** leave a live `SnapshotSource` for a commented-out loader. 3. Add `model_specs/.json` when the family needs package-spec discovery. 4. Add one or more `ModelPackage` entries in `tools/model_manager.py`: - Set `family=""` explicitly when the package id does not strip cleanly - to the loader id (examples: `kokoro_82m_bf16` → `kokoro_tts`, - `vietneu_tts_v3_turbo` → `vietneu_tts`). + to the loader id. - Set `tasks=(...)` when defaults would be ambiguous. - Use `standalone=False` + `parent_package_id` for tokenizers / subcomponents. 5. Update README supported-model / package tables. @@ -99,9 +87,8 @@ Pick **one** family string and use it everywhere: - `ModelPackage.family` - README “Supported Models” family column -Avoid mismatches such as catalog `higgs_audio_tts` with a registry stub named -`higgs_tts`. Integrators match on the string; aliases are not implied (the sync -check only knows the small parked alias map for currently parked stubs). +Integrators match on the string; aliases are not implied unless listed in +`PARKED_FAMILY_ALIASES` for currently parked stubs. ## CI diff --git a/tools/check_loader_catalog_sync.py b/tools/check_loader_catalog_sync.py index bcae3d467..19069f64e 100644 --- a/tools/check_loader_catalog_sync.py +++ b/tools/check_loader_catalog_sync.py @@ -1,21 +1,9 @@ #!/usr/bin/env python3 """Fail when installable catalog packages reference unregistered loaders. -The machine-readable contract from PR #74 makes package ``family`` and -``audiocpp_cli --list-loaders`` authoritative for integrators. Catalog entries -must not advertise installable packages for families that are commented out or -missing from ``src/framework/runtime/registry.cpp``. - -Verified release-tree facts this check encodes: - -- Parked registry stubs currently include ``kokoro_tts``, ``higgs_tts``, and - ``parakeet_tdt``. Those loader *sources are not in this tree* (no - ``src/models/`` / matching include); only comments + warm-bench tests - remain. Matching catalog packages must be ``UnsupportedSource``. -- ``higgs_audio_tts`` is treated as an alias of the parked ``higgs_tts`` stub - until one family id is chosen when the loader returns. -- ``silero_vad`` is a registered loader without a model_manager package (bundled - asset path). That is allowed; see docs/maintainers/loader_and_catalog.md. +``model_manager list --json`` family fields and ``audiocpp_cli --list-loaders`` +must stay aligned. Installable standalone packages cannot advertise a family +that is missing or commented out in ``src/framework/runtime/registry.cpp``. See docs/maintainers/loader_and_catalog.md. """ @@ -35,8 +23,7 @@ _LOADER_CALL_RE = re.compile(r"\bmake_([a-z0-9_]+)_loader\s*\(\s*\)") -# Catalog family strings that refer to a differently named parked registry stub. -# When re-enabling a loader, collapse these to one id everywhere. +# Optional: catalog family strings that map to a differently named parked stub. PARKED_FAMILY_ALIASES: dict[str, set[str]] = { "higgs_tts": {"higgs_audio_tts"}, } @@ -161,7 +148,6 @@ def check_catalog( ) if explicit is None and inferred not in active and family in active: - # Should be unreachable if family comes from inference, but keep tight. errors.append( f"{package_id}: set ModelPackage.family explicitly " f"(id inference '{inferred}' is not a registered loader)" @@ -173,7 +159,6 @@ def check_catalog( f"is not registered in registry.cpp{parked_hint(family, commented)}" ) elif family_is_parked(family, commented): - # Active and commented with same name should not happen; still guard. errors.append( f"{package_id}: family '{family}' is both active and commented in registry.cpp" ) @@ -250,37 +235,40 @@ def check_readme( class _SyncCheckSelfTests(unittest.TestCase): def test_parse_active_and_commented(self) -> None: text = """ - // make_kokoro_tts_loader(), - make_pocket_tts_loader(), - make_higgs_tts_loader(), // trailing comment still active + // make_family_a_loader(), + make_family_b_loader(), + make_family_c_loader(), // trailing comment still active """ active, commented = parse_registry_loaders(text) - self.assertEqual(active, {"pocket_tts", "higgs_tts"}) - self.assertEqual(commented, {"kokoro_tts"}) + self.assertEqual(active, {"family_b", "family_c"}) + self.assertEqual(commented, {"family_a"}) def test_parked_alias_blocks_installable(self) -> None: class Pkg: def __init__(self, family=None): self.family = family + stub = next(iter(PARKED_FAMILY_ALIASES)) + alias = next(iter(PARKED_FAMILY_ALIASES[stub])) + def payload(package): return { - "id": "higgs_audio_v3_tts_4b", - "family": "higgs_audio_tts", + "id": "pkg_alias", + "family": alias, "installable": True, "standalone": True, "source": {"kind": "huggingface_snapshot"}, } errors, _ = check_catalog( - active={"pocket_tts"}, - commented={"higgs_tts"}, - packages=[Pkg(family="higgs_audio_tts")], + active={"family_b"}, + commented={stub}, + packages=[Pkg(family=alias)], package_payload=payload, - default_family_from_package_id=lambda _pid: "higgs_audio_v3_tts", + default_family_from_package_id=lambda _pid: "pkg_alias", ) - self.assertTrue(any("higgs_audio_tts" in e for e in errors)) - self.assertTrue(any("parked loader 'higgs_tts'" in e for e in errors)) + self.assertTrue(any(alias in e for e in errors)) + self.assertTrue(any(f"parked loader '{stub}'" in e for e in errors)) def main() -> int: diff --git a/tools/model_manager.py b/tools/model_manager.py index 8f899fb1c..9af409492 100644 --- a/tools/model_manager.py +++ b/tools/model_manager.py @@ -220,9 +220,6 @@ def package_usage_examples(package: ModelPackage) -> list[str]: id="kokoro_82m_bf16", display_name="Kokoro 82M bf16", target_directory="Kokoro-82M-bf16", - # Loader is not registered in this release tree (see registry.cpp and - # docs/maintainers/loader_and_catalog.md). Keep the id for docs/history - # but do not advertise an installable HF snapshot. source=UnsupportedSource( reason=( "kokoro_tts loader is not registered in this release tree yet " @@ -849,9 +846,6 @@ def package_usage_examples(package: ModelPackage) -> list[str]: id="higgs_audio_v3_tts_4b", display_name="Higgs Audio v3 TTS 4B", target_directory="higgs-audio-v3-tts-4b", - # Catalog family must match the registered loader family id. The parked - # registry stub currently uses higgs_tts; when re-enabling, pick one - # family string and use it in registry, model_specs, and this field. source=UnsupportedSource( reason=( "higgs_tts / higgs_audio_tts loader is not registered in this "