426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
315 lines
8.3 KiB
Python
315 lines
8.3 KiB
Python
"""Tests for `append_voice_model_version.py`.
|
|
|
|
Covers:
|
|
- Validates `--id` against the known voice model set.
|
|
- Asset parsing rejects bad shape / bad sha256 / bad quant.
|
|
- Idempotent re-run (no double-write) when the entry already exists.
|
|
- `--append-changelog` inserts an H3 under the matching H2.
|
|
- `--dry-run` writes nothing to disk.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
from textwrap import dedent
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[3]
|
|
SCRIPT = (
|
|
REPO_ROOT / "packages" / "training" / "scripts" / "append_voice_model_version.py"
|
|
)
|
|
|
|
VOICE_MODELS_TS_TEMPLATE = dedent(
|
|
"""\
|
|
export const VOICE_MODEL_VERSIONS: ReadonlyArray<VoiceModelVersion> = [
|
|
{
|
|
id: "kokoro",
|
|
version: "0.1.0",
|
|
publishedToHfAt: "2026-05-14T00:00:00Z",
|
|
hfRepo: "elizaos/eliza-1-voice-kokoro-same",
|
|
hfRevision: "main",
|
|
ggufAssets: [],
|
|
evalDeltas: { netImprovement: true },
|
|
changelogEntry: "Initial release.",
|
|
minBundleVersion: "0.0.0",
|
|
},
|
|
];
|
|
"""
|
|
)
|
|
|
|
CHANGELOG_MD_TEMPLATE = dedent(
|
|
"""\
|
|
# Eliza voice sub-models — changelog
|
|
|
|
## kokoro
|
|
|
|
### 0.1.0 — 2026-05-14
|
|
|
|
- Initial release.
|
|
"""
|
|
)
|
|
|
|
|
|
def _setup_workspace(tmp_path: Path) -> tuple[Path, Path]:
|
|
ts_path = tmp_path / "voice-models.ts"
|
|
md_path = tmp_path / "CHANGELOG.md"
|
|
ts_path.write_text(VOICE_MODELS_TS_TEMPLATE, encoding="utf-8")
|
|
md_path.write_text(CHANGELOG_MD_TEMPLATE, encoding="utf-8")
|
|
return ts_path, md_path
|
|
|
|
|
|
def _run(*args: str) -> subprocess.CompletedProcess[str]:
|
|
return subprocess.run(
|
|
[sys.executable, str(SCRIPT), *args],
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
env={**os.environ, "PYTHONDONTWRITEBYTECODE": "1"},
|
|
)
|
|
|
|
|
|
def test_unknown_id_rejected(tmp_path: Path) -> None:
|
|
ts_path, _ = _setup_workspace(tmp_path)
|
|
res = _run(
|
|
"--id",
|
|
"not-a-real-id",
|
|
"--version",
|
|
"0.2.0",
|
|
"--hf-repo",
|
|
"elizaos/foo",
|
|
"--hf-revision",
|
|
"main",
|
|
"--min-bundle",
|
|
"0.0.0",
|
|
"--changelog-entry",
|
|
"hi",
|
|
"--voice-models-ts",
|
|
str(ts_path),
|
|
)
|
|
assert res.returncode != 0
|
|
assert "invalid choice" in res.stderr or "not-a-real-id" in res.stderr
|
|
|
|
|
|
def test_invalid_semver_rejected(tmp_path: Path) -> None:
|
|
ts_path, _ = _setup_workspace(tmp_path)
|
|
res = _run(
|
|
"--id",
|
|
"kokoro",
|
|
"--version",
|
|
"bogus",
|
|
"--hf-repo",
|
|
"elizaos/eliza-1-voice-kokoro-same",
|
|
"--hf-revision",
|
|
"main",
|
|
"--min-bundle",
|
|
"0.0.0",
|
|
"--changelog-entry",
|
|
"hi",
|
|
"--voice-models-ts",
|
|
str(ts_path),
|
|
)
|
|
assert res.returncode == 2
|
|
|
|
|
|
def test_bad_asset_rejected(tmp_path: Path) -> None:
|
|
ts_path, _ = _setup_workspace(tmp_path)
|
|
res = _run(
|
|
"--id",
|
|
"kokoro",
|
|
"--version",
|
|
"0.2.0",
|
|
"--hf-repo",
|
|
"elizaos/eliza-1-voice-kokoro-same",
|
|
"--hf-revision",
|
|
"main",
|
|
"--asset",
|
|
"kokoro.onnx:not-a-sha:1024:onnx-fp16",
|
|
"--min-bundle",
|
|
"0.0.0",
|
|
"--changelog-entry",
|
|
"hi",
|
|
"--voice-models-ts",
|
|
str(ts_path),
|
|
)
|
|
assert res.returncode != 0
|
|
|
|
|
|
def test_writes_new_version_block(tmp_path: Path) -> None:
|
|
ts_path, _ = _setup_workspace(tmp_path)
|
|
res = _run(
|
|
"--id",
|
|
"kokoro",
|
|
"--version",
|
|
"0.2.0",
|
|
"--parent-version",
|
|
"0.1.0",
|
|
"--hf-repo",
|
|
"elizaos/eliza-1-voice-kokoro-same",
|
|
"--hf-revision",
|
|
"abc123def456abc123def456abc123def456abcd",
|
|
"--asset",
|
|
"kokoro.onnx:" + "a" * 64 + ":2048:onnx-fp16",
|
|
"--min-bundle",
|
|
"0.1.0",
|
|
"--net-improvement",
|
|
"true",
|
|
"--rtf-delta",
|
|
"-0.05",
|
|
"--mos-delta",
|
|
"0.12",
|
|
"--changelog-entry",
|
|
"sam clone v2 (lower RTF, higher MOS).",
|
|
"--voice-models-ts",
|
|
str(ts_path),
|
|
)
|
|
assert res.returncode == 0, res.stderr
|
|
contents = ts_path.read_text(encoding="utf-8")
|
|
assert 'id: "kokoro"' in contents
|
|
assert 'version: "0.2.0"' in contents
|
|
assert 'parentVersion: "0.1.0"' in contents
|
|
assert "sha256: " + json.dumps("a" * 64) in contents
|
|
assert "quant: " + json.dumps("onnx-fp16") in contents
|
|
# The new entry must appear before the existing 0.1.0 entry (reverse-chrono).
|
|
idx_new = contents.find('version: "0.2.0"')
|
|
idx_old = contents.find('version: "0.1.0"')
|
|
assert idx_new < idx_old
|
|
assert "rtfDelta: -0.05" in contents
|
|
assert "mosDelta: 0.12" in contents
|
|
assert "netImprovement: true" in contents
|
|
|
|
|
|
def test_idempotent_rerun(tmp_path: Path) -> None:
|
|
ts_path, _ = _setup_workspace(tmp_path)
|
|
common = [
|
|
"--id",
|
|
"kokoro",
|
|
"--version",
|
|
"0.2.0",
|
|
"--parent-version",
|
|
"0.1.0",
|
|
"--hf-repo",
|
|
"elizaos/eliza-1-voice-kokoro-same",
|
|
"--hf-revision",
|
|
"main",
|
|
"--asset",
|
|
"kokoro.onnx:" + "a" * 64 + ":2048:onnx-fp16",
|
|
"--min-bundle",
|
|
"0.1.0",
|
|
"--net-improvement",
|
|
"true",
|
|
"--changelog-entry",
|
|
"sam v2.",
|
|
"--voice-models-ts",
|
|
str(ts_path),
|
|
]
|
|
res1 = _run(*common)
|
|
assert res1.returncode == 0, res1.stderr
|
|
contents1 = ts_path.read_text(encoding="utf-8")
|
|
res2 = _run(*common)
|
|
assert res2.returncode == 0, res2.stderr
|
|
contents2 = ts_path.read_text(encoding="utf-8")
|
|
# Second run leaves the file unchanged.
|
|
assert contents1 == contents2
|
|
# The version literal appears exactly once.
|
|
assert contents2.count('version: "0.2.0"') == 1
|
|
|
|
|
|
def test_append_changelog_inserts_h3(tmp_path: Path) -> None:
|
|
ts_path, md_path = _setup_workspace(tmp_path)
|
|
res = _run(
|
|
"--id",
|
|
"kokoro",
|
|
"--version",
|
|
"0.2.0",
|
|
"--parent-version",
|
|
"0.1.0",
|
|
"--hf-repo",
|
|
"elizaos/eliza-1-voice-kokoro-same",
|
|
"--hf-revision",
|
|
"abc",
|
|
"--asset",
|
|
"kokoro.onnx:" + "b" * 64 + ":1024:onnx-fp16",
|
|
"--min-bundle",
|
|
"0.1.0",
|
|
"--net-improvement",
|
|
"true",
|
|
"--changelog-entry",
|
|
"sam v2 with lower RTF.",
|
|
"--voice-models-ts",
|
|
str(ts_path),
|
|
"--changelog-md",
|
|
str(md_path),
|
|
"--append-changelog",
|
|
)
|
|
assert res.returncode == 0, res.stderr
|
|
md_contents = md_path.read_text(encoding="utf-8")
|
|
assert "### 0.2.0 — " in md_contents
|
|
assert "sam v2 with lower RTF." in md_contents
|
|
# H2 ordering preserved.
|
|
assert md_contents.index("## kokoro") < md_contents.index("### 0.2.0")
|
|
# Reverse chrono: new H3 above the old one.
|
|
assert md_contents.index("### 0.2.0") < md_contents.index("### 0.1.0")
|
|
|
|
|
|
def test_dry_run_writes_nothing(tmp_path: Path) -> None:
|
|
ts_path, md_path = _setup_workspace(tmp_path)
|
|
ts_before = ts_path.read_text(encoding="utf-8")
|
|
md_before = md_path.read_text(encoding="utf-8")
|
|
res = _run(
|
|
"--id",
|
|
"kokoro",
|
|
"--version",
|
|
"0.2.0",
|
|
"--parent-version",
|
|
"0.1.0",
|
|
"--hf-repo",
|
|
"elizaos/eliza-1-voice-kokoro-same",
|
|
"--hf-revision",
|
|
"main",
|
|
"--asset",
|
|
"kokoro.onnx:" + "c" * 64 + ":1024:onnx-fp16",
|
|
"--min-bundle",
|
|
"0.1.0",
|
|
"--net-improvement",
|
|
"true",
|
|
"--changelog-entry",
|
|
"sam v2.",
|
|
"--voice-models-ts",
|
|
str(ts_path),
|
|
"--changelog-md",
|
|
str(md_path),
|
|
"--append-changelog",
|
|
"--dry-run",
|
|
)
|
|
assert res.returncode == 0, res.stderr
|
|
assert ts_path.read_text(encoding="utf-8") == ts_before
|
|
assert md_path.read_text(encoding="utf-8") == md_before
|
|
|
|
|
|
def test_successor_requires_net_improvement(tmp_path: Path) -> None:
|
|
ts_path, _ = _setup_workspace(tmp_path)
|
|
res = _run(
|
|
"--id",
|
|
"kokoro",
|
|
"--version",
|
|
"0.2.0",
|
|
"--parent-version",
|
|
"0.1.0",
|
|
"--hf-repo",
|
|
"elizaos/eliza-1-voice-kokoro-same",
|
|
"--hf-revision",
|
|
"main",
|
|
"--min-bundle",
|
|
"0.1.0",
|
|
"--changelog-entry",
|
|
"sam v2.",
|
|
"--voice-models-ts",
|
|
str(ts_path),
|
|
)
|
|
assert res.returncode == 2
|
|
assert "--net-improvement is required" in res.stderr
|