diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d49cf66e..b347441d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -181,9 +181,10 @@ jobs: run: bash scripts/test/e2e.sh ./build/wally linux: - # Match the oldest supported Linux release baseline. Building on 24.04 - # silently introduced GLIBC_2.38 / GLIBCXX_3.4.31+ requirements. - runs-on: ubuntu-22.04 + # Kit 0.20.39's Sherpa prebuilt needs glibc 2.38 and GLIBCXX_3.4.32, so + # this job builds and runs on that floor. wally's own code picks up the + # same glibc; versions.toml [linux_abi] is that floor. + runs-on: ubuntu-24.04 timeout-minutes: 60 steps: - uses: actions/checkout@v4 @@ -192,7 +193,8 @@ jobs: - name: Install build deps run: | sudo apt-get update - sudo apt-get install -y ninja-build cmake libcurl4-openssl-dev patchelf + sudo apt-get install -y ninja-build cmake libcurl4-openssl-dev patchelf \ + libzstd-dev libbrotli-dev libbz2-dev - uses: hendrikmuhs/ccache-action@f09c25b45002a07be2955cbe52e8cee55643f89d with: key: ccache-ci-linux-x64 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8bda2643..b0d18099 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -265,9 +265,8 @@ jobs: linux: needs: [validate-dispatch] - # Release compatibility floor. Ubuntu 24.04 produced a bottle requiring - # GLIBC_2.38 and GLIBCXX_3.4.31/32, which fails on Ubuntu 22.04. - runs-on: ubuntu-22.04 + # Kit 0.20.39's Sherpa prebuilt needs glibc 2.38 and GLIBCXX_3.4.32. + runs-on: ubuntu-24.04 timeout-minutes: 60 steps: - uses: actions/checkout@v4 @@ -276,7 +275,8 @@ jobs: - name: Install build deps run: | sudo apt-get update - sudo apt-get install -y ninja-build cmake libcurl4-openssl-dev patchelf + sudo apt-get install -y ninja-build cmake libcurl4-openssl-dev patchelf \ + libzstd-dev libbrotli-dev libbz2-dev - uses: hendrikmuhs/ccache-action@f09c25b45002a07be2955cbe52e8cee55643f89d with: key: ccache-release-linux-x64 diff --git a/Cargo.lock b/Cargo.lock index 9aa69cb8..2e37694b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1410,7 +1410,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wally" -version = "0.8.3" +version = "0.8.5" dependencies = [ "brotli-decompressor", "ctrlc", diff --git a/Cargo.toml b/Cargo.toml index b1d59797..17f125f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ [package] name = "wally" # Must equal [product] version in versions.toml (scripts/ci/check-versions.py). -version = "0.8.3" +version = "0.8.5" edition = "2021" rust-version = "1.93" license = "Apache-2.0" diff --git a/Formula/wally.rb b/Formula/wally.rb index 31973bb6..c229f418 100644 --- a/Formula/wally.rb +++ b/Formula/wally.rb @@ -3,15 +3,15 @@ class Wally < Formula desc "Run language, speech and image models on your own machine" homepage "https://github.com/RunanywhereAI/wally" - version "0.8.3" + version "0.8.5" license "MIT" # macOS arm64 ships the Swift MLX host # (llama.cpp + ONNX + Sherpa + MLX). Linux is not in this cut. on_macos do on_arm do - url "https://github.com/RunanywhereAI/wally/releases/download/v0.8.3/wally-0.8.3-macos-arm64.tar.gz" - # Placeholder -- the v0.8.3 release has not published a wally-named asset + url "https://github.com/RunanywhereAI/wally/releases/download/v0.8.5/wally-0.8.5-macos-arm64.tar.gz" + # Placeholder -- the v0.8.5 release has not published a wally-named asset # yet. scripts/release/update-tap.sh re-stamps this from the real release # checksum; a stale value here fails brew install's own hash check # rather than installing something unverified. diff --git a/README.md b/README.md index 3b31c4dd..d3bec51d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ ## Install On macOS with Apple Silicon (Intel Macs are not supported) and on Linux with -x86-64 or ARM64 and glibc 2.35 or newer (Ubuntu 22.04+, Debian 12+): +x86-64 or ARM64 and glibc 2.39 or newer (Ubuntu 24.04+, Debian 13+): ```bash curl -fsSL https://raw.githubusercontent.com/RunanywhereAI/wally/main/install.sh | sh diff --git a/build.rs b/build.rs index cf40636b..acd86873 100644 --- a/build.rs +++ b/build.rs @@ -294,32 +294,21 @@ fn link_native(build_env: &BTreeMap) { Ok("macos") | Ok("ios") => println!("cargo:rustc-link-arg=-lc++"), Ok("linux") => { println!("cargo:rustc-link-arg=-lstdc++"); - // aarch64 only. Two unrelated needs, both because cargo drives the - // link with the C compiler and consumes -lc before the kit's static - // C++ archives: - // - those archives reference __stack_chk_guard (libc) and the - // compiler's outline-atomics helpers (libgcc); name both again - // after them. x86-64 reaches the stack guard through TLS and - // emits no outline atomics. - // - the aarch64 kit was built against zstd/brotli (its cpp-httplib - // server) and bz2 (libarchive), which x86-64 kits reference - // from none of their objects. Name them so the kit's symbols - // resolve; package-wally.sh bundles the runtime .so. They sit - // under the link's --as-needed, so a later kit built without - // these backends drops them with no DT_NEEDED. + // Kit 0.20.39's libarchive references bz2, and its Sherpa prebuilt + // references glibc 2.38 / GLIBCXX_3.4.32. Name the compression + // libraries; package-wally.sh bundles whichever the binary actually + // needs. --allow-shlib-undefined keeps a link on an older host from + // dying on Sherpa's versioned symbols. The bottle still only starts + // where those symbols exist (Ubuntu 24.04). + println!("cargo:rustc-link-arg=-Wl,--allow-shlib-undefined"); + for lib in ["brotlienc", "brotlidec", "zstd", "bz2"] { + println!("cargo:rustc-link-arg=-l{lib}"); + } + // aarch64 static archives reference __stack_chk_guard and the + // compiler's outline-atomics helpers. Name libc and libgcc again + // after the kit archives. x86-64 reaches the stack guard through + // TLS and emits no outline atomics. if env::var("CARGO_CFG_TARGET_ARCH").as_deref() == Ok("aarch64") { - // The kit's arm64 Sherpa prebuilt is built against glibc 2.38 and - // GCC 13's libstdc++ (GLIBCXX_3.4.32), higher than the 22.04 build - // floor. Those symbols are present at runtime on every system the - // bottle supports (check-linux-abi.py [linux_abi_arm64] and - // install.sh both hold the 2.38 floor), so let the shared library - // carry its own undefined references instead of failing the link - // on a build host whose libc is older. This keeps wally's own code - // on the low floor; only the Sherpa .so asks for 2.38. - println!("cargo:rustc-link-arg=-Wl,--allow-shlib-undefined"); - for lib in ["brotlienc", "brotlidec", "zstd", "bz2"] { - println!("cargo:rustc-link-arg=-l{lib}"); - } println!("cargo:rustc-link-arg=-lgcc"); println!("cargo:rustc-link-arg=-lc"); } diff --git a/docs/ENGINES.md b/docs/ENGINES.md index 2e22fbaa..54e6eee9 100644 --- a/docs/ENGINES.md +++ b/docs/ENGINES.md @@ -59,9 +59,9 @@ QHexRT on device also needs QAIRT matching the Hexagon skel (`QNN_SDK_ROOT` + `A **Windows x64** (public zip): GGUF / ONNX / Sherpa. No MLX, no NeuRT, no QHexRT. -**Linux x86-64** (public tarball): llama.cpp + Sherpa + ONNX, same as Windows x64. Needs glibc 2.35 or newer. +**Linux x86-64** (public tarball): llama.cpp + Sherpa + ONNX, same as Windows x64. Needs glibc 2.39 or newer. -**Linux ARM64** (public tarball): llama.cpp + Sherpa + ONNX, same as Linux x86-64. Needs glibc 2.35 or newer. +**Linux ARM64** (public tarball): llama.cpp + Sherpa + ONNX, same as Linux x86-64. Needs glibc 2.39 or newer. **Windows ARM64** (Snapdragon): public kit has no llama.cpp/ONNX/Sherpa. The QHexRT overlay runs Hexagon NPU models from a local `*_HNPU` tree. Do not expect `mlx-*`, GGUF, or `sd15` on that binary. diff --git a/install.sh b/install.sh index e1cca9b1..565fe50b 100755 --- a/install.sh +++ b/install.sh @@ -29,17 +29,17 @@ BIN_DIR="${HOME}/.local/bin" # from the system rather than shipping. Both mirror versions.toml [linux_abi] # (glibc_max, system_libraries); scripts/ci/check-versions.py fails when they # drift. libc's own family is left out: glibc is checked by version above. -MIN_GLIBC="2.35" +MIN_GLIBC="2.39" # The arm64 bottle has its own floor entry so the two arches can diverge again # (mirrors versions.toml [linux_abi_arm64]; check-versions.py holds it). The # arm64 case below swaps these in before check_linux_system runs. The # system-library list is the same on both arches (the loader differs, but that # is checked by the glibc version, not looked up here). -MIN_GLIBC_ARM64="2.35" -MIN_GLIBCXX_ARM64="3.4.30" +MIN_GLIBC_ARM64="2.39" +MIN_GLIBCXX_ARM64="3.4.32" # What the refusals name as a system that qualifies. -DISTRO_HINT="Ubuntu 22.04+, Debian 12+ and other distributions from 2022 on" -MIN_GCC="12" +DISTRO_HINT="Ubuntu 24.04+, Debian 13+ and other distributions from 2024 on" +MIN_GCC="13" LINUX_SYSTEM_LIBRARIES="libstdc++.so.6 libgcc_s.so.1 libssl.so.3 libcrypto.so.3 libcurl.so.4" # The highest GLIBCXX_/CXXABI_ symbol version the bottle's own ELF files ask @@ -52,7 +52,7 @@ LINUX_SYSTEM_LIBRARIES="libstdc++.so.6 libgcc_s.so.1 libssl.so.3 libcrypto.so.3 # catches a glibc-2.35 host whose libstdc++ is otherwise too old: v0.6.0's # bottle needed GLIBCXX_3.4.32, which a stock 22.04 libstdc++ (3.4.30) does not # have, and the installer downloaded before finding that out. -MIN_GLIBCXX="3.4.30" +MIN_GLIBCXX="3.4.32" MIN_CXXABI="1.3.13" # Retries cover a dropped connection or a 5xx from the CDN, which a first-time @@ -107,7 +107,7 @@ check_linux_system() { [ -e "$loader" ] && musl=1 done if [ "$musl" -eq 1 ] && ! getconf GNU_LIBC_VERSION >/dev/null 2>&1; then - fail "Wally's Linux build needs glibc, and this system uses musl (Alpine and similar). Use a glibc distribution such as Ubuntu 22.04+ or Debian 12+." + fail "Wally's Linux build needs glibc, and this system uses musl (Alpine and similar). Use a glibc distribution such as Ubuntu 24.04+ or Debian 13+." fi glibc="$(getconf GNU_LIBC_VERSION 2>/dev/null | awk '{ print $2 }')" if [ -z "$glibc" ]; then diff --git a/scripts/build/package-wally.sh b/scripts/build/package-wally.sh index b08bafcb..d7fca354 100755 --- a/scripts/build/package-wally.sh +++ b/scripts/build/package-wally.sh @@ -126,9 +126,8 @@ if [[ -n "${KIT}" && -d "${KIT}/third_party" ]]; then mkdir -p "${STAGE}/licenses" cp "${gomp_licence}" "${STAGE}/licenses/libgomp1.copyright" fi - # The aarch64 kit is built against zstd + brotli (its cpp-httplib server) - # and bz2 (libarchive); an x86_64 kit references none, so this bundles - # only where they are real. Keyed on ldd, not readelf, so libbrotlicommon + # The kit is built against zstd + brotli (its cpp-httplib server) and bz2 + # (libarchive). Keyed on ldd, not readelf, so libbrotlicommon # -- pulled in behind libbrotli{enc,dec} rather than by wally directly -- # is shipped too. All three licences are permissive and travel with the # library under the same $ORIGIN runpath as libgomp above. diff --git a/scripts/test/linux-install-matrix.sh b/scripts/test/linux-install-matrix.sh index 87de2a9e..b362a067 100644 --- a/scripts/test/linux-install-matrix.sh +++ b/scripts/test/linux-install-matrix.sh @@ -28,10 +28,11 @@ ARCHIVE="wally-${VERSION}-linux-x86_64.tar.gz" # image | expectation | text the output must contain CASES=( - "ubuntu:22.04|installs|wally ${VERSION}" "ubuntu:24.04|installs|wally ${VERSION}" - "debian:12|installs|wally ${VERSION}" - "ubuntu:20.04|refused|needs glibc 2.35 or newer" + "debian:13|installs|wally ${VERSION}" + "ubuntu:22.04|refused|needs glibc 2.39 or newer" + "debian:12|refused|needs glibc 2.39 or newer" + "ubuntu:20.04|refused|needs glibc 2.39 or newer" "alpine:3.20|refused|uses musl" ) diff --git a/scripts/test/test-install-libstdcxx-preflight.sh b/scripts/test/test-install-libstdcxx-preflight.sh index 8493d44e..31742b01 100755 --- a/scripts/test/test-install-libstdcxx-preflight.sh +++ b/scripts/test/test-install-libstdcxx-preflight.sh @@ -40,7 +40,7 @@ chmod +x "$STUB/uname" cat > "$STUB/getconf" <<'GETCONF' #!/bin/sh -[ "$1" = "GNU_LIBC_VERSION" ] && echo "glibc 2.35" +[ "$1" = "GNU_LIBC_VERSION" ] && echo "glibc 2.39" GETCONF chmod +x "$STUB/getconf" @@ -132,13 +132,13 @@ old_code="$(printf '%s\n' "$result_old" | head -1)" old_body="$(printf '%s\n' "$result_old" | tail -n +2)" check "an old libstdc++ is refused (exit 1)" "$([ "$old_code" = "1" ] && echo 1 || echo 0)" check "the refusal names the required GLIBCXX floor" \ - "$(printf '%s' "$old_body" | grep -qF 'GLIBCXX_3.4.30' && echo 1 || echo 0)" + "$(printf '%s' "$old_body" | grep -qF 'GLIBCXX_3.4.32' && echo 1 || echo 0)" check "nothing was downloaded before the refusal" \ "$(printf '%s' "$old_body" | grep -qF Downloading && echo 0 || echo 1)" # --- a libstdc++ at or above the floor is accepted and the install proceeds -- new="$WORK/new-libstdcxx.txt" -printf 'GLIBCXX_3.4.30\nCXXABI_1.3.13\nGLIBCXX_3.4.31\n' >"$new" +printf 'GLIBCXX_3.4.32\nCXXABI_1.3.13\n' >"$new" home_new="$WORK/home-new"; mkdir -p "$home_new" result_new="$(run "$home_new" "$new")" new_code="$(printf '%s\n' "$result_new" | head -1)" @@ -167,7 +167,7 @@ bg_code="$(printf '%s\n' "$result_bg" | head -1)" bg_body="$(printf '%s\n' "$result_bg" | tail -n +2)" check "a bottle library needing a newer glibc is refused (exit 1)" "$([ "$bg_code" = "1" ] && echo 1 || echo 0)" check "the refusal names the file and both glibc versions" \ - "$(printf '%s' "$bg_body" | grep -qF 'lib/libbundled.so.1 needs glibc 2.99; this system has 2.35' && echo 1 || echo 0)" + "$(printf '%s' "$bg_body" | grep -qF 'lib/libbundled.so.1 needs glibc 2.99; this system has 2.39' && echo 1 || echo 0)" check "nothing was installed after that refusal" \ "$([ ! -e "$home_bg/.local/lib/wally" ] && [ ! -e "$home_bg/.local/bin/wally" ] && echo 1 || echo 0)" diff --git a/src/catalog/catalog.rs b/src/catalog/catalog.rs index fa74e888..cbd29db6 100644 --- a/src/catalog/catalog.rs +++ b/src/catalog/catalog.rs @@ -2762,6 +2762,144 @@ const CLEF_MLX_4BIT_FILES: &[CatalogFile] = &[ }, ]; +const D1_3B_GGUF_FILES: &[CatalogFile] = &[CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/gguf/d1-3B-Q4_K_M.gguf", + filename: "d1-3B-Q4_K_M.gguf", + required: true, + size_bytes: 1674456672, + checksum_sha256: Some("16aff27ea2eefdc32b9897f43854a5d3170c1dc8dccb9c756905af30a4e22402"), +}]; + +const D1_OMNI_GGUF_FILES: &[CatalogFile] = &[CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/gguf/d1-omni-600M-Q8_0.gguf", + filename: "d1-omni-600M-Q8_0.gguf", + required: true, + size_bytes: 407207584, + checksum_sha256: Some("cd94463f4cac9c700ec6750df8df005bb6846de410e159d1f5e985e1171693d3"), +}]; + +const GLINER_DECIDE_GGUF_FILES: &[CatalogFile] = &[CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/gguf/gliner2.5-decide-q4_k_m.gguf", + filename: "gliner2.5-decide-q4_k_m.gguf", + required: true, + size_bytes: 299547616, + checksum_sha256: Some("44b496627d85c19e407ffb188866456ef6c8b73ca1efd36b31981c28a96346b5"), +}]; + +const D1_3B_MLX_FILES: &[CatalogFile] = &[ + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-3b-8bit/config.json", + filename: "config.json", + required: true, + size_bytes: 3445, + checksum_sha256: Some("d7e4d856b45cad2191ac9bac4266e55f7b5ea878fcb5e69a6ceac3f54b689ab9"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-3b-8bit/model.safetensors", + filename: "model.safetensors", + required: true, + size_bytes: 3718720809, + checksum_sha256: Some("c003549c43780cdcdef9fe3af8647ddde573e7eeea816315f7718179f109cce8"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-3b-8bit/tokenizer.json", + filename: "tokenizer.json", + required: true, + size_bytes: 17905750, + checksum_sha256: Some("8096ecb9f54599d756c8de728a598a340bc1e43c0deb77ddd62456c38349fcee"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-3b-8bit/tokenizer_config.json", + filename: "tokenizer_config.json", + required: true, + size_bytes: 506, + checksum_sha256: Some("880b960c1ea99a84bc16cb759e2e343ea8126f8e86ecb3bcb0a837b2aebb8c1d"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-3b-8bit/processor_config.json", + filename: "processor_config.json", + required: true, + size_bytes: 720, + checksum_sha256: Some("7c68d308c96ca6111414d641e6fe9b94505167a1d00714f18f43fd7f8ae91414"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-3b-8bit/chat_template.jinja", + filename: "chat_template.jinja", + required: false, + size_bytes: 5436, + checksum_sha256: Some("86f4770449a4797c9b4212d110b0cc70fb993c1ce960095bcfb12eea22f61cca"), + }, +]; + +const D1_OMNI_MLX_FILES: &[CatalogFile] = &[ + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-omni-600m/config.json", + filename: "config.json", + required: true, + size_bytes: 1922, + checksum_sha256: Some("0b985b0c881d2297b25fab09bc805617d0b3a82ed699045da3e1634c3ea06a0a"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-omni-600m/model.safetensors", + filename: "model.safetensors", + required: true, + size_bytes: 1174449298, + checksum_sha256: Some("22fcd4a2b582ccba956ae78a47ffc69ee65df7602e74101a73e83e3569438e7a"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-omni-600m/tokenizer.json", + filename: "tokenizer.json", + required: true, + size_bytes: 4733371, + checksum_sha256: Some("1efc3a6609abf6b63b1f47188d139f3b59973a6a434dffe970a7261a51ed2711"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/lfm-d1-omni-600m/tokenizer_config.json", + filename: "tokenizer_config.json", + required: true, + size_bytes: 259, + checksum_sha256: Some("03efc74b752b899b6292ff7e607738be59e6f206fec9aca32bbc05e9184090fc"), + }, +]; + +const GLINER_DECIDE_MLX_FILES: &[CatalogFile] = &[ + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/gliner-2.5-decide-4bit/config.json", + filename: "config.json", + required: true, + size_bytes: 1454, + checksum_sha256: Some("216030044bb8f5ae3ffeda85fc3dee54501322108ec2425ce00faf63d4c5d793"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/gliner-2.5-decide-4bit/model.safetensors", + filename: "model.safetensors", + required: true, + size_bytes: 350433655, + checksum_sha256: Some("52fb2f493fbd584537a8247ab3184053ebab4129e3d322d4e85868bbe8f0f0a4"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/gliner-2.5-decide-4bit/tokenizer.json", + filename: "tokenizer.json", + required: true, + size_bytes: 8333952, + checksum_sha256: Some("3ad87d9ffe669147063e70850927dd2da90249e2acc5c8527f1eb65df467bcc8"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/gliner-2.5-decide-4bit/tokenizer_config.json", + filename: "tokenizer_config.json", + required: true, + size_bytes: 3356, + checksum_sha256: Some("323199a4e946039410899f3779f2aa3eaef1500213c512727ad0f623d4f21309"), + }, + CatalogFile { + url: "https://huggingface.co/runanywhere/decision-models-stable-fork/resolve/main/mlx/gliner-2.5-decide-4bit/special_tokens_map.json", + filename: "special_tokens_map.json", + required: true, + size_bytes: 2414, + checksum_sha256: Some("84ea70143f533d7e99b393d87f20010887a9ac2cba955828ef313886e4e83f4f"), + }, +]; + const CATALOG: &[CatalogEntry] = &[ // --- LLM (LlamaCpp / GGUF) --- // Name carries Q8_0 on purpose: this is the one GGUF artifact in the @@ -4765,6 +4903,108 @@ const CATALOG: &[CatalogEntry] = &[ merge_key: Some("pplx-decider-27b"), harness_compatible: false, }, + CatalogEntry { + id: "lfm-d1-3b", + alias: Some("lfm-d1-3b-gguf"), + name: "LFM D1 3B", + category: v1::ModelCategory::Decision, + framework: v1::InferenceFramework::LlamaCpp, + format: v1::ModelFormat::Gguf, + url: None, + files: D1_3B_GGUF_FILES, + download_size_bytes: 1674456672, + context_length: 0, + supports_thinking: false, + memory_required_bytes: 0, + cua_profile: "", + merge_key: Some("lfm-d1-3b"), + harness_compatible: false, + }, + CatalogEntry { + id: "mlx-lfm-d1-3b-8bit", + alias: Some("lfm-d1-3b-mlx"), + name: "LFM D1 3B", + category: v1::ModelCategory::Decision, + framework: v1::InferenceFramework::Mlx, + format: v1::ModelFormat::Safetensors, + url: None, + files: D1_3B_MLX_FILES, + download_size_bytes: 3736636666, + context_length: 0, + supports_thinking: false, + memory_required_bytes: 0, + cua_profile: "", + merge_key: Some("lfm-d1-3b"), + harness_compatible: false, + }, + CatalogEntry { + id: "lfm-d1-omni-600m", + alias: Some("lfm-d1-omni-600m-gguf"), + name: "LFM D1 Omni 600M", + category: v1::ModelCategory::Decision, + framework: v1::InferenceFramework::LlamaCpp, + format: v1::ModelFormat::Gguf, + url: None, + files: D1_OMNI_GGUF_FILES, + download_size_bytes: 407207584, + context_length: 0, + supports_thinking: false, + memory_required_bytes: 0, + cua_profile: "", + merge_key: Some("lfm-d1-omni-600m"), + harness_compatible: false, + }, + CatalogEntry { + id: "mlx-lfm-d1-omni-600m", + alias: Some("lfm-d1-omni-600m-mlx"), + name: "LFM D1 Omni 600M", + category: v1::ModelCategory::Decision, + framework: v1::InferenceFramework::Mlx, + format: v1::ModelFormat::Safetensors, + url: None, + files: D1_OMNI_MLX_FILES, + download_size_bytes: 1179184850, + context_length: 0, + supports_thinking: false, + memory_required_bytes: 0, + cua_profile: "", + merge_key: Some("lfm-d1-omni-600m"), + harness_compatible: false, + }, + CatalogEntry { + id: "gliner-2.5-decide", + alias: Some("gliner-2.5-decide-gguf"), + name: "GLiNER 2.5 Decide", + category: v1::ModelCategory::Decision, + framework: v1::InferenceFramework::LlamaCpp, + format: v1::ModelFormat::Gguf, + url: None, + files: GLINER_DECIDE_GGUF_FILES, + download_size_bytes: 299547616, + context_length: 512, + supports_thinking: false, + memory_required_bytes: 0, + cua_profile: "", + merge_key: Some("gliner-2.5-decide"), + harness_compatible: false, + }, + CatalogEntry { + id: "mlx-gliner-2.5-decide-4bit", + alias: Some("gliner-2.5-decide-mlx"), + name: "GLiNER 2.5 Decide", + category: v1::ModelCategory::Decision, + framework: v1::InferenceFramework::Mlx, + format: v1::ModelFormat::Safetensors, + url: None, + files: GLINER_DECIDE_MLX_FILES, + download_size_bytes: 358774831, + context_length: 0, + supports_thinking: false, + memory_required_bytes: 0, + cua_profile: "", + merge_key: Some("gliner-2.5-decide"), + harness_compatible: false, + }, ]; // AUTO-TRANSLITERATED DATA END @@ -4822,6 +5062,16 @@ pub fn all() -> &'static [CatalogEntry] { LLM_ONLY.get_or_init(|| CATALOG.iter().copied().filter(listed).collect()) } +/// Whether `id_or_alias` is some catalog entry other than `merge_key`. +/// Platform filtering does not apply: a hidden row must not display an id +/// that pulls a different model where that other model is listed. +pub(crate) fn names_different_model(id_or_alias: &str, merge_key: &str) -> bool { + CATALOG.iter().any(|entry| { + (entry.id == id_or_alias || entry.alias == Some(id_or_alias)) + && entry.merge_key.unwrap_or(entry.id) != merge_key + }) +} + /// Exact id or alias lookup. pub fn find(id_or_alias: &str) -> Option<&'static CatalogEntry> { for entry in CATALOG { diff --git a/src/commands/cmd_list.rs b/src/commands/cmd_list.rs index a9b13749..75f91d77 100644 --- a/src/commands/cmd_list.rs +++ b/src/commands/cmd_list.rs @@ -74,12 +74,13 @@ impl Default for GroupedRow { } } -// A short "how do I download one?" header for the human list. The pull id -// differs by backend, so show one example per backend this build can run: -// llama.cpp where the kit has it (not the Windows ARM64 kit); on Apple also -// MLX. Never printed in --json. +// The table id is the model name, with no backend prefix. The same two +// spellings work for every row: the id as written is llama.cpp, and `mlx-` +// in front of it is the Apple GPU build. Never printed in --json. fn print_pull_examples() { - out::result_line("Download a model with `wally models pull `:"); + out::result_line( + "Each id below is the model. Pull it as written, or add mlx- for the Apple GPU build:", + ); #[cfg(wally_has_llamacpp)] out::result_line(" wally models pull qwen3-4b-instruct-2507 # llama.cpp"); #[cfg(target_os = "macos")] @@ -130,10 +131,11 @@ fn group_models( continue; } let key = crate::catalog::merge_key_for(&model.id); + let shown = shown_model_id(&key); let row = groups.entry(key.clone()).or_insert_with(|| { order.push(key.clone()); GroupedRow { - id: key.clone(), + id: shown, ..GroupedRow::default() } }); @@ -148,18 +150,13 @@ fn group_models( || catalog_entry .map(|entry| entry.harness_compatible) .unwrap_or(false); - // Show the id of a variant actually on disk, not a merge key that - // names nothing downloaded, so copying it inspects/pulls the same - // backend that's there rather than falling back to catalog defaults. - // When the variant registered under the merge key itself is on disk, - // it wins over a better-ranked backend: that id is downloaded too, and - // it is the one the C++ list showed, so a second downloaded backend - // must not make it vanish from the list. + // Remember where a downloaded copy lives. The shown id stays the + // model name either way, so a downloaded MLX build does not rename + // the row to `mlx-…`. let id_rank = if model.id == key { i32::MIN } else { rank }; if is_downloaded && id_rank < row.path_rank { row.path_rank = id_rank; row.local_path = model.local_path.clone(); - row.id = model.id.clone(); } if rank < row.name_rank { row.name_rank = rank; @@ -181,31 +178,37 @@ fn group_models( (order, groups) } -// The merge key only resolves when a variant is registered under it or under -// it as an alias; a model that ships a single `mlx-` build (ternary-bonsai-27b) -// has neither, so `pull ` failed as an unknown model. Show the -// best-ranked real id instead. The size then comes from the variant that id -// pulls: the best-ranked size alone showed the MLX build while `pull ` -// fetched the GGUF (2.2 GB listed, 4.0 GB pulled for qwen3-4b-instruct-2507). +/// Drop a leading `mlx-` only when the bare name is not already a different +/// catalog model. `llama3.2` is the GGUF 3B; the MLX 1B stays `mlx-llama3.2`. +fn shown_model_id(key: &str) -> String { + let Some(stripped) = key.strip_prefix("mlx-") else { + return key.to_string(); + }; + if crate::catalog::names_different_model(stripped, key) { + return key.to_string(); + } + stripped.to_string() +} + +fn variant_for_shown_id(row: &GroupedRow) -> Option { + if row.variants.iter().any(|(id, _, _)| id == &row.id) { + return Some(row.id.clone()); + } + let prefixed = format!("mlx-{}", row.id); + row.variants + .iter() + .find(|(id, _, _)| *id == prefixed || crate::catalog::merge_key_for(id) == row.id) + .map(|(id, _, _)| id.clone()) +} + +// Size follows the build `pull ` fetches. When that name is only an +// Apple GPU model, `pull mlx-` is the build, and the size is that one. +// The shown id itself is left alone. fn settle_row_id_and_size(row: &mut GroupedRow) { - let pulled = crate::catalog::find(&row.id) - .map(|entry| entry.id.to_string()) - .filter(|id| row.variants.iter().any(|(variant, _, _)| variant == id)) - .or_else(|| { - row.variants - .iter() - .find(|(variant, _, _)| *variant == row.id) - .map(|(variant, _, _)| variant.clone()) - }); + let pulled = variant_for_shown_id(row); let pulled = match pulled { Some(id) => id, - None => match row.variants.iter().min_by_key(|(_, rank, _)| *rank) { - Some((id, _, _)) => { - row.id = id.clone(); - id.clone() - } - None => return, - }, + None => return, }; if let Some((id, rank, size)) = row.variants.iter().find(|(id, _, _)| *id == pulled) { // An unknown size shows as `-`, not as another backend's size. @@ -570,10 +573,9 @@ mod tests { } #[test] - fn downloaded_variant_id_wins_over_merge_key() { - // Only the MLX variant is downloaded. Without the fix, row.id stayed - // the merge key even though the merge key names no downloaded - // backend here, so copying it would pull/inspect the wrong id. + fn downloaded_mlx_variant_keeps_the_model_name() { + // Only the MLX variant is downloaded. The row still shows the model + // name. The user adds mlx- when they want that build. let models = vec![ llamacpp_variant(""), mlx_variant("/models/mlx-qwen3-4b-instruct-2507-4bit"), @@ -583,7 +585,7 @@ mod tests { let (order, groups) = group_models(&models, &downloaded, true); assert_eq!(order, vec!["qwen3-4b-instruct-2507".to_string()]); let row = &groups["qwen3-4b-instruct-2507"]; - assert_eq!(row.id, "mlx-qwen3-4b-instruct-2507-4bit"); + assert_eq!(row.id, "qwen3-4b-instruct-2507"); assert_eq!(row.local_path, "/models/mlx-qwen3-4b-instruct-2507-4bit"); } @@ -633,7 +635,9 @@ mod tests { } #[test] - fn downloaded_mlx_row_shows_the_mlx_size() { + fn downloaded_mlx_row_keeps_the_llama_cpp_size() { + // The shown id pulls the llama.cpp build, so the size is that build + // even when only the MLX copy is on disk. let models = vec![ llamacpp_variant(""), mlx_variant("/models/mlx-qwen3-4b-instruct-2507-4bit"), @@ -641,13 +645,13 @@ mod tests { let downloaded: std::collections::HashSet = std::iter::once("mlx-qwen3-4b-instruct-2507-4bit".to_string()).collect(); let (_, groups) = group_models(&models, &downloaded, true); - assert_eq!(groups["qwen3-4b-instruct-2507"].size_bytes, 2_360_000_000); + assert_eq!(groups["qwen3-4b-instruct-2507"].size_bytes, 4_280_000_000); } #[test] - fn mlx_only_model_shows_a_pullable_id() { - // ternary-bonsai-27b ships only an mlx- build, so its merge key names - // no registered model. + fn mlx_only_model_drops_the_prefix() { + // ternary-bonsai-27b ships only an mlx- build. The row shows the + // model name; `pull mlx-ternary-bonsai-27b` is how you get it. let models = vec![v1::ModelInfo { id: "mlx-ternary-bonsai-27b-2bit".to_string(), name: "Ternary Bonsai 27B".to_string(), @@ -660,10 +664,32 @@ mod tests { let (order, groups) = group_models(&models, &downloaded, true); let row = &groups[&order[0]]; assert_eq!(order, vec!["ternary-bonsai-27b".to_string()]); - assert_eq!(row.id, "mlx-ternary-bonsai-27b-2bit"); + assert_eq!(row.id, "ternary-bonsai-27b"); assert_eq!(row.size_bytes, 8_480_000_000); } + #[test] + fn mlx_only_id_stays_when_the_bare_name_is_another_model() { + // `llama3.2` is the GGUF Llama 3.2 3B alias. Stripping the prefix + // would list the MLX 1B under an id that pulls the other model. + let models = vec![v1::ModelInfo { + id: "mlx-llama-3.2-1b-instruct-4bit".to_string(), + name: "Llama 3.2 1B Instruct".to_string(), + category: v1::ModelCategory::Language as i32, + framework: v1::InferenceFramework::Mlx as i32, + download_size_bytes: 712_575_975, + ..Default::default() + }]; + let downloaded: std::collections::HashSet = std::collections::HashSet::new(); + let (order, groups) = group_models(&models, &downloaded, true); + let row = &groups[&order[0]]; + assert_eq!(row.id, "mlx-llama3.2"); + assert_eq!( + crate::catalog::merge_key_for("mlx-llama-3.2-1b-instruct-4bit"), + row.id + ); + } + #[test] fn unknown_size_of_the_pulled_build_is_not_filled_from_another() { let mut gguf = llamacpp_variant(""); diff --git a/src/sys/bindings.rs b/src/sys/bindings.rs index 3644c36e..4ef55851 100644 --- a/src/sys/bindings.rs +++ b/src/sys/bindings.rs @@ -1,4 +1,4 @@ -// @generated by scripts/build/gen-sys-bindings.sh from RunAnywhere kit 0.20.38. +// @generated by scripts/build/gen-sys-bindings.sh from RunAnywhere kit 0.20.39. // DO NOT EDIT. Regenerate after a kit pin bump. /* automatically generated by rust-bindgen 0.73.2 */ diff --git a/swift/Package.resolved b/swift/Package.resolved index 5c40fb52..a9bbd0a7 100644 --- a/swift/Package.resolved +++ b/swift/Package.resolved @@ -33,7 +33,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/RunanywhereAI/mlx-audio-swift.git", "state" : { - "revision" : "ecc772d3c433d8b7967d423f2ea35995085c4d1c" + "revision" : "cade76c23fa00ef2184452adb12fae22942c73cb", + "version" : "0.1.8" } }, { @@ -50,8 +51,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/RunanywhereAI/mlx-swift-lm.git", "state" : { - "revision" : "6166b1bb1ea96652f37231d09fb3f475fcfa3a25", - "version" : "3.31.8" + "revision" : "4c31da1d4aa22e2d15b545120a0ba3c19368bc2c", + "version" : "3.31.10" } }, { diff --git a/tests/golden/expected/local__-q__models__list.stdout b/tests/golden/expected/local__-q__models__list.stdout index 5a394238..7d2936d2 100644 --- a/tests/golden/expected/local__-q__models__list.stdout +++ b/tests/golden/expected/local__-q__models__list.stdout @@ -1,4 +1,4 @@ -Download a model with `wally models pull `: +Each id below is the model. Pull it as written, or add mlx- for the Apple GPU build: wally models pull qwen3-4b-instruct-2507 # llama.cpp wally models pull mlx-qwen3-4b-instruct-2507 # MLX (Apple GPU) diff --git a/tests/golden/expected/local__models__list.stdout b/tests/golden/expected/local__models__list.stdout index 5a394238..7d2936d2 100644 --- a/tests/golden/expected/local__models__list.stdout +++ b/tests/golden/expected/local__models__list.stdout @@ -1,4 +1,4 @@ -Download a model with `wally models pull `: +Each id below is the model. Pull it as written, or add mlx- for the Apple GPU build: wally models pull qwen3-4b-instruct-2507 # llama.cpp wally models pull mlx-qwen3-4b-instruct-2507 # MLX (Apple GPU) diff --git a/tests/golden/expected/local__models__list__--all.stdout b/tests/golden/expected/local__models__list__--all.stdout index b5e0d0da..ec8d383e 100644 --- a/tests/golden/expected/local__models__list__--all.stdout +++ b/tests/golden/expected/local__models__list__--all.stdout @@ -1,39 +1,42 @@ -Download a model with `wally models pull `: +Each id below is the model. Pull it as written, or add mlx- for the Apple GPU build: wally models pull qwen3-4b-instruct-2507 # llama.cpp wally models pull mlx-qwen3-4b-instruct-2507 # MLX (Apple GPU) -ID MODALITY BACKEND SIZE DOWNLOADED TAGS -bonsai-1.7b llm mlx/llama.cpp 236.8 MB no -bonsai-27b llm mlx/llama.cpp 3.5 GB no -bonsai-4b llm mlx/llama.cpp 545.8 MB no -bonsai-8b llm mlx/llama.cpp 1.1 GB no -clef-27b decision mlx/llama.cpp 17.9 GB no -clef-flash-9b decision mlx/llama.cpp 6.0 GB no -gemma-4-12b llm mlx/llama.cpp 6.6 GB no -gemma-4-26b-a4b llm mlx/llama.cpp 15.8 GB no -gemma-4-31b llm mlx/llama.cpp 17.1 GB no -gemma-4-e2b llm mlx/llama.cpp 2.9 GB no -gemma-4-e4b llm mlx/llama.cpp 4.6 GB no -granite-4.1-30b llm mlx/llama.cpp 16.3 GB no -granite-4.1-3b llm mlx/llama.cpp 2.0 GB no -granite-4.1-8b llm mlx/llama.cpp 5.0 GB no -granite-4.2-30b llm llama.cpp 16.8 GB no -granite-4.2-8b llm llama.cpp 5.2 GB no -lfm2.5-1.2b llm llama.cpp 697.0 MB no -lfm2.5-2.6b llm llama.cpp 1.6 GB no -lfm2.5-230m llm llama.cpp 146.3 MB no -lfm2.5-350m llm llama.cpp 219.0 MB no -llama-3.2-3b llm llama.cpp 2.0 GB no -maple-preview llm mlx/llama.cpp 4.6 GB no -mlx-nemotron-nano llm mlx 4.2 GB no -mlx-llama3.2 llm mlx 679.6 MB no -mlx-nemotron-mini llm mlx 2.2 GB no -mlx-pplx-decider-27b-4bit decision mlx 14.3 GB no -qwen3-0.6b llm mlx/llama.cpp 639.0 MB no -qwen3-4b-instruct-2507 llm mlx/llama.cpp 4.0 GB no [harness-compatible] -qwen3.8-27b llm mlx/llama.cpp 15.9 GB no -ternary-bonsai-1.7b llm mlx/llama.cpp 467.5 MB no -mlx-ternary-bonsai-27b-2bit llm mlx 7.9 GB no -ternary-bonsai-4b llm mlx/llama.cpp 1.1 GB no -ternary-bonsai-8b llm mlx/llama.cpp 2.2 GB no -smollm2-135m llm llama.cpp 96.0 MB no +ID MODALITY BACKEND SIZE DOWNLOADED TAGS +bonsai-1.7b llm mlx/llama.cpp 236.8 MB no +bonsai-27b llm mlx/llama.cpp 3.5 GB no +bonsai-4b llm mlx/llama.cpp 545.8 MB no +bonsai-8b llm mlx/llama.cpp 1.1 GB no +clef-27b decision mlx/llama.cpp 17.9 GB no +clef-flash-9b decision mlx/llama.cpp 6.0 GB no +gemma-4-12b llm mlx/llama.cpp 6.6 GB no +gemma-4-26b-a4b llm mlx/llama.cpp 15.8 GB no +gemma-4-31b llm mlx/llama.cpp 17.1 GB no +gemma-4-e2b llm mlx/llama.cpp 2.9 GB no +gemma-4-e4b llm mlx/llama.cpp 4.6 GB no +gliner-2.5-decide decision mlx/llama.cpp 285.7 MB no +granite-4.1-30b llm mlx/llama.cpp 16.3 GB no +granite-4.1-3b llm mlx/llama.cpp 2.0 GB no +granite-4.1-8b llm mlx/llama.cpp 5.0 GB no +granite-4.2-30b llm llama.cpp 16.8 GB no +granite-4.2-8b llm llama.cpp 5.2 GB no +lfm-d1-3b decision mlx/llama.cpp 1.6 GB no +lfm-d1-omni-600m decision mlx/llama.cpp 388.3 MB no +lfm2.5-1.2b llm llama.cpp 697.0 MB no +lfm2.5-2.6b llm llama.cpp 1.6 GB no +lfm2.5-230m llm llama.cpp 146.3 MB no +lfm2.5-350m llm llama.cpp 219.0 MB no +llama-3.2-3b llm llama.cpp 2.0 GB no +maple-preview llm mlx/llama.cpp 4.6 GB no +nemotron-nano llm mlx 4.2 GB no +mlx-llama3.2 llm mlx 679.6 MB no +nemotron-mini llm mlx 2.2 GB no +pplx-decider-27b decision mlx 14.3 GB no +qwen3-0.6b llm mlx/llama.cpp 639.0 MB no +qwen3-4b-instruct-2507 llm mlx/llama.cpp 4.0 GB no [harness-compatible] +qwen3.8-27b llm mlx/llama.cpp 15.9 GB no +ternary-bonsai-1.7b llm mlx/llama.cpp 467.5 MB no +ternary-bonsai-27b llm mlx 7.9 GB no +ternary-bonsai-4b llm mlx/llama.cpp 1.1 GB no +ternary-bonsai-8b llm mlx/llama.cpp 2.2 GB no +smollm2-135m llm llama.cpp 96.0 MB no diff --git a/tests/golden/expected/local__models__list__--all__--json.stdout b/tests/golden/expected/local__models__list__--all__--json.stdout index 2b4eeace..9a40968e 100644 --- a/tests/golden/expected/local__models__list__--all__--json.stdout +++ b/tests/golden/expected/local__models__list__--all__--json.stdout @@ -1 +1 @@ -{"models":[{"id":"bonsai-1.7b","name":"Bonsai 1.7B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":248302272,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"bonsai-27b","name":"Bonsai 27B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":3803452480,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"bonsai-4b","name":"Bonsai 4B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":572270624,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"bonsai-8b","name":"Bonsai 8B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":1158654496,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"clef-27b","name":"Clef 27B (decision)","modality":"decision","backend":"mlx/llama.cpp","size_bytes":19232219200,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"clef-flash-9b","name":"Clef Flash 9B (decision)","modality":"decision","backend":"mlx/llama.cpp","size_bytes":6486448288,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-12b","name":"Gemma 4 12B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":7121861440,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-26b-a4b","name":"Gemma 4 26B-A4B (MoE)","modality":"llm","backend":"mlx/llama.cpp","size_bytes":17010980576,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-31b","name":"Gemma 4 31B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":18323733440,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-e2b","name":"Gemma 4 E2B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":3106738272,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-e4b","name":"Gemma 4 E4B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":4977171584,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.1-30b","name":"IBM Granite 4.1 30B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":17490241472,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.1-3b","name":"IBM Granite 4.1 3B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":2099502400,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.1-8b","name":"IBM Granite 4.1 8B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":5347915136,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.2-30b","name":"IBM Granite 4.2 30B","modality":"llm","backend":"llama.cpp","size_bytes":18027118592,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.2-8b","name":"IBM Granite 4.2 8B","modality":"llm","backend":"llama.cpp","size_bytes":5539627008,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm2.5-1.2b","name":"LiquidAI LFM2.5 1.2B Instruct","modality":"llm","backend":"llama.cpp","size_bytes":730857472,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm2.5-2.6b","name":"LiquidAI LFM2.5 2.6B","modality":"llm","backend":"llama.cpp","size_bytes":1674575872,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm2.5-230m","name":"LiquidAI LFM2.5 230M","modality":"llm","backend":"llama.cpp","size_bytes":153406304,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm2.5-350m","name":"LiquidAI LFM2.5 350M","modality":"llm","backend":"llama.cpp","size_bytes":229638144,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"llama-3.2-3b","name":"Llama 3.2 3B Instruct","modality":"llm","backend":"llama.cpp","size_bytes":2118123520,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"maple-preview","name":"DeepGrove Maple Preview","modality":"llm","backend":"mlx/llama.cpp","size_bytes":4984016416,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"mlx-nemotron-nano","name":"NVIDIA Llama 3.1 Nemotron Nano 8B","modality":"llm","backend":"mlx","size_bytes":4534806075,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"mlx-llama3.2","name":"Llama 3.2 1B Instruct","modality":"llm","backend":"mlx","size_bytes":712575975,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"mlx-nemotron-mini","name":"NVIDIA Nemotron Mini 4B Instruct","modality":"llm","backend":"mlx","size_bytes":2392679103,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"mlx-pplx-decider-27b-4bit","name":"Pplx Decider 27B (decision)","modality":"decision","backend":"mlx","size_bytes":15362201309,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"qwen3-0.6b","name":"Qwen3 0.6B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":670040064,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"qwen3-4b-instruct-2507","name":"Qwen3 4B Instruct 2507","modality":"llm","backend":"mlx/llama.cpp","size_bytes":4300000000,"downloaded":false,"harness_compatible":true,"local_path":"","cloud":false},{"id":"qwen3.8-27b","name":"Qwen3.8 27B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":17106775008,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"ternary-bonsai-1.7b","name":"Ternary-Bonsai 1.7B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":490163968,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"mlx-ternary-bonsai-27b-2bit","name":"Ternary-Bonsai 27B","modality":"llm","backend":"mlx","size_bytes":8490785104,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"ternary-bonsai-4b","name":"Ternary-Bonsai 4B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":1137806656,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"ternary-bonsai-8b","name":"Ternary-Bonsai 8B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":2310125920,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"smollm2-135m","name":"SmolLM2 135M","modality":"llm","backend":"llama.cpp","size_bytes":100663296,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false}]} +{"models":[{"id":"bonsai-1.7b","name":"Bonsai 1.7B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":248302272,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"bonsai-27b","name":"Bonsai 27B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":3803452480,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"bonsai-4b","name":"Bonsai 4B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":572270624,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"bonsai-8b","name":"Bonsai 8B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":1158654496,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"clef-27b","name":"Clef 27B (decision)","modality":"decision","backend":"mlx/llama.cpp","size_bytes":19232219200,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"clef-flash-9b","name":"Clef Flash 9B (decision)","modality":"decision","backend":"mlx/llama.cpp","size_bytes":6486448288,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-12b","name":"Gemma 4 12B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":7121861440,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-26b-a4b","name":"Gemma 4 26B-A4B (MoE)","modality":"llm","backend":"mlx/llama.cpp","size_bytes":17010980576,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-31b","name":"Gemma 4 31B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":18323733440,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-e2b","name":"Gemma 4 E2B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":3106738272,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gemma-4-e4b","name":"Gemma 4 E4B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":4977171584,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"gliner-2.5-decide","name":"GLiNER 2.5 Decide","modality":"decision","backend":"mlx/llama.cpp","size_bytes":299547616,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.1-30b","name":"IBM Granite 4.1 30B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":17490241472,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.1-3b","name":"IBM Granite 4.1 3B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":2099502400,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.1-8b","name":"IBM Granite 4.1 8B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":5347915136,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.2-30b","name":"IBM Granite 4.2 30B","modality":"llm","backend":"llama.cpp","size_bytes":18027118592,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"granite-4.2-8b","name":"IBM Granite 4.2 8B","modality":"llm","backend":"llama.cpp","size_bytes":5539627008,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm-d1-3b","name":"LFM D1 3B","modality":"decision","backend":"mlx/llama.cpp","size_bytes":1674456672,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm-d1-omni-600m","name":"LFM D1 Omni 600M","modality":"decision","backend":"mlx/llama.cpp","size_bytes":407207584,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm2.5-1.2b","name":"LiquidAI LFM2.5 1.2B Instruct","modality":"llm","backend":"llama.cpp","size_bytes":730857472,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm2.5-2.6b","name":"LiquidAI LFM2.5 2.6B","modality":"llm","backend":"llama.cpp","size_bytes":1674575872,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm2.5-230m","name":"LiquidAI LFM2.5 230M","modality":"llm","backend":"llama.cpp","size_bytes":153406304,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"lfm2.5-350m","name":"LiquidAI LFM2.5 350M","modality":"llm","backend":"llama.cpp","size_bytes":229638144,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"llama-3.2-3b","name":"Llama 3.2 3B Instruct","modality":"llm","backend":"llama.cpp","size_bytes":2118123520,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"maple-preview","name":"DeepGrove Maple Preview","modality":"llm","backend":"mlx/llama.cpp","size_bytes":4984016416,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"nemotron-nano","name":"NVIDIA Llama 3.1 Nemotron Nano 8B","modality":"llm","backend":"mlx","size_bytes":4534806075,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"mlx-llama3.2","name":"Llama 3.2 1B Instruct","modality":"llm","backend":"mlx","size_bytes":712575975,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"nemotron-mini","name":"NVIDIA Nemotron Mini 4B Instruct","modality":"llm","backend":"mlx","size_bytes":2392679103,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"pplx-decider-27b","name":"Pplx Decider 27B (decision)","modality":"decision","backend":"mlx","size_bytes":15362201309,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"qwen3-0.6b","name":"Qwen3 0.6B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":670040064,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"qwen3-4b-instruct-2507","name":"Qwen3 4B Instruct 2507","modality":"llm","backend":"mlx/llama.cpp","size_bytes":4300000000,"downloaded":false,"harness_compatible":true,"local_path":"","cloud":false},{"id":"qwen3.8-27b","name":"Qwen3.8 27B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":17106775008,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"ternary-bonsai-1.7b","name":"Ternary-Bonsai 1.7B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":490163968,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"ternary-bonsai-27b","name":"Ternary-Bonsai 27B","modality":"llm","backend":"mlx","size_bytes":8490785104,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"ternary-bonsai-4b","name":"Ternary-Bonsai 4B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":1137806656,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"ternary-bonsai-8b","name":"Ternary-Bonsai 8B","modality":"llm","backend":"mlx/llama.cpp","size_bytes":2310125920,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false},{"id":"smollm2-135m","name":"SmolLM2 135M","modality":"llm","backend":"llama.cpp","size_bytes":100663296,"downloaded":false,"harness_compatible":false,"local_path":"","cloud":false}]} diff --git a/tests/golden/expected/local__models__list__--home__HOMEelsewhere.stdout b/tests/golden/expected/local__models__list__--home__HOMEelsewhere.stdout index 5a394238..7d2936d2 100644 --- a/tests/golden/expected/local__models__list__--home__HOMEelsewhere.stdout +++ b/tests/golden/expected/local__models__list__--home__HOMEelsewhere.stdout @@ -1,4 +1,4 @@ -Download a model with `wally models pull `: +Each id below is the model. Pull it as written, or add mlx- for the Apple GPU build: wally models pull qwen3-4b-instruct-2507 # llama.cpp wally models pull mlx-qwen3-4b-instruct-2507 # MLX (Apple GPU) diff --git a/tests/golden/expected/local__models__ls.stdout b/tests/golden/expected/local__models__ls.stdout index 5a394238..7d2936d2 100644 --- a/tests/golden/expected/local__models__ls.stdout +++ b/tests/golden/expected/local__models__ls.stdout @@ -1,4 +1,4 @@ -Download a model with `wally models pull `: +Each id below is the model. Pull it as written, or add mlx- for the Apple GPU build: wally models pull qwen3-4b-instruct-2507 # llama.cpp wally models pull mlx-qwen3-4b-instruct-2507 # MLX (Apple GPU) diff --git a/tests/golden/expected/version__--json__version.stdout b/tests/golden/expected/version__--json__version.stdout index 5c50a551..917fe08d 100644 --- a/tests/golden/expected/version__--json__version.stdout +++ b/tests/golden/expected/version__--json__version.stdout @@ -1 +1 @@ -{"wally":"","commons":"0.20.38","pinned_sdk":"0.20.38","idl_version":"1.5.0","idl_schema_sha256":"faca2c22e518f3d41e534399b854bbbc9617d4a76511592a6013a888fdd3cf3d","idl_protoc":"35.1","pin_ok":true} +{"wally":"","commons":"0.20.39","pinned_sdk":"0.20.39","idl_version":"1.5.0","idl_schema_sha256":"faca2c22e518f3d41e534399b854bbbc9617d4a76511592a6013a888fdd3cf3d","idl_protoc":"35.1","pin_ok":true} diff --git a/tests/golden/expected/version__version.stdout b/tests/golden/expected/version__version.stdout index c72a6968..68e0bbec 100644 --- a/tests/golden/expected/version__version.stdout +++ b/tests/golden/expected/version__version.stdout @@ -1,2 +1,2 @@ -wally (commons 0.20.38) +wally (commons 0.20.39) idl 1.5.0 sha256 faca2c22e518f3d41e534399b854bbbc9617d4a76511592a6013a888fdd3cf3d diff --git a/tests/golden/expected/version__version__--json.stdout b/tests/golden/expected/version__version__--json.stdout index 5c50a551..917fe08d 100644 --- a/tests/golden/expected/version__version__--json.stdout +++ b/tests/golden/expected/version__version__--json.stdout @@ -1 +1 @@ -{"wally":"","commons":"0.20.38","pinned_sdk":"0.20.38","idl_version":"1.5.0","idl_schema_sha256":"faca2c22e518f3d41e534399b854bbbc9617d4a76511592a6013a888fdd3cf3d","idl_protoc":"35.1","pin_ok":true} +{"wally":"","commons":"0.20.39","pinned_sdk":"0.20.39","idl_version":"1.5.0","idl_schema_sha256":"faca2c22e518f3d41e534399b854bbbc9617d4a76511592a6013a888fdd3cf3d","idl_protoc":"35.1","pin_ok":true} diff --git a/versions.toml b/versions.toml index 320240e5..c37d9f97 100644 --- a/versions.toml +++ b/versions.toml @@ -7,7 +7,7 @@ [product] # wally's own release version; git tag is v (auto-tag.yml reads it here). -version = "0.8.3" +version = "0.8.5" [contracts] # Vendored from InferenceInfra at this exact revision. @@ -16,16 +16,16 @@ decisions_contract_sha256 = "6cd5afaa222e55337dcab1fa4b2bbee2763cea707e18d539a5c [sdk] # The published C++ desktop kit this tree builds against; bump the SHAs with it. -kit_version = "0.20.38" -kit_release_tag = "cpp-desktop-v0.20.38-4" +kit_version = "0.20.39" +kit_release_tag = "cpp-desktop-v0.20.39" idl_version = "1.5.0" idl_schema_sha256 = "faca2c22e518f3d41e534399b854bbbc9617d4a76511592a6013a888fdd3cf3d" idl_protoc_version = "35.1" -kit_sha256_macos_arm64 = "5e025878f2b2267ebe5840b858b9dab44d4af1ea43c674939f12fdb485905290" -kit_sha256_windows_x64 = "48c72cad2de2bba467f4be9225daeb30cff43a4e1b710d0f8153de3c09e7230c" -kit_sha256_windows_arm64 = "f194fd6eec1aa20c360ef9e7a82391c7fde09ad563d1da3343cec404c5421a85" -kit_sha256_linux_x64 = "8008d49b40534cb09f12dbdbbcfeaa4f7e74791908ec42d1acd919caf62c3cd2" -kit_sha256_linux_arm64 = "6971dfe6c67a38e791e6787d11eafbeae0a7d96e4f5b1816a7059473964533e0" +kit_sha256_macos_arm64 = "1262fa1a54be0945c862d66565afeadcee8d840dac3c65a0649838fba62ffda6" +kit_sha256_windows_x64 = "917c0798706f237a0668f45b1a78915d3b44150b19659347a4641ea7830bf51a" +kit_sha256_windows_arm64 = "10964d413eda749698e8a2d2afe9438182d2748b1b46a38c82b7f91ea1622653" +kit_sha256_linux_x64 = "fa9080f282c3cc494ee5a9d1fdfa0e8fc01a621292b44b6ccd9d3140c7853eed" +kit_sha256_linux_arm64 = "7492758d20e584f56b99be9d262959c4c512011ae13337a34b49bf44498ec5e6" [swift] # The Apple MLX host's Swift SDK: sdk_package_version pins swift/Package.swift, @@ -64,14 +64,16 @@ linux_compat = "ubuntu-22.04" linux_arm64 = "ubuntu-22.04-arm" [linux_abi] -# What the Linux bottle may ask of the system it runs on. The floor is Ubuntu -# 22.04 (glibc 2.35, libstdc++ from GCC 12); Debian 12 and newer Ubuntu clear -# it. scripts/release/check-linux-abi.py fails a release whose ELF files need a -# newer symbol version, or a shared library that is neither shipped in the -# bottle nor listed here. install.sh checks the same glibc, glibcxx_max and -# cxxabi_max before it downloads (MIN_GLIBC, MIN_GLIBCXX, MIN_CXXABI). -glibc_max = "2.35" -glibcxx_max = "3.4.30" +# What the Linux bottle may ask of the system it runs on. Kit 0.20.39's +# Sherpa prebuilt needs glibc 2.38 and GLIBCXX_3.4.32. Building the bottle on +# Ubuntu 24.04 also pulls glibc 2.39 into wally itself, so the floor is Ubuntu +# 24.04 (GCC 13). Debian 13 clears it. scripts/release/check-linux-abi.py fails +# a release whose ELF files need a newer symbol version, or a shared library +# that is neither shipped in the bottle nor listed here. install.sh checks the +# same glibc, glibcxx_max and cxxabi_max before it downloads (MIN_GLIBC, +# MIN_GLIBCXX, MIN_CXXABI). +glibc_max = "2.39" +glibcxx_max = "3.4.32" cxxabi_max = "1.3.13" system_libraries = [ "ld-linux-x86-64.so.2", "libc.so.6", "libm.so.6", "libdl.so.2", @@ -83,16 +85,15 @@ system_libraries = [ interpreters = ["/lib64/ld-linux-x86-64.so.2"] [linux_abi_arm64] -# The arm64 bottle has the same floor as the x86-64 one (Ubuntu 22.04, Debian -# 12): wally and the kit's Sherpa prebuilt are both built on ubuntu-22.04-arm. +# The arm64 bottle has the same floor as the x86-64 one (Ubuntu 24.04, Debian +# 13). The kit's Sherpa prebuilt needs glibc 2.38 and GLIBCXX_3.4.32. # It keeps its own block for the loader name and system libraries below. The -# arm64 kit's cpp-httplib (zstd, brotli) and libarchive (bz2) pull three -# compression libraries the x86-64 kit references from none of its objects, so -# the bottle bundles those under lib/ (they are shipped, not listed here). +# Both kits pull zstd, brotli and bz2. The bottle bundles those under lib/ +# (they are shipped, not listed here). # check-linux-abi.py reads this block for an arm64 archive; install.sh holds # MIN_GLIBC_ARM64/MIN_GLIBCXX_ARM64 to it. -glibc_max = "2.35" -glibcxx_max = "3.4.30" +glibc_max = "2.39" +glibcxx_max = "3.4.32" cxxabi_max = "1.3.13" system_libraries = [ "ld-linux-aarch64.so.1", "libc.so.6", "libm.so.6", "libdl.so.2",