- Replace non-ASCII symbols (checkmarks, arrows, bullets, em-dashes)
with ASCII equivalents in Rich console output to prevent
UnicodeEncodeError on Windows without PYTHONIOENCODING=utf-8
- Add _validate_output_path() for AWQ/GPTQ export — output path
traversal is now checked before import check (previously unreachable
when autoawq/auto-gptq not installed)
- 4 new tests for output path validation (2065 total, 0 failures)
- Update SECURITY.md with v0.22.0–v0.24.1 hardening history
- Update test counts to 74 files / 2061 tests (was 62 / 1789)
- Add complete test file table matching CLAUDE.md
- Sync PR checklist with .github/pull_request_template.md
- Add Good First Issues section and New Recipe guide
- Add Conventional Commits format for commit messages
- Add CODEOWNERS for auto-reviewer assignment
Part A: HuggingFace Dataset browser
- soup data search: search HF Hub for datasets (sort by downloads/likes)
- soup data preview: preview remote dataset metadata, splits, features
- soup data download: stream HF dataset to local JSONL (with format conversion)
- Security: trust_remote_code=False, path traversal protection, samples cap at 1M
Part B: Freeze training (like LLaMA-Factory finetuning_type: freeze)
- freeze_layers / freeze_ratio config fields
- soup_cli/utils/freeze.py: detect layers, freeze bottom N
- Wired into SFT trainer before LoRA application
- Supports LLaMA (layers.N) and GPT-2 (h.N) naming
Part C: Loss watchdog (like Axolotl loss_watchdog_threshold)
- loss_watchdog, loss_watchdog_threshold, loss_watchdog_patience config
- Implemented in SoupTrainerCallback with patience counter
- Rich warning panel (stops Live display first), fires only once
- Wired into all 11 trainers via callback kwargs
Part D: Dataset info registry
- soup data register/unregister/registry commands
- ~/.soup/datasets.json local name→path+format mapping
- Name validation, path traversal protection, Rich markup escaping
82 new tests (2061 total), 74 test files.
Rich/Typer truncates help panel on narrow terminals (macOS CI), causing
--bits and --group-size flags to not appear in rendered help text. Switch
to inspecting the function signature directly for cross-platform reliability.
- AWQ export (`soup export --format awq`) via autoawq, with --bits, --group-size, --calibration-data
- GPTQ export (`soup export --format gptq`) via auto-gptq, with calibration data support
- Sample packing (`packing: true`) for SFT/Pretrain trainers via TRL's native packing
- `soup data split` — train/val/test splitting with random and stratified strategies
- Curriculum learning (`curriculum: true`) — sort dataset by difficulty for staged training
- New utility: soup_cli/utils/curriculum.py (sort_by_length, create_buckets)
- Security: calibration data path traversal protection, bits validation (4/8 only)
- 1970 tests across 70 test files
The v0.22.0 release broke CI on Python 3.9 because serve.py used
PEP 604 union syntax (str | None) at module level, which requires 3.10+.
Fixed in previous commit; this bumps version to v0.22.1 for a clean PyPI release.
The `str | None` union syntax at module level requires Python 3.10+.
serve.py cannot use `from __future__ import annotations` because it
defines Pydantic models inside functions (FastAPI needs runtime types).
- fix: replace Unicode ⚠ (U+26A0) with ASCII [yellow]![/] in migrate
warnings to prevent UnicodeEncodeError on Windows cp1251/cp866
- fix: load_config() now accepts str in addition to Path
- fix: recipe count in docs corrected from 30 to 29
- chore: bump version to v0.21.1
Bugfix release: ANSI-safe CI test assertions (macOS fix), path
confinement hardening, circular import fix, rate limiting implementation,
trust_remote_code warning, new terracotta logo + Web UI color scheme.
Replace purple/cyan cyberpunk theme with warm terracotta palette matching
new SVG logo. Update README to use soup_logo_svg.svg. Update chart colors
in app.js to match new palette (#C0512D primary, #E8975A warm accent).
- Implement sleep-based rate limiting using --requests-per-minute flag
(was declared but never enforced).
- Add Rich warning panel before loading local models with
trust_remote_code=True, matching SGLang/audio precedent.
- Replace silent ValueError pass in dedup pipeline with debug logging.
- Extract _parse_json_array into soup_cli/data/providers/_utils.py to
avoid circular imports between generate.py and provider modules.
- Narrow bare except Exception in detect_ollama to httpx.HTTPError/OSError
with debug logging instead of silent swallow.
Replace simple '..' check with resolve() + relative_to(cwd) for output
path. Add same confinement guard to --seed, --dedup-with, and --context
file paths. Add _path_within_cwd helper. 4 new security tests.
Rich markup wraps --model-a with ANSI codes on macOS, breaking the
substring check. Strip ANSI codes before asserting, matching the
existing pattern in test_speculative_decoding.py and test_deploy_ollama.py.
Rich markup in Typer help output inserts ANSI escape codes around
--flag names on macOS, breaking exact string matches. Check for
lowercase words instead of --prefixed flags.
Show GitHub URL in `soup version`, `soup version --full`, `soup doctor`,
and `soup --help` so users can find and star the repo.
Extract URL to GITHUB_URL constant in utils/constants.py.
- Use AutoModel instead of AutoModelForCausalLM for audio-language models
(Qwen2-Audio, Whisper don't work with causal LM auto class)
- Use Path.is_relative_to() for path traversal check (symlink-safe, Python 3.9+)
- Fail fast with helpful error if librosa not installed before dataset processing
- Use -100 ignore_index for pad tokens in perplexity computation (avoids
redundant softmax on padding positions)
- Block URL-based model paths in SGLang create_sglang_runtime (SSRF protection)
Rich inserts color codes between flag name parts (e.g. --speculative
becomes \x1b[1;36m-\x1b[0m\x1b[1;36m-speculative\x1b[0m), so plain
substring match fails in CI. Strip ANSI before asserting.
- Rename --spec-tokens to --num-speculative-tokens to avoid prefix
collision with --speculative-decoding in Typer help rendering
- Add pytest.skip for _create_app tests when fastapi is not installed