Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
357 changes: 103 additions & 254 deletions README.md

Large diffs are not rendered by default.

249 changes: 70 additions & 179 deletions app/src/main/java/com/runanywhere/runanywhereai/data/ModelCatalog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -207,74 +207,14 @@ internal object ModelCatalog {

// --- LLM (llama.cpp) ------------------------------------------------------
private val llm = listOf(
// SmolLM2
SingleFileModel(
"smollm2-360m-q8_0",
"SmolLM2 360M Q8_0",
"https://huggingface.co/prithivMLmods/SmolLM2-360M-GGUF/resolve/main/SmolLM2-360M.Q8_0.gguf",
LLAMA,
LANGUAGE,
386_404_416
),
// Qwen (2.5, then 3, then 3.5)
SingleFileModel(
"qwen2.5-0.5b-instruct-q6_k",
"Qwen 2.5 0.5B Instruct Q6_K",
"https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct-GGUF/resolve/main/qwen2.5-0.5b-instruct-q6_k.gguf",
LLAMA,
LANGUAGE,
// downloadBytes defaults to memoryBytes, so a RAM-shaped round number here is also
// published as the transfer total the progress bar divides by. 600_000_000 is 50 MB short
// of the real asset (measured twice: 650_379_104 bytes on disk, and the HTTP layer logs
// `bytes_written=650379104`), which drove the bar to 100% at 92% of the file and left the
// line reading "596.2 MB of 572.2 MB" with the ETA gone while 50 MB was still arriving.
memoryBytes = 600_000_000,
downloadBytes = 650_379_104,
supportsLora = true
),
SingleFileModel(
"qwen2.5-1.5b-instruct-q4_k_m",
"Qwen 2.5 1.5B Instruct Q4_K_M",
"https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct-GGUF/resolve/main/qwen2.5-1.5b-instruct-q4_k_m.gguf",
LLAMA,
LANGUAGE,
2_500_000_000
),
SingleFileModel(
"qwen3-0.6b-q4_k_m",
"Qwen3 0.6B Q4_K_M",
"https://huggingface.co/unsloth/Qwen3-0.6B-GGUF/resolve/main/Qwen3-0.6B-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
memoryBytes = 500_000_000,
downloadBytes = 396_705_472,
supportsThinking = true
),
SingleFileModel(
"qwen3-1.7b-q4_k_m",
"Qwen3 1.7B Q4_K_M",
"https://huggingface.co/unsloth/Qwen3-1.7B-GGUF/resolve/main/Qwen3-1.7B-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
1_200_000_000,
supportsThinking = true
),
SingleFileModel(
"qwen3-4b-q4_k_m",
"Qwen3 4B Q4_K_M",
"https://huggingface.co/unsloth/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
2_800_000_000,
supportsThinking = true
),
SingleFileModel(
"qwen3.5-0.8b-q4_k_m",
"Qwen3.5 0.8B Q4_K_M",
"https://huggingface.co/bartowski/Qwen_Qwen3.5-0.8B-GGUF/resolve/main/Qwen3.5-0.8B-Q4_K_M.gguf",
"https://huggingface.co/unsloth/Qwen3.5-0.8B-GGUF/resolve/main/Qwen3.5-0.8B-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
620_000_000,
memoryBytes = 900_000_000,
downloadBytes = 532_517_120,
supportsThinking = true
),
// Qwen3.6 — MoE (35B total / 3B active), agentic-coding-focused release.
Expand All @@ -293,10 +233,11 @@ internal object ModelCatalog {
SingleFileModel(
"qwen3.8-27b-q4_k_m",
"Qwen3.8 27B Q4_K_M (heavy)",
"https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/resolve/main/Qwen3.8-27B-Q4_K_M.gguf",
"https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/resolve/main/Qwen3.8-27B-UD-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
17_106_775_008,
memoryBytes = 17_106_775_008,
downloadBytes = 16_464_440_224,
supportsThinking = true
),
// LFM2 / LFM2.5 (Liquid AI)
Expand All @@ -315,28 +256,6 @@ internal object ModelCatalog {
// 153,406,304 B of weights plus KV cache and runtime overhead.
190_000_000
),
// ONE quantization per model. The Q8_0 sibling of this row was removed
// deliberately: two quants of the same 350M model differ only in bytes
// (229 MB vs 379 MB), so the second row costs a catalog slot and a
// "which one do I pick?" decision without adding a capability. The same
// collapse was applied to LFM2 1.2B Tool and LFM2.5 2.6B below.
SingleFileModel(
"lfm2-350m-q4_k_m",
"LiquidAI LFM2 350M Q4_K_M",
"https://huggingface.co/LiquidAI/LFM2-350M-GGUF/resolve/main/LFM2-350M-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
250_000_000
),
// Q8_0 sibling removed — one quantization per model (see the 350M note above).
SingleFileModel(
"lfm2-1.2b-tool-q4_k_m",
"LiquidAI LFM2 1.2B Tool Q4_K_M",
"https://huggingface.co/LiquidAI/LFM2-1.2B-Tool-GGUF/resolve/main/LFM2-1.2B-Tool-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
800_000_000
),
SingleFileModel(
"lfm2.5-1.2b-instruct-q4_k_m",
"LiquidAI LFM2.5 1.2B Instruct Q4_K_M",
Expand All @@ -355,24 +274,6 @@ internal object ModelCatalog {
1_674_000_000,
supportsThinking = true
),
// Llama
SingleFileModel(
"llama-2-7b-chat-q4_k_m",
"Llama 2 7B Chat Q4_K_M",
"https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGUF/resolve/main/llama-2-7b-chat.Q4_K_M.gguf",
LLAMA,
LANGUAGE,
4_000_000_000
),
// Mistral
SingleFileModel(
"mistral-7b-instruct-q4_k_m",
"Mistral 7B Instruct Q4_K_M",
"https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.1-GGUF/resolve/main/mistral-7b-instruct-v0.1.Q4_K_M.gguf",
LLAMA,
LANGUAGE,
4_000_000_000
),
// Gemma
// Gemma 4 license: Google's Gemma Terms of Use (https://ai.google.dev/gemma/terms),
// not Apache — same license family as the gemma3n/gemma4 QHexRT rows in npuCatalog
Expand Down Expand Up @@ -429,14 +330,6 @@ internal object ModelCatalog {
LANGUAGE,
18_323_733_440
),
SingleFileModel(
"gemma-4-31b-it-ud-q2_k_xl",
"Gemma 4 31B IT UD-Q2_K_XL (heavy)",
"https://huggingface.co/unsloth/gemma-4-31B-it-GGUF/resolve/main/gemma-4-31B-it-UD-Q2_K_XL.gguf",
LLAMA,
LANGUAGE,
11_774_991_296
),
// Granite (IBM)
// Apache 2.0 (verified via HF cardData.license). Dense, three sizes.
SingleFileModel(
Expand Down Expand Up @@ -469,29 +362,6 @@ internal object ModelCatalog {
// Exact P0 NVIDIA checkpoint. The pinned llama.cpp fork has native
// `nemotron` support; this exact Q4_K_M artifact was load/inference
// checked through rcli on macOS before being exposed in the catalog.
SingleFileModel(
"nemotron-mini-4b-instruct-q4_k_m",
"NVIDIA Nemotron Mini 4B Instruct Q4_K_M",
"https://huggingface.co/bartowski/Nemotron-Mini-4B-Instruct-GGUF/resolve/fb49cde090c86092d89905bea2ffc41c23c2615e/Nemotron-Mini-4B-Instruct-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
2_697_387_072,
contextLength = 4_096
),
// Exact P0 NVIDIA Nano checkpoint. The file itself is 4.92 GB, while
// llama.cpp also needs KV/cache/compute headroom. Keep those two facts
// separate so the download planner validates the exact transport size
// and the mandatory SDK compatibility preflight requires 6 GiB of
// currently available RAM before either download or lifecycle load.
//
// INTENTIONAL CROSS-SDK DIVERGENCE: this row is Android/rcli-only. The
// pinned llama.cpp fork's `nemotron` path was load/inference checked for
// this exact Q4_K_M artifact through rcli on macOS (not yet an on-device
// Android smoke). iOS deliberately withholds it (ModelCatalogBootstrap:
// pending an Apple-provider inference smoke) and the Web catalog omits it
// (its ~4.92 GB single artifact exceeds the browser WASM32 4 GiB gate).
// Hold or re-scope this row if the Android llama.cpp path has to clear the
// same on-device bar iOS requires.
SingleFileModel(
"llama-3.1-nemotron-nano-4b-v1.1-q4_k_m",
"NVIDIA Llama 3.1 Nemotron Nano 4B v1.1 Q4_K_M",
Expand All @@ -512,6 +382,15 @@ internal object ModelCatalog {
downloadBytes = 4_920_736_864L,
contextLength = 4_096,
),
SingleFileModel(
"nemotron-mini-4b-instruct-q4_k_m",
"NVIDIA Nemotron Mini 4B Instruct Q4_K_M",
"https://huggingface.co/bartowski/Nemotron-Mini-4B-Instruct-GGUF/resolve/fb49cde090c86092d89905bea2ffc41c23c2615e/Nemotron-Mini-4B-Instruct-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
2_697_387_072,
contextLength = 4_096
),
// Bonsai (PrismML)
// Bonsai family at TRUE 1-bit (Q1_0, ~1.125 bit/wt) on CPU via llama.cpp — the same GGUF
// that runs on the NPU (bonsai_{4b,8b,27b}_1bit, QHEXRT). Requires a llama.cpp build with
Expand Down Expand Up @@ -562,6 +441,58 @@ internal object ModelCatalog {
// "invalid ggml type 142" — it only added Q1_0 (plain Bonsai) support, not
// Ternary-Bonsai's tensor encoding. Re-enable once the fork adds it.
// Ternary-Bonsai MLX works fine (iOS/macOS only — no MLX on Android).

// Added from the verified model list.
SingleFileModel(
"lfm2.5-1.2b-thinking-q4_k_m",
"LFM2.5 1.2B Thinking Q4_K_M",
"https://huggingface.co/LiquidAI/LFM2.5-1.2B-Thinking-GGUF/resolve/main/LFM2.5-1.2B-Thinking-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
memoryBytes = 900_000_000,
downloadBytes = 730_895_360,
supportsThinking = true
),
SingleFileModel(
"qwen3.5-2b-q4_k_m",
"Qwen3.5 2B Q4_K_M",
"https://huggingface.co/unsloth/Qwen3.5-2B-GGUF/resolve/main/Qwen3.5-2B-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
memoryBytes = 1_550_000_000,
downloadBytes = 1_280_835_840,
supportsThinking = true
),
SingleFileModel(
"qwen3.5-4b-q4_k_m",
"Qwen3.5 4B Q4_K_M",
"https://huggingface.co/unsloth/Qwen3.5-4B-GGUF/resolve/main/Qwen3.5-4B-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
memoryBytes = 3_350_000_000,
downloadBytes = 2_740_937_888,
supportsThinking = true
),
SingleFileModel(
"qwen3.5-9b-q4_k_m",
"Qwen3.5 9B Q4_K_M",
"https://huggingface.co/unsloth/Qwen3.5-9B-GGUF/resolve/main/Qwen3.5-9B-Q4_K_M.gguf",
LLAMA,
LANGUAGE,
memoryBytes = 6_950_000_000,
downloadBytes = 5_680_522_464,
supportsThinking = true
),
SingleFileModel(
"maple-preview-tq1_0",
"Maple Preview 20B-A1B TQ1_0 (1-bit)",
"https://huggingface.co/deepgrove/maple-preview-GGUF/resolve/main/maple-preview-TQ1_0-head-Q4_K.gguf",
LLAMA,
LANGUAGE,
memoryBytes = 6_100_000_000,
downloadBytes = 4_984_016_416,
supportsThinking = true
),
)

// --- VLM (llama.cpp, multimodal) ------------------------------------------
Expand Down Expand Up @@ -603,47 +534,6 @@ internal object ModelCatalog {
TAR_GZ,
ArchiveStructure.ARCHIVE_STRUCTURE_DIRECTORY_BASED
),
// Qwen (2-VL, then 2.5-VL)
MultiFileModel(
"qwen2-vl-2b-instruct-q4_k_m", "Qwen2-VL 2B Instruct", LLAMA, MULTIMODAL, 1_800_000_000,
files = listOf(
ModelFile(
"https://huggingface.co/ggml-org/Qwen2-VL-2B-Instruct-GGUF/resolve/main/Qwen2-VL-2B-Instruct-Q4_K_M.gguf",
"Qwen2-VL-2B-Instruct-Q4_K_M.gguf"
),
ModelFile(
"https://huggingface.co/ggml-org/Qwen2-VL-2B-Instruct-GGUF/resolve/main/mmproj-Qwen2-VL-2B-Instruct-Q8_0.gguf",
"mmproj-Qwen2-VL-2B-Instruct-Q8_0.gguf"
),
),
),
MultiFileModel(
"qwen2.5-vl-3b-instruct-q4_k_m", "Qwen2.5-VL 3B Instruct Q4_K_M", LLAMA, MULTIMODAL, 2_800_000_000,
files = listOf(
ModelFile(
"https://huggingface.co/ggml-org/Qwen2.5-VL-3B-Instruct-GGUF/resolve/main/Qwen2.5-VL-3B-Instruct-Q4_K_M.gguf",
"Qwen2.5-VL-3B-Instruct-Q4_K_M.gguf"
),
ModelFile(
"https://huggingface.co/ggml-org/Qwen2.5-VL-3B-Instruct-GGUF/resolve/main/mmproj-Qwen2.5-VL-3B-Instruct-Q8_0.gguf",
"mmproj-Qwen2.5-VL-3B-Instruct-Q8_0.gguf"
),
),
),
// LFM2-VL / LFM2.5-VL (Liquid AI)
MultiFileModel(
"lfm2-vl-450m-q8_0", "LFM2-VL 450M", LLAMA, MULTIMODAL, 600_000_000,
files = listOf(
ModelFile(
"https://huggingface.co/runanywhere/LFM2-VL-450M-GGUF/resolve/main/LFM2-VL-450M-Q8_0.gguf",
"LFM2-VL-450M-Q8_0.gguf"
),
ModelFile(
"https://huggingface.co/runanywhere/LFM2-VL-450M-GGUF/resolve/main/mmproj-LFM2-VL-450M-Q8_0.gguf",
"mmproj-LFM2-VL-450M-Q8_0.gguf"
),
),
),
// Q4_K_M, matching the Qwen2.5-VL 3B row beside it and the LFM2.5 2.6B LLM
// row this VLM is built on: one quantization per model, and Q4_K_M is what
// every other 3B-class GGUF row in this catalog ships. The mmproj is Q8_0
Expand Down Expand Up @@ -706,9 +596,10 @@ internal object ModelCatalog {
MultiFileModel(
"gemma-4-e4b-it-q4_k_m", "Gemma 4 E4B IT Q4_K_M (Experimental)", LLAMA, MULTIMODAL, 5_500_000_000,
files = listOf(
// ggml-org publishes no Q4_K_M for this repo — Q4_0 is its only 4-bit build.
ModelFile(
"https://huggingface.co/ggml-org/gemma-4-E4B-it-GGUF/resolve/main/gemma-4-E4B-it-Q4_K_M.gguf",
"gemma-4-E4B-it-Q4_K_M.gguf"
"https://huggingface.co/ggml-org/gemma-4-E4B-it-GGUF/resolve/main/gemma-4-E4B-it-Q4_0.gguf",
"gemma-4-E4B-it-Q4_0.gguf"
),
ModelFile(
"https://huggingface.co/ggml-org/gemma-4-E4B-it-GGUF/resolve/main/mmproj-gemma-4-E4B-it-Q8_0.gguf",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ object ModelRecommendation {
// Curated GGUF LLM ids, ordered best-first (product preference, not device fit).
private val preferredGgufLLMs: List<String> = listOf(
"lfm2.5-1.2b-instruct-q4_k_m",
"qwen3-1.7b-q4_k_m",
"lfm2-1.2b-tool-q4_k_m",
"qwen3-0.6b-q4_k_m",
"qwen2.5-0.5b-instruct-q6_k",
"lfm2-350m-q4_k_m",
"qwen3.5-2b-q4_k_m",
"lfm2.5-1.2b-thinking-q4_k_m",
"qwen3.5-0.8b-q4_k_m",
"granite-4.1-3b-q4_k_m",
"lfm2.5-230m-q4_k_m",
"bonsai-1.7b-q1_0",
)

// HNPU (QHexRT) LLMs surfaced first when the device reports a Hexagon NPU.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ enum class ModelOrg(val brand: Brand) {
ALIBABA(RACBrands.Alibaba),
GOOGLE(RACBrands.Google),
MICROSOFT(RACBrands.Microsoft),
IBM(RACBrands.Ibm),
DEEPSEEK(RACBrands.DeepSeek),
LIQUID(RACBrands.Liquid),
MISTRAL(RACBrands.Mistral),
PRISM(RACBrands.Prism),
DEEPGROVE(RACBrands.Deepgrove),
OPENAI(RACBrands.OpenAI),
ZHIPU(RACBrands.Zhipu),
HUGGING_FACE(RACBrands.HuggingFace),
APPLE(RACBrands.Apple),
OPEN_SOURCE(RACBrands.OpenSource),
Expand Down Expand Up @@ -55,14 +58,20 @@ private val orgSpecs: List<OrgSpec> = listOf(
),
org(ModelOrg.DEEPSEEK, "deepseek"),
org(ModelOrg.PRISM, "bonsai"),
org(ModelOrg.MICROSOFT, "phi"),
org(ModelOrg.DEEPGROVE, "maple"),
org(ModelOrg.IBM, "granite"),
// "fara" sits with Microsoft's "phi" rather than on its own: Fara1.5 ships
// mirrored under our own HF org, so the catalog row names no publisher.
// Filing it by its own name beats guessing one into a UI label.
org(ModelOrg.MICROSOFT, "phi", "fara"),
org(ModelOrg.GOOGLE, "gemma", "embeddinggemma", "siglip"),
org(ModelOrg.META, "llama"),
org(ModelOrg.META, "llama", "muse-glimmer", "muse_glimmer"),
org(ModelOrg.ALIBABA, "qwen"),
org(ModelOrg.LIQUID, "lfm2"),
org(ModelOrg.MISTRAL, "mistral"),
org(ModelOrg.MISTRAL, "mistral", "ministral"),
org(ModelOrg.HUGGING_FACE, "smollm", "smolvlm"),
org(ModelOrg.OPENAI, "whisper"),
org(ModelOrg.ZHIPU, "glm"),
org(
ModelOrg.OPEN_SOURCE,
"internvl",
Expand Down
Loading