Adapter Lifecycle Finish (v0.67.0)
Six surfaces that complete what v0.57 soup adapters started. Adapters are now first-class versioned, collaborative, multi-tenant, evolvable, lockfile-tracked, bisect-able artifacts. We are not aware of a hosted vendor offering this set: evolutionary merge is mostly research demo, VeRA-style storage cuts against per-GPU-hour pricing, MoLE routing needs both a training and a serving stack, and adapter PRs need weights, eval and history together.
CMA-ES merge — evolutionary search over LoRA weights
soup adapters merge ./lora_a ./lora_b ./lora_c --strategy cmaes \
--eval ./suite.yaml --budget 1h --output ./mergedSakana-style evolutionary merge. Pure-Python rank-mu CMA-ES (no cma dependency). Softmaxes N-1 logits onto the simplex, samples a population, keeps the elite half, plateau-detects after 3 generations without improvement (converged=True).
- 2..16 adapters; population
[2, 256]; generations[1, 10K] - Budget
[60s, 24h]— reuses v0.57blame.parse_budget - Eval-fn failures swallowed with sentinel -1e9 score (one broken eval ≠ crashed run)
- Live as of v0.71.4 — the full loop merges, materialises, and scores each candidate against the eval suite and writes the best-weighted merge;
--canaryadds an OK/MINOR/MAJOR verdict
VeRA / VB-LoRA vector bank — multi-tenant adapter economics
from soup_cli.utils.vector_bank import VectorBank, write_bank, estimate_bank_size
bank = VectorBank(
name="customer-personalisation",
base_model="meta-llama/Llama-3-8B",
entries={"user_1": (0.31, -0.07, ...), "user_2": (...)},
)
write_bank(bank, "./bank.json")
# 128-D scaling vector at fp32 ≈ 512 bytes / user
# vs. ~30 MB per rank-16 LoRA on Llama-3-8BShared random projection P (d_model × d_model) + per-user scaling vector v_u. Thousands of per-user adapters at MB-each instead of hundreds-of-MB per LoRA. Atomic JSON I/O + cwd containment + symlink rejection + 16 MiB cap.
estimate_bank_size(num_users, vector_dim) for sizing. Live as of v0.71.12 — soup serve --bank <bank.json> [--bank-strength S] reconstructs the projection + per-user vectors and installs a decode-time hook; the active user is chosen per request via the X-User-Id header (unknown/absent id is a zero-delta no-op, so no cross-request leak).
MoLE — per-token gating over task LoRAs
# soup.yaml
task: moe_lora_routing
training:
mole_task_adapters: # the live form: paths to the frozen task LoRAs
- ./adapters/coder
- ./adapters/math
mole_temperature: 1.0 # softmax sharpness
mole_top_k: 2Mixture of LoRA Experts. Gating network routes per-token activations to top-K task adapters via softmax over hidden state. Backend-cross-validator rejects mlx. Live as of v0.71.12 — mole_task_adapters: [...] trains a real per-token gating network that blends N frozen task LoRAs (only the router trains); the gate is saved as mole_gate.pt.
soup adapters pr — GitHub-shaped adapter pull requests
soup adapters pr "Better politeness on EU support tickets" \
--base-sha 9f2e... --adapter ./candidate \
--eval ./eval_delta.json --samples ./sample_diffs.json \
--output ./PR.mdPR = {base SHA, dataset diff, adapter weights, eval-delta report} rendered as review-friendly Markdown with eval-delta table + per-sample baseline/candidate diffs:
| Metric | Baseline | Candidate | Δ |
|---|---|---|---|
| judge_score | 7.4 | 8.2 | +0.8 |
| retry_rate | 12.1% | 4.6% | -7.5% |
_md_table_escape neutralises the backtick, |, \n, \r and \t in operator-controlled cells. JSON output also available for v0.68 GitHub Action. Bounds: ≤64 deltas, ≤256 samples, ≤32 KiB per sample.
soup lock — shared run lockfile
soup lock write --base-model meta-llama/Llama-3-8B \
--base-sha <64hex> --dataset-sha <64hex> --env-hash <64hex> \
--output soup.lock
soup lock show soup.lock
soup lock check --base-model ... --base-sha ... --dataset-sha ... --env-hash ...
# exit 3 on driftClosure of (base_model_sha, dataset_sha, env_hash):
closure_sha = SHA256(base_sha || dataset_sha || env_hash)Commit soup.lock to git so the whole team coordinates on the same reproducible run. soup_version + created_at are advisory only — legitimate operator upgrades don't trigger drift. Composes with v0.64 soup env lock (provides env_hash) and v0.64 soup plan (provides base/dataset hashes from config).
soup adapters bisect — binary search over training history
soup adapters bisect ./ckpt-0500 ./ckpt-1000 ./ckpt-1500 ./ckpt-2000 \
--eval-command "soup eval custom --model {ckpt} --tasks ./regression.jsonl"Binary search over ordered checkpoint history. Operator supplies a shell template with {ckpt} placeholder — Soup uses shlex.split after shlex.quote(ckpt) (argv-list mode, no shell=True). Probes both endpoints first (short-circuits all-OK / all-broken), then ~log₂(n) midpoint probes. Exit 3 on BROKEN_AT.
Composes with v0.66 influence-blame: bisect finds the broken checkpoint, blame attributes it to specific training rows.
Numbers
+165 tests in v0.67.0 (10,836 → 11,021), 7 new test files. CMA-ES eval-wiring went live in v0.71.4, VeRA multi-tenant serve in v0.71.17, and the MoLE gating kernel in v0.71.12.
See also
- Adapter algebra (v0.71.34) — task arithmetic over LoRA deltas, the newest member of this command family.
- Adapters (v0.57) — diff / merge / blame / branch / checkout, the foundation v0.67 builds on.
- Post-train x-rays — v0.66 blame is what
bisecthands off to. - Pre-flight & tooling — v0.64
soup env lock+soup planare the inputs tosoup lock.
Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.