1 // Copyright 2026 Splitfire AB (Onde Inference). All rights reserved.
2 // SPDX-License-Identifier: MIT OR Apache-2.0
3
4 /// Pre-quantized Qwen 2.5 1.5B Instruct (GGUF Q4_K_M) — lightest mobile option (~941 MB).
5 /// Fits comfortably on both iOS (iPhone 16e, 8 GB RAM) and Android memory-constrained devices.
6 /// Note: the 3B variant (~1.93 GB) caused OOM on iPhone 16e because iOS gives apps only ~2-3 GB;
7 /// the 1.5B variant at ~941 MB leaves comfortable headroom for KV cache, activations, and the app.
8 /// bartowski's GGUF embeds the full tokenizer and Qwen2.5 chat template, so on iOS/macOS no
9 /// separate tok_model_id download is needed. On Android an explicit tok_model_id is required.
10 pub const BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF: &str = "bartowski/Qwen2.5-1.5B-Instruct-GGUF";
11 /// The specific GGUF filename to download from the bartowski 1.5B repo.
12 pub const QWEN25_1_5B_GGUF_FILE: &str = "Qwen2.5-1.5B-Instruct-Q4_K_M.gguf";
13 /// Base model repo used for the HF tokenizer on Android.
14 /// On Android, GGUF loading requires an explicit tokenizer source; on iOS/macOS the tokenizer
15 /// embedded in the GGUF file is used instead to avoid an extra network download.
16 pub const QWEN25_1_5B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-1.5B-Instruct";
17
18 /// Pre-quantized Qwen 2.5 0.5B Instruct (GGUF Q4_K_M), smallest model (~380 MB).
19 /// Used on tvOS (Apple TV 4K) where the hard memory limit is 2 GB.
20 pub const BARTOWSKI_QWEN25_0_5B_INSTRUCT_GGUF: &str = "bartowski/Qwen2.5-0.5B-Instruct-GGUF";
21 /// The specific GGUF filename to download from the bartowski 0.5B repo.
22 pub const QWEN25_0_5B_GGUF_FILE: &str = "Qwen2.5-0.5B-Instruct-Q4_K_M.gguf";
23 /// Base model repo used for the HF tokenizer on Android.
24 pub const QWEN25_0_5B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-0.5B-Instruct";
25
26 /// Pre-quantized Qwen 2.5 Coder 1.5B Instruct (GGUF Q4_K_M) — dedicated coding model (~941 MB).
27 ///
28 /// Uses the `qwen2` GGUF architecture, identical to Qwen2.5-1.5B-Instruct, so it loads through
29 /// the existing `quantized_qwen.rs` path in mistral.rs without any code changes.
30 ///
31 /// Strongly preferred over the general-purpose 1.5B for coding tasks: trained on 5.5T tokens of
32 /// code and math data, with fill-in-the-middle (FIM) and repo-level code understanding.
33 /// Same memory footprint as the general 1.5B (~941 MB) but dramatically better at code.
34 ///
35 /// bartowski's GGUF embeds the full tokenizer and chat template, so on iOS/macOS no separate
36 /// tok_model_id download is needed. On Android an explicit tok_model_id is required.
37 pub const BARTOWSKI_QWEN25_CODER_1_5B_INSTRUCT_GGUF: &str =
38 "bartowski/Qwen2.5-Coder-1.5B-Instruct-GGUF";
39 /// The specific GGUF filename to download from the bartowski Coder 1.5B repo.
40 pub const QWEN25_CODER_1_5B_GGUF_FILE: &str = "Qwen2.5-Coder-1.5B-Instruct-Q4_K_M.gguf";
41 /// Base model repo used for the HF tokenizer on Android.
42 pub const QWEN25_CODER_1_5B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-Coder-1.5B-Instruct";
43
44 /// HuggingFace repo for the full-precision Qwen 2.5 Coder 7B Instruct model.
45 ///
46 /// Used by ISQ pipelines (`TextModelBuilder`) which download the safetensors weights
47 /// directly and quantise them in-situ on the device. Unlike the bartowski GGUF
48 /// variants, this repo ships the original BF16 weights; mistral.rs handles
49 /// quantisation to Q4K or Q8_0 at load time via the `--isq` flag.
50 ///
51 /// Requires ~8 GB RAM during the load phase (4-bit); ~12 GB for 8-bit.
52 /// Metal-accelerated on macOS; CPU fallback available but very slow.
53 pub const QWEN25_CODER_7B_INSTRUCT: &str = "Qwen/Qwen2.5-Coder-7B-Instruct";
54
55 /// Pre-quantized Qwen 2.5 Coder 3B Instruct (GGUF Q4_K_M) — best coding quality on macOS (~1.93 GB).
56 ///
57 /// Same `qwen2` architecture as the 3B general model; ideal for macOS desktops where the extra
58 /// quality headroom over the 1.5B is worthwhile. Not recommended for iOS (OOM risk).
59 pub const BARTOWSKI_QWEN25_CODER_3B_INSTRUCT_GGUF: &str =
60 "bartowski/Qwen2.5-Coder-3B-Instruct-GGUF";
61 /// The specific GGUF filename to download from the bartowski Coder 3B repo.
62 pub const QWEN25_CODER_3B_GGUF_FILE: &str = "Qwen2.5-Coder-3B-Instruct-Q4_K_M.gguf";
63 /// Base model repo used for the HF tokenizer on Android.
64 pub const QWEN25_CODER_3B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-Coder-3B-Instruct";
65
66 /// Pre-quantized Qwen 2.5 Coder 7B Instruct (GGUF Q4_K_M) — strong coding model with tool calling (~4.4 GB).
67 ///
68 /// Uses the `qwen2` GGUF architecture. Trained on 5.5T tokens of code/math data with
69 /// fill-in-the-middle and repo-level code understanding. Supports function/tool calling
70 /// via the Qwen2.5 chat template. Requires ~8 GB RAM.
71 pub const BARTOWSKI_QWEN25_CODER_7B_INSTRUCT_GGUF: &str =
72 "bartowski/Qwen2.5-Coder-7B-Instruct-GGUF";
73 /// The specific GGUF filename to download from the bartowski Coder 7B repo.
74 pub const QWEN25_CODER_7B_GGUF_FILE: &str = "Qwen2.5-Coder-7B-Instruct-Q4_K_M.gguf";
75 /// Base model repo used for the HF tokenizer on Android.
76 pub const QWEN25_CODER_7B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-Coder-7B-Instruct";
77
78 /// Pre-quantized Qwen 2.5 3B Instruct (GGUF Q4_K_M) — balanced option (~1.93 GB).
79 /// Ideal for macOS desktops and Android devices with sufficient RAM.
80 /// Not recommended as default on iOS: the 3B variant caused OOM on iPhone 16e (8 GB RAM)
81 /// because iOS gives apps only ~2-3 GB; use the 1.5B variant for iOS instead.
82 /// No in-situ quantization needed; loads directly at quantized size.
83 pub const BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF: &str = "bartowski/Qwen2.5-3B-Instruct-GGUF";
84 /// The specific GGUF filename to download from the bartowski 3B repo.
85 pub const QWEN25_3B_GGUF_FILE: &str = "Qwen2.5-3B-Instruct-Q4_K_M.gguf";
86 /// Base model repo used for the HF tokenizer (tokenizer.json + tokenizer_config.json).
87 pub const QWEN25_3B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-3B-Instruct";
88
89 // ── Qwen 3 family (GGUF Q4_K_M) ──────────────────────────────────────────────
90 //
91 // The Qwen 3 line uses the `qwen3` GGUF architecture (and `qwen3moe` for the
92 // 30B-A3B mixture-of-experts variant), both supported by mistral.rs's quantized
93 // loader. Every Qwen 3 model is a hybrid reasoner with an extended thinking mode
94 // (`<think>…</think>`); always load with `max_tokens ≥ 4096` so the thinking
95 // block does not exhaust the token budget before the real reply.
96 //
97 // bartowski's repos embed the tokenizer and chat template inside the GGUF, so on
98 // iOS/macOS no separate tokenizer download is needed. On Android the candle GGUF
99 // backend cannot parse the embedded tokenizer, so each model also declares a
100 // `TOK_MODEL_ID` pointing at the official Qwen repo for a standalone tokenizer.
101
102 /// Pre-quantized Qwen 3 0.6B (GGUF Q4_K_M) — smallest Qwen 3 variant (~0.5 GB).
103 ///
104 /// Lightest tool-capable Qwen 3 model. Suitable for tvOS and the most
105 /// memory-constrained mobile devices where even the 1.7B is too large.
106 pub const BARTOWSKI_QWEN3_0_6B_GGUF: &str = "bartowski/Qwen_Qwen3-0.6B-GGUF";
107 /// The specific GGUF filename for the bartowski Qwen 3 0.6B repo.
108 pub const QWEN3_0_6B_GGUF_FILE: &str = "Qwen_Qwen3-0.6B-Q4_K_M.gguf";
109 /// Base model repo used for the HF tokenizer on Android.
110 pub const QWEN3_0_6B_TOK_MODEL_ID: &str = "Qwen/Qwen3-0.6B";
111
112 /// Pre-quantized Qwen 3 1.7B (GGUF Q4_K_M) — lightweight tool-calling model (~1.3 GB).
113 ///
114 /// Smallest Qwen 3 variant with comfortable tool calling. Suitable for mobile
115 /// devices where the 4B model would be too large.
116 pub const BARTOWSKI_QWEN3_1_7B_GGUF: &str = "bartowski/Qwen_Qwen3-1.7B-GGUF";
117 /// The specific GGUF filename for the Qwen3 1.7B repo.
118 pub const QWEN3_1_7B_GGUF_FILE: &str = "Qwen_Qwen3-1.7B-Q4_K_M.gguf";
119 /// Base model repo used for the HF tokenizer on Android.
120 pub const QWEN3_1_7B_TOK_MODEL_ID: &str = "Qwen/Qwen3-1.7B";
121
122 /// Pre-quantized Qwen 3 4B (GGUF Q4_K_M) — full OpenAI-compatible tool calling (~2.7 GB).
123 ///
124 /// Recommended model for siGit Code (coding agent with tool calling on macOS/Linux/Windows).
125 pub const BARTOWSKI_QWEN3_4B_GGUF: &str = "bartowski/Qwen_Qwen3-4B-GGUF";
126 /// The specific GGUF filename to download from the bartowski Qwen 3 4B repo.
127 pub const QWEN3_4B_GGUF_FILE: &str = "Qwen_Qwen3-4B-Q4_K_M.gguf";
128 /// Base model repo used for the HF tokenizer on Android.
129 pub const QWEN3_4B_TOK_MODEL_ID: &str = "Qwen/Qwen3-4B";
130
131 /// Pre-quantized Qwen 3 8B (GGUF Q4_K_M) — strong tool-calling model (~5 GB).
132 ///
133 /// Best balance of quality and memory for macOS with 24+ GB RAM.
134 /// Full tool calling and extended thinking mode support.
135 pub const BARTOWSKI_QWEN3_8B_GGUF: &str = "bartowski/Qwen_Qwen3-8B-GGUF";
136 pub const QWEN3_8B_GGUF_FILE: &str = "Qwen_Qwen3-8B-Q4_K_M.gguf";
137 /// Base model repo used for the HF tokenizer on Android.
138 pub const QWEN3_8B_TOK_MODEL_ID: &str = "Qwen/Qwen3-8B";
139
140 /// Pre-quantized Qwen 3 14B (GGUF Q4_K_M) — strong reasoning and tool-calling model (~8.4 GB).
141 ///
142 /// Best all-around model for macOS with 16+ GB RAM. Full tool calling support.
143 pub const BARTOWSKI_QWEN3_14B_GGUF: &str = "bartowski/Qwen_Qwen3-14B-GGUF";
144 /// The specific GGUF filename.
145 pub const QWEN3_14B_GGUF_FILE: &str = "Qwen_Qwen3-14B-Q4_K_M.gguf";
146 /// Base model repo used for the HF tokenizer on Android.
147 pub const QWEN3_14B_TOK_MODEL_ID: &str = "Qwen/Qwen3-14B";
148
149 /// Pre-quantized Qwen 3 32B (GGUF Q4_K_M) — largest dense Qwen 3 model (~19.8 GB).
150 ///
151 /// Highest-quality dense Qwen 3 variant. Requires a high-memory desktop
152 /// (32+ GB RAM / unified memory). Full tool calling and extended thinking.
153 pub const BARTOWSKI_QWEN3_32B_GGUF: &str = "bartowski/Qwen_Qwen3-32B-GGUF";
154 /// The specific GGUF filename for the bartowski Qwen 3 32B repo.
155 pub const QWEN3_32B_GGUF_FILE: &str = "Qwen_Qwen3-32B-Q4_K_M.gguf";
156 /// Base model repo used for the HF tokenizer on Android.
157 pub const QWEN3_32B_TOK_MODEL_ID: &str = "Qwen/Qwen3-32B";
158
159 // ── Qwen 3 "2507" updated releases ───────────────────────────────────────────
160 //
161 // The July/August 2025 refresh split Qwen 3 into dedicated non-thinking
162 // (`-Instruct-2507`) and thinking-only (`-Thinking-2507`) checkpoints with
163 // markedly improved instruction following, tool use, and long-context quality.
164 // These are the latest open Qwen 3 weights available as on-device GGUF.
165
166 /// Pre-quantized Qwen 3 4B Instruct 2507 (GGUF Q4_K_M) — latest non-thinking 4B (~2.5 GB).
167 ///
168 /// Updated instruction-tuned checkpoint. Unlike the base 4B it does *not* emit a
169 /// `<think>` block, so it is faster and more predictable for chat and tool use.
170 pub const BARTOWSKI_QWEN3_4B_INSTRUCT_2507_GGUF: &str =
171 "bartowski/Qwen_Qwen3-4B-Instruct-2507-GGUF";
172 /// The specific GGUF filename for the bartowski Qwen 3 4B Instruct 2507 repo.
173 pub const QWEN3_4B_INSTRUCT_2507_GGUF_FILE: &str = "Qwen_Qwen3-4B-Instruct-2507-Q4_K_M.gguf";
174 /// Base model repo used for the HF tokenizer on Android.
175 pub const QWEN3_4B_INSTRUCT_2507_TOK_MODEL_ID: &str = "Qwen/Qwen3-4B-Instruct-2507";
176
177 /// Pre-quantized Qwen 3 4B Thinking 2507 (GGUF Q4_K_M) — latest reasoning 4B (~2.5 GB).
178 ///
179 /// Updated thinking-only checkpoint with stronger reasoning and tool-use accuracy.
180 /// Always emits a `<think>` block — load with `max_tokens ≥ 4096`.
181 pub const BARTOWSKI_QWEN3_4B_THINKING_2507_GGUF: &str =
182 "bartowski/Qwen_Qwen3-4B-Thinking-2507-GGUF";
183 /// The specific GGUF filename for the bartowski Qwen 3 4B Thinking 2507 repo.
184 pub const QWEN3_4B_THINKING_2507_GGUF_FILE: &str = "Qwen_Qwen3-4B-Thinking-2507-Q4_K_M.gguf";
185 /// Base model repo used for the HF tokenizer on Android.
186 pub const QWEN3_4B_THINKING_2507_TOK_MODEL_ID: &str = "Qwen/Qwen3-4B-Thinking-2507";
187
188 /// Pre-quantized Qwen 3 30B-A3B Instruct 2507 (GGUF Q4_K_M) — flagship MoE (~18.6 GB).
189 ///
190 /// Mixture-of-experts model: 30B total parameters but only ~3B active per token,
191 /// so inference is far cheaper than a 30B dense model while quality rivals it.
192 /// Loads via the `qwen3moe` GGUF architecture in mistral.rs. Requires a
193 /// high-memory desktop (32+ GB RAM / unified memory).
194 pub const BARTOWSKI_QWEN3_30B_A3B_INSTRUCT_2507_GGUF: &str =
195 "bartowski/Qwen_Qwen3-30B-A3B-Instruct-2507-GGUF";
196 /// The specific GGUF filename for the bartowski Qwen 3 30B-A3B Instruct 2507 repo.
197 pub const QWEN3_30B_A3B_INSTRUCT_2507_GGUF_FILE: &str =
198 "Qwen_Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf";
199 /// Base model repo used for the HF tokenizer on Android.
200 pub const QWEN3_30B_A3B_INSTRUCT_2507_TOK_MODEL_ID: &str = "Qwen/Qwen3-30B-A3B-Instruct-2507";
201
202 /// DeepSeek Coder v1 6.7B Instruct (GGUF Q4_K_M) — dedicated code generation model (~3.8 GB).
203 ///
204 /// Uses the `llama` GGUF architecture, so it loads through the existing
205 /// `quantized_llama.rs` path in mistral.rs without any code changes.
206 /// Strong coding performance. Requires ~8 GB RAM.
207 pub const THEBLOKE_DEEPSEEK_CODER_6_7B_INSTRUCT_GGUF: &str =
208 "TheBloke/deepseek-coder-6.7B-instruct-GGUF";
209 /// The specific GGUF filename.
210 pub const DEEPSEEK_CODER_6_7B_GGUF_FILE: &str = "deepseek-coder-6.7b-instruct.Q4_K_M.gguf";
211 /// Base model repo used for the HF tokenizer on Android.
212 pub const DEEPSEEK_CODER_6_7B_TOK_MODEL_ID: &str = "deepseek-ai/deepseek-coder-6.7b-instruct";
213
214 /// All model IDs that the Onde inference engine supports.
215 /// Used by `list_local_hf_models` to filter the HuggingFace cache
216 /// to only show models that can actually be used for generation.
217 pub const SUPPORTED_MODELS: &[&str] = &[
218 BARTOWSKI_QWEN25_0_5B_INSTRUCT_GGUF,
219 BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF,
220 BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF,
221 BARTOWSKI_QWEN3_0_6B_GGUF,
222 BARTOWSKI_QWEN3_1_7B_GGUF,
223 BARTOWSKI_QWEN3_4B_GGUF,
224 BARTOWSKI_QWEN3_8B_GGUF,
225 BARTOWSKI_QWEN3_14B_GGUF,
226 BARTOWSKI_QWEN3_32B_GGUF,
227 BARTOWSKI_QWEN3_4B_INSTRUCT_2507_GGUF,
228 BARTOWSKI_QWEN3_4B_THINKING_2507_GGUF,
229 BARTOWSKI_QWEN3_30B_A3B_INSTRUCT_2507_GGUF,
230 BARTOWSKI_QWEN25_CODER_7B_INSTRUCT_GGUF,
231 THEBLOKE_DEEPSEEK_CODER_6_7B_INSTRUCT_GGUF,
232 ];
233
234 /// Catalogued models Onde has verified for structured tool calling.
235 ///
236 /// Every Qwen 3 repo routes through mistral.rs' Qwen tool parser. Qwen 2.5
237 /// Coder 7B is the one Qwen 2.5 model in the catalogue verified alongside it.
238 /// Entries must also appear in [`SUPPORTED_MODELS`].
239 pub const TOOL_CALLING_MODELS: &[&str] = &[
240 BARTOWSKI_QWEN3_0_6B_GGUF,
241 BARTOWSKI_QWEN3_1_7B_GGUF,
242 BARTOWSKI_QWEN3_4B_GGUF,
243 BARTOWSKI_QWEN3_8B_GGUF,
244 BARTOWSKI_QWEN3_14B_GGUF,
245 BARTOWSKI_QWEN3_32B_GGUF,
246 BARTOWSKI_QWEN3_4B_INSTRUCT_2507_GGUF,
247 BARTOWSKI_QWEN3_4B_THINKING_2507_GGUF,
248 BARTOWSKI_QWEN3_30B_A3B_INSTRUCT_2507_GGUF,
249 BARTOWSKI_QWEN25_CODER_7B_INSTRUCT_GGUF,
250 ];
251
252 /// Return Onde's verified tool-calling capability for a model repository.
253 ///
254 /// The three answers mean different things, and callers should treat them
255 /// differently:
256 ///
257 /// - `Supported` — catalogued and verified. Use tools freely.
258 /// - `Unsupported` — catalogued, and *not* verified for tool calling. This is
259 /// Onde's own test coverage talking, not an upstream capability claim: some
260 /// of these models ship tool-call templates and may well work. A caller that
261 /// wants to try one anyway should, but should not present it as supported.
262 /// - `Unknown` — not in the catalogue at all. Onde has no opinion. Callers may
263 /// try these, but should surface that the capability is unverified.
264 ///
265 /// Matching is exact. A custom repository whose name merely resembles a
266 /// catalogued one (`acme/my-qwen3-finetune`) is `Unknown`, not `Supported` —
267 /// Onde has not tested it, and a name is not a verification.
268 pub fn tool_calling_support(model_id: &str) -> super::types::ToolCallingSupport {
269 use super::types::ToolCallingSupport;
270
271 if TOOL_CALLING_MODELS.contains(&model_id) {
272 ToolCallingSupport::Supported
273 } else if SUPPORTED_MODELS.contains(&model_id) {
274 ToolCallingSupport::Unsupported
275 } else {
276 ToolCallingSupport::Unknown
277 }
278 }
279
280 /// Rich metadata for a supported model, used by the frontend to display
281 /// unavailable models that can be downloaded.
282 pub struct SupportedModelInfo {
283 /// The full HuggingFace model identifier, e.g. "bartowski/Qwen2.5-1.5B-Instruct-GGUF".
284 pub id: &'static str,
285 /// Human-friendly display name for the model.
286 pub name: &'static str,
287 /// Organisation or publisher display name.
288 pub org: &'static str,
289 /// Short description of the model's purpose / capabilities.
290 pub description: &'static str,
291 /// Approximate total size in bytes when fully downloaded.
292 /// Used by the progress monitor to estimate download percentage.
293 ///
294 /// These values are computed by summing every file in the model's
295 /// HuggingFace repository (via the `/api/models/{id}?blobs=true`
296 /// endpoint's `siblings[].size` fields).
297 pub expected_size_bytes: u64,
298 }
299
300 /// Complete list of supported models with display metadata.
301 ///
302 /// When adding a new model, add its constant ID to [`SUPPORTED_MODELS`] **and**
303 /// a corresponding entry here so the frontend can show it in the model list UI.
304 pub const SUPPORTED_MODEL_INFO: &[SupportedModelInfo] = &[
305 SupportedModelInfo {
306 id: BARTOWSKI_QWEN25_0_5B_INSTRUCT_GGUF,
307 name: "Qwen 2.5 0.5B (GGUF)",
308 org: "Qwen / Alibaba",
309 description: "Smallest pre-quantized chat model, used on tvOS Apple TV (~380 MB).",
310 expected_size_bytes: 397_808_192,
311 },
312 SupportedModelInfo {
313 id: BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF,
314 name: "Qwen 2.5 1.5B (GGUF)",
315 org: "Qwen / Alibaba",
316 description: "Lightest pre-quantized chat model — ideal for iOS & Android (~941 MB). \
317 Fits comfortably within iOS memory limits (iPhone 16e, 8 GB RAM).",
318 // Qwen2.5-1.5B-Instruct-Q4_K_M.gguf from bartowski repo.
319 // Exact file size from HuggingFace API siblings[].size.
320 expected_size_bytes: 986_048_768,
321 },
322 SupportedModelInfo {
323 id: BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF,
324 name: "Qwen 2.5 3B (GGUF)",
325 org: "Qwen / Alibaba",
326 description:
327 "Pre-quantized chat model for macOS & Android — balanced quality and size (~1.93 GB). \
328 Not recommended as default on iOS due to memory constraints.",
329 // Qwen2.5-3B-Instruct-Q4_K_M.gguf from bartowski repo.
330 // Exact file size from HuggingFace API siblings[].size.
331 expected_size_bytes: 1_929_903_264,
332 },
333 SupportedModelInfo {
334 id: BARTOWSKI_QWEN3_0_6B_GGUF,
335 name: "Qwen 3 0.6B (GGUF)",
336 org: "Qwen / Alibaba",
337 description: "Smallest Qwen 3 variant with tool calling (~0.5 GB). \
338 Suitable for tvOS and the most memory-constrained mobile devices.",
339 // Exact Q4_K_M file size from HuggingFace API siblings[].size.
340 expected_size_bytes: 484_220_320,
341 },
342 SupportedModelInfo {
343 id: BARTOWSKI_QWEN3_1_7B_GGUF,
344 name: "Qwen 3 1.7B (GGUF)",
345 org: "Qwen / Alibaba",
346 description: "Lightweight tool-calling model for mobile (~1.3 GB). \
347 Smallest Qwen 3 variant with comfortable tool calling support.",
348 expected_size_bytes: 1_282_439_584,
349 },
350 SupportedModelInfo {
351 id: BARTOWSKI_QWEN3_4B_GGUF,
352 name: "Qwen 3 4B (GGUF)",
353 org: "Qwen / Alibaba",
354 description: "Full tool-calling support with extended reasoning mode (~2.7 GB). \
355 Recommended for siGit Code on macOS, Linux, and Windows.",
356 // Qwen_Qwen3-4B-Q4_K_M.gguf from bartowski repo.
357 expected_size_bytes: 2_497_280_960,
358 },
359 SupportedModelInfo {
360 id: BARTOWSKI_QWEN3_8B_GGUF,
361 name: "Qwen 3 8B (GGUF)",
362 org: "Qwen / Alibaba",
363 description: "Strong tool-calling model with extended thinking (~5 GB). \
364 Best balance of quality and memory for macOS with 24+ GB RAM.",
365 expected_size_bytes: 5_027_784_224,
366 },
367 SupportedModelInfo {
368 id: BARTOWSKI_QWEN3_14B_GGUF,
369 name: "Qwen 3 14B (GGUF)",
370 org: "Qwen / Alibaba",
371 description: "Strong reasoning and tool-calling model with extended thinking (~8.4 GB). \
372 Best all-around model for macOS with 16+ GB RAM.",
373 // Qwen_Qwen3-14B-Q4_K_M.gguf from bartowski repo.
374 // Exact file size from HuggingFace API siblings[].size.
375 expected_size_bytes: 9_001_753_632,
376 },
377 SupportedModelInfo {
378 id: BARTOWSKI_QWEN3_32B_GGUF,
379 name: "Qwen 3 32B (GGUF)",
380 org: "Qwen / Alibaba",
381 description: "Largest dense Qwen 3 model with extended thinking (~19.8 GB). \
382 Highest-quality dense variant; requires 32+ GB RAM.",
383 // Exact Q4_K_M file size from HuggingFace API siblings[].size.
384 expected_size_bytes: 19_762_149_696,
385 },
386 SupportedModelInfo {
387 id: BARTOWSKI_QWEN3_4B_INSTRUCT_2507_GGUF,
388 name: "Qwen 3 4B Instruct 2507 (GGUF)",
389 org: "Qwen / Alibaba",
390 description: "Latest non-thinking 4B checkpoint — faster, predictable chat and \
391 tool use (~2.5 GB). Recommended general-purpose Qwen 3 model.",
392 // Exact Q4_K_M file size from HuggingFace API siblings[].size.
393 expected_size_bytes: 2_497_280_736,
394 },
395 SupportedModelInfo {
396 id: BARTOWSKI_QWEN3_4B_THINKING_2507_GGUF,
397 name: "Qwen 3 4B Thinking 2507 (GGUF)",
398 org: "Qwen / Alibaba",
399 description: "Latest reasoning-focused 4B checkpoint with extended thinking (~2.5 GB). \
400 Stronger reasoning and tool-use accuracy; load with max_tokens ≥ 4096.",
401 // Exact Q4_K_M file size from HuggingFace API siblings[].size.
402 expected_size_bytes: 2_497_280_736,
403 },
404 SupportedModelInfo {
405 id: BARTOWSKI_QWEN3_30B_A3B_INSTRUCT_2507_GGUF,
406 name: "Qwen 3 30B-A3B Instruct 2507 (GGUF)",
407 org: "Qwen / Alibaba",
408 description: "Flagship mixture-of-experts model: 30B total / ~3B active (~18.6 GB). \
409 Near-dense quality at far lower inference cost; requires 32+ GB RAM.",
410 // Exact Q4_K_M file size from HuggingFace API siblings[].size.
411 expected_size_bytes: 18_632_183_808,
412 },
413 SupportedModelInfo {
414 id: BARTOWSKI_QWEN25_CODER_7B_INSTRUCT_GGUF,
415 name: "Qwen 2.5 Coder 7B (GGUF)",
416 org: "Qwen / Alibaba",
417 description: "Strong coding model with tool calling support (~4.4 GB). \
418 Trained on 5.5T code tokens. Requires 8+ GB RAM.",
419 expected_size_bytes: 4_683_074_336,
420 },
421 SupportedModelInfo {
422 id: THEBLOKE_DEEPSEEK_CODER_6_7B_INSTRUCT_GGUF,
423 name: "DeepSeek Coder 6.7B (GGUF)",
424 org: "DeepSeek AI",
425 description: "Strong code generation model using the llama architecture (~3.8 GB). \
426 Requires 8+ GB RAM. Not recommended for mobile devices.",
427 expected_size_bytes: 4_083_015_904,
428 },
429 ];
430
431 /// Return the explicit tokenizer model ID required on Android for `hf_repo_id`.
432 ///
433 /// The candle GGUF backend cannot parse the tokenizer embedded inside GGUF
434 /// files; an explicit `tok_model_id` triggers a separate tokenizer download
435 /// from the base model repo. Returns `None` on iOS and macOS where the
436 /// embedded tokenizer is used automatically.
437 pub fn tok_model_id_for_repo(hf_repo_id: &str) -> Option<&'static str> {
438 match hf_repo_id {
439 BARTOWSKI_QWEN25_0_5B_INSTRUCT_GGUF => Some(QWEN25_0_5B_TOK_MODEL_ID),
440 BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF => Some(QWEN25_1_5B_TOK_MODEL_ID),
441 BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF => Some(QWEN25_3B_TOK_MODEL_ID),
442 BARTOWSKI_QWEN25_CODER_1_5B_INSTRUCT_GGUF => Some(QWEN25_CODER_1_5B_TOK_MODEL_ID),
443 BARTOWSKI_QWEN25_CODER_3B_INSTRUCT_GGUF => Some(QWEN25_CODER_3B_TOK_MODEL_ID),
444 BARTOWSKI_QWEN25_CODER_7B_INSTRUCT_GGUF => Some(QWEN25_CODER_7B_TOK_MODEL_ID),
445 BARTOWSKI_QWEN3_0_6B_GGUF => Some(QWEN3_0_6B_TOK_MODEL_ID),
446 BARTOWSKI_QWEN3_1_7B_GGUF => Some(QWEN3_1_7B_TOK_MODEL_ID),
447 BARTOWSKI_QWEN3_4B_GGUF => Some(QWEN3_4B_TOK_MODEL_ID),
448 BARTOWSKI_QWEN3_8B_GGUF => Some(QWEN3_8B_TOK_MODEL_ID),
449 BARTOWSKI_QWEN3_14B_GGUF => Some(QWEN3_14B_TOK_MODEL_ID),
450 BARTOWSKI_QWEN3_32B_GGUF => Some(QWEN3_32B_TOK_MODEL_ID),
451 BARTOWSKI_QWEN3_4B_INSTRUCT_2507_GGUF => Some(QWEN3_4B_INSTRUCT_2507_TOK_MODEL_ID),
452 BARTOWSKI_QWEN3_4B_THINKING_2507_GGUF => Some(QWEN3_4B_THINKING_2507_TOK_MODEL_ID),
453 BARTOWSKI_QWEN3_30B_A3B_INSTRUCT_2507_GGUF => {
454 Some(QWEN3_30B_A3B_INSTRUCT_2507_TOK_MODEL_ID)
455 }
456 THEBLOKE_DEEPSEEK_CODER_6_7B_INSTRUCT_GGUF => Some(DEEPSEEK_CODER_6_7B_TOK_MODEL_ID),
457 _ => None,
458 }
459 }
460
461 #[cfg(test)]
462 mod tests {
463 use super::*;
464
465 #[test]
466 fn tool_calling_capability_is_authoritative_for_known_and_custom_models() {
467 use super::super::types::ToolCallingSupport;
468
469 assert_eq!(
470 tool_calling_support(BARTOWSKI_QWEN3_1_7B_GGUF),
471 ToolCallingSupport::Supported
472 );
473 assert_eq!(
474 tool_calling_support(BARTOWSKI_QWEN25_CODER_7B_INSTRUCT_GGUF),
475 ToolCallingSupport::Supported
476 );
477 assert_eq!(
478 tool_calling_support(BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF),
479 ToolCallingSupport::Unsupported
480 );
481 assert_eq!(
482 tool_calling_support("acme/custom-agent-model"),
483 ToolCallingSupport::Unknown
484 );
485 // A custom repo that merely looks like a catalogued one is still
486 // uncatalogued. Onde has not verified it, so it must not claim to have.
487 assert_eq!(
488 tool_calling_support("acme/my-qwen3-finetune"),
489 ToolCallingSupport::Unknown
490 );
491 }
492
493 /// A tool-calling entry that is not a supported model would be dead: the
494 /// engine only ever asks about repos it has actually loaded.
495 #[test]
496 fn every_tool_calling_model_is_a_supported_model() {
497 for model_id in TOOL_CALLING_MODELS {
498 assert!(
499 SUPPORTED_MODELS.contains(model_id),
500 "{model_id} is listed for tool calling but is not a supported model"
501 );
502 }
503 }
504
505 /// Catches the drift the old substring match papered over: a Qwen 3 repo
506 /// added to the catalogue without being added to the tool-calling list
507 /// would silently report `Unsupported`.
508 #[test]
509 fn every_catalogued_qwen3_model_supports_tool_calling() {
510 for model_id in SUPPORTED_MODELS {
511 if model_id.to_ascii_lowercase().contains("qwen3") {
512 assert!(
513 TOOL_CALLING_MODELS.contains(model_id),
514 "{model_id} is a catalogued Qwen 3 repo but is missing from TOOL_CALLING_MODELS"
515 );
516 }
517 }
518 }
519
520 /// Every supported model must have a corresponding display-metadata entry
521 /// so the model-list UI can render it.
522 #[test]
523 fn every_supported_model_has_info() {
524 for id in SUPPORTED_MODELS {
525 assert!(
526 SUPPORTED_MODEL_INFO.iter().any(|info| info.id == *id),
527 "{id} is in SUPPORTED_MODELS but missing from SUPPORTED_MODEL_INFO"
528 );
529 }
530 }
531
532 /// Every Qwen 3 repo must resolve to an Android tokenizer ID so loading
533 /// works on the candle GGUF backend.
534 #[test]
535 fn qwen3_repos_have_android_tokenizer() {
536 let qwen3 = SUPPORTED_MODELS.iter().filter(|id| id.contains("Qwen3"));
537 for id in qwen3 {
538 assert!(
539 tok_model_id_for_repo(id).is_some(),
540 "{id} has no Android tokenizer mapping"
541 );
542 }
543 }
544 }