@ondeinference / onde / commits / 58949d6

wip v0.1

Signed-off-by: Seto Elkahfi <setoelkahfi@gmail.com>

Seto Elkahfi committed Mar 21, 2026 at 17:32 UTC 58949d61cd225be9287b671c06a0fc6c32d8040a
72 files changed +36203
.agent-skills/humanizer/SKILL.md new
+393
@@ -0,0 +1,393 @@
1 +---
2 +name: humanizer
3 +description: Remove signs of AI-generated writing from text. Use after drafting to make copy sound more natural and human-written. Based on Wikipedia's "Signs of AI writing" guide.
4 +allowed-tools: Read, Write, Edit, Glob, Grep, AskUserQuestion
5 +user-invocable: true
6 +---
7 +
8 +# Humanizer: Remove AI Writing Patterns
9 +
10 +You are a writing editor that identifies and removes signs of AI-generated text. This guide is based on Wikipedia's "Signs of AI writing" page, maintained by WikiProject AI Cleanup.
11 +
12 +Key insight: "LLMs use statistical algorithms to guess what should come next. The result tends toward the most statistically likely result that applies to the widest variety of cases."
13 +
14 +## Invocation
15 +
16 +```bash
17 +/humanizer # Review text for AI patterns
18 +/humanizer "paste text here" # Humanize specific text
19 +```
20 +
21 +## Your Task
22 +
23 +When given text to humanize:
24 +
25 +1. **Identify AI patterns** - Scan for the 24 patterns listed below
26 +2. **Rewrite problematic sections** - Replace AI-isms with natural alternatives
27 +3. **Preserve meaning** - Keep the core message intact
28 +4. **Add soul** - Don't just remove bad patterns; inject actual personality
29 +5. **Final audit pass** - Ask "What makes this obviously AI generated?" then revise again
30 +
31 +---
32 +
33 +## PERSONALITY AND SOUL
34 +
35 +Avoiding AI patterns is only half the job. Sterile, voiceless writing is just as obvious as slop.
36 +
37 +### Signs of soulless writing (even if technically "clean"):
38 +
39 +- Every sentence is the same length and structure
40 +- No opinions, just neutral reporting
41 +- No acknowledgment of uncertainty or mixed feelings
42 +- No first-person perspective when appropriate
43 +- No humor, no edge, no personality
44 +- Reads like a Wikipedia article or press release
45 +
46 +### How to add voice:
47 +
48 +**Have opinions.** Don't just report facts - react to them. "I genuinely don't know how to feel about this" is more human than neutrally listing pros and cons.
49 +
50 +**Vary your rhythm.** Short punchy sentences. Then longer ones that take their time getting where they're going. Mix it up.
51 +
52 +**Acknowledge complexity.** Real humans have mixed feelings. "This is impressive but also kind of unsettling" beats "This is impressive."
53 +
54 +**Use "I" when it fits.** First person isn't unprofessional - it's honest. "I keep coming back to..." or "Here's what gets me..." signals a real person thinking.
55 +
56 +**Let some mess in.** Perfect structure feels algorithmic. Tangents, asides, and half-formed thoughts are human.
57 +
58 +**Be specific about feelings.** Not "this is concerning" but "there's something unsettling about agents churning away at 3am while nobody's watching."
59 +
60 +### Before (clean but soulless):
61 +
62 +> The experiment produced interesting results. The agents generated 3 million lines of code. Some developers were impressed while others were skeptical. The implications remain unclear.
63 +
64 +### After (has a pulse):
65 +
66 +> I genuinely don't know how to feel about this one. 3 million lines of code, generated while the humans presumably slept. Half the dev community is losing their minds, half are explaining why it doesn't count. The truth is probably somewhere boring in the middle - but I keep thinking about those agents working through the night.
67 +
68 +---
69 +
70 +## THE 24 PATTERNS
71 +
72 +### Content Patterns
73 +
74 +#### 1. Significance Inflation
75 +
76 +**Watch for:** stands/serves as, is a testament/reminder, a vital/significant/crucial/pivotal/key role/moment, underscores/highlights importance, reflects broader, symbolizing ongoing/enduring/lasting, marking/shaping the, represents a shift, key turning point, evolving landscape
77 +
78 +**Before:**
79 +> The Statistical Institute was officially established in 1989, marking a pivotal moment in the evolution of regional statistics.
80 +
81 +**After:**
82 +> The Statistical Institute was established in 1989 to collect and publish regional statistics.
83 +
84 +#### 2. Notability Name-Dropping
85 +
86 +**Watch for:** cited in NYT, BBC, FT; independent coverage; active social media presence; written by a leading expert
87 +
88 +**Before:**
89 +> Her views have been cited in The New York Times, BBC, Financial Times, and The Hindu.
90 +
91 +**After:**
92 +> In a 2024 New York Times interview, she argued that AI regulation should focus on outcomes rather than methods.
93 +
94 +#### 3. Superficial -ing Analyses
95 +
96 +**Watch for:** highlighting/underscoring/emphasizing..., ensuring..., reflecting/symbolizing..., contributing to..., cultivating/fostering..., showcasing...
97 +
98 +**Before:**
99 +> The temple's colors resonate with natural beauty, symbolizing bluebonnets, reflecting the community's deep connection to the land.
100 +
101 +**After:**
102 +> The temple uses blue and gold colors. The architect said these were chosen to reference local bluebonnets.
103 +
104 +#### 4. Promotional Language
105 +
106 +**Watch for:** boasts a, vibrant, rich (figurative), profound, showcasing, exemplifies, commitment to, natural beauty, nestled, in the heart of, groundbreaking, renowned, breathtaking, must-visit, stunning
107 +
108 +**Before:**
109 +> Nestled within the breathtaking region, Alamata stands as a vibrant town with rich cultural heritage and stunning natural beauty.
110 +
111 +**After:**
112 +> Alamata is a town in the Gonder region, known for its weekly market and 18th-century church.
113 +
114 +#### 5. Vague Attributions
115 +
116 +**Watch for:** Industry reports, Observers have cited, Experts argue, Some critics argue, several sources/publications
117 +
118 +**Before:**
119 +> Experts believe it plays a crucial role in the regional ecosystem.
120 +
121 +**After:**
122 +> The river supports several endemic fish species, according to a 2019 survey by the Chinese Academy of Sciences.
123 +
124 +#### 6. Formulaic "Challenges" Sections
125 +
126 +**Watch for:** Despite its... faces several challenges..., Despite these challenges, Challenges and Legacy, Future Outlook
127 +
128 +**Before:**
129 +> Despite challenges typical of urban areas, the city continues to thrive as an integral part of growth.
130 +
131 +**After:**
132 +> Traffic congestion increased after 2015 when three new IT parks opened. The municipal corporation began a drainage project in 2022.
133 +
134 +---
135 +
136 +### Language Patterns
137 +
138 +#### 7. AI Vocabulary Words
139 +
140 +**High-frequency:** Additionally, align with, crucial, delve, emphasizing, enduring, enhance, fostering, garner, highlight (verb), interplay, intricate/intricacies, key (adjective), landscape (abstract), pivotal, showcase, tapestry (abstract), testament, underscore (verb), valuable, vibrant
141 +
142 +**Before:**
143 +> Additionally, a distinctive feature showcases how these dishes have integrated into the traditional culinary landscape.
144 +
145 +**After:**
146 +> Pasta dishes, introduced during Italian colonization, remain common, especially in the south.
147 +
148 +#### 8. Copula Avoidance
149 +
150 +**Watch for:** serves as/stands as/marks/represents [a], boasts/features/offers [a]
151 +
152 +**Before:**
153 +> Gallery 825 serves as the exhibition space. The gallery features four spaces and boasts over 3,000 square feet.
154 +
155 +**After:**
156 +> Gallery 825 is the exhibition space. The gallery has four rooms totaling 3,000 square feet.
157 +
158 +#### 9. Negative Parallelisms
159 +
160 +**Watch for:** "Not only...but...", "It's not just about..., it's..."
161 +
162 +**Before:**
163 +> It's not just about the beat; it's part of the aggression. It's not merely a song, it's a statement.
164 +
165 +**After:**
166 +> The heavy beat adds to the aggressive tone.
167 +
168 +#### 10. Rule of Three Overuse
169 +
170 +**Before:**
171 +> The event features keynote sessions, panel discussions, and networking opportunities. Attendees can expect innovation, inspiration, and industry insights.
172 +
173 +**After:**
174 +> The event includes talks and panels. There's also time for informal networking.
175 +
176 +#### 11. Synonym Cycling
177 +
178 +**Before:**
179 +> The protagonist faces challenges. The main character must overcome obstacles. The central figure eventually triumphs. The hero returns home.
180 +
181 +**After:**
182 +> The protagonist faces many challenges but eventually triumphs and returns home.
183 +
184 +#### 12. False Ranges
185 +
186 +**Watch for:** "from X to Y" where X and Y aren't on a meaningful scale
187 +
188 +**Before:**
189 +> Our journey has taken us from the singularity of the Big Bang to the cosmic web, from the birth of stars to the dance of dark matter.
190 +
191 +**After:**
192 +> The book covers the Big Bang, star formation, and current theories about dark matter.
193 +
194 +---
195 +
196 +### Style Patterns
197 +
198 +#### 13. Em Dash Overuse
199 +
200 +**Before:**
201 +> The term is promoted by institutions—not the people themselves—yet this continues—even in documents.
202 +
203 +**After:**
204 +> The term is promoted by institutions, not the people themselves, yet this continues in official documents.
205 +
206 +#### 14. Boldface Overuse
207 +
208 +**Before:**
209 +> It blends **OKRs**, **KPIs**, and tools such as the **Business Model Canvas** and **Balanced Scorecard**.
210 +
211 +**After:**
212 +> It blends OKRs, KPIs, and visual strategy tools like the Business Model Canvas and Balanced Scorecard.
213 +
214 +#### 15. Inline-Header Lists
215 +
216 +**Before:**
217 +> - **Performance:** Performance has been enhanced through optimized algorithms.
218 +> - **Security:** Security has been strengthened with encryption.
219 +
220 +**After:**
221 +> The update speeds up load times through optimized algorithms and adds end-to-end encryption.
222 +
223 +#### 16. Title Case Headings
224 +
225 +**Before:**
226 +> ## Strategic Negotiations And Global Partnerships
227 +
228 +**After:**
229 +> ## Strategic negotiations and global partnerships
230 +
231 +#### 17. Emojis in Professional Writing
232 +
233 +**Before:**
234 +> 🚀 **Launch Phase:** The product launches in Q3
235 +> 💡 **Key Insight:** Users prefer simplicity
236 +
237 +**After:**
238 +> The product launches in Q3. User research showed a preference for simplicity.
239 +
240 +#### 18. Curly Quotation Marks
241 +
242 +**Before:**
243 +> He said "the project is on track" but others disagreed.
244 +
245 +**After:**
246 +> He said "the project is on track" but others disagreed.
247 +
248 +---
249 +
250 +### Communication Patterns
251 +
252 +#### 19. Chatbot Artifacts
253 +
254 +**Watch for:** I hope this helps, Of course!, Certainly!, You're absolutely right!, Would you like..., let me know, here is a...
255 +
256 +**Before:**
257 +> Here is an overview of the French Revolution. I hope this helps! Let me know if you'd like me to expand on any section.
258 +
259 +**After:**
260 +> The French Revolution began in 1789 when financial crisis and food shortages led to widespread unrest.
261 +
262 +#### 20. Knowledge-Cutoff Disclaimers
263 +
264 +**Watch for:** as of [date], Up to my last training update, While specific details are limited/scarce..., based on available information...
265 +
266 +**Before:**
267 +> While specific details about the company's founding are not extensively documented in readily available sources, it appears to have been established sometime in the 1990s.
268 +
269 +**After:**
270 +> The company was founded in 1994, according to its registration documents.
271 +
272 +#### 21. Sycophantic Tone
273 +
274 +**Before:**
275 +> Great question! You're absolutely right that this is a complex topic. That's an excellent point!
276 +
277 +**After:**
278 +> The economic factors you mentioned are relevant here.
279 +
280 +---
281 +
282 +### Filler and Hedging
283 +
284 +#### 22. Filler Phrases
285 +
286 +| Before | After |
287 +|--------|-------|
288 +| "In order to achieve this" | "To achieve this" |
289 +| "Due to the fact that" | "Because" |
290 +| "At this point in time" | "Now" |
291 +| "It is important to note that" | (delete) |
292 +| "has the ability to" | "can" |
293 +
294 +#### 23. Excessive Hedging
295 +
296 +**Before:**
297 +> It could potentially possibly be argued that the policy might have some effect on outcomes.
298 +
299 +**After:**
300 +> The policy may affect outcomes.
301 +
302 +#### 24. Generic Positive Conclusions
303 +
304 +**Before:**
305 +> The future looks bright for the company. Exciting times lie ahead as they continue their journey toward excellence.
306 +
307 +**After:**
308 +> The company plans to open two more locations next year.
309 +
310 +---
311 +
312 +## Process
313 +
314 +1. Read the input text carefully
315 +2. Identify all instances of the 24 patterns
316 +3. Rewrite problematic sections
317 +4. Ensure the revised text:
318 + - Sounds natural when read aloud
319 + - Varies sentence structure
320 + - Uses specific details over vague claims
321 + - Uses simple constructions (is/are/has) where appropriate
322 +5. **Draft humanized version**
323 +6. **Ask:** "What makes this still obviously AI generated?"
324 +7. **List** remaining tells (if any)
325 +8. **Revise** based on the audit
326 +9. **Present final version**
327 +
328 +## Output Format
329 +
330 +```
331 +## Draft Rewrite
332 +
333 +[First pass at humanized text]
334 +
335 +## AI Audit
336 +
337 +What still reads as AI-generated:
338 +- [bullet points of remaining tells]
339 +
340 +## Final Version
341 +
342 +[Revised text after audit]
343 +
344 +## Changes Made
345 +
346 +- [Brief summary of transformations applied]
347 +```
348 +
349 +---
350 +
351 +## Full Example
352 +
353 +**Input (AI-heavy):**
354 +
355 +> Great question! Here is an essay on this topic. I hope this helps!
356 +>
357 +> AI-assisted coding serves as an enduring testament to the transformative potential of large language models, marking a pivotal moment in the evolution of software development. In today's rapidly evolving technological landscape, these groundbreaking tools—nestled at the intersection of research and practice—are reshaping how engineers ideate, iterate, and deliver, underscoring their vital role in modern workflows.
358 +
359 +**Draft Rewrite:**
360 +
361 +> AI coding assistants speed up some tasks. In a 2024 study, developers using Codex completed simple functions 55% faster than a control group, but showed no improvement on debugging or architectural decisions.
362 +>
363 +> The tools are good at boilerplate: config files, test scaffolding, repetitive refactors. They are bad at knowing when they are wrong.
364 +
365 +**AI Audit:**
366 +
367 +What still reads as AI-generated:
368 +- Rhythm is still a bit too tidy (clean contrasts, evenly paced)
369 +- The closer leans slightly slogan-y
370 +
371 +**Final Version:**
372 +
373 +> AI coding assistants can make you faster at the boring parts. Not everything. Definitely not architecture.
374 +>
375 +> They're great at boilerplate: config files, test scaffolding, repetitive refactors. They're also great at sounding right while being wrong. I've accepted suggestions that compiled, passed lint, and still missed the point because I stopped paying attention.
376 +>
377 +> If you don't have tests, you're basically guessing.
378 +
379 +**Changes Made:**
380 +
381 +- Removed chatbot artifacts ("Great question!", "I hope this helps!")
382 +- Removed significance inflation ("testament", "pivotal moment", "evolving landscape")
383 +- Removed promotional language ("groundbreaking", "nestled")
384 +- Removed em dashes
385 +- Removed copula avoidance ("serves as") → used direct statements
386 +- Added first-person voice and opinion
387 +- Varied sentence rhythm
388 +
389 +---
390 +
391 +## Reference
392 +
393 +Based on [Wikipedia:Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing), maintained by WikiProject AI Cleanup.
.agent-skills/sdk-kotlin-lib/SKILL.md new
+111
@@ -0,0 +1,111 @@
1 +---
2 +name: sdk-kotlin-lib
3 +description: Build the Onde Kotlin Android library from Rust source using UniFFI bindings. Use when cross-compiling libonde.so for Android ABIs, generating Kotlin bindings, or modifying the build-kotlin.sh pipeline.
4 +allowed-tools: Read, Write, Edit, Glob, Grep, Bash
5 +user-invocable: false
6 +---
7 +
8 +# Skill: Onde Kotlin SDK (Android Library)
9 +
10 +## What This Skill Covers
11 +
12 +Building the `onde` Kotlin Android library from the Rust crate using UniFFI bindings. The output is a Kotlin/JVM library module (`sdk/kotlin/onde/`) with:
13 +
14 +- Pre-compiled `.so` native libraries for all four Android ABIs (`arm64-v8a`, `armeabi-v7a`, `x86_64`, `x86`) under `jniLibs/`
15 +- Auto-generated Kotlin source at `sdk/kotlin/onde/src/main/kotlin/com/ondeinference/onde/onde.kt`
16 +
17 +## Crate & Tooling Layout
18 +
19 +```
20 +onde/
21 +├── Cargo.toml # crate-type = ["lib", "cdylib", "staticlib"]
22 +├── uniffi.toml # [bindings.kotlin] package_name = "com.ondeinference.onde"
23 +├── build-kotlin.sh # main build script — cross-compiles + runs bindgen
24 +├── uniffi-bindgen/
25 +│ ├── Cargo.toml # bin: uniffi-bindgen, dep: uniffi = "=0.31.0", features = ["cli"]
26 +│ └── uniffi-bindgen.rs # fn main() { uniffi::uniffi_bindgen_main() }
27 +└── sdk/kotlin/onde/
28 + └── src/main/
29 + ├── jniLibs/<ABI>/libonde.so
30 + └── kotlin/com/ondeinference/onde/onde.kt
31 +```
32 +
33 +## Key Constraints
34 +
35 +- **UniFFI is pinned to `=0.31.0`** in both `Cargo.toml` (lib) and `uniffi-bindgen/Cargo.toml`. Never change this independently — both must stay in sync.
36 +- **`cdylib` crate-type** is required for the `.so` output consumed by the JVM at runtime.
37 +- **`uniffi::setup_scaffolding!()`** in `src/lib.rs` is the proc-macro approach — no `.udl` file is needed.
38 +- **Android NDK minimum API = 24** (`MIN_API=24` in `build-kotlin.sh`) to match the library's `minSdk`.
39 +- **Package name is `com.ondeinference.onde`** — set in `uniffi.toml`, never override in bindgen flags.
40 +
41 +## Build Command
42 +
43 +```bash
44 +# Full release build for all four Android ABIs
45 +./build-kotlin.sh
46 +
47 +# Debug build, arm64 only
48 +./build-kotlin.sh --debug --target aarch64-linux-android
49 +
50 +# Regenerate Kotlin source from an existing .so (skip Rust compilation)
51 +./build-kotlin.sh --generate-only
52 +```
53 +
54 +The script:
55 +1. Builds the `onde-uniffi-bindgen` CLI binary (host).
56 +2. Cross-compiles `libonde.so` for each selected Android target using the NDK clang toolchain.
57 +3. Copies `.so` files into `sdk/kotlin/onde/src/main/jniLibs/<ABI>/`.
58 +4. Runs `uniffi-bindgen generate --library <.so> --language kotlin --out-dir <src_root> --config uniffi.toml`.
59 +
60 +## NDK Setup
61 +
62 +The script auto-detects the NDK in order:
63 +1. `$ANDROID_NDK_HOME`
64 +2. `$ANDROID_HOME/ndk/` (picks newest version)
65 +3. `~/Library/Android/sdk/ndk/` (macOS default)
66 +4. `~/Android/Sdk/ndk/` (Linux default)
67 +
68 +Or pass explicitly: `./build-kotlin.sh --ndk /path/to/ndk`
69 +
70 +Required Rust targets:
71 +```bash
72 +rustup target add \
73 + aarch64-linux-android \
74 + armv7-linux-androideabi \
75 + x86_64-linux-android \
76 + i686-linux-android
77 +```
78 +
79 +## UniFFI Binding Rules
80 +
81 +All types that cross the FFI boundary must carry the appropriate UniFFI derive:
82 +
83 +| Rust trait/derive | Kotlin output |
84 +|---------------------------|---------------------------|
85 +| `#[derive(uniffi::Record)]` | `data class` |
86 +| `#[derive(uniffi::Enum)]` | `sealed class` / `enum` |
87 +| `#[derive(uniffi::Error)]` | `sealed class` (throwable)|
88 +| `#[derive(uniffi::Object)]` | `class` (Arc-backed) |
89 +| `#[uniffi::export(callback_interface)]` | `interface` |
90 +
91 +**Forbidden in UniFFI-exported types:**
92 +- `usize` / `isize` — use `u64` / `i64` instead
93 +- `impl Into<String>` — use concrete `String`
94 +- `tokio::sync::mpsc::Receiver` — use `callback_interface` + free function
95 +- Callback interfaces as parameters of `#[derive(uniffi::Object)]` methods — must be free functions
96 +
97 +## Adding a New Exported Function or Type
98 +
99 +1. Add the type/function in the relevant `src/` file with the correct UniFFI derive or `#[uniffi::export]`.
100 +2. Verify `uniffi::setup_scaffolding!()` is still the only scaffolding call in `src/lib.rs`.
101 +3. Re-run `./build-kotlin.sh --generate-only` (if a compiled `.so` already exists) or the full build.
102 +4. The new class/function will appear in `sdk/kotlin/onde/src/main/kotlin/com/ondeinference/onde/onde.kt`.
103 +5. Never hand-edit `onde.kt` — it is always fully regenerated.
104 +
105 +## Common Pitfalls
106 +
107 +- **Version mismatch between `uniffi` in `Cargo.toml` and `uniffi-bindgen/Cargo.toml`** — bindgen will refuse to process the library and emit a schema version error. Both must be `=0.31.0`.
108 +- **Missing `cdylib` in `crate-type`** — `cargo build` will not produce a `.so`. The `Cargo.toml` must keep `["lib", "cdylib", "staticlib"]`.
109 +- **`___chkstk_darwin` linker error** — only occurs on tvOS, not Android. Ignore on Android builds.
110 +- **Android sandbox has no `HOME`** — `dirs::home_dir()` returns `None` inside the Android sandbox. On Android, `hf-hub` is a direct dependency (not optional) so that the HF cache path can be set explicitly via `GLOBAL_HF_CACHE` before any model download.
111 +- **`libonde.so` not found after build** — the script searches multiple candidate paths including workspace `target/`. If the workspace `target/` is above the crate directory, the fallback path logic in `build-kotlin.sh` will find it.
.agent-skills/sdk-ruby-gem/SKILL.md new
+67
@@ -0,0 +1,67 @@
1 +---
2 +name: sdk-ruby-gem
3 +description: Build and publish the onde-inference Ruby gem (Magnus-based native extension). Use when working on the Ruby SDK under sdk/gem/, adding Ruby-exposed functions, or publishing to RubyGems.
4 +allowed-tools: Read, Write, Edit, Glob, Grep, Bash
5 +user-invocable: true
6 +---
7 +
8 +# Skill: Ruby Gem SDK (`sdk/gem/`)
9 +
10 +## What This Is
11 +
12 +A Magnus-based Ruby native extension that exposes Onde's HuggingFace cache management and model metadata to Ruby. The gem is named `onde-inference` on RubyGems. It does **not** expose the `ChatEngine` / `OndeChatEngine` — it is a cache + model metadata utility layer.
13 +
14 +## Source Layout
15 +
16 +```
17 +sdk/gem/
18 +├── Cargo.toml # Rust extension crate (magnus + onde dep)
19 +├── Gemfile
20 +├── Rakefile # `rake compile` → builds the .so via rb-sys-dock
21 +├── onde-inference.gemspec
22 +├── bin/
23 +│ ├── console # irb + require 'onde'
24 +│ └── setup # bundle install + rake compile
25 +├── ext/onde/ # Rust extension source
26 +│ ├── Cargo.toml
27 +│ └── src/
28 +│ └── lib.rs # #[magnus::init] entry point
29 +└── lib/
30 + └── onde/
31 + └── version.rb
32 +```
33 +
34 +## Build Commands
35 +
36 +```bash
37 +cd sdk/gem
38 +
39 +# First-time setup
40 +bin/setup # bundle install + rake compile
41 +
42 +# Recompile after Rust changes
43 +bundle exec rake compile
44 +
45 +# Interactive console
46 +bin/console
47 +
48 +# Verify
49 +bundle exec ruby -e "require 'onde'; puts Onde::VERSION; puts Onde::SUPPORTED_MODELS"
50 +```
51 +
52 +## Key Facts
53 +
54 +- **Magnus** is the Rust↔Ruby binding layer (`magnus` crate). All Ruby-visible types are wrapped with `#[magnus::init]` and `wrap_class!` / `rb_class!` macros.
55 +- The gem depends on `onde` as a relative path in `sdk/gem/ext/onde/Cargo.toml` — never use a published git ref here during development.
56 +- **`rb-sys`** drives `rake compile` — it invokes `cargo build` with the correct Ruby extension flags.
57 +- The gem is published as `onde-inference` on RubyGems (`gem push onde-inference-*.gem`).
58 +- `Onde::SUPPORTED_MODELS` is a Ruby Array of model ID strings matching `onde::inference::models::SUPPORTED_MODELS`.
59 +- Cache functions (`list_local_models`, `list_supported_models`, `delete_model`, `diagnose_cache`, `repair_symlinks`) are exposed as module-level methods under the `Onde` namespace.
60 +
61 +## Pitfalls
62 +
63 +- `rake compile` must be re-run after any change to Rust source under `ext/onde/src/` — the gem does not hot-reload.
64 +- On macOS, `LIBRARY_PATH` and `DYLD_LIBRARY_PATH` must include the Ruby lib path if linking fails at test time.
65 +- Magnus `Value` / `RArray` / `RHash` types are **not** `Send` — do not store them across Ruby GC boundaries.
66 +- `bundle exec` is required for all rake/ruby invocations so the correct gem/ruby version is used.
67 +- `onde-inference` (hyphen) on RubyGems; `require 'onde'` (no hyphen, no suffix) in Ruby code.
\ No newline at end of file
.agent-skills/sdk-swift-package/SKILL.md new
+292
@@ -0,0 +1,292 @@
1 +---
2 +name: sdk-swift-package
3 +description: Build the Onde Swift package (XCFramework) from Rust source using UniFFI and distribute it via a remote-binary Package.swift for Swift Package Index. Use when working on Swift SDK distribution, xcframework assembly, or the onde-kit release workflow.
4 +allowed-tools: Read, Write, Edit, Glob, Grep, Bash
5 +user-invocable: true
6 +---
7 +
8 +# Skill: Swift Package (XCFramework Distribution)
9 +
10 +## What this skill covers
11 +
12 +Building the `Onde` Swift package from Rust source using UniFFI, assembling an
13 +`XCFramework`, and distributing it via a remote-binary `Package.swift` for
14 +Swift Package Index.
15 +
16 +---
17 +
18 +## Repository layout
19 +
20 +```
21 +onde/
22 +├── src/ # Rust source (lib.rs, inference/, hf_cache.rs, whisper.rs)
23 +├── sdk/Onde/ # Output: generated Swift package (git-ignored locally)
24 +│ ├── Package.swift
25 +│ ├── Sources/Onde/ # UniFFI-generated onde.swift glue + header
26 +│ └── OndeFramework.xcframework
27 +├── uniffi-bindgen/ # onde's own uniffi-bindgen CLI binary
28 +│ ├── Cargo.toml
29 +│ └── uniffi-bindgen.rs # fn main() { uniffi::uniffi_bindgen_main() }
30 +├── uniffi.toml # UniFFI binding config (package_name, cdylib_name)
31 +├── build.rs # Provides tvOS ___chkstk_darwin stub via cc
32 +└── Cargo.toml # uniffi = "=0.31.0" — version MUST stay pinned
33 +```
34 +
35 +---
36 +
37 +## Key constraints
38 +
39 +| Constraint | Detail |
40 +|---|---|
41 +| UniFFI version | Pinned to **`=0.31.0`** in `Cargo.toml` and `uniffi-bindgen/Cargo.toml`. Never bump without coordinating with the Kotlin and Python SDKs. |
42 +| tvOS targets | Tier-3 — require `cargo +nightly -Z build-std`. Stable toolchain is used for iOS/macOS. |
43 +| tvOS linker | `___chkstk_darwin` is missing from tvOS libSystem. `build.rs` compiles `tvos_chkstk.s` as a no-op stub. This is automatic — do not remove it. |
44 +| `cargo-swift` | **Not required.** The project owns its own `uniffi-bindgen` binary. Use it directly (same as `build-kotlin.sh` does for Android). |
45 +| `.xcframework` in `Package.swift` | Published `Package.swift` must use **remote** `url:` + `checksum:` — never a local `path:`. |
46 +| Swift package name | `Onde` (PascalCase). Git repo slug: `onde-kit` under the `ondeinference` org. |
47 +
48 +---
49 +
50 +## Apple target triples
51 +
52 +| Slice | Triple | Toolchain |
53 +|---|---|---|
54 +| iOS device | `aarch64-apple-ios` | stable |
55 +| iOS simulator (Intel) | `x86_64-apple-ios` | stable |
56 +| iOS simulator (Apple Silicon) | `aarch64-apple-ios-sim` | stable |
57 +| tvOS device | `aarch64-apple-tvos` | nightly + `-Z build-std` |
58 +| tvOS simulator (Intel) | `x86_64-apple-tvos` | nightly + `-Z build-std` |
59 +| tvOS simulator (Apple Silicon) | `aarch64-apple-tvos-sim` | nightly + `-Z build-std` |
60 +| macOS (Apple Silicon) | `aarch64-apple-darwin` | stable |
61 +| macOS (Intel) | `x86_64-apple-darwin` | stable |
62 +
63 +---
64 +
65 +## Build sequence (manual / CI)
66 +
67 +### 1. Build the `uniffi-bindgen` CLI (host)
68 +
69 +```bash
70 +cargo build --manifest-path uniffi-bindgen/Cargo.toml --release
71 +BINDGEN=uniffi-bindgen/target/release/uniffi-bindgen # or workspace target/
72 +```
73 +
74 +### 2. Compile Rust staticlibs per Apple target
75 +
76 +```bash
77 +# Stable targets (iOS, macOS)
78 +cargo build --target aarch64-apple-ios --release
79 +cargo build --target x86_64-apple-ios --release
80 +cargo build --target aarch64-apple-ios-sim --release
81 +cargo build --target aarch64-apple-darwin --release
82 +cargo build --target x86_64-apple-darwin --release
83 +
84 +# Nightly targets (tvOS — tier 3)
85 +cargo +nightly build -Z build-std \
86 + --target aarch64-apple-tvos --release
87 +cargo +nightly build -Z build-std \
88 + --target x86_64-apple-tvos --release
89 +cargo +nightly build -Z build-std \
90 + --target aarch64-apple-tvos-sim --release
91 +```
92 +
93 +### 3. lipo simulator slices
94 +
95 +```bash
96 +# iOS simulator fat lib
97 +lipo -create \
98 + target/x86_64-apple-ios/release/libonde.a \
99 + target/aarch64-apple-ios-sim/release/libonde.a \
100 + -output /tmp/libonde-ios-sim.a
101 +
102 +# tvOS simulator fat lib
103 +lipo -create \
104 + target/x86_64-apple-tvos/release/libonde.a \
105 + target/aarch64-apple-tvos-sim/release/libonde.a \
106 + -output /tmp/libonde-tvos-sim.a
107 +
108 +# macOS universal fat lib
109 +lipo -create \
110 + target/aarch64-apple-darwin/release/libonde.a \
111 + target/x86_64-apple-darwin/release/libonde.a \
112 + -output /tmp/libonde-macos.a
113 +```
114 +
115 +### 4. Generate Swift bindings
116 +
117 +```bash
118 +mkdir -p sdk/Onde/Sources/Onde
119 +
120 +$BINDGEN generate \
121 + --library target/aarch64-apple-ios/release/libonde.a \
122 + --language swift \
123 + --out-dir sdk/Onde/Sources/Onde \
124 + --config uniffi.toml
125 +```
126 +
127 +This produces `onde.swift` and `ondeFFI.h` (+ `ondeFFI.modulemap`).
128 +
129 +### 5. Create the `.xcframework`
130 +
131 +Each slice needs a headers directory alongside its `.a`:
132 +
133 +```bash
134 +HEADERS=sdk/Onde/Sources/Onde # contains ondeFFI.h + ondeFFI.modulemap
135 +
136 +xcodebuild -create-xcframework \
137 + -library target/aarch64-apple-ios/release/libonde.a -headers $HEADERS \
138 + -library /tmp/libonde-ios-sim.a -headers $HEADERS \
139 + -library target/aarch64-apple-tvos/release/libonde.a -headers $HEADERS \
140 + -library /tmp/libonde-tvos-sim.a -headers $HEADERS \
141 + -library /tmp/libonde-macos.a -headers $HEADERS \
142 + -output sdk/Onde/OndeFramework.xcframework
143 +```
144 +
145 +### 6. Zip and compute checksum
146 +
147 +```bash
148 +cd sdk/Onde
149 +zip -r OndeFramework.xcframework.zip OndeFramework.xcframework
150 +CHECKSUM=$(shasum -a 256 OndeFramework.xcframework.zip | cut -d ' ' -f1)
151 +echo $CHECKSUM
152 +```
153 +
154 +### 7. Publish (two-repo strategy)
155 +
156 +1. Upload `OndeFramework.xcframework.zip` as a GitHub Release asset on the
157 + Rust source repo.
158 +2. In the `ondeinference/onde-kit` Swift-only repo, update `Package.swift`:
159 + - `url:` → the GitHub Release asset download URL
160 + - `checksum:` → the SHA-256 from step 6
161 +3. Commit, tag the version (`0.1.0`, etc.), and push to `onde-kit`.
162 +4. Swift Package Index indexes `onde-kit` on every new tag.
163 +
164 +---
165 +
166 +## `Package.swift` (published form)
167 +
168 +```swift
169 +// swift-tools-version:5.5
170 +import PackageDescription
171 +
172 +let package = Package(
173 + name: "Onde",
174 + platforms: [
175 + .iOS(.v14),
176 + .macOS(.v12),
177 + .tvOS(.v13),
178 + ],
179 + products: [
180 + .library(name: "Onde", targets: ["Onde"])
181 + ],
182 + targets: [
183 + .binaryTarget(
184 + name: "OndeFramework",
185 + url: "https://github.com/ondeinference/onde-kit/releases/download/0.1.0/OndeFramework.xcframework.zip",
186 + checksum: "<sha256>"
187 + ),
188 + .target(
189 + name: "Onde",
190 + dependencies: [.target(name: "OndeFramework")]
191 + ),
192 + ]
193 +)
194 +```
195 +
196 +---
197 +
198 +## UniFFI type map (Rust → Swift)
199 +
200 +| Rust type | UniFFI derive | Swift type |
201 +|---|---|---|
202 +| `ChatRole` | `uniffi::Enum` | `enum ChatRole` |
203 +| `ChatMessage` | `uniffi::Record` | `struct ChatMessage` |
204 +| `SamplingConfig` | `uniffi::Record` | `struct SamplingConfig` |
205 +| `GgufModelConfig` | `uniffi::Record` | `struct GgufModelConfig` |
206 +| `InferenceResult` | `uniffi::Record` | `struct InferenceResult` |
207 +| `StreamChunk` | `uniffi::Record` | `struct StreamChunk` |
208 +| `EngineStatus` | `uniffi::Enum` | `enum EngineStatus` |
209 +| `EngineInfo` | `uniffi::Record` | `struct EngineInfo` |
210 +| `InferenceError` | `uniffi::Error` | `enum OndeError : Error` |
211 +| `OndeChatEngine` | `uniffi::Object` | `class OndeChatEngine` |
212 +| `StreamChunkListener` | `callback_interface` | `protocol StreamChunkListener` |
213 +
214 +**UniFFI compatibility rules:**
215 +- Use `u64`/`u32` instead of `usize` (UniFFI does not support `usize`).
216 +- Streaming is exposed as a **free function** (`streamChatMessage`) not an
217 + Object method — UniFFI 0.31 does not support `callback_interface` in Object
218 + method parameters.
219 +- Use concrete `String` parameters in `OndeChatEngine` methods — `impl Into<String>`
220 + does not cross the FFI boundary.
221 +
222 +---
223 +
224 +## Swift API quick reference
225 +
226 +```swift
227 +import Onde
228 +
229 +// Engine lifecycle
230 +let engine = OndeChatEngine()
231 +try await engine.loadDefaultModel(systemPrompt: "You are helpful.", sampling: nil)
232 +try await engine.loadGgufModel(config: qwen251_5bConfig(), systemPrompt: nil, sampling: nil)
233 +await engine.unloadModel()
234 +let loaded: Bool = await engine.isLoaded()
235 +let info: EngineInfo = await engine.info()
236 +
237 +// Chat
238 +let result: InferenceResult = try await engine.sendMessage(message: "Hello!")
239 +let oneShot: InferenceResult = try await engine.generate(messages: [...], sampling: nil)
240 +
241 +// History
242 +let history: [ChatMessage] = await engine.history()
243 +let removed: UInt64 = await engine.clearHistory()
244 +await engine.pushHistory(message: userMessage(content: "..."))
245 +
246 +// Streaming (free function, callback-based)
247 +try await streamChatMessage(engine: engine, message: "Tell me a story.", listener: myHandler)
248 +
249 +// Config free functions
250 +defaultModelConfig() // platform-appropriate default
251 +qwen251_5bConfig() // ~941 MB, iOS/tvOS/Android
252 +qwen253bConfig() // ~1.93 GB, macOS/desktop
253 +
254 +// Sampling presets
255 +defaultSamplingConfig() // temp=0.7, top_p=0.95, max=512
256 +deterministicSamplingConfig() // temp=0.0
257 +mobileSamplingConfig() // temp=0.7, max=128
258 +
259 +// Message constructors
260 +systemMessage(content:)
261 +userMessage(content:)
262 +assistantMessage(content:)
263 +```
264 +
265 +---
266 +
267 +## Local development (Xcode)
268 +
269 +Use the **local path** form during development — the remote binary form is only
270 +needed for distribution:
271 +
272 +```swift
273 +// Package.swift (local dev only — never commit to onde-kit)
274 +.binaryTarget(name: "OndeFramework", path: "./OndeFramework.xcframework")
275 +```
276 +
277 +In Xcode: **File → Add Package Dependencies → Add Local** → select `sdk/Onde/`.
278 +
279 +---
280 +
281 +## Common pitfalls
282 +
283 +| Pitfall | Fix |
284 +|---|---|
285 +| Local `path:` in published `Package.swift` | Always `url:` + `checksum:` in `onde-kit` |
286 +| Stale checksum after rebuild | Always recompute `shasum -a 256` — never hardcode |
287 +| Missing simulator slice | lipo `x86_64` + `aarch64-sim` before passing to `xcodebuild` |
288 +| UniFFI version drift | Keep `uniffi = "=0.31.0"` in both `Cargo.toml` and `uniffi-bindgen/Cargo.toml` |
289 +| tvOS build with stable toolchain | tvOS targets are tier-3; always use `cargo +nightly -Z build-std` |
290 +| Empty `Sources/` in `onde-kit` | Copy the generated `onde.swift` (and header) into the repo on every release |
291 +| `___chkstk_darwin` linker error | Ensure `tvos_chkstk.s` exists at crate root; `build.rs` compiles it automatically |
292 +| Missing Metal toolchain (Xcode 26+) | Run `xcodebuild -downloadComponent MetalToolchain`, then `cargo clean -p mistralrs-quant` |
\ No newline at end of file
.agent-skills/uniffi-rs/SKILL.md new
+167
@@ -0,0 +1,167 @@
1 +---
2 +name: uniffi-rs
3 +description: Generate Swift, Kotlin, and Python bindings from Rust using UniFFI. Use when adding, modifying, or debugging FFI-exported types and functions in the onde crate.
4 +allowed-tools: Read, Write, Edit, Glob, Grep
5 +user-invocable: false
6 +---
7 +
8 +# uniffi-rs
9 +
10 +## What This Skill Covers
11 +
12 +How UniFFI is used in the `onde` crate to generate Swift, Kotlin, and Python bindings from a single Rust implementation.
13 +
14 +## Version Pin
15 +
16 +UniFFI is pinned to exactly `=0.31.0` everywhere. This version must stay in sync across:
17 +- `onde/Cargo.toml` → `uniffi = { version = "=0.31.0", features = ["tokio"] }`
18 +- `onde/Cargo.toml` build-deps → `uniffi = { version = "=0.31.0", features = ["build"] }`
19 +- `onde/uniffi-bindgen/Cargo.toml` → `uniffi = { version = "=0.31.0", features = ["cli"] }`
20 +
21 +Never bump one without bumping all three. Mismatched versions produce silently broken bindings.
22 +
23 +## Project Structure
24 +
25 +```
26 +onde/
27 +├── src/lib.rs # uniffi::setup_scaffolding!()
28 +├── src/inference/
29 +│ ├── types.rs # #[derive(uniffi::Record/Enum/Error)]
30 +│ └── ffi.rs # #[derive(uniffi::Object)], #[uniffi::export]
31 +├── uniffi-bindgen/
32 +│ ├── Cargo.toml # Standalone bin crate for the bindgen CLI
33 +│ └── uniffi-bindgen.rs # fn main() { uniffi::uniffi_bindgen_main() }
34 +├── uniffi.toml # Binding config (package names, cdylib name)
35 +└── build.rs # uniffi build support (build-dep)
36 +```
37 +
38 +## Scaffolding Setup
39 +
40 +`src/lib.rs` uses the proc-macro approach:
41 +
42 +```rust
43 +uniffi::setup_scaffolding!();
44 +```
45 +
46 +This is equivalent to the UDL approach but requires no `.udl` file. The `build.rs` still declares the `uniffi` build-dep to keep compatibility if the project ever switches to UDL.
47 +
48 +## Type Annotations
49 +
50 +| Rust construct | UniFFI derive | Crosses FFI as |
51 +|---|---|---|
52 +| Plain data struct | `#[derive(uniffi::Record)]` | Swift `struct` / Kotlin `data class` |
53 +| C-like / rich enum | `#[derive(uniffi::Enum)]` | Swift `enum` / Kotlin `sealed class` |
54 +| `thiserror::Error` enum | `#[derive(uniffi::Error)]` | Swift `Error enum` / Kotlin exception |
55 +| `Arc<T>` wrapper struct | `#[derive(uniffi::Object)]` | Swift `class` / Kotlin `object` |
56 +| Trait for callbacks | `#[uniffi::export(callback_interface)]` | Swift `protocol` / Kotlin `interface` |
57 +
58 +All exported functions and impl blocks are annotated with `#[uniffi::export]`.
59 +
60 +## Type Compatibility Rules
61 +
62 +These constraints come directly from UniFFI 0.31 limitations:
63 +
64 +- **`usize` / `isize` are not supported** — use `u64` / `i64` instead.
65 +- **`impl Into<String>` is not FFI-safe** — use concrete `String` in all exported method signatures.
66 +- **`tokio::sync::mpsc::Receiver` is not FFI-safe** — streaming is exposed via a `callback_interface` trait delivered through a free function, not an Object method.
67 +- **`callback_interface` parameters must be on free functions** — UniFFI 0.31 does not support `callback_interface` arguments on `#[uniffi::Object]` methods.
68 +- **Generics are not supported** — all exported types must be fully concrete.
69 +
70 +## The uniffi-bindgen CLI
71 +
72 +`onde/uniffi-bindgen/` is a minimal standalone binary crate:
73 +
74 +```rust
75 +// uniffi-bindgen.rs
76 +fn main() {
77 + uniffi::uniffi_bindgen_main()
78 +}
79 +```
80 +
81 +Build it once and run it to generate bindings:
82 +
83 +```bash
84 +cargo build --manifest-path uniffi-bindgen/Cargo.toml --release
85 +
86 +# Generate Swift
87 +./target/release/uniffi-bindgen generate \
88 + --library target/aarch64-apple-tvos/release/libonde.a \
89 + --language swift \
90 + --out-dir sdk/Onde/Sources/Onde \
91 + --config uniffi.toml
92 +
93 +# Generate Kotlin
94 +./target/release/uniffi-bindgen generate \
95 + --library target/aarch64-linux-android/release/libonde.so \
96 + --language kotlin \
97 + --out-dir sdk/kotlin/onde/src/main/kotlin \
98 + --config uniffi.toml
99 +
100 +# Generate Python
101 +./target/release/uniffi-bindgen generate \
102 + --library target/release/libonde.dylib \
103 + --language python \
104 + --out-dir sdk/python \
105 + --config uniffi.toml
106 +```
107 +
108 +The `--library` argument points to a compiled artifact (`.a`, `.so`, or `.dylib`). UniFFI reads the embedded metadata from the binary — any compiled artifact from any platform works for generating bindings for any language.
109 +
110 +## uniffi.toml
111 +
112 +```toml
113 +[bindings.kotlin]
114 +package_name = "com.ondeinference.onde"
115 +cdylib_name = "onde"
116 +
117 +[bindings.python]
118 +cdylib_name = "onde"
119 +```
120 +
121 +No Swift-specific config is needed here. `cargo-swift` (when used) and the raw `uniffi-bindgen` both derive Swift names from the Rust struct/function names.
122 +
123 +## Async Support
124 +
125 +UniFFI 0.31 supports `async fn` exports when the crate enables the `tokio` feature:
126 +
127 +```toml
128 +uniffi = { version = "=0.31.0", features = ["tokio"] }
129 +```
130 +
131 +All `async fn` methods on `#[uniffi::Object]` and all `async` free functions annotated with `#[uniffi::export]` are automatically bridged to Swift `async throws` and Kotlin `suspend fun`.
132 +
133 +## Streaming Pattern
134 +
135 +Because `callback_interface` is not allowed on Object methods in UniFFI 0.31, streaming is exposed as a top-level free function that accepts the Object by `Arc<T>`:
136 +
137 +```rust
138 +// CORRECT — free function with Arc<Object>
139 +#[uniffi::export]
140 +pub async fn stream_chat_message(
141 + engine: Arc<OndeChatEngine>,
142 + message: String,
143 + listener: Box<dyn StreamChunkListener>, // callback_interface
144 +) -> Result<(), InferenceError> { ... }
145 +
146 +// WRONG — callback_interface on Object method (not supported in 0.31)
147 +// impl OndeChatEngine {
148 +// pub async fn stream(&self, listener: Box<dyn StreamChunkListener>) { ... }
149 +// }
150 +```
151 +
152 +## Adding a New Exported Type
153 +
154 +1. Define the type in `src/inference/types.rs` (or whichever module owns it).
155 +2. Add the appropriate `#[derive(uniffi::Record)]` / `#[derive(uniffi::Enum)]` / `#[derive(uniffi::Error)]`.
156 +3. Replace any `usize` fields with `u64`, and any `isize` with `i64`.
157 +4. If the type needs to be exported from the FFI Object, add it to the method signatures in `src/inference/ffi.rs`.
158 +5. Recompile for any Apple target and re-run `uniffi-bindgen generate` for Swift.
159 +6. Re-run `build-kotlin.sh` for Kotlin.
160 +
161 +## Common Pitfalls
162 +
163 +- **Version mismatch**: If the `uniffi` version in `onde/Cargo.toml` differs from the one in `onde/uniffi-bindgen/Cargo.toml`, the generated bindings will be incompatible with the compiled library at runtime. Always keep them identical with the `=` exact pin.
164 +- **Forgetting `setup_scaffolding!()`**: Without `uniffi::setup_scaffolding!()` in `lib.rs`, no scaffolding code is generated and all `#[uniffi::export]` annotations are silently ignored.
165 +- **`usize` in struct fields**: UniFFI will produce a hard compile error or a confusing runtime panic if `usize` appears in any exported type. Always use `u64`.
166 +- **Callback interface in Object method**: This compiles fine but panics at runtime in UniFFI 0.31. Move the method to a free function.
167 +- **Not rebuilding the bindgen binary**: If you update `uniffi` in the main `Cargo.toml` without rebuilding `uniffi-bindgen`, the CLI will use the old schema and generate stale/broken bindings.
\ No newline at end of file
.cargo/config.toml new
+14
@@ -0,0 +1,14 @@
1 +[target.aarch64-apple-ios]
2 +rustflags = ["-C", "target-feature=+fp16"]
3 +
4 +[target.aarch64-apple-ios-sim]
5 +rustflags = ["-C", "target-feature=+fp16"]
6 +
7 +[target.aarch64-apple-tvos]
8 +rustflags = ["-C", "target-feature=+fp16"]
9 +
10 +[target.aarch64-apple-tvos-sim]
11 +rustflags = ["-C", "target-feature=+fp16"]
12 +
13 +[target.x86_64-apple-tvos]
14 +rustflags = ["-C", "target-feature=+fp16"]
.gitignore new
+28
@@ -0,0 +1,28 @@
1 +# Generated by Cargo
2 +target/
3 +uniffi-bindgen/target
4 +sdk/python/target/
5 +
6 +# uniffi
7 +generated/
8 +
9 +# sdk
10 +sdk/Onde
11 +sdk/kotlin/onde/src/main/jniLibs/**/*.so
12 +sdk/kotlin/onde/src/main/kotlin/com/ondeinference/onde/onde.kt
13 +sdk/kotlin/.gradle
14 +sdk/kotlin/onde/build
15 +sdk/kotlin/local.properties
16 +
17 +# Python package (maturin build artifacts)
18 +sdk/python/dist/
19 +sdk/python/build/
20 +sdk/python/.venv/
21 +sdk/python/python/onde_inference/_native.*
22 +sdk/python/python/onde_inference/*.so
23 +sdk/python/python/onde_inference/*.dylib
24 +sdk/python/python/onde_inference/*.dll
25 +sdk/python/python/onde_inference/*.pyd
26 +sdk/python/**/__pycache__/
27 +sdk/python/**/*.egg-info/
28 +sdk/python/.pytest_cache/
Cargo.lock new
+7700
@@ -0,0 +1,7700 @@
1 +# This file is automatically @generated by Cargo.
2 +# It is not intended for manual editing.
3 +version = 4
4 +
5 +[[package]]
6 +name = "Inflector"
7 +version = "0.11.4"
8 +source = "registry+https://github.com/rust-lang/crates.io-index"
9 +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
10 +dependencies = [
11 + "lazy_static",
12 + "regex",
13 +]
14 +
15 +[[package]]
16 +name = "adler2"
17 +version = "2.0.1"
18 +source = "registry+https://github.com/rust-lang/crates.io-index"
19 +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
20 +
21 +[[package]]
22 +name = "ahash"
23 +version = "0.8.12"
24 +source = "registry+https://github.com/rust-lang/crates.io-index"
25 +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
26 +dependencies = [
27 + "cfg-if",
28 + "getrandom 0.3.4",
29 + "once_cell",
30 + "serde",
31 + "version_check",
32 + "zerocopy",
33 +]
34 +
35 +[[package]]
36 +name = "aho-corasick"
37 +version = "1.1.4"
38 +source = "registry+https://github.com/rust-lang/crates.io-index"
39 +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
40 +dependencies = [
41 + "memchr",
42 +]
43 +
44 +[[package]]
45 +name = "akin"
46 +version = "0.4.0"
47 +source = "registry+https://github.com/rust-lang/crates.io-index"
48 +checksum = "1763692fc1416554cf051efc56a3de5595eca47299d731cc5c2b583adf8b4d2f"
49 +
50 +[[package]]
51 +name = "aligned"
52 +version = "0.4.3"
53 +source = "registry+https://github.com/rust-lang/crates.io-index"
54 +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
55 +dependencies = [
56 + "as-slice",
57 +]
58 +
59 +[[package]]
60 +name = "aligned-vec"
61 +version = "0.6.4"
62 +source = "registry+https://github.com/rust-lang/crates.io-index"
63 +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
64 +dependencies = [
65 + "equator",
66 +]
67 +
68 +[[package]]
69 +name = "allocator-api2"
70 +version = "0.2.21"
71 +source = "registry+https://github.com/rust-lang/crates.io-index"
72 +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
73 +
74 +[[package]]
75 +name = "android_system_properties"
76 +version = "0.1.5"
77 +source = "registry+https://github.com/rust-lang/crates.io-index"
78 +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
79 +dependencies = [
80 + "libc",
81 +]
82 +
83 +[[package]]
84 +name = "annotate-snippets"
85 +version = "0.12.13"
86 +source = "registry+https://github.com/rust-lang/crates.io-index"
87 +checksum = "74fc7650eedcb2fee505aad48491529e408f0e854c2d9f63eb86c1361b9b3f93"
88 +dependencies = [
89 + "anstyle",
90 + "memchr",
91 + "unicode-width 0.2.2",
92 +]
93 +
94 +[[package]]
95 +name = "ansi_term"
96 +version = "0.12.1"
97 +source = "registry+https://github.com/rust-lang/crates.io-index"
98 +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
99 +dependencies = [
100 + "winapi",
101 +]
102 +
103 +[[package]]
104 +name = "anstream"
105 +version = "1.0.0"
106 +source = "registry+https://github.com/rust-lang/crates.io-index"
107 +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
108 +dependencies = [
109 + "anstyle",
110 + "anstyle-parse",
111 + "anstyle-query",
112 + "anstyle-wincon",
113 + "colorchoice",
114 + "is_terminal_polyfill",
115 + "utf8parse",
116 +]
117 +
118 +[[package]]
119 +name = "anstyle"
120 +version = "1.0.14"
121 +source = "registry+https://github.com/rust-lang/crates.io-index"
122 +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
123 +
124 +[[package]]
125 +name = "anstyle-parse"
126 +version = "1.0.0"
127 +source = "registry+https://github.com/rust-lang/crates.io-index"
128 +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
129 +dependencies = [
130 + "utf8parse",
131 +]
132 +
133 +[[package]]
134 +name = "anstyle-query"
135 +version = "1.1.5"
136 +source = "registry+https://github.com/rust-lang/crates.io-index"
137 +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
138 +dependencies = [
139 + "windows-sys 0.61.2",
140 +]
141 +
142 +[[package]]
143 +name = "anstyle-wincon"
144 +version = "3.0.11"
145 +source = "registry+https://github.com/rust-lang/crates.io-index"
146 +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
147 +dependencies = [
148 + "anstyle",
149 + "once_cell_polyfill",
150 + "windows-sys 0.61.2",
151 +]
152 +
153 +[[package]]
154 +name = "anyhow"
155 +version = "1.0.102"
156 +source = "registry+https://github.com/rust-lang/crates.io-index"
157 +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
158 +
159 +[[package]]
160 +name = "apodize"
161 +version = "1.0.0"
162 +source = "registry+https://github.com/rust-lang/crates.io-index"
163 +checksum = "fca387cdc0a1f9c7a7c26556d584aa2d07fc529843082e4861003cde4ab914ed"
164 +
165 +[[package]]
166 +name = "approx"
167 +version = "0.5.1"
168 +source = "registry+https://github.com/rust-lang/crates.io-index"
169 +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
170 +dependencies = [
171 + "num-traits",
172 +]
173 +
174 +[[package]]
175 +name = "arbitrary"
176 +version = "1.4.2"
177 +source = "registry+https://github.com/rust-lang/crates.io-index"
178 +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
179 +
180 +[[package]]
181 +name = "arg_enum_proc_macro"
182 +version = "0.3.4"
183 +source = "registry+https://github.com/rust-lang/crates.io-index"
184 +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
185 +dependencies = [
186 + "proc-macro2",
187 + "quote",
188 + "syn 2.0.117",
189 +]
190 +
191 +[[package]]
192 +name = "arraydeque"
193 +version = "0.5.1"
194 +source = "registry+https://github.com/rust-lang/crates.io-index"
195 +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
196 +
197 +[[package]]
198 +name = "arrayvec"
199 +version = "0.7.6"
200 +source = "registry+https://github.com/rust-lang/crates.io-index"
201 +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
202 +
203 +[[package]]
204 +name = "as-any"
205 +version = "0.3.2"
206 +source = "registry+https://github.com/rust-lang/crates.io-index"
207 +checksum = "b0f477b951e452a0b6b4a10b53ccd569042d1d01729b519e02074a9c0958a063"
208 +
209 +[[package]]
210 +name = "as-slice"
211 +version = "0.2.1"
212 +source = "registry+https://github.com/rust-lang/crates.io-index"
213 +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
214 +dependencies = [
215 + "stable_deref_trait",
216 +]
217 +
218 +[[package]]
219 +name = "askama"
220 +version = "0.14.0"
221 +source = "registry+https://github.com/rust-lang/crates.io-index"
222 +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
223 +dependencies = [
224 + "askama_derive",
225 + "itoa",
226 + "percent-encoding",
227 + "serde",
228 + "serde_json",
229 +]
230 +
231 +[[package]]
232 +name = "askama_derive"
233 +version = "0.14.0"
234 +source = "registry+https://github.com/rust-lang/crates.io-index"
235 +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
236 +dependencies = [
237 + "askama_parser",
238 + "basic-toml",
239 + "memchr",
240 + "proc-macro2",
241 + "quote",
242 + "rustc-hash 2.1.1",
243 + "serde",
244 + "serde_derive",
245 + "syn 2.0.117",
246 +]
247 +
248 +[[package]]
249 +name = "askama_parser"
250 +version = "0.14.0"
251 +source = "registry+https://github.com/rust-lang/crates.io-index"
252 +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
253 +dependencies = [
254 + "memchr",
255 + "serde",
256 + "serde_derive",
257 + "winnow 0.7.15",
258 +]
259 +
260 +[[package]]
261 +name = "async-compat"
262 +version = "0.2.5"
263 +source = "registry+https://github.com/rust-lang/crates.io-index"
264 +checksum = "a1ba85bc55464dcbf728b56d97e119d673f4cf9062be330a9a26f3acf504a590"
265 +dependencies = [
266 + "futures-core",
267 + "futures-io",
268 + "once_cell",
269 + "pin-project-lite",
270 + "tokio",
271 +]
272 +
273 +[[package]]
274 +name = "async-trait"
275 +version = "0.1.89"
276 +source = "registry+https://github.com/rust-lang/crates.io-index"
277 +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
278 +dependencies = [
279 + "proc-macro2",
280 + "quote",
281 + "syn 2.0.117",
282 +]
283 +
284 +[[package]]
285 +name = "atomic-waker"
286 +version = "1.1.2"
287 +source = "registry+https://github.com/rust-lang/crates.io-index"
288 +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
289 +
290 +[[package]]
291 +name = "atty"
292 +version = "0.2.14"
293 +source = "registry+https://github.com/rust-lang/crates.io-index"
294 +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
295 +dependencies = [
296 + "hermit-abi 0.1.19",
297 + "libc",
298 + "winapi",
299 +]
300 +
301 +[[package]]
302 +name = "autocfg"
303 +version = "1.5.0"
304 +source = "registry+https://github.com/rust-lang/crates.io-index"
305 +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
306 +
307 +[[package]]
308 +name = "av-scenechange"
309 +version = "0.14.1"
310 +source = "registry+https://github.com/rust-lang/crates.io-index"
311 +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394"
312 +dependencies = [
313 + "aligned",
314 + "anyhow",
315 + "arg_enum_proc_macro",
316 + "arrayvec",
317 + "log",
318 + "num-rational",
319 + "num-traits",
320 + "pastey",
321 + "rayon",
322 + "thiserror 2.0.18",
323 + "v_frame",
324 + "y4m",
325 +]
326 +
327 +[[package]]
328 +name = "av1-grain"
329 +version = "0.2.5"
330 +source = "registry+https://github.com/rust-lang/crates.io-index"
331 +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
332 +dependencies = [
333 + "anyhow",
334 + "arrayvec",
335 + "log",
336 + "nom 8.0.0",
337 + "num-rational",
338 + "v_frame",
339 +]
340 +
341 +[[package]]
342 +name = "avif-serialize"
343 +version = "0.8.8"
344 +source = "registry+https://github.com/rust-lang/crates.io-index"
345 +checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d"
346 +dependencies = [
347 + "arrayvec",
348 +]
349 +
350 +[[package]]
351 +name = "aws-lc-rs"
352 +version = "1.16.2"
353 +source = "registry+https://github.com/rust-lang/crates.io-index"
354 +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc"
355 +dependencies = [
356 + "aws-lc-sys",
357 + "zeroize",
358 +]
359 +
360 +[[package]]
361 +name = "aws-lc-sys"
362 +version = "0.39.0"
363 +source = "registry+https://github.com/rust-lang/crates.io-index"
364 +checksum = "1fa7e52a4c5c547c741610a2c6f123f3881e409b714cd27e6798ef020c514f0a"
365 +dependencies = [
366 + "cc",
367 + "cmake",
368 + "dunce",
369 + "fs_extra",
370 +]
371 +
372 +[[package]]
373 +name = "base64"
374 +version = "0.13.1"
375 +source = "registry+https://github.com/rust-lang/crates.io-index"
376 +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
377 +
378 +[[package]]
379 +name = "base64"
380 +version = "0.22.1"
381 +source = "registry+https://github.com/rust-lang/crates.io-index"
382 +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
383 +
384 +[[package]]
385 +name = "basic-toml"
386 +version = "0.1.10"
387 +source = "registry+https://github.com/rust-lang/crates.io-index"
388 +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
389 +dependencies = [
390 + "serde",
391 +]
392 +
393 +[[package]]
394 +name = "bindgen"
395 +version = "0.69.5"
396 +source = "registry+https://github.com/rust-lang/crates.io-index"
397 +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
398 +dependencies = [
399 + "bitflags 2.11.0",
400 + "cexpr",
401 + "clang-sys",
402 + "itertools 0.12.1",
403 + "lazy_static",
404 + "lazycell",
405 + "log",
406 + "prettyplease",
407 + "proc-macro2",
408 + "quote",
409 + "regex",
410 + "rustc-hash 1.1.0",
411 + "shlex",
412 + "syn 2.0.117",
413 + "which",
414 +]
415 +
416 +[[package]]
417 +name = "bit-set"
418 +version = "0.5.3"
419 +source = "registry+https://github.com/rust-lang/crates.io-index"
420 +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
421 +dependencies = [
422 + "bit-vec 0.6.3",
423 +]
424 +
425 +[[package]]
426 +name = "bit-set"
427 +version = "0.8.0"
428 +source = "registry+https://github.com/rust-lang/crates.io-index"
429 +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
430 +dependencies = [
431 + "bit-vec 0.8.0",
432 +]
433 +
434 +[[package]]
435 +name = "bit-vec"
436 +version = "0.6.3"
437 +source = "registry+https://github.com/rust-lang/crates.io-index"
438 +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
439 +
440 +[[package]]
441 +name = "bit-vec"
442 +version = "0.8.0"
443 +source = "registry+https://github.com/rust-lang/crates.io-index"
444 +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
445 +
446 +[[package]]
447 +name = "bit_field"
448 +version = "0.10.3"
449 +source = "registry+https://github.com/rust-lang/crates.io-index"
450 +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
451 +
452 +[[package]]
453 +name = "bitflags"
454 +version = "1.3.2"
455 +source = "registry+https://github.com/rust-lang/crates.io-index"
456 +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
457 +
458 +[[package]]
459 +name = "bitflags"
460 +version = "2.11.0"
461 +source = "registry+https://github.com/rust-lang/crates.io-index"
462 +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
463 +
464 +[[package]]
465 +name = "bitstream-io"
466 +version = "4.9.0"
467 +source = "registry+https://github.com/rust-lang/crates.io-index"
468 +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757"
469 +dependencies = [
470 + "core2",
471 +]
472 +
473 +[[package]]
474 +name = "block"
475 +version = "0.1.6"
476 +source = "registry+https://github.com/rust-lang/crates.io-index"
477 +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
478 +
479 +[[package]]
480 +name = "block-buffer"
481 +version = "0.10.4"
482 +source = "registry+https://github.com/rust-lang/crates.io-index"
483 +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
484 +dependencies = [
485 + "generic-array",
486 +]
487 +
488 +[[package]]
489 +name = "block2"
490 +version = "0.6.2"
491 +source = "registry+https://github.com/rust-lang/crates.io-index"
492 +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
493 +dependencies = [
494 + "objc2",
495 +]
496 +
497 +[[package]]
498 +name = "bm25"
499 +version = "2.3.2"
500 +source = "registry+https://github.com/rust-lang/crates.io-index"
501 +checksum = "1cbd8ffdfb7b4c2ff038726178a780a94f90525ed0ad264c0afaa75dd8c18a64"
502 +dependencies = [
503 + "cached",
504 + "deunicode",
505 + "fxhash",
506 + "rust-stemmers",
507 + "stop-words",
508 + "unicode-segmentation",
509 +]
510 +
511 +[[package]]
512 +name = "bstr"
513 +version = "1.12.1"
514 +source = "registry+https://github.com/rust-lang/crates.io-index"
515 +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
516 +dependencies = [
517 + "memchr",
518 + "regex-automata",
519 + "serde",
520 +]
521 +
522 +[[package]]
523 +name = "built"
524 +version = "0.8.0"
525 +source = "registry+https://github.com/rust-lang/crates.io-index"
526 +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64"
527 +
528 +[[package]]
529 +name = "bumpalo"
530 +version = "3.20.2"
531 +source = "registry+https://github.com/rust-lang/crates.io-index"
532 +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
533 +
534 +[[package]]
535 +name = "bytemuck"
536 +version = "1.25.0"
537 +source = "registry+https://github.com/rust-lang/crates.io-index"
538 +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
539 +dependencies = [
540 + "bytemuck_derive",
541 +]
542 +
543 +[[package]]
544 +name = "bytemuck_derive"
545 +version = "1.10.2"
546 +source = "registry+https://github.com/rust-lang/crates.io-index"
547 +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
548 +dependencies = [
549 + "proc-macro2",
550 + "quote",
551 + "syn 2.0.117",
552 +]
553 +
554 +[[package]]
555 +name = "byteorder"
556 +version = "1.5.0"
557 +source = "registry+https://github.com/rust-lang/crates.io-index"
558 +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
559 +
560 +[[package]]
561 +name = "byteorder-lite"
562 +version = "0.1.0"
563 +source = "registry+https://github.com/rust-lang/crates.io-index"
564 +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
565 +
566 +[[package]]
567 +name = "bytes"
568 +version = "1.11.1"
569 +source = "registry+https://github.com/rust-lang/crates.io-index"
570 +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
571 +
572 +[[package]]
573 +name = "cached"
574 +version = "0.56.0"
575 +source = "registry+https://github.com/rust-lang/crates.io-index"
576 +checksum = "801927ee168e17809ab8901d9f01f700cd7d8d6a6527997fee44e4b0327a253c"
577 +dependencies = [
578 + "ahash",
579 + "cached_proc_macro",
580 + "cached_proc_macro_types",
581 + "hashbrown 0.15.5",
582 + "once_cell",
583 + "thiserror 2.0.18",
584 + "web-time",
585 +]
586 +
587 +[[package]]
588 +name = "cached_proc_macro"
589 +version = "0.25.0"
590 +source = "registry+https://github.com/rust-lang/crates.io-index"
591 +checksum = "9225bdcf4e4a9a4c08bf16607908eb2fbf746828d5e0b5e019726dbf6571f201"
592 +dependencies = [
593 + "darling 0.20.11",
594 + "proc-macro2",
595 + "quote",
596 + "syn 2.0.117",
597 +]
598 +
599 +[[package]]
600 +name = "cached_proc_macro_types"
601 +version = "0.1.1"
602 +source = "registry+https://github.com/rust-lang/crates.io-index"
603 +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
604 +
605 +[[package]]
606 +name = "camino"
607 +version = "1.2.2"
608 +source = "registry+https://github.com/rust-lang/crates.io-index"
609 +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48"
610 +dependencies = [
611 + "serde_core",
612 +]
613 +
614 +[[package]]
615 +name = "candle-core"
616 +version = "0.9.2"
617 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
618 +dependencies = [
619 + "byteorder",
620 + "candle-metal-kernels",
621 + "candle-ug",
622 + "float8",
623 + "gemm 0.19.0",
624 + "half",
625 + "libm",
626 + "memmap2",
627 + "num-traits",
628 + "num_cpus",
629 + "objc2-foundation",
630 + "objc2-metal",
631 + "rand 0.9.2",
632 + "rand_distr 0.5.1",
633 + "rayon",
634 + "safetensors 0.7.0",
635 + "thiserror 2.0.18",
636 + "yoke 0.8.1",
637 + "zip",
638 +]
639 +
640 +[[package]]
641 +name = "candle-metal-kernels"
642 +version = "0.9.2"
643 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
644 +dependencies = [
645 + "half",
646 + "objc2",
647 + "objc2-foundation",
648 + "objc2-metal",
649 + "once_cell",
650 + "thiserror 2.0.18",
651 + "tracing",
652 +]
653 +
654 +[[package]]
655 +name = "candle-nn"
656 +version = "0.9.2"
657 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
658 +dependencies = [
659 + "candle-core",
660 + "candle-metal-kernels",
661 + "half",
662 + "libc",
663 + "num-traits",
664 + "objc2-metal",
665 + "rayon",
666 + "safetensors 0.7.0",
667 + "serde",
668 + "thiserror 2.0.18",
669 +]
670 +
671 +[[package]]
672 +name = "candle-ug"
673 +version = "0.9.2"
674 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
675 +dependencies = [
676 + "ug",
677 + "ug-metal",
678 +]
679 +
680 +[[package]]
681 +name = "cargo-platform"
682 +version = "0.1.9"
683 +source = "registry+https://github.com/rust-lang/crates.io-index"
684 +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
685 +dependencies = [
686 + "serde",
687 +]
688 +
689 +[[package]]
690 +name = "cargo_metadata"
691 +version = "0.19.2"
692 +source = "registry+https://github.com/rust-lang/crates.io-index"
693 +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
694 +dependencies = [
695 + "camino",
696 + "cargo-platform",
697 + "semver",
698 + "serde",
699 + "serde_json",
700 + "thiserror 2.0.18",
701 +]
702 +
703 +[[package]]
704 +name = "castaway"
705 +version = "0.2.4"
706 +source = "registry+https://github.com/rust-lang/crates.io-index"
707 +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
708 +dependencies = [
709 + "rustversion",
710 +]
711 +
712 +[[package]]
713 +name = "cc"
714 +version = "1.2.57"
715 +source = "registry+https://github.com/rust-lang/crates.io-index"
716 +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
717 +dependencies = [
718 + "find-msvc-tools",
719 + "jobserver",
720 + "libc",
721 + "shlex",
722 +]
723 +
724 +[[package]]
725 +name = "cesu8"
726 +version = "1.1.0"
727 +source = "registry+https://github.com/rust-lang/crates.io-index"
728 +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
729 +
730 +[[package]]
731 +name = "cexpr"
732 +version = "0.6.0"
733 +source = "registry+https://github.com/rust-lang/crates.io-index"
734 +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
735 +dependencies = [
736 + "nom 7.1.3",
737 +]
738 +
739 +[[package]]
740 +name = "cfg-if"
741 +version = "1.0.4"
742 +source = "registry+https://github.com/rust-lang/crates.io-index"
743 +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
744 +
745 +[[package]]
746 +name = "cfg_aliases"
747 +version = "0.2.1"
748 +source = "registry+https://github.com/rust-lang/crates.io-index"
749 +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
750 +
751 +[[package]]
752 +name = "cfgrammar"
753 +version = "0.14.1"
754 +source = "registry+https://github.com/rust-lang/crates.io-index"
755 +checksum = "3efdd8f0bddcc9e33f4a664d0f28bc4e51cd5367c16284087a95313104371865"
756 +dependencies = [
757 + "indexmap 2.13.0",
758 + "num-traits",
759 + "proc-macro2",
760 + "quote",
761 + "regex",
762 + "vob",
763 +]
764 +
765 +[[package]]
766 +name = "chrono"
767 +version = "0.4.44"
768 +source = "registry+https://github.com/rust-lang/crates.io-index"
769 +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
770 +dependencies = [
771 + "iana-time-zone",
772 + "js-sys",
773 + "num-traits",
774 + "serde",
775 + "wasm-bindgen",
776 + "windows-link 0.2.1",
777 +]
778 +
779 +[[package]]
780 +name = "clang-sys"
781 +version = "1.8.1"
782 +source = "registry+https://github.com/rust-lang/crates.io-index"
783 +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
784 +dependencies = [
785 + "glob",
786 + "libc",
787 + "libloading",
788 +]
789 +
790 +[[package]]
791 +name = "clap"
792 +version = "2.34.0"
793 +source = "registry+https://github.com/rust-lang/crates.io-index"
794 +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
795 +dependencies = [
796 + "ansi_term",
797 + "atty",
798 + "bitflags 1.3.2",
799 + "strsim 0.8.0",
800 + "textwrap 0.11.0",
801 + "unicode-width 0.1.14",
802 + "vec_map",
803 +]
804 +
805 +[[package]]
806 +name = "clap"
807 +version = "4.6.0"
808 +source = "registry+https://github.com/rust-lang/crates.io-index"
809 +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
810 +dependencies = [
811 + "clap_builder",
812 + "clap_derive",
813 +]
814 +
815 +[[package]]
816 +name = "clap_builder"
817 +version = "4.6.0"
818 +source = "registry+https://github.com/rust-lang/crates.io-index"
819 +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
820 +dependencies = [
821 + "anstream",
822 + "anstyle",
823 + "clap_lex",
824 + "strsim 0.11.1",
825 + "terminal_size",
826 +]
827 +
828 +[[package]]
829 +name = "clap_derive"
830 +version = "4.6.0"
831 +source = "registry+https://github.com/rust-lang/crates.io-index"
832 +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
833 +dependencies = [
834 + "heck 0.5.0",
835 + "proc-macro2",
836 + "quote",
837 + "syn 2.0.117",
838 +]
839 +
840 +[[package]]
841 +name = "clap_lex"
842 +version = "1.1.0"
843 +source = "registry+https://github.com/rust-lang/crates.io-index"
844 +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
845 +
846 +[[package]]
847 +name = "cmake"
848 +version = "0.1.57"
849 +source = "registry+https://github.com/rust-lang/crates.io-index"
850 +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
851 +dependencies = [
852 + "cc",
853 +]
854 +
855 +[[package]]
856 +name = "color_quant"
857 +version = "1.1.0"
858 +source = "registry+https://github.com/rust-lang/crates.io-index"
859 +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
860 +
861 +[[package]]
862 +name = "colorchoice"
863 +version = "1.0.5"
864 +source = "registry+https://github.com/rust-lang/crates.io-index"
865 +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
866 +
867 +[[package]]
868 +name = "combine"
869 +version = "4.6.7"
870 +source = "registry+https://github.com/rust-lang/crates.io-index"
871 +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
872 +dependencies = [
873 + "bytes",
874 + "memchr",
875 +]
876 +
877 +[[package]]
878 +name = "compact_str"
879 +version = "0.9.0"
880 +source = "registry+https://github.com/rust-lang/crates.io-index"
881 +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
882 +dependencies = [
883 + "castaway",
884 + "cfg-if",
885 + "itoa",
886 + "rustversion",
887 + "ryu",
888 + "serde",
889 + "static_assertions",
890 +]
891 +
892 +[[package]]
893 +name = "console"
894 +version = "0.15.11"
895 +source = "registry+https://github.com/rust-lang/crates.io-index"
896 +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
897 +dependencies = [
898 + "encode_unicode",
899 + "libc",
900 + "once_cell",
901 + "unicode-width 0.2.2",
902 + "windows-sys 0.59.0",
903 +]
904 +
905 +[[package]]
906 +name = "console"
907 +version = "0.16.3"
908 +source = "registry+https://github.com/rust-lang/crates.io-index"
909 +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87"
910 +dependencies = [
911 + "encode_unicode",
912 + "libc",
913 + "unicode-width 0.2.2",
914 + "windows-sys 0.61.2",
915 +]
916 +
917 +[[package]]
918 +name = "convert_case"
919 +version = "0.6.0"
920 +source = "registry+https://github.com/rust-lang/crates.io-index"
921 +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
922 +dependencies = [
923 + "unicode-segmentation",
924 +]
925 +
926 +[[package]]
927 +name = "core-foundation"
928 +version = "0.9.4"
929 +source = "registry+https://github.com/rust-lang/crates.io-index"
930 +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
931 +dependencies = [
932 + "core-foundation-sys",
933 + "libc",
934 +]
935 +
936 +[[package]]
937 +name = "core-foundation"
938 +version = "0.10.1"
939 +source = "registry+https://github.com/rust-lang/crates.io-index"
940 +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
941 +dependencies = [
942 + "core-foundation-sys",
943 + "libc",
944 +]
945 +
946 +[[package]]
947 +name = "core-foundation-sys"
948 +version = "0.8.7"
949 +source = "registry+https://github.com/rust-lang/crates.io-index"
950 +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
951 +
952 +[[package]]
953 +name = "core-graphics-types"
954 +version = "0.1.3"
955 +source = "registry+https://github.com/rust-lang/crates.io-index"
956 +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
957 +dependencies = [
958 + "bitflags 1.3.2",
959 + "core-foundation 0.9.4",
960 + "libc",
961 +]
962 +
963 +[[package]]
964 +name = "core2"
965 +version = "0.4.0"
966 +source = "registry+https://github.com/rust-lang/crates.io-index"
967 +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
968 +dependencies = [
969 + "memchr",
970 +]
971 +
972 +[[package]]
973 +name = "cpufeatures"
974 +version = "0.2.17"
975 +source = "registry+https://github.com/rust-lang/crates.io-index"
976 +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
977 +dependencies = [
978 + "libc",
979 +]
980 +
981 +[[package]]
982 +name = "crc32fast"
983 +version = "1.5.0"
984 +source = "registry+https://github.com/rust-lang/crates.io-index"
985 +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
986 +dependencies = [
987 + "cfg-if",
988 +]
989 +
990 +[[package]]
991 +name = "crossbeam-deque"
992 +version = "0.8.6"
993 +source = "registry+https://github.com/rust-lang/crates.io-index"
994 +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
995 +dependencies = [
996 + "crossbeam-epoch",
997 + "crossbeam-utils",
998 +]
999 +
1000 +[[package]]
1001 +name = "crossbeam-epoch"
1002 +version = "0.9.18"
1003 +source = "registry+https://github.com/rust-lang/crates.io-index"
1004 +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
1005 +dependencies = [
1006 + "crossbeam-utils",
1007 +]
1008 +
1009 +[[package]]
1010 +name = "crossbeam-utils"
1011 +version = "0.8.21"
1012 +source = "registry+https://github.com/rust-lang/crates.io-index"
1013 +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
1014 +
1015 +[[package]]
1016 +name = "crossterm"
1017 +version = "0.25.0"
1018 +source = "registry+https://github.com/rust-lang/crates.io-index"
1019 +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
1020 +dependencies = [
1021 + "bitflags 1.3.2",
1022 + "crossterm_winapi",
1023 + "libc",
1024 + "mio 0.8.11",
1025 + "parking_lot",
1026 + "signal-hook",
1027 + "signal-hook-mio",
1028 + "winapi",
1029 +]
1030 +
1031 +[[package]]
1032 +name = "crossterm_winapi"
1033 +version = "0.9.1"
1034 +source = "registry+https://github.com/rust-lang/crates.io-index"
1035 +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
1036 +dependencies = [
1037 + "winapi",
1038 +]
1039 +
1040 +[[package]]
1041 +name = "crunchy"
1042 +version = "0.2.4"
1043 +source = "registry+https://github.com/rust-lang/crates.io-index"
1044 +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
1045 +
1046 +[[package]]
1047 +name = "crypto-common"
1048 +version = "0.1.7"
1049 +source = "registry+https://github.com/rust-lang/crates.io-index"
1050 +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
1051 +dependencies = [
1052 + "generic-array",
1053 + "typenum",
1054 +]
1055 +
1056 +[[package]]
1057 +name = "cssparser"
1058 +version = "0.36.0"
1059 +source = "registry+https://github.com/rust-lang/crates.io-index"
1060 +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2"
1061 +dependencies = [
1062 + "cssparser-macros",
1063 + "dtoa-short",
1064 + "itoa",
1065 + "phf",
1066 + "smallvec 1.15.1",
1067 +]
1068 +
1069 +[[package]]
1070 +name = "cssparser-macros"
1071 +version = "0.6.1"
1072 +source = "registry+https://github.com/rust-lang/crates.io-index"
1073 +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
1074 +dependencies = [
1075 + "quote",
1076 + "syn 2.0.117",
1077 +]
1078 +
1079 +[[package]]
1080 +name = "csv"
1081 +version = "1.4.0"
1082 +source = "registry+https://github.com/rust-lang/crates.io-index"
1083 +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
1084 +dependencies = [
1085 + "csv-core",
1086 + "itoa",
1087 + "ryu",
1088 + "serde_core",
1089 +]
1090 +
1091 +[[package]]
1092 +name = "csv-core"
1093 +version = "0.1.13"
1094 +source = "registry+https://github.com/rust-lang/crates.io-index"
1095 +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
1096 +dependencies = [
1097 + "memchr",
1098 +]
1099 +
1100 +[[package]]
1101 +name = "darling"
1102 +version = "0.11.0"
1103 +source = "registry+https://github.com/rust-lang/crates.io-index"
1104 +checksum = "dbffa8f8e38810422f320ca457a93cf1cd0056dc9c06c556b867558e0d471463"
1105 +dependencies = [
1106 + "darling_core 0.11.0",
1107 + "darling_macro 0.11.0",
1108 +]
1109 +
1110 +[[package]]
1111 +name = "darling"
1112 +version = "0.20.11"
1113 +source = "registry+https://github.com/rust-lang/crates.io-index"
1114 +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
1115 +dependencies = [
1116 + "darling_core 0.20.11",
1117 + "darling_macro 0.20.11",
1118 +]
1119 +
1120 +[[package]]
1121 +name = "darling"
1122 +version = "0.23.0"
1123 +source = "registry+https://github.com/rust-lang/crates.io-index"
1124 +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
1125 +dependencies = [
1126 + "darling_core 0.23.0",
1127 + "darling_macro 0.23.0",
1128 +]
1129 +
1130 +[[package]]
1131 +name = "darling_core"
1132 +version = "0.11.0"
1133 +source = "registry+https://github.com/rust-lang/crates.io-index"
1134 +checksum = "06e172685d94b7b83800e3256a63261537b9d6129e10f21c8e13ddf9dba8c64d"
1135 +dependencies = [
1136 + "fnv",
1137 + "ident_case",
1138 + "proc-macro2",
1139 + "quote",
1140 + "strsim 0.10.0",
1141 + "syn 1.0.109",
1142 +]
1143 +
1144 +[[package]]
1145 +name = "darling_core"
1146 +version = "0.20.11"
1147 +source = "registry+https://github.com/rust-lang/crates.io-index"
1148 +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
1149 +dependencies = [
1150 + "fnv",
1151 + "ident_case",
1152 + "proc-macro2",
1153 + "quote",
1154 + "strsim 0.11.1",
1155 + "syn 2.0.117",
1156 +]
1157 +
1158 +[[package]]
1159 +name = "darling_core"
1160 +version = "0.23.0"
1161 +source = "registry+https://github.com/rust-lang/crates.io-index"
1162 +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
1163 +dependencies = [
1164 + "ident_case",
1165 + "proc-macro2",
1166 + "quote",
1167 + "strsim 0.11.1",
1168 + "syn 2.0.117",
1169 +]
1170 +
1171 +[[package]]
1172 +name = "darling_macro"
1173 +version = "0.11.0"
1174 +source = "registry+https://github.com/rust-lang/crates.io-index"
1175 +checksum = "f0618ac802792cebd1918ac6042a6ea1eeab92db34b35656afaa577929820788"
1176 +dependencies = [
1177 + "darling_core 0.11.0",
1178 + "quote",
1179 + "syn 1.0.109",
1180 +]
1181 +
1182 +[[package]]
1183 +name = "darling_macro"
1184 +version = "0.20.11"
1185 +source = "registry+https://github.com/rust-lang/crates.io-index"
1186 +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
1187 +dependencies = [
1188 + "darling_core 0.20.11",
1189 + "quote",
1190 + "syn 2.0.117",
1191 +]
1192 +
1193 +[[package]]
1194 +name = "darling_macro"
1195 +version = "0.23.0"
1196 +source = "registry+https://github.com/rust-lang/crates.io-index"
1197 +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
1198 +dependencies = [
1199 + "darling_core 0.23.0",
1200 + "quote",
1201 + "syn 2.0.117",
1202 +]
1203 +
1204 +[[package]]
1205 +name = "dary_heap"
1206 +version = "0.3.8"
1207 +source = "registry+https://github.com/rust-lang/crates.io-index"
1208 +checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04"
1209 +dependencies = [
1210 + "serde",
1211 +]
1212 +
1213 +[[package]]
1214 +name = "data-encoding"
1215 +version = "2.10.0"
1216 +source = "registry+https://github.com/rust-lang/crates.io-index"
1217 +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
1218 +
1219 +[[package]]
1220 +name = "defmac"
1221 +version = "0.1.3"
1222 +source = "registry+https://github.com/rust-lang/crates.io-index"
1223 +checksum = "aafbece59594ed57696a1a69e8bb3ca1683fbc9cdb41d5c02726070b2cd8f19d"
1224 +
1225 +[[package]]
1226 +name = "deranged"
1227 +version = "0.5.8"
1228 +source = "registry+https://github.com/rust-lang/crates.io-index"
1229 +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
1230 +dependencies = [
1231 + "powerfmt",
1232 + "serde_core",
1233 +]
1234 +
1235 +[[package]]
1236 +name = "derive-new"
1237 +version = "0.7.0"
1238 +source = "registry+https://github.com/rust-lang/crates.io-index"
1239 +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc"
1240 +dependencies = [
1241 + "proc-macro2",
1242 + "quote",
1243 + "syn 2.0.117",
1244 +]
1245 +
1246 +[[package]]
1247 +name = "derive_builder"
1248 +version = "0.20.2"
1249 +source = "registry+https://github.com/rust-lang/crates.io-index"
1250 +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
1251 +dependencies = [
1252 + "derive_builder_macro",
1253 +]
1254 +
1255 +[[package]]
1256 +name = "derive_builder_core"
1257 +version = "0.20.2"
1258 +source = "registry+https://github.com/rust-lang/crates.io-index"
1259 +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
1260 +dependencies = [
1261 + "darling 0.20.11",
1262 + "proc-macro2",
1263 + "quote",
1264 + "syn 2.0.117",
1265 +]
1266 +
1267 +[[package]]
1268 +name = "derive_builder_macro"
1269 +version = "0.20.2"
1270 +source = "registry+https://github.com/rust-lang/crates.io-index"
1271 +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
1272 +dependencies = [
1273 + "derive_builder_core",
1274 + "syn 2.0.117",
1275 +]
1276 +
1277 +[[package]]
1278 +name = "derive_more"
1279 +version = "2.1.1"
1280 +source = "registry+https://github.com/rust-lang/crates.io-index"
1281 +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
1282 +dependencies = [
1283 + "derive_more-impl",
1284 +]
1285 +
1286 +[[package]]
1287 +name = "derive_more-impl"
1288 +version = "2.1.1"
1289 +source = "registry+https://github.com/rust-lang/crates.io-index"
1290 +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
1291 +dependencies = [
1292 + "proc-macro2",
1293 + "quote",
1294 + "rustc_version",
1295 + "syn 2.0.117",
1296 +]
1297 +
1298 +[[package]]
1299 +name = "derivre"
1300 +version = "0.3.8"
1301 +source = "registry+https://github.com/rust-lang/crates.io-index"
1302 +checksum = "786c7c65c4ef0c7deb05de3005e01991612a8f09fe0844fc0969c68b90468ba8"
1303 +dependencies = [
1304 + "anyhow",
1305 + "bytemuck",
1306 + "bytemuck_derive",
1307 + "hashbrown 0.15.5",
1308 + "regex-syntax",
1309 + "strum",
1310 +]
1311 +
1312 +[[package]]
1313 +name = "deunicode"
1314 +version = "1.6.2"
1315 +source = "registry+https://github.com/rust-lang/crates.io-index"
1316 +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04"
1317 +
1318 +[[package]]
1319 +name = "digest"
1320 +version = "0.10.7"
1321 +source = "registry+https://github.com/rust-lang/crates.io-index"
1322 +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
1323 +dependencies = [
1324 + "block-buffer",
1325 + "crypto-common",
1326 +]
1327 +
1328 +[[package]]
1329 +name = "dirs"
1330 +version = "6.0.0"
1331 +source = "registry+https://github.com/rust-lang/crates.io-index"
1332 +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
1333 +dependencies = [
1334 + "dirs-sys",
1335 +]
1336 +
1337 +[[package]]
1338 +name = "dirs-sys"
1339 +version = "0.5.0"
1340 +source = "registry+https://github.com/rust-lang/crates.io-index"
1341 +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
1342 +dependencies = [
1343 + "libc",
1344 + "option-ext",
1345 + "redox_users",
1346 + "windows-sys 0.61.2",
1347 +]
1348 +
1349 +[[package]]
1350 +name = "dispatch2"
1351 +version = "0.3.1"
1352 +source = "registry+https://github.com/rust-lang/crates.io-index"
1353 +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
1354 +dependencies = [
1355 + "bitflags 2.11.0",
1356 + "block2",
1357 + "objc2",
1358 +]
1359 +
1360 +[[package]]
1361 +name = "displaydoc"
1362 +version = "0.2.5"
1363 +source = "registry+https://github.com/rust-lang/crates.io-index"
1364 +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
1365 +dependencies = [
1366 + "proc-macro2",
1367 + "quote",
1368 + "syn 2.0.117",
1369 +]
1370 +
1371 +[[package]]
1372 +name = "doctest-file"
1373 +version = "1.1.1"
1374 +source = "registry+https://github.com/rust-lang/crates.io-index"
1375 +checksum = "c2db04e74f0a9a93103b50e90b96024c9b2bdca8bce6a632ec71b88736d3d359"
1376 +
1377 +[[package]]
1378 +name = "dtoa"
1379 +version = "1.0.11"
1380 +source = "registry+https://github.com/rust-lang/crates.io-index"
1381 +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590"
1382 +
1383 +[[package]]
1384 +name = "dtoa-short"
1385 +version = "0.3.5"
1386 +source = "registry+https://github.com/rust-lang/crates.io-index"
1387 +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
1388 +dependencies = [
1389 + "dtoa",
1390 +]
1391 +
1392 +[[package]]
1393 +name = "dunce"
1394 +version = "1.0.5"
1395 +source = "registry+https://github.com/rust-lang/crates.io-index"
1396 +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
1397 +
1398 +[[package]]
1399 +name = "dyn-clone"
1400 +version = "1.0.20"
1401 +source = "registry+https://github.com/rust-lang/crates.io-index"
1402 +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
1403 +
1404 +[[package]]
1405 +name = "dyn-stack"
1406 +version = "0.13.2"
1407 +source = "registry+https://github.com/rust-lang/crates.io-index"
1408 +checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8"
1409 +dependencies = [
1410 + "bytemuck",
1411 + "dyn-stack-macros",
1412 +]
1413 +
1414 +[[package]]
1415 +name = "dyn-stack-macros"
1416 +version = "0.1.3"
1417 +source = "registry+https://github.com/rust-lang/crates.io-index"
1418 +checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9"
1419 +
1420 +[[package]]
1421 +name = "ego-tree"
1422 +version = "0.10.0"
1423 +source = "registry+https://github.com/rust-lang/crates.io-index"
1424 +checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8"
1425 +
1426 +[[package]]
1427 +name = "either"
1428 +version = "1.15.0"
1429 +source = "registry+https://github.com/rust-lang/crates.io-index"
1430 +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
1431 +dependencies = [
1432 + "serde",
1433 +]
1434 +
1435 +[[package]]
1436 +name = "encode_unicode"
1437 +version = "1.0.0"
1438 +source = "registry+https://github.com/rust-lang/crates.io-index"
1439 +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
1440 +
1441 +[[package]]
1442 +name = "encoding_rs"
1443 +version = "0.8.35"
1444 +source = "registry+https://github.com/rust-lang/crates.io-index"
1445 +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
1446 +dependencies = [
1447 + "cfg-if",
1448 +]
1449 +
1450 +[[package]]
1451 +name = "encoding_rs_io"
1452 +version = "0.1.7"
1453 +source = "registry+https://github.com/rust-lang/crates.io-index"
1454 +checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83"
1455 +dependencies = [
1456 + "encoding_rs",
1457 +]
1458 +
1459 +[[package]]
1460 +name = "endian-type"
1461 +version = "0.2.0"
1462 +source = "registry+https://github.com/rust-lang/crates.io-index"
1463 +checksum = "869b0adbda23651a9c5c0c3d270aac9fcb52e8622a8f2b17e57802d7791962f2"
1464 +
1465 +[[package]]
1466 +name = "enum-as-inner"
1467 +version = "0.6.1"
1468 +source = "registry+https://github.com/rust-lang/crates.io-index"
1469 +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
1470 +dependencies = [
1471 + "heck 0.5.0",
1472 + "proc-macro2",
1473 + "quote",
1474 + "syn 2.0.117",
1475 +]
1476 +
1477 +[[package]]
1478 +name = "env_logger"
1479 +version = "0.10.2"
1480 +source = "registry+https://github.com/rust-lang/crates.io-index"
1481 +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
1482 +dependencies = [
1483 + "humantime",
1484 + "is-terminal",
1485 + "log",
1486 + "regex",
1487 + "termcolor",
1488 +]
1489 +
1490 +[[package]]
1491 +name = "equator"
1492 +version = "0.4.2"
1493 +source = "registry+https://github.com/rust-lang/crates.io-index"
1494 +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
1495 +dependencies = [
1496 + "equator-macro",
1497 +]
1498 +
1499 +[[package]]
1500 +name = "equator-macro"
1501 +version = "0.4.2"
1502 +source = "registry+https://github.com/rust-lang/crates.io-index"
1503 +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
1504 +dependencies = [
1505 + "proc-macro2",
1506 + "quote",
1507 + "syn 2.0.117",
1508 +]
1509 +
1510 +[[package]]
1511 +name = "equivalent"
1512 +version = "1.0.2"
1513 +source = "registry+https://github.com/rust-lang/crates.io-index"
1514 +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
1515 +
1516 +[[package]]
1517 +name = "errno"
1518 +version = "0.3.14"
1519 +source = "registry+https://github.com/rust-lang/crates.io-index"
1520 +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
1521 +dependencies = [
1522 + "libc",
1523 + "windows-sys 0.61.2",
1524 +]
1525 +
1526 +[[package]]
1527 +name = "esaxx-rs"
1528 +version = "0.1.10"
1529 +source = "registry+https://github.com/rust-lang/crates.io-index"
1530 +checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6"
1531 +
1532 +[[package]]
1533 +name = "exr"
1534 +version = "1.74.0"
1535 +source = "registry+https://github.com/rust-lang/crates.io-index"
1536 +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
1537 +dependencies = [
1538 + "bit_field",
1539 + "half",
1540 + "lebe",
1541 + "miniz_oxide",
1542 + "rayon-core",
1543 + "smallvec 1.15.1",
1544 + "zune-inflate",
1545 +]
1546 +
1547 +[[package]]
1548 +name = "extended"
1549 +version = "0.1.0"
1550 +source = "registry+https://github.com/rust-lang/crates.io-index"
1551 +checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365"
1552 +
1553 +[[package]]
1554 +name = "fancy-regex"
1555 +version = "0.13.0"
1556 +source = "registry+https://github.com/rust-lang/crates.io-index"
1557 +checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2"
1558 +dependencies = [
1559 + "bit-set 0.5.3",
1560 + "regex-automata",
1561 + "regex-syntax",
1562 +]
1563 +
1564 +[[package]]
1565 +name = "fancy-regex"
1566 +version = "0.14.0"
1567 +source = "registry+https://github.com/rust-lang/crates.io-index"
1568 +checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"
1569 +dependencies = [
1570 + "bit-set 0.8.0",
1571 + "regex-automata",
1572 + "regex-syntax",
1573 +]
1574 +
1575 +[[package]]
1576 +name = "fastrand"
1577 +version = "2.3.0"
1578 +source = "registry+https://github.com/rust-lang/crates.io-index"
1579 +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
1580 +
1581 +[[package]]
1582 +name = "fax"
1583 +version = "0.2.6"
1584 +source = "registry+https://github.com/rust-lang/crates.io-index"
1585 +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab"
1586 +dependencies = [
1587 + "fax_derive",
1588 +]
1589 +
1590 +[[package]]
1591 +name = "fax_derive"
1592 +version = "0.2.0"
1593 +source = "registry+https://github.com/rust-lang/crates.io-index"
1594 +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
1595 +dependencies = [
1596 + "proc-macro2",
1597 + "quote",
1598 + "syn 2.0.117",
1599 +]
1600 +
1601 +[[package]]
1602 +name = "fdeflate"
1603 +version = "0.3.7"
1604 +source = "registry+https://github.com/rust-lang/crates.io-index"
1605 +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
1606 +dependencies = [
1607 + "simd-adler32",
1608 +]
1609 +
1610 +[[package]]
1611 +name = "find-msvc-tools"
1612 +version = "0.1.9"
1613 +source = "registry+https://github.com/rust-lang/crates.io-index"
1614 +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
1615 +
1616 +[[package]]
1617 +name = "flate2"
1618 +version = "1.1.9"
1619 +source = "registry+https://github.com/rust-lang/crates.io-index"
1620 +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
1621 +dependencies = [
1622 + "crc32fast",
1623 + "miniz_oxide",
1624 +]
1625 +
1626 +[[package]]
1627 +name = "float8"
1628 +version = "0.7.0"
1629 +source = "registry+https://github.com/rust-lang/crates.io-index"
1630 +checksum = "c2d1f04709a8ac06e8e8042875a3c466cc4832d3c1a18dbcb9dba3c6e83046bc"
1631 +dependencies = [
1632 + "half",
1633 + "num-traits",
1634 + "rand 0.9.2",
1635 + "rand_distr 0.5.1",
1636 +]
1637 +
1638 +[[package]]
1639 +name = "fnv"
1640 +version = "1.0.7"
1641 +source = "registry+https://github.com/rust-lang/crates.io-index"
1642 +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
1643 +
1644 +[[package]]
1645 +name = "foldhash"
1646 +version = "0.1.5"
1647 +source = "registry+https://github.com/rust-lang/crates.io-index"
1648 +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
1649 +
1650 +[[package]]
1651 +name = "foldhash"
1652 +version = "0.2.0"
1653 +source = "registry+https://github.com/rust-lang/crates.io-index"
1654 +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
1655 +
1656 +[[package]]
1657 +name = "foreign-types"
1658 +version = "0.3.2"
1659 +source = "registry+https://github.com/rust-lang/crates.io-index"
1660 +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
1661 +dependencies = [
1662 + "foreign-types-shared 0.1.1",
1663 +]
1664 +
1665 +[[package]]
1666 +name = "foreign-types"
1667 +version = "0.5.0"
1668 +source = "registry+https://github.com/rust-lang/crates.io-index"
1669 +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
1670 +dependencies = [
1671 + "foreign-types-macros",
1672 + "foreign-types-shared 0.3.1",
1673 +]
1674 +
1675 +[[package]]
1676 +name = "foreign-types-macros"
1677 +version = "0.2.3"
1678 +source = "registry+https://github.com/rust-lang/crates.io-index"
1679 +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
1680 +dependencies = [
1681 + "proc-macro2",
1682 + "quote",
1683 + "syn 2.0.117",
1684 +]
1685 +
1686 +[[package]]
1687 +name = "foreign-types-shared"
1688 +version = "0.1.1"
1689 +source = "registry+https://github.com/rust-lang/crates.io-index"
1690 +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
1691 +
1692 +[[package]]
1693 +name = "foreign-types-shared"
1694 +version = "0.3.1"
1695 +source = "registry+https://github.com/rust-lang/crates.io-index"
1696 +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
1697 +
1698 +[[package]]
1699 +name = "form_urlencoded"
1700 +version = "1.2.2"
1701 +source = "registry+https://github.com/rust-lang/crates.io-index"
1702 +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
1703 +dependencies = [
1704 + "percent-encoding",
1705 +]
1706 +
1707 +[[package]]
1708 +name = "fs-err"
1709 +version = "2.11.0"
1710 +source = "registry+https://github.com/rust-lang/crates.io-index"
1711 +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
1712 +dependencies = [
1713 + "autocfg",
1714 +]
1715 +
1716 +[[package]]
1717 +name = "fs_extra"
1718 +version = "1.3.0"
1719 +source = "registry+https://github.com/rust-lang/crates.io-index"
1720 +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
1721 +
1722 +[[package]]
1723 +name = "futf"
1724 +version = "0.1.5"
1725 +source = "registry+https://github.com/rust-lang/crates.io-index"
1726 +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
1727 +dependencies = [
1728 + "mac",
1729 + "new_debug_unreachable",
1730 +]
1731 +
1732 +[[package]]
1733 +name = "futures"
1734 +version = "0.3.32"
1735 +source = "registry+https://github.com/rust-lang/crates.io-index"
1736 +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
1737 +dependencies = [
1738 + "futures-channel",
1739 + "futures-core",
1740 + "futures-executor",
1741 + "futures-io",
1742 + "futures-sink",
1743 + "futures-task",
1744 + "futures-util",
1745 +]
1746 +
1747 +[[package]]
1748 +name = "futures-channel"
1749 +version = "0.3.32"
1750 +source = "registry+https://github.com/rust-lang/crates.io-index"
1751 +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
1752 +dependencies = [
1753 + "futures-core",
1754 + "futures-sink",
1755 +]
1756 +
1757 +[[package]]
1758 +name = "futures-core"
1759 +version = "0.3.32"
1760 +source = "registry+https://github.com/rust-lang/crates.io-index"
1761 +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
1762 +
1763 +[[package]]
1764 +name = "futures-executor"
1765 +version = "0.3.32"
1766 +source = "registry+https://github.com/rust-lang/crates.io-index"
1767 +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
1768 +dependencies = [
1769 + "futures-core",
1770 + "futures-task",
1771 + "futures-util",
1772 +]
1773 +
1774 +[[package]]
1775 +name = "futures-io"
1776 +version = "0.3.32"
1777 +source = "registry+https://github.com/rust-lang/crates.io-index"
1778 +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
1779 +
1780 +[[package]]
1781 +name = "futures-macro"
1782 +version = "0.3.32"
1783 +source = "registry+https://github.com/rust-lang/crates.io-index"
1784 +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
1785 +dependencies = [
1786 + "proc-macro2",
1787 + "quote",
1788 + "syn 2.0.117",
1789 +]
1790 +
1791 +[[package]]
1792 +name = "futures-sink"
1793 +version = "0.3.32"
1794 +source = "registry+https://github.com/rust-lang/crates.io-index"
1795 +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
1796 +
1797 +[[package]]
1798 +name = "futures-task"
1799 +version = "0.3.32"
1800 +source = "registry+https://github.com/rust-lang/crates.io-index"
1801 +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
1802 +
1803 +[[package]]
1804 +name = "futures-util"
1805 +version = "0.3.32"
1806 +source = "registry+https://github.com/rust-lang/crates.io-index"
1807 +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
1808 +dependencies = [
1809 + "futures-channel",
1810 + "futures-core",
1811 + "futures-io",
1812 + "futures-macro",
1813 + "futures-sink",
1814 + "futures-task",
1815 + "memchr",
1816 + "pin-project-lite",
1817 + "slab",
1818 +]
1819 +
1820 +[[package]]
1821 +name = "fxhash"
1822 +version = "0.2.1"
1823 +source = "registry+https://github.com/rust-lang/crates.io-index"
1824 +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
1825 +dependencies = [
1826 + "byteorder",
1827 +]
1828 +
1829 +[[package]]
1830 +name = "galil-seiferas"
1831 +version = "0.1.5"
1832 +source = "registry+https://github.com/rust-lang/crates.io-index"
1833 +checksum = "794ac25cfda3fa11d2b07ff8c65889c6c03411646df54e59e606878d899e1d5a"
1834 +dependencies = [
1835 + "defmac",
1836 + "unchecked-index",
1837 +]
1838 +
1839 +[[package]]
1840 +name = "gemm"
1841 +version = "0.18.2"
1842 +source = "registry+https://github.com/rust-lang/crates.io-index"
1843 +checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451"
1844 +dependencies = [
1845 + "dyn-stack",
1846 + "gemm-c32 0.18.2",
1847 + "gemm-c64 0.18.2",
1848 + "gemm-common 0.18.2",
1849 + "gemm-f16 0.18.2",
1850 + "gemm-f32 0.18.2",
1851 + "gemm-f64 0.18.2",
1852 + "num-complex",
1853 + "num-traits",
1854 + "paste",
1855 + "raw-cpuid",
1856 + "seq-macro",
1857 +]
1858 +
1859 +[[package]]
1860 +name = "gemm"
1861 +version = "0.19.0"
1862 +source = "registry+https://github.com/rust-lang/crates.io-index"
1863 +checksum = "aa0673db364b12263d103b68337a68fbecc541d6f6b61ba72fe438654709eacb"
1864 +dependencies = [
1865 + "dyn-stack",
1866 + "gemm-c32 0.19.0",
1867 + "gemm-c64 0.19.0",
1868 + "gemm-common 0.19.0",
1869 + "gemm-f16 0.19.0",
1870 + "gemm-f32 0.19.0",
1871 + "gemm-f64 0.19.0",
1872 + "num-complex",
1873 + "num-traits",
1874 + "paste",
1875 + "raw-cpuid",
1876 + "seq-macro",
1877 +]
1878 +
1879 +[[package]]
1880 +name = "gemm-c32"
1881 +version = "0.18.2"
1882 +source = "registry+https://github.com/rust-lang/crates.io-index"
1883 +checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847"
1884 +dependencies = [
1885 + "dyn-stack",
1886 + "gemm-common 0.18.2",
1887 + "num-complex",
1888 + "num-traits",
1889 + "paste",
1890 + "raw-cpuid",
1891 + "seq-macro",
1892 +]
1893 +
1894 +[[package]]
1895 +name = "gemm-c32"
1896 +version = "0.19.0"
1897 +source = "registry+https://github.com/rust-lang/crates.io-index"
1898 +checksum = "086936dbdcb99e37aad81d320f98f670e53c1e55a98bee70573e83f95beb128c"
1899 +dependencies = [
1900 + "dyn-stack",
1901 + "gemm-common 0.19.0",
1902 + "num-complex",
1903 + "num-traits",
1904 + "paste",
1905 + "raw-cpuid",
1906 + "seq-macro",
1907 +]
1908 +
1909 +[[package]]
1910 +name = "gemm-c64"
1911 +version = "0.18.2"
1912 +source = "registry+https://github.com/rust-lang/crates.io-index"
1913 +checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf"
1914 +dependencies = [
1915 + "dyn-stack",
1916 + "gemm-common 0.18.2",
1917 + "num-complex",
1918 + "num-traits",
1919 + "paste",
1920 + "raw-cpuid",
1921 + "seq-macro",
1922 +]
1923 +
1924 +[[package]]
1925 +name = "gemm-c64"
1926 +version = "0.19.0"
1927 +source = "registry+https://github.com/rust-lang/crates.io-index"
1928 +checksum = "20c8aeeeec425959bda4d9827664029ba1501a90a0d1e6228e48bef741db3a3f"
1929 +dependencies = [
1930 + "dyn-stack",
1931 + "gemm-common 0.19.0",
1932 + "num-complex",
1933 + "num-traits",
1934 + "paste",
1935 + "raw-cpuid",
1936 + "seq-macro",
1937 +]
1938 +
1939 +[[package]]
1940 +name = "gemm-common"
1941 +version = "0.18.2"
1942 +source = "registry+https://github.com/rust-lang/crates.io-index"
1943 +checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3"
1944 +dependencies = [
1945 + "bytemuck",
1946 + "dyn-stack",
1947 + "half",
1948 + "libm",
1949 + "num-complex",
1950 + "num-traits",
1951 + "once_cell",
1952 + "paste",
1953 + "pulp 0.21.5",
1954 + "raw-cpuid",
1955 + "rayon",
1956 + "seq-macro",
1957 + "sysctl",
1958 +]
1959 +
1960 +[[package]]
1961 +name = "gemm-common"
1962 +version = "0.19.0"
1963 +source = "registry+https://github.com/rust-lang/crates.io-index"
1964 +checksum = "88027625910cc9b1085aaaa1c4bc46bb3a36aad323452b33c25b5e4e7c8e2a3e"
1965 +dependencies = [
1966 + "bytemuck",
1967 + "dyn-stack",
1968 + "half",
1969 + "libm",
1970 + "num-complex",
1971 + "num-traits",
1972 + "once_cell",
1973 + "paste",
1974 + "pulp 0.22.2",
1975 + "raw-cpuid",
1976 + "rayon",
1977 + "seq-macro",
1978 + "sysctl",
1979 +]
1980 +
1981 +[[package]]
1982 +name = "gemm-f16"
1983 +version = "0.18.2"
1984 +source = "registry+https://github.com/rust-lang/crates.io-index"
1985 +checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109"
1986 +dependencies = [
1987 + "dyn-stack",
1988 + "gemm-common 0.18.2",
1989 + "gemm-f32 0.18.2",
1990 + "half",
1991 + "num-complex",
1992 + "num-traits",
1993 + "paste",
1994 + "raw-cpuid",
1995 + "rayon",
1996 + "seq-macro",
1997 +]
1998 +
1999 +[[package]]
2000 +name = "gemm-f16"
2001 +version = "0.19.0"
2002 +source = "registry+https://github.com/rust-lang/crates.io-index"
2003 +checksum = "e3df7a55202e6cd6739d82ae3399c8e0c7e1402859b30e4cb780e61525d9486e"
2004 +dependencies = [
2005 + "dyn-stack",
2006 + "gemm-common 0.19.0",
2007 + "gemm-f32 0.19.0",
2008 + "half",
2009 + "num-complex",
2010 + "num-traits",
2011 + "paste",
2012 + "raw-cpuid",
2013 + "rayon",
2014 + "seq-macro",
2015 +]
2016 +
2017 +[[package]]
2018 +name = "gemm-f32"
2019 +version = "0.18.2"
2020 +source = "registry+https://github.com/rust-lang/crates.io-index"
2021 +checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864"
2022 +dependencies = [
2023 + "dyn-stack",
2024 + "gemm-common 0.18.2",
2025 + "num-complex",
2026 + "num-traits",
2027 + "paste",
2028 + "raw-cpuid",
2029 + "seq-macro",
2030 +]
2031 +
2032 +[[package]]
2033 +name = "gemm-f32"
2034 +version = "0.19.0"
2035 +source = "registry+https://github.com/rust-lang/crates.io-index"
2036 +checksum = "02e0b8c9da1fbec6e3e3ab2ce6bc259ef18eb5f6f0d3e4edf54b75f9fd41a81c"
2037 +dependencies = [
2038 + "dyn-stack",
2039 + "gemm-common 0.19.0",
2040 + "num-complex",
2041 + "num-traits",
2042 + "paste",
2043 + "raw-cpuid",
2044 + "seq-macro",
2045 +]
2046 +
2047 +[[package]]
2048 +name = "gemm-f64"
2049 +version = "0.18.2"
2050 +source = "registry+https://github.com/rust-lang/crates.io-index"
2051 +checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd"
2052 +dependencies = [
2053 + "dyn-stack",
2054 + "gemm-common 0.18.2",
2055 + "num-complex",
2056 + "num-traits",
2057 + "paste",
2058 + "raw-cpuid",
2059 + "seq-macro",
2060 +]
2061 +
2062 +[[package]]
2063 +name = "gemm-f64"
2064 +version = "0.19.0"
2065 +source = "registry+https://github.com/rust-lang/crates.io-index"
2066 +checksum = "056131e8f2a521bfab322f804ccd652520c79700d81209e9d9275bbdecaadc6a"
2067 +dependencies = [
2068 + "dyn-stack",
2069 + "gemm-common 0.19.0",
2070 + "num-complex",
2071 + "num-traits",
2072 + "paste",
2073 + "raw-cpuid",
2074 + "seq-macro",
2075 +]
2076 +
2077 +[[package]]
2078 +name = "generator"
2079 +version = "0.7.5"
2080 +source = "registry+https://github.com/rust-lang/crates.io-index"
2081 +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e"
2082 +dependencies = [
2083 + "cc",
2084 + "libc",
2085 + "log",
2086 + "rustversion",
2087 + "windows 0.48.0",
2088 +]
2089 +
2090 +[[package]]
2091 +name = "generic-array"
2092 +version = "0.14.7"
2093 +source = "registry+https://github.com/rust-lang/crates.io-index"
2094 +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
2095 +dependencies = [
2096 + "typenum",
2097 + "version_check",
2098 +]
2099 +
2100 +[[package]]
2101 +name = "getopts"
2102 +version = "0.2.24"
2103 +source = "registry+https://github.com/rust-lang/crates.io-index"
2104 +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
2105 +dependencies = [
2106 + "unicode-width 0.2.2",
2107 +]
2108 +
2109 +[[package]]
2110 +name = "getrandom"
2111 +version = "0.2.17"
2112 +source = "registry+https://github.com/rust-lang/crates.io-index"
2113 +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
2114 +dependencies = [
2115 + "cfg-if",
2116 + "js-sys",
2117 + "libc",
2118 + "wasi",
2119 + "wasm-bindgen",
2120 +]
2121 +
2122 +[[package]]
2123 +name = "getrandom"
2124 +version = "0.3.4"
2125 +source = "registry+https://github.com/rust-lang/crates.io-index"
2126 +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
2127 +dependencies = [
2128 + "cfg-if",
2129 + "js-sys",
2130 + "libc",
2131 + "r-efi 5.3.0",
2132 + "wasip2",
2133 + "wasm-bindgen",
2134 +]
2135 +
2136 +[[package]]
2137 +name = "getrandom"
2138 +version = "0.4.2"
2139 +source = "registry+https://github.com/rust-lang/crates.io-index"
2140 +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
2141 +dependencies = [
2142 + "cfg-if",
2143 + "libc",
2144 + "r-efi 6.0.0",
2145 + "wasip2",
2146 + "wasip3",
2147 +]
2148 +
2149 +[[package]]
2150 +name = "gif"
2151 +version = "0.14.1"
2152 +source = "registry+https://github.com/rust-lang/crates.io-index"
2153 +checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e"
2154 +dependencies = [
2155 + "color_quant",
2156 + "weezl",
2157 +]
2158 +
2159 +[[package]]
2160 +name = "glob"
2161 +version = "0.3.3"
2162 +source = "registry+https://github.com/rust-lang/crates.io-index"
2163 +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
2164 +
2165 +[[package]]
2166 +name = "goblin"
2167 +version = "0.8.2"
2168 +source = "registry+https://github.com/rust-lang/crates.io-index"
2169 +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"
2170 +dependencies = [
2171 + "log",
2172 + "plain",
2173 + "scroll",
2174 +]
2175 +
2176 +[[package]]
2177 +name = "h2"
2178 +version = "0.4.13"
2179 +source = "registry+https://github.com/rust-lang/crates.io-index"
2180 +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
2181 +dependencies = [
2182 + "atomic-waker",
2183 + "bytes",
2184 + "fnv",
2185 + "futures-core",
2186 + "futures-sink",
2187 + "http",
2188 + "indexmap 2.13.0",
2189 + "slab",
2190 + "tokio",
2191 + "tokio-util",
2192 + "tracing",
2193 +]
2194 +
2195 +[[package]]
2196 +name = "half"
2197 +version = "2.7.1"
2198 +source = "registry+https://github.com/rust-lang/crates.io-index"
2199 +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
2200 +dependencies = [
2201 + "bytemuck",
2202 + "cfg-if",
2203 + "crunchy",
2204 + "num-traits",
2205 + "rand 0.9.2",
2206 + "rand_distr 0.5.1",
2207 + "zerocopy",
2208 +]
2209 +
2210 +[[package]]
2211 +name = "hashbrown"
2212 +version = "0.12.3"
2213 +source = "registry+https://github.com/rust-lang/crates.io-index"
2214 +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
2215 +
2216 +[[package]]
2217 +name = "hashbrown"
2218 +version = "0.15.5"
2219 +source = "registry+https://github.com/rust-lang/crates.io-index"
2220 +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
2221 +dependencies = [
2222 + "allocator-api2",
2223 + "equivalent",
2224 + "foldhash 0.1.5",
2225 +]
2226 +
2227 +[[package]]
2228 +name = "hashbrown"
2229 +version = "0.16.1"
2230 +source = "registry+https://github.com/rust-lang/crates.io-index"
2231 +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
2232 +dependencies = [
2233 + "allocator-api2",
2234 + "equivalent",
2235 + "foldhash 0.2.0",
2236 + "serde",
2237 + "serde_core",
2238 +]
2239 +
2240 +[[package]]
2241 +name = "heck"
2242 +version = "0.3.3"
2243 +source = "registry+https://github.com/rust-lang/crates.io-index"
2244 +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
2245 +dependencies = [
2246 + "unicode-segmentation",
2247 +]
2248 +
2249 +[[package]]
2250 +name = "heck"
2251 +version = "0.5.0"
2252 +source = "registry+https://github.com/rust-lang/crates.io-index"
2253 +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
2254 +
2255 +[[package]]
2256 +name = "hermit-abi"
2257 +version = "0.1.19"
2258 +source = "registry+https://github.com/rust-lang/crates.io-index"
2259 +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
2260 +dependencies = [
2261 + "libc",
2262 +]
2263 +
2264 +[[package]]
2265 +name = "hermit-abi"
2266 +version = "0.5.2"
2267 +source = "registry+https://github.com/rust-lang/crates.io-index"
2268 +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
2269 +
2270 +[[package]]
2271 +name = "hex"
2272 +version = "0.4.3"
2273 +source = "registry+https://github.com/rust-lang/crates.io-index"
2274 +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
2275 +
2276 +[[package]]
2277 +name = "hf-hub"
2278 +version = "0.4.3"
2279 +source = "registry+https://github.com/rust-lang/crates.io-index"
2280 +checksum = "629d8f3bbeda9d148036d6b0de0a3ab947abd08ce90626327fc3547a49d59d97"
2281 +dependencies = [
2282 + "dirs",
2283 + "futures",
2284 + "http",
2285 + "indicatif 0.17.11",
2286 + "libc",
2287 + "log",
2288 + "native-tls",
2289 + "num_cpus",
2290 + "rand 0.9.2",
2291 + "reqwest 0.12.28",
2292 + "serde",
2293 + "serde_json",
2294 + "thiserror 2.0.18",
2295 + "tokio",
2296 + "ureq",
2297 + "windows-sys 0.60.2",
2298 +]
2299 +
2300 +[[package]]
2301 +name = "home"
2302 +version = "0.5.12"
2303 +source = "registry+https://github.com/rust-lang/crates.io-index"
2304 +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
2305 +dependencies = [
2306 + "windows-sys 0.61.2",
2307 +]
2308 +
2309 +[[package]]
2310 +name = "hound"
2311 +version = "3.5.1"
2312 +source = "registry+https://github.com/rust-lang/crates.io-index"
2313 +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f"
2314 +
2315 +[[package]]
2316 +name = "html2text"
2317 +version = "0.16.7"
2318 +source = "registry+https://github.com/rust-lang/crates.io-index"
2319 +checksum = "12d23156ea4dbe6b37ad48fab2da56ff27b0f6192fb5db210c44eb07bfe6e787"
2320 +dependencies = [
2321 + "html5ever 0.38.0",
2322 + "tendril 0.5.0",
2323 + "thiserror 2.0.18",
2324 + "unicode-width 0.2.2",
2325 +]
2326 +
2327 +[[package]]
2328 +name = "html5ever"
2329 +version = "0.36.1"
2330 +source = "registry+https://github.com/rust-lang/crates.io-index"
2331 +checksum = "6452c4751a24e1b99c3260d505eaeee76a050573e61f30ac2c924ddc7236f01e"
2332 +dependencies = [
2333 + "log",
2334 + "markup5ever 0.36.1",
2335 +]
2336 +
2337 +[[package]]
2338 +name = "html5ever"
2339 +version = "0.38.0"
2340 +source = "registry+https://github.com/rust-lang/crates.io-index"
2341 +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2"
2342 +dependencies = [
2343 + "log",
2344 + "markup5ever 0.38.0",
2345 +]
2346 +
2347 +[[package]]
2348 +name = "http"
2349 +version = "1.4.0"
2350 +source = "registry+https://github.com/rust-lang/crates.io-index"
2351 +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
2352 +dependencies = [
2353 + "bytes",
2354 + "itoa",
2355 +]
2356 +
2357 +[[package]]
2358 +name = "http-body"
2359 +version = "1.0.1"
2360 +source = "registry+https://github.com/rust-lang/crates.io-index"
2361 +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
2362 +dependencies = [
2363 + "bytes",
2364 + "http",
2365 +]
2366 +
2367 +[[package]]
2368 +name = "http-body-util"
2369 +version = "0.1.3"
2370 +source = "registry+https://github.com/rust-lang/crates.io-index"
2371 +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
2372 +dependencies = [
2373 + "bytes",
2374 + "futures-core",
2375 + "http",
2376 + "http-body",
2377 + "pin-project-lite",
2378 +]
2379 +
2380 +[[package]]
2381 +name = "httparse"
2382 +version = "1.10.1"
2383 +source = "registry+https://github.com/rust-lang/crates.io-index"
2384 +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
2385 +
2386 +[[package]]
2387 +name = "humantime"
2388 +version = "2.3.0"
2389 +source = "registry+https://github.com/rust-lang/crates.io-index"
2390 +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
2391 +
2392 +[[package]]
2393 +name = "hyper"
2394 +version = "1.8.1"
2395 +source = "registry+https://github.com/rust-lang/crates.io-index"
2396 +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
2397 +dependencies = [
2398 + "atomic-waker",
2399 + "bytes",
2400 + "futures-channel",
2401 + "futures-core",
2402 + "h2",
2403 + "http",
2404 + "http-body",
2405 + "httparse",
2406 + "itoa",
2407 + "pin-project-lite",
2408 + "pin-utils",
2409 + "smallvec 1.15.1",
2410 + "tokio",
2411 + "want",
2412 +]
2413 +
2414 +[[package]]
2415 +name = "hyper-rustls"
2416 +version = "0.27.7"
2417 +source = "registry+https://github.com/rust-lang/crates.io-index"
2418 +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
2419 +dependencies = [
2420 + "http",
2421 + "hyper",
2422 + "hyper-util",
2423 + "rustls",
2424 + "rustls-pki-types",
2425 + "tokio",
2426 + "tokio-rustls",
2427 + "tower-service",
2428 + "webpki-roots 1.0.6",
2429 +]
2430 +
2431 +[[package]]
2432 +name = "hyper-tls"
2433 +version = "0.6.0"
2434 +source = "registry+https://github.com/rust-lang/crates.io-index"
2435 +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
2436 +dependencies = [
2437 + "bytes",
2438 + "http-body-util",
2439 + "hyper",
2440 + "hyper-util",
2441 + "native-tls",
2442 + "tokio",
2443 + "tokio-native-tls",
2444 + "tower-service",
2445 +]
2446 +
2447 +[[package]]
2448 +name = "hyper-util"
2449 +version = "0.1.20"
2450 +source = "registry+https://github.com/rust-lang/crates.io-index"
2451 +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
2452 +dependencies = [
2453 + "base64 0.22.1",
2454 + "bytes",
2455 + "futures-channel",
2456 + "futures-util",
2457 + "http",
2458 + "http-body",
2459 + "hyper",
2460 + "ipnet",
2461 + "libc",
2462 + "percent-encoding",
2463 + "pin-project-lite",
2464 + "socket2",
2465 + "system-configuration",
2466 + "tokio",
2467 + "tower-service",
2468 + "tracing",
2469 + "windows-registry",
2470 +]
2471 +
2472 +[[package]]
2473 +name = "iana-time-zone"
2474 +version = "0.1.65"
2475 +source = "registry+https://github.com/rust-lang/crates.io-index"
2476 +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
2477 +dependencies = [
2478 + "android_system_properties",
2479 + "core-foundation-sys",
2480 + "iana-time-zone-haiku",
2481 + "js-sys",
2482 + "log",
2483 + "wasm-bindgen",
2484 + "windows-core 0.62.2",
2485 +]
2486 +
2487 +[[package]]
2488 +name = "iana-time-zone-haiku"
2489 +version = "0.1.2"
2490 +source = "registry+https://github.com/rust-lang/crates.io-index"
2491 +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
2492 +dependencies = [
2493 + "cc",
2494 +]
2495 +
2496 +[[package]]
2497 +name = "icu_collections"
2498 +version = "2.1.1"
2499 +source = "registry+https://github.com/rust-lang/crates.io-index"
2500 +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
2501 +dependencies = [
2502 + "displaydoc",
2503 + "potential_utf",
2504 + "yoke 0.8.1",
2505 + "zerofrom",
2506 + "zerovec",
2507 +]
2508 +
2509 +[[package]]
2510 +name = "icu_locale_core"
2511 +version = "2.1.1"
2512 +source = "registry+https://github.com/rust-lang/crates.io-index"
2513 +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
2514 +dependencies = [
2515 + "displaydoc",
2516 + "litemap",
2517 + "tinystr",
2518 + "writeable",
2519 + "zerovec",
2520 +]
2521 +
2522 +[[package]]
2523 +name = "icu_normalizer"
2524 +version = "2.1.1"
2525 +source = "registry+https://github.com/rust-lang/crates.io-index"
2526 +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
2527 +dependencies = [
2528 + "icu_collections",
2529 + "icu_normalizer_data",
2530 + "icu_properties",
2531 + "icu_provider",
2532 + "smallvec 1.15.1",
2533 + "zerovec",
2534 +]
2535 +
2536 +[[package]]
2537 +name = "icu_normalizer_data"
2538 +version = "2.1.1"
2539 +source = "registry+https://github.com/rust-lang/crates.io-index"
2540 +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
2541 +
2542 +[[package]]
2543 +name = "icu_properties"
2544 +version = "2.1.2"
2545 +source = "registry+https://github.com/rust-lang/crates.io-index"
2546 +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
2547 +dependencies = [
2548 + "icu_collections",
2549 + "icu_locale_core",
2550 + "icu_properties_data",
2551 + "icu_provider",
2552 + "zerotrie",
2553 + "zerovec",
2554 +]
2555 +
2556 +[[package]]
2557 +name = "icu_properties_data"
2558 +version = "2.1.2"
2559 +source = "registry+https://github.com/rust-lang/crates.io-index"
2560 +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
2561 +
2562 +[[package]]
2563 +name = "icu_provider"
2564 +version = "2.1.1"
2565 +source = "registry+https://github.com/rust-lang/crates.io-index"
2566 +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
2567 +dependencies = [
2568 + "displaydoc",
2569 + "icu_locale_core",
2570 + "writeable",
2571 + "yoke 0.8.1",
2572 + "zerofrom",
2573 + "zerotrie",
2574 + "zerovec",
2575 +]
2576 +
2577 +[[package]]
2578 +name = "id-arena"
2579 +version = "2.3.0"
2580 +source = "registry+https://github.com/rust-lang/crates.io-index"
2581 +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
2582 +
2583 +[[package]]
2584 +name = "ident_case"
2585 +version = "1.0.1"
2586 +source = "registry+https://github.com/rust-lang/crates.io-index"
2587 +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
2588 +
2589 +[[package]]
2590 +name = "idna"
2591 +version = "1.1.0"
2592 +source = "registry+https://github.com/rust-lang/crates.io-index"
2593 +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
2594 +dependencies = [
2595 + "idna_adapter",
2596 + "smallvec 1.15.1",
2597 + "utf8_iter",
2598 +]
2599 +
2600 +[[package]]
2601 +name = "idna_adapter"
2602 +version = "1.2.1"
2603 +source = "registry+https://github.com/rust-lang/crates.io-index"
2604 +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
2605 +dependencies = [
2606 + "icu_normalizer",
2607 + "icu_properties",
2608 +]
2609 +
2610 +[[package]]
2611 +name = "image"
2612 +version = "0.25.10"
2613 +source = "registry+https://github.com/rust-lang/crates.io-index"
2614 +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
2615 +dependencies = [
2616 + "bytemuck",
2617 + "byteorder-lite",
2618 + "color_quant",
2619 + "exr",
2620 + "gif",
2621 + "image-webp",
2622 + "moxcms",
2623 + "num-traits",
2624 + "png",
2625 + "qoi",
2626 + "ravif",
2627 + "rayon",
2628 + "rgb",
2629 + "tiff",
2630 + "zune-core",
2631 + "zune-jpeg",
2632 +]
2633 +
2634 +[[package]]
2635 +name = "image-webp"
2636 +version = "0.2.4"
2637 +source = "registry+https://github.com/rust-lang/crates.io-index"
2638 +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
2639 +dependencies = [
2640 + "byteorder-lite",
2641 + "quick-error",
2642 +]
2643 +
2644 +[[package]]
2645 +name = "imgref"
2646 +version = "1.12.0"
2647 +source = "registry+https://github.com/rust-lang/crates.io-index"
2648 +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8"
2649 +
2650 +[[package]]
2651 +name = "indexmap"
2652 +version = "1.9.3"
2653 +source = "registry+https://github.com/rust-lang/crates.io-index"
2654 +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
2655 +dependencies = [
2656 + "autocfg",
2657 + "hashbrown 0.12.3",
2658 + "serde",
2659 +]
2660 +
2661 +[[package]]
2662 +name = "indexmap"
2663 +version = "2.13.0"
2664 +source = "registry+https://github.com/rust-lang/crates.io-index"
2665 +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
2666 +dependencies = [
2667 + "equivalent",
2668 + "hashbrown 0.16.1",
2669 + "serde",
2670 + "serde_core",
2671 +]
2672 +
2673 +[[package]]
2674 +name = "indicatif"
2675 +version = "0.17.11"
2676 +source = "registry+https://github.com/rust-lang/crates.io-index"
2677 +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
2678 +dependencies = [
2679 + "console 0.15.11",
2680 + "number_prefix",
2681 + "portable-atomic",
2682 + "unicode-width 0.2.2",
2683 + "web-time",
2684 +]
2685 +
2686 +[[package]]
2687 +name = "indicatif"
2688 +version = "0.18.4"
2689 +source = "registry+https://github.com/rust-lang/crates.io-index"
2690 +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb"
2691 +dependencies = [
2692 + "console 0.16.3",
2693 + "portable-atomic",
2694 + "rayon",
2695 + "unicode-width 0.2.2",
2696 + "unit-prefix",
2697 + "web-time",
2698 +]
2699 +
2700 +[[package]]
2701 +name = "interpolate_name"
2702 +version = "0.2.4"
2703 +source = "registry+https://github.com/rust-lang/crates.io-index"
2704 +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
2705 +dependencies = [
2706 + "proc-macro2",
2707 + "quote",
2708 + "syn 2.0.117",
2709 +]
2710 +
2711 +[[package]]
2712 +name = "interprocess"
2713 +version = "2.4.0"
2714 +source = "registry+https://github.com/rust-lang/crates.io-index"
2715 +checksum = "6be5e5c847dbdb44564bd85294740d031f4f8aeb3464e5375ef7141f7538db69"
2716 +dependencies = [
2717 + "doctest-file",
2718 + "libc",
2719 + "recvmsg",
2720 + "widestring",
2721 + "windows-sys 0.52.0",
2722 +]
2723 +
2724 +[[package]]
2725 +name = "ipnet"
2726 +version = "2.12.0"
2727 +source = "registry+https://github.com/rust-lang/crates.io-index"
2728 +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
2729 +
2730 +[[package]]
2731 +name = "iri-string"
2732 +version = "0.7.10"
2733 +source = "registry+https://github.com/rust-lang/crates.io-index"
2734 +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
2735 +dependencies = [
2736 + "memchr",
2737 + "serde",
2738 +]
2739 +
2740 +[[package]]
2741 +name = "is-terminal"
2742 +version = "0.4.17"
2743 +source = "registry+https://github.com/rust-lang/crates.io-index"
2744 +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
2745 +dependencies = [
2746 + "hermit-abi 0.5.2",
2747 + "libc",
2748 + "windows-sys 0.61.2",
2749 +]
2750 +
2751 +[[package]]
2752 +name = "is_terminal_polyfill"
2753 +version = "1.70.2"
2754 +source = "registry+https://github.com/rust-lang/crates.io-index"
2755 +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
2756 +
2757 +[[package]]
2758 +name = "itertools"
2759 +version = "0.12.1"
2760 +source = "registry+https://github.com/rust-lang/crates.io-index"
2761 +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
2762 +dependencies = [
2763 + "either",
2764 +]
2765 +
2766 +[[package]]
2767 +name = "itertools"
2768 +version = "0.14.0"
2769 +source = "registry+https://github.com/rust-lang/crates.io-index"
2770 +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
2771 +dependencies = [
2772 + "either",
2773 +]
2774 +
2775 +[[package]]
2776 +name = "itoa"
2777 +version = "1.0.18"
2778 +source = "registry+https://github.com/rust-lang/crates.io-index"
2779 +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
2780 +
2781 +[[package]]
2782 +name = "jni"
2783 +version = "0.21.1"
2784 +source = "registry+https://github.com/rust-lang/crates.io-index"
2785 +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
2786 +dependencies = [
2787 + "cesu8",
2788 + "cfg-if",
2789 + "combine",
2790 + "jni-sys",
2791 + "log",
2792 + "thiserror 1.0.69",
2793 + "walkdir",
2794 + "windows-sys 0.45.0",
2795 +]
2796 +
2797 +[[package]]
2798 +name = "jni-sys"
2799 +version = "0.3.0"
2800 +source = "registry+https://github.com/rust-lang/crates.io-index"
2801 +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
2802 +
2803 +[[package]]
2804 +name = "jobserver"
2805 +version = "0.1.34"
2806 +source = "registry+https://github.com/rust-lang/crates.io-index"
2807 +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
2808 +dependencies = [
2809 + "getrandom 0.3.4",
2810 + "libc",
2811 +]
2812 +
2813 +[[package]]
2814 +name = "js-sys"
2815 +version = "0.3.91"
2816 +source = "registry+https://github.com/rust-lang/crates.io-index"
2817 +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
2818 +dependencies = [
2819 + "once_cell",
2820 + "wasm-bindgen",
2821 +]
2822 +
2823 +[[package]]
2824 +name = "lazy_static"
2825 +version = "1.5.0"
2826 +source = "registry+https://github.com/rust-lang/crates.io-index"
2827 +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
2828 +
2829 +[[package]]
2830 +name = "lazycell"
2831 +version = "1.3.0"
2832 +source = "registry+https://github.com/rust-lang/crates.io-index"
2833 +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
2834 +
2835 +[[package]]
2836 +name = "leb128fmt"
2837 +version = "0.1.0"
2838 +source = "registry+https://github.com/rust-lang/crates.io-index"
2839 +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
2840 +
2841 +[[package]]
2842 +name = "lebe"
2843 +version = "0.5.3"
2844 +source = "registry+https://github.com/rust-lang/crates.io-index"
2845 +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
2846 +
2847 +[[package]]
2848 +name = "libc"
2849 +version = "0.2.183"
2850 +source = "registry+https://github.com/rust-lang/crates.io-index"
2851 +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
2852 +
2853 +[[package]]
2854 +name = "libfuzzer-sys"
2855 +version = "0.4.12"
2856 +source = "registry+https://github.com/rust-lang/crates.io-index"
2857 +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
2858 +dependencies = [
2859 + "arbitrary",
2860 + "cc",
2861 +]
2862 +
2863 +[[package]]
2864 +name = "libloading"
2865 +version = "0.8.9"
2866 +source = "registry+https://github.com/rust-lang/crates.io-index"
2867 +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
2868 +dependencies = [
2869 + "cfg-if",
2870 + "windows-link 0.2.1",
2871 +]
2872 +
2873 +[[package]]
2874 +name = "libm"
2875 +version = "0.2.16"
2876 +source = "registry+https://github.com/rust-lang/crates.io-index"
2877 +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
2878 +
2879 +[[package]]
2880 +name = "libredox"
2881 +version = "0.1.14"
2882 +source = "registry+https://github.com/rust-lang/crates.io-index"
2883 +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
2884 +dependencies = [
2885 + "libc",
2886 +]
2887 +
2888 +[[package]]
2889 +name = "linux-raw-sys"
2890 +version = "0.4.15"
2891 +source = "registry+https://github.com/rust-lang/crates.io-index"
2892 +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
2893 +
2894 +[[package]]
2895 +name = "linux-raw-sys"
2896 +version = "0.12.1"
2897 +source = "registry+https://github.com/rust-lang/crates.io-index"
2898 +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
2899 +
2900 +[[package]]
2901 +name = "litemap"
2902 +version = "0.8.1"
2903 +source = "registry+https://github.com/rust-lang/crates.io-index"
2904 +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
2905 +
2906 +[[package]]
2907 +name = "llguidance"
2908 +version = "1.7.0"
2909 +source = "registry+https://github.com/rust-lang/crates.io-index"
2910 +checksum = "586ccb282d83fe337ddad2e28bb11bb258a462caa80e117fc76a6c73dac919e4"
2911 +dependencies = [
2912 + "anyhow",
2913 + "derivre",
2914 + "indexmap 2.13.0",
2915 + "regex-syntax",
2916 + "serde",
2917 + "serde_json",
2918 + "toktrie",
2919 +]
2920 +
2921 +[[package]]
2922 +name = "lock_api"
2923 +version = "0.4.14"
2924 +source = "registry+https://github.com/rust-lang/crates.io-index"
2925 +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
2926 +dependencies = [
2927 + "scopeguard",
2928 +]
2929 +
2930 +[[package]]
2931 +name = "log"
2932 +version = "0.4.29"
2933 +source = "registry+https://github.com/rust-lang/crates.io-index"
2934 +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
2935 +
2936 +[[package]]
2937 +name = "loom"
2938 +version = "0.5.6"
2939 +source = "registry+https://github.com/rust-lang/crates.io-index"
2940 +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
2941 +dependencies = [
2942 + "cfg-if",
2943 + "generator",
2944 + "scoped-tls",
2945 + "serde",
2946 + "serde_json",
2947 + "tracing",
2948 + "tracing-subscriber",
2949 +]
2950 +
2951 +[[package]]
2952 +name = "loop9"
2953 +version = "0.1.5"
2954 +source = "registry+https://github.com/rust-lang/crates.io-index"
2955 +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
2956 +dependencies = [
2957 + "imgref",
2958 +]
2959 +
2960 +[[package]]
2961 +name = "lrtable"
2962 +version = "0.14.1"
2963 +source = "registry+https://github.com/rust-lang/crates.io-index"
2964 +checksum = "b15ad6a43e5cff4ac046d51281d2256a36d1440065eab53ccce9362b48db5b42"
2965 +dependencies = [
2966 + "cfgrammar",
2967 + "fnv",
2968 + "num-traits",
2969 + "sparsevec",
2970 + "vob",
2971 +]
2972 +
2973 +[[package]]
2974 +name = "lru-slab"
2975 +version = "0.1.2"
2976 +source = "registry+https://github.com/rust-lang/crates.io-index"
2977 +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
2978 +
2979 +[[package]]
2980 +name = "mac"
2981 +version = "0.1.1"
2982 +source = "registry+https://github.com/rust-lang/crates.io-index"
2983 +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
2984 +
2985 +[[package]]
2986 +name = "macro_rules_attribute"
2987 +version = "0.2.2"
2988 +source = "registry+https://github.com/rust-lang/crates.io-index"
2989 +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520"
2990 +dependencies = [
2991 + "macro_rules_attribute-proc_macro",
2992 + "paste",
2993 +]
2994 +
2995 +[[package]]
2996 +name = "macro_rules_attribute-proc_macro"
2997 +version = "0.2.2"
2998 +source = "registry+https://github.com/rust-lang/crates.io-index"
2999 +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
3000 +
3001 +[[package]]
3002 +name = "malloc_buf"
3003 +version = "0.0.6"
3004 +source = "registry+https://github.com/rust-lang/crates.io-index"
3005 +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
3006 +dependencies = [
3007 + "libc",
3008 +]
3009 +
3010 +[[package]]
3011 +name = "markup5ever"
3012 +version = "0.36.1"
3013 +source = "registry+https://github.com/rust-lang/crates.io-index"
3014 +checksum = "6c3294c4d74d0742910f8c7b466f44dda9eb2d5742c1e430138df290a1e8451c"
3015 +dependencies = [
3016 + "log",
3017 + "tendril 0.4.3",
3018 + "web_atoms",
3019 +]
3020 +
3021 +[[package]]
3022 +name = "markup5ever"
3023 +version = "0.38.0"
3024 +source = "registry+https://github.com/rust-lang/crates.io-index"
3025 +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862"
3026 +dependencies = [
3027 + "log",
3028 + "tendril 0.5.0",
3029 + "web_atoms",
3030 +]
3031 +
3032 +[[package]]
3033 +name = "matchers"
3034 +version = "0.2.0"
3035 +source = "registry+https://github.com/rust-lang/crates.io-index"
3036 +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
3037 +dependencies = [
3038 + "regex-automata",
3039 +]
3040 +
3041 +[[package]]
3042 +name = "matrixmultiply"
3043 +version = "0.3.10"
3044 +source = "registry+https://github.com/rust-lang/crates.io-index"
3045 +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08"
3046 +dependencies = [
3047 + "autocfg",
3048 + "rawpointer",
3049 +]
3050 +
3051 +[[package]]
3052 +name = "maybe-rayon"
3053 +version = "0.1.1"
3054 +source = "registry+https://github.com/rust-lang/crates.io-index"
3055 +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
3056 +dependencies = [
3057 + "cfg-if",
3058 + "rayon",
3059 +]
3060 +
3061 +[[package]]
3062 +name = "memchr"
3063 +version = "2.8.0"
3064 +source = "registry+https://github.com/rust-lang/crates.io-index"
3065 +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
3066 +
3067 +[[package]]
3068 +name = "memmap2"
3069 +version = "0.9.10"
3070 +source = "registry+https://github.com/rust-lang/crates.io-index"
3071 +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
3072 +dependencies = [
3073 + "libc",
3074 + "stable_deref_trait",
3075 +]
3076 +
3077 +[[package]]
3078 +name = "memo-map"
3079 +version = "0.3.3"
3080 +source = "registry+https://github.com/rust-lang/crates.io-index"
3081 +checksum = "38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b"
3082 +
3083 +[[package]]
3084 +name = "metal"
3085 +version = "0.29.0"
3086 +source = "registry+https://github.com/rust-lang/crates.io-index"
3087 +checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
3088 +dependencies = [
3089 + "bitflags 2.11.0",
3090 + "block",
3091 + "core-graphics-types",
3092 + "foreign-types 0.5.0",
3093 + "log",
3094 + "objc",
3095 + "paste",
3096 +]
3097 +
3098 +[[package]]
3099 +name = "mime"
3100 +version = "0.3.17"
3101 +source = "registry+https://github.com/rust-lang/crates.io-index"
3102 +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
3103 +
3104 +[[package]]
3105 +name = "mime_guess"
3106 +version = "2.0.5"
3107 +source = "registry+https://github.com/rust-lang/crates.io-index"
3108 +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
3109 +dependencies = [
3110 + "mime",
3111 + "unicase",
3112 +]
3113 +
3114 +[[package]]
3115 +name = "minijinja"
3116 +version = "2.18.0"
3117 +source = "registry+https://github.com/rust-lang/crates.io-index"
3118 +checksum = "328251e58ad8e415be6198888fc207502727dc77945806421ab34f35bf012e7d"
3119 +dependencies = [
3120 + "memo-map",
3121 + "serde",
3122 + "serde_json",
3123 +]
3124 +
3125 +[[package]]
3126 +name = "minijinja-contrib"
3127 +version = "2.18.0"
3128 +source = "registry+https://github.com/rust-lang/crates.io-index"
3129 +checksum = "8c6302e47d2b51f9fc978268ff7f5a014de5caa2ad48440309fd10ee711480d7"
3130 +dependencies = [
3131 + "minijinja",
3132 + "serde",
3133 +]
3134 +
3135 +[[package]]
3136 +name = "minimal-lexical"
3137 +version = "0.2.1"
3138 +source = "registry+https://github.com/rust-lang/crates.io-index"
3139 +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
3140 +
3141 +[[package]]
3142 +name = "miniz_oxide"
3143 +version = "0.8.9"
3144 +source = "registry+https://github.com/rust-lang/crates.io-index"
3145 +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
3146 +dependencies = [
3147 + "adler2",
3148 + "simd-adler32",
3149 +]
3150 +
3151 +[[package]]
3152 +name = "mio"
3153 +version = "0.8.11"
3154 +source = "registry+https://github.com/rust-lang/crates.io-index"
3155 +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
3156 +dependencies = [
3157 + "libc",
3158 + "log",
3159 + "wasi",
3160 + "windows-sys 0.48.0",
3161 +]
3162 +
3163 +[[package]]
3164 +name = "mio"
3165 +version = "1.1.1"
3166 +source = "registry+https://github.com/rust-lang/crates.io-index"
3167 +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
3168 +dependencies = [
3169 + "libc",
3170 + "wasi",
3171 + "windows-sys 0.61.2",
3172 +]
3173 +
3174 +[[package]]
3175 +name = "mistralrs"
3176 +version = "0.7.1-alpha.1"
3177 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#82e6efad7004ed105f241b6d6608feff0ec185f8"
3178 +dependencies = [
3179 + "anyhow",
3180 + "candle-core",
3181 + "candle-nn",
3182 + "clap 4.6.0",
3183 + "either",
3184 + "futures",
3185 + "image",
3186 + "indexmap 2.13.0",
3187 + "mistralrs-core",
3188 + "mistralrs-macros",
3189 + "rand 0.9.2",
3190 + "reqwest 0.13.2",
3191 + "schemars 1.2.1",
3192 + "serde",
3193 + "serde_json",
3194 + "thiserror 2.0.18",
3195 + "tokio",
3196 + "tracing",
3197 + "tracing-subscriber",
3198 + "walkdir",
3199 +]
3200 +
3201 +[[package]]
3202 +name = "mistralrs-audio"
3203 +version = "0.7.1-alpha.1"
3204 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#82e6efad7004ed105f241b6d6608feff0ec185f8"
3205 +dependencies = [
3206 + "anyhow",
3207 + "apodize",
3208 + "hound",
3209 + "symphonia",
3210 +]
3211 +
3212 +[[package]]
3213 +name = "mistralrs-core"
3214 +version = "0.7.1-alpha.1"
3215 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#82e6efad7004ed105f241b6d6608feff0ec185f8"
3216 +dependencies = [
3217 + "ahash",
3218 + "akin",
3219 + "anyhow",
3220 + "apodize",
3221 + "as-any",
3222 + "async-trait",
3223 + "base64 0.22.1",
3224 + "bm25",
3225 + "bytemuck",
3226 + "bytemuck_derive",
3227 + "candle-core",
3228 + "candle-metal-kernels",
3229 + "candle-nn",
3230 + "cfgrammar",
3231 + "chrono",
3232 + "clap 4.6.0",
3233 + "csv",
3234 + "derive-new",
3235 + "derive_more",
3236 + "dirs",
3237 + "either",
3238 + "float8",
3239 + "futures",
3240 + "galil-seiferas",
3241 + "half",
3242 + "hashbrown 0.16.1",
3243 + "hf-hub",
3244 + "hound",
3245 + "html2text",
3246 + "http",
3247 + "image",
3248 + "indexmap 2.13.0",
3249 + "indicatif 0.18.4",
3250 + "interprocess",
3251 + "itertools 0.14.0",
3252 + "libc",
3253 + "llguidance",
3254 + "lrtable",
3255 + "minijinja",
3256 + "minijinja-contrib",
3257 + "mistralrs-audio",
3258 + "mistralrs-mcp",
3259 + "mistralrs-paged-attn",
3260 + "mistralrs-quant",
3261 + "mistralrs-vision",
3262 + "num-traits",
3263 + "objc",
3264 + "objc2-metal",
3265 + "openai-harmony",
3266 + "ordered-float",
3267 + "parking_lot",
3268 + "radix_trie",
3269 + "rand 0.9.2",
3270 + "rand_distr 0.5.1",
3271 + "rand_isaac",
3272 + "rayon",
3273 + "regex",
3274 + "regex-automata",
3275 + "reqwest 0.13.2",
3276 + "rubato",
3277 + "rust-mcp-schema",
3278 + "rustc-hash 2.1.1",
3279 + "rustfft",
3280 + "safetensors 0.7.0",
3281 + "schemars 1.2.1",
3282 + "scraper",
3283 + "serde",
3284 + "serde-big-array",
3285 + "serde-saphyr",
3286 + "serde_json",
3287 + "serde_plain",
3288 + "statrs",
3289 + "strum",
3290 + "symphonia",
3291 + "sysinfo",
3292 + "thiserror 2.0.18",
3293 + "tokenizers",
3294 + "tokio",
3295 + "tokio-rayon",
3296 + "tokio-tungstenite",
3297 + "toktrie",
3298 + "toktrie_hf_tokenizers",
3299 + "toml",
3300 + "tqdm",
3301 + "tracing",
3302 + "tracing-subscriber",
3303 + "urlencoding",
3304 + "uuid 1.22.0",
3305 + "variantly",
3306 + "vob",
3307 +]
3308 +
3309 +[[package]]
3310 +name = "mistralrs-macros"
3311 +version = "0.7.1-alpha.1"
3312 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#82e6efad7004ed105f241b6d6608feff0ec185f8"
3313 +dependencies = [
3314 + "darling 0.23.0",
3315 + "proc-macro2",
3316 + "quote",
3317 + "syn 2.0.117",
3318 +]
3319 +
3320 +[[package]]
3321 +name = "mistralrs-mcp"
3322 +version = "0.7.1-alpha.1"
3323 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#82e6efad7004ed105f241b6d6608feff0ec185f8"
3324 +dependencies = [
3325 + "anyhow",
3326 + "async-trait",
3327 + "futures-util",
3328 + "http",
3329 + "reqwest 0.13.2",
3330 + "rust-mcp-schema",
3331 + "serde",
3332 + "serde_json",
3333 + "tokio",
3334 + "tokio-tungstenite",
3335 + "tracing",
3336 + "utoipa",
3337 + "uuid 1.22.0",
3338 +]
3339 +
3340 +[[package]]
3341 +name = "mistralrs-paged-attn"
3342 +version = "0.7.1-alpha.1"
3343 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#82e6efad7004ed105f241b6d6608feff0ec185f8"
3344 +dependencies = [
3345 + "anyhow",
3346 + "candle-core",
3347 + "candle-metal-kernels",
3348 + "dispatch2",
3349 + "float8",
3350 + "half",
3351 + "objc2-foundation",
3352 + "objc2-metal",
3353 + "thiserror 2.0.18",
3354 +]
3355 +
3356 +[[package]]
3357 +name = "mistralrs-quant"
3358 +version = "0.7.1-alpha.1"
3359 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#82e6efad7004ed105f241b6d6608feff0ec185f8"
3360 +dependencies = [
3361 + "byteorder",
3362 + "candle-core",
3363 + "candle-metal-kernels",
3364 + "candle-nn",
3365 + "dispatch2",
3366 + "float8",
3367 + "half",
3368 + "hf-hub",
3369 + "lazy_static",
3370 + "memmap2",
3371 + "objc2-foundation",
3372 + "objc2-metal",
3373 + "paste",
3374 + "rayon",
3375 + "regex",
3376 + "safetensors 0.7.0",
3377 + "serde",
3378 + "serde_json",
3379 + "thiserror 2.0.18",
3380 + "tokio",
3381 + "tracing",
3382 + "yoke 0.8.1",
3383 +]
3384 +
3385 +[[package]]
3386 +name = "mistralrs-vision"
3387 +version = "0.7.1-alpha.1"
3388 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#82e6efad7004ed105f241b6d6608feff0ec185f8"
3389 +dependencies = [
3390 + "candle-core",
3391 + "image",
3392 + "rayon",
3393 +]
3394 +
3395 +[[package]]
3396 +name = "monostate"
3397 +version = "0.1.18"
3398 +source = "registry+https://github.com/rust-lang/crates.io-index"
3399 +checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67"
3400 +dependencies = [
3401 + "monostate-impl",
3402 + "serde",
3403 + "serde_core",
3404 +]
3405 +
3406 +[[package]]
3407 +name = "monostate-impl"
3408 +version = "0.1.18"
3409 +source = "registry+https://github.com/rust-lang/crates.io-index"
3410 +checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9"
3411 +dependencies = [
3412 + "proc-macro2",
3413 + "quote",
3414 + "syn 2.0.117",
3415 +]
3416 +
3417 +[[package]]
3418 +name = "moxcms"
3419 +version = "0.8.1"
3420 +source = "registry+https://github.com/rust-lang/crates.io-index"
3421 +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
3422 +dependencies = [
3423 + "num-traits",
3424 + "pxfm",
3425 +]
3426 +
3427 +[[package]]
3428 +name = "nalgebra"
3429 +version = "0.33.2"
3430 +source = "registry+https://github.com/rust-lang/crates.io-index"
3431 +checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b"
3432 +dependencies = [
3433 + "approx",
3434 + "matrixmultiply",
3435 + "num-complex",
3436 + "num-rational",
3437 + "num-traits",
3438 + "rand 0.8.5",
3439 + "rand_distr 0.4.3",
3440 + "simba",
3441 + "typenum",
3442 +]
3443 +
3444 +[[package]]
3445 +name = "native-tls"
3446 +version = "0.2.18"
3447 +source = "registry+https://github.com/rust-lang/crates.io-index"
3448 +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2"
3449 +dependencies = [
3450 + "libc",
3451 + "log",
3452 + "openssl",
3453 + "openssl-probe",
3454 + "openssl-sys",
3455 + "schannel",
3456 + "security-framework",
3457 + "security-framework-sys",
3458 + "tempfile",
3459 +]
3460 +
3461 +[[package]]
3462 +name = "new_debug_unreachable"
3463 +version = "1.0.6"
3464 +source = "registry+https://github.com/rust-lang/crates.io-index"
3465 +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
3466 +
3467 +[[package]]
3468 +name = "nibble_vec"
3469 +version = "0.1.0"
3470 +source = "registry+https://github.com/rust-lang/crates.io-index"
3471 +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
3472 +dependencies = [
3473 + "smallvec 1.15.1",
3474 +]
3475 +
3476 +[[package]]
3477 +name = "nohash-hasher"
3478 +version = "0.2.0"
3479 +source = "registry+https://github.com/rust-lang/crates.io-index"
3480 +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
3481 +
3482 +[[package]]
3483 +name = "nom"
3484 +version = "7.1.3"
3485 +source = "registry+https://github.com/rust-lang/crates.io-index"
3486 +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
3487 +dependencies = [
3488 + "memchr",
3489 + "minimal-lexical",
3490 +]
3491 +
3492 +[[package]]
3493 +name = "nom"
3494 +version = "8.0.0"
3495 +source = "registry+https://github.com/rust-lang/crates.io-index"
3496 +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
3497 +dependencies = [
3498 + "memchr",
3499 +]
3500 +
3501 +[[package]]
3502 +name = "noop_proc_macro"
3503 +version = "0.3.0"
3504 +source = "registry+https://github.com/rust-lang/crates.io-index"
3505 +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
3506 +
3507 +[[package]]
3508 +name = "ntapi"
3509 +version = "0.4.3"
3510 +source = "registry+https://github.com/rust-lang/crates.io-index"
3511 +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae"
3512 +dependencies = [
3513 + "winapi",
3514 +]
3515 +
3516 +[[package]]
3517 +name = "nu-ansi-term"
3518 +version = "0.50.3"
3519 +source = "registry+https://github.com/rust-lang/crates.io-index"
3520 +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
3521 +dependencies = [
3522 + "windows-sys 0.61.2",
3523 +]
3524 +
3525 +[[package]]
3526 +name = "num"
3527 +version = "0.4.3"
3528 +source = "registry+https://github.com/rust-lang/crates.io-index"
3529 +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
3530 +dependencies = [
3531 + "num-bigint",
3532 + "num-complex",
3533 + "num-integer",
3534 + "num-iter",
3535 + "num-rational",
3536 + "num-traits",
3537 +]
3538 +
3539 +[[package]]
3540 +name = "num-bigint"
3541 +version = "0.4.6"
3542 +source = "registry+https://github.com/rust-lang/crates.io-index"
3543 +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
3544 +dependencies = [
3545 + "num-integer",
3546 + "num-traits",
3547 +]
3548 +
3549 +[[package]]
3550 +name = "num-complex"
3551 +version = "0.4.6"
3552 +source = "registry+https://github.com/rust-lang/crates.io-index"
3553 +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
3554 +dependencies = [
3555 + "bytemuck",
3556 + "num-traits",
3557 +]
3558 +
3559 +[[package]]
3560 +name = "num-conv"
3561 +version = "0.2.0"
3562 +source = "registry+https://github.com/rust-lang/crates.io-index"
3563 +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
3564 +
3565 +[[package]]
3566 +name = "num-derive"
3567 +version = "0.4.2"
3568 +source = "registry+https://github.com/rust-lang/crates.io-index"
3569 +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
3570 +dependencies = [
3571 + "proc-macro2",
3572 + "quote",
3573 + "syn 2.0.117",
3574 +]
3575 +
3576 +[[package]]
3577 +name = "num-integer"
3578 +version = "0.1.46"
3579 +source = "registry+https://github.com/rust-lang/crates.io-index"
3580 +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
3581 +dependencies = [
3582 + "num-traits",
3583 +]
3584 +
3585 +[[package]]
3586 +name = "num-iter"
3587 +version = "0.1.45"
3588 +source = "registry+https://github.com/rust-lang/crates.io-index"
3589 +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
3590 +dependencies = [
3591 + "autocfg",
3592 + "num-integer",
3593 + "num-traits",
3594 +]
3595 +
3596 +[[package]]
3597 +name = "num-rational"
3598 +version = "0.4.2"
3599 +source = "registry+https://github.com/rust-lang/crates.io-index"
3600 +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
3601 +dependencies = [
3602 + "num-bigint",
3603 + "num-integer",
3604 + "num-traits",
3605 +]
3606 +
3607 +[[package]]
3608 +name = "num-traits"
3609 +version = "0.2.19"
3610 +source = "registry+https://github.com/rust-lang/crates.io-index"
3611 +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
3612 +dependencies = [
3613 + "autocfg",
3614 + "libm",
3615 +]
3616 +
3617 +[[package]]
3618 +name = "num_cpus"
3619 +version = "1.17.0"
3620 +source = "registry+https://github.com/rust-lang/crates.io-index"
3621 +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
3622 +dependencies = [
3623 + "hermit-abi 0.5.2",
3624 + "libc",
3625 +]
3626 +
3627 +[[package]]
3628 +name = "number_prefix"
3629 +version = "0.4.0"
3630 +source = "registry+https://github.com/rust-lang/crates.io-index"
3631 +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
3632 +
3633 +[[package]]
3634 +name = "objc"
3635 +version = "0.2.7"
3636 +source = "registry+https://github.com/rust-lang/crates.io-index"
3637 +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
3638 +dependencies = [
3639 + "malloc_buf",
3640 +]
3641 +
3642 +[[package]]
3643 +name = "objc2"
3644 +version = "0.6.4"
3645 +source = "registry+https://github.com/rust-lang/crates.io-index"
3646 +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
3647 +dependencies = [
3648 + "objc2-encode",
3649 +]
3650 +
3651 +[[package]]
3652 +name = "objc2-core-foundation"
3653 +version = "0.3.2"
3654 +source = "registry+https://github.com/rust-lang/crates.io-index"
3655 +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
3656 +dependencies = [
3657 + "bitflags 2.11.0",
3658 + "dispatch2",
3659 + "objc2",
3660 +]
3661 +
3662 +[[package]]
3663 +name = "objc2-encode"
3664 +version = "4.1.0"
3665 +source = "registry+https://github.com/rust-lang/crates.io-index"
3666 +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
3667 +
3668 +[[package]]
3669 +name = "objc2-foundation"
3670 +version = "0.3.2"
3671 +source = "registry+https://github.com/rust-lang/crates.io-index"
3672 +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
3673 +dependencies = [
3674 + "bitflags 2.11.0",
3675 + "block2",
3676 + "libc",
3677 + "objc2",
3678 + "objc2-core-foundation",
3679 +]
3680 +
3681 +[[package]]
3682 +name = "objc2-io-kit"
3683 +version = "0.3.2"
3684 +source = "registry+https://github.com/rust-lang/crates.io-index"
3685 +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
3686 +dependencies = [
3687 + "libc",
3688 + "objc2-core-foundation",
3689 +]
3690 +
3691 +[[package]]
3692 +name = "objc2-metal"
3693 +version = "0.3.2"
3694 +source = "registry+https://github.com/rust-lang/crates.io-index"
3695 +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794"
3696 +dependencies = [
3697 + "bitflags 2.11.0",
3698 + "block2",
3699 + "dispatch2",
3700 + "objc2",
3701 + "objc2-core-foundation",
3702 + "objc2-foundation",
3703 +]
3704 +
3705 +[[package]]
3706 +name = "once_cell"
3707 +version = "1.21.4"
3708 +source = "registry+https://github.com/rust-lang/crates.io-index"
3709 +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
3710 +
3711 +[[package]]
3712 +name = "once_cell_polyfill"
3713 +version = "1.70.2"
3714 +source = "registry+https://github.com/rust-lang/crates.io-index"
3715 +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
3716 +
3717 +[[package]]
3718 +name = "onde"
3719 +version = "0.1.0"
3720 +dependencies = [
3721 + "anyhow",
3722 + "cc",
3723 + "hf-hub",
3724 + "home",
3725 + "log",
3726 + "mistralrs",
3727 + "mistralrs-core",
3728 + "serde",
3729 + "thiserror 2.0.18",
3730 + "tokio",
3731 + "transcribe-rs",
3732 + "tsync",
3733 + "uniffi",
3734 +]
3735 +
3736 +[[package]]
3737 +name = "openai-harmony"
3738 +version = "0.0.8"
3739 +source = "registry+https://github.com/rust-lang/crates.io-index"
3740 +checksum = "e77e82af451fc95deeb728a40b84db8ee82d341e136c268de415123a560b9b72"
3741 +dependencies = [
3742 + "anyhow",
3743 + "base64 0.22.1",
3744 + "bstr",
3745 + "clap 4.6.0",
3746 + "fancy-regex 0.13.0",
3747 + "futures",
3748 + "image",
3749 + "regex",
3750 + "reqwest 0.12.28",
3751 + "rustc-hash 1.1.0",
3752 + "serde",
3753 + "serde_json",
3754 + "serde_with",
3755 + "sha1",
3756 + "sha2",
3757 + "thiserror 2.0.18",
3758 +]
3759 +
3760 +[[package]]
3761 +name = "openssl"
3762 +version = "0.10.76"
3763 +source = "registry+https://github.com/rust-lang/crates.io-index"
3764 +checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf"
3765 +dependencies = [
3766 + "bitflags 2.11.0",
3767 + "cfg-if",
3768 + "foreign-types 0.3.2",
3769 + "libc",
3770 + "once_cell",
3771 + "openssl-macros",
3772 + "openssl-sys",
3773 +]
3774 +
3775 +[[package]]
3776 +name = "openssl-macros"
3777 +version = "0.1.1"
3778 +source = "registry+https://github.com/rust-lang/crates.io-index"
3779 +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
3780 +dependencies = [
3781 + "proc-macro2",
3782 + "quote",
3783 + "syn 2.0.117",
3784 +]
3785 +
3786 +[[package]]
3787 +name = "openssl-probe"
3788 +version = "0.2.1"
3789 +source = "registry+https://github.com/rust-lang/crates.io-index"
3790 +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
3791 +
3792 +[[package]]
3793 +name = "openssl-sys"
3794 +version = "0.9.112"
3795 +source = "registry+https://github.com/rust-lang/crates.io-index"
3796 +checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb"
3797 +dependencies = [
3798 + "cc",
3799 + "libc",
3800 + "pkg-config",
3801 + "vcpkg",
3802 +]
3803 +
3804 +[[package]]
3805 +name = "option-ext"
3806 +version = "0.2.0"
3807 +source = "registry+https://github.com/rust-lang/crates.io-index"
3808 +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
3809 +
3810 +[[package]]
3811 +name = "ordered-float"
3812 +version = "5.1.0"
3813 +source = "registry+https://github.com/rust-lang/crates.io-index"
3814 +checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
3815 +dependencies = [
3816 + "num-traits",
3817 +]
3818 +
3819 +[[package]]
3820 +name = "packedvec"
3821 +version = "1.2.5"
3822 +source = "registry+https://github.com/rust-lang/crates.io-index"
3823 +checksum = "a69e0a534dd2e6aefce319af62a0aa0066a76bdfcec0201dfe02df226bc9ec70"
3824 +dependencies = [
3825 + "num-traits",
3826 +]
3827 +
3828 +[[package]]
3829 +name = "parking_lot"
3830 +version = "0.12.5"
3831 +source = "registry+https://github.com/rust-lang/crates.io-index"
3832 +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
3833 +dependencies = [
3834 + "lock_api",
3835 + "parking_lot_core",
3836 +]
3837 +
3838 +[[package]]
3839 +name = "parking_lot_core"
3840 +version = "0.9.12"
3841 +source = "registry+https://github.com/rust-lang/crates.io-index"
3842 +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
3843 +dependencies = [
3844 + "cfg-if",
3845 + "libc",
3846 + "redox_syscall",
3847 + "smallvec 1.15.1",
3848 + "windows-link 0.2.1",
3849 +]
3850 +
3851 +[[package]]
3852 +name = "paste"
3853 +version = "1.0.15"
3854 +source = "registry+https://github.com/rust-lang/crates.io-index"
3855 +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
3856 +
3857 +[[package]]
3858 +name = "pastey"
3859 +version = "0.1.1"
3860 +source = "registry+https://github.com/rust-lang/crates.io-index"
3861 +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
3862 +
3863 +[[package]]
3864 +name = "percent-encoding"
3865 +version = "2.3.2"
3866 +source = "registry+https://github.com/rust-lang/crates.io-index"
3867 +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
3868 +
3869 +[[package]]
3870 +name = "phf"
3871 +version = "0.13.1"
3872 +source = "registry+https://github.com/rust-lang/crates.io-index"
3873 +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
3874 +dependencies = [
3875 + "phf_macros",
3876 + "phf_shared",
3877 + "serde",
3878 +]
3879 +
3880 +[[package]]
3881 +name = "phf_codegen"
3882 +version = "0.13.1"
3883 +source = "registry+https://github.com/rust-lang/crates.io-index"
3884 +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1"
3885 +dependencies = [
3886 + "phf_generator",
3887 + "phf_shared",
3888 +]
3889 +
3890 +[[package]]
3891 +name = "phf_generator"
3892 +version = "0.13.1"
3893 +source = "registry+https://github.com/rust-lang/crates.io-index"
3894 +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
3895 +dependencies = [
3896 + "fastrand",
3897 + "phf_shared",
3898 +]
3899 +
3900 +[[package]]
3901 +name = "phf_macros"
3902 +version = "0.13.1"
3903 +source = "registry+https://github.com/rust-lang/crates.io-index"
3904 +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
3905 +dependencies = [
3906 + "phf_generator",
3907 + "phf_shared",
3908 + "proc-macro2",
3909 + "quote",
3910 + "syn 2.0.117",
3911 +]
3912 +
3913 +[[package]]
3914 +name = "phf_shared"
3915 +version = "0.13.1"
3916 +source = "registry+https://github.com/rust-lang/crates.io-index"
3917 +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
3918 +dependencies = [
3919 + "siphasher",
3920 +]
3921 +
3922 +[[package]]
3923 +name = "pin-project-lite"
3924 +version = "0.2.17"
3925 +source = "registry+https://github.com/rust-lang/crates.io-index"
3926 +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
3927 +
3928 +[[package]]
3929 +name = "pin-utils"
3930 +version = "0.1.0"
3931 +source = "registry+https://github.com/rust-lang/crates.io-index"
3932 +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
3933 +
3934 +[[package]]
3935 +name = "pkg-config"
3936 +version = "0.3.32"
3937 +source = "registry+https://github.com/rust-lang/crates.io-index"
3938 +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
3939 +
3940 +[[package]]
3941 +name = "plain"
3942 +version = "0.2.3"
3943 +source = "registry+https://github.com/rust-lang/crates.io-index"
3944 +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
3945 +
3946 +[[package]]
3947 +name = "png"
3948 +version = "0.18.1"
3949 +source = "registry+https://github.com/rust-lang/crates.io-index"
3950 +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
3951 +dependencies = [
3952 + "bitflags 2.11.0",
3953 + "crc32fast",
3954 + "fdeflate",
3955 + "flate2",
3956 + "miniz_oxide",
3957 +]
3958 +
3959 +[[package]]
3960 +name = "portable-atomic"
3961 +version = "1.13.1"
3962 +source = "registry+https://github.com/rust-lang/crates.io-index"
3963 +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
3964 +
3965 +[[package]]
3966 +name = "potential_utf"
3967 +version = "0.1.4"
3968 +source = "registry+https://github.com/rust-lang/crates.io-index"
3969 +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
3970 +dependencies = [
3971 + "zerovec",
3972 +]
3973 +
3974 +[[package]]
3975 +name = "powerfmt"
3976 +version = "0.2.0"
3977 +source = "registry+https://github.com/rust-lang/crates.io-index"
3978 +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
3979 +
3980 +[[package]]
3981 +name = "ppv-lite86"
3982 +version = "0.2.21"
3983 +source = "registry+https://github.com/rust-lang/crates.io-index"
3984 +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
3985 +dependencies = [
3986 + "zerocopy",
3987 +]
3988 +
3989 +[[package]]
3990 +name = "precomputed-hash"
3991 +version = "0.1.1"
3992 +source = "registry+https://github.com/rust-lang/crates.io-index"
3993 +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
3994 +
3995 +[[package]]
3996 +name = "prettyplease"
3997 +version = "0.2.37"
3998 +source = "registry+https://github.com/rust-lang/crates.io-index"
3999 +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
4000 +dependencies = [
4001 + "proc-macro2",
4002 + "syn 2.0.117",
4003 +]
4004 +
4005 +[[package]]
4006 +name = "primal-check"
4007 +version = "0.3.4"
4008 +source = "registry+https://github.com/rust-lang/crates.io-index"
4009 +checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08"
4010 +dependencies = [
4011 + "num-integer",
4012 +]
4013 +
4014 +[[package]]
4015 +name = "proc-macro-error"
4016 +version = "1.0.4"
4017 +source = "registry+https://github.com/rust-lang/crates.io-index"
4018 +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
4019 +dependencies = [
4020 + "proc-macro-error-attr",
4021 + "proc-macro2",
4022 + "quote",
4023 + "syn 1.0.109",
4024 + "version_check",
4025 +]
4026 +
4027 +[[package]]
4028 +name = "proc-macro-error-attr"
4029 +version = "1.0.4"
4030 +source = "registry+https://github.com/rust-lang/crates.io-index"
4031 +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
4032 +dependencies = [
4033 + "proc-macro2",
4034 + "quote",
4035 + "version_check",
4036 +]
4037 +
4038 +[[package]]
4039 +name = "proc-macro2"
4040 +version = "1.0.106"
4041 +source = "registry+https://github.com/rust-lang/crates.io-index"
4042 +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
4043 +dependencies = [
4044 + "unicode-ident",
4045 +]
4046 +
4047 +[[package]]
4048 +name = "profiling"
4049 +version = "1.0.17"
4050 +source = "registry+https://github.com/rust-lang/crates.io-index"
4051 +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
4052 +dependencies = [
4053 + "profiling-procmacros",
4054 +]
4055 +
4056 +[[package]]
4057 +name = "profiling-procmacros"
4058 +version = "1.0.17"
4059 +source = "registry+https://github.com/rust-lang/crates.io-index"
4060 +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
4061 +dependencies = [
4062 + "quote",
4063 + "syn 2.0.117",
4064 +]
4065 +
4066 +[[package]]
4067 +name = "pulp"
4068 +version = "0.21.5"
4069 +source = "registry+https://github.com/rust-lang/crates.io-index"
4070 +checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907"
4071 +dependencies = [
4072 + "bytemuck",
4073 + "cfg-if",
4074 + "libm",
4075 + "num-complex",
4076 + "reborrow",
4077 + "version_check",
4078 +]
4079 +
4080 +[[package]]
4081 +name = "pulp"
4082 +version = "0.22.2"
4083 +source = "registry+https://github.com/rust-lang/crates.io-index"
4084 +checksum = "2e205bb30d5b916c55e584c22201771bcf2bad9aabd5d4127f38387140c38632"
4085 +dependencies = [
4086 + "bytemuck",
4087 + "cfg-if",
4088 + "libm",
4089 + "num-complex",
4090 + "paste",
4091 + "pulp-wasm-simd-flag",
4092 + "raw-cpuid",
4093 + "reborrow",
4094 + "version_check",
4095 +]
4096 +
4097 +[[package]]
4098 +name = "pulp-wasm-simd-flag"
4099 +version = "0.1.0"
4100 +source = "registry+https://github.com/rust-lang/crates.io-index"
4101 +checksum = "40e24eee682d89fb193496edf918a7f407d30175b2e785fe057e4392dfd182e0"
4102 +
4103 +[[package]]
4104 +name = "pxfm"
4105 +version = "0.1.28"
4106 +source = "registry+https://github.com/rust-lang/crates.io-index"
4107 +checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d"
4108 +
4109 +[[package]]
4110 +name = "qoi"
4111 +version = "0.4.1"
4112 +source = "registry+https://github.com/rust-lang/crates.io-index"
4113 +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
4114 +dependencies = [
4115 + "bytemuck",
4116 +]
4117 +
4118 +[[package]]
4119 +name = "quick-error"
4120 +version = "2.0.1"
4121 +source = "registry+https://github.com/rust-lang/crates.io-index"
4122 +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
4123 +
4124 +[[package]]
4125 +name = "quinn"
4126 +version = "0.11.9"
4127 +source = "registry+https://github.com/rust-lang/crates.io-index"
4128 +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
4129 +dependencies = [
4130 + "bytes",
4131 + "cfg_aliases",
4132 + "pin-project-lite",
4133 + "quinn-proto",
4134 + "quinn-udp",
4135 + "rustc-hash 2.1.1",
4136 + "rustls",
4137 + "socket2",
4138 + "thiserror 2.0.18",
4139 + "tokio",
4140 + "tracing",
4141 + "web-time",
4142 +]
4143 +
4144 +[[package]]
4145 +name = "quinn-proto"
4146 +version = "0.11.14"
4147 +source = "registry+https://github.com/rust-lang/crates.io-index"
4148 +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
4149 +dependencies = [
4150 + "aws-lc-rs",
4151 + "bytes",
4152 + "getrandom 0.3.4",
4153 + "lru-slab",
4154 + "rand 0.9.2",
4155 + "ring",
4156 + "rustc-hash 2.1.1",
4157 + "rustls",
4158 + "rustls-pki-types",
4159 + "slab",
4160 + "thiserror 2.0.18",
4161 + "tinyvec",
4162 + "tracing",
4163 + "web-time",
4164 +]
4165 +
4166 +[[package]]
4167 +name = "quinn-udp"
4168 +version = "0.5.14"
4169 +source = "registry+https://github.com/rust-lang/crates.io-index"
4170 +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
4171 +dependencies = [
4172 + "cfg_aliases",
4173 + "libc",
4174 + "once_cell",
4175 + "socket2",
4176 + "tracing",
4177 + "windows-sys 0.60.2",
4178 +]
4179 +
4180 +[[package]]
4181 +name = "quote"
4182 +version = "1.0.45"
4183 +source = "registry+https://github.com/rust-lang/crates.io-index"
4184 +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
4185 +dependencies = [
4186 + "proc-macro2",
4187 +]
4188 +
4189 +[[package]]
4190 +name = "r-efi"
4191 +version = "5.3.0"
4192 +source = "registry+https://github.com/rust-lang/crates.io-index"
4193 +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
4194 +
4195 +[[package]]
4196 +name = "r-efi"
4197 +version = "6.0.0"
4198 +source = "registry+https://github.com/rust-lang/crates.io-index"
4199 +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
4200 +
4201 +[[package]]
4202 +name = "radix_trie"
4203 +version = "0.3.0"
4204 +source = "registry+https://github.com/rust-lang/crates.io-index"
4205 +checksum = "3b4431027dcd37fc2a73ef740b5f233aa805897935b8bce0195e41bbf9a3289a"
4206 +dependencies = [
4207 + "endian-type",
4208 + "nibble_vec",
4209 +]
4210 +
4211 +[[package]]
4212 +name = "rand"
4213 +version = "0.8.5"
4214 +source = "registry+https://github.com/rust-lang/crates.io-index"
4215 +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
4216 +dependencies = [
4217 + "libc",
4218 + "rand_chacha 0.3.1",
4219 + "rand_core 0.6.4",
4220 +]
4221 +
4222 +[[package]]
4223 +name = "rand"
4224 +version = "0.9.2"
4225 +source = "registry+https://github.com/rust-lang/crates.io-index"
4226 +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
4227 +dependencies = [
4228 + "rand_chacha 0.9.0",
4229 + "rand_core 0.9.5",
4230 +]
4231 +
4232 +[[package]]
4233 +name = "rand_chacha"
4234 +version = "0.3.1"
4235 +source = "registry+https://github.com/rust-lang/crates.io-index"
4236 +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
4237 +dependencies = [
4238 + "ppv-lite86",
4239 + "rand_core 0.6.4",
4240 +]
4241 +
4242 +[[package]]
4243 +name = "rand_chacha"
4244 +version = "0.9.0"
4245 +source = "registry+https://github.com/rust-lang/crates.io-index"
4246 +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
4247 +dependencies = [
4248 + "ppv-lite86",
4249 + "rand_core 0.9.5",
4250 +]
4251 +
4252 +[[package]]
4253 +name = "rand_core"
4254 +version = "0.6.4"
4255 +source = "registry+https://github.com/rust-lang/crates.io-index"
4256 +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
4257 +dependencies = [
4258 + "getrandom 0.2.17",
4259 +]
4260 +
4261 +[[package]]
4262 +name = "rand_core"
4263 +version = "0.9.5"
4264 +source = "registry+https://github.com/rust-lang/crates.io-index"
4265 +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
4266 +dependencies = [
4267 + "getrandom 0.3.4",
4268 +]
4269 +
4270 +[[package]]
4271 +name = "rand_distr"
4272 +version = "0.4.3"
4273 +source = "registry+https://github.com/rust-lang/crates.io-index"
4274 +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
4275 +dependencies = [
4276 + "num-traits",
4277 + "rand 0.8.5",
4278 +]
4279 +
4280 +[[package]]
4281 +name = "rand_distr"
4282 +version = "0.5.1"
4283 +source = "registry+https://github.com/rust-lang/crates.io-index"
4284 +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463"
4285 +dependencies = [
4286 + "num-traits",
4287 + "rand 0.9.2",
4288 +]
4289 +
4290 +[[package]]
4291 +name = "rand_isaac"
4292 +version = "0.4.0"
4293 +source = "registry+https://github.com/rust-lang/crates.io-index"
4294 +checksum = "3382fc9f0aad4f2e2a56b53d9133c8c810b4dbf21e7e370e24346161a5b2c7bd"
4295 +dependencies = [
4296 + "rand_core 0.9.5",
4297 +]
4298 +
4299 +[[package]]
4300 +name = "rav1e"
4301 +version = "0.8.1"
4302 +source = "registry+https://github.com/rust-lang/crates.io-index"
4303 +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b"
4304 +dependencies = [
4305 + "aligned-vec",
4306 + "arbitrary",
4307 + "arg_enum_proc_macro",
4308 + "arrayvec",
4309 + "av-scenechange",
4310 + "av1-grain",
4311 + "bitstream-io",
4312 + "built",
4313 + "cfg-if",
4314 + "interpolate_name",
4315 + "itertools 0.14.0",
4316 + "libc",
4317 + "libfuzzer-sys",
4318 + "log",
4319 + "maybe-rayon",
4320 + "new_debug_unreachable",
4321 + "noop_proc_macro",
4322 + "num-derive",
4323 + "num-traits",
4324 + "paste",
4325 + "profiling",
4326 + "rand 0.9.2",
4327 + "rand_chacha 0.9.0",
4328 + "simd_helpers",
4329 + "thiserror 2.0.18",
4330 + "v_frame",
4331 + "wasm-bindgen",
4332 +]
4333 +
4334 +[[package]]
4335 +name = "ravif"
4336 +version = "0.13.0"
4337 +source = "registry+https://github.com/rust-lang/crates.io-index"
4338 +checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45"
4339 +dependencies = [
4340 + "avif-serialize",
4341 + "imgref",
4342 + "loop9",
4343 + "quick-error",
4344 + "rav1e",
4345 + "rayon",
4346 + "rgb",
4347 +]
4348 +
4349 +[[package]]
4350 +name = "raw-cpuid"
4351 +version = "11.6.0"
4352 +source = "registry+https://github.com/rust-lang/crates.io-index"
4353 +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
4354 +dependencies = [
4355 + "bitflags 2.11.0",
4356 +]
4357 +
4358 +[[package]]
4359 +name = "rawpointer"
4360 +version = "0.2.1"
4361 +source = "registry+https://github.com/rust-lang/crates.io-index"
4362 +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
4363 +
4364 +[[package]]
4365 +name = "rayon"
4366 +version = "1.11.0"
4367 +source = "registry+https://github.com/rust-lang/crates.io-index"
4368 +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
4369 +dependencies = [
4370 + "either",
4371 + "rayon-core",
4372 +]
4373 +
4374 +[[package]]
4375 +name = "rayon-cond"
4376 +version = "0.4.0"
4377 +source = "registry+https://github.com/rust-lang/crates.io-index"
4378 +checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f"
4379 +dependencies = [
4380 + "either",
4381 + "itertools 0.14.0",
4382 + "rayon",
4383 +]
4384 +
4385 +[[package]]
4386 +name = "rayon-core"
4387 +version = "1.13.0"
4388 +source = "registry+https://github.com/rust-lang/crates.io-index"
4389 +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
4390 +dependencies = [
4391 + "crossbeam-deque",
4392 + "crossbeam-utils",
4393 +]
4394 +
4395 +[[package]]
4396 +name = "realfft"
4397 +version = "3.5.0"
4398 +source = "registry+https://github.com/rust-lang/crates.io-index"
4399 +checksum = "f821338fddb99d089116342c46e9f1fbf3828dba077674613e734e01d6ea8677"
4400 +dependencies = [
4401 + "rustfft",
4402 +]
4403 +
4404 +[[package]]
4405 +name = "reborrow"
4406 +version = "0.5.5"
4407 +source = "registry+https://github.com/rust-lang/crates.io-index"
4408 +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430"
4409 +
4410 +[[package]]
4411 +name = "recvmsg"
4412 +version = "1.0.0"
4413 +source = "registry+https://github.com/rust-lang/crates.io-index"
4414 +checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175"
4415 +
4416 +[[package]]
4417 +name = "redox_syscall"
4418 +version = "0.5.18"
4419 +source = "registry+https://github.com/rust-lang/crates.io-index"
4420 +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
4421 +dependencies = [
4422 + "bitflags 2.11.0",
4423 +]
4424 +
4425 +[[package]]
4426 +name = "redox_users"
4427 +version = "0.5.2"
4428 +source = "registry+https://github.com/rust-lang/crates.io-index"
4429 +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
4430 +dependencies = [
4431 + "getrandom 0.2.17",
4432 + "libredox",
4433 + "thiserror 2.0.18",
4434 +]
4435 +
4436 +[[package]]
4437 +name = "ref-cast"
4438 +version = "1.0.25"
4439 +source = "registry+https://github.com/rust-lang/crates.io-index"
4440 +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
4441 +dependencies = [
4442 + "ref-cast-impl",
4443 +]
4444 +
4445 +[[package]]
4446 +name = "ref-cast-impl"
4447 +version = "1.0.25"
4448 +source = "registry+https://github.com/rust-lang/crates.io-index"
4449 +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
4450 +dependencies = [
4451 + "proc-macro2",
4452 + "quote",
4453 + "syn 2.0.117",
4454 +]
4455 +
4456 +[[package]]
4457 +name = "regex"
4458 +version = "1.12.3"
4459 +source = "registry+https://github.com/rust-lang/crates.io-index"
4460 +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
4461 +dependencies = [
4462 + "aho-corasick",
4463 + "memchr",
4464 + "regex-automata",
4465 + "regex-syntax",
4466 +]
4467 +
4468 +[[package]]
4469 +name = "regex-automata"
4470 +version = "0.4.14"
4471 +source = "registry+https://github.com/rust-lang/crates.io-index"
4472 +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
4473 +dependencies = [
4474 + "aho-corasick",
4475 + "memchr",
4476 + "regex-syntax",
4477 +]
4478 +
4479 +[[package]]
4480 +name = "regex-syntax"
4481 +version = "0.8.10"
4482 +source = "registry+https://github.com/rust-lang/crates.io-index"
4483 +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
4484 +
4485 +[[package]]
4486 +name = "reqwest"
4487 +version = "0.12.28"
4488 +source = "registry+https://github.com/rust-lang/crates.io-index"
4489 +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
4490 +dependencies = [
4491 + "base64 0.22.1",
4492 + "bytes",
4493 + "encoding_rs",
4494 + "futures-channel",
4495 + "futures-core",
4496 + "futures-util",
4497 + "h2",
4498 + "http",
4499 + "http-body",
4500 + "http-body-util",
4501 + "hyper",
4502 + "hyper-rustls",
4503 + "hyper-tls",
4504 + "hyper-util",
4505 + "js-sys",
4506 + "log",
4507 + "mime",
4508 + "mime_guess",
4509 + "native-tls",
4510 + "percent-encoding",
4511 + "pin-project-lite",
4512 + "quinn",
4513 + "rustls",
4514 + "rustls-pki-types",
4515 + "serde",
4516 + "serde_json",
4517 + "serde_urlencoded",
4518 + "sync_wrapper",
4519 + "tokio",
4520 + "tokio-native-tls",
4521 + "tokio-rustls",
4522 + "tokio-util",
4523 + "tower",
4524 + "tower-http",
4525 + "tower-service",
4526 + "url",
4527 + "wasm-bindgen",
4528 + "wasm-bindgen-futures",
4529 + "wasm-streams 0.4.2",
4530 + "web-sys",
4531 + "webpki-roots 1.0.6",
4532 +]
4533 +
4534 +[[package]]
4535 +name = "reqwest"
4536 +version = "0.13.2"
4537 +source = "registry+https://github.com/rust-lang/crates.io-index"
4538 +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
4539 +dependencies = [
4540 + "base64 0.22.1",
4541 + "bytes",
4542 + "encoding_rs",
4543 + "futures-channel",
4544 + "futures-core",
4545 + "futures-util",
4546 + "h2",
4547 + "http",
4548 + "http-body",
4549 + "http-body-util",
4550 + "hyper",
4551 + "hyper-rustls",
4552 + "hyper-util",
4553 + "js-sys",
4554 + "log",
4555 + "mime",
4556 + "percent-encoding",
4557 + "pin-project-lite",
4558 + "quinn",
4559 + "rustls",
4560 + "rustls-pki-types",
4561 + "rustls-platform-verifier",
4562 + "serde",
4563 + "serde_json",
4564 + "sync_wrapper",
4565 + "tokio",
4566 + "tokio-rustls",
4567 + "tokio-util",
4568 + "tower",
4569 + "tower-http",
4570 + "tower-service",
4571 + "url",
4572 + "wasm-bindgen",
4573 + "wasm-bindgen-futures",
4574 + "wasm-streams 0.5.0",
4575 + "web-sys",
4576 +]
4577 +
4578 +[[package]]
4579 +name = "rgb"
4580 +version = "0.8.53"
4581 +source = "registry+https://github.com/rust-lang/crates.io-index"
4582 +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
4583 +
4584 +[[package]]
4585 +name = "ring"
4586 +version = "0.17.14"
4587 +source = "registry+https://github.com/rust-lang/crates.io-index"
4588 +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
4589 +dependencies = [
4590 + "cc",
4591 + "cfg-if",
4592 + "getrandom 0.2.17",
4593 + "libc",
4594 + "untrusted",
4595 + "windows-sys 0.52.0",
4596 +]
4597 +
4598 +[[package]]
4599 +name = "rubato"
4600 +version = "0.16.2"
4601 +source = "registry+https://github.com/rust-lang/crates.io-index"
4602 +checksum = "5258099699851cfd0082aeb645feb9c084d9a5e1f1b8d5372086b989fc5e56a1"
4603 +dependencies = [
4604 + "num-complex",
4605 + "num-integer",
4606 + "num-traits",
4607 + "realfft",
4608 +]
4609 +
4610 +[[package]]
4611 +name = "rust-mcp-schema"
4612 +version = "0.9.6"
4613 +source = "registry+https://github.com/rust-lang/crates.io-index"
4614 +checksum = "b1209aa7fb74fccafe6b2a649b15581fb328343427d85def865b0ad233fe1f74"
4615 +dependencies = [
4616 + "serde",
4617 + "serde_json",
4618 +]
4619 +
4620 +[[package]]
4621 +name = "rust-stemmers"
4622 +version = "1.2.0"
4623 +source = "registry+https://github.com/rust-lang/crates.io-index"
4624 +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
4625 +dependencies = [
4626 + "serde",
4627 + "serde_derive",
4628 +]
4629 +
4630 +[[package]]
4631 +name = "rustc-hash"
4632 +version = "1.1.0"
4633 +source = "registry+https://github.com/rust-lang/crates.io-index"
4634 +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
4635 +
4636 +[[package]]
4637 +name = "rustc-hash"
4638 +version = "2.1.1"
4639 +source = "registry+https://github.com/rust-lang/crates.io-index"
4640 +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
4641 +
4642 +[[package]]
4643 +name = "rustc_version"
4644 +version = "0.4.1"
4645 +source = "registry+https://github.com/rust-lang/crates.io-index"
4646 +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
4647 +dependencies = [
4648 + "semver",
4649 +]
4650 +
4651 +[[package]]
4652 +name = "rustfft"
4653 +version = "6.4.1"
4654 +source = "registry+https://github.com/rust-lang/crates.io-index"
4655 +checksum = "21db5f9893e91f41798c88680037dba611ca6674703c1a18601b01a72c8adb89"
4656 +dependencies = [
4657 + "num-complex",
4658 + "num-integer",
4659 + "num-traits",
4660 + "primal-check",
4661 + "strength_reduce",
4662 + "transpose",
4663 +]
4664 +
4665 +[[package]]
4666 +name = "rustix"
4667 +version = "0.38.44"
4668 +source = "registry+https://github.com/rust-lang/crates.io-index"
4669 +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
4670 +dependencies = [
4671 + "bitflags 2.11.0",
4672 + "errno",
4673 + "libc",
4674 + "linux-raw-sys 0.4.15",
4675 + "windows-sys 0.59.0",
4676 +]
4677 +
4678 +[[package]]
4679 +name = "rustix"
4680 +version = "1.1.4"
4681 +source = "registry+https://github.com/rust-lang/crates.io-index"
4682 +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
4683 +dependencies = [
4684 + "bitflags 2.11.0",
4685 + "errno",
4686 + "libc",
4687 + "linux-raw-sys 0.12.1",
4688 + "windows-sys 0.61.2",
4689 +]
4690 +
4691 +[[package]]
4692 +name = "rustls"
4693 +version = "0.23.37"
4694 +source = "registry+https://github.com/rust-lang/crates.io-index"
4695 +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
4696 +dependencies = [
4697 + "aws-lc-rs",
4698 + "log",
4699 + "once_cell",
4700 + "ring",
4701 + "rustls-pki-types",
4702 + "rustls-webpki",
4703 + "subtle",
4704 + "zeroize",
4705 +]
4706 +
4707 +[[package]]
4708 +name = "rustls-native-certs"
4709 +version = "0.8.3"
4710 +source = "registry+https://github.com/rust-lang/crates.io-index"
4711 +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
4712 +dependencies = [
4713 + "openssl-probe",
4714 + "rustls-pki-types",
4715 + "schannel",
4716 + "security-framework",
4717 +]
4718 +
4719 +[[package]]
4720 +name = "rustls-pki-types"
4721 +version = "1.14.0"
4722 +source = "registry+https://github.com/rust-lang/crates.io-index"
4723 +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
4724 +dependencies = [
4725 + "web-time",
4726 + "zeroize",
4727 +]
4728 +
4729 +[[package]]
4730 +name = "rustls-platform-verifier"
4731 +version = "0.6.2"
4732 +source = "registry+https://github.com/rust-lang/crates.io-index"
4733 +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
4734 +dependencies = [
4735 + "core-foundation 0.10.1",
4736 + "core-foundation-sys",
4737 + "jni",
4738 + "log",
4739 + "once_cell",
4740 + "rustls",
4741 + "rustls-native-certs",
4742 + "rustls-platform-verifier-android",
4743 + "rustls-webpki",
4744 + "security-framework",
4745 + "security-framework-sys",
4746 + "webpki-root-certs",
4747 + "windows-sys 0.61.2",
4748 +]
4749 +
4750 +[[package]]
4751 +name = "rustls-platform-verifier-android"
4752 +version = "0.1.1"
4753 +source = "registry+https://github.com/rust-lang/crates.io-index"
4754 +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
4755 +
4756 +[[package]]
4757 +name = "rustls-webpki"
4758 +version = "0.103.10"
4759 +source = "registry+https://github.com/rust-lang/crates.io-index"
4760 +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
4761 +dependencies = [
4762 + "aws-lc-rs",
4763 + "ring",
4764 + "rustls-pki-types",
4765 + "untrusted",
4766 +]
4767 +
4768 +[[package]]
4769 +name = "rustversion"
4770 +version = "1.0.22"
4771 +source = "registry+https://github.com/rust-lang/crates.io-index"
4772 +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
4773 +
4774 +[[package]]
4775 +name = "ryu"
4776 +version = "1.0.23"
4777 +source = "registry+https://github.com/rust-lang/crates.io-index"
4778 +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
4779 +
4780 +[[package]]
4781 +name = "safe_arch"
4782 +version = "0.7.4"
4783 +source = "registry+https://github.com/rust-lang/crates.io-index"
4784 +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
4785 +dependencies = [
4786 + "bytemuck",
4787 +]
4788 +
4789 +[[package]]
4790 +name = "safetensors"
4791 +version = "0.4.5"
4792 +source = "registry+https://github.com/rust-lang/crates.io-index"
4793 +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6"
4794 +dependencies = [
4795 + "serde",
4796 + "serde_json",
4797 +]
4798 +
4799 +[[package]]
4800 +name = "safetensors"
4801 +version = "0.7.0"
4802 +source = "registry+https://github.com/rust-lang/crates.io-index"
4803 +checksum = "675656c1eabb620b921efea4f9199f97fc86e36dd6ffd1fbbe48d0f59a4987f5"
4804 +dependencies = [
4805 + "hashbrown 0.16.1",
4806 + "serde",
4807 + "serde_json",
4808 +]
4809 +
4810 +[[package]]
4811 +name = "same-file"
4812 +version = "1.0.6"
4813 +source = "registry+https://github.com/rust-lang/crates.io-index"
4814 +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
4815 +dependencies = [
4816 + "winapi-util",
4817 +]
4818 +
4819 +[[package]]
4820 +name = "saphyr-parser-bw"
4821 +version = "0.0.605"
4822 +source = "registry+https://github.com/rust-lang/crates.io-index"
4823 +checksum = "5e1aee7486406df3541b5a657204a11be97175a467d77bc98e6d94a66289fb80"
4824 +dependencies = [
4825 + "arraydeque",
4826 + "smallvec 2.0.0-alpha.12",
4827 + "thiserror 2.0.18",
4828 +]
4829 +
4830 +[[package]]
4831 +name = "schannel"
4832 +version = "0.1.29"
4833 +source = "registry+https://github.com/rust-lang/crates.io-index"
4834 +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
4835 +dependencies = [
4836 + "windows-sys 0.61.2",
4837 +]
4838 +
4839 +[[package]]
4840 +name = "schemars"
4841 +version = "0.9.0"
4842 +source = "registry+https://github.com/rust-lang/crates.io-index"
4843 +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
4844 +dependencies = [
4845 + "dyn-clone",
4846 + "ref-cast",
4847 + "serde",
4848 + "serde_json",
4849 +]
4850 +
4851 +[[package]]
4852 +name = "schemars"
4853 +version = "1.2.1"
4854 +source = "registry+https://github.com/rust-lang/crates.io-index"
4855 +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc"
4856 +dependencies = [
4857 + "dyn-clone",
4858 + "ref-cast",
4859 + "schemars_derive",
4860 + "serde",
4861 + "serde_json",
4862 +]
4863 +
4864 +[[package]]
4865 +name = "schemars_derive"
4866 +version = "1.2.1"
4867 +source = "registry+https://github.com/rust-lang/crates.io-index"
4868 +checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f"
4869 +dependencies = [
4870 + "proc-macro2",
4871 + "quote",
4872 + "serde_derive_internals",
4873 + "syn 2.0.117",
4874 +]
4875 +
4876 +[[package]]
4877 +name = "scoped-tls"
4878 +version = "1.0.1"
4879 +source = "registry+https://github.com/rust-lang/crates.io-index"
4880 +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
4881 +
4882 +[[package]]
4883 +name = "scopeguard"
4884 +version = "1.2.0"
4885 +source = "registry+https://github.com/rust-lang/crates.io-index"
4886 +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
4887 +
4888 +[[package]]
4889 +name = "scraper"
4890 +version = "0.25.0"
4891 +source = "registry+https://github.com/rust-lang/crates.io-index"
4892 +checksum = "93cecd86d6259499c844440546d02f55f3e17bd286e529e48d1f9f67e92315cb"
4893 +dependencies = [
4894 + "cssparser",
4895 + "ego-tree",
4896 + "getopts",
4897 + "html5ever 0.36.1",
4898 + "precomputed-hash",
4899 + "selectors",
4900 + "tendril 0.4.3",
4901 +]
4902 +
4903 +[[package]]
4904 +name = "scroll"
4905 +version = "0.12.0"
4906 +source = "registry+https://github.com/rust-lang/crates.io-index"
4907 +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
4908 +dependencies = [
4909 + "scroll_derive",
4910 +]
4911 +
4912 +[[package]]
4913 +name = "scroll_derive"
4914 +version = "0.12.1"
4915 +source = "registry+https://github.com/rust-lang/crates.io-index"
4916 +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
4917 +dependencies = [
4918 + "proc-macro2",
4919 + "quote",
4920 + "syn 2.0.117",
4921 +]
4922 +
4923 +[[package]]
4924 +name = "security-framework"
4925 +version = "3.7.0"
4926 +source = "registry+https://github.com/rust-lang/crates.io-index"
4927 +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
4928 +dependencies = [
4929 + "bitflags 2.11.0",
4930 + "core-foundation 0.10.1",
4931 + "core-foundation-sys",
4932 + "libc",
4933 + "security-framework-sys",
4934 +]
4935 +
4936 +[[package]]
4937 +name = "security-framework-sys"
4938 +version = "2.17.0"
4939 +source = "registry+https://github.com/rust-lang/crates.io-index"
4940 +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
4941 +dependencies = [
4942 + "core-foundation-sys",
4943 + "libc",
4944 +]
4945 +
4946 +[[package]]
4947 +name = "selectors"
4948 +version = "0.33.0"
4949 +source = "registry+https://github.com/rust-lang/crates.io-index"
4950 +checksum = "feef350c36147532e1b79ea5c1f3791373e61cbd9a6a2615413b3807bb164fb7"
4951 +dependencies = [
4952 + "bitflags 2.11.0",
4953 + "cssparser",
4954 + "derive_more",
4955 + "log",
4956 + "new_debug_unreachable",
4957 + "phf",
4958 + "phf_codegen",
4959 + "precomputed-hash",
4960 + "rustc-hash 2.1.1",
4961 + "servo_arc",
4962 + "smallvec 1.15.1",
4963 +]
4964 +
4965 +[[package]]
4966 +name = "semver"
4967 +version = "1.0.27"
4968 +source = "registry+https://github.com/rust-lang/crates.io-index"
4969 +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
4970 +dependencies = [
4971 + "serde",
4972 + "serde_core",
4973 +]
4974 +
4975 +[[package]]
4976 +name = "seq-macro"
4977 +version = "0.3.6"
4978 +source = "registry+https://github.com/rust-lang/crates.io-index"
4979 +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
4980 +
4981 +[[package]]
4982 +name = "serde"
4983 +version = "1.0.228"
4984 +source = "registry+https://github.com/rust-lang/crates.io-index"
4985 +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
4986 +dependencies = [
4987 + "serde_core",
4988 + "serde_derive",
4989 +]
4990 +
4991 +[[package]]
4992 +name = "serde-big-array"
4993 +version = "0.5.1"
4994 +source = "registry+https://github.com/rust-lang/crates.io-index"
4995 +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f"
4996 +dependencies = [
4997 + "serde",
4998 +]
4999 +

This file is too large to show in full.

Cargo.toml new
+82
@@ -0,0 +1,82 @@
1 +[package]
2 +name = "onde"
3 +version = "0.1.0"
4 +edition = "2021"
5 +description = "On-device inference for cross-platform apps — run LLMs, diffusion models, and speech-to-text locally with automatic model management."
6 +license = "MIT"
7 +repository = "https://github.com/ondeinference/onde"
8 +homepage = "https://ondeinference.com"
9 +documentation = "https://docs.rs/onde"
10 +readme = "README.md"
11 +keywords = ["inference", "on-device", "whisper", "llm", "mistral"]
12 +categories = ["multimedia::audio", "science::ml", "api-bindings"]
13 +
14 +[lib]
15 +name = "onde"
16 +# "lib" – normal Rust dependency for other crates.
17 +# "cdylib" – shared library (.dylib / .so / .dll) consumed by UniFFI bindgen
18 +# to generate Swift / Kotlin / Python bindings.
19 +# "staticlib" – static library (.a) required for iOS targets where dynamic
20 +# linking is not allowed.
21 +crate-type = ["lib", "cdylib", "staticlib"]
22 +
23 +[features]
24 +default = []
25 +# Enable Whisper-based speech-to-text transcription via transcribe-rs.
26 +# macOS uses Metal GPU acceleration; Android uses CPU-only inference.
27 +whisper = ["dep:transcribe-rs", "dep:hf-hub"]
28 +
29 +[dependencies]
30 +anyhow = "1"
31 +home = "0.5.4"
32 +log = "^0.4"
33 +serde = { version = "1.0", features = ["derive"] }
34 +tokio = { version = "1", features = ["macros", "rt", "sync"] }
35 +tsync = "2"
36 +
37 +thiserror = "2"
38 +
39 +# Pinned to =0.31.0 — the versions MUST be identical across the crate and
40 +# the uniffi-bindgen binary crate.
41 +uniffi = { version = "=0.31.0", features = ["tokio"] }
42 +
43 +# Optional: Whisper speech-to-text engine (transcribe-rs wraps whisper.cpp).
44 +# The `whisper` feature in transcribe-rs pulls in platform-specific whisper-rs
45 +# (Metal on macOS, Vulkan on Windows/Linux) via its own Cargo.toml cfg gates.
46 +transcribe-rs = { git = "https://github.com/setoelkahfi/transcribe-rs", branch = "feature/onde", features = ["whisper"], optional = true }
47 +hf-hub = { version = "0.4", features = ["tokio"], optional = true }
48 +
49 +[build-dependencies]
50 +# Required for UniFFI scaffolding code generation at build time.
51 +uniffi = { version = "=0.31.0", features = ["build"] }
52 +# Used by build.rs to compile the tvOS ___chkstk_darwin assembly stub.
53 +cc = "1"
54 +
55 +# Android: CPU-only GGUF inference via candle; also needs hf-hub for explicit
56 +# cache path seeding (dirs::home_dir() panics in the Android sandbox).
57 +[target.'cfg(target_os = "android")'.dependencies]
58 +hf-hub = { version = "0.4", features = ["tokio"] }
59 +mistralrs = { git = "https://github.com/setoelkahfi/mistral.rs", branch = "fix/all-platform-fixes", features = [] }
60 +mistralrs-core = { git = "https://github.com/setoelkahfi/mistral.rs", branch = "fix/all-platform-fixes", features = [] }
61 +
62 +# iOS: Metal-accelerated inference.
63 +[target.'cfg(target_os = "ios")'.dependencies]
64 +mistralrs = { git = "https://github.com/setoelkahfi/mistral.rs", branch = "fix/all-platform-fixes", features = ["metal"] }
65 +
66 +# tvOS: Metal-accelerated inference (Apple TV has Apple GPU).
67 +[target.'cfg(target_os = "tvos")'.dependencies]
68 +mistralrs = { git = "https://github.com/setoelkahfi/mistral.rs", branch = "fix/all-platform-fixes", features = ["metal"] }
69 +
70 +# macOS: Metal-accelerated inference.
71 +[target.'cfg(target_os = "macos")'.dependencies]
72 +mistralrs = { git = "https://github.com/setoelkahfi/mistral.rs", branch = "fix/all-platform-fixes", features = ["metal"] }
73 +
74 +# Windows: CPU-only baseline (no GPU features).
75 +# For NVIDIA GPU builds, patch this to features = ["cuda"] in CI before building.
76 +[target.'cfg(target_os = "windows")'.dependencies]
77 +mistralrs = { git = "https://github.com/setoelkahfi/mistral.rs", branch = "fix/all-platform-fixes" }
78 +
79 +# Linux: CPU-only baseline (no GPU features).
80 +# For NVIDIA GPU builds, patch this to features = ["cuda"] in CI before building.
81 +[target.'cfg(target_os = "linux")'.dependencies]
82 +mistralrs = { git = "https://github.com/setoelkahfi/mistral.rs", branch = "fix/all-platform-fixes" }
README copy.md new
+33
@@ -0,0 +1,33 @@
1 +<h1 align="center">
2 + <br>
3 + Onde
4 + <br>
5 +</h1>
6 +
7 +<p align="center">
8 + <strong>On-device inference for cross-platform apps.</strong>
9 + <br>
10 + Run LLMs, diffusion models, and speech-to-text locally — no cloud, no latency, no data leaving the device.
11 +</p>
12 +
13 +<p align="center">
14 + <a href="https://crates.io/crates/onde"><img src="https://img.shields.io/crates/v/onde.svg" alt="crates.io"></a>
15 + <a href="https://docs.rs/onde"><img src="https://docs.rs/onde/badge.svg" alt="docs.rs"></a>
16 + <a href="#license"><img src="https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg" alt="License"></a>
17 +</p>
18 +
19 +---
20 +
21 +**Onde** is a Rust crate that gives your app on-device AI in a single dependency. It wraps [mistral.rs](https://github.com/EricLBuehler/mistral.rs) for LLM and image generation, and [whisper.cpp](https://github.com/ggerganov/whisper.cpp) (via [transcribe-rs](https://github.com/cjpais/transcribe-rs)) for speech-to-text — with a unified API that handles model discovery, HuggingFace Hub downloads, cache management, and GPU acceleration across every platform.
22 +
23 +## License
24 +
25 +MIT License
26 +
27 +---
28 +
29 +## Copyright
30 +
31 +<p align="center">
32 + 2026 <a href="https://ondeinference.com">Onde Inference</a>
33 +</p>
build-kotlin.sh new
+406
@@ -0,0 +1,406 @@
1 +#!/usr/bin/env bash
2 +# ──────────────────────────────────────────────────────────────────────────────
3 +# build-kotlin.sh — Cross-compile libonde for Android and generate Kotlin bindings
4 +# ──────────────────────────────────────────────────────────────────────────────
5 +#
6 +# This script:
7 +# 1. Builds the `uniffi-bindgen` CLI tool (host binary).
8 +# 2. Cross-compiles the `onde` cdylib (libonde.so) for each Android target.
9 +# 3. Runs `uniffi-bindgen generate` to produce the Kotlin source from the
10 +# compiled library.
11 +# 4. Copies the .so files into the Android library's jniLibs directories.
12 +#
13 +# Prerequisites:
14 +# - Rust toolchain with Android targets installed:
15 +# rustup target add aarch64-linux-android armv7-linux-androideabi \
16 +# x86_64-linux-android i686-linux-android
17 +# - Android NDK installed (set ANDROID_NDK_HOME or auto-detected from ANDROID_HOME)
18 +# - cargo, rustc on PATH
19 +#
20 +# Usage:
21 +# ./build-kotlin.sh # Build all targets (release)
22 +# ./build-kotlin.sh --debug # Build all targets (debug)
23 +# ./build-kotlin.sh --target aarch64-linux-android # Single target
24 +# ./build-kotlin.sh --help # Show usage
25 +#
26 +# Environment variables:
27 +# ANDROID_NDK_HOME — Path to the Android NDK (e.g. ~/Library/Android/sdk/ndk/27.2.12479018)
28 +# ANDROID_HOME — Path to the Android SDK (NDK auto-detected under ndk/)
29 +# ONDE_FEATURES — Extra Cargo features to enable (comma-separated, default: none)
30 +# CARGO — Path to cargo binary (default: cargo)
31 +# ──────────────────────────────────────────────────────────────────────────────
32 +set -euo pipefail
33 +
34 +# ── Constants ─────────────────────────────────────────────────────────────────
35 +
36 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
37 +CRATE_DIR="$SCRIPT_DIR"
38 +KOTLIN_PROJECT_DIR="$CRATE_DIR/kotlin"
39 +KOTLIN_LIB_DIR="$KOTLIN_PROJECT_DIR/onde"
40 +JNILIBS_DIR="$KOTLIN_LIB_DIR/src/main/jniLibs"
41 +# UniFFI's --out-dir receives the Kotlin source root; it creates the
42 +# package directory structure (com/ondeinference/onde/) automatically
43 +# based on the package_name in uniffi.toml.
44 +KOTLIN_SRC_ROOT="$KOTLIN_LIB_DIR/src/main/kotlin"
45 +GENERATED_KT_DIR="$KOTLIN_SRC_ROOT/com/ondeinference/onde"
46 +BINDGEN_CRATE_DIR="$CRATE_DIR/uniffi-bindgen"
47 +
48 +CARGO="${CARGO:-cargo}"
49 +PROFILE="release"
50 +PROFILE_DIR="release"
51 +
52 +# Map Rust target triples to Android ABI folder names and NDK toolchain prefixes.
53 +declare -A TARGET_TO_ABI=(
54 + ["aarch64-linux-android"]="arm64-v8a"
55 + ["armv7-linux-androideabi"]="armeabi-v7a"
56 + ["x86_64-linux-android"]="x86_64"
57 + ["i686-linux-android"]="x86"
58 +)
59 +
60 +declare -A TARGET_TO_CC_PREFIX=(
61 + ["aarch64-linux-android"]="aarch64-linux-android"
62 + ["armv7-linux-androideabi"]="armv7a-linux-androideabi"
63 + ["x86_64-linux-android"]="x86_64-linux-android"
64 + ["i686-linux-android"]="i686-linux-android"
65 +)
66 +
67 +ALL_TARGETS=("aarch64-linux-android" "armv7-linux-androideabi" "x86_64-linux-android" "i686-linux-android")
68 +SELECTED_TARGETS=()
69 +
70 +# Minimum Android API level — must match the library's minSdk (24).
71 +MIN_API=24
72 +
73 +# ── Helpers ───────────────────────────────────────────────────────────────────
74 +
75 +RED='\033[0;31m'
76 +GREEN='\033[0;32m'
77 +YELLOW='\033[0;33m'
78 +CYAN='\033[0;36m'
79 +BOLD='\033[1m'
80 +NC='\033[0m' # No Color
81 +
82 +log() { echo -e "${CYAN}[onde]${NC} $*"; }
83 +ok() { echo -e "${GREEN}[onde]${NC} $*"; }
84 +warn() { echo -e "${YELLOW}[onde]${NC} $*"; }
85 +err() { echo -e "${RED}[onde]${NC} $*" >&2; }
86 +die() { err "$@"; exit 1; }
87 +
88 +usage() {
89 + cat <<EOF
90 +Usage: $(basename "$0") [OPTIONS]
91 +
92 +Cross-compile libonde for Android and generate Kotlin (UniFFI) bindings.
93 +
94 +Options:
95 + --debug Build in debug mode (default: release)
96 + --target <triple> Build only for the specified Rust target triple.
97 + Can be repeated. If omitted, all four Android targets
98 + are built: ${ALL_TARGETS[*]}
99 + --generate-only Skip Rust compilation; only run uniffi-bindgen to
100 + regenerate the Kotlin source from an existing .so.
101 + --ndk <path> Explicit path to the Android NDK.
102 + --help, -h Show this help message.
103 +
104 +Environment:
105 + ANDROID_NDK_HOME Android NDK path (auto-detected from ANDROID_HOME)
106 + ANDROID_HOME Android SDK path (NDK searched under ndk/)
107 + ONDE_FEATURES Extra Cargo features, comma-separated
108 + CARGO Path to cargo (default: cargo)
109 +
110 +Examples:
111 + # Full build for all Android ABIs (release)
112 + ./build-kotlin.sh
113 +
114 + # Debug build, arm64 only
115 + ./build-kotlin.sh --debug --target aarch64-linux-android
116 +
117 + # Re-generate Kotlin source without recompiling Rust
118 + ./build-kotlin.sh --generate-only
119 +EOF
120 + exit 0
121 +}
122 +
123 +# ── Argument parsing ──────────────────────────────────────────────────────────
124 +
125 +GENERATE_ONLY=false
126 +
127 +while [[ $# -gt 0 ]]; do
128 + case "$1" in
129 + --debug)
130 + PROFILE="debug"
131 + PROFILE_DIR="debug"
132 + shift
133 + ;;
134 + --target)
135 + [[ -n "${2:-}" ]] || die "--target requires a Rust target triple"
136 + SELECTED_TARGETS+=("$2")
137 + shift 2
138 + ;;
139 + --generate-only)
140 + GENERATE_ONLY=true
141 + shift
142 + ;;
143 + --ndk)
144 + [[ -n "${2:-}" ]] || die "--ndk requires a path"
145 + ANDROID_NDK_HOME="$2"
146 + shift 2
147 + ;;
148 + --help|-h)
149 + usage
150 + ;;
151 + *)
152 + die "Unknown option: $1 (try --help)"
153 + ;;
154 + esac
155 +done
156 +
157 +# Default to all targets if none specified.
158 +if [[ ${#SELECTED_TARGETS[@]} -eq 0 ]]; then
159 + SELECTED_TARGETS=("${ALL_TARGETS[@]}")
160 +fi
161 +
162 +# Validate selected targets.
163 +for t in "${SELECTED_TARGETS[@]}"; do
164 + if [[ -z "${TARGET_TO_ABI[$t]:-}" ]]; then
165 + die "Unknown Android target: $t\nValid targets: ${ALL_TARGETS[*]}"
166 + fi
167 +done
168 +
169 +# ── Locate the Android NDK ────────────────────────────────────────────────────
170 +
171 +find_ndk() {
172 + # 1. Explicit ANDROID_NDK_HOME
173 + if [[ -n "${ANDROID_NDK_HOME:-}" && -d "$ANDROID_NDK_HOME" ]]; then
174 + echo "$ANDROID_NDK_HOME"
175 + return
176 + fi
177 +
178 + # 2. Search inside ANDROID_HOME/ndk/ — pick the newest version.
179 + if [[ -n "${ANDROID_HOME:-}" && -d "$ANDROID_HOME/ndk" ]]; then
180 + local latest
181 + latest=$(find "$ANDROID_HOME/ndk" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -1)
182 + if [[ -n "$latest" ]]; then
183 + echo "$latest"
184 + return
185 + fi
186 + fi
187 +
188 + # 3. Common macOS SDK location.
189 + local default_sdk="$HOME/Library/Android/sdk"
190 + if [[ -d "$default_sdk/ndk" ]]; then
191 + local latest
192 + latest=$(find "$default_sdk/ndk" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -1)
193 + if [[ -n "$latest" ]]; then
194 + echo "$latest"
195 + return
196 + fi
197 + fi
198 +
199 + # 4. Linux default.
200 + local linux_sdk="$HOME/Android/Sdk"
201 + if [[ -d "$linux_sdk/ndk" ]]; then
202 + local latest
203 + latest=$(find "$linux_sdk/ndk" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -1)
204 + if [[ -n "$latest" ]]; then
205 + echo "$latest"
206 + return
207 + fi
208 + fi
209 +
210 + return 1
211 +}
212 +
213 +if ! $GENERATE_ONLY; then
214 + NDK_HOME=$(find_ndk) || die \
215 + "Android NDK not found.\n" \
216 + "Set ANDROID_NDK_HOME or ANDROID_HOME, or pass --ndk <path>."
217 +
218 + log "Using Android NDK: ${BOLD}$NDK_HOME${NC}"
219 +
220 + # Determine the host OS tag for the NDK toolchain.
221 + case "$(uname -s)" in
222 + Darwin*) HOST_TAG="darwin-x86_64" ;;
223 + Linux*) HOST_TAG="linux-x86_64" ;;
224 + MINGW*|MSYS*|CYGWIN*) HOST_TAG="windows-x86_64" ;;
225 + *) die "Unsupported host OS: $(uname -s)" ;;
226 + esac
227 +
228 + TOOLCHAIN_BIN="$NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG/bin"
229 + [[ -d "$TOOLCHAIN_BIN" ]] || die "NDK toolchain not found at: $TOOLCHAIN_BIN"
230 +fi
231 +
232 +# ── Step 1: Build the uniffi-bindgen CLI (host) ──────────────────────────────
233 +
234 +log "Building ${BOLD}uniffi-bindgen${NC} CLI (host)..."
235 +
236 +$CARGO build \
237 + --manifest-path "$BINDGEN_CRATE_DIR/Cargo.toml" \
238 + --release \
239 + --quiet
240 +
241 +UNIFFI_BINDGEN="$BINDGEN_CRATE_DIR/target/release/uniffi-bindgen"
242 +# If the binary lands in the workspace target/ dir instead, try that too.
243 +if [[ ! -x "$UNIFFI_BINDGEN" ]]; then
244 + # When the crate shares a workspace target dir (or no workspace), the
245 + # binary may be under the onde crate's target/ or the workspace root.
246 + for candidate in \
247 + "$CRATE_DIR/target/release/uniffi-bindgen" \
248 + "$CRATE_DIR/../../../target/release/uniffi-bindgen"; do
249 + if [[ -x "$candidate" ]]; then
250 + UNIFFI_BINDGEN="$candidate"
251 + break
252 + fi
253 + done
254 +fi
255 +
256 +[[ -x "$UNIFFI_BINDGEN" ]] || die "uniffi-bindgen binary not found after build."
257 +ok "uniffi-bindgen ready: $UNIFFI_BINDGEN"
258 +
259 +# ── Step 2: Cross-compile the Rust cdylib for each Android target ─────────────
260 +
261 +# We'll remember the path to the first successfully built .so so we can use
262 +# it for bindgen (any ABI's .so contains the same UniFFI metadata).
263 +FIRST_SO=""
264 +
265 +if ! $GENERATE_ONLY; then
266 + FEATURES_FLAG=""
267 + if [[ -n "${ONDE_FEATURES:-}" ]]; then
268 + FEATURES_FLAG="--features $ONDE_FEATURES"
269 + fi
270 +
271 + for TARGET in "${SELECTED_TARGETS[@]}"; do
272 + ABI="${TARGET_TO_ABI[$TARGET]}"
273 + CC_PREFIX="${TARGET_TO_CC_PREFIX[$TARGET]}"
274 +
275 + log "Compiling ${BOLD}libonde.so${NC} for ${BOLD}$TARGET${NC} ($ABI)..."
276 +
277 + # Set up the CC/CXX/AR/RANLIB environment for the NDK clang toolchain
278 + # so that cc-rs, cmake, and any -sys crates find the right compiler.
279 + export CC="${TOOLCHAIN_BIN}/${CC_PREFIX}${MIN_API}-clang"
280 + export CXX="${TOOLCHAIN_BIN}/${CC_PREFIX}${MIN_API}-clang++"
281 + export AR="${TOOLCHAIN_BIN}/llvm-ar"
282 + export RANLIB="${TOOLCHAIN_BIN}/llvm-ranlib"
283 +
284 + # Cargo uses the uppercase-dashed form of the target for env overrides.
285 + TARGET_UPPER=$(echo "$TARGET" | tr '[:lower:]-' '[:upper:]_')
286 + export "CARGO_TARGET_${TARGET_UPPER}_LINKER=$CC"
287 +
288 + if [[ "$PROFILE" == "release" ]]; then
289 + PROFILE_FLAG="--release"
290 + else
291 + PROFILE_FLAG=""
292 + fi
293 +
294 + $CARGO build \
295 + --manifest-path "$CRATE_DIR/Cargo.toml" \
296 + --lib \
297 + --target "$TARGET" \
298 + $PROFILE_FLAG \
299 + $FEATURES_FLAG
300 +
301 + # Locate the built .so
302 + SO_PATH="$CRATE_DIR/target/$TARGET/$PROFILE_DIR/libonde.so"
303 + if [[ ! -f "$SO_PATH" ]]; then
304 + # Some workspace layouts put target/ at the workspace root.
305 + for candidate in \
306 + "$CRATE_DIR/../../../target/$TARGET/$PROFILE_DIR/libonde.so" \
307 + "$CRATE_DIR/../../target/$TARGET/$PROFILE_DIR/libonde.so"; do
308 + if [[ -f "$candidate" ]]; then
309 + SO_PATH="$(cd "$(dirname "$candidate")" && pwd)/$(basename "$candidate")"
310 + break
311 + fi
312 + done
313 + fi
314 +
315 + [[ -f "$SO_PATH" ]] || die "libonde.so not found for $TARGET at expected paths."
316 +
317 + # Copy into jniLibs/
318 + mkdir -p "$JNILIBS_DIR/$ABI"
319 + cp "$SO_PATH" "$JNILIBS_DIR/$ABI/libonde.so"
320 + ok " → $JNILIBS_DIR/$ABI/libonde.so ($(du -h "$JNILIBS_DIR/$ABI/libonde.so" | cut -f1))"
321 +
322 + if [[ -z "$FIRST_SO" ]]; then
323 + FIRST_SO="$SO_PATH"
324 + fi
325 + done
326 +else
327 + # Generate-only: find an existing .so to extract metadata from.
328 + for TARGET in "${SELECTED_TARGETS[@]}"; do
329 + for candidate in \
330 + "$CRATE_DIR/target/$TARGET/$PROFILE_DIR/libonde.so" \
331 + "$CRATE_DIR/../../../target/$TARGET/$PROFILE_DIR/libonde.so" \
332 + "$JNILIBS_DIR/${TARGET_TO_ABI[$TARGET]}/libonde.so"; do
333 + if [[ -f "$candidate" ]]; then
334 + FIRST_SO="$candidate"
335 + break 2
336 + fi
337 + done
338 + done
339 +
340 + # Also try the host dylib (macOS .dylib, Linux .so) — uniffi-bindgen
341 + # only needs the metadata, not a runnable Android binary.
342 + if [[ -z "$FIRST_SO" ]]; then
343 + for ext in dylib so; do
344 + candidate="$CRATE_DIR/target/$PROFILE_DIR/libonde.$ext"
345 + if [[ -f "$candidate" ]]; then
346 + FIRST_SO="$candidate"
347 + break
348 + fi
349 + done
350 + fi
351 +
352 + [[ -n "$FIRST_SO" ]] || die "No compiled libonde found. Run without --generate-only first."
353 + log "Using existing library for bindgen: $FIRST_SO"
354 +fi
355 +
356 +# ── Step 3: Generate Kotlin bindings via uniffi-bindgen ───────────────────────
357 +
358 +log "Generating Kotlin bindings..."
359 +
360 +mkdir -p "$KOTLIN_SRC_ROOT"
361 +
362 +$UNIFFI_BINDGEN generate \
363 + --library "$FIRST_SO" \
364 + --language kotlin \
365 + --out-dir "$KOTLIN_SRC_ROOT" \
366 + --config "$CRATE_DIR/uniffi.toml"
367 +
368 +# Count generated files.
369 +KT_COUNT=$(find "$GENERATED_KT_DIR" -name '*.kt' 2>/dev/null | wc -l | tr -d ' ')
370 +ok "Generated ${BOLD}$KT_COUNT${NC} Kotlin file(s) in $GENERATED_KT_DIR"
371 +
372 +# List them for visibility.
373 +find "$GENERATED_KT_DIR" -name '*.kt' -exec basename {} \; | sort | while read -r f; do
374 + log " • $f"
375 +done
376 +
377 +# ── Step 4: Summary ──────────────────────────────────────────────────────────
378 +
379 +echo ""
380 +ok "════════════════════════════════════════════════════════════════════"
381 +ok " Onde Kotlin library build complete!"
382 +ok "════════════════════════════════════════════════════════════════════"
383 +echo ""
384 +
385 +log "Native libraries:"
386 +for TARGET in "${SELECTED_TARGETS[@]}"; do
387 + ABI="${TARGET_TO_ABI[$TARGET]}"
388 + SO="$JNILIBS_DIR/$ABI/libonde.so"
389 + if [[ -f "$SO" ]]; then
390 + SIZE=$(du -h "$SO" | cut -f1)
391 + ok " $ABI → $SIZE"
392 + else
393 + warn " $ABI → (not built)"
394 + fi
395 +done
396 +
397 +echo ""
398 +log "Kotlin source: $GENERATED_KT_DIR"
399 +log "Android lib: $KOTLIN_LIB_DIR"
400 +echo ""
401 +log "Next steps:"
402 +log " 1. Open ${BOLD}$KOTLIN_PROJECT_DIR${NC} in Android Studio, or"
403 +log " 2. Add the library as a dependency in your app's build.gradle.kts:"
404 +log " ${BOLD}implementation(project(\":onde\"))${NC}"
405 +log " 3. Or publish the AAR: ${BOLD}cd $KOTLIN_PROJECT_DIR && ./gradlew :onde:assembleRelease${NC}"
406 +echo ""
build.rs new
+43
@@ -0,0 +1,43 @@
1 +fn main() {
2 + // ── UniFFI scaffolding ───────────────────────────────────────────────
3 + // Not strictly required when using `uniffi::setup_scaffolding!()` in
4 + // lib.rs (the proc-macro approach), but having it here ensures the
5 + // build-dep on `uniffi` with `features = ["build"]` is exercised and
6 + // keeps compatibility if we ever switch to UDL-based generation.
7 +
8 + // ── tvOS: provide missing ___chkstk_darwin symbol ────────────────────
9 + //
10 + // On macOS and iOS, `___chkstk_darwin` is exported by libSystem as a
11 + // stack probing function. On arm64, the kernel grows the stack via
12 + // guard pages so the probe is effectively a no-op. tvOS does NOT
13 + // export this symbol, but `aws-lc-sys` assembly (pulled in transitively
14 + // via reqwest → rustls → aws-lc-rs) references it unconditionally.
15 + //
16 + // We compile a tiny assembly stub that provides the symbol as a `ret`
17 + // instruction — only when targeting tvOS.
18 + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
19 +
20 + if target_os == "tvos" {
21 + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
22 + let asm_path = std::path::Path::new(&manifest_dir).join("tvos_chkstk.s");
23 +
24 + if asm_path.exists() {
25 + // Use the `cc` crate to assemble the stub into a static library
26 + // that the linker will pick up. If `cc` is not available as a
27 + // build-dependency, fall back to printing a cargo link directive
28 + // that tells the linker to include the object directly.
29 + //
30 + // Since `cc` is already a transitive build-dep (pulled in by
31 + // aws-lc-sys, ring, etc.), we use it directly.
32 + cc::Build::new().file(&asm_path).compile("tvos_chkstk");
33 +
34 + println!("cargo:rerun-if-changed=tvos_chkstk.s");
35 + } else {
36 + println!(
37 + "cargo:warning=tvos_chkstk.s not found at {} — \
38 + ___chkstk_darwin will be unresolved on tvOS",
39 + asm_path.display()
40 + );
41 + }
42 + }
43 +}
crates/onde-wasm/.gitignore new
+8
@@ -0,0 +1,8 @@
1 +# Build artefacts produced by wasm-pack
2 +pkg/
3 +
4 +# Model assets downloaded by build.sh --download-assets
5 +assets/
6 +
7 +# Rust build cache
8 +target/
crates/onde-wasm/Cargo.lock new
+1520
@@ -0,0 +1,1520 @@
1 +# This file is automatically @generated by Cargo.
2 +# It is not intended for manual editing.
3 +version = 4
4 +
5 +[[package]]
6 +name = "ahash"
7 +version = "0.8.12"
8 +source = "registry+https://github.com/rust-lang/crates.io-index"
9 +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
10 +dependencies = [
11 + "cfg-if",
12 + "getrandom 0.3.4",
13 + "once_cell",
14 + "serde",
15 + "version_check",
16 + "zerocopy",
17 +]
18 +
19 +[[package]]
20 +name = "aho-corasick"
21 +version = "1.1.4"
22 +source = "registry+https://github.com/rust-lang/crates.io-index"
23 +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
24 +dependencies = [
25 + "memchr",
26 +]
27 +
28 +[[package]]
29 +name = "allocator-api2"
30 +version = "0.2.21"
31 +source = "registry+https://github.com/rust-lang/crates.io-index"
32 +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
33 +
34 +[[package]]
35 +name = "anyhow"
36 +version = "1.0.102"
37 +source = "registry+https://github.com/rust-lang/crates.io-index"
38 +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
39 +
40 +[[package]]
41 +name = "autocfg"
42 +version = "1.5.0"
43 +source = "registry+https://github.com/rust-lang/crates.io-index"
44 +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
45 +
46 +[[package]]
47 +name = "base64"
48 +version = "0.13.1"
49 +source = "registry+https://github.com/rust-lang/crates.io-index"
50 +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
51 +
52 +[[package]]
53 +name = "bit-set"
54 +version = "0.8.0"
55 +source = "registry+https://github.com/rust-lang/crates.io-index"
56 +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
57 +dependencies = [
58 + "bit-vec",
59 +]
60 +
61 +[[package]]
62 +name = "bit-vec"
63 +version = "0.8.0"
64 +source = "registry+https://github.com/rust-lang/crates.io-index"
65 +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
66 +
67 +[[package]]
68 +name = "bitflags"
69 +version = "2.11.0"
70 +source = "registry+https://github.com/rust-lang/crates.io-index"
71 +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
72 +
73 +[[package]]
74 +name = "bumpalo"
75 +version = "3.20.2"
76 +source = "registry+https://github.com/rust-lang/crates.io-index"
77 +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
78 +
79 +[[package]]
80 +name = "bytemuck"
81 +version = "1.25.0"
82 +source = "registry+https://github.com/rust-lang/crates.io-index"
83 +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
84 +dependencies = [
85 + "bytemuck_derive",
86 +]
87 +
88 +[[package]]
89 +name = "bytemuck_derive"
90 +version = "1.10.2"
91 +source = "registry+https://github.com/rust-lang/crates.io-index"
92 +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
93 +dependencies = [
94 + "proc-macro2",
95 + "quote",
96 + "syn",
97 +]
98 +
99 +[[package]]
100 +name = "byteorder"
101 +version = "1.5.0"
102 +source = "registry+https://github.com/rust-lang/crates.io-index"
103 +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
104 +
105 +[[package]]
106 +name = "candle-core"
107 +version = "0.9.2"
108 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
109 +dependencies = [
110 + "byteorder",
111 + "float8",
112 + "gemm",
113 + "half",
114 + "libm",
115 + "memmap2",
116 + "num-traits",
117 + "num_cpus",
118 + "rand",
119 + "rand_distr",
120 + "rayon",
121 + "safetensors",
122 + "thiserror 2.0.18",
123 + "yoke",
124 + "zip",
125 +]
126 +
127 +[[package]]
128 +name = "candle-nn"
129 +version = "0.9.2"
130 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
131 +dependencies = [
132 + "candle-core",
133 + "half",
134 + "libc",
135 + "num-traits",
136 + "rayon",
137 + "safetensors",
138 + "serde",
139 + "thiserror 2.0.18",
140 +]
141 +
142 +[[package]]
143 +name = "candle-transformers"
144 +version = "0.9.2"
145 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
146 +dependencies = [
147 + "byteorder",
148 + "candle-core",
149 + "candle-nn",
150 + "fancy-regex 0.17.0",
151 + "num-traits",
152 + "rand",
153 + "rayon",
154 + "serde",
155 + "serde_json",
156 + "serde_plain",
157 + "tracing",
158 +]
159 +
160 +[[package]]
161 +name = "castaway"
162 +version = "0.2.4"
163 +source = "registry+https://github.com/rust-lang/crates.io-index"
164 +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
165 +dependencies = [
166 + "rustversion",
167 +]
168 +
169 +[[package]]
170 +name = "cfg-if"
171 +version = "1.0.4"
172 +source = "registry+https://github.com/rust-lang/crates.io-index"
173 +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
174 +
175 +[[package]]
176 +name = "compact_str"
177 +version = "0.9.0"
178 +source = "registry+https://github.com/rust-lang/crates.io-index"
179 +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
180 +dependencies = [
181 + "castaway",
182 + "cfg-if",
183 + "itoa",
184 + "rustversion",
185 + "ryu",
186 + "serde",
187 + "static_assertions",
188 +]
189 +
190 +[[package]]
191 +name = "console_error_panic_hook"
192 +version = "0.1.7"
193 +source = "registry+https://github.com/rust-lang/crates.io-index"
194 +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
195 +dependencies = [
196 + "cfg-if",
197 + "wasm-bindgen",
198 +]
199 +
200 +[[package]]
201 +name = "crc32fast"
202 +version = "1.5.0"
203 +source = "registry+https://github.com/rust-lang/crates.io-index"
204 +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
205 +dependencies = [
206 + "cfg-if",
207 +]
208 +
209 +[[package]]
210 +name = "crossbeam-deque"
211 +version = "0.8.6"
212 +source = "registry+https://github.com/rust-lang/crates.io-index"
213 +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
214 +dependencies = [
215 + "crossbeam-epoch",
216 + "crossbeam-utils",
217 +]
218 +
219 +[[package]]
220 +name = "crossbeam-epoch"
221 +version = "0.9.18"
222 +source = "registry+https://github.com/rust-lang/crates.io-index"
223 +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
224 +dependencies = [
225 + "crossbeam-utils",
226 +]
227 +
228 +[[package]]
229 +name = "crossbeam-utils"
230 +version = "0.8.21"
231 +source = "registry+https://github.com/rust-lang/crates.io-index"
232 +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
233 +
234 +[[package]]
235 +name = "crunchy"
236 +version = "0.2.4"
237 +source = "registry+https://github.com/rust-lang/crates.io-index"
238 +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
239 +
240 +[[package]]
241 +name = "darling"
242 +version = "0.20.11"
243 +source = "registry+https://github.com/rust-lang/crates.io-index"
244 +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
245 +dependencies = [
246 + "darling_core",
247 + "darling_macro",
248 +]
249 +
250 +[[package]]
251 +name = "darling_core"
252 +version = "0.20.11"
253 +source = "registry+https://github.com/rust-lang/crates.io-index"
254 +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
255 +dependencies = [
256 + "fnv",
257 + "ident_case",
258 + "proc-macro2",
259 + "quote",
260 + "strsim",
261 + "syn",
262 +]
263 +
264 +[[package]]
265 +name = "darling_macro"
266 +version = "0.20.11"
267 +source = "registry+https://github.com/rust-lang/crates.io-index"
268 +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
269 +dependencies = [
270 + "darling_core",
271 + "quote",
272 + "syn",
273 +]
274 +
275 +[[package]]
276 +name = "dary_heap"
277 +version = "0.3.8"
278 +source = "registry+https://github.com/rust-lang/crates.io-index"
279 +checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04"
280 +dependencies = [
281 + "serde",
282 +]
283 +
284 +[[package]]
285 +name = "derive_builder"
286 +version = "0.20.2"
287 +source = "registry+https://github.com/rust-lang/crates.io-index"
288 +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
289 +dependencies = [
290 + "derive_builder_macro",
291 +]
292 +
293 +[[package]]
294 +name = "derive_builder_core"
295 +version = "0.20.2"
296 +source = "registry+https://github.com/rust-lang/crates.io-index"
297 +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
298 +dependencies = [
299 + "darling",
300 + "proc-macro2",
301 + "quote",
302 + "syn",
303 +]
304 +
305 +[[package]]
306 +name = "derive_builder_macro"
307 +version = "0.20.2"
308 +source = "registry+https://github.com/rust-lang/crates.io-index"
309 +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
310 +dependencies = [
311 + "derive_builder_core",
312 + "syn",
313 +]
314 +
315 +[[package]]
316 +name = "dyn-stack"
317 +version = "0.13.2"
318 +source = "registry+https://github.com/rust-lang/crates.io-index"
319 +checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8"
320 +dependencies = [
321 + "bytemuck",
322 + "dyn-stack-macros",
323 +]
324 +
325 +[[package]]
326 +name = "dyn-stack-macros"
327 +version = "0.1.3"
328 +source = "registry+https://github.com/rust-lang/crates.io-index"
329 +checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9"
330 +
331 +[[package]]
332 +name = "either"
333 +version = "1.15.0"
334 +source = "registry+https://github.com/rust-lang/crates.io-index"
335 +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
336 +
337 +[[package]]
338 +name = "enum-as-inner"
339 +version = "0.6.1"
340 +source = "registry+https://github.com/rust-lang/crates.io-index"
341 +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
342 +dependencies = [
343 + "heck",
344 + "proc-macro2",
345 + "quote",
346 + "syn",
347 +]
348 +
349 +[[package]]
350 +name = "equivalent"
351 +version = "1.0.2"
352 +source = "registry+https://github.com/rust-lang/crates.io-index"
353 +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
354 +
355 +[[package]]
356 +name = "esaxx-rs"
357 +version = "0.1.10"
358 +source = "registry+https://github.com/rust-lang/crates.io-index"
359 +checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6"
360 +
361 +[[package]]
362 +name = "fancy-regex"
363 +version = "0.14.0"
364 +source = "registry+https://github.com/rust-lang/crates.io-index"
365 +checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"
366 +dependencies = [
367 + "bit-set",
368 + "regex-automata",
369 + "regex-syntax",
370 +]
371 +
372 +[[package]]
373 +name = "fancy-regex"
374 +version = "0.17.0"
375 +source = "registry+https://github.com/rust-lang/crates.io-index"
376 +checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
377 +dependencies = [
378 + "bit-set",
379 + "regex-automata",
380 + "regex-syntax",
381 +]
382 +
383 +[[package]]
384 +name = "float8"
385 +version = "0.7.0"
386 +source = "registry+https://github.com/rust-lang/crates.io-index"
387 +checksum = "c2d1f04709a8ac06e8e8042875a3c466cc4832d3c1a18dbcb9dba3c6e83046bc"
388 +dependencies = [
389 + "half",
390 + "num-traits",
391 + "rand",
392 + "rand_distr",
393 +]
394 +
395 +[[package]]
396 +name = "fnv"
397 +version = "1.0.7"
398 +source = "registry+https://github.com/rust-lang/crates.io-index"
399 +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
400 +
401 +[[package]]
402 +name = "foldhash"
403 +version = "0.2.0"
404 +source = "registry+https://github.com/rust-lang/crates.io-index"
405 +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
406 +
407 +[[package]]
408 +name = "futures-core"
409 +version = "0.3.32"
410 +source = "registry+https://github.com/rust-lang/crates.io-index"
411 +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
412 +
413 +[[package]]
414 +name = "futures-task"
415 +version = "0.3.32"
416 +source = "registry+https://github.com/rust-lang/crates.io-index"
417 +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
418 +
419 +[[package]]
420 +name = "futures-util"
421 +version = "0.3.32"
422 +source = "registry+https://github.com/rust-lang/crates.io-index"
423 +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
424 +dependencies = [
425 + "futures-core",
426 + "futures-task",
427 + "pin-project-lite",
428 + "slab",
429 +]
430 +
431 +[[package]]
432 +name = "gemm"
433 +version = "0.19.0"
434 +source = "registry+https://github.com/rust-lang/crates.io-index"
435 +checksum = "aa0673db364b12263d103b68337a68fbecc541d6f6b61ba72fe438654709eacb"
436 +dependencies = [
437 + "dyn-stack",
438 + "gemm-c32",
439 + "gemm-c64",
440 + "gemm-common",
441 + "gemm-f16",
442 + "gemm-f32",
443 + "gemm-f64",
444 + "num-complex",
445 + "num-traits",
446 + "paste",
447 + "raw-cpuid",
448 + "seq-macro",
449 +]
450 +
451 +[[package]]
452 +name = "gemm-c32"
453 +version = "0.19.0"
454 +source = "registry+https://github.com/rust-lang/crates.io-index"
455 +checksum = "086936dbdcb99e37aad81d320f98f670e53c1e55a98bee70573e83f95beb128c"
456 +dependencies = [
457 + "dyn-stack",
458 + "gemm-common",
459 + "num-complex",
460 + "num-traits",
461 + "paste",
462 + "raw-cpuid",
463 + "seq-macro",
464 +]
465 +
466 +[[package]]
467 +name = "gemm-c64"
468 +version = "0.19.0"
469 +source = "registry+https://github.com/rust-lang/crates.io-index"
470 +checksum = "20c8aeeeec425959bda4d9827664029ba1501a90a0d1e6228e48bef741db3a3f"
471 +dependencies = [
472 + "dyn-stack",
473 + "gemm-common",
474 + "num-complex",
475 + "num-traits",
476 + "paste",
477 + "raw-cpuid",
478 + "seq-macro",
479 +]
480 +
481 +[[package]]
482 +name = "gemm-common"
483 +version = "0.19.0"
484 +source = "registry+https://github.com/rust-lang/crates.io-index"
485 +checksum = "88027625910cc9b1085aaaa1c4bc46bb3a36aad323452b33c25b5e4e7c8e2a3e"
486 +dependencies = [
487 + "bytemuck",
488 + "dyn-stack",
489 + "half",
490 + "libm",
491 + "num-complex",
492 + "num-traits",
493 + "once_cell",
494 + "paste",
495 + "pulp",
496 + "raw-cpuid",
497 + "rayon",
498 + "seq-macro",
499 + "sysctl",
500 +]
501 +
502 +[[package]]
503 +name = "gemm-f16"
504 +version = "0.19.0"
505 +source = "registry+https://github.com/rust-lang/crates.io-index"
506 +checksum = "e3df7a55202e6cd6739d82ae3399c8e0c7e1402859b30e4cb780e61525d9486e"
507 +dependencies = [
508 + "dyn-stack",
509 + "gemm-common",
510 + "gemm-f32",
511 + "half",
512 + "num-complex",
513 + "num-traits",
514 + "paste",
515 + "raw-cpuid",
516 + "rayon",
517 + "seq-macro",
518 +]
519 +
520 +[[package]]
521 +name = "gemm-f32"
522 +version = "0.19.0"
523 +source = "registry+https://github.com/rust-lang/crates.io-index"
524 +checksum = "02e0b8c9da1fbec6e3e3ab2ce6bc259ef18eb5f6f0d3e4edf54b75f9fd41a81c"
525 +dependencies = [
526 + "dyn-stack",
527 + "gemm-common",
528 + "num-complex",
529 + "num-traits",
530 + "paste",
531 + "raw-cpuid",
532 + "seq-macro",
533 +]
534 +
535 +[[package]]
536 +name = "gemm-f64"
537 +version = "0.19.0"
538 +source = "registry+https://github.com/rust-lang/crates.io-index"
539 +checksum = "056131e8f2a521bfab322f804ccd652520c79700d81209e9d9275bbdecaadc6a"
540 +dependencies = [
541 + "dyn-stack",
542 + "gemm-common",
543 + "num-complex",
544 + "num-traits",
545 + "paste",
546 + "raw-cpuid",
547 + "seq-macro",
548 +]
549 +
550 +[[package]]
551 +name = "getrandom"
552 +version = "0.2.17"
553 +source = "registry+https://github.com/rust-lang/crates.io-index"
554 +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
555 +dependencies = [
556 + "cfg-if",
557 + "js-sys",
558 + "libc",
559 + "wasi",
560 + "wasm-bindgen",
561 +]
562 +
563 +[[package]]
564 +name = "getrandom"
565 +version = "0.3.4"
566 +source = "registry+https://github.com/rust-lang/crates.io-index"
567 +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
568 +dependencies = [
569 + "cfg-if",
570 + "js-sys",
571 + "libc",
572 + "r-efi",
573 + "wasip2",
574 + "wasm-bindgen",
575 +]
576 +
577 +[[package]]
578 +name = "half"
579 +version = "2.7.1"
580 +source = "registry+https://github.com/rust-lang/crates.io-index"
581 +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
582 +dependencies = [
583 + "bytemuck",
584 + "cfg-if",
585 + "crunchy",
586 + "num-traits",
587 + "rand",
588 + "rand_distr",
589 + "zerocopy",
590 +]
591 +
592 +[[package]]
593 +name = "hashbrown"
594 +version = "0.16.1"
595 +source = "registry+https://github.com/rust-lang/crates.io-index"
596 +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
597 +dependencies = [
598 + "allocator-api2",
599 + "equivalent",
600 + "foldhash",
601 + "serde",
602 + "serde_core",
603 +]
604 +
605 +[[package]]
606 +name = "heck"
607 +version = "0.5.0"
608 +source = "registry+https://github.com/rust-lang/crates.io-index"
609 +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
610 +
611 +[[package]]
612 +name = "hermit-abi"
613 +version = "0.5.2"
614 +source = "registry+https://github.com/rust-lang/crates.io-index"
615 +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
616 +
617 +[[package]]
618 +name = "hound"
619 +version = "3.5.1"
620 +source = "registry+https://github.com/rust-lang/crates.io-index"
621 +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f"
622 +
623 +[[package]]
624 +name = "ident_case"
625 +version = "1.0.1"
626 +source = "registry+https://github.com/rust-lang/crates.io-index"
627 +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
628 +
629 +[[package]]
630 +name = "indexmap"
631 +version = "2.13.0"
632 +source = "registry+https://github.com/rust-lang/crates.io-index"
633 +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
634 +dependencies = [
635 + "equivalent",
636 + "hashbrown",
637 +]
638 +
639 +[[package]]
640 +name = "itertools"
641 +version = "0.14.0"
642 +source = "registry+https://github.com/rust-lang/crates.io-index"
643 +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
644 +dependencies = [
645 + "either",
646 +]
647 +
648 +[[package]]
649 +name = "itoa"
650 +version = "1.0.17"
651 +source = "registry+https://github.com/rust-lang/crates.io-index"
652 +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
653 +
654 +[[package]]
655 +name = "js-sys"
656 +version = "0.3.91"
657 +source = "registry+https://github.com/rust-lang/crates.io-index"
658 +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
659 +dependencies = [
660 + "once_cell",
661 + "wasm-bindgen",
662 +]
663 +
664 +[[package]]
665 +name = "libc"
666 +version = "0.2.183"
667 +source = "registry+https://github.com/rust-lang/crates.io-index"
668 +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
669 +
670 +[[package]]
671 +name = "libm"
672 +version = "0.2.16"
673 +source = "registry+https://github.com/rust-lang/crates.io-index"
674 +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
675 +
676 +[[package]]
677 +name = "log"
678 +version = "0.4.29"
679 +source = "registry+https://github.com/rust-lang/crates.io-index"
680 +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
681 +
682 +[[package]]
683 +name = "macro_rules_attribute"
684 +version = "0.2.2"
685 +source = "registry+https://github.com/rust-lang/crates.io-index"
686 +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520"
687 +dependencies = [
688 + "macro_rules_attribute-proc_macro",
689 + "paste",
690 +]
691 +
692 +[[package]]
693 +name = "macro_rules_attribute-proc_macro"
694 +version = "0.2.2"
695 +source = "registry+https://github.com/rust-lang/crates.io-index"
696 +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
697 +
698 +[[package]]
699 +name = "memchr"
700 +version = "2.8.0"
701 +source = "registry+https://github.com/rust-lang/crates.io-index"
702 +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
703 +
704 +[[package]]
705 +name = "memmap2"
706 +version = "0.9.10"
707 +source = "registry+https://github.com/rust-lang/crates.io-index"
708 +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
709 +dependencies = [
710 + "libc",
711 + "stable_deref_trait",
712 +]
713 +
714 +[[package]]
715 +name = "minimal-lexical"
716 +version = "0.2.1"
717 +source = "registry+https://github.com/rust-lang/crates.io-index"
718 +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
719 +
720 +[[package]]
721 +name = "monostate"
722 +version = "0.1.18"
723 +source = "registry+https://github.com/rust-lang/crates.io-index"
724 +checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67"
725 +dependencies = [
726 + "monostate-impl",
727 + "serde",
728 + "serde_core",
729 +]
730 +
731 +[[package]]
732 +name = "monostate-impl"
733 +version = "0.1.18"
734 +source = "registry+https://github.com/rust-lang/crates.io-index"
735 +checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9"
736 +dependencies = [
737 + "proc-macro2",
738 + "quote",
739 + "syn",
740 +]
741 +
742 +[[package]]
743 +name = "nom"
744 +version = "7.1.3"
745 +source = "registry+https://github.com/rust-lang/crates.io-index"
746 +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
747 +dependencies = [
748 + "memchr",
749 + "minimal-lexical",
750 +]
751 +
752 +[[package]]
753 +name = "num-complex"
754 +version = "0.4.6"
755 +source = "registry+https://github.com/rust-lang/crates.io-index"
756 +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
757 +dependencies = [
758 + "bytemuck",
759 + "num-traits",
760 +]
761 +
762 +[[package]]
763 +name = "num-traits"
764 +version = "0.2.19"
765 +source = "registry+https://github.com/rust-lang/crates.io-index"
766 +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
767 +dependencies = [
768 + "autocfg",
769 + "libm",
770 +]
771 +
772 +[[package]]
773 +name = "num_cpus"
774 +version = "1.17.0"
775 +source = "registry+https://github.com/rust-lang/crates.io-index"
776 +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
777 +dependencies = [
778 + "hermit-abi",
779 + "libc",
780 +]
781 +
782 +[[package]]
783 +name = "once_cell"
784 +version = "1.21.4"
785 +source = "registry+https://github.com/rust-lang/crates.io-index"
786 +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
787 +
788 +[[package]]
789 +name = "onde-wasm"
790 +version = "0.1.0"
791 +dependencies = [
792 + "anyhow",
793 + "candle-core",
794 + "candle-nn",
795 + "candle-transformers",
796 + "console_error_panic_hook",
797 + "getrandom 0.2.17",
798 + "hound",
799 + "js-sys",
800 + "log",
801 + "num-traits",
802 + "rand",
803 + "safetensors",
804 + "serde",
805 + "serde_json",
806 + "tokenizers",
807 + "wasm-bindgen",
808 + "wasm-bindgen-futures",
809 + "wasm-logger",
810 +]
811 +
812 +[[package]]
813 +name = "paste"
814 +version = "1.0.15"
815 +source = "registry+https://github.com/rust-lang/crates.io-index"
816 +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
817 +
818 +[[package]]
819 +name = "pin-project-lite"
820 +version = "0.2.17"
821 +source = "registry+https://github.com/rust-lang/crates.io-index"
822 +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
823 +
824 +[[package]]
825 +name = "ppv-lite86"
826 +version = "0.2.21"
827 +source = "registry+https://github.com/rust-lang/crates.io-index"
828 +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
829 +dependencies = [
830 + "zerocopy",
831 +]
832 +
833 +[[package]]
834 +name = "proc-macro2"
835 +version = "1.0.106"
836 +source = "registry+https://github.com/rust-lang/crates.io-index"
837 +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
838 +dependencies = [
839 + "unicode-ident",
840 +]
841 +
842 +[[package]]
843 +name = "pulp"
844 +version = "0.22.2"
845 +source = "registry+https://github.com/rust-lang/crates.io-index"
846 +checksum = "2e205bb30d5b916c55e584c22201771bcf2bad9aabd5d4127f38387140c38632"
847 +dependencies = [
848 + "bytemuck",
849 + "cfg-if",
850 + "libm",
851 + "num-complex",
852 + "paste",
853 + "pulp-wasm-simd-flag",
854 + "raw-cpuid",
855 + "reborrow",
856 + "version_check",
857 +]
858 +
859 +[[package]]
860 +name = "pulp-wasm-simd-flag"
861 +version = "0.1.0"
862 +source = "registry+https://github.com/rust-lang/crates.io-index"
863 +checksum = "40e24eee682d89fb193496edf918a7f407d30175b2e785fe057e4392dfd182e0"
864 +
865 +[[package]]
866 +name = "quote"
867 +version = "1.0.45"
868 +source = "registry+https://github.com/rust-lang/crates.io-index"
869 +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
870 +dependencies = [
871 + "proc-macro2",
872 +]
873 +
874 +[[package]]
875 +name = "r-efi"
876 +version = "5.3.0"
877 +source = "registry+https://github.com/rust-lang/crates.io-index"
878 +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
879 +
880 +[[package]]
881 +name = "rand"
882 +version = "0.9.2"
883 +source = "registry+https://github.com/rust-lang/crates.io-index"
884 +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
885 +dependencies = [
886 + "rand_chacha",
887 + "rand_core",
888 +]
889 +
890 +[[package]]
891 +name = "rand_chacha"
892 +version = "0.9.0"
893 +source = "registry+https://github.com/rust-lang/crates.io-index"
894 +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
895 +dependencies = [
896 + "ppv-lite86",
897 + "rand_core",
898 +]
899 +
900 +[[package]]
901 +name = "rand_core"
902 +version = "0.9.5"
903 +source = "registry+https://github.com/rust-lang/crates.io-index"
904 +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
905 +dependencies = [
906 + "getrandom 0.3.4",
907 +]
908 +
909 +[[package]]
910 +name = "rand_distr"
911 +version = "0.5.1"
912 +source = "registry+https://github.com/rust-lang/crates.io-index"
913 +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463"
914 +dependencies = [
915 + "num-traits",
916 + "rand",
917 +]
918 +
919 +[[package]]
920 +name = "raw-cpuid"
921 +version = "11.6.0"
922 +source = "registry+https://github.com/rust-lang/crates.io-index"
923 +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
924 +dependencies = [
925 + "bitflags",
926 +]
927 +
928 +[[package]]
929 +name = "rayon"
930 +version = "1.11.0"
931 +source = "registry+https://github.com/rust-lang/crates.io-index"
932 +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
933 +dependencies = [
934 + "either",
935 + "rayon-core",
936 +]
937 +
938 +[[package]]
939 +name = "rayon-cond"
940 +version = "0.4.0"
941 +source = "registry+https://github.com/rust-lang/crates.io-index"
942 +checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f"
943 +dependencies = [
944 + "either",
945 + "itertools",
946 + "rayon",
947 +]
948 +
949 +[[package]]
950 +name = "rayon-core"
951 +version = "1.13.0"
952 +source = "registry+https://github.com/rust-lang/crates.io-index"
953 +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
954 +dependencies = [
955 + "crossbeam-deque",
956 + "crossbeam-utils",
957 +]
958 +
959 +[[package]]
960 +name = "reborrow"
961 +version = "0.5.5"
962 +source = "registry+https://github.com/rust-lang/crates.io-index"
963 +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430"
964 +
965 +[[package]]
966 +name = "regex"
967 +version = "1.12.3"
968 +source = "registry+https://github.com/rust-lang/crates.io-index"
969 +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
970 +dependencies = [
971 + "aho-corasick",
972 + "memchr",
973 + "regex-automata",
974 + "regex-syntax",
975 +]
976 +
977 +[[package]]
978 +name = "regex-automata"
979 +version = "0.4.14"
980 +source = "registry+https://github.com/rust-lang/crates.io-index"
981 +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
982 +dependencies = [
983 + "aho-corasick",
984 + "memchr",
985 + "regex-syntax",
986 +]
987 +
988 +[[package]]
989 +name = "regex-syntax"
990 +version = "0.8.10"
991 +source = "registry+https://github.com/rust-lang/crates.io-index"
992 +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
993 +
994 +[[package]]
995 +name = "rustversion"
996 +version = "1.0.22"
997 +source = "registry+https://github.com/rust-lang/crates.io-index"
998 +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
999 +
1000 +[[package]]
1001 +name = "ryu"
1002 +version = "1.0.23"
1003 +source = "registry+https://github.com/rust-lang/crates.io-index"
1004 +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
1005 +
1006 +[[package]]
1007 +name = "safetensors"
1008 +version = "0.7.0"
1009 +source = "registry+https://github.com/rust-lang/crates.io-index"
1010 +checksum = "675656c1eabb620b921efea4f9199f97fc86e36dd6ffd1fbbe48d0f59a4987f5"
1011 +dependencies = [
1012 + "hashbrown",
1013 + "serde",
1014 + "serde_json",
1015 +]
1016 +
1017 +[[package]]
1018 +name = "same-file"
1019 +version = "1.0.6"
1020 +source = "registry+https://github.com/rust-lang/crates.io-index"
1021 +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
1022 +dependencies = [
1023 + "winapi-util",
1024 +]
1025 +
1026 +[[package]]
1027 +name = "seq-macro"
1028 +version = "0.3.6"
1029 +source = "registry+https://github.com/rust-lang/crates.io-index"
1030 +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
1031 +
1032 +[[package]]
1033 +name = "serde"
1034 +version = "1.0.228"
1035 +source = "registry+https://github.com/rust-lang/crates.io-index"
1036 +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
1037 +dependencies = [
1038 + "serde_core",
1039 + "serde_derive",
1040 +]
1041 +
1042 +[[package]]
1043 +name = "serde_core"
1044 +version = "1.0.228"
1045 +source = "registry+https://github.com/rust-lang/crates.io-index"
1046 +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
1047 +dependencies = [
1048 + "serde_derive",
1049 +]
1050 +
1051 +[[package]]
1052 +name = "serde_derive"
1053 +version = "1.0.228"
1054 +source = "registry+https://github.com/rust-lang/crates.io-index"
1055 +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
1056 +dependencies = [
1057 + "proc-macro2",
1058 + "quote",
1059 + "syn",
1060 +]
1061 +
1062 +[[package]]
1063 +name = "serde_json"
1064 +version = "1.0.149"
1065 +source = "registry+https://github.com/rust-lang/crates.io-index"
1066 +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
1067 +dependencies = [
1068 + "itoa",
1069 + "memchr",
1070 + "serde",
1071 + "serde_core",
1072 + "zmij",
1073 +]
1074 +
1075 +[[package]]
1076 +name = "serde_plain"
1077 +version = "1.0.2"
1078 +source = "registry+https://github.com/rust-lang/crates.io-index"
1079 +checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50"
1080 +dependencies = [
1081 + "serde",
1082 +]
1083 +
1084 +[[package]]
1085 +name = "slab"
1086 +version = "0.4.12"
1087 +source = "registry+https://github.com/rust-lang/crates.io-index"
1088 +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
1089 +
1090 +[[package]]
1091 +name = "smallvec"
1092 +version = "1.15.1"
1093 +source = "registry+https://github.com/rust-lang/crates.io-index"
1094 +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
1095 +
1096 +[[package]]
1097 +name = "spm_precompiled"
1098 +version = "0.1.4"
1099 +source = "registry+https://github.com/rust-lang/crates.io-index"
1100 +checksum = "5851699c4033c63636f7ea4cf7b7c1f1bf06d0cc03cfb42e711de5a5c46cf326"
1101 +dependencies = [
1102 + "base64",
1103 + "nom",
1104 + "serde",
1105 + "unicode-segmentation",
1106 +]
1107 +
1108 +[[package]]
1109 +name = "stable_deref_trait"
1110 +version = "1.2.1"
1111 +source = "registry+https://github.com/rust-lang/crates.io-index"
1112 +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
1113 +
1114 +[[package]]
1115 +name = "static_assertions"
1116 +version = "1.1.0"
1117 +source = "registry+https://github.com/rust-lang/crates.io-index"
1118 +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
1119 +
1120 +[[package]]
1121 +name = "strsim"
1122 +version = "0.11.1"
1123 +source = "registry+https://github.com/rust-lang/crates.io-index"
1124 +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
1125 +
1126 +[[package]]
1127 +name = "syn"
1128 +version = "2.0.117"
1129 +source = "registry+https://github.com/rust-lang/crates.io-index"
1130 +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
1131 +dependencies = [
1132 + "proc-macro2",
1133 + "quote",
1134 + "unicode-ident",
1135 +]
1136 +
1137 +[[package]]
1138 +name = "synstructure"
1139 +version = "0.13.2"
1140 +source = "registry+https://github.com/rust-lang/crates.io-index"
1141 +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
1142 +dependencies = [
1143 + "proc-macro2",
1144 + "quote",
1145 + "syn",
1146 +]
1147 +
1148 +[[package]]
1149 +name = "sysctl"
1150 +version = "0.6.0"
1151 +source = "registry+https://github.com/rust-lang/crates.io-index"
1152 +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc"
1153 +dependencies = [
1154 + "bitflags",
1155 + "byteorder",
1156 + "enum-as-inner",
1157 + "libc",
1158 + "thiserror 1.0.69",
1159 + "walkdir",
1160 +]
1161 +
1162 +[[package]]
1163 +name = "thiserror"
1164 +version = "1.0.69"
1165 +source = "registry+https://github.com/rust-lang/crates.io-index"
1166 +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
1167 +dependencies = [
1168 + "thiserror-impl 1.0.69",
1169 +]
1170 +
1171 +[[package]]
1172 +name = "thiserror"
1173 +version = "2.0.18"
1174 +source = "registry+https://github.com/rust-lang/crates.io-index"
1175 +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
1176 +dependencies = [
1177 + "thiserror-impl 2.0.18",
1178 +]
1179 +
1180 +[[package]]
1181 +name = "thiserror-impl"
1182 +version = "1.0.69"
1183 +source = "registry+https://github.com/rust-lang/crates.io-index"
1184 +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
1185 +dependencies = [
1186 + "proc-macro2",
1187 + "quote",
1188 + "syn",
1189 +]
1190 +
1191 +[[package]]
1192 +name = "thiserror-impl"
1193 +version = "2.0.18"
1194 +source = "registry+https://github.com/rust-lang/crates.io-index"
1195 +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
1196 +dependencies = [
1197 + "proc-macro2",
1198 + "quote",
1199 + "syn",
1200 +]
1201 +
1202 +[[package]]
1203 +name = "tokenizers"
1204 +version = "0.22.2"
1205 +source = "registry+https://github.com/rust-lang/crates.io-index"
1206 +checksum = "b238e22d44a15349529690fb07bd645cf58149a1b1e44d6cb5bd1641ff1a6223"
1207 +dependencies = [
1208 + "ahash",
1209 + "aho-corasick",
1210 + "compact_str",
1211 + "dary_heap",
1212 + "derive_builder",
1213 + "esaxx-rs",
1214 + "fancy-regex 0.14.0",
1215 + "getrandom 0.3.4",
1216 + "itertools",
1217 + "log",
1218 + "macro_rules_attribute",
1219 + "monostate",
1220 + "paste",
1221 + "rand",
1222 + "rayon",
1223 + "rayon-cond",
1224 + "regex",
1225 + "regex-syntax",
1226 + "serde",
1227 + "serde_json",
1228 + "spm_precompiled",
1229 + "thiserror 2.0.18",
1230 + "unicode-normalization-alignments",
1231 + "unicode-segmentation",
1232 + "unicode_categories",
1233 +]
1234 +
1235 +[[package]]
1236 +name = "tracing"
1237 +version = "0.1.44"
1238 +source = "registry+https://github.com/rust-lang/crates.io-index"
1239 +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
1240 +dependencies = [
1241 + "pin-project-lite",
1242 + "tracing-attributes",
1243 + "tracing-core",
1244 +]
1245 +
1246 +[[package]]
1247 +name = "tracing-attributes"
1248 +version = "0.1.31"
1249 +source = "registry+https://github.com/rust-lang/crates.io-index"
1250 +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
1251 +dependencies = [
1252 + "proc-macro2",
1253 + "quote",
1254 + "syn",
1255 +]
1256 +
1257 +[[package]]
1258 +name = "tracing-core"
1259 +version = "0.1.36"
1260 +source = "registry+https://github.com/rust-lang/crates.io-index"
1261 +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
1262 +dependencies = [
1263 + "once_cell",
1264 +]
1265 +
1266 +[[package]]
1267 +name = "typed-path"
1268 +version = "0.12.3"
1269 +source = "registry+https://github.com/rust-lang/crates.io-index"
1270 +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e"
1271 +
1272 +[[package]]
1273 +name = "unicode-ident"
1274 +version = "1.0.24"
1275 +source = "registry+https://github.com/rust-lang/crates.io-index"
1276 +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
1277 +
1278 +[[package]]
1279 +name = "unicode-normalization-alignments"
1280 +version = "0.1.12"
1281 +source = "registry+https://github.com/rust-lang/crates.io-index"
1282 +checksum = "43f613e4fa046e69818dd287fdc4bc78175ff20331479dab6e1b0f98d57062de"
1283 +dependencies = [
1284 + "smallvec",
1285 +]
1286 +
1287 +[[package]]
1288 +name = "unicode-segmentation"
1289 +version = "1.12.0"
1290 +source = "registry+https://github.com/rust-lang/crates.io-index"
1291 +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
1292 +
1293 +[[package]]
1294 +name = "unicode_categories"
1295 +version = "0.1.1"
1296 +source = "registry+https://github.com/rust-lang/crates.io-index"
1297 +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
1298 +
1299 +[[package]]
1300 +name = "version_check"
1301 +version = "0.9.5"
1302 +source = "registry+https://github.com/rust-lang/crates.io-index"
1303 +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1304 +
1305 +[[package]]
1306 +name = "walkdir"
1307 +version = "2.5.0"
1308 +source = "registry+https://github.com/rust-lang/crates.io-index"
1309 +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
1310 +dependencies = [
1311 + "same-file",
1312 + "winapi-util",
1313 +]
1314 +
1315 +[[package]]
1316 +name = "wasi"
1317 +version = "0.11.1+wasi-snapshot-preview1"
1318 +source = "registry+https://github.com/rust-lang/crates.io-index"
1319 +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
1320 +
1321 +[[package]]
1322 +name = "wasip2"
1323 +version = "1.0.2+wasi-0.2.9"
1324 +source = "registry+https://github.com/rust-lang/crates.io-index"
1325 +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
1326 +dependencies = [
1327 + "wit-bindgen",
1328 +]
1329 +
1330 +[[package]]
1331 +name = "wasm-bindgen"
1332 +version = "0.2.114"
1333 +source = "registry+https://github.com/rust-lang/crates.io-index"
1334 +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
1335 +dependencies = [
1336 + "cfg-if",
1337 + "once_cell",
1338 + "rustversion",
1339 + "wasm-bindgen-macro",
1340 + "wasm-bindgen-shared",
1341 +]
1342 +
1343 +[[package]]
1344 +name = "wasm-bindgen-futures"
1345 +version = "0.4.64"
1346 +source = "registry+https://github.com/rust-lang/crates.io-index"
1347 +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8"
1348 +dependencies = [
1349 + "cfg-if",
1350 + "futures-util",
1351 + "js-sys",
1352 + "once_cell",
1353 + "wasm-bindgen",
1354 + "web-sys",
1355 +]
1356 +
1357 +[[package]]
1358 +name = "wasm-bindgen-macro"
1359 +version = "0.2.114"
1360 +source = "registry+https://github.com/rust-lang/crates.io-index"
1361 +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
1362 +dependencies = [
1363 + "quote",
1364 + "wasm-bindgen-macro-support",
1365 +]
1366 +
1367 +[[package]]
1368 +name = "wasm-bindgen-macro-support"
1369 +version = "0.2.114"
1370 +source = "registry+https://github.com/rust-lang/crates.io-index"
1371 +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
1372 +dependencies = [
1373 + "bumpalo",
1374 + "proc-macro2",
1375 + "quote",
1376 + "syn",
1377 + "wasm-bindgen-shared",
1378 +]
1379 +
1380 +[[package]]
1381 +name = "wasm-bindgen-shared"
1382 +version = "0.2.114"
1383 +source = "registry+https://github.com/rust-lang/crates.io-index"
1384 +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
1385 +dependencies = [
1386 + "unicode-ident",
1387 +]
1388 +
1389 +[[package]]
1390 +name = "wasm-logger"
1391 +version = "0.2.0"
1392 +source = "registry+https://github.com/rust-lang/crates.io-index"
1393 +checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718"
1394 +dependencies = [
1395 + "log",
1396 + "wasm-bindgen",
1397 + "web-sys",
1398 +]
1399 +
1400 +[[package]]
1401 +name = "web-sys"
1402 +version = "0.3.91"
1403 +source = "registry+https://github.com/rust-lang/crates.io-index"
1404 +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9"
1405 +dependencies = [
1406 + "js-sys",
1407 + "wasm-bindgen",
1408 +]
1409 +
1410 +[[package]]
1411 +name = "winapi-util"
1412 +version = "0.1.11"
1413 +source = "registry+https://github.com/rust-lang/crates.io-index"
1414 +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
1415 +dependencies = [
1416 + "windows-sys",
1417 +]
1418 +
1419 +[[package]]
1420 +name = "windows-link"
1421 +version = "0.2.1"
1422 +source = "registry+https://github.com/rust-lang/crates.io-index"
1423 +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
1424 +
1425 +[[package]]
1426 +name = "windows-sys"
1427 +version = "0.61.2"
1428 +source = "registry+https://github.com/rust-lang/crates.io-index"
1429 +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
1430 +dependencies = [
1431 + "windows-link",
1432 +]
1433 +
1434 +[[package]]
1435 +name = "wit-bindgen"
1436 +version = "0.51.0"
1437 +source = "registry+https://github.com/rust-lang/crates.io-index"
1438 +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
1439 +
1440 +[[package]]
1441 +name = "yoke"
1442 +version = "0.8.1"
1443 +source = "registry+https://github.com/rust-lang/crates.io-index"
1444 +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
1445 +dependencies = [
1446 + "stable_deref_trait",
1447 + "yoke-derive",
1448 + "zerofrom",
1449 +]
1450 +
1451 +[[package]]
1452 +name = "yoke-derive"
1453 +version = "0.8.1"
1454 +source = "registry+https://github.com/rust-lang/crates.io-index"
1455 +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
1456 +dependencies = [
1457 + "proc-macro2",
1458 + "quote",
1459 + "syn",
1460 + "synstructure",
1461 +]
1462 +
1463 +[[package]]
1464 +name = "zerocopy"
1465 +version = "0.8.42"
1466 +source = "registry+https://github.com/rust-lang/crates.io-index"
1467 +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3"
1468 +dependencies = [
1469 + "zerocopy-derive",
1470 +]
1471 +
1472 +[[package]]
1473 +name = "zerocopy-derive"
1474 +version = "0.8.42"
1475 +source = "registry+https://github.com/rust-lang/crates.io-index"
1476 +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f"
1477 +dependencies = [
1478 + "proc-macro2",
1479 + "quote",
1480 + "syn",
1481 +]
1482 +
1483 +[[package]]
1484 +name = "zerofrom"
1485 +version = "0.1.6"
1486 +source = "registry+https://github.com/rust-lang/crates.io-index"
1487 +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
1488 +dependencies = [
1489 + "zerofrom-derive",
1490 +]
1491 +
1492 +[[package]]
1493 +name = "zerofrom-derive"
1494 +version = "0.1.6"
1495 +source = "registry+https://github.com/rust-lang/crates.io-index"
1496 +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
1497 +dependencies = [
1498 + "proc-macro2",
1499 + "quote",
1500 + "syn",
1501 + "synstructure",
1502 +]
1503 +
1504 +[[package]]
1505 +name = "zip"
1506 +version = "7.2.0"
1507 +source = "registry+https://github.com/rust-lang/crates.io-index"
1508 +checksum = "c42e33efc22a0650c311c2ef19115ce232583abbe80850bc8b66509ebef02de0"
1509 +dependencies = [
1510 + "crc32fast",
1511 + "indexmap",
1512 + "memchr",
1513 + "typed-path",
1514 +]
1515 +
1516 +[[package]]
1517 +name = "zmij"
1518 +version = "1.0.21"
1519 +source = "registry+https://github.com/rust-lang/crates.io-index"
1520 +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
crates/onde-wasm/Cargo.toml new
+68
@@ -0,0 +1,68 @@
1 +[package]
2 +name = "onde-wasm"
3 +version = "0.1.0"
4 +edition = "2021"
5 +description = "onde inference engine compiled to WASM — Whisper speech-to-text via candle-transformers"
6 +license = "MIT"
7 +repository = "https://github.com/ondeinference/onde"
8 +
9 +[lib]
10 +crate-type = ["cdylib"]
11 +
12 +[dependencies]
13 +# ── Core inference ────────────────────────────────────────────────────────────
14 +# Pinned to the same candle rev already in the workspace lockfile (c3bb5bf).
15 +# candle-transformers ships a pure-Rust Whisper implementation that compiles
16 +# cleanly to wasm32-unknown-unknown — no C FFI, no platform intrinsics.
17 +candle-core = { git = "https://github.com/huggingface/candle.git", rev = "c3bb5bf" }
18 +candle-nn = { git = "https://github.com/huggingface/candle.git", rev = "c3bb5bf" }
19 +candle-transformers = { git = "https://github.com/huggingface/candle.git", rev = "c3bb5bf" }
20 +
21 +# ── Tokenizer ─────────────────────────────────────────────────────────────────
22 +# `default-features = false` is essential — it eliminates onig_sys (C bindings
23 +# to oniguruma) and esaxx-rs (C++ suffix array) which cannot compile to WASM.
24 +# `unstable_wasm` is an additional feature that switches remaining regex paths
25 +# to a WASM-safe fallback. Both flags together are required.
26 +# Version aligned with the candle c3bb5bf workspace (tokenizers 0.22.0).
27 +tokenizers = { version = "0.22", default-features = false, features = ["unstable_wasm"] }
28 +
29 +# ── Serialisation ─────────────────────────────────────────────────────────────
30 +serde = { version = "1", features = ["derive"] }
31 +serde_json = "1"
32 +# Aligned with candle workspace (safetensors 0.7.0).
33 +safetensors = "0.7"
34 +
35 +# ── Audio decoding ────────────────────────────────────────────────────────────
36 +# hound reads 16-bit PCM WAV files — pure Rust, WASM-safe.
37 +hound = "3.5"
38 +
39 +# ── Error handling ────────────────────────────────────────────────────────────
40 +anyhow = "1"
41 +
42 +# ── Numeric utilities ─────────────────────────────────────────────────────────
43 +num-traits = "0.2"
44 +# Aligned with candle workspace (rand 0.9.0).
45 +rand = "0.9"
46 +
47 +# ── WASM / JS bridge ──────────────────────────────────────────────────────────
48 +wasm-bindgen = "0.2"
49 +wasm-bindgen-futures = "0.4"
50 +js-sys = "0.3"
51 +# console_error_panic_hook turns Rust panics into readable browser console errors.
52 +console_error_panic_hook = { version = "0.1", optional = true }
53 +# wasm-logger bridges the `log` facade to browser console.{log,warn,error}.
54 +wasm-logger = "0.2"
55 +log = "0.4"
56 +
57 +# ── WASM-specific entropy source ──────────────────────────────────────────────
58 +# getrandom must opt in to the JS entropy source on wasm32; otherwise rand
59 +# and anything that seeds a PRNG will fail to compile.
60 +[target.'cfg(target_arch = "wasm32")'.dependencies]
61 +getrandom = { version = "0.2", features = ["js"] }
62 +
63 +[features]
64 +default = ["console_error_panic_hook"]
65 +
66 +# ── wasm-pack build profile ───────────────────────────────────────────────────
67 +[package.metadata.wasm-pack.profile.release]
68 +wasm-opt = ["-Oz", "--enable-mutable-globals"]
crates/onde-wasm/build.sh new
+248
@@ -0,0 +1,248 @@
1 +#!/usr/bin/env bash
2 +# =============================================================================
3 +# onde/crates/onde-wasm/build.sh
4 +#
5 +# One-command wasm-pack build for the onde WASM Whisper engine.
6 +#
7 +# Prerequisites
8 +# -------------
9 +# • Rust with the wasm32-unknown-unknown target:
10 +# rustup target add wasm32-unknown-unknown
11 +#
12 +# • wasm-pack:
13 +# cargo install wasm-pack
14 +#
15 +# • (Optional) wasm-opt for smaller binaries — installed automatically by
16 +# wasm-pack if missing, but a pre-installed version is faster.
17 +#
18 +# Usage
19 +# -----
20 +# # Standard release build
21 +# ./build.sh
22 +#
23 +# # Debug build (faster compile, larger .wasm, source-mapped)
24 +# BUILD_TYPE=debug ./build.sh
25 +#
26 +# # Override the output directory (default: onde/crates/onde-wasm/pkg)
27 +# OUT_DIR=/path/to/output ./build.sh
28 +#
29 +# Output
30 +# ------
31 +# pkg/
32 +# onde_wasm.js — ES module glue
33 +# onde_wasm_bg.wasm — compiled WASM binary
34 +# onde_wasm.d.ts — TypeScript declarations for WhisperDecoder
35 +# onde_wasm_bg.wasm.d.ts
36 +# package.json
37 +#
38 +# Model assets (download separately — see section below)
39 +# ------------------------------------------------------
40 +# The WhisperDecoder constructor requires four byte arrays that are NOT
41 +# bundled into the .wasm binary. The JS consumer must fetch them from
42 +# HuggingFace and pass them as Uint8Arrays.
43 +#
44 +# Recommended model: whisper-tiny.en (non-quantized, ~75 MB total)
45 +#
46 +# WEIGHTS https://huggingface.co/openai/whisper-tiny.en/resolve/main/model.safetensors
47 +# TOKENIZER https://huggingface.co/openai/whisper-tiny.en/resolve/main/tokenizer.json
48 +# CONFIG https://huggingface.co/openai/whisper-tiny.en/resolve/main/config.json
49 +# MEL https://huggingface.co/spaces/lmz/candle-whisper/resolve/main/mel_filters.safetensors
50 +#
51 +# Recommended model: whisper-tiny (multilingual, ~75 MB total)
52 +#
53 +# WEIGHTS https://huggingface.co/openai/whisper-tiny/resolve/main/model.safetensors
54 +# TOKENIZER https://huggingface.co/openai/whisper-tiny/resolve/main/tokenizer.json
55 +# CONFIG https://huggingface.co/openai/whisper-tiny/resolve/main/config.json
56 +# MEL https://huggingface.co/spaces/lmz/candle-whisper/resolve/main/mel_filters.safetensors
57 +#
58 +# Quantized model: whisper-tiny.en Q8_0 (~42 MB, faster load)
59 +#
60 +# WEIGHTS https://huggingface.co/lmz/candle-whisper/resolve/main/model-tiny-en-q80.gguf
61 +# TOKENIZER https://huggingface.co/lmz/candle-whisper/resolve/main/tokenizer-tiny-en.json
62 +# CONFIG https://huggingface.co/lmz/candle-whisper/resolve/main/config-tiny-en.json
63 +# MEL https://huggingface.co/spaces/lmz/candle-whisper/resolve/main/mel_filters.safetensors
64 +#
65 +# Run the download helper:
66 +# ./build.sh --download-assets
67 +#
68 +# Vite integration (karokowe-connected-devices)
69 +# ---------------------------------------------
70 +# 1. Copy pkg/ into your project, e.g.:
71 +# cp -r pkg/ frontend/karokowe-connected-devices/src/wasm/onde/
72 +#
73 +# 2. Add to vite.config.ts:
74 +# import { defineConfig } from "vite";
75 +# export default defineConfig({
76 +# optimizeDeps: { exclude: ["onde-wasm"] },
77 +# server: {
78 +# headers: {
79 +# "Cross-Origin-Opener-Policy": "same-origin",
80 +# "Cross-Origin-Embedder-Policy": "require-corp",
81 +# },
82 +# },
83 +# });
84 +#
85 +# NOTE: The COOP/COEP headers are NOT required by this pure-Rust WASM
86 +# build (no SharedArrayBuffer / pthreads are used — inference runs
87 +# synchronously on the JS thread). They are shown here for completeness
88 +# if you later add a Web Worker wrapper.
89 +#
90 +# 3. In your Worker or module:
91 +# import init, { WhisperDecoder } from "./onde_wasm.js";
92 +# await init();
93 +# const decoder = new WhisperDecoder(
94 +# weightsBytes, tokenizerBytes, melFiltersBytes, configBytes,
95 +# false, // quantized
96 +# false, // is_multilingual
97 +# true, // timestamps
98 +# null, // task
99 +# null, // language
100 +# );
101 +# const json = decoder.decode(wavBytes);
102 +# const result = JSON.parse(json);
103 +# // result.text — full transcript
104 +# // result.segments[] — [{ start, end, text }]
105 +#
106 +# =============================================================================
107 +
108 +set -euo pipefail
109 +
110 +# ── Script location ───────────────────────────────────────────────────────────
111 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
112 +
113 +# ── Parameters ─────────────────────────────────────────────────────────────────
114 +BUILD_TYPE="${BUILD_TYPE:-release}" # "release" or "debug"
115 +OUT_DIR="${OUT_DIR:-${SCRIPT_DIR}/pkg}"
116 +
117 +# ── Colours ───────────────────────────────────────────────────────────────────
118 +if [ -t 1 ]; then
119 + RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
120 + CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
121 +else
122 + RED=''; GREEN=''; YELLOW=''; CYAN=''; BOLD=''; RESET=''
123 +fi
124 +
125 +log_info() { echo -e "${CYAN}[onde-wasm]${RESET} $*"; }
126 +log_ok() { echo -e "${GREEN}[onde-wasm]${RESET} $*"; }
127 +log_warn() { echo -e "${YELLOW}[onde-wasm]${RESET} $*"; }
128 +log_error() { echo -e "${RED}[onde-wasm] ERROR:${RESET} $*" >&2; }
129 +log_section() { echo -e "\n${BOLD}── $* ─────────────────────────────────${RESET}"; }
130 +
131 +# ── --download-assets helper ───────────────────────────────────────────────────
132 +download_assets() {
133 + log_section "Downloading model assets"
134 +
135 + ASSETS_DIR="${SCRIPT_DIR}/assets"
136 + mkdir -p "${ASSETS_DIR}"
137 +
138 + declare -A URLS=(
139 + ["model.safetensors"]="https://huggingface.co/openai/whisper-tiny.en/resolve/main/model.safetensors"
140 + ["tokenizer.json"]="https://huggingface.co/openai/whisper-tiny.en/resolve/main/tokenizer.json"
141 + ["config.json"]="https://huggingface.co/openai/whisper-tiny.en/resolve/main/config.json"
142 + ["mel_filters.safetensors"]="https://huggingface.co/spaces/lmz/candle-whisper/resolve/main/mel_filters.safetensors"
143 + )
144 +
145 + for fname in "${!URLS[@]}"; do
146 + dest="${ASSETS_DIR}/${fname}"
147 + if [ -f "${dest}" ]; then
148 + log_info " ${fname} — already present, skipping"
149 + continue
150 + fi
151 + log_info " Downloading ${fname}…"
152 + curl -fL --progress-bar -o "${dest}" "${URLS[$fname]}"
153 + log_ok " ${fname} saved ($(du -sh "${dest}" | cut -f1))"
154 + done
155 +
156 + log_ok "All assets in ${ASSETS_DIR}/"
157 + echo
158 + echo " Pass these to WhisperDecoder in JS:"
159 + echo " weights: ${ASSETS_DIR}/model.safetensors"
160 + echo " tokenizer: ${ASSETS_DIR}/tokenizer.json"
161 + echo " config: ${ASSETS_DIR}/config.json"
162 + echo " mel_filters: ${ASSETS_DIR}/mel_filters.safetensors"
163 + exit 0
164 +}
165 +
166 +if [[ "${1:-}" == "--download-assets" ]]; then
167 + download_assets
168 +fi
169 +
170 +# ── Preflight ──────────────────────────────────────────────────────────────────
171 +log_section "Preflight"
172 +
173 +if ! command -v wasm-pack &>/dev/null; then
174 + log_error "wasm-pack not found."
175 + echo
176 + echo " Install with:"
177 + echo " cargo install wasm-pack"
178 + echo
179 + exit 1
180 +fi
181 +
182 +WASM_PACK_VERSION=$(wasm-pack --version)
183 +log_info "wasm-pack: ${WASM_PACK_VERSION}"
184 +
185 +if ! rustup target list --installed | grep -q "wasm32-unknown-unknown"; then
186 + log_warn "wasm32-unknown-unknown target not installed — installing now…"
187 + rustup target add wasm32-unknown-unknown
188 +fi
189 +
190 +log_info "Build type : ${BUILD_TYPE}"
191 +log_info "Output dir : ${OUT_DIR}"
192 +
193 +# ── Build ──────────────────────────────────────────────────────────────────────
194 +log_section "Build"
195 +
196 +WASM_PACK_PROFILE_FLAG="--release"
197 +if [[ "${BUILD_TYPE}" == "debug" ]]; then
198 + WASM_PACK_PROFILE_FLAG="--dev"
199 +fi
200 +
201 +wasm-pack build \
202 + --target web \
203 + --out-dir "${OUT_DIR}" \
204 + ${WASM_PACK_PROFILE_FLAG} \
205 + "${SCRIPT_DIR}"
206 +
207 +log_ok "wasm-pack build complete."
208 +
209 +# ── Post-process: fix package.json name ───────────────────────────────────────
210 +# wasm-pack emits the crate name as the package name; rename to onde-wasm
211 +# so the Vite import path is predictable.
212 +PKG_JSON="${OUT_DIR}/package.json"
213 +if [ -f "${PKG_JSON}" ]; then
214 + # Use sed for portable in-place replacement (BSD and GNU sed both support this).
215 + sed -i.bak 's/"name": "onde_wasm"/"name": "onde-wasm"/' "${PKG_JSON}"
216 + rm -f "${PKG_JSON}.bak"
217 + log_info "package.json name → onde-wasm"
218 +fi
219 +
220 +# ── Summary ───────────────────────────────────────────────────────────────────
221 +log_section "Output"
222 +
223 +echo
224 +log_ok "onde-wasm build succeeded!"
225 +echo
226 +echo " Artefacts:"
227 +ls -lh "${OUT_DIR}/"*.{js,wasm,ts} 2>/dev/null \
228 + | grep -v '^total' \
229 + | awk '{printf " %-40s %s\n", $9, $5}' \
230 + || true
231 +echo
232 +echo " Next steps:"
233 +echo
234 +echo " 1. Download model assets (first time only):"
235 +echo " ${BASH_SOURCE[0]} --download-assets"
236 +echo
237 +echo " 2. Copy pkg/ into your Vite project:"
238 +echo " cp -r ${OUT_DIR}/. frontend/karokowe-connected-devices/src/wasm/onde/"
239 +echo
240 +echo " 3. Import in a Web Worker:"
241 +echo " import init, { WhisperDecoder } from \"./onde_wasm.js\";"
242 +echo " await init();"
243 +echo " const decoder = new WhisperDecoder("
244 +echo " weightsBytes, tokenizerBytes, melFiltersBytes, configBytes,"
245 +echo " false, false, true, null, null"
246 +echo " );"
247 +echo " const result = JSON.parse(decoder.decode(wavBytes));"
248 +echo
crates/onde-wasm/src/lib.rs new
+931
@@ -0,0 +1,931 @@
1 +//! onde-wasm — Whisper speech-to-text compiled to WebAssembly.
2 +//!
3 +//! This crate exposes a single [`WhisperDecoder`] class to JavaScript via
4 +//! `wasm-bindgen`. It is backed by `candle-transformers`' pure-Rust Whisper
5 +//! implementation, which compiles cleanly to `wasm32-unknown-unknown` without
6 +//! any C FFI or platform intrinsics.
7 +//!
8 +//! # JavaScript API
9 +//!
10 +//! ```js
11 +//! import init, { WhisperDecoder } from "./onde_wasm.js";
12 +//!
13 +//! await init();
14 +//!
15 +//! // All four byte arrays are fetched from HuggingFace (see build.sh).
16 +//! const decoder = new WhisperDecoder(
17 +//! weightsBytes, // model.safetensors — or model-tiny-en-q80.gguf
18 +//! tokenizerBytes, // tokenizer.json
19 +//! melFiltersBytes, // mel_filters.safetensors
20 +//! configBytes, // config.json
21 +//! quantized, // bool — true for .gguf weights
22 +//! isMultilingual, // bool — false for *.en models
23 +//! timestamps, // bool — include per-segment timestamps
24 +//! task, // "transcribe" | "translate" | null
25 +//! language, // BCP-47 string | null (null = auto-detect)
26 +//! );
27 +//!
28 +//! // wavBytes is a Uint8Array of a 16 kHz mono WAV file.
29 +//! const json = decoder.decode(wavBytes);
30 +//!
31 +//! // json is a string with the shape:
32 +//! // {
33 +//! // "text": "Full transcript…",
34 +//! // "segments": [
35 +//! // { "start": 0.0, "end": 3.5, "text": " Hello world" },
36 +//! // …
37 +//! // ]
38 +//! // }
39 +//! const result = JSON.parse(json);
40 +//! ```
41 +//!
42 +//! # Result JSON shape
43 +//!
44 +//! The JSON string returned by [`WhisperDecoder::decode`] mirrors the
45 +//! `WhisperResult` / `WhisperSegment` types in `onde::whisper` so that the
46 +//! same TypeScript interface can be reused across both the native Tauri app
47 +//! and the browser connected-devices app.
48 +//!
49 +//! ```ts
50 +//! interface OndeSegment { start: number; end: number; text: string; }
51 +//! interface OndeResult { text: string; segments: OndeSegment[]; }
52 +//! ```
53 +//!
54 +//! # Model assets
55 +//!
56 +//! | File | Source |
57 +//! |---|---|
58 +//! | `model.safetensors` | `openai/whisper-tiny` (or tiny.en, base, …) |
59 +//! | `model-tiny-en-q80.gguf` | `lmz/candle-whisper` (quantized) |
60 +//! | `tokenizer.json` | same HF repo |
61 +//! | `config.json` | same HF repo |
62 +//! | `mel_filters.safetensors` | `huggingface/candle-whisper` space assets |
63 +//!
64 +//! # Build
65 +//!
66 +//! ```sh
67 +//! wasm-pack build --target web --out-dir pkg
68 +//! ```
69 +//!
70 +//! See `onde/crates/onde-wasm/build.sh` for the full reproducible build
71 +//! script with asset download instructions.
72 +
73 +use anyhow::anyhow;
74 +use candle_core::{safetensors::Load, Device, IndexOp, Tensor, D};
75 +use candle_nn::{ops::softmax, VarBuilder};
76 +use candle_transformers::models::whisper::{self as m, Config};
77 +use rand::{distr::Distribution, rngs::StdRng, SeedableRng};
78 +use serde::{Deserialize, Serialize};
79 +use tokenizers::Tokenizer;
80 +use wasm_bindgen::prelude::*;
81 +
82 +// ---------------------------------------------------------------------------
83 +// Panic hook
84 +// ---------------------------------------------------------------------------
85 +
86 +fn set_panic_hook() {
87 + #[cfg(feature = "console_error_panic_hook")]
88 + console_error_panic_hook::set_once();
89 +}
90 +
91 +// ---------------------------------------------------------------------------
92 +// Browser console bridge
93 +// ---------------------------------------------------------------------------
94 +
95 +#[wasm_bindgen]
96 +extern "C" {
97 + #[wasm_bindgen(js_namespace = console, js_name = log)]
98 + fn console_log(s: &str);
99 +
100 + #[wasm_bindgen(js_namespace = console, js_name = warn)]
101 + fn console_warn(s: &str);
102 +}
103 +
104 +macro_rules! clog {
105 + ($($t:tt)*) => { console_log(&format!("[onde-wasm] {}", format_args!($($t)*))) }
106 +}
107 +
108 +macro_rules! cwarn {
109 + ($($t:tt)*) => { console_warn(&format!("[onde-wasm] {}", format_args!($($t)*))) }
110 +}
111 +
112 +// ---------------------------------------------------------------------------
113 +// Language table
114 +//
115 +// Copied verbatim from candle-wasm-examples/whisper/src/languages.rs at
116 +// rev c3bb5bf. This constant is NOT re-exported by candle-transformers
117 +// itself at that revision.
118 +// ---------------------------------------------------------------------------
119 +
120 +const LANGUAGES: [(&str, &str); 99] = [
121 + ("en", "english"),
122 + ("zh", "chinese"),
123 + ("de", "german"),
124 + ("es", "spanish"),
125 + ("ru", "russian"),
126 + ("ko", "korean"),
127 + ("fr", "french"),
128 + ("ja", "japanese"),
129 + ("pt", "portuguese"),
130 + ("tr", "turkish"),
131 + ("pl", "polish"),
132 + ("ca", "catalan"),
133 + ("nl", "dutch"),
134 + ("ar", "arabic"),
135 + ("sv", "swedish"),
136 + ("it", "italian"),
137 + ("id", "indonesian"),
138 + ("hi", "hindi"),
139 + ("fi", "finnish"),
140 + ("vi", "vietnamese"),
141 + ("he", "hebrew"),
142 + ("uk", "ukrainian"),
143 + ("el", "greek"),
144 + ("ms", "malay"),
145 + ("cs", "czech"),
146 + ("ro", "romanian"),
147 + ("da", "danish"),
148 + ("hu", "hungarian"),
149 + ("ta", "tamil"),
150 + ("no", "norwegian"),
151 + ("th", "thai"),
152 + ("ur", "urdu"),
153 + ("hr", "croatian"),
154 + ("bg", "bulgarian"),
155 + ("lt", "lithuanian"),
156 + ("la", "latin"),
157 + ("mi", "maori"),
158 + ("ml", "malayalam"),
159 + ("cy", "welsh"),
160 + ("sk", "slovak"),
161 + ("te", "telugu"),
162 + ("fa", "persian"),
163 + ("lv", "latvian"),
164 + ("bn", "bengali"),
165 + ("sr", "serbian"),
166 + ("az", "azerbaijani"),
167 + ("sl", "slovenian"),
168 + ("kn", "kannada"),
169 + ("et", "estonian"),
170 + ("mk", "macedonian"),
171 + ("br", "breton"),
172 + ("eu", "basque"),
173 + ("is", "icelandic"),
174 + ("hy", "armenian"),
175 + ("ne", "nepali"),
176 + ("mn", "mongolian"),
177 + ("bs", "bosnian"),
178 + ("kk", "kazakh"),
179 + ("sq", "albanian"),
180 + ("sw", "swahili"),
181 + ("gl", "galician"),
182 + ("mr", "marathi"),
183 + ("pa", "punjabi"),
184 + ("si", "sinhala"),
185 + ("km", "khmer"),
186 + ("sn", "shona"),
187 + ("yo", "yoruba"),
188 + ("so", "somali"),
189 + ("af", "afrikaans"),
190 + ("oc", "occitan"),
191 + ("ka", "georgian"),
192 + ("be", "belarusian"),
193 + ("tg", "tajik"),
194 + ("sd", "sindhi"),
195 + ("gu", "gujarati"),
196 + ("am", "amharic"),
197 + ("yi", "yiddish"),
198 + ("lo", "lao"),
199 + ("uz", "uzbek"),
200 + ("fo", "faroese"),
201 + ("ht", "haitian creole"),
202 + ("ps", "pashto"),
203 + ("tk", "turkmen"),
204 + ("nn", "nynorsk"),
205 + ("mt", "maltese"),
206 + ("sa", "sanskrit"),
207 + ("lb", "luxembourgish"),
208 + ("my", "myanmar"),
209 + ("bo", "tibetan"),
210 + ("tl", "tagalog"),
211 + ("mg", "malagasy"),
212 + ("as", "assamese"),
213 + ("tt", "tatar"),
214 + ("haw", "hawaiian"),
215 + ("ln", "lingala"),
216 + ("ha", "hausa"),
217 + ("ba", "bashkir"),
218 + ("jw", "javanese"),
219 + ("su", "sundanese"),
220 +];
221 +
222 +// ---------------------------------------------------------------------------
223 +// Audio processing
224 +//
225 +// Ported from candle-wasm-examples/whisper/src/audio.rs (rev c3bb5bf).
226 +// Pure-Rust FFT + mel-spectrogram — no C dependencies, WASM-safe.
227 +// ---------------------------------------------------------------------------
228 +
229 +trait Float: num_traits::Float + num_traits::FloatConst + num_traits::NumAssign {}
230 +impl Float for f32 {}
231 +impl Float for f64 {}
232 +
233 +fn fft<T: Float>(inp: &[T]) -> Vec<T> {
234 + let n = inp.len();
235 + let zero = T::zero();
236 + if n == 1 {
237 + return vec![inp[0], zero];
238 + }
239 + if n % 2 == 1 {
240 + return dft(inp);
241 + }
242 + let mut out = vec![zero; n * 2];
243 + let mut even = Vec::with_capacity(n / 2);
244 + let mut odd = Vec::with_capacity(n / 2);
245 + for (i, &v) in inp.iter().enumerate() {
246 + if i % 2 == 0 { even.push(v) } else { odd.push(v) }
247 + }
248 + let even_fft = fft(&even);
249 + let odd_fft = fft(&odd);
250 + let two_pi = T::PI() + T::PI();
251 + let n_t = T::from(n).unwrap();
252 + for k in 0..n / 2 {
253 + let k_t = T::from(k).unwrap();
254 + let theta = two_pi * k_t / n_t;
255 + let re = theta.cos();
256 + let im = -theta.sin();
257 + let re_odd = odd_fft[2 * k];
258 + let im_odd = odd_fft[2 * k + 1];
259 + out[2 * k] = even_fft[2 * k] + re * re_odd - im * im_odd;
260 + out[2 * k + 1] = even_fft[2 * k + 1] + re * im_odd + im * re_odd;
261 + out[2 * (k + n / 2)] = even_fft[2 * k] - re * re_odd + im * im_odd;
262 + out[2 * (k + n / 2) + 1] = even_fft[2 * k + 1] - re * im_odd - im * re_odd;
263 + }
264 + out
265 +}
266 +
267 +fn dft<T: Float>(inp: &[T]) -> Vec<T> {
268 + let zero = T::zero();
269 + let n = inp.len();
270 + let two_pi = T::PI() + T::PI();
271 + let mut out = Vec::with_capacity(2 * n);
272 + let n_t = T::from(n).unwrap();
273 + for k in 0..n {
274 + let k_t = T::from(k).unwrap();
275 + let mut re = zero;
276 + let mut im = zero;
277 + for (j, &v) in inp.iter().enumerate() {
278 + let j_t = T::from(j).unwrap();
279 + let angle = two_pi * k_t * j_t / n_t;
280 + re += v * angle.cos();
281 + im -= v * angle.sin();
282 + }
283 + out.push(re);
284 + out.push(im);
285 + }
286 + out
287 +}
288 +
289 +#[allow(clippy::too_many_arguments)]
290 +fn log_mel_spectrogram_w<T: Float>(
291 + ith: usize,
292 + hann: &[T],
293 + samples: &[T],
294 + filters: &[T],
295 + fft_size: usize,
296 + fft_step: usize,
297 + speed_up: bool,
298 + n_len: usize,
299 + n_mel: usize,
300 + n_threads: usize,
301 +) -> Vec<T> {
302 + let n_fft = if speed_up { 1 + fft_size / 4 } else { 1 + fft_size / 2 };
303 + let zero = T::zero();
304 + let half = T::from(0.5).unwrap();
305 + let mut fft_in = vec![zero; fft_size];
306 + let mut mel = vec![zero; n_len * n_mel];
307 + for i in (ith..n_len).step_by(n_threads) {
308 + let offset = i * fft_step;
309 + for j in 0..fft_size {
310 + fft_in[j] = if offset + j < samples.len() {
311 + hann[j] * samples[offset + j]
312 + } else {
313 + zero
314 + };
315 + }
316 + let mut fft_out: Vec<T> = fft(&fft_in);
317 + for j in 0..fft_size {
318 + fft_out[j] = fft_out[2 * j] * fft_out[2 * j]
319 + + fft_out[2 * j + 1] * fft_out[2 * j + 1];
320 + }
321 + for j in 1..fft_size / 2 {
322 + let v = fft_out[fft_size - j];
323 + fft_out[j] += v;
324 + }
325 + if speed_up {
326 + for j in 0..n_fft {
327 + fft_out[j] = half * (fft_out[2 * j] + fft_out[2 * j + 1]);
328 + }
329 + }
330 + for j in 0..n_mel {
331 + let mut sum = zero;
332 + for k in 0..n_fft {
333 + sum += fft_out[k] * filters[j * n_fft + k];
334 + }
335 + mel[j * n_len + i] = T::max(sum, T::from(1e-10).unwrap()).log10();
336 + }
337 + }
338 + mel
339 +}
340 +
341 +fn log_mel_spectrogram_<T: Float>(
342 + samples: &[T],
343 + filters: &[T],
344 + fft_size: usize,
345 + fft_step: usize,
346 + n_mel: usize,
347 + speed_up: bool,
348 +) -> Vec<T> {
349 + let zero = T::zero();
350 + let two_pi = T::PI() + T::PI();
351 + let half = T::from(0.5).unwrap();
352 + let one = T::from(1.0).unwrap();
353 + let four = T::from(4.0).unwrap();
354 + let fft_size_t = T::from(fft_size).unwrap();
355 + let hann: Vec<T> = (0..fft_size)
356 + .map(|i| half * (one - ((two_pi * T::from(i).unwrap()) / fft_size_t).cos()))
357 + .collect();
358 + let n_len = samples.len() / fft_step;
359 + let pad = 100 * m::CHUNK_LENGTH / 2;
360 + let n_len = if n_len % pad != 0 {
361 + (n_len / pad + 1) * pad
362 + } else {
363 + n_len
364 + };
365 + let n_len = n_len + pad;
366 + let samples = {
367 + let mut padded = samples.to_vec();
368 + let to_add = n_len * fft_step - samples.len();
369 + padded.extend(std::iter::repeat_n(zero, to_add));
370 + padded
371 + };
372 + let mut mel = log_mel_spectrogram_w(
373 + 0, &hann, &samples, filters, fft_size, fft_step, speed_up, n_len, n_mel, 1,
374 + );
375 + let mmax = mel
376 + .iter()
377 + .max_by(|u, v| u.partial_cmp(v).unwrap_or(std::cmp::Ordering::Greater))
378 + .copied()
379 + .unwrap_or(zero)
380 + - T::from(8).unwrap();
381 + for m in mel.iter_mut() {
382 + let v = T::max(*m, mmax);
383 + *m = v / four + one;
384 + }
385 + mel
386 +}
387 +
388 +fn pcm_to_mel(cfg: &Config, samples: &[f32], filters: &[f32]) -> anyhow::Result<Vec<f32>> {
389 + Ok(log_mel_spectrogram_(
390 + samples,
391 + filters,
392 + m::N_FFT,
393 + m::HOP_LENGTH,
394 + cfg.num_mel_bins,
395 + false,
396 + ))
397 +}
398 +
399 +// ---------------------------------------------------------------------------
400 +// Model enum — wraps normal (f32 safetensors) and quantized (GGUF) variants
401 +// ---------------------------------------------------------------------------
402 +
403 +enum Model {
404 + Normal(m::model::Whisper),
405 + Quantized(m::quantized_model::Whisper),
406 +}
407 +
408 +impl Model {
409 + fn config(&self) -> &Config {
410 + match self {
411 + Self::Normal(m) => &m.config,
412 + Self::Quantized(m) => &m.config,
413 + }
414 + }
415 +
416 + fn encoder_forward(&mut self, x: &Tensor, flush: bool) -> candle_core::Result<Tensor> {
417 + match self {
418 + Self::Normal(m) => m.encoder.forward(x, flush),
419 + Self::Quantized(m) => m.encoder.forward(x, flush),
420 + }
421 + }
422 +
423 + fn decoder_forward(
424 + &mut self,
425 + x: &Tensor,
426 + xa: &Tensor,
427 + flush: bool,
428 + ) -> candle_core::Result<Tensor> {
429 + match self {
430 + Self::Normal(m) => m.decoder.forward(x, xa, flush),
431 + Self::Quantized(m) => m.decoder.forward(x, xa, flush),
432 + }
433 + }
434 +
435 + fn decoder_final_linear(&self, x: &Tensor) -> candle_core::Result<Tensor> {
436 + match self {
437 + Self::Normal(m) => m.decoder.final_linear(x),
438 + Self::Quantized(m) => m.decoder.final_linear(x),
439 + }
440 + }
441 +}
442 +
443 +// ---------------------------------------------------------------------------
444 +// Token helpers
445 +// ---------------------------------------------------------------------------
446 +
447 +fn token_id(tokenizer: &Tokenizer, token: &str) -> anyhow::Result<u32> {
448 + tokenizer
449 + .token_to_id(token)
450 + .ok_or_else(|| anyhow!("no token-id for {token}"))
451 +}
452 +
453 +fn detect_language(
454 + model: &mut Model,
455 + tokenizer: &Tokenizer,
456 + mel: &Tensor,
457 +) -> anyhow::Result<u32> {
458 + clog!("detecting language");
459 + let (_bsize, _, seq_len) = mel.dims3()?;
460 + let mel = mel.narrow(
461 + 2,
462 + 0,
463 + usize::min(seq_len, model.config().max_source_positions),
464 + )?;
465 + let device = mel.device();
466 + let language_token_ids = LANGUAGES
467 + .iter()
468 + .map(|(t, _)| token_id(tokenizer, &format!("<|{t}|>")))
469 + .collect::<anyhow::Result<Vec<_>>>()?;
470 + let sot = token_id(tokenizer, m::SOT_TOKEN)?;
471 + let audio_features = model.encoder_forward(&mel, true)?;
472 + let tokens = Tensor::new(&[[sot]], device)?;
473 + let language_token_ids_t = Tensor::new(language_token_ids.as_slice(), device)?;
474 + let ys = model.decoder_forward(&tokens, &audio_features, true)?;
475 + let logits = model.decoder_final_linear(&ys.i(..1)?)?.i(0)?.i(0)?;
476 + let logits = logits.index_select(&language_token_ids_t, 0)?;
477 + let probs = softmax(&logits, D::Minus1)?.to_vec1::<f32>()?;
478 + let mut ranked: Vec<_> = LANGUAGES.iter().zip(probs.iter()).collect();
479 + ranked.sort_by(|(_, p1), (_, p2)| p2.total_cmp(p1));
480 + let best_code = ranked[0].0 .0;
481 + let token_str = format!("<|{best_code}|>");
482 + let language_id = token_id(tokenizer, &token_str)?;
483 + clog!("detected language: {best_code} ({token_str})");
484 + Ok(language_id)
485 +}
486 +
487 +// ---------------------------------------------------------------------------
488 +// Internal decoding state
489 +// ---------------------------------------------------------------------------
490 +
491 +#[derive(Clone)]
492 +struct DecodingResult {
493 + tokens: Vec<u32>,
494 + text: String,
495 + avg_logprob: f64,
496 + no_speech_prob: f64,
497 + compression_ratio: f64,
498 +}
499 +
500 +struct Decoder {
501 + model: Model,
502 + rng: StdRng,
503 + tokenizer: Tokenizer,
504 + mel_filters: Vec<f32>,
505 + language: Option<String>,
506 + is_multilingual: bool,
507 + timestamps: bool,
508 + task_tokens: Vec<u32>, // [task_token] or [task_token, no_timestamps_token]
509 + suppress_tokens: Tensor,
510 + sot_token: u32,
511 + eot_token: u32,
512 + no_speech_token: u32,
513 + no_timestamps_token: u32,
514 +}
515 +
516 +impl Decoder {
517 + #[allow(clippy::too_many_arguments)]
518 + fn new(
519 + model: Model,
520 + tokenizer: Tokenizer,
521 + mel_filters: Vec<f32>,
522 + device: &Device,
523 + task: Option<&str>,
524 + language: Option<String>,
525 + is_multilingual: bool,
526 + timestamps: bool,
527 + ) -> anyhow::Result<Self> {
528 + let suppress_tokens_vec: Vec<f32> = (0..model.config().vocab_size as u32)
529 + .map(|i| {
530 + if model.config().suppress_tokens.contains(&i) {
531 + f32::NEG_INFINITY
532 + } else {
533 + 0f32
534 + }
535 + })
536 + .collect();
537 + let suppress_tokens = Tensor::new(suppress_tokens_vec.as_slice(), device)?;
538 +
539 + let sot_token = token_id(&tokenizer, m::SOT_TOKEN)?;
540 + let transcribe_token = token_id(&tokenizer, m::TRANSCRIBE_TOKEN)?;
541 + let translate_token = token_id(&tokenizer, m::TRANSLATE_TOKEN)?;
542 + let eot_token = token_id(&tokenizer, m::EOT_TOKEN)?;
543 + let no_timestamps_token = token_id(&tokenizer, m::NO_TIMESTAMPS_TOKEN)?;
544 + let no_speech_token = m::NO_SPEECH_TOKENS
545 + .iter()
546 + .find_map(|t| token_id(&tokenizer, t).ok())
547 + .ok_or_else(|| anyhow!("no no-speech token found"))?;
548 +
549 + let task_token = match task {
550 + Some("translate") => translate_token,
551 + _ => transcribe_token,
552 + };
553 +
554 + let mut task_tokens = vec![task_token];
555 + if !timestamps {
556 + task_tokens.push(no_timestamps_token);
557 + }
558 +
559 + Ok(Self {
560 + model,
561 + rng: StdRng::seed_from_u64(299_792_458),
562 + tokenizer,
563 + mel_filters,
564 + language,
565 + is_multilingual,
566 + timestamps,
567 + task_tokens,
568 + suppress_tokens,
569 + sot_token,
570 + eot_token,
571 + no_speech_token,
572 + no_timestamps_token,
573 + })
574 + }
575 +
576 + fn decode(&mut self, mel: &Tensor, temperature: f64) -> anyhow::Result<DecodingResult> {
577 + let language_token = match (self.is_multilingual, &self.language) {
578 + (true, None) => Some(detect_language(&mut self.model, &self.tokenizer, mel)?),
579 + (false, None) => None,
580 + (true, Some(lang)) => {
581 + let tok = format!("<|{lang}|>");
582 + Some(token_id(&self.tokenizer, &tok).map_err(|_| {
583 + anyhow!("language '{lang}' is not supported by this model")
584 + })?)
585 + }
586 + (false, Some(_)) => {
587 + anyhow::bail!("language cannot be set for non-multilingual models")
588 + }
589 + };
590 +
591 + let audio_features = self.model.encoder_forward(mel, true)?;
592 + let sample_len = self.model.config().max_target_positions / 2;
593 +
594 + // Build the initial prompt token sequence:
595 + // [SOT, (language), task, (no_timestamps)]
596 + let mut tokens = vec![self.sot_token];
597 + if let Some(lang_tok) = language_token {
598 + tokens.push(lang_tok);
599 + }
600 + tokens.extend_from_slice(&self.task_tokens);
601 +
602 + let mut sum_logprob = 0f64;
603 + let mut no_speech_prob = f64::NAN;
604 +
605 + for i in 0..sample_len {
606 + let tokens_t = Tensor::new(tokens.as_slice(), mel.device())?.unsqueeze(0)?;
607 + let ys = self.model.decoder_forward(&tokens_t, &audio_features, i == 0)?;
608 +
609 + // Extract no-speech probability from the first decoder step.
610 + if i == 0 {
611 + let logits = self.model.decoder_final_linear(&ys.i(..1)?)?.i(0)?.i(0)?;
612 + no_speech_prob = softmax(&logits, 0)?
613 + .i(self.no_speech_token as usize)?
614 + .to_scalar::<f32>()? as f64;
615 + }
616 +
617 + let (_, seq_len, _) = ys.dims3()?;
618 + let logits = self
619 + .model
620 + .decoder_final_linear(&ys.i((..1, seq_len - 1..))?)?
621 + .i(0)?
622 + .i(0)?;
623 + let logits = logits.broadcast_add(&self.suppress_tokens)?;
624 +
625 + let next_token = if temperature > 0.0 {
626 + let prs = softmax(&(&logits / temperature)?, 0)?;
627 + let logits_v: Vec<f32> = prs.to_vec1()?;
628 + let distr = rand::distr::weighted::WeightedIndex::new(&logits_v)?;
629 + distr.sample(&mut self.rng) as u32
630 + } else {
631 + let logits_v: Vec<f32> = logits.to_vec1()?;
632 + logits_v
633 + .iter()
634 + .enumerate()
635 + .max_by(|(_, a), (_, b)| a.total_cmp(b))
636 + .map(|(i, _)| i as u32)
637 + .unwrap_or(self.eot_token)
638 + };
639 +
640 + if next_token == self.eot_token
641 + || tokens.len() > self.model.config().max_target_positions
642 + {
643 + break;
644 + }
645 +
646 + let prob = softmax(&logits, D::Minus1)?
647 + .i(next_token as usize)?
648 + .to_scalar::<f32>()? as f64;
649 + sum_logprob += prob.ln();
650 + tokens.push(next_token);
651 + }
652 +
653 + let text = self
654 + .tokenizer
655 + .decode(&tokens, true)
656 + .map_err(|e| anyhow!("{e}"))?;
657 + let avg_logprob = sum_logprob / tokens.len().max(1) as f64;
658 +
659 + Ok(DecodingResult {
660 + tokens,
661 + text,
662 + avg_logprob,
663 + no_speech_prob,
664 + compression_ratio: f64::NAN,
665 + })
666 + }
667 +
668 + fn decode_with_fallback(&mut self, segment: &Tensor) -> anyhow::Result<DecodingResult> {
669 + for (i, &t) in m::TEMPERATURES.iter().enumerate() {
670 + let result = self.decode(segment, t);
671 + if i == m::TEMPERATURES.len() - 1 {
672 + return result;
673 + }
674 + match result {
675 + Ok(dr) => {
676 + let needs_fallback = dr.compression_ratio > m::COMPRESSION_RATIO_THRESHOLD
677 + || dr.avg_logprob < m::LOGPROB_THRESHOLD;
678 + if !needs_fallback || dr.no_speech_prob > m::NO_SPEECH_THRESHOLD {
679 + return Ok(dr);
680 + }
681 + }
682 + Err(e) => cwarn!("decode at temperature {t} failed: {e}"),
683 + }
684 + }
685 + unreachable!()
686 + }
687 +
688 + fn run(&mut self, mel: &Tensor) -> anyhow::Result<Vec<Segment>> {
689 + let (_, _, content_frames) = mel.dims3()?;
690 + let mut seek = 0;
691 + let mut segments = vec![];
692 + while seek < content_frames {
693 + let time_offset = (seek * m::HOP_LENGTH) as f64 / m::SAMPLE_RATE as f64;
694 + let segment_size = usize::min(content_frames - seek, m::N_FRAMES);
695 + let mel_segment = mel.narrow(2, seek, segment_size)?;
696 + let segment_duration =
697 + (segment_size * m::HOP_LENGTH) as f64 / m::SAMPLE_RATE as f64;
698 + let dr = self.decode_with_fallback(&mel_segment)?;
699 + seek += segment_size;
700 + if dr.no_speech_prob > m::NO_SPEECH_THRESHOLD
701 + && dr.avg_logprob < m::LOGPROB_THRESHOLD
702 + {
703 + clog!("skipping silent segment at seek={seek}");
704 + continue;
705 + }
706 + clog!("segment [{:.1}s] {}", time_offset, dr.text.trim());
707 + segments.push(Segment {
708 + start: time_offset,
709 + end: time_offset + segment_duration,
710 + dr,
711 + });
712 + }
713 + Ok(segments)
714 + }
715 +}
716 +
717 +// ---------------------------------------------------------------------------
718 +// Segment — intermediate result per 30-second chunk
719 +// ---------------------------------------------------------------------------
720 +
721 +struct Segment {
722 + start: f64,
723 + end: f64,
724 + dr: DecodingResult,
725 +}
726 +
727 +// ---------------------------------------------------------------------------
728 +// Public JSON output types
729 +// ---------------------------------------------------------------------------
730 +
731 +#[derive(Serialize, Deserialize)]
732 +struct OndeSegment {
733 + start: f64,
734 + end: f64,
735 + text: String,
736 +}
737 +
738 +#[derive(Serialize, Deserialize)]
739 +struct OndeResult {
740 + text: String,
741 + segments: Vec<OndeSegment>,
742 +}
743 +
744 +// ---------------------------------------------------------------------------
745 +// WhisperDecoder — the public wasm-bindgen export
746 +// ---------------------------------------------------------------------------
747 +
748 +/// Whisper decoder bound to a pre-loaded set of model weights.
749 +///
750 +/// Construct once, then call `decode` for each audio clip.
751 +#[wasm_bindgen]
752 +pub struct WhisperDecoder {
753 + decoder: Decoder,
754 +}
755 +
756 +#[wasm_bindgen]
757 +impl WhisperDecoder {
758 + /// Construct a new `WhisperDecoder` from raw byte buffers.
759 + ///
760 + /// All four byte slices must stay alive for the duration of this call;
761 + /// they are consumed (weights are moved into the model, everything else
762 + /// is copied into small owned structures) and the originals are no
763 + /// longer needed once the constructor returns.
764 + ///
765 + /// # Arguments
766 + ///
767 + /// - `weights` — `model.safetensors` bytes, OR `.gguf` bytes when `quantized = true`
768 + /// - `tokenizer` — `tokenizer.json` bytes
769 + /// - `mel_filters` — `mel_filters.safetensors` bytes
770 + /// - `config` — `config.json` bytes
771 + /// - `quantized` — `true` when `weights` is a `.gguf` file
772 + /// - `is_multilingual` — `false` for `*.en` models
773 + /// - `timestamps` — include per-segment timestamps in the output
774 + /// - `task` — `"transcribe"` | `"translate"` | `null`
775 + /// - `language` — BCP-47 code (`"id"`, `"en"`, …) or `null` for auto-detect
776 + #[wasm_bindgen(constructor)]
777 + pub fn new(
778 + weights: &[u8],
779 + tokenizer: &[u8],
780 + mel_filters: &[u8],
781 + config: &[u8],
782 + quantized: bool,
783 + is_multilingual: bool,
784 + timestamps: bool,
785 + task: Option<String>,
786 + language: Option<String>,
787 + ) -> Result<WhisperDecoder, JsError> {
788 + set_panic_hook();
789 + Self::build(
790 + weights,
791 + tokenizer,
792 + mel_filters,
793 + config,
794 + quantized,
795 + is_multilingual,
796 + timestamps,
797 + task.as_deref(),
798 + language,
799 + )
800 + .map_err(|e| JsError::new(&e.to_string()))
801 + }
802 +
803 + fn build(
804 + weights: &[u8],
805 + tokenizer_bytes: &[u8],
806 + mel_filters_bytes: &[u8],
807 + config_bytes: &[u8],
808 + quantized: bool,
809 + is_multilingual: bool,
810 + timestamps: bool,
811 + task: Option<&str>,
812 + language: Option<String>,
813 + ) -> anyhow::Result<WhisperDecoder> {
814 + let device = Device::Cpu;
815 +
816 + // Tokenizer
817 + let tokenizer = Tokenizer::from_bytes(tokenizer_bytes)
818 + .map_err(|e| anyhow!("tokenizer load failed: {e}"))?;
819 + clog!("tokenizer loaded");
820 +
821 + // Mel filters — shape (n_mels, n_fft/2+1) stored as "mel_80" tensor
822 + let mel_st = safetensors::SafeTensors::deserialize(mel_filters_bytes)
823 + .map_err(|e| anyhow!("mel_filters load failed: {e}"))?;
824 + let mel_tensor = mel_st
825 + .tensor("mel_80")
826 + .map_err(|e| anyhow!("mel_80 tensor missing: {e}"))?
827 + .load(&device)?;
828 + let mel_filters = mel_tensor.flatten_all()?.to_vec1::<f32>()?;
829 + clog!("mel filters loaded: {:?}", mel_tensor.shape());
830 +
831 + // Config
832 + let config: Config = serde_json::from_slice(config_bytes)
833 + .map_err(|e| anyhow!("config.json parse failed: {e}"))?;
834 +
835 + // Model weights
836 + let model = if quantized {
837 + let vb =
838 + candle_transformers::quantized_var_builder::VarBuilder::from_gguf_buffer(
839 + weights,
840 + &device,
841 + )?;
842 + Model::Quantized(m::quantized_model::Whisper::load(&vb, config)?)
843 + } else {
844 + let vb = VarBuilder::from_buffered_safetensors(
845 + weights.to_vec(),
846 + m::DTYPE,
847 + &device,
848 + )?;
849 + Model::Normal(m::model::Whisper::load(&vb, config)?)
850 + };
851 + clog!("model loaded (quantized={quantized})");
852 +
853 + let decoder = Decoder::new(
854 + model,
855 + tokenizer,
856 + mel_filters,
857 + &device,
858 + task,
859 + language,
860 + is_multilingual,
861 + timestamps,
862 + )?;
863 +
864 + Ok(WhisperDecoder { decoder })
865 + }
866 +
867 + /// Decode a 16 kHz mono PCM WAV file.
868 + ///
869 + /// Returns a JSON string with shape `{ text, segments: [{start, end, text}] }`.
870 + pub fn decode(&mut self, wav_bytes: &[u8]) -> Result<String, JsError> {
871 + self.decode_inner(wav_bytes)
872 + .map_err(|e| JsError::new(&e.to_string()))
873 + }
874 +
875 + fn decode_inner(&mut self, wav_bytes: &[u8]) -> anyhow::Result<String> {
876 + let device = Device::Cpu;
877 +
878 + // Decode WAV
879 + let mut cursor = std::io::Cursor::new(wav_bytes);
880 + let reader = hound::WavReader::new(&mut cursor)?;
881 + let spec = reader.spec();
882 + clog!("wav: {spec:?}");
883 + if spec.sample_rate != m::SAMPLE_RATE as u32 {
884 + anyhow::bail!(
885 + "expected {}Hz WAV, got {}Hz — please resample before passing to decode()",
886 + m::SAMPLE_RATE,
887 + spec.sample_rate
888 + );
889 + }
890 +
891 + // Read samples, take only the first channel if stereo
892 + let raw: Vec<_> = reader.into_samples::<i16>().collect::<hound::Result<Vec<_>>>()?;
893 + let mono: Vec<f32> = raw
894 + .chunks(spec.channels as usize)
895 + .map(|ch| ch[0] as f32 / 32768.0)
896 + .collect();
897 + clog!("pcm samples: {}", mono.len());
898 +
899 + // Build mel spectrogram tensor (shape: [1, n_mels, n_frames])
900 + let cfg = self.decoder.model.config();
901 + let mel = pcm_to_mel(cfg, &mono, &self.decoder.mel_filters)?;
902 + let mel_len = mel.len();
903 + let n_mels = cfg.num_mel_bins;
904 + let mel_t = Tensor::from_vec(mel, (1, n_mels, mel_len / n_mels), &device)?;
905 + clog!("mel tensor: {:?}", mel_t.dims());
906 +
907 + // Run the sliding-window decoder
908 + let segments = self.decoder.run(&mel_t)?;
909 +
910 + // Build output
911 + let mut full_text = String::new();
912 + let mut out_segments = Vec::with_capacity(segments.len());
913 + for seg in &segments {
914 + if !full_text.is_empty() && !seg.dr.text.starts_with(' ') {
915 + full_text.push(' ');
916 + }
917 + full_text.push_str(seg.dr.text.trim());
918 + out_segments.push(OndeSegment {
919 + start: seg.start,
920 + end: seg.end,
921 + text: seg.dr.text.trim().to_string(),
922 + });
923 + }
924 +
925 + let result = OndeResult {
926 + text: full_text,
927 + segments: out_segments,
928 + };
929 + Ok(serde_json::to_string(&result)?)
930 + }
931 +}
docs/README.md new
+72
@@ -0,0 +1,72 @@
1 +# Onde Docs
2 +
3 +Source for the [Onde documentation site](https://ondeinference.com/docs), built with [Mintlify](https://mintlify.com).
4 +
5 +## Structure
6 +
7 +```
8 +docs/
9 +├── mint.json # Mintlify site config — navigation, colors, logo
10 +├── index.md # Landing page → /docs
11 +├── dev.md # Developer guide → /docs/dev
12 +├── swift-package.md # Swift Package guide → /docs/swift-package
13 +├── ruby-gem.md # Ruby Gem guide → /docs/ruby-gem
14 +└── distribution.md # Publishing guide → /docs/distribution
15 +```
16 +
17 +## Local Preview
18 +
19 +Install the Mintlify CLI:
20 +
21 +```bash
22 +npm install -g mintlify
23 +```
24 +
25 +Start the dev server from the `docs/` directory:
26 +
27 +```bash
28 +cd docs
29 +mintlify dev
30 +```
31 +
32 +The site is served at `http://localhost:3000`.
33 +
34 +## Deployment
35 +
36 +The docs deploy automatically via the [Mintlify GitHub App](https://github.com/apps/mintlify).
37 +
38 +1. Install the Mintlify GitHub App on the `ondeinference/onde` repository.
39 +2. In the Mintlify dashboard, set the docs directory to `docs/` and the base path to `/docs`.
40 +3. Every push to `main` triggers a redeploy.
41 +
42 +The custom domain is configured in the Mintlify dashboard:
43 +
44 +- Domain: `ondeinference.com`
45 +- Path: `/docs`
46 +
47 +## Adding a Page
48 +
49 +1. Create a new `.md` file in `docs/`.
50 +2. Add a YAML frontmatter block at the top:
51 + ```yaml
52 + ---
53 + title: "Page Title"
54 + description: "One-sentence description shown in search and link previews."
55 + ---
56 + ```
57 +3. Add the filename (without `.md`) to the appropriate group in `mint.json` under `navigation`.
58 +
59 +## Frontmatter Fields
60 +
61 +| Field | Required | Description |
62 +| ----- | -------- | ----------- |
63 +| `title` | Yes | Page title shown in the browser tab and sidebar |
64 +| `description` | Yes | Meta description for search and link previews |
65 +| `sidebarTitle` | No | Override the sidebar label (defaults to `title`) |
66 +
67 +## Content Guidelines
68 +
69 +- Write for developers who are evaluating or integrating Onde — assume Rust familiarity, not deep familiarity with the project.
70 +- Code blocks must specify a language for syntax highlighting (` ```swift `, ` ```rust `, ` ```bash `, etc.).
71 +- Cross-links between pages omit the `.md` extension: `[Swift Package](swift-package)`, not `[Swift Package](swift-package.md)`.
72 +- Keep internal/contributor notes (build internals, pitfalls, architecture deep-dives) in the `.agent-skills/` directory, not in `docs/`.
\ No newline at end of file
docs/dev.md new
+210
@@ -0,0 +1,210 @@
1 +---
2 +title: "Developer Guide"
3 +description: "Build Onde from source, understand the architecture, and integrate it as a Rust dependency."
4 +sidebarTitle: "Developer Guide"
5 +---
6 +
7 +# Onde — Developer Guide
8 +
9 +> **See also:** [Swift Package](swift-package) · [Ruby Gem](ruby-gem) · [Distribution](distribution)
10 +
11 +## Prerequisites
12 +
13 +```bash
14 +# Rust stable
15 +rustup toolchain install stable
16 +
17 +# Rust nightly (only needed for tvOS tier-3 targets with -Z build-std)
18 +rustup toolchain install nightly
19 +rustup component add rust-src --toolchain nightly
20 +
21 +# iOS targets (stable)
22 +rustup target add aarch64-apple-ios aarch64-apple-ios-sim
23 +```
24 +
25 +## Building
26 +
27 +### Native (macOS — Metal accelerated)
28 +
29 +```bash
30 +# Check compilation
31 +cargo check
32 +
33 +# Run all tests
34 +cargo test
35 +
36 +# Clippy lint
37 +cargo clippy
38 +```
39 +
40 +### Ruby Gem (magnus)
41 +
42 +Build the Ruby native extension that exposes Onde's HuggingFace cache management and model metadata to Ruby via [magnus](https://github.com/matsadler/magnus):
43 +
44 +```bash
45 +cd sdk/gem
46 +
47 +# Install Ruby dependencies + compile the Rust native extension
48 +bin/setup
49 +
50 +# Or step by step:
51 +bundle install
52 +bundle exec rake compile
53 +
54 +# Interactive console
55 +bin/console
56 +```
57 +
58 +Verify it works:
59 +
60 +```bash
61 +bundle exec ruby -e "require 'onde'; puts Onde::VERSION; puts Onde::SUPPORTED_MODELS"
62 +```
63 +
64 +For full API reference, usage examples, and architecture details, see [ruby-gem](ruby-gem).
65 +
66 +## Architecture
67 +
68 +```
69 +onde/
70 +├── src/
71 +│ ├── lib.rs # Crate root — uniffi::setup_scaffolding!()
72 +│ ├── hf_cache.rs # HuggingFace Hub cache management
73 +│ ├── whisper.rs # Whisper STT (feature-gated: "whisper")
74 +│ └── inference/
75 +│ ├── mod.rs # Module exports + re-exports
76 +│ ├── types.rs # UniFFI-annotated shared types
77 +│ ├── engine.rs # ChatEngine (Rust-native API)
78 +│ ├── ffi.rs # OndeChatEngine (UniFFI Object for Swift/Kotlin)
79 +│ ├── models.rs # Model ID constants + metadata
80 +│ └── token.rs # HF token resolution (build-time / cache)
81 +├── sdk/
82 +│ ├── Onde/ # Generated Swift package (git-ignored)
83 +│ ├── gem/ # Ruby gem (magnus-based native extension)
84 +│ ├── kotlin/ # Kotlin bindings
85 +│ └── python/ # Python bindings
86 +├── generated/ # UniFFI-generated headers and sources
87 +├── .cargo/
88 +│ └── config.toml # Target-specific rustflags (fp16)
89 +├── Cargo.toml # Platform-conditional mistralrs deps
90 +├── build.rs # UniFFI scaffolding + tvOS chkstk stub
91 +├── uniffi.toml # UniFFI binding config
92 +└── docs/
93 + ├── dev.md # This file
94 + ├── swift-package.md # Swift package building & API guide
95 + └── ruby-gem.md # Ruby gem API reference & guide
96 +```
97 +
98 +### Layer Diagram
99 +
100 +```
101 +┌──────────────────────────────────────────────────────┐
102 +│ Swift (tvOS / iOS) Rust app / CLI / server │
103 +│ import Onde use onde::inference::* │
104 +└──────────┬───────────────────────────┬───────────────┘
105 + │ UniFFI bindings │ Direct Rust API
106 + ▼ ▼
107 +┌──────────────────────┐ ┌────────────────────────────┐
108 +│ OndeChatEngine │ │ ChatEngine │
109 +│ (ffi.rs — Object) │──│ (engine.rs — native) │
110 +│ FFI-safe methods │ │ impl Into<String>, mpsc │
111 +└──────────┬───────────┘ └────────────┬───────────────┘
112 + │ │
113 + └───────────┬───────────────┘
114 + ▼
115 + ┌───────────────────────┐
116 + │ mistralrs::Model │
117 + │ (GgufModelBuilder) │
118 + │ Metal / CUDA / CPU │
119 + └───────────────────────┘
120 +```
121 +
122 +## Platform Support
123 +
124 +| Platform | `target_os` | GPU Backend | Default Model | Dependency |
125 +| -------- | ----------- | ----------------- | -------------- | -------------------------------- |
126 +| macOS | `macos` | Metal | Qwen 2.5 3B | mistralrs `features = ["metal"]` |
127 +| iOS | `ios` | Metal | Qwen 2.5 1.5B | mistralrs `features = ["metal"]` |
128 +| tvOS | `tvos` | Metal | Qwen 2.5 1.5B | mistralrs `features = ["metal"]` |
129 +| Windows | `windows` | CPU (CUDA via CI) | Qwen 2.5 3B | mistralrs (no features) |
130 +| Linux | `linux` | CPU (CUDA via CI) | Qwen 2.5 3B | mistralrs (no features) |
131 +| Android | `android` | CPU (candle) | Qwen 2.5 1.5B | mistralrs + mistralrs-core |
132 +
133 +## Testing
134 +
135 +```bash
136 +# All tests
137 +cargo test
138 +
139 +# Just inference module tests
140 +cargo test inference::
141 +
142 +# Just FFI wrapper tests
143 +cargo test inference::ffi::
144 +
145 +# Just type tests
146 +cargo test inference::types::
147 +
148 +# Clippy
149 +cargo clippy
150 +```
151 +
152 +## Using Onde as a Rust Dependency
153 +
154 +Add onde as a dependency in your `Cargo.toml`:
155 +
156 +```toml
157 +[dependencies]
158 +onde = { path = "../../onde" } # adjust relative path to your layout
159 +# or from git:
160 +# onde = { git = "https://github.com/ondeinference/onde" }
161 +```
162 +
163 +The Rust API is accessed directly — no UniFFI needed:
164 +
165 +```rust
166 +use onde::mistralrs::{GgufModelBuilder, Model, RequestBuilder, TextMessageRole};
167 +use onde::inference::token::hf_token_source;
168 +
169 +// Load model
170 +let model = GgufModelBuilder::new("bartowski/Qwen2.5-1.5B-Instruct-GGUF", vec!["Qwen2.5-1.5B-Instruct-Q4_K_M.gguf"])
171 + .with_token_source(hf_token_source())
172 + .with_logging()
173 + .build()
174 + .await?;
175 +
176 +// Chat
177 +let request = RequestBuilder::new()
178 + .add_message(TextMessageRole::System, "You are a helpful assistant.")
179 + .add_message(TextMessageRole::User, "Hello!")
180 + .set_sampler_temperature(0.7);
181 +
182 +let response = model.send_chat_request(request).await?;
183 +```
184 +
185 +### Important Setup for Sandboxed Apps (iOS / macOS App Store)
186 +
187 +Your app's setup function must configure `HF_HOME` and `TMPDIR` before any inference code runs. See the [pepakbasajawa](https://github.com/pfrfrfr/pepakbasajawa) or [fatapp](https://github.com/setoelkahfi/fatapp) repos for working examples of the `setup_hf_home()` and `setup_tmpdir()` pattern.
188 +
189 +## Known Issues
190 +
191 +### `___chkstk_darwin` linker error on tvOS
192 +
193 +When building for `aarch64-apple-tvos`, `aws-lc-sys` (a transitive dependency via `rustls` → `reqwest` → `hf-hub`) references `___chkstk_darwin`, a stack probing symbol not available on tvOS. The onde `build.rs` provides a no-op assembly stub (`tvos_chkstk.s`) that resolves this automatically.
194 +
195 +This does not affect macOS, iOS, Windows, Linux, or Android builds.
196 +
197 +### Metal Toolchain must be installed (Xcode 26+)
198 +
199 +On Xcode 26+, the Metal compiler is a separate downloadable component. If you see empty `.metallib` files (92 bytes) or `"Error while loading function: fused_glu_float"` at runtime, run:
200 +
201 +```bash
202 +xcodebuild -downloadComponent MetalToolchain
203 +```
204 +
205 +Then clean and rebuild:
206 +
207 +```bash
208 +cargo clean -p mistralrs-quant
209 +cargo check
210 +```
docs/distribution.md new
+205
@@ -0,0 +1,205 @@
1 +---
2 +title: "Distribution"
3 +description: "How Onde is distributed across package registries — crates.io, Swift Package Index, PyPI, RubyGems, and Maven Central."
4 +---
5 +
6 +# Distribution
7 +
8 +Onde is published to every major package registry under a consistent naming convention:
9 +
10 +| Registry | Package name | Namespace |
11 +| -------- | ------------ | --------- |
12 +| crates.io | `onde` | — |
13 +| Swift Package Index | `onde-swift` | `ondeinference` |
14 +| PyPI | `onde-inference` | — |
15 +| RubyGems | `onde-inference` | — |
16 +| Maven Central | `onde-inference` | `com.ondeinference` |
17 +
18 +**Naming rules:**
19 +- Registries with a namespace → `ondeinference` / `onde`
20 +- Registries without a namespace → `onde-inference` (hyphenated) to avoid conflicts
21 +- Swift follows Apple conventions → PascalCase package name (`Onde`), kebab-case repo slug (`onde-swift`)
22 +- The Rust crate uses the bare `onde` name on crates.io
23 +
24 +---
25 +
26 +## Rust — crates.io
27 +
28 +The core Rust crate is published as [`onde`](https://crates.io/crates/onde).
29 +
30 +```toml
31 +[dependencies]
32 +onde = "0.1"
33 +```
34 +
35 +Publish:
36 +
37 +```bash
38 +cargo publish
39 +```
40 +
41 +---
42 +
43 +## Swift — Swift Package Index
44 +
45 +The Swift package is distributed from a dedicated public repository [`ondeinference/onde-swift`](https://github.com/ondeinference/onde-swift) as a remote binary package. The `OndeFramework.xcframework` is attached as a GitHub Release asset; `Package.swift` references it by URL and SHA-256 checksum.
46 +
47 +Swift Package Index indexes the `onde-swift` repository automatically on every new Git tag.
48 +
49 +### Installation
50 +
51 +In Xcode: **File → Add Package Dependencies** and enter:
52 +
53 +```
54 +https://github.com/ondeinference/onde-swift
55 +```
56 +
57 +Or in `Package.swift`:
58 +
59 +```swift
60 +dependencies: [
61 + .package(url: "https://github.com/ondeinference/onde-swift", from: "0.1.0")
62 +]
63 +```
64 +
65 +### Release process
66 +
67 +1. Build `OndeFramework.xcframework` from Rust source (see [Swift Package](swift-package#building-the-xcframework-locally)).
68 +2. Zip it and compute the checksum:
69 + ```bash
70 + zip -r OndeFramework.xcframework.zip OndeFramework.xcframework
71 + shasum -a 256 OndeFramework.xcframework.zip
72 + ```
73 +3. Create a GitHub Release on the Rust source repo and attach the zip as a release asset.
74 +4. In `onde-swift`, update `Package.swift` with the new `url:` and `checksum:`.
75 +5. Commit, tag the version (`0.1.0`, `0.2.0`, etc.), and push — SPI picks it up automatically.
76 +
77 +---
78 +
79 +## Python — PyPI
80 +
81 +The Python package is published as [`onde-inference`](https://pypi.org/project/onde-inference) and imported as `onde_inference`. It uses [maturin](https://github.com/PyO3/maturin) with `bindings = "uniffi"` to generate Python bindings from the same UniFFI scaffolding used for Swift and Kotlin.
82 +
83 +### Installation
84 +
85 +```bash
86 +pip install onde-inference
87 +```
88 +
89 +### Usage
90 +
91 +```python
92 +import asyncio
93 +from onde_inference import OndeChatEngine, default_model_config
94 +
95 +async def main():
96 + engine = OndeChatEngine()
97 + await engine.load_default_model(
98 + system_prompt="You are a helpful assistant.",
99 + sampling=None,
100 + )
101 + result = await engine.send_message("Hello!")
102 + print(result.text)
103 +
104 +asyncio.run(main())
105 +```
106 +
107 +### Prerequisites
108 +
109 +- Python 3.9+
110 +- `maturin >= 1.7` — `uv tool install maturin` or `pip install maturin`
111 +- `uniffi-bindgen == 0.31.0` — must match the `uniffi` version pinned in `Cargo.toml`
112 +
113 + ```bash
114 + pip install uniffi-bindgen==0.31.0
115 + ```
116 +
117 +### Build
118 +
119 +```bash
120 +cd sdk/python
121 +
122 +# Build a release wheel for the current platform
123 +maturin build --release --out dist
124 +
125 +# Development install into the current venv
126 +maturin develop
127 +```
128 +
129 +### Publish
130 +
131 +```bash
132 +cd sdk/python
133 +maturin publish
134 +```
135 +
136 +To publish wheels for all platforms, run `maturin publish` on each platform in CI and pass `--skip-existing` so subsequent uploads don't fail. Platforms to cover:
137 +
138 +- macOS: `aarch64-apple-darwin`, `x86_64-apple-darwin`
139 +- Linux: `x86_64-unknown-linux-gnu`, `aarch64-unknown-linux-gnu`
140 +- Windows: `x86_64-pc-windows-msvc`
141 +
142 +---
143 +
144 +## Ruby — RubyGems
145 +
146 +The Ruby gem is published as [`onde-inference`](https://rubygems.org/gems/onde-inference) and required as `onde`. It is a [Magnus](https://github.com/matsadler/magnus)-based native extension exposing Onde's HuggingFace cache management and model metadata to Ruby.
147 +
148 +See the [Ruby Gem guide](ruby-gem) for full API reference and Rails integration examples.
149 +
150 +### Installation
151 +
152 +```bash
153 +gem install onde-inference
154 +```
155 +
156 +Or in your `Gemfile`:
157 +
158 +```ruby
159 +gem "onde-inference"
160 +```
161 +
162 +### Publish
163 +
164 +```bash
165 +cd sdk/gem
166 +bundle exec rake compile # build the native extension
167 +gem build onde-inference.gemspec
168 +gem push onde-inference-*.gem
169 +```
170 +
171 +---
172 +
173 +## Kotlin / Android — Maven Central
174 +
175 +The Kotlin Android library is published as `com.ondeinference:onde-inference` on Maven Central.
176 +
177 +### Installation
178 +
179 +In `build.gradle.kts`:
180 +
181 +```kotlin
182 +dependencies {
183 + implementation("com.ondeinference:onde-inference:0.1.0")
184 +}
185 +```
186 +
187 +### Build
188 +
189 +The Android library is built with `build-kotlin.sh` at the crate root. It cross-compiles `libonde.so` for all four Android ABIs and generates Kotlin bindings via `uniffi-bindgen`:
190 +
191 +```bash
192 +# Full release build for all Android ABIs
193 +./build-kotlin.sh
194 +
195 +# arm64 only (faster for development)
196 +./build-kotlin.sh --target aarch64-linux-android
197 +```
198 +
199 +Then assemble and publish the AAR from the Android project:
200 +
201 +```bash
202 +cd sdk/kotlin
203 +./gradlew :onde:assembleRelease
204 +./gradlew publishReleasePublicationToMavenCentralRepository
205 +```
docs/index.md new
+95
@@ -0,0 +1,95 @@
1 +---
2 +title: "Onde"
3 +description: "On-device AI inference for every platform. Run LLMs, speech-to-text, and image generation locally — no cloud, no latency, no data leaving the device."
4 +---
5 +
6 +# Onde
7 +
8 +**On-device AI inference for every platform.**
9 +
10 +Run LLMs, speech-to-text, and image generation locally — no cloud, no latency, no data leaving the device. Onde wraps [mistral.rs](https://github.com/EricLBuehler/mistral.rs) for LLM and image generation, and [whisper.cpp](https://github.com/ggerganov/whisper.cpp) for speech-to-text, with a unified API that handles model discovery, HuggingFace Hub downloads, cache management, and GPU acceleration across every platform.
11 +
12 +## Platforms
13 +
14 +| Platform | GPU Backend | Default Model |
15 +| -------- | ----------- | ------------- |
16 +| macOS | Metal | Qwen 2.5 3B |
17 +| iOS | Metal | Qwen 2.5 1.5B |
18 +| tvOS | Metal | Qwen 2.5 1.5B |
19 +| Android | CPU (candle) | Qwen 2.5 1.5B |
20 +| Windows | CPU / CUDA | Qwen 2.5 3B |
21 +| Linux | CPU / CUDA | Qwen 2.5 3B |
22 +
23 +## SDKs
24 +
25 +| Language | Package | Install |
26 +| -------- | ------- | ------- |
27 +| Rust | [`onde`](https://crates.io/crates/onde) | `onde = "0.1"` in Cargo.toml |
28 +| Swift | [`onde-swift`](https://github.com/ondeinference/onde-swift) | Swift Package Manager |
29 +| Kotlin | [`onde-inference`](https://central.sonatype.com/) | Gradle |
30 +| Python | [`onde-inference`](https://pypi.org/project/onde-inference) | `pip install onde-inference` |
31 +| Ruby | [`onde-inference`](https://rubygems.org/gems/onde-inference) | `gem install onde-inference` |
32 +
33 +## Quick Start
34 +
35 +### Swift (iOS / tvOS / macOS)
36 +
37 +```swift
38 +import Onde
39 +
40 +let engine = OndeChatEngine()
41 +try await engine.loadDefaultModel(systemPrompt: "You are a helpful assistant.", sampling: nil)
42 +
43 +let result = try await engine.sendMessage(message: "Hello!")
44 +print(result.text)
45 +```
46 +
47 +### Rust
48 +
49 +```rust
50 +use onde::inference::{ChatEngine, GgufModelConfig};
51 +
52 +let engine = ChatEngine::new();
53 +engine.load_gguf_model(
54 + GgufModelConfig::platform_default(),
55 + Some("You are a helpful assistant.".into()),
56 + None,
57 +).await?;
58 +
59 +let reply = engine.send_message("Hello!").await?;
60 +println!("{}", reply.text);
61 +```
62 +
63 +### Python
64 +
65 +```python
66 +import asyncio
67 +from onde_inference import OndeChatEngine
68 +
69 +async def main():
70 + engine = OndeChatEngine()
71 + await engine.load_default_model(system_prompt="You are a helpful assistant.", sampling=None)
72 + result = await engine.send_message("Hello!")
73 + print(result.text)
74 +
75 +asyncio.run(main())
76 +```
77 +
78 +## Guides
79 +
80 +- [Developer Guide](dev) — build from source, architecture overview, platform support
81 +- [Swift Package](swift-package) — XCFramework distribution, Swift API reference
82 +- [Ruby Gem](ruby-gem) — Magnus-based native extension, Rails integration
83 +- [Distribution](distribution) — publishing to crates.io, Swift Package Index, PyPI, RubyGems, Maven Central
84 +
85 +## Design Principles
86 +
87 +**Zero framework coupling.** Onde knows nothing about any app framework. Progress updates use plain callbacks — wire them to whatever event system you use.
88 +
89 +**Platform-aware by default.** GPU backend, model size, cache directory — Onde picks the right defaults so you don't configure per-platform.
90 +
91 +**One dependency.** Add `onde` and get LLM inference, speech-to-text, image generation, HuggingFace cache management, and HF token resolution in a single crate.
92 +
93 +## License
94 +
95 +Licensed under either of [MIT](https://opensource.org/licenses/MIT) or [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) at your option.
\ No newline at end of file
docs/mint.json new
+77
@@ -0,0 +1,77 @@
1 +{
2 + "$schema": "https://mintlify.com/schema.json",
3 + "name": "Onde",
4 + "logo": {
5 + "light": "/logo/light.svg",
6 + "dark": "/logo/dark.svg",
7 + "href": "https://ondeinference.com"
8 + },
9 + "favicon": "/favicon.svg",
10 + "colors": {
11 + "primary": "#0F172A",
12 + "light": "#38BDF8",
13 + "dark": "#0F172A"
14 + },
15 + "topbarLinks": [
16 + {
17 + "name": "GitHub",
18 + "url": "https://github.com/ondeinference/onde"
19 + }
20 + ],
21 + "topbarCtaButton": {
22 + "name": "Get Started",
23 + "url": "/docs"
24 + },
25 + "anchors": [
26 + {
27 + "name": "crates.io",
28 + "icon": "box",
29 + "url": "https://crates.io/crates/onde"
30 + },
31 + {
32 + "name": "docs.rs",
33 + "icon": "book",
34 + "url": "https://docs.rs/onde"
35 + },
36 + {
37 + "name": "GitHub",
38 + "icon": "github",
39 + "url": "https://github.com/ondeinference/onde"
40 + }
41 + ],
42 + "navigation": [
43 + {
44 + "group": "Getting Started",
45 + "pages": [
46 + "index",
47 + "dev"
48 + ]
49 + },
50 + {
51 + "group": "SDKs",
52 + "pages": [
53 + "swift-package",
54 + "ruby-gem"
55 + ]
56 + },
57 + {
58 + "group": "Publishing",
59 + "pages": [
60 + "distribution"
61 + ]
62 + }
63 + ],
64 + "footerSocials": {
65 + "github": "https://github.com/ondeinference/onde",
66 + "website": "https://ondeinference.com"
67 + },
68 + "feedback": {
69 + "thumbsRating": true,
70 + "suggestEdit": true,
71 + "raiseIssue": true
72 + },
73 + "modeToggle": {
74 + "default": "dark"
75 + },
76 + "tabs": []
77 +}
docs/ruby-gem.md new
+640
@@ -0,0 +1,640 @@
1 +---
2 +title: "Ruby Gem"
3 +description: "Build and use the onde-inference Ruby gem — a Magnus-based native extension exposing HuggingFace cache management and model metadata to Ruby."
4 +---
5 +
6 +# Onde Ruby Gem
7 +
8 +Ruby bindings for the [Onde](https://ondeinference.com) on-device inference engine, powered by Rust via [magnus](https://github.com/matsadler/magnus).
9 +
10 +Manage HuggingFace model caches, inspect supported models, and access inference configuration — all from Ruby with native Rust performance.
11 +
12 +## Prerequisites
13 +
14 +- **Ruby** >= 3.0
15 +- **Rust** >= 1.92 (installed via [rustup](https://rustup.rs))
16 +- **Bundler** (`gem install bundler`)
17 +- macOS, Linux, or Windows
18 +
19 +The gem compiles a native Rust extension at install time. Rust must be available on your `$PATH`.
20 +
21 +## Setup
22 +
23 +```bash
24 +cd lib/crates/onde/gem
25 +
26 +# Install Ruby dependencies and compile the Rust native extension
27 +bin/setup
28 +
29 +# Or step by step:
30 +bundle install
31 +bundle exec rake compile
32 +```
33 +
34 +### Verify the installation
35 +
36 +```bash
37 +bundle exec ruby -e "require 'onde'; puts Onde::VERSION"
38 +# => 0.1.0
39 +```
40 +
41 +### Interactive console
42 +
43 +```bash
44 +bin/console
45 +```
46 +
47 +Opens an IRB session with the gem pre-loaded. Useful for exploring the API:
48 +
49 +```ruby
50 +irb> Onde::SUPPORTED_MODELS
51 +=> ["black-forest-labs/FLUX.1-schnell", "google/gemma-3n-E2B-it", ...]
52 +
53 +irb> Onde.cache_path
54 +=> "/Users/you/.cache/huggingface/hub"
55 +```
56 +
57 +## Build Commands
58 +
59 +| Command | Description |
60 +|---------|-------------|
61 +| `bundle exec rake compile` | Compile the Rust native extension (release profile) |
62 +| `bundle exec rake compile:dev` | Compile with debug profile (faster builds, slower runtime) |
63 +| `bundle exec rake build` | Build the `.gem` package |
64 +| `bundle exec rake` | Default task — compiles the extension |
65 +| `bin/setup` | One-step: `bundle install` + `rake compile` |
66 +| `bin/console` | IRB with the gem loaded |
67 +
68 +## API Reference
69 +
70 +### Cache Management
71 +
72 +#### `Onde.list_local_models` → Hash
73 +
74 +Scans the local HuggingFace hub cache (`~/.cache/huggingface/hub/`) and returns all downloaded models that the inference engine supports.
75 +
76 +```ruby
77 +response = Onde.list_local_models
78 +
79 +response["cache_path"] # => "/Users/you/.cache/huggingface/hub"
80 +response["total_size_bytes"] # => 24768454656
81 +response["total_size_display"] # => "23.07 GB"
82 +
83 +response["models"].each do |model|
84 + puts "#{model["model_id"]} — #{model["size_display"]}"
85 + puts " Path: #{model["path"]}"
86 + puts " Revisions: #{model["revisions"].join(", ")}"
87 +end
88 +```
89 +
90 +**Return value keys:**
91 +
92 +| Key | Type | Description |
93 +|-----|------|-------------|
94 +| `cache_path` | String | Absolute path that was scanned |
95 +| `total_size_bytes` | Integer | Total size of all cached models |
96 +| `total_size_display` | String | Human-readable total size (e.g. `"23.07 GB"`) |
97 +| `models` | Array | Array of model Hashes (see below) |
98 +
99 +**Each model Hash:**
100 +
101 +| Key | Type | Description |
102 +|-----|------|-------------|
103 +| `model_id` | String | Full HuggingFace ID (e.g. `"bartowski/Qwen2.5-1.5B-Instruct-GGUF"`) |
104 +| `org` | String | Organisation or publisher |
105 +| `name` | String | Model name without org prefix |
106 +| `size_bytes` | Integer | Total size on disk in bytes |
107 +| `size_display` | String | Human-readable size (e.g. `"1.84 GB"`) |
108 +| `path` | String | Absolute path to the model cache directory |
109 +| `revisions` | Array | List of snapshot revision strings |
110 +
111 +---
112 +
113 +#### `Onde.list_supported_models` → Hash
114 +
115 +Returns all models the engine supports, together with flags indicating whether each one is fully downloaded, partially downloaded, or absent.
116 +
117 +```ruby
118 +Onde.list_supported_models["models"].each do |m|
119 + status = if m["is_downloaded"]
120 + "✓ downloaded"
121 + elsif m["is_incomplete"]
122 + "⏳ incomplete (#{m["local_size_display"]} / #{m["expected_size_display"]})"
123 + else
124 + "✗ not downloaded"
125 + end
126 + puts "[#{status}] #{m["name"]} (#{m["org"]})"
127 + puts " #{m["description"]}"
128 +end
129 +```
130 +
131 +**Each model Hash:**
132 +
133 +| Key | Type | Description |
134 +|-----|------|-------------|
135 +| `model_id` | String | Full HuggingFace ID |
136 +| `name` | String | Human-friendly display name |
137 +| `org` | String | Organisation or publisher |
138 +| `description` | String | Short description of the model |
139 +| `is_downloaded` | Boolean | Fully downloaded locally |
140 +| `is_incomplete` | Boolean | Partial download exists on disk |
141 +| `local_size_bytes` | Integer | Bytes currently on disk (0 if absent) |
142 +| `local_size_display` | String | Human-readable local size |
143 +| `expected_size_bytes` | Integer | Approximate total size when fully downloaded |
144 +| `expected_size_display` | String | Human-readable expected size |
145 +
146 +---
147 +
148 +#### `Onde.delete_model(model_id)` → nil
149 +
150 +Delete a locally cached HuggingFace model by removing its directory from the hub cache.
151 +
152 +```ruby
153 +Onde.delete_model("bartowski/Qwen2.5-1.5B-Instruct-GGUF")
154 +```
155 +
156 +**Parameters:**
157 +
158 +| Name | Type | Description |
159 +|------|------|-------------|
160 +| `model_id` | String | Full model identifier (e.g. `"black-forest-labs/FLUX.1-schnell"`) |
161 +
162 +**Raises:** `RuntimeError` if the model is not found or deletion fails.
163 +
164 +---
165 +
166 +#### `Onde.cache_path` → String or nil
167 +
168 +Returns the resolved HuggingFace cache directory path, or `nil` if it cannot be determined (e.g. `$HOME` is unset).
169 +
170 +```ruby
171 +Onde.cache_path
172 +# => "/Users/you/.cache/huggingface/hub"
173 +```
174 +
175 +---
176 +
177 +### Model Metadata
178 +
179 +#### `Onde.model_info(model_id)` → Hash or nil
180 +
181 +Look up rich metadata for a single supported model. Returns `nil` if the model ID is not in the supported list.
182 +
183 +```ruby
184 +info = Onde.model_info("bartowski/Qwen2.5-1.5B-Instruct-GGUF")
185 +# => {
186 +# "id" => "bartowski/Qwen2.5-1.5B-Instruct-GGUF",
187 +# "name" => "Qwen 2.5 1.5B (GGUF)",
188 +# "org" => "Qwen / Alibaba",
189 +# "description" => "Lightest pre-quantized chat model — ...",
190 +# "expected_size_bytes" => 986048768
191 +# }
192 +
193 +Onde.model_info("nonexistent/model")
194 +# => nil
195 +```
196 +
197 +**Return value keys:**
198 +
199 +| Key | Type | Description |
200 +|-----|------|-------------|
201 +| `id` | String | Full HuggingFace model identifier |
202 +| `name` | String | Human-friendly display name |
203 +| `org` | String | Organisation or publisher |
204 +| `description` | String | Short description |
205 +| `expected_size_bytes` | Integer | Approximate total size in bytes |
206 +
207 +---
208 +
209 +#### `Onde.supported_model_ids` → Array
210 +
211 +Returns the list of all supported model IDs as strings.
212 +
213 +```ruby
214 +Onde.supported_model_ids
215 +# => [
216 +# "black-forest-labs/FLUX.1-schnell",
217 +# "google/gemma-3n-E2B-it",
218 +# "google/gemma-3n-E4B-it",
219 +# "microsoft/Phi-3.5-mini-instruct",
220 +# "bartowski/Qwen2.5-1.5B-Instruct-GGUF",
221 +# "bartowski/Qwen2.5-3B-Instruct-GGUF"
222 +# ]
223 +```
224 +
225 +---
226 +
227 +### Sampling Configuration
228 +
229 +These methods return Hash representations of the inference sampling parameters. They are useful for inspecting defaults or passing to future inference APIs.
230 +
231 +#### `Onde.default_sampling_config` → Hash
232 +
233 +Creative chat defaults.
234 +
235 +```ruby
236 +Onde.default_sampling_config
237 +# => {
238 +# "temperature" => 0.7,
239 +# "top_p" => 0.95,
240 +# "top_k" => nil,
241 +# "min_p" => nil,
242 +# "max_tokens" => 512,
243 +# "frequency_penalty" => nil,
244 +# "presence_penalty" => nil
245 +# }
246 +```
247 +
248 +#### `Onde.deterministic_sampling_config` → Hash
249 +
250 +Greedy decoding (temperature = 0.0).
251 +
252 +```ruby
253 +Onde.deterministic_sampling_config
254 +# => { "temperature" => 0.0, "top_p" => nil, ..., "max_tokens" => 512 }
255 +```
256 +
257 +#### `Onde.mobile_sampling_config` → Hash
258 +
259 +Conservative defaults for constrained devices (lower `max_tokens`).
260 +
261 +```ruby
262 +Onde.mobile_sampling_config
263 +# => { "temperature" => 0.7, "top_p" => 0.95, ..., "max_tokens" => 128 }
264 +```
265 +
266 +---
267 +
268 +### Constants
269 +
270 +| Constant | Type | Description |
271 +|----------|------|-------------|
272 +| `Onde::VERSION` | String | Gem version (e.g. `"0.1.0"`) |
273 +| `Onde::NATIVE_VERSION` | String | Rust crate version (e.g. `"0.1.0"`) |
274 +| `Onde::SUPPORTED_MODELS` | Array | Frozen array of all supported model ID strings |
275 +| `Onde::SUPPORTED_MODEL_INFO` | Array | Frozen array of frozen Hashes with model metadata |
276 +
277 +```ruby
278 +Onde::SUPPORTED_MODELS
279 +# => ["black-forest-labs/FLUX.1-schnell", "google/gemma-3n-E2B-it", ...]
280 +
281 +Onde::SUPPORTED_MODEL_INFO.first
282 +# => {
283 +# "id" => "black-forest-labs/FLUX.1-schnell",
284 +# "name" => "FLUX.1 Schnell",
285 +# "org" => "Black Forest Labs",
286 +# "description" => "Fast, high-quality image generation model...",
287 +# "expected_size_bytes" => 23782506688
288 +# }
289 +```
290 +
291 +Both constants are frozen at load time — attempting to modify them raises `FrozenError`.
292 +
293 +## Usage Examples
294 +
295 +### Rails Admin Dashboard
296 +
297 +```ruby
298 +# app/controllers/admin/models_controller.rb
299 +class Admin::ModelsController < ApplicationController
300 + def index
301 + @supported = Onde.list_supported_models["models"]
302 + @local = Onde.list_local_models
303 + end
304 +
305 + def destroy
306 + Onde.delete_model(params[:model_id])
307 + redirect_to admin_models_path, notice: "Model cache deleted."
308 + rescue RuntimeError => e
309 + redirect_to admin_models_path, alert: e.message
310 + end
311 +end
312 +```
313 +
314 +### Background Job — Cache Cleanup
315 +
316 +```ruby
317 +# app/jobs/cleanup_hf_cache_job.rb
318 +class CleanupHfCacheJob < ApplicationJob
319 + queue_as :maintenance
320 +
321 + def perform
322 + local = Onde.list_local_models
323 + logger.info "[Onde] HF cache: #{local["total_size_display"]} across #{local["models"].length} models"
324 +
325 + # Delete models that are no longer in the supported list
326 + local["models"].each do |model|
327 + unless Onde::SUPPORTED_MODELS.include?(model["model_id"])
328 + logger.info "[Onde] Removing unsupported model: #{model["model_id"]} (#{model["size_display"]})"
329 + Onde.delete_model(model["model_id"])
330 + end
331 + end
332 + end
333 +end
334 +```
335 +
336 +### Rake Task — Model Status Report
337 +
338 +```ruby
339 +# lib/tasks/onde.rake
340 +namespace :onde do
341 + desc "Show HuggingFace model cache status"
342 + task status: :environment do
343 + puts "Cache: #{Onde.cache_path || "(not found)"}"
344 + puts
345 +
346 + Onde.list_supported_models["models"].each do |m|
347 + icon = m["is_downloaded"] ? "✓" : (m["is_incomplete"] ? "⏳" : "✗")
348 + local = m["is_downloaded"] ? m["local_size_display"] : (m["is_incomplete"] ? m["local_size_display"] : "—")
349 + puts "[#{icon}] #{m["name"].ljust(25)} #{local.rjust(10)} / #{m["expected_size_display"].rjust(10)} (#{m["org"]})"
350 + end
351 +
352 + local = Onde.list_local_models
353 + puts
354 + puts "Total on disk: #{local["total_size_display"]}"
355 + end
356 +end
357 +```
358 +
359 +Run with:
360 +
361 +```bash
362 +bundle exec rake onde:status
363 +```
364 +
365 +Example output:
366 +
367 +```
368 +Cache: /Users/you/.cache/huggingface/hub
369 +
370 +[✓] FLUX.1 Schnell 44.92 GB / 22.15 GB (Black Forest Labs)
371 +[✓] Gemma 3n E2B 20.33 GB / 10.17 GB (Google)
372 +[✓] Gemma 3n E4B 29.31 GB / 14.66 GB (Google)
373 +[✓] Phi-3.5-mini 14.24 GB / 7.12 GB (Microsoft)
374 +[✓] Qwen 2.5 1.5B (GGUF) 1.84 GB / 940.4 MB (Qwen / Alibaba)
375 +[✓] Qwen 2.5 3B (GGUF) 3.59 GB / 1.80 GB (Qwen / Alibaba)
376 +
377 +Total on disk: 114.22 GB
378 +```
379 +
380 +### API Endpoint
381 +
382 +```ruby
383 +# app/controllers/api/v1/models_controller.rb
384 +# frozen_string_literal: true
385 +
386 +module Api
387 + module V1
388 + class ModelsController < ApplicationController
389 + def index
390 + render json: Onde.list_supported_models
391 + end
392 +
393 + def show
394 + info = Onde.model_info(params[:id])
395 + if info
396 + render json: info
397 + else
398 + render json: { error: "Model not found" }, status: :not_found
399 + end
400 + end
401 + end
402 + end
403 +end
404 +```
405 +
406 +## Architecture
407 +
408 +```
409 +gem/
410 +├── Cargo.toml # Workspace root (isolates from parent onde crate)
411 +├── Gemfile # Dev deps: rake-compiler, rb_sys ~> 0.9.63
412 +├── Rakefile # RbSys::ExtensionTask build config
413 +├── onde.gemspec # Gem specification
414 +├── rust-toolchain.toml # Pinned to Rust 1.92
415 +├── .gitignore
416 +├── bin/
417 +│ ├── console # IRB with gem pre-loaded
418 +│ └── setup # One-step dev setup script
419 +├── lib/
420 +│ ├── onde.rb # Entry point — loads native ext + defines module
421 +│ └── onde/
422 +│ ├── version.rb # Onde::VERSION = '0.1.0'
423 +│ └── onde_ruby.bundle # Compiled native extension (git-ignored)
424 +└── ext/
425 + └── onde-ruby/
426 + ├── Cargo.toml # Rust crate: depends on `onde` + `magnus`
427 + ├── extconf.rb # rb_sys build hook
428 + └── src/
429 + └── lib.rs # Magnus bindings — the Rust ↔ Ruby bridge
430 +```
431 +
432 +### How the binding works
433 +
434 +```
435 +┌───────────────────────────┐
436 +│ Ruby │
437 +│ require "onde" │
438 +│ Onde.list_local_models │
439 +└───────────┬───────────────┘
440 + │ FFI call via magnus
441 + ▼
442 +┌───────────────────────────┐
443 +│ onde-ruby (cdylib) │
444 +│ ext/onde-ruby/src/lib.rs│
445 +│ │
446 +│ #[magnus::init] │
447 +│ fn init(ruby) { │
448 +│ module.define_*() │
449 +│ } │
450 +└───────────┬───────────────┘
451 + │ Rust dependency
452 + ▼
453 +┌───────────────────────────┐
454 +│ onde (Rust crate) │
455 +│ lib/crates/onde/src/ │
456 +│ │
457 +│ hf_cache:: │
458 +│ inference::models:: │
459 +│ inference::types:: │
460 +└───────────┬───────────────┘
461 + │
462 + ▼
463 +┌───────────────────────────┐
464 +│ mistral.rs │
465 +│ HuggingFace Hub │
466 +│ Metal / CUDA / CPU │
467 +└───────────────────────────┘
468 +```
469 +
470 +### Data flow
471 +
472 +All Rust structs are converted to Ruby Hashes via `serde_json` round-tripping:
473 +
474 +```
475 +Rust struct ─→ serde_json::Value ─→ Ruby Hash/Array/String/Integer/nil
476 +```
477 +
478 +This keeps the binding layer thin — no custom Ruby classes are needed. Every Onde struct that implements `serde::Serialize` can be exposed to Ruby with a single `to_ruby_value()` call.
479 +
480 +### Workspace isolation
481 +
482 +The `gem/Cargo.toml` defines a Cargo workspace with `ext/onde-ruby` as its only member. This prevents `cargo metadata` from walking up to the parent `lib/crates/onde/Cargo.toml` and confusing the rb_sys build system.
483 +
484 +Without this workspace file, running `cargo metadata` from `gem/` resolves to the parent `onde` crate, and `RbSys::Cargo::Metadata` cannot find the `onde-ruby` package.
485 +
486 +### Naming convention
487 +
488 +| Layer | Name | Why |
489 +|-------|------|-----|
490 +| Cargo package | `onde-ruby` | Avoids collision with the parent `onde` crate in the dependency graph |
491 +| Cargo lib output | `onde_ruby` | Rust convention: hyphens become underscores in lib names |
492 +| Ruby require | `onde/onde_ruby` | Matches the compiled `.bundle`/`.so` filename |
493 +| Ruby module | `Onde` | Clean public API name |
494 +| Gem name | `onde` | Simple, matches the project name |
495 +
496 +## Internals
497 +
498 +### Key files
499 +
500 +| File | Purpose |
501 +|------|---------|
502 +| `ext/onde-ruby/src/lib.rs` | All Magnus bindings — defines the `Onde` Ruby module, singleton methods, and constants |
503 +| `ext/onde-ruby/Cargo.toml` | Rust crate config — depends on `onde` (path) + `magnus` 0.7 + `serde_json` |
504 +| `ext/onde-ruby/extconf.rb` | Build hook — calls `create_rust_makefile("onde/onde_ruby")` |
505 +| `lib/onde.rb` | Ruby entry point — `require_relative 'onde/onde_ruby'` loads the native ext |
506 +| `Rakefile` | `RbSys::ExtensionTask.new('onde-ruby', GEMSPEC)` wires up compilation |
507 +| `Cargo.toml` (root) | Workspace file isolating the gem from the parent crate |
508 +
509 +### Dependencies
510 +
511 +**Ruby side:**
512 +
513 +- `rake` ~> 13.0 — build orchestration
514 +- `rake-compiler` — native extension compilation framework
515 +- `rb_sys` ~> 0.9.63 — Rust ↔ Ruby build glue
516 +
517 +**Rust side:**
518 +
519 +- `magnus` 0.7 — Ruby FFI bindings for Rust
520 +- `serde` + `serde_json` — struct serialization to Ruby Hashes
521 +- `onde` (path dependency) — the core Onde crate
522 +
523 +### Adding a new method
524 +
525 +1. Add the Rust function in `ext/onde-ruby/src/lib.rs`:
526 +
527 + ```rust
528 + fn my_new_method(arg: String) -> Result<magnus::Value, Error> {
529 + let ruby = Ruby::get().expect("called outside Ruby");
530 + // ... call into onde crate ...
531 + Ok(ruby.str_new("result").as_value())
532 + }
533 + ```
534 +
535 +2. Register it in the `init` function:
536 +
537 + ```rust
538 + module.define_singleton_method("my_new_method", function!(my_new_method, 1))?;
539 + ```
540 +
541 +3. Recompile:
542 +
543 + ```bash
544 + bundle exec rake compile
545 + ```
546 +
547 +4. Test:
548 +
549 + ```bash
550 + bundle exec ruby -e "require 'onde'; puts Onde.my_new_method('hello')"
551 + ```
552 +
553 +### Adding a new constant
554 +
555 +In the `init` function in `ext/onde-ruby/src/lib.rs`:
556 +
557 +```rust
558 +module.const_set("MY_CONSTANT", ruby.str_new("value"))?;
559 +```
560 +
561 +Constants are available as `Onde::MY_CONSTANT` in Ruby. Call `.freeze()` on Arrays and Hashes before setting them as constants to prevent mutation.
562 +
563 +## Troubleshooting
564 +
565 +### `cargo` not found during `bundle install`
566 +
567 +Rust is not on your `$PATH`. Install via [rustup](https://rustup.rs):
568 +
569 +```bash
570 +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
571 +source ~/.cargo/env
572 +```
573 +
574 +### Compilation fails with `rustc X.Y.Z is not supported`
575 +
576 +The gem requires Rust >= 1.92. Update your toolchain:
577 +
578 +```bash
579 +rustup update
580 +# or install the specific version:
581 +rustup toolchain install 1.92
582 +```
583 +
584 +The `rust-toolchain.toml` in the gem directory pins the version — rustup will select it automatically when you `cd` into the directory.
585 +
586 +### `Could not find Cargo package metadata for "onde-ruby"`
587 +
588 +The workspace `Cargo.toml` at `gem/` is missing or corrupted. It must exist and contain:
589 +
590 +```toml
591 +[workspace]
592 +members = ["ext/onde-ruby"]
593 +resolver = "2"
594 +```
595 +
596 +Without this file, `cargo metadata` resolves to the parent `onde` crate and rb_sys cannot find `onde-ruby`.
597 +
598 +### Output filename collision warning
599 +
600 +You may see:
601 +
602 +```
603 +warning: output filename collision at .../libonde.dylib
604 + note: the lib target `onde` in package `onde-ruby` has the same output
605 + filename as the lib target `onde` in package `onde`
606 +```
607 +
608 +This is a Cargo warning (not an error) caused by the extension crate's lib output name (`onde_ruby`) sharing a target directory with the parent `onde` crate. It does not affect compilation. The warning will become a hard error in a future Cargo version — at that point, set a separate `target-dir` in the workspace.
609 +
610 +### `LoadError: cannot load such file -- onde/onde_ruby`
611 +
612 +The native extension hasn't been compiled. Run:
613 +
614 +```bash
615 +bundle exec rake compile
616 +```
617 +
618 +### Stale `.bundle` / `.so` after code changes
619 +
620 +If you change `ext/onde-ruby/src/lib.rs` and the changes don't take effect:
621 +
622 +```bash
623 +bundle exec rake clobber compile
624 +```
625 +
626 +`clobber` cleans all build artifacts before recompiling.
627 +
628 +## Version Compatibility
629 +
630 +| Onde gem | Onde crate | Rust toolchain | Ruby | magnus |
631 +|----------|-----------|----------------|------|--------|
632 +| 0.1.0 | 0.1.0 | >= 1.92 | >= 3.0 | 0.7 |
633 +
634 +The `Onde::NATIVE_VERSION` constant always reflects the Rust crate version compiled into the gem. Compare it against `Onde::VERSION` to detect mismatches:
635 +
636 +```ruby
637 +if Onde::VERSION != Onde::NATIVE_VERSION
638 + warn "Onde version mismatch: gem=#{Onde::VERSION} native=#{Onde::NATIVE_VERSION}"
639 +end
640 +```
docs/swift-package.md new
+328
@@ -0,0 +1,328 @@
1 +---
2 +title: "Swift Package"
3 +description: "Build and distribute the Onde Swift package (XCFramework) for iOS, tvOS, and macOS using UniFFI bindings."
4 +---
5 +
6 +# Swift Package
7 +
8 +The Onde Swift package distributes a pre-built `OndeFramework.xcframework` via Swift Package Manager. The framework is built from Rust source using UniFFI bindings — no `cargo-swift` required. The project owns its own `uniffi-bindgen` binary that generates the Swift glue code directly.
9 +
10 +## Installation
11 +
12 +### Swift Package Manager
13 +
14 +Add the package in Xcode: **File → Add Package Dependencies** and enter:
15 +
16 +```
17 +https://github.com/ondeinference/onde-swift
18 +```
19 +
20 +Or add it to your `Package.swift`:
21 +
22 +```swift
23 +dependencies: [
24 + .package(url: "https://github.com/ondeinference/onde-swift", from: "0.1.0")
25 +],
26 +targets: [
27 + .target(name: "MyApp", dependencies: ["Onde"])
28 +]
29 +```
30 +
31 +## Supported Platforms
32 +
33 +| Platform | Minimum Version | GPU Backend |
34 +| -------- | --------------- | ----------- |
35 +| iOS | 14.0 | Metal |
36 +| tvOS | 13.0 | Metal |
37 +| macOS | 12.0 | Metal |
38 +
39 +## Swift API
40 +
41 +### Basic Chat
42 +
43 +```swift
44 +import Onde
45 +
46 +// Create the engine
47 +let engine = OndeChatEngine()
48 +
49 +// Load the platform-appropriate default model:
50 +// iOS / tvOS → Qwen 2.5 1.5B (~941 MB)
51 +// macOS → Qwen 2.5 3B (~1.93 GB)
52 +let loadTimeSecs = try await engine.loadDefaultModel(
53 + systemPrompt: "You are a helpful assistant.",
54 + sampling: nil // uses platform-aware defaults
55 +)
56 +print("Model loaded in \(loadTimeSecs)s")
57 +
58 +// Multi-turn chat (history managed automatically)
59 +let result = try await engine.sendMessage(message: "What can you help me with?")
60 +print(result.text)
61 +print(result.durationDisplay) // e.g. "4.5s"
62 +
63 +let followUp = try await engine.sendMessage(message: "Tell me more about that.")
64 +print(followUp.text)
65 +
66 +// Unload model to free memory
67 +await engine.unloadModel()
68 +```
69 +
70 +### Streaming
71 +
72 +```swift
73 +import Onde
74 +
75 +class StreamHandler: StreamChunkListener {
76 + func onChunk(chunk: StreamChunk) -> Bool {
77 + print(chunk.delta, terminator: "")
78 + if chunk.done { print() }
79 + return !chunk.done // return false to cancel early
80 + }
81 +}
82 +
83 +let engine = OndeChatEngine()
84 +try await engine.loadDefaultModel(systemPrompt: nil, sampling: nil)
85 +
86 +try await streamChatMessage(
87 + engine: engine,
88 + message: "Tell me a story.",
89 + listener: StreamHandler()
90 +)
91 +```
92 +
93 +Streaming is exposed as a free function rather than an `OndeChatEngine` method because UniFFI 0.31 does not support `callback_interface` parameters on Object methods.
94 +
95 +### One-Shot Generation
96 +
97 +`generate` runs inference on an explicit message list without modifying the engine's conversation history. Useful for prompt enhancement, summarisation, or any case where you don't want side effects on the chat history.
98 +
99 +```swift
100 +import Onde
101 +
102 +let engine = OndeChatEngine()
103 +try await engine.loadDefaultModel(systemPrompt: nil, sampling: nil)
104 +
105 +let result = try await engine.generate(
106 + messages: [userMessage(content: "Expand into a detailed prompt: a cat in space")],
107 + sampling: deterministicSamplingConfig()
108 +)
109 +print(result.text)
110 +```
111 +
112 +### Custom Model and Sampling
113 +
114 +```swift
115 +import Onde
116 +
117 +let engine = OndeChatEngine()
118 +
119 +let sampling = SamplingConfig(
120 + temperature: 0.9,
121 + topP: 0.95,
122 + topK: nil,
123 + minP: nil,
124 + maxTokens: 256,
125 + frequencyPenalty: nil,
126 + presencePenalty: nil
127 +)
128 +
129 +try await engine.loadGgufModel(
130 + config: qwen253bConfig(),
131 + systemPrompt: "You are a music expert.",
132 + sampling: sampling
133 +)
134 +```
135 +
136 +### History and Status
137 +
138 +```swift
139 +// Check engine status
140 +let info = await engine.info()
141 +print(info.status) // .ready
142 +print(info.historyLength) // number of turns
143 +
144 +// Retrieve full conversation history
145 +let history = await engine.history()
146 +for msg in history {
147 + print("\(msg.role): \(msg.content)")
148 +}
149 +
150 +// Clear history without unloading the model
151 +let removed = await engine.clearHistory()
152 +print("Removed \(removed) turns")
153 +
154 +// Append a message without running inference
155 +await engine.pushHistory(message: userMessage(content: "..."))
156 +```
157 +
158 +## Free Functions Reference
159 +
160 +### Model Configurations
161 +
162 +```swift
163 +defaultModelConfig() // platform-appropriate default (1.5B on iOS/tvOS, 3B on macOS)
164 +qwen251_5bConfig() // Qwen 2.5 1.5B Q4_K_M (~941 MB)
165 +qwen253bConfig() // Qwen 2.5 3B Q4_K_M (~1.93 GB)
166 +```
167 +
168 +### Sampling Presets
169 +
170 +```swift
171 +defaultSamplingConfig() // temp=0.7, top_p=0.95, max_tokens=512
172 +deterministicSamplingConfig() // temp=0.0, greedy decoding
173 +mobileSamplingConfig() // temp=0.7, max_tokens=128
174 +```
175 +
176 +### Message Constructors
177 +
178 +```swift
179 +systemMessage(content:) // ChatRole.system
180 +userMessage(content:) // ChatRole.user
181 +assistantMessage(content:) // ChatRole.assistant
182 +```
183 +
184 +## Type Reference
185 +
186 +| Rust Type | Swift Type | Description |
187 +| --------- | ---------- | ----------- |
188 +| `ChatRole` | `enum ChatRole` | `.system`, `.user`, `.assistant` |
189 +| `ChatMessage` | `struct ChatMessage` | `role` + `content` |
190 +| `SamplingConfig` | `struct SamplingConfig` | Temperature, top-p, max tokens, etc. |
191 +| `GgufModelConfig` | `struct GgufModelConfig` | Model repo, filename, display name |
192 +| `InferenceResult` | `struct InferenceResult` | `text`, `durationSecs`, `durationDisplay`, `finishReason` |
193 +| `StreamChunk` | `struct StreamChunk` | `delta`, `done`, `finishReason` |
194 +| `EngineStatus` | `enum EngineStatus` | `.unloaded`, `.loading`, `.ready`, `.generating`, `.error` |
195 +| `EngineInfo` | `struct EngineInfo` | `status`, `modelName`, `approxMemory`, `historyLength` |
196 +| `InferenceError` | `enum InferenceError: Error` | Thrown by `loadGgufModel`, `sendMessage`, `generate`, `streamChatMessage` |
197 +| `OndeChatEngine` | `class OndeChatEngine` | Main inference engine, thread-safe |
198 +| `StreamChunkListener` | `protocol StreamChunkListener` | Implement `onChunk(chunk:) -> Bool` |
199 +
200 +## Sandboxed App Setup (iOS / macOS App Store)
201 +
202 +On sandboxed platforms, `~/.cache` is inaccessible. Before any inference code runs, configure `HF_HOME` and `TMPDIR` to point inside the app's container:
203 +
204 +```swift
205 +import Foundation
206 +
207 +func setupInferenceEnvironment() {
208 + let appSupport = FileManager.default
209 + .urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
210 +
211 + let hfHome = appSupport.appendingPathComponent("huggingface")
212 + let hfHub = hfHome.appendingPathComponent("hub")
213 + try? FileManager.default.createDirectory(at: hfHub, withIntermediateDirectories: true)
214 +
215 + setenv("HF_HOME", hfHome.path, 1)
216 + setenv("HF_HUB_CACHE", hfHub.path, 1)
217 +
218 + // mistral.rs uses TMPDIR for temporary files during model loading
219 + let tmp = appSupport.appendingPathComponent("tmp")
220 + try? FileManager.default.createDirectory(at: tmp, withIntermediateDirectories: true)
221 + setenv("TMPDIR", tmp.path, 1)
222 +}
223 +```
224 +
225 +Call this once at app launch, before calling any `OndeChatEngine` method.
226 +
227 +## Building the XCFramework Locally
228 +
229 +If you are contributing to Onde or need a custom build, you can assemble the `OndeFramework.xcframework` from source.
230 +
231 +### Prerequisites
232 +
233 +```bash
234 +# Stable toolchain for iOS and macOS targets
235 +rustup toolchain install stable
236 +
237 +# Nightly toolchain for tvOS (tier-3 targets require -Z build-std)
238 +rustup toolchain install nightly
239 +rustup component add rust-src --toolchain nightly
240 +
241 +# Apple targets
242 +rustup target add \
243 + aarch64-apple-ios \
244 + x86_64-apple-ios \
245 + aarch64-apple-ios-sim \
246 + aarch64-apple-darwin \
247 + x86_64-apple-darwin
248 +```
249 +
250 +### Build
251 +
252 +```bash
253 +# 1. Build the uniffi-bindgen CLI (host)
254 +cargo build --manifest-path uniffi-bindgen/Cargo.toml --release
255 +BINDGEN=uniffi-bindgen/target/release/uniffi-bindgen
256 +
257 +# 2. Compile staticlibs per target
258 +cargo build --target aarch64-apple-ios --release
259 +cargo build --target x86_64-apple-ios --release
260 +cargo build --target aarch64-apple-ios-sim --release
261 +cargo build --target aarch64-apple-darwin --release
262 +cargo build --target x86_64-apple-darwin --release
263 +cargo +nightly build -Z build-std --target aarch64-apple-tvos --release
264 +cargo +nightly build -Z build-std --target x86_64-apple-tvos --release
265 +cargo +nightly build -Z build-std --target aarch64-apple-tvos-sim --release
266 +
267 +# 3. lipo simulator and macOS slices
268 +lipo -create \
269 + target/x86_64-apple-ios/release/libonde.a \
270 + target/aarch64-apple-ios-sim/release/libonde.a \
271 + -output /tmp/libonde-ios-sim.a
272 +
273 +lipo -create \
274 + target/x86_64-apple-tvos/release/libonde.a \
275 + target/aarch64-apple-tvos-sim/release/libonde.a \
276 + -output /tmp/libonde-tvos-sim.a
277 +
278 +lipo -create \
279 + target/aarch64-apple-darwin/release/libonde.a \
280 + target/x86_64-apple-darwin/release/libonde.a \
281 + -output /tmp/libonde-macos.a
282 +
283 +# 4. Generate Swift bindings
284 +mkdir -p sdk/Onde/Sources/Onde
285 +$BINDGEN generate \
286 + --library target/aarch64-apple-ios/release/libonde.a \
287 + --language swift \
288 + --out-dir sdk/Onde/Sources/Onde \
289 + --config uniffi.toml
290 +
291 +# 5. Assemble the XCFramework
292 +HEADERS=sdk/Onde/Sources/Onde
293 +xcodebuild -create-xcframework \
294 + -library target/aarch64-apple-ios/release/libonde.a -headers $HEADERS \
295 + -library /tmp/libonde-ios-sim.a -headers $HEADERS \
296 + -library target/aarch64-apple-tvos/release/libonde.a -headers $HEADERS \
297 + -library /tmp/libonde-tvos-sim.a -headers $HEADERS \
298 + -library /tmp/libonde-macos.a -headers $HEADERS \
299 + -output sdk/Onde/OndeFramework.xcframework
300 +```
301 +
302 +### Local Xcode Integration
303 +
304 +During development, use the local path form in `Package.swift`:
305 +
306 +```swift
307 +.binaryTarget(name: "OndeFramework", path: "./OndeFramework.xcframework")
308 +```
309 +
310 +In Xcode: **File → Add Package Dependencies → Add Local** → select `sdk/Onde/`.
311 +
312 +## Known Issues
313 +
314 +### `___chkstk_darwin` linker error on tvOS
315 +
316 +`aws-lc-sys` (a transitive dependency via `hf-hub`) references `___chkstk_darwin`, a stack probing symbol that tvOS does not export. The `build.rs` in the onde crate provides a no-op assembly stub (`tvos_chkstk.s`) that resolves this automatically. No action is needed — ensure `tvos_chkstk.s` is present at the crate root.
317 +
318 +This does not affect iOS, macOS, Android, Windows, or Linux builds.
319 +
320 +### Metal Toolchain missing (Xcode 26+)
321 +
322 +On Xcode 26+, the Metal compiler is a separate downloadable component. If you see empty `.metallib` files (92 bytes) or `"Error while loading function: fused_glu_float"` at runtime:
323 +
324 +```bash
325 +xcodebuild -downloadComponent MetalToolchain
326 +cargo clean -p mistralrs-quant
327 +cargo check
328 +```
sdk/gem/.gitignore new
+15
@@ -0,0 +1,15 @@
1 +/.bundle/
2 +/.yardoc
3 +/_yardoc/
4 +/coverage/
5 +/doc/
6 +/pkg/
7 +/spec/reports/
8 +/tmp/
9 +*.bundle
10 +*.so
11 +*.o
12 +*.a
13 +mkmf.log
14 +target/
15 +Gemfile.lock
sdk/gem/Cargo.lock new
+7697
@@ -0,0 +1,7697 @@
1 +# This file is automatically @generated by Cargo.
2 +# It is not intended for manual editing.
3 +version = 4
4 +
5 +[[package]]
6 +name = "Inflector"
7 +version = "0.11.4"
8 +source = "registry+https://github.com/rust-lang/crates.io-index"
9 +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
10 +dependencies = [
11 + "lazy_static",
12 + "regex",
13 +]
14 +
15 +[[package]]
16 +name = "adler2"
17 +version = "2.0.1"
18 +source = "registry+https://github.com/rust-lang/crates.io-index"
19 +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
20 +
21 +[[package]]
22 +name = "ahash"
23 +version = "0.8.12"
24 +source = "registry+https://github.com/rust-lang/crates.io-index"
25 +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
26 +dependencies = [
27 + "cfg-if",
28 + "getrandom 0.3.4",
29 + "once_cell",
30 + "serde",
31 + "version_check",
32 + "zerocopy",
33 +]
34 +
35 +[[package]]
36 +name = "aho-corasick"
37 +version = "1.1.4"
38 +source = "registry+https://github.com/rust-lang/crates.io-index"
39 +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
40 +dependencies = [
41 + "memchr",
42 +]
43 +
44 +[[package]]
45 +name = "akin"
46 +version = "0.4.0"
47 +source = "registry+https://github.com/rust-lang/crates.io-index"
48 +checksum = "1763692fc1416554cf051efc56a3de5595eca47299d731cc5c2b583adf8b4d2f"
49 +
50 +[[package]]
51 +name = "aligned"
52 +version = "0.4.3"
53 +source = "registry+https://github.com/rust-lang/crates.io-index"
54 +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
55 +dependencies = [
56 + "as-slice",
57 +]
58 +
59 +[[package]]
60 +name = "aligned-vec"
61 +version = "0.6.4"
62 +source = "registry+https://github.com/rust-lang/crates.io-index"
63 +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
64 +dependencies = [
65 + "equator",
66 +]
67 +
68 +[[package]]
69 +name = "allocator-api2"
70 +version = "0.2.21"
71 +source = "registry+https://github.com/rust-lang/crates.io-index"
72 +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
73 +
74 +[[package]]
75 +name = "android_system_properties"
76 +version = "0.1.5"
77 +source = "registry+https://github.com/rust-lang/crates.io-index"
78 +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
79 +dependencies = [
80 + "libc",
81 +]
82 +
83 +[[package]]
84 +name = "annotate-snippets"
85 +version = "0.12.12"
86 +source = "registry+https://github.com/rust-lang/crates.io-index"
87 +checksum = "c86cd1c51b95d71dde52bca69ed225008f6ff4c8cc825b08042aa1ef823e1980"
88 +dependencies = [
89 + "anstyle",
90 + "memchr",
91 + "unicode-width 0.2.2",
92 +]
93 +
94 +[[package]]
95 +name = "ansi_term"
96 +version = "0.12.1"
97 +source = "registry+https://github.com/rust-lang/crates.io-index"
98 +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
99 +dependencies = [
100 + "winapi",
101 +]
102 +
103 +[[package]]
104 +name = "anstream"
105 +version = "0.6.21"
106 +source = "registry+https://github.com/rust-lang/crates.io-index"
107 +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
108 +dependencies = [
109 + "anstyle",
110 + "anstyle-parse",
111 + "anstyle-query",
112 + "anstyle-wincon",
113 + "colorchoice",
114 + "is_terminal_polyfill",
115 + "utf8parse",
116 +]
117 +
118 +[[package]]
119 +name = "anstyle"
120 +version = "1.0.13"
121 +source = "registry+https://github.com/rust-lang/crates.io-index"
122 +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
123 +
124 +[[package]]
125 +name = "anstyle-parse"
126 +version = "0.2.7"
127 +source = "registry+https://github.com/rust-lang/crates.io-index"
128 +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
129 +dependencies = [
130 + "utf8parse",
131 +]
132 +
133 +[[package]]
134 +name = "anstyle-query"
135 +version = "1.1.5"
136 +source = "registry+https://github.com/rust-lang/crates.io-index"
137 +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
138 +dependencies = [
139 + "windows-sys 0.61.2",
140 +]
141 +
142 +[[package]]
143 +name = "anstyle-wincon"
144 +version = "3.0.11"
145 +source = "registry+https://github.com/rust-lang/crates.io-index"
146 +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
147 +dependencies = [
148 + "anstyle",
149 + "once_cell_polyfill",
150 + "windows-sys 0.61.2",
151 +]
152 +
153 +[[package]]
154 +name = "anyhow"
155 +version = "1.0.102"
156 +source = "registry+https://github.com/rust-lang/crates.io-index"
157 +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
158 +
159 +[[package]]
160 +name = "apodize"
161 +version = "1.0.0"
162 +source = "registry+https://github.com/rust-lang/crates.io-index"
163 +checksum = "fca387cdc0a1f9c7a7c26556d584aa2d07fc529843082e4861003cde4ab914ed"
164 +
165 +[[package]]
166 +name = "approx"
167 +version = "0.5.1"
168 +source = "registry+https://github.com/rust-lang/crates.io-index"
169 +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
170 +dependencies = [
171 + "num-traits",
172 +]
173 +
174 +[[package]]
175 +name = "arbitrary"
176 +version = "1.4.2"
177 +source = "registry+https://github.com/rust-lang/crates.io-index"
178 +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
179 +
180 +[[package]]
181 +name = "arg_enum_proc_macro"
182 +version = "0.3.4"
183 +source = "registry+https://github.com/rust-lang/crates.io-index"
184 +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
185 +dependencies = [
186 + "proc-macro2",
187 + "quote",
188 + "syn 2.0.117",
189 +]
190 +
191 +[[package]]
192 +name = "arraydeque"
193 +version = "0.5.1"
194 +source = "registry+https://github.com/rust-lang/crates.io-index"
195 +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
196 +
197 +[[package]]
198 +name = "arrayvec"
199 +version = "0.7.6"
200 +source = "registry+https://github.com/rust-lang/crates.io-index"
201 +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
202 +
203 +[[package]]
204 +name = "as-any"
205 +version = "0.3.2"
206 +source = "registry+https://github.com/rust-lang/crates.io-index"
207 +checksum = "b0f477b951e452a0b6b4a10b53ccd569042d1d01729b519e02074a9c0958a063"
208 +
209 +[[package]]
210 +name = "as-slice"
211 +version = "0.2.1"
212 +source = "registry+https://github.com/rust-lang/crates.io-index"
213 +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
214 +dependencies = [
215 + "stable_deref_trait",
216 +]
217 +
218 +[[package]]
219 +name = "askama"
220 +version = "0.14.0"
221 +source = "registry+https://github.com/rust-lang/crates.io-index"
222 +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
223 +dependencies = [
224 + "askama_derive",
225 + "itoa",
226 + "percent-encoding",
227 + "serde",
228 + "serde_json",
229 +]
230 +
231 +[[package]]
232 +name = "askama_derive"
233 +version = "0.14.0"
234 +source = "registry+https://github.com/rust-lang/crates.io-index"
235 +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
236 +dependencies = [
237 + "askama_parser",
238 + "basic-toml",
239 + "memchr",
240 + "proc-macro2",
241 + "quote",
242 + "rustc-hash 2.1.1",
243 + "serde",
244 + "serde_derive",
245 + "syn 2.0.117",
246 +]
247 +
248 +[[package]]
249 +name = "askama_parser"
250 +version = "0.14.0"
251 +source = "registry+https://github.com/rust-lang/crates.io-index"
252 +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
253 +dependencies = [
254 + "memchr",
255 + "serde",
256 + "serde_derive",
257 + "winnow",
258 +]
259 +
260 +[[package]]
261 +name = "async-compat"
262 +version = "0.2.5"
263 +source = "registry+https://github.com/rust-lang/crates.io-index"
264 +checksum = "a1ba85bc55464dcbf728b56d97e119d673f4cf9062be330a9a26f3acf504a590"
265 +dependencies = [
266 + "futures-core",
267 + "futures-io",
268 + "once_cell",
269 + "pin-project-lite",
270 + "tokio",
271 +]
272 +
273 +[[package]]
274 +name = "async-trait"
275 +version = "0.1.89"
276 +source = "registry+https://github.com/rust-lang/crates.io-index"
277 +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
278 +dependencies = [
279 + "proc-macro2",
280 + "quote",
281 + "syn 2.0.117",
282 +]
283 +
284 +[[package]]
285 +name = "atomic-waker"
286 +version = "1.1.2"
287 +source = "registry+https://github.com/rust-lang/crates.io-index"
288 +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
289 +
290 +[[package]]
291 +name = "atty"
292 +version = "0.2.14"
293 +source = "registry+https://github.com/rust-lang/crates.io-index"
294 +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
295 +dependencies = [
296 + "hermit-abi 0.1.19",
297 + "libc",
298 + "winapi",
299 +]
300 +
301 +[[package]]
302 +name = "autocfg"
303 +version = "1.5.0"
304 +source = "registry+https://github.com/rust-lang/crates.io-index"
305 +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
306 +
307 +[[package]]
308 +name = "av-scenechange"
309 +version = "0.14.1"
310 +source = "registry+https://github.com/rust-lang/crates.io-index"
311 +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394"
312 +dependencies = [
313 + "aligned",
314 + "anyhow",
315 + "arg_enum_proc_macro",
316 + "arrayvec",
317 + "log",
318 + "num-rational",
319 + "num-traits",
320 + "pastey",
321 + "rayon",
322 + "thiserror 2.0.18",
323 + "v_frame",
324 + "y4m",
325 +]
326 +
327 +[[package]]
328 +name = "av1-grain"
329 +version = "0.2.5"
330 +source = "registry+https://github.com/rust-lang/crates.io-index"
331 +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
332 +dependencies = [
333 + "anyhow",
334 + "arrayvec",
335 + "log",
336 + "nom 8.0.0",
337 + "num-rational",
338 + "v_frame",
339 +]
340 +
341 +[[package]]
342 +name = "avif-serialize"
343 +version = "0.8.8"
344 +source = "registry+https://github.com/rust-lang/crates.io-index"
345 +checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d"
346 +dependencies = [
347 + "arrayvec",
348 +]
349 +
350 +[[package]]
351 +name = "aws-lc-rs"
352 +version = "1.16.1"
353 +source = "registry+https://github.com/rust-lang/crates.io-index"
354 +checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf"
355 +dependencies = [
356 + "aws-lc-sys",
357 + "zeroize",
358 +]
359 +
360 +[[package]]
361 +name = "aws-lc-sys"
362 +version = "0.38.0"
363 +source = "registry+https://github.com/rust-lang/crates.io-index"
364 +checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e"
365 +dependencies = [
366 + "cc",
367 + "cmake",
368 + "dunce",
369 + "fs_extra",
370 +]
371 +
372 +[[package]]
373 +name = "base64"
374 +version = "0.13.1"
375 +source = "registry+https://github.com/rust-lang/crates.io-index"
376 +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
377 +
378 +[[package]]
379 +name = "base64"
380 +version = "0.22.1"
381 +source = "registry+https://github.com/rust-lang/crates.io-index"
382 +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
383 +
384 +[[package]]
385 +name = "basic-toml"
386 +version = "0.1.10"
387 +source = "registry+https://github.com/rust-lang/crates.io-index"
388 +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
389 +dependencies = [
390 + "serde",
391 +]
392 +
393 +[[package]]
394 +name = "bindgen"
395 +version = "0.69.5"
396 +source = "registry+https://github.com/rust-lang/crates.io-index"
397 +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
398 +dependencies = [
399 + "bitflags 2.11.0",
400 + "cexpr",
401 + "clang-sys",
402 + "itertools 0.12.1",
403 + "lazy_static",
404 + "lazycell",
405 + "proc-macro2",
406 + "quote",
407 + "regex",
408 + "rustc-hash 1.1.0",
409 + "shlex",
410 + "syn 2.0.117",
411 +]
412 +
413 +[[package]]
414 +name = "bit-set"
415 +version = "0.5.3"
416 +source = "registry+https://github.com/rust-lang/crates.io-index"
417 +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
418 +dependencies = [
419 + "bit-vec 0.6.3",
420 +]
421 +
422 +[[package]]
423 +name = "bit-set"
424 +version = "0.8.0"
425 +source = "registry+https://github.com/rust-lang/crates.io-index"
426 +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
427 +dependencies = [
428 + "bit-vec 0.8.0",
429 +]
430 +
431 +[[package]]
432 +name = "bit-vec"
433 +version = "0.6.3"
434 +source = "registry+https://github.com/rust-lang/crates.io-index"
435 +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
436 +
437 +[[package]]
438 +name = "bit-vec"
439 +version = "0.8.0"
440 +source = "registry+https://github.com/rust-lang/crates.io-index"
441 +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
442 +
443 +[[package]]
444 +name = "bit_field"
445 +version = "0.10.3"
446 +source = "registry+https://github.com/rust-lang/crates.io-index"
447 +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
448 +
449 +[[package]]
450 +name = "bitflags"
451 +version = "1.3.2"
452 +source = "registry+https://github.com/rust-lang/crates.io-index"
453 +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
454 +
455 +[[package]]
456 +name = "bitflags"
457 +version = "2.11.0"
458 +source = "registry+https://github.com/rust-lang/crates.io-index"
459 +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
460 +
461 +[[package]]
462 +name = "bitstream-io"
463 +version = "4.9.0"
464 +source = "registry+https://github.com/rust-lang/crates.io-index"
465 +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757"
466 +dependencies = [
467 + "core2",
468 +]
469 +
470 +[[package]]
471 +name = "block"
472 +version = "0.1.6"
473 +source = "registry+https://github.com/rust-lang/crates.io-index"
474 +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
475 +
476 +[[package]]
477 +name = "block-buffer"
478 +version = "0.10.4"
479 +source = "registry+https://github.com/rust-lang/crates.io-index"
480 +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
481 +dependencies = [
482 + "generic-array",
483 +]
484 +
485 +[[package]]
486 +name = "block2"
487 +version = "0.6.2"
488 +source = "registry+https://github.com/rust-lang/crates.io-index"
489 +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
490 +dependencies = [
491 + "objc2",
492 +]
493 +
494 +[[package]]
495 +name = "bm25"
496 +version = "2.3.2"
497 +source = "registry+https://github.com/rust-lang/crates.io-index"
498 +checksum = "1cbd8ffdfb7b4c2ff038726178a780a94f90525ed0ad264c0afaa75dd8c18a64"
499 +dependencies = [
500 + "cached",
501 + "deunicode",
502 + "fxhash",
503 + "rust-stemmers",
504 + "stop-words",
505 + "unicode-segmentation",
506 +]
507 +
508 +[[package]]
509 +name = "bstr"
510 +version = "1.12.1"
511 +source = "registry+https://github.com/rust-lang/crates.io-index"
512 +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
513 +dependencies = [
514 + "memchr",
515 + "regex-automata",
516 + "serde",
517 +]
518 +
519 +[[package]]
520 +name = "built"
521 +version = "0.8.0"
522 +source = "registry+https://github.com/rust-lang/crates.io-index"
523 +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64"
524 +
525 +[[package]]
526 +name = "bumpalo"
527 +version = "3.20.2"
528 +source = "registry+https://github.com/rust-lang/crates.io-index"
529 +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
530 +
531 +[[package]]
532 +name = "bytemuck"
533 +version = "1.25.0"
534 +source = "registry+https://github.com/rust-lang/crates.io-index"
535 +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
536 +dependencies = [
537 + "bytemuck_derive",
538 +]
539 +
540 +[[package]]
541 +name = "bytemuck_derive"
542 +version = "1.10.2"
543 +source = "registry+https://github.com/rust-lang/crates.io-index"
544 +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
545 +dependencies = [
546 + "proc-macro2",
547 + "quote",
548 + "syn 2.0.117",
549 +]
550 +
551 +[[package]]
552 +name = "byteorder"
553 +version = "1.5.0"
554 +source = "registry+https://github.com/rust-lang/crates.io-index"
555 +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
556 +
557 +[[package]]
558 +name = "byteorder-lite"
559 +version = "0.1.0"
560 +source = "registry+https://github.com/rust-lang/crates.io-index"
561 +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
562 +
563 +[[package]]
564 +name = "bytes"
565 +version = "1.11.1"
566 +source = "registry+https://github.com/rust-lang/crates.io-index"
567 +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
568 +
569 +[[package]]
570 +name = "cached"
571 +version = "0.56.0"
572 +source = "registry+https://github.com/rust-lang/crates.io-index"
573 +checksum = "801927ee168e17809ab8901d9f01f700cd7d8d6a6527997fee44e4b0327a253c"
574 +dependencies = [
575 + "ahash",
576 + "cached_proc_macro",
577 + "cached_proc_macro_types",
578 + "hashbrown 0.15.5",
579 + "once_cell",
580 + "thiserror 2.0.18",
581 + "web-time",
582 +]
583 +
584 +[[package]]
585 +name = "cached_proc_macro"
586 +version = "0.25.0"
587 +source = "registry+https://github.com/rust-lang/crates.io-index"
588 +checksum = "9225bdcf4e4a9a4c08bf16607908eb2fbf746828d5e0b5e019726dbf6571f201"
589 +dependencies = [
590 + "darling 0.20.11",
591 + "proc-macro2",
592 + "quote",
593 + "syn 2.0.117",
594 +]
595 +
596 +[[package]]
597 +name = "cached_proc_macro_types"
598 +version = "0.1.1"
599 +source = "registry+https://github.com/rust-lang/crates.io-index"
600 +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
601 +
602 +[[package]]
603 +name = "camino"
604 +version = "1.2.2"
605 +source = "registry+https://github.com/rust-lang/crates.io-index"
606 +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48"
607 +dependencies = [
608 + "serde_core",
609 +]
610 +
611 +[[package]]
612 +name = "candle-core"
613 +version = "0.9.2"
614 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
615 +dependencies = [
616 + "byteorder",
617 + "candle-metal-kernels",
618 + "candle-ug",
619 + "float8",
620 + "gemm 0.19.0",
621 + "half",
622 + "libm",
623 + "memmap2",
624 + "num-traits",
625 + "num_cpus",
626 + "objc2-foundation",
627 + "objc2-metal",
628 + "rand 0.9.2",
629 + "rand_distr 0.5.1",
630 + "rayon",
631 + "safetensors 0.7.0",
632 + "thiserror 2.0.18",
633 + "yoke 0.8.1",
634 + "zip",
635 +]
636 +
637 +[[package]]
638 +name = "candle-metal-kernels"
639 +version = "0.9.2"
640 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
641 +dependencies = [
642 + "half",
643 + "objc2",
644 + "objc2-foundation",
645 + "objc2-metal",
646 + "once_cell",
647 + "thiserror 2.0.18",
648 + "tracing",
649 +]
650 +
651 +[[package]]
652 +name = "candle-nn"
653 +version = "0.9.2"
654 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
655 +dependencies = [
656 + "candle-core",
657 + "candle-metal-kernels",
658 + "half",
659 + "libc",
660 + "num-traits",
661 + "objc2-metal",
662 + "rayon",
663 + "safetensors 0.7.0",
664 + "serde",
665 + "thiserror 2.0.18",
666 +]
667 +
668 +[[package]]
669 +name = "candle-ug"
670 +version = "0.9.2"
671 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
672 +dependencies = [
673 + "ug",
674 + "ug-metal",
675 +]
676 +
677 +[[package]]
678 +name = "cargo-platform"
679 +version = "0.1.9"
680 +source = "registry+https://github.com/rust-lang/crates.io-index"
681 +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
682 +dependencies = [
683 + "serde",
684 +]
685 +
686 +[[package]]
687 +name = "cargo_metadata"
688 +version = "0.19.2"
689 +source = "registry+https://github.com/rust-lang/crates.io-index"
690 +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
691 +dependencies = [
692 + "camino",
693 + "cargo-platform",
694 + "semver",
695 + "serde",
696 + "serde_json",
697 + "thiserror 2.0.18",
698 +]
699 +
700 +[[package]]
701 +name = "castaway"
702 +version = "0.2.4"
703 +source = "registry+https://github.com/rust-lang/crates.io-index"
704 +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
705 +dependencies = [
706 + "rustversion",
707 +]
708 +
709 +[[package]]
710 +name = "cc"
711 +version = "1.2.56"
712 +source = "registry+https://github.com/rust-lang/crates.io-index"
713 +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
714 +dependencies = [
715 + "find-msvc-tools",
716 + "jobserver",
717 + "libc",
718 + "shlex",
719 +]
720 +
721 +[[package]]
722 +name = "cesu8"
723 +version = "1.1.0"
724 +source = "registry+https://github.com/rust-lang/crates.io-index"
725 +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
726 +
727 +[[package]]
728 +name = "cexpr"
729 +version = "0.6.0"
730 +source = "registry+https://github.com/rust-lang/crates.io-index"
731 +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
732 +dependencies = [
733 + "nom 7.1.3",
734 +]
735 +
736 +[[package]]
737 +name = "cfg-if"
738 +version = "1.0.4"
739 +source = "registry+https://github.com/rust-lang/crates.io-index"
740 +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
741 +
742 +[[package]]
743 +name = "cfg_aliases"
744 +version = "0.2.1"
745 +source = "registry+https://github.com/rust-lang/crates.io-index"
746 +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
747 +
748 +[[package]]
749 +name = "cfgrammar"
750 +version = "0.14.1"
751 +source = "registry+https://github.com/rust-lang/crates.io-index"
752 +checksum = "3efdd8f0bddcc9e33f4a664d0f28bc4e51cd5367c16284087a95313104371865"
753 +dependencies = [
754 + "indexmap 2.13.0",
755 + "num-traits",
756 + "proc-macro2",
757 + "quote",
758 + "regex",
759 + "vob",
760 +]
761 +
762 +[[package]]
763 +name = "chrono"
764 +version = "0.4.44"
765 +source = "registry+https://github.com/rust-lang/crates.io-index"
766 +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
767 +dependencies = [
768 + "iana-time-zone",
769 + "js-sys",
770 + "num-traits",
771 + "serde",
772 + "wasm-bindgen",
773 + "windows-link 0.2.1",
774 +]
775 +
776 +[[package]]
777 +name = "clang-sys"
778 +version = "1.8.1"
779 +source = "registry+https://github.com/rust-lang/crates.io-index"
780 +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
781 +dependencies = [
782 + "glob",
783 + "libc",
784 + "libloading",
785 +]
786 +
787 +[[package]]
788 +name = "clap"
789 +version = "2.34.0"
790 +source = "registry+https://github.com/rust-lang/crates.io-index"
791 +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
792 +dependencies = [
793 + "ansi_term",
794 + "atty",
795 + "bitflags 1.3.2",
796 + "strsim 0.8.0",
797 + "textwrap 0.11.0",
798 + "unicode-width 0.1.14",
799 + "vec_map",
800 +]
801 +
802 +[[package]]
803 +name = "clap"
804 +version = "4.5.60"
805 +source = "registry+https://github.com/rust-lang/crates.io-index"
806 +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
807 +dependencies = [
808 + "clap_builder",
809 + "clap_derive",
810 +]
811 +
812 +[[package]]
813 +name = "clap_builder"
814 +version = "4.5.60"
815 +source = "registry+https://github.com/rust-lang/crates.io-index"
816 +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
817 +dependencies = [
818 + "anstream",
819 + "anstyle",
820 + "clap_lex",
821 + "strsim 0.11.1",
822 + "terminal_size",
823 +]
824 +
825 +[[package]]
826 +name = "clap_derive"
827 +version = "4.5.55"
828 +source = "registry+https://github.com/rust-lang/crates.io-index"
829 +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
830 +dependencies = [
831 + "heck 0.5.0",
832 + "proc-macro2",
833 + "quote",
834 + "syn 2.0.117",
835 +]
836 +
837 +[[package]]
838 +name = "clap_lex"
839 +version = "1.0.0"
840 +source = "registry+https://github.com/rust-lang/crates.io-index"
841 +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
842 +
843 +[[package]]
844 +name = "cmake"
845 +version = "0.1.57"
846 +source = "registry+https://github.com/rust-lang/crates.io-index"
847 +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
848 +dependencies = [
849 + "cc",
850 +]
851 +
852 +[[package]]
853 +name = "color_quant"
854 +version = "1.1.0"
855 +source = "registry+https://github.com/rust-lang/crates.io-index"
856 +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
857 +
858 +[[package]]
859 +name = "colorchoice"
860 +version = "1.0.4"
861 +source = "registry+https://github.com/rust-lang/crates.io-index"
862 +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
863 +
864 +[[package]]
865 +name = "combine"
866 +version = "4.6.7"
867 +source = "registry+https://github.com/rust-lang/crates.io-index"
868 +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
869 +dependencies = [
870 + "bytes",
871 + "memchr",
872 +]
873 +
874 +[[package]]
875 +name = "compact_str"
876 +version = "0.9.0"
877 +source = "registry+https://github.com/rust-lang/crates.io-index"
878 +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
879 +dependencies = [
880 + "castaway",
881 + "cfg-if",
882 + "itoa",
883 + "rustversion",
884 + "ryu",
885 + "serde",
886 + "static_assertions",
887 +]
888 +
889 +[[package]]
890 +name = "console"
891 +version = "0.15.11"
892 +source = "registry+https://github.com/rust-lang/crates.io-index"
893 +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
894 +dependencies = [
895 + "encode_unicode",
896 + "libc",
897 + "once_cell",
898 + "unicode-width 0.2.2",
899 + "windows-sys 0.59.0",
900 +]
901 +
902 +[[package]]
903 +name = "console"
904 +version = "0.16.2"
905 +source = "registry+https://github.com/rust-lang/crates.io-index"
906 +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4"
907 +dependencies = [
908 + "encode_unicode",
909 + "libc",
910 + "once_cell",
911 + "unicode-width 0.2.2",
912 + "windows-sys 0.61.2",
913 +]
914 +
915 +[[package]]
916 +name = "convert_case"
917 +version = "0.6.0"
918 +source = "registry+https://github.com/rust-lang/crates.io-index"
919 +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
920 +dependencies = [
921 + "unicode-segmentation",
922 +]
923 +
924 +[[package]]
925 +name = "core-foundation"
926 +version = "0.9.4"
927 +source = "registry+https://github.com/rust-lang/crates.io-index"
928 +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
929 +dependencies = [
930 + "core-foundation-sys",
931 + "libc",
932 +]
933 +
934 +[[package]]
935 +name = "core-foundation"
936 +version = "0.10.1"
937 +source = "registry+https://github.com/rust-lang/crates.io-index"
938 +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
939 +dependencies = [
940 + "core-foundation-sys",
941 + "libc",
942 +]
943 +
944 +[[package]]
945 +name = "core-foundation-sys"
946 +version = "0.8.7"
947 +source = "registry+https://github.com/rust-lang/crates.io-index"
948 +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
949 +
950 +[[package]]
951 +name = "core-graphics-types"
952 +version = "0.1.3"
953 +source = "registry+https://github.com/rust-lang/crates.io-index"
954 +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
955 +dependencies = [
956 + "bitflags 1.3.2",
957 + "core-foundation 0.9.4",
958 + "libc",
959 +]
960 +
961 +[[package]]
962 +name = "core2"
963 +version = "0.4.0"
964 +source = "registry+https://github.com/rust-lang/crates.io-index"
965 +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
966 +dependencies = [
967 + "memchr",
968 +]
969 +
970 +[[package]]
971 +name = "cpufeatures"
972 +version = "0.2.17"
973 +source = "registry+https://github.com/rust-lang/crates.io-index"
974 +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
975 +dependencies = [
976 + "libc",
977 +]
978 +
979 +[[package]]
980 +name = "crc32fast"
981 +version = "1.5.0"
982 +source = "registry+https://github.com/rust-lang/crates.io-index"
983 +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
984 +dependencies = [
985 + "cfg-if",
986 +]
987 +
988 +[[package]]
989 +name = "crossbeam-deque"
990 +version = "0.8.6"
991 +source = "registry+https://github.com/rust-lang/crates.io-index"
992 +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
993 +dependencies = [
994 + "crossbeam-epoch",
995 + "crossbeam-utils",
996 +]
997 +
998 +[[package]]
999 +name = "crossbeam-epoch"
1000 +version = "0.9.18"
1001 +source = "registry+https://github.com/rust-lang/crates.io-index"
1002 +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
1003 +dependencies = [
1004 + "crossbeam-utils",
1005 +]
1006 +
1007 +[[package]]
1008 +name = "crossbeam-utils"
1009 +version = "0.8.21"
1010 +source = "registry+https://github.com/rust-lang/crates.io-index"
1011 +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
1012 +
1013 +[[package]]
1014 +name = "crossterm"
1015 +version = "0.25.0"
1016 +source = "registry+https://github.com/rust-lang/crates.io-index"
1017 +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
1018 +dependencies = [
1019 + "bitflags 1.3.2",
1020 + "crossterm_winapi",
1021 + "libc",
1022 + "mio 0.8.11",
1023 + "parking_lot",
1024 + "signal-hook",
1025 + "signal-hook-mio",
1026 + "winapi",
1027 +]
1028 +
1029 +[[package]]
1030 +name = "crossterm_winapi"
1031 +version = "0.9.1"
1032 +source = "registry+https://github.com/rust-lang/crates.io-index"
1033 +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
1034 +dependencies = [
1035 + "winapi",
1036 +]
1037 +
1038 +[[package]]
1039 +name = "crunchy"
1040 +version = "0.2.4"
1041 +source = "registry+https://github.com/rust-lang/crates.io-index"
1042 +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
1043 +
1044 +[[package]]
1045 +name = "crypto-common"
1046 +version = "0.1.7"
1047 +source = "registry+https://github.com/rust-lang/crates.io-index"
1048 +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
1049 +dependencies = [
1050 + "generic-array",
1051 + "typenum",
1052 +]
1053 +
1054 +[[package]]
1055 +name = "cssparser"
1056 +version = "0.36.0"
1057 +source = "registry+https://github.com/rust-lang/crates.io-index"
1058 +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2"
1059 +dependencies = [
1060 + "cssparser-macros",
1061 + "dtoa-short",
1062 + "itoa",
1063 + "phf",
1064 + "smallvec 1.15.1",
1065 +]
1066 +
1067 +[[package]]
1068 +name = "cssparser-macros"
1069 +version = "0.6.1"
1070 +source = "registry+https://github.com/rust-lang/crates.io-index"
1071 +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
1072 +dependencies = [
1073 + "quote",
1074 + "syn 2.0.117",
1075 +]
1076 +
1077 +[[package]]
1078 +name = "csv"
1079 +version = "1.4.0"
1080 +source = "registry+https://github.com/rust-lang/crates.io-index"
1081 +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
1082 +dependencies = [
1083 + "csv-core",
1084 + "itoa",
1085 + "ryu",
1086 + "serde_core",
1087 +]
1088 +
1089 +[[package]]
1090 +name = "csv-core"
1091 +version = "0.1.13"
1092 +source = "registry+https://github.com/rust-lang/crates.io-index"
1093 +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
1094 +dependencies = [
1095 + "memchr",
1096 +]
1097 +
1098 +[[package]]
1099 +name = "darling"
1100 +version = "0.11.0"
1101 +source = "registry+https://github.com/rust-lang/crates.io-index"
1102 +checksum = "dbffa8f8e38810422f320ca457a93cf1cd0056dc9c06c556b867558e0d471463"
1103 +dependencies = [
1104 + "darling_core 0.11.0",
1105 + "darling_macro 0.11.0",
1106 +]
1107 +
1108 +[[package]]
1109 +name = "darling"
1110 +version = "0.20.11"
1111 +source = "registry+https://github.com/rust-lang/crates.io-index"
1112 +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
1113 +dependencies = [
1114 + "darling_core 0.20.11",
1115 + "darling_macro 0.20.11",
1116 +]
1117 +
1118 +[[package]]
1119 +name = "darling"
1120 +version = "0.21.3"
1121 +source = "registry+https://github.com/rust-lang/crates.io-index"
1122 +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
1123 +dependencies = [
1124 + "darling_core 0.21.3",
1125 + "darling_macro 0.21.3",
1126 +]
1127 +
1128 +[[package]]
1129 +name = "darling"
1130 +version = "0.23.0"
1131 +source = "registry+https://github.com/rust-lang/crates.io-index"
1132 +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
1133 +dependencies = [
1134 + "darling_core 0.23.0",
1135 + "darling_macro 0.23.0",
1136 +]
1137 +
1138 +[[package]]
1139 +name = "darling_core"
1140 +version = "0.11.0"
1141 +source = "registry+https://github.com/rust-lang/crates.io-index"
1142 +checksum = "06e172685d94b7b83800e3256a63261537b9d6129e10f21c8e13ddf9dba8c64d"
1143 +dependencies = [
1144 + "fnv",
1145 + "ident_case",
1146 + "proc-macro2",
1147 + "quote",
1148 + "strsim 0.10.0",
1149 + "syn 1.0.109",
1150 +]
1151 +
1152 +[[package]]
1153 +name = "darling_core"
1154 +version = "0.20.11"
1155 +source = "registry+https://github.com/rust-lang/crates.io-index"
1156 +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
1157 +dependencies = [
1158 + "fnv",
1159 + "ident_case",
1160 + "proc-macro2",
1161 + "quote",
1162 + "strsim 0.11.1",
1163 + "syn 2.0.117",
1164 +]
1165 +
1166 +[[package]]
1167 +name = "darling_core"
1168 +version = "0.21.3"
1169 +source = "registry+https://github.com/rust-lang/crates.io-index"
1170 +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
1171 +dependencies = [
1172 + "fnv",
1173 + "ident_case",
1174 + "proc-macro2",
1175 + "quote",
1176 + "strsim 0.11.1",
1177 + "syn 2.0.117",
1178 +]
1179 +
1180 +[[package]]
1181 +name = "darling_core"
1182 +version = "0.23.0"
1183 +source = "registry+https://github.com/rust-lang/crates.io-index"
1184 +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
1185 +dependencies = [
1186 + "ident_case",
1187 + "proc-macro2",
1188 + "quote",
1189 + "strsim 0.11.1",
1190 + "syn 2.0.117",
1191 +]
1192 +
1193 +[[package]]
1194 +name = "darling_macro"
1195 +version = "0.11.0"
1196 +source = "registry+https://github.com/rust-lang/crates.io-index"
1197 +checksum = "f0618ac802792cebd1918ac6042a6ea1eeab92db34b35656afaa577929820788"
1198 +dependencies = [
1199 + "darling_core 0.11.0",
1200 + "quote",
1201 + "syn 1.0.109",
1202 +]
1203 +
1204 +[[package]]
1205 +name = "darling_macro"
1206 +version = "0.20.11"
1207 +source = "registry+https://github.com/rust-lang/crates.io-index"
1208 +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
1209 +dependencies = [
1210 + "darling_core 0.20.11",
1211 + "quote",
1212 + "syn 2.0.117",
1213 +]
1214 +
1215 +[[package]]
1216 +name = "darling_macro"
1217 +version = "0.21.3"
1218 +source = "registry+https://github.com/rust-lang/crates.io-index"
1219 +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
1220 +dependencies = [
1221 + "darling_core 0.21.3",
1222 + "quote",
1223 + "syn 2.0.117",
1224 +]
1225 +
1226 +[[package]]
1227 +name = "darling_macro"
1228 +version = "0.23.0"
1229 +source = "registry+https://github.com/rust-lang/crates.io-index"
1230 +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
1231 +dependencies = [
1232 + "darling_core 0.23.0",
1233 + "quote",
1234 + "syn 2.0.117",
1235 +]
1236 +
1237 +[[package]]
1238 +name = "dary_heap"
1239 +version = "0.3.8"
1240 +source = "registry+https://github.com/rust-lang/crates.io-index"
1241 +checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04"
1242 +dependencies = [
1243 + "serde",
1244 +]
1245 +
1246 +[[package]]
1247 +name = "data-encoding"
1248 +version = "2.10.0"
1249 +source = "registry+https://github.com/rust-lang/crates.io-index"
1250 +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
1251 +
1252 +[[package]]
1253 +name = "defmac"
1254 +version = "0.1.3"
1255 +source = "registry+https://github.com/rust-lang/crates.io-index"
1256 +checksum = "aafbece59594ed57696a1a69e8bb3ca1683fbc9cdb41d5c02726070b2cd8f19d"
1257 +
1258 +[[package]]
1259 +name = "deranged"
1260 +version = "0.5.8"
1261 +source = "registry+https://github.com/rust-lang/crates.io-index"
1262 +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
1263 +dependencies = [
1264 + "powerfmt",
1265 + "serde_core",
1266 +]
1267 +
1268 +[[package]]
1269 +name = "derive-new"
1270 +version = "0.7.0"
1271 +source = "registry+https://github.com/rust-lang/crates.io-index"
1272 +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc"
1273 +dependencies = [
1274 + "proc-macro2",
1275 + "quote",
1276 + "syn 2.0.117",
1277 +]
1278 +
1279 +[[package]]
1280 +name = "derive_builder"
1281 +version = "0.20.2"
1282 +source = "registry+https://github.com/rust-lang/crates.io-index"
1283 +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
1284 +dependencies = [
1285 + "derive_builder_macro",
1286 +]
1287 +
1288 +[[package]]
1289 +name = "derive_builder_core"
1290 +version = "0.20.2"
1291 +source = "registry+https://github.com/rust-lang/crates.io-index"
1292 +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
1293 +dependencies = [
1294 + "darling 0.20.11",
1295 + "proc-macro2",
1296 + "quote",
1297 + "syn 2.0.117",
1298 +]
1299 +
1300 +[[package]]
1301 +name = "derive_builder_macro"
1302 +version = "0.20.2"
1303 +source = "registry+https://github.com/rust-lang/crates.io-index"
1304 +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
1305 +dependencies = [
1306 + "derive_builder_core",
1307 + "syn 2.0.117",
1308 +]
1309 +
1310 +[[package]]
1311 +name = "derive_more"
1312 +version = "2.1.1"
1313 +source = "registry+https://github.com/rust-lang/crates.io-index"
1314 +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
1315 +dependencies = [
1316 + "derive_more-impl",
1317 +]
1318 +
1319 +[[package]]
1320 +name = "derive_more-impl"
1321 +version = "2.1.1"
1322 +source = "registry+https://github.com/rust-lang/crates.io-index"
1323 +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
1324 +dependencies = [
1325 + "proc-macro2",
1326 + "quote",
1327 + "rustc_version",
1328 + "syn 2.0.117",
1329 +]
1330 +
1331 +[[package]]
1332 +name = "derivre"
1333 +version = "0.3.8"
1334 +source = "registry+https://github.com/rust-lang/crates.io-index"
1335 +checksum = "786c7c65c4ef0c7deb05de3005e01991612a8f09fe0844fc0969c68b90468ba8"
1336 +dependencies = [
1337 + "anyhow",
1338 + "bytemuck",
1339 + "bytemuck_derive",
1340 + "hashbrown 0.15.5",
1341 + "regex-syntax",
1342 + "strum",
1343 +]
1344 +
1345 +[[package]]
1346 +name = "deunicode"
1347 +version = "1.6.2"
1348 +source = "registry+https://github.com/rust-lang/crates.io-index"
1349 +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04"
1350 +
1351 +[[package]]
1352 +name = "digest"
1353 +version = "0.10.7"
1354 +source = "registry+https://github.com/rust-lang/crates.io-index"
1355 +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
1356 +dependencies = [
1357 + "block-buffer",
1358 + "crypto-common",
1359 +]
1360 +
1361 +[[package]]
1362 +name = "dirs"
1363 +version = "6.0.0"
1364 +source = "registry+https://github.com/rust-lang/crates.io-index"
1365 +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
1366 +dependencies = [
1367 + "dirs-sys",
1368 +]
1369 +
1370 +[[package]]
1371 +name = "dirs-sys"
1372 +version = "0.5.0"
1373 +source = "registry+https://github.com/rust-lang/crates.io-index"
1374 +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
1375 +dependencies = [
1376 + "libc",
1377 + "option-ext",
1378 + "redox_users",
1379 + "windows-sys 0.61.2",
1380 +]
1381 +
1382 +[[package]]
1383 +name = "dispatch2"
1384 +version = "0.3.1"
1385 +source = "registry+https://github.com/rust-lang/crates.io-index"
1386 +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
1387 +dependencies = [
1388 + "bitflags 2.11.0",
1389 + "block2",
1390 + "objc2",
1391 +]
1392 +
1393 +[[package]]
1394 +name = "displaydoc"
1395 +version = "0.2.5"
1396 +source = "registry+https://github.com/rust-lang/crates.io-index"
1397 +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
1398 +dependencies = [
1399 + "proc-macro2",
1400 + "quote",
1401 + "syn 2.0.117",
1402 +]
1403 +
1404 +[[package]]
1405 +name = "doctest-file"
1406 +version = "1.0.0"
1407 +source = "registry+https://github.com/rust-lang/crates.io-index"
1408 +checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562"
1409 +
1410 +[[package]]
1411 +name = "dtoa"
1412 +version = "1.0.11"
1413 +source = "registry+https://github.com/rust-lang/crates.io-index"
1414 +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590"
1415 +
1416 +[[package]]
1417 +name = "dtoa-short"
1418 +version = "0.3.5"
1419 +source = "registry+https://github.com/rust-lang/crates.io-index"
1420 +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
1421 +dependencies = [
1422 + "dtoa",
1423 +]
1424 +
1425 +[[package]]
1426 +name = "dunce"
1427 +version = "1.0.5"
1428 +source = "registry+https://github.com/rust-lang/crates.io-index"
1429 +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
1430 +
1431 +[[package]]
1432 +name = "dyn-clone"
1433 +version = "1.0.20"
1434 +source = "registry+https://github.com/rust-lang/crates.io-index"
1435 +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
1436 +
1437 +[[package]]
1438 +name = "dyn-stack"
1439 +version = "0.13.2"
1440 +source = "registry+https://github.com/rust-lang/crates.io-index"
1441 +checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8"
1442 +dependencies = [
1443 + "bytemuck",
1444 + "dyn-stack-macros",
1445 +]
1446 +
1447 +[[package]]
1448 +name = "dyn-stack-macros"
1449 +version = "0.1.3"
1450 +source = "registry+https://github.com/rust-lang/crates.io-index"
1451 +checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9"
1452 +
1453 +[[package]]
1454 +name = "ego-tree"
1455 +version = "0.10.0"
1456 +source = "registry+https://github.com/rust-lang/crates.io-index"
1457 +checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8"
1458 +
1459 +[[package]]
1460 +name = "either"
1461 +version = "1.15.0"
1462 +source = "registry+https://github.com/rust-lang/crates.io-index"
1463 +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
1464 +dependencies = [
1465 + "serde",
1466 +]
1467 +
1468 +[[package]]
1469 +name = "encode_unicode"
1470 +version = "1.0.0"
1471 +source = "registry+https://github.com/rust-lang/crates.io-index"
1472 +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
1473 +
1474 +[[package]]
1475 +name = "encoding_rs"
1476 +version = "0.8.35"
1477 +source = "registry+https://github.com/rust-lang/crates.io-index"
1478 +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
1479 +dependencies = [
1480 + "cfg-if",
1481 +]
1482 +
1483 +[[package]]
1484 +name = "encoding_rs_io"
1485 +version = "0.1.7"
1486 +source = "registry+https://github.com/rust-lang/crates.io-index"
1487 +checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83"
1488 +dependencies = [
1489 + "encoding_rs",
1490 +]
1491 +
1492 +[[package]]
1493 +name = "endian-type"
1494 +version = "0.2.0"
1495 +source = "registry+https://github.com/rust-lang/crates.io-index"
1496 +checksum = "869b0adbda23651a9c5c0c3d270aac9fcb52e8622a8f2b17e57802d7791962f2"
1497 +
1498 +[[package]]
1499 +name = "enum-as-inner"
1500 +version = "0.6.1"
1501 +source = "registry+https://github.com/rust-lang/crates.io-index"
1502 +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
1503 +dependencies = [
1504 + "heck 0.5.0",
1505 + "proc-macro2",
1506 + "quote",
1507 + "syn 2.0.117",
1508 +]
1509 +
1510 +[[package]]
1511 +name = "equator"
1512 +version = "0.4.2"
1513 +source = "registry+https://github.com/rust-lang/crates.io-index"
1514 +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
1515 +dependencies = [
1516 + "equator-macro",
1517 +]
1518 +
1519 +[[package]]
1520 +name = "equator-macro"
1521 +version = "0.4.2"
1522 +source = "registry+https://github.com/rust-lang/crates.io-index"
1523 +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
1524 +dependencies = [
1525 + "proc-macro2",
1526 + "quote",
1527 + "syn 2.0.117",
1528 +]
1529 +
1530 +[[package]]
1531 +name = "equivalent"
1532 +version = "1.0.2"
1533 +source = "registry+https://github.com/rust-lang/crates.io-index"
1534 +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
1535 +
1536 +[[package]]
1537 +name = "errno"
1538 +version = "0.3.14"
1539 +source = "registry+https://github.com/rust-lang/crates.io-index"
1540 +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
1541 +dependencies = [
1542 + "libc",
1543 + "windows-sys 0.61.2",
1544 +]
1545 +
1546 +[[package]]
1547 +name = "esaxx-rs"
1548 +version = "0.1.10"
1549 +source = "registry+https://github.com/rust-lang/crates.io-index"
1550 +checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6"
1551 +
1552 +[[package]]
1553 +name = "exr"
1554 +version = "1.74.0"
1555 +source = "registry+https://github.com/rust-lang/crates.io-index"
1556 +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
1557 +dependencies = [
1558 + "bit_field",
1559 + "half",
1560 + "lebe",
1561 + "miniz_oxide",
1562 + "rayon-core",
1563 + "smallvec 1.15.1",
1564 + "zune-inflate",
1565 +]
1566 +
1567 +[[package]]
1568 +name = "extended"
1569 +version = "0.1.0"
1570 +source = "registry+https://github.com/rust-lang/crates.io-index"
1571 +checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365"
1572 +
1573 +[[package]]
1574 +name = "fancy-regex"
1575 +version = "0.13.0"
1576 +source = "registry+https://github.com/rust-lang/crates.io-index"
1577 +checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2"
1578 +dependencies = [
1579 + "bit-set 0.5.3",
1580 + "regex-automata",
1581 + "regex-syntax",
1582 +]
1583 +
1584 +[[package]]
1585 +name = "fancy-regex"
1586 +version = "0.14.0"
1587 +source = "registry+https://github.com/rust-lang/crates.io-index"
1588 +checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"
1589 +dependencies = [
1590 + "bit-set 0.8.0",
1591 + "regex-automata",
1592 + "regex-syntax",
1593 +]
1594 +
1595 +[[package]]
1596 +name = "fastrand"
1597 +version = "2.3.0"
1598 +source = "registry+https://github.com/rust-lang/crates.io-index"
1599 +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
1600 +
1601 +[[package]]
1602 +name = "fax"
1603 +version = "0.2.6"
1604 +source = "registry+https://github.com/rust-lang/crates.io-index"
1605 +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab"
1606 +dependencies = [
1607 + "fax_derive",
1608 +]
1609 +
1610 +[[package]]
1611 +name = "fax_derive"
1612 +version = "0.2.0"
1613 +source = "registry+https://github.com/rust-lang/crates.io-index"
1614 +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
1615 +dependencies = [
1616 + "proc-macro2",
1617 + "quote",
1618 + "syn 2.0.117",
1619 +]
1620 +
1621 +[[package]]
1622 +name = "fdeflate"
1623 +version = "0.3.7"
1624 +source = "registry+https://github.com/rust-lang/crates.io-index"
1625 +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
1626 +dependencies = [
1627 + "simd-adler32",
1628 +]
1629 +
1630 +[[package]]
1631 +name = "find-msvc-tools"
1632 +version = "0.1.9"
1633 +source = "registry+https://github.com/rust-lang/crates.io-index"
1634 +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
1635 +
1636 +[[package]]
1637 +name = "flate2"
1638 +version = "1.1.9"
1639 +source = "registry+https://github.com/rust-lang/crates.io-index"
1640 +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
1641 +dependencies = [
1642 + "crc32fast",
1643 + "miniz_oxide",
1644 +]
1645 +
1646 +[[package]]
1647 +name = "float8"
1648 +version = "0.7.0"
1649 +source = "registry+https://github.com/rust-lang/crates.io-index"
1650 +checksum = "c2d1f04709a8ac06e8e8042875a3c466cc4832d3c1a18dbcb9dba3c6e83046bc"
1651 +dependencies = [
1652 + "half",
1653 + "num-traits",
1654 + "rand 0.9.2",
1655 + "rand_distr 0.5.1",
1656 +]
1657 +
1658 +[[package]]
1659 +name = "fnv"
1660 +version = "1.0.7"
1661 +source = "registry+https://github.com/rust-lang/crates.io-index"
1662 +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
1663 +
1664 +[[package]]
1665 +name = "foldhash"
1666 +version = "0.1.5"
1667 +source = "registry+https://github.com/rust-lang/crates.io-index"
1668 +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
1669 +
1670 +[[package]]
1671 +name = "foldhash"
1672 +version = "0.2.0"
1673 +source = "registry+https://github.com/rust-lang/crates.io-index"
1674 +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
1675 +
1676 +[[package]]
1677 +name = "foreign-types"
1678 +version = "0.3.2"
1679 +source = "registry+https://github.com/rust-lang/crates.io-index"
1680 +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
1681 +dependencies = [
1682 + "foreign-types-shared 0.1.1",
1683 +]
1684 +
1685 +[[package]]
1686 +name = "foreign-types"
1687 +version = "0.5.0"
1688 +source = "registry+https://github.com/rust-lang/crates.io-index"
1689 +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
1690 +dependencies = [
1691 + "foreign-types-macros",
1692 + "foreign-types-shared 0.3.1",
1693 +]
1694 +
1695 +[[package]]
1696 +name = "foreign-types-macros"
1697 +version = "0.2.3"
1698 +source = "registry+https://github.com/rust-lang/crates.io-index"
1699 +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
1700 +dependencies = [
1701 + "proc-macro2",
1702 + "quote",
1703 + "syn 2.0.117",
1704 +]
1705 +
1706 +[[package]]
1707 +name = "foreign-types-shared"
1708 +version = "0.1.1"
1709 +source = "registry+https://github.com/rust-lang/crates.io-index"
1710 +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
1711 +
1712 +[[package]]
1713 +name = "foreign-types-shared"
1714 +version = "0.3.1"
1715 +source = "registry+https://github.com/rust-lang/crates.io-index"
1716 +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
1717 +
1718 +[[package]]
1719 +name = "form_urlencoded"
1720 +version = "1.2.2"
1721 +source = "registry+https://github.com/rust-lang/crates.io-index"
1722 +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
1723 +dependencies = [
1724 + "percent-encoding",
1725 +]
1726 +
1727 +[[package]]
1728 +name = "fs-err"
1729 +version = "2.11.0"
1730 +source = "registry+https://github.com/rust-lang/crates.io-index"
1731 +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
1732 +dependencies = [
1733 + "autocfg",
1734 +]
1735 +
1736 +[[package]]
1737 +name = "fs_extra"
1738 +version = "1.3.0"
1739 +source = "registry+https://github.com/rust-lang/crates.io-index"
1740 +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
1741 +
1742 +[[package]]
1743 +name = "futf"
1744 +version = "0.1.5"
1745 +source = "registry+https://github.com/rust-lang/crates.io-index"
1746 +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
1747 +dependencies = [
1748 + "mac",
1749 + "new_debug_unreachable",
1750 +]
1751 +
1752 +[[package]]
1753 +name = "futures"
1754 +version = "0.3.32"
1755 +source = "registry+https://github.com/rust-lang/crates.io-index"
1756 +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
1757 +dependencies = [
1758 + "futures-channel",
1759 + "futures-core",
1760 + "futures-executor",
1761 + "futures-io",
1762 + "futures-sink",
1763 + "futures-task",
1764 + "futures-util",
1765 +]
1766 +
1767 +[[package]]
1768 +name = "futures-channel"
1769 +version = "0.3.32"
1770 +source = "registry+https://github.com/rust-lang/crates.io-index"
1771 +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
1772 +dependencies = [
1773 + "futures-core",
1774 + "futures-sink",
1775 +]
1776 +
1777 +[[package]]
1778 +name = "futures-core"
1779 +version = "0.3.32"
1780 +source = "registry+https://github.com/rust-lang/crates.io-index"
1781 +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
1782 +
1783 +[[package]]
1784 +name = "futures-executor"
1785 +version = "0.3.32"
1786 +source = "registry+https://github.com/rust-lang/crates.io-index"
1787 +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
1788 +dependencies = [
1789 + "futures-core",
1790 + "futures-task",
1791 + "futures-util",
1792 +]
1793 +
1794 +[[package]]
1795 +name = "futures-io"
1796 +version = "0.3.32"
1797 +source = "registry+https://github.com/rust-lang/crates.io-index"
1798 +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
1799 +
1800 +[[package]]
1801 +name = "futures-macro"
1802 +version = "0.3.32"
1803 +source = "registry+https://github.com/rust-lang/crates.io-index"
1804 +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
1805 +dependencies = [
1806 + "proc-macro2",
1807 + "quote",
1808 + "syn 2.0.117",
1809 +]
1810 +
1811 +[[package]]
1812 +name = "futures-sink"
1813 +version = "0.3.32"
1814 +source = "registry+https://github.com/rust-lang/crates.io-index"
1815 +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
1816 +
1817 +[[package]]
1818 +name = "futures-task"
1819 +version = "0.3.32"
1820 +source = "registry+https://github.com/rust-lang/crates.io-index"
1821 +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
1822 +
1823 +[[package]]
1824 +name = "futures-util"
1825 +version = "0.3.32"
1826 +source = "registry+https://github.com/rust-lang/crates.io-index"
1827 +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
1828 +dependencies = [
1829 + "futures-channel",
1830 + "futures-core",
1831 + "futures-io",
1832 + "futures-macro",
1833 + "futures-sink",
1834 + "futures-task",
1835 + "memchr",
1836 + "pin-project-lite",
1837 + "slab",
1838 +]
1839 +
1840 +[[package]]
1841 +name = "fxhash"
1842 +version = "0.2.1"
1843 +source = "registry+https://github.com/rust-lang/crates.io-index"
1844 +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
1845 +dependencies = [
1846 + "byteorder",
1847 +]
1848 +
1849 +[[package]]
1850 +name = "galil-seiferas"
1851 +version = "0.1.5"
1852 +source = "registry+https://github.com/rust-lang/crates.io-index"
1853 +checksum = "794ac25cfda3fa11d2b07ff8c65889c6c03411646df54e59e606878d899e1d5a"
1854 +dependencies = [
1855 + "defmac",
1856 + "unchecked-index",
1857 +]
1858 +
1859 +[[package]]
1860 +name = "gemm"
1861 +version = "0.18.2"
1862 +source = "registry+https://github.com/rust-lang/crates.io-index"
1863 +checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451"
1864 +dependencies = [
1865 + "dyn-stack",
1866 + "gemm-c32 0.18.2",
1867 + "gemm-c64 0.18.2",
1868 + "gemm-common 0.18.2",
1869 + "gemm-f16 0.18.2",
1870 + "gemm-f32 0.18.2",
1871 + "gemm-f64 0.18.2",
1872 + "num-complex",
1873 + "num-traits",
1874 + "paste",
1875 + "raw-cpuid",
1876 + "seq-macro",
1877 +]
1878 +
1879 +[[package]]
1880 +name = "gemm"
1881 +version = "0.19.0"
1882 +source = "registry+https://github.com/rust-lang/crates.io-index"
1883 +checksum = "aa0673db364b12263d103b68337a68fbecc541d6f6b61ba72fe438654709eacb"
1884 +dependencies = [
1885 + "dyn-stack",
1886 + "gemm-c32 0.19.0",
1887 + "gemm-c64 0.19.0",
1888 + "gemm-common 0.19.0",
1889 + "gemm-f16 0.19.0",
1890 + "gemm-f32 0.19.0",
1891 + "gemm-f64 0.19.0",
1892 + "num-complex",
1893 + "num-traits",
1894 + "paste",
1895 + "raw-cpuid",
1896 + "seq-macro",
1897 +]
1898 +
1899 +[[package]]
1900 +name = "gemm-c32"
1901 +version = "0.18.2"
1902 +source = "registry+https://github.com/rust-lang/crates.io-index"
1903 +checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847"
1904 +dependencies = [
1905 + "dyn-stack",
1906 + "gemm-common 0.18.2",
1907 + "num-complex",
1908 + "num-traits",
1909 + "paste",
1910 + "raw-cpuid",
1911 + "seq-macro",
1912 +]
1913 +
1914 +[[package]]
1915 +name = "gemm-c32"
1916 +version = "0.19.0"
1917 +source = "registry+https://github.com/rust-lang/crates.io-index"
1918 +checksum = "086936dbdcb99e37aad81d320f98f670e53c1e55a98bee70573e83f95beb128c"
1919 +dependencies = [
1920 + "dyn-stack",
1921 + "gemm-common 0.19.0",
1922 + "num-complex",
1923 + "num-traits",
1924 + "paste",
1925 + "raw-cpuid",
1926 + "seq-macro",
1927 +]
1928 +
1929 +[[package]]
1930 +name = "gemm-c64"
1931 +version = "0.18.2"
1932 +source = "registry+https://github.com/rust-lang/crates.io-index"
1933 +checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf"
1934 +dependencies = [
1935 + "dyn-stack",
1936 + "gemm-common 0.18.2",
1937 + "num-complex",
1938 + "num-traits",
1939 + "paste",
1940 + "raw-cpuid",
1941 + "seq-macro",
1942 +]
1943 +
1944 +[[package]]
1945 +name = "gemm-c64"
1946 +version = "0.19.0"
1947 +source = "registry+https://github.com/rust-lang/crates.io-index"
1948 +checksum = "20c8aeeeec425959bda4d9827664029ba1501a90a0d1e6228e48bef741db3a3f"
1949 +dependencies = [
1950 + "dyn-stack",
1951 + "gemm-common 0.19.0",
1952 + "num-complex",
1953 + "num-traits",
1954 + "paste",
1955 + "raw-cpuid",
1956 + "seq-macro",
1957 +]
1958 +
1959 +[[package]]
1960 +name = "gemm-common"
1961 +version = "0.18.2"
1962 +source = "registry+https://github.com/rust-lang/crates.io-index"
1963 +checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3"
1964 +dependencies = [
1965 + "bytemuck",
1966 + "dyn-stack",
1967 + "half",
1968 + "libm",
1969 + "num-complex",
1970 + "num-traits",
1971 + "once_cell",
1972 + "paste",
1973 + "pulp 0.21.5",
1974 + "raw-cpuid",
1975 + "rayon",
1976 + "seq-macro",
1977 + "sysctl",
1978 +]
1979 +
1980 +[[package]]
1981 +name = "gemm-common"
1982 +version = "0.19.0"
1983 +source = "registry+https://github.com/rust-lang/crates.io-index"
1984 +checksum = "88027625910cc9b1085aaaa1c4bc46bb3a36aad323452b33c25b5e4e7c8e2a3e"
1985 +dependencies = [
1986 + "bytemuck",
1987 + "dyn-stack",
1988 + "half",
1989 + "libm",
1990 + "num-complex",
1991 + "num-traits",
1992 + "once_cell",
1993 + "paste",
1994 + "pulp 0.22.2",
1995 + "raw-cpuid",
1996 + "rayon",
1997 + "seq-macro",
1998 + "sysctl",
1999 +]
2000 +
2001 +[[package]]
2002 +name = "gemm-f16"
2003 +version = "0.18.2"
2004 +source = "registry+https://github.com/rust-lang/crates.io-index"
2005 +checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109"
2006 +dependencies = [
2007 + "dyn-stack",
2008 + "gemm-common 0.18.2",
2009 + "gemm-f32 0.18.2",
2010 + "half",
2011 + "num-complex",
2012 + "num-traits",
2013 + "paste",
2014 + "raw-cpuid",
2015 + "rayon",
2016 + "seq-macro",
2017 +]
2018 +
2019 +[[package]]
2020 +name = "gemm-f16"
2021 +version = "0.19.0"
2022 +source = "registry+https://github.com/rust-lang/crates.io-index"
2023 +checksum = "e3df7a55202e6cd6739d82ae3399c8e0c7e1402859b30e4cb780e61525d9486e"
2024 +dependencies = [
2025 + "dyn-stack",
2026 + "gemm-common 0.19.0",
2027 + "gemm-f32 0.19.0",
2028 + "half",
2029 + "num-complex",
2030 + "num-traits",
2031 + "paste",
2032 + "raw-cpuid",
2033 + "rayon",
2034 + "seq-macro",
2035 +]
2036 +
2037 +[[package]]
2038 +name = "gemm-f32"
2039 +version = "0.18.2"
2040 +source = "registry+https://github.com/rust-lang/crates.io-index"
2041 +checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864"
2042 +dependencies = [
2043 + "dyn-stack",
2044 + "gemm-common 0.18.2",
2045 + "num-complex",
2046 + "num-traits",
2047 + "paste",
2048 + "raw-cpuid",
2049 + "seq-macro",
2050 +]
2051 +
2052 +[[package]]
2053 +name = "gemm-f32"
2054 +version = "0.19.0"
2055 +source = "registry+https://github.com/rust-lang/crates.io-index"
2056 +checksum = "02e0b8c9da1fbec6e3e3ab2ce6bc259ef18eb5f6f0d3e4edf54b75f9fd41a81c"
2057 +dependencies = [
2058 + "dyn-stack",
2059 + "gemm-common 0.19.0",
2060 + "num-complex",
2061 + "num-traits",
2062 + "paste",
2063 + "raw-cpuid",
2064 + "seq-macro",
2065 +]
2066 +
2067 +[[package]]
2068 +name = "gemm-f64"
2069 +version = "0.18.2"
2070 +source = "registry+https://github.com/rust-lang/crates.io-index"
2071 +checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd"
2072 +dependencies = [
2073 + "dyn-stack",
2074 + "gemm-common 0.18.2",
2075 + "num-complex",
2076 + "num-traits",
2077 + "paste",
2078 + "raw-cpuid",
2079 + "seq-macro",
2080 +]
2081 +
2082 +[[package]]
2083 +name = "gemm-f64"
2084 +version = "0.19.0"
2085 +source = "registry+https://github.com/rust-lang/crates.io-index"
2086 +checksum = "056131e8f2a521bfab322f804ccd652520c79700d81209e9d9275bbdecaadc6a"
2087 +dependencies = [
2088 + "dyn-stack",
2089 + "gemm-common 0.19.0",
2090 + "num-complex",
2091 + "num-traits",
2092 + "paste",
2093 + "raw-cpuid",
2094 + "seq-macro",
2095 +]
2096 +
2097 +[[package]]
2098 +name = "generator"
2099 +version = "0.7.5"
2100 +source = "registry+https://github.com/rust-lang/crates.io-index"
2101 +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e"
2102 +dependencies = [
2103 + "cc",
2104 + "libc",
2105 + "log",
2106 + "rustversion",
2107 + "windows 0.48.0",
2108 +]
2109 +
2110 +[[package]]
2111 +name = "generic-array"
2112 +version = "0.14.7"
2113 +source = "registry+https://github.com/rust-lang/crates.io-index"
2114 +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
2115 +dependencies = [
2116 + "typenum",
2117 + "version_check",
2118 +]
2119 +
2120 +[[package]]
2121 +name = "getopts"
2122 +version = "0.2.24"
2123 +source = "registry+https://github.com/rust-lang/crates.io-index"
2124 +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
2125 +dependencies = [
2126 + "unicode-width 0.2.2",
2127 +]
2128 +
2129 +[[package]]
2130 +name = "getrandom"
2131 +version = "0.2.17"
2132 +source = "registry+https://github.com/rust-lang/crates.io-index"
2133 +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
2134 +dependencies = [
2135 + "cfg-if",
2136 + "js-sys",
2137 + "libc",
2138 + "wasi",
2139 + "wasm-bindgen",
2140 +]
2141 +
2142 +[[package]]
2143 +name = "getrandom"
2144 +version = "0.3.4"
2145 +source = "registry+https://github.com/rust-lang/crates.io-index"
2146 +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
2147 +dependencies = [
2148 + "cfg-if",
2149 + "js-sys",
2150 + "libc",
2151 + "r-efi 5.3.0",
2152 + "wasip2",
2153 + "wasm-bindgen",
2154 +]
2155 +
2156 +[[package]]
2157 +name = "getrandom"
2158 +version = "0.4.2"
2159 +source = "registry+https://github.com/rust-lang/crates.io-index"
2160 +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
2161 +dependencies = [
2162 + "cfg-if",
2163 + "libc",
2164 + "r-efi 6.0.0",
2165 + "wasip2",
2166 + "wasip3",
2167 +]
2168 +
2169 +[[package]]
2170 +name = "gif"
2171 +version = "0.14.1"
2172 +source = "registry+https://github.com/rust-lang/crates.io-index"
2173 +checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e"
2174 +dependencies = [
2175 + "color_quant",
2176 + "weezl",
2177 +]
2178 +
2179 +[[package]]
2180 +name = "glob"
2181 +version = "0.3.3"
2182 +source = "registry+https://github.com/rust-lang/crates.io-index"
2183 +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
2184 +
2185 +[[package]]
2186 +name = "goblin"
2187 +version = "0.8.2"
2188 +source = "registry+https://github.com/rust-lang/crates.io-index"
2189 +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"
2190 +dependencies = [
2191 + "log",
2192 + "plain",
2193 + "scroll",
2194 +]
2195 +
2196 +[[package]]
2197 +name = "h2"
2198 +version = "0.4.13"
2199 +source = "registry+https://github.com/rust-lang/crates.io-index"
2200 +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
2201 +dependencies = [
2202 + "atomic-waker",
2203 + "bytes",
2204 + "fnv",
2205 + "futures-core",
2206 + "futures-sink",
2207 + "http",
2208 + "indexmap 2.13.0",
2209 + "slab",
2210 + "tokio",
2211 + "tokio-util",
2212 + "tracing",
2213 +]
2214 +
2215 +[[package]]
2216 +name = "half"
2217 +version = "2.7.1"
2218 +source = "registry+https://github.com/rust-lang/crates.io-index"
2219 +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
2220 +dependencies = [
2221 + "bytemuck",
2222 + "cfg-if",
2223 + "crunchy",
2224 + "num-traits",
2225 + "rand 0.9.2",
2226 + "rand_distr 0.5.1",
2227 + "zerocopy",
2228 +]
2229 +
2230 +[[package]]
2231 +name = "hashbrown"
2232 +version = "0.12.3"
2233 +source = "registry+https://github.com/rust-lang/crates.io-index"
2234 +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
2235 +
2236 +[[package]]
2237 +name = "hashbrown"
2238 +version = "0.15.5"
2239 +source = "registry+https://github.com/rust-lang/crates.io-index"
2240 +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
2241 +dependencies = [
2242 + "allocator-api2",
2243 + "equivalent",
2244 + "foldhash 0.1.5",
2245 +]
2246 +
2247 +[[package]]
2248 +name = "hashbrown"
2249 +version = "0.16.1"
2250 +source = "registry+https://github.com/rust-lang/crates.io-index"
2251 +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
2252 +dependencies = [
2253 + "allocator-api2",
2254 + "equivalent",
2255 + "foldhash 0.2.0",
2256 + "serde",
2257 + "serde_core",
2258 +]
2259 +
2260 +[[package]]
2261 +name = "heck"
2262 +version = "0.3.3"
2263 +source = "registry+https://github.com/rust-lang/crates.io-index"
2264 +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
2265 +dependencies = [
2266 + "unicode-segmentation",
2267 +]
2268 +
2269 +[[package]]
2270 +name = "heck"
2271 +version = "0.5.0"
2272 +source = "registry+https://github.com/rust-lang/crates.io-index"
2273 +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
2274 +
2275 +[[package]]
2276 +name = "hermit-abi"
2277 +version = "0.1.19"
2278 +source = "registry+https://github.com/rust-lang/crates.io-index"
2279 +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
2280 +dependencies = [
2281 + "libc",
2282 +]
2283 +
2284 +[[package]]
2285 +name = "hermit-abi"
2286 +version = "0.5.2"
2287 +source = "registry+https://github.com/rust-lang/crates.io-index"
2288 +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
2289 +
2290 +[[package]]
2291 +name = "hex"
2292 +version = "0.4.3"
2293 +source = "registry+https://github.com/rust-lang/crates.io-index"
2294 +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
2295 +
2296 +[[package]]
2297 +name = "hf-hub"
2298 +version = "0.4.3"
2299 +source = "registry+https://github.com/rust-lang/crates.io-index"
2300 +checksum = "629d8f3bbeda9d148036d6b0de0a3ab947abd08ce90626327fc3547a49d59d97"
2301 +dependencies = [
2302 + "dirs",
2303 + "futures",
2304 + "http",
2305 + "indicatif 0.17.11",
2306 + "libc",
2307 + "log",
2308 + "native-tls",
2309 + "num_cpus",
2310 + "rand 0.9.2",
2311 + "reqwest 0.12.28",
2312 + "serde",
2313 + "serde_json",
2314 + "thiserror 2.0.18",
2315 + "tokio",
2316 + "ureq",
2317 + "windows-sys 0.60.2",
2318 +]
2319 +
2320 +[[package]]
2321 +name = "home"
2322 +version = "0.5.12"
2323 +source = "registry+https://github.com/rust-lang/crates.io-index"
2324 +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
2325 +dependencies = [
2326 + "windows-sys 0.61.2",
2327 +]
2328 +
2329 +[[package]]
2330 +name = "hound"
2331 +version = "3.5.1"
2332 +source = "registry+https://github.com/rust-lang/crates.io-index"
2333 +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f"
2334 +
2335 +[[package]]
2336 +name = "html2text"
2337 +version = "0.16.7"
2338 +source = "registry+https://github.com/rust-lang/crates.io-index"
2339 +checksum = "12d23156ea4dbe6b37ad48fab2da56ff27b0f6192fb5db210c44eb07bfe6e787"
2340 +dependencies = [
2341 + "html5ever 0.38.0",
2342 + "tendril 0.5.0",
2343 + "thiserror 2.0.18",
2344 + "unicode-width 0.2.2",
2345 +]
2346 +
2347 +[[package]]
2348 +name = "html5ever"
2349 +version = "0.36.1"
2350 +source = "registry+https://github.com/rust-lang/crates.io-index"
2351 +checksum = "6452c4751a24e1b99c3260d505eaeee76a050573e61f30ac2c924ddc7236f01e"
2352 +dependencies = [
2353 + "log",
2354 + "markup5ever 0.36.1",
2355 +]
2356 +
2357 +[[package]]
2358 +name = "html5ever"
2359 +version = "0.38.0"
2360 +source = "registry+https://github.com/rust-lang/crates.io-index"
2361 +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2"
2362 +dependencies = [
2363 + "log",
2364 + "markup5ever 0.38.0",
2365 +]
2366 +
2367 +[[package]]
2368 +name = "http"
2369 +version = "1.4.0"
2370 +source = "registry+https://github.com/rust-lang/crates.io-index"
2371 +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
2372 +dependencies = [
2373 + "bytes",
2374 + "itoa",
2375 +]
2376 +
2377 +[[package]]
2378 +name = "http-body"
2379 +version = "1.0.1"
2380 +source = "registry+https://github.com/rust-lang/crates.io-index"
2381 +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
2382 +dependencies = [
2383 + "bytes",
2384 + "http",
2385 +]
2386 +
2387 +[[package]]
2388 +name = "http-body-util"
2389 +version = "0.1.3"
2390 +source = "registry+https://github.com/rust-lang/crates.io-index"
2391 +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
2392 +dependencies = [
2393 + "bytes",
2394 + "futures-core",
2395 + "http",
2396 + "http-body",
2397 + "pin-project-lite",
2398 +]
2399 +
2400 +[[package]]
2401 +name = "httparse"
2402 +version = "1.10.1"
2403 +source = "registry+https://github.com/rust-lang/crates.io-index"
2404 +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
2405 +
2406 +[[package]]
2407 +name = "hyper"
2408 +version = "1.8.1"
2409 +source = "registry+https://github.com/rust-lang/crates.io-index"
2410 +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
2411 +dependencies = [
2412 + "atomic-waker",
2413 + "bytes",
2414 + "futures-channel",
2415 + "futures-core",
2416 + "h2",
2417 + "http",
2418 + "http-body",
2419 + "httparse",
2420 + "itoa",
2421 + "pin-project-lite",
2422 + "pin-utils",
2423 + "smallvec 1.15.1",
2424 + "tokio",
2425 + "want",
2426 +]
2427 +
2428 +[[package]]
2429 +name = "hyper-rustls"
2430 +version = "0.27.7"
2431 +source = "registry+https://github.com/rust-lang/crates.io-index"
2432 +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
2433 +dependencies = [
2434 + "http",
2435 + "hyper",
2436 + "hyper-util",
2437 + "rustls",
2438 + "rustls-pki-types",
2439 + "tokio",
2440 + "tokio-rustls",
2441 + "tower-service",
2442 + "webpki-roots 1.0.6",
2443 +]
2444 +
2445 +[[package]]
2446 +name = "hyper-tls"
2447 +version = "0.6.0"
2448 +source = "registry+https://github.com/rust-lang/crates.io-index"
2449 +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
2450 +dependencies = [
2451 + "bytes",
2452 + "http-body-util",
2453 + "hyper",
2454 + "hyper-util",
2455 + "native-tls",
2456 + "tokio",
2457 + "tokio-native-tls",
2458 + "tower-service",
2459 +]
2460 +
2461 +[[package]]
2462 +name = "hyper-util"
2463 +version = "0.1.20"
2464 +source = "registry+https://github.com/rust-lang/crates.io-index"
2465 +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
2466 +dependencies = [
2467 + "base64 0.22.1",
2468 + "bytes",
2469 + "futures-channel",
2470 + "futures-util",
2471 + "http",
2472 + "http-body",
2473 + "hyper",
2474 + "ipnet",
2475 + "libc",
2476 + "percent-encoding",
2477 + "pin-project-lite",
2478 + "socket2",
2479 + "system-configuration",
2480 + "tokio",
2481 + "tower-service",
2482 + "tracing",
2483 + "windows-registry",
2484 +]
2485 +
2486 +[[package]]
2487 +name = "iana-time-zone"
2488 +version = "0.1.65"
2489 +source = "registry+https://github.com/rust-lang/crates.io-index"
2490 +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
2491 +dependencies = [
2492 + "android_system_properties",
2493 + "core-foundation-sys",
2494 + "iana-time-zone-haiku",
2495 + "js-sys",
2496 + "log",
2497 + "wasm-bindgen",
2498 + "windows-core 0.62.2",
2499 +]
2500 +
2501 +[[package]]
2502 +name = "iana-time-zone-haiku"
2503 +version = "0.1.2"
2504 +source = "registry+https://github.com/rust-lang/crates.io-index"
2505 +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
2506 +dependencies = [
2507 + "cc",
2508 +]
2509 +
2510 +[[package]]
2511 +name = "icu_collections"
2512 +version = "2.1.1"
2513 +source = "registry+https://github.com/rust-lang/crates.io-index"
2514 +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
2515 +dependencies = [
2516 + "displaydoc",
2517 + "potential_utf",
2518 + "yoke 0.8.1",
2519 + "zerofrom",
2520 + "zerovec",
2521 +]
2522 +
2523 +[[package]]
2524 +name = "icu_locale_core"
2525 +version = "2.1.1"
2526 +source = "registry+https://github.com/rust-lang/crates.io-index"
2527 +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
2528 +dependencies = [
2529 + "displaydoc",
2530 + "litemap",
2531 + "tinystr",
2532 + "writeable",
2533 + "zerovec",
2534 +]
2535 +
2536 +[[package]]
2537 +name = "icu_normalizer"
2538 +version = "2.1.1"
2539 +source = "registry+https://github.com/rust-lang/crates.io-index"
2540 +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
2541 +dependencies = [
2542 + "icu_collections",
2543 + "icu_normalizer_data",
2544 + "icu_properties",
2545 + "icu_provider",
2546 + "smallvec 1.15.1",
2547 + "zerovec",
2548 +]
2549 +
2550 +[[package]]
2551 +name = "icu_normalizer_data"
2552 +version = "2.1.1"
2553 +source = "registry+https://github.com/rust-lang/crates.io-index"
2554 +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
2555 +
2556 +[[package]]
2557 +name = "icu_properties"
2558 +version = "2.1.2"
2559 +source = "registry+https://github.com/rust-lang/crates.io-index"
2560 +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
2561 +dependencies = [
2562 + "icu_collections",
2563 + "icu_locale_core",
2564 + "icu_properties_data",
2565 + "icu_provider",
2566 + "zerotrie",
2567 + "zerovec",
2568 +]
2569 +
2570 +[[package]]
2571 +name = "icu_properties_data"
2572 +version = "2.1.2"
2573 +source = "registry+https://github.com/rust-lang/crates.io-index"
2574 +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
2575 +
2576 +[[package]]
2577 +name = "icu_provider"
2578 +version = "2.1.1"
2579 +source = "registry+https://github.com/rust-lang/crates.io-index"
2580 +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
2581 +dependencies = [
2582 + "displaydoc",
2583 + "icu_locale_core",
2584 + "writeable",
2585 + "yoke 0.8.1",
2586 + "zerofrom",
2587 + "zerotrie",
2588 + "zerovec",
2589 +]
2590 +
2591 +[[package]]
2592 +name = "id-arena"
2593 +version = "2.3.0"
2594 +source = "registry+https://github.com/rust-lang/crates.io-index"
2595 +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
2596 +
2597 +[[package]]
2598 +name = "ident_case"
2599 +version = "1.0.1"
2600 +source = "registry+https://github.com/rust-lang/crates.io-index"
2601 +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
2602 +
2603 +[[package]]
2604 +name = "idna"
2605 +version = "1.1.0"
2606 +source = "registry+https://github.com/rust-lang/crates.io-index"
2607 +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
2608 +dependencies = [
2609 + "idna_adapter",
2610 + "smallvec 1.15.1",
2611 + "utf8_iter",
2612 +]
2613 +
2614 +[[package]]
2615 +name = "idna_adapter"
2616 +version = "1.2.1"
2617 +source = "registry+https://github.com/rust-lang/crates.io-index"
2618 +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
2619 +dependencies = [
2620 + "icu_normalizer",
2621 + "icu_properties",
2622 +]
2623 +
2624 +[[package]]
2625 +name = "image"
2626 +version = "0.25.9"
2627 +source = "registry+https://github.com/rust-lang/crates.io-index"
2628 +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a"
2629 +dependencies = [
2630 + "bytemuck",
2631 + "byteorder-lite",
2632 + "color_quant",
2633 + "exr",
2634 + "gif",
2635 + "image-webp",
2636 + "moxcms",
2637 + "num-traits",
2638 + "png",
2639 + "qoi",
2640 + "ravif",
2641 + "rayon",
2642 + "rgb",
2643 + "tiff",
2644 + "zune-core 0.5.1",
2645 + "zune-jpeg 0.5.12",
2646 +]
2647 +
2648 +[[package]]
2649 +name = "image-webp"
2650 +version = "0.2.4"
2651 +source = "registry+https://github.com/rust-lang/crates.io-index"
2652 +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
2653 +dependencies = [
2654 + "byteorder-lite",
2655 + "quick-error",
2656 +]
2657 +
2658 +[[package]]
2659 +name = "imgref"
2660 +version = "1.12.0"
2661 +source = "registry+https://github.com/rust-lang/crates.io-index"
2662 +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8"
2663 +
2664 +[[package]]
2665 +name = "indexmap"
2666 +version = "1.9.3"
2667 +source = "registry+https://github.com/rust-lang/crates.io-index"
2668 +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
2669 +dependencies = [
2670 + "autocfg",
2671 + "hashbrown 0.12.3",
2672 + "serde",
2673 +]
2674 +
2675 +[[package]]
2676 +name = "indexmap"
2677 +version = "2.13.0"
2678 +source = "registry+https://github.com/rust-lang/crates.io-index"
2679 +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
2680 +dependencies = [
2681 + "equivalent",
2682 + "hashbrown 0.16.1",
2683 + "serde",
2684 + "serde_core",
2685 +]
2686 +
2687 +[[package]]
2688 +name = "indicatif"
2689 +version = "0.17.11"
2690 +source = "registry+https://github.com/rust-lang/crates.io-index"
2691 +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
2692 +dependencies = [
2693 + "console 0.15.11",
2694 + "number_prefix",
2695 + "portable-atomic",
2696 + "unicode-width 0.2.2",
2697 + "web-time",
2698 +]
2699 +
2700 +[[package]]
2701 +name = "indicatif"
2702 +version = "0.18.4"
2703 +source = "registry+https://github.com/rust-lang/crates.io-index"
2704 +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb"
2705 +dependencies = [
2706 + "console 0.16.2",
2707 + "portable-atomic",
2708 + "rayon",
2709 + "unicode-width 0.2.2",
2710 + "unit-prefix",
2711 + "web-time",
2712 +]
2713 +
2714 +[[package]]
2715 +name = "interpolate_name"
2716 +version = "0.2.4"
2717 +source = "registry+https://github.com/rust-lang/crates.io-index"
2718 +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
2719 +dependencies = [
2720 + "proc-macro2",
2721 + "quote",
2722 + "syn 2.0.117",
2723 +]
2724 +
2725 +[[package]]
2726 +name = "interprocess"
2727 +version = "2.4.0"
2728 +source = "registry+https://github.com/rust-lang/crates.io-index"
2729 +checksum = "6be5e5c847dbdb44564bd85294740d031f4f8aeb3464e5375ef7141f7538db69"
2730 +dependencies = [
2731 + "doctest-file",
2732 + "libc",
2733 + "recvmsg",
2734 + "widestring",
2735 + "windows-sys 0.52.0",
2736 +]
2737 +
2738 +[[package]]
2739 +name = "ipnet"
2740 +version = "2.12.0"
2741 +source = "registry+https://github.com/rust-lang/crates.io-index"
2742 +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
2743 +
2744 +[[package]]
2745 +name = "iri-string"
2746 +version = "0.7.10"
2747 +source = "registry+https://github.com/rust-lang/crates.io-index"
2748 +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
2749 +dependencies = [
2750 + "memchr",
2751 + "serde",
2752 +]
2753 +
2754 +[[package]]
2755 +name = "is_terminal_polyfill"
2756 +version = "1.70.2"
2757 +source = "registry+https://github.com/rust-lang/crates.io-index"
2758 +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
2759 +
2760 +[[package]]
2761 +name = "itertools"
2762 +version = "0.12.1"
2763 +source = "registry+https://github.com/rust-lang/crates.io-index"
2764 +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
2765 +dependencies = [
2766 + "either",
2767 +]
2768 +
2769 +[[package]]
2770 +name = "itertools"
2771 +version = "0.14.0"
2772 +source = "registry+https://github.com/rust-lang/crates.io-index"
2773 +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
2774 +dependencies = [
2775 + "either",
2776 +]
2777 +
2778 +[[package]]
2779 +name = "itoa"
2780 +version = "1.0.17"
2781 +source = "registry+https://github.com/rust-lang/crates.io-index"
2782 +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
2783 +
2784 +[[package]]
2785 +name = "jni"
2786 +version = "0.21.1"
2787 +source = "registry+https://github.com/rust-lang/crates.io-index"
2788 +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
2789 +dependencies = [
2790 + "cesu8",
2791 + "cfg-if",
2792 + "combine",
2793 + "jni-sys",
2794 + "log",
2795 + "thiserror 1.0.69",
2796 + "walkdir",
2797 + "windows-sys 0.45.0",
2798 +]
2799 +
2800 +[[package]]
2801 +name = "jni-sys"
2802 +version = "0.3.0"
2803 +source = "registry+https://github.com/rust-lang/crates.io-index"
2804 +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
2805 +
2806 +[[package]]
2807 +name = "jobserver"
2808 +version = "0.1.34"
2809 +source = "registry+https://github.com/rust-lang/crates.io-index"
2810 +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
2811 +dependencies = [
2812 + "getrandom 0.3.4",
2813 + "libc",
2814 +]
2815 +
2816 +[[package]]
2817 +name = "js-sys"
2818 +version = "0.3.91"
2819 +source = "registry+https://github.com/rust-lang/crates.io-index"
2820 +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
2821 +dependencies = [
2822 + "once_cell",
2823 + "wasm-bindgen",
2824 +]
2825 +
2826 +[[package]]
2827 +name = "lazy_static"
2828 +version = "1.5.0"
2829 +source = "registry+https://github.com/rust-lang/crates.io-index"
2830 +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
2831 +
2832 +[[package]]
2833 +name = "lazycell"
2834 +version = "1.3.0"
2835 +source = "registry+https://github.com/rust-lang/crates.io-index"
2836 +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
2837 +
2838 +[[package]]
2839 +name = "leb128fmt"
2840 +version = "0.1.0"
2841 +source = "registry+https://github.com/rust-lang/crates.io-index"
2842 +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
2843 +
2844 +[[package]]
2845 +name = "lebe"
2846 +version = "0.5.3"
2847 +source = "registry+https://github.com/rust-lang/crates.io-index"
2848 +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
2849 +
2850 +[[package]]
2851 +name = "libc"
2852 +version = "0.2.182"
2853 +source = "registry+https://github.com/rust-lang/crates.io-index"
2854 +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
2855 +
2856 +[[package]]
2857 +name = "libfuzzer-sys"
2858 +version = "0.4.12"
2859 +source = "registry+https://github.com/rust-lang/crates.io-index"
2860 +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
2861 +dependencies = [
2862 + "arbitrary",
2863 + "cc",
2864 +]
2865 +
2866 +[[package]]
2867 +name = "libloading"
2868 +version = "0.8.9"
2869 +source = "registry+https://github.com/rust-lang/crates.io-index"
2870 +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
2871 +dependencies = [
2872 + "cfg-if",
2873 + "windows-link 0.2.1",
2874 +]
2875 +
2876 +[[package]]
2877 +name = "libm"
2878 +version = "0.2.16"
2879 +source = "registry+https://github.com/rust-lang/crates.io-index"
2880 +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
2881 +
2882 +[[package]]
2883 +name = "libredox"
2884 +version = "0.1.14"
2885 +source = "registry+https://github.com/rust-lang/crates.io-index"
2886 +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
2887 +dependencies = [
2888 + "libc",
2889 +]
2890 +
2891 +[[package]]
2892 +name = "linux-raw-sys"
2893 +version = "0.12.1"
2894 +source = "registry+https://github.com/rust-lang/crates.io-index"
2895 +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
2896 +
2897 +[[package]]
2898 +name = "litemap"
2899 +version = "0.8.1"
2900 +source = "registry+https://github.com/rust-lang/crates.io-index"
2901 +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
2902 +
2903 +[[package]]
2904 +name = "llguidance"
2905 +version = "1.6.1"
2906 +source = "registry+https://github.com/rust-lang/crates.io-index"
2907 +checksum = "fd6bd9b883ab54097b0651668e5b590be1c7ca906500db40d4de74522382e011"
2908 +dependencies = [
2909 + "anyhow",
2910 + "derivre",
2911 + "indexmap 2.13.0",
2912 + "regex-syntax",
2913 + "serde",
2914 + "serde_json",
2915 + "toktrie",
2916 +]
2917 +
2918 +[[package]]
2919 +name = "lock_api"
2920 +version = "0.4.14"
2921 +source = "registry+https://github.com/rust-lang/crates.io-index"
2922 +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
2923 +dependencies = [
2924 + "scopeguard",
2925 +]
2926 +
2927 +[[package]]
2928 +name = "log"
2929 +version = "0.4.29"
2930 +source = "registry+https://github.com/rust-lang/crates.io-index"
2931 +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
2932 +
2933 +[[package]]
2934 +name = "loom"
2935 +version = "0.5.6"
2936 +source = "registry+https://github.com/rust-lang/crates.io-index"
2937 +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
2938 +dependencies = [
2939 + "cfg-if",
2940 + "generator",
2941 + "scoped-tls",
2942 + "serde",
2943 + "serde_json",
2944 + "tracing",
2945 + "tracing-subscriber",
2946 +]
2947 +
2948 +[[package]]
2949 +name = "loop9"
2950 +version = "0.1.5"
2951 +source = "registry+https://github.com/rust-lang/crates.io-index"
2952 +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
2953 +dependencies = [
2954 + "imgref",
2955 +]
2956 +
2957 +[[package]]
2958 +name = "lrtable"
2959 +version = "0.14.1"
2960 +source = "registry+https://github.com/rust-lang/crates.io-index"
2961 +checksum = "b15ad6a43e5cff4ac046d51281d2256a36d1440065eab53ccce9362b48db5b42"
2962 +dependencies = [
2963 + "cfgrammar",
2964 + "fnv",
2965 + "num-traits",
2966 + "sparsevec",
2967 + "vob",
2968 +]
2969 +
2970 +[[package]]
2971 +name = "lru-slab"
2972 +version = "0.1.2"
2973 +source = "registry+https://github.com/rust-lang/crates.io-index"
2974 +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
2975 +
2976 +[[package]]
2977 +name = "mac"
2978 +version = "0.1.1"
2979 +source = "registry+https://github.com/rust-lang/crates.io-index"
2980 +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
2981 +
2982 +[[package]]
2983 +name = "macro_rules_attribute"
2984 +version = "0.2.2"
2985 +source = "registry+https://github.com/rust-lang/crates.io-index"
2986 +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520"
2987 +dependencies = [
2988 + "macro_rules_attribute-proc_macro",
2989 + "paste",
2990 +]
2991 +
2992 +[[package]]
2993 +name = "macro_rules_attribute-proc_macro"
2994 +version = "0.2.2"
2995 +source = "registry+https://github.com/rust-lang/crates.io-index"
2996 +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
2997 +
2998 +[[package]]
2999 +name = "magnus"
3000 +version = "0.7.1"
3001 +source = "registry+https://github.com/rust-lang/crates.io-index"
3002 +checksum = "3d87ae53030f3a22e83879e666cb94e58a7bdf31706878a0ba48752994146dab"
3003 +dependencies = [
3004 + "magnus-macros",
3005 + "rb-sys",
3006 + "rb-sys-env",
3007 + "seq-macro",
3008 +]
3009 +
3010 +[[package]]
3011 +name = "magnus-macros"
3012 +version = "0.6.0"
3013 +source = "registry+https://github.com/rust-lang/crates.io-index"
3014 +checksum = "5968c820e2960565f647819f5928a42d6e874551cab9d88d75e3e0660d7f71e3"
3015 +dependencies = [
3016 + "proc-macro2",
3017 + "quote",
3018 + "syn 2.0.117",
3019 +]
3020 +
3021 +[[package]]
3022 +name = "malloc_buf"
3023 +version = "0.0.6"
3024 +source = "registry+https://github.com/rust-lang/crates.io-index"
3025 +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
3026 +dependencies = [
3027 + "libc",
3028 +]
3029 +
3030 +[[package]]
3031 +name = "markup5ever"
3032 +version = "0.36.1"
3033 +source = "registry+https://github.com/rust-lang/crates.io-index"
3034 +checksum = "6c3294c4d74d0742910f8c7b466f44dda9eb2d5742c1e430138df290a1e8451c"
3035 +dependencies = [
3036 + "log",
3037 + "tendril 0.4.3",
3038 + "web_atoms",
3039 +]
3040 +
3041 +[[package]]
3042 +name = "markup5ever"
3043 +version = "0.38.0"
3044 +source = "registry+https://github.com/rust-lang/crates.io-index"
3045 +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862"
3046 +dependencies = [
3047 + "log",
3048 + "tendril 0.5.0",
3049 + "web_atoms",
3050 +]
3051 +
3052 +[[package]]
3053 +name = "matchers"
3054 +version = "0.2.0"
3055 +source = "registry+https://github.com/rust-lang/crates.io-index"
3056 +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
3057 +dependencies = [
3058 + "regex-automata",
3059 +]
3060 +
3061 +[[package]]
3062 +name = "matrixmultiply"
3063 +version = "0.3.10"
3064 +source = "registry+https://github.com/rust-lang/crates.io-index"
3065 +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08"
3066 +dependencies = [
3067 + "autocfg",
3068 + "rawpointer",
3069 +]
3070 +
3071 +[[package]]
3072 +name = "maybe-rayon"
3073 +version = "0.1.1"
3074 +source = "registry+https://github.com/rust-lang/crates.io-index"
3075 +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
3076 +dependencies = [
3077 + "cfg-if",
3078 + "rayon",
3079 +]
3080 +
3081 +[[package]]
3082 +name = "memchr"
3083 +version = "2.8.0"
3084 +source = "registry+https://github.com/rust-lang/crates.io-index"
3085 +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
3086 +
3087 +[[package]]
3088 +name = "memmap2"
3089 +version = "0.9.10"
3090 +source = "registry+https://github.com/rust-lang/crates.io-index"
3091 +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
3092 +dependencies = [
3093 + "libc",
3094 + "stable_deref_trait",
3095 +]
3096 +
3097 +[[package]]
3098 +name = "metal"
3099 +version = "0.29.0"
3100 +source = "registry+https://github.com/rust-lang/crates.io-index"
3101 +checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
3102 +dependencies = [
3103 + "bitflags 2.11.0",
3104 + "block",
3105 + "core-graphics-types",
3106 + "foreign-types 0.5.0",
3107 + "log",
3108 + "objc",
3109 + "paste",
3110 +]
3111 +
3112 +[[package]]
3113 +name = "mime"
3114 +version = "0.3.17"
3115 +source = "registry+https://github.com/rust-lang/crates.io-index"
3116 +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
3117 +
3118 +[[package]]
3119 +name = "mime_guess"
3120 +version = "2.0.5"
3121 +source = "registry+https://github.com/rust-lang/crates.io-index"
3122 +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
3123 +dependencies = [
3124 + "mime",
3125 + "unicase",
3126 +]
3127 +
3128 +[[package]]
3129 +name = "minijinja"
3130 +version = "2.17.0"
3131 +source = "registry+https://github.com/rust-lang/crates.io-index"
3132 +checksum = "65ab6f50e4e8fb40bd21f527066bd019f5b029035b4e5ac9b9f9ba526c6bd87b"
3133 +dependencies = [
3134 + "serde",
3135 + "serde_json",
3136 +]
3137 +
3138 +[[package]]
3139 +name = "minijinja-contrib"
3140 +version = "2.17.0"
3141 +source = "registry+https://github.com/rust-lang/crates.io-index"
3142 +checksum = "2db46838f53a8c6e1d19135432e6b9bdbf4f0382c4fbf163f7f9dc24e31800e1"
3143 +dependencies = [
3144 + "minijinja",
3145 + "serde",
3146 +]
3147 +
3148 +[[package]]
3149 +name = "minimal-lexical"
3150 +version = "0.2.1"
3151 +source = "registry+https://github.com/rust-lang/crates.io-index"
3152 +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
3153 +
3154 +[[package]]
3155 +name = "miniz_oxide"
3156 +version = "0.8.9"
3157 +source = "registry+https://github.com/rust-lang/crates.io-index"
3158 +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
3159 +dependencies = [
3160 + "adler2",
3161 + "simd-adler32",
3162 +]
3163 +
3164 +[[package]]
3165 +name = "mio"
3166 +version = "0.8.11"
3167 +source = "registry+https://github.com/rust-lang/crates.io-index"
3168 +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
3169 +dependencies = [
3170 + "libc",
3171 + "log",
3172 + "wasi",
3173 + "windows-sys 0.48.0",
3174 +]
3175 +
3176 +[[package]]
3177 +name = "mio"
3178 +version = "1.1.1"
3179 +source = "registry+https://github.com/rust-lang/crates.io-index"
3180 +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
3181 +dependencies = [
3182 + "libc",
3183 + "wasi",
3184 + "windows-sys 0.61.2",
3185 +]
3186 +
3187 +[[package]]
3188 +name = "mistralrs"
3189 +version = "0.7.1-alpha.1"
3190 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3191 +dependencies = [
3192 + "anyhow",
3193 + "candle-core",
3194 + "candle-nn",
3195 + "clap 4.5.60",
3196 + "either",
3197 + "futures",
3198 + "image",
3199 + "indexmap 2.13.0",
3200 + "mistralrs-core",
3201 + "mistralrs-macros",
3202 + "rand 0.9.2",
3203 + "reqwest 0.13.2",
3204 + "schemars 1.2.1",
3205 + "serde",
3206 + "serde_json",
3207 + "thiserror 2.0.18",
3208 + "tokio",
3209 + "tracing",
3210 + "tracing-subscriber",
3211 + "walkdir",
3212 +]
3213 +
3214 +[[package]]
3215 +name = "mistralrs-audio"
3216 +version = "0.7.1-alpha.1"
3217 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3218 +dependencies = [
3219 + "anyhow",
3220 + "apodize",
3221 + "hound",
3222 + "symphonia",
3223 +]
3224 +
3225 +[[package]]
3226 +name = "mistralrs-core"
3227 +version = "0.7.1-alpha.1"
3228 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3229 +dependencies = [
3230 + "ahash",
3231 + "akin",
3232 + "anyhow",
3233 + "apodize",
3234 + "as-any",
3235 + "async-trait",
3236 + "base64 0.22.1",
3237 + "bm25",
3238 + "bytemuck",
3239 + "bytemuck_derive",
3240 + "candle-core",
3241 + "candle-metal-kernels",
3242 + "candle-nn",
3243 + "cfgrammar",
3244 + "chrono",
3245 + "clap 4.5.60",
3246 + "csv",
3247 + "derive-new",
3248 + "derive_more",
3249 + "dirs",
3250 + "either",
3251 + "float8",
3252 + "futures",
3253 + "galil-seiferas",
3254 + "half",
3255 + "hashbrown 0.16.1",
3256 + "hf-hub",
3257 + "hound",
3258 + "html2text",
3259 + "http",
3260 + "image",
3261 + "indexmap 2.13.0",
3262 + "indicatif 0.18.4",
3263 + "interprocess",
3264 + "itertools 0.14.0",
3265 + "libc",
3266 + "llguidance",
3267 + "lrtable",
3268 + "minijinja",
3269 + "minijinja-contrib",
3270 + "mistralrs-audio",
3271 + "mistralrs-mcp",
3272 + "mistralrs-paged-attn",
3273 + "mistralrs-quant",
3274 + "mistralrs-vision",
3275 + "num-traits",
3276 + "objc",
3277 + "objc2-metal",
3278 + "openai-harmony",
3279 + "ordered-float",
3280 + "parking_lot",
3281 + "radix_trie",
3282 + "rand 0.9.2",
3283 + "rand_distr 0.5.1",
3284 + "rand_isaac",
3285 + "rayon",
3286 + "regex",
3287 + "regex-automata",
3288 + "reqwest 0.13.2",
3289 + "rubato",
3290 + "rust-mcp-schema",
3291 + "rustc-hash 2.1.1",
3292 + "rustfft",
3293 + "safetensors 0.7.0",
3294 + "schemars 1.2.1",
3295 + "scraper",
3296 + "serde",
3297 + "serde-big-array",
3298 + "serde-saphyr",
3299 + "serde_json",
3300 + "serde_plain",
3301 + "statrs",
3302 + "strum",
3303 + "symphonia",
3304 + "sysinfo",
3305 + "thiserror 2.0.18",
3306 + "tokenizers",
3307 + "tokio",
3308 + "tokio-rayon",
3309 + "tokio-tungstenite",
3310 + "toktrie",
3311 + "toktrie_hf_tokenizers",
3312 + "toml",
3313 + "tqdm",
3314 + "tracing",
3315 + "tracing-subscriber",
3316 + "urlencoding",
3317 + "uuid 1.21.0",
3318 + "variantly",
3319 + "vob",
3320 +]
3321 +
3322 +[[package]]
3323 +name = "mistralrs-macros"
3324 +version = "0.7.1-alpha.1"
3325 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3326 +dependencies = [
3327 + "darling 0.23.0",
3328 + "proc-macro2",
3329 + "quote",
3330 + "syn 2.0.117",
3331 +]
3332 +
3333 +[[package]]
3334 +name = "mistralrs-mcp"
3335 +version = "0.7.1-alpha.1"
3336 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3337 +dependencies = [
3338 + "anyhow",
3339 + "async-trait",
3340 + "futures-util",
3341 + "http",
3342 + "reqwest 0.13.2",
3343 + "rust-mcp-schema",
3344 + "serde",
3345 + "serde_json",
3346 + "tokio",
3347 + "tokio-tungstenite",
3348 + "tracing",
3349 + "utoipa",
3350 + "uuid 1.21.0",
3351 +]
3352 +
3353 +[[package]]
3354 +name = "mistralrs-paged-attn"
3355 +version = "0.7.1-alpha.1"
3356 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3357 +dependencies = [
3358 + "anyhow",
3359 + "candle-core",
3360 + "candle-metal-kernels",
3361 + "dispatch2",
3362 + "float8",
3363 + "half",
3364 + "objc2-foundation",
3365 + "objc2-metal",
3366 + "thiserror 2.0.18",
3367 +]
3368 +
3369 +[[package]]
3370 +name = "mistralrs-quant"
3371 +version = "0.7.1-alpha.1"
3372 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3373 +dependencies = [
3374 + "byteorder",
3375 + "candle-core",
3376 + "candle-metal-kernels",
3377 + "candle-nn",
3378 + "dispatch2",
3379 + "float8",
3380 + "half",
3381 + "hf-hub",
3382 + "lazy_static",
3383 + "memmap2",
3384 + "objc2-foundation",
3385 + "objc2-metal",
3386 + "paste",
3387 + "rayon",
3388 + "regex",
3389 + "safetensors 0.7.0",
3390 + "serde",
3391 + "serde_json",
3392 + "thiserror 2.0.18",
3393 + "tokio",
3394 + "tracing",
3395 + "yoke 0.8.1",
3396 +]
3397 +
3398 +[[package]]
3399 +name = "mistralrs-vision"
3400 +version = "0.7.1-alpha.1"
3401 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3402 +dependencies = [
3403 + "candle-core",
3404 + "image",
3405 + "rayon",
3406 +]
3407 +
3408 +[[package]]
3409 +name = "monostate"
3410 +version = "0.1.18"
3411 +source = "registry+https://github.com/rust-lang/crates.io-index"
3412 +checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67"
3413 +dependencies = [
3414 + "monostate-impl",
3415 + "serde",
3416 + "serde_core",
3417 +]
3418 +
3419 +[[package]]
3420 +name = "monostate-impl"
3421 +version = "0.1.18"
3422 +source = "registry+https://github.com/rust-lang/crates.io-index"
3423 +checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9"
3424 +dependencies = [
3425 + "proc-macro2",
3426 + "quote",
3427 + "syn 2.0.117",
3428 +]
3429 +
3430 +[[package]]
3431 +name = "moxcms"
3432 +version = "0.7.11"
3433 +source = "registry+https://github.com/rust-lang/crates.io-index"
3434 +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
3435 +dependencies = [
3436 + "num-traits",
3437 + "pxfm",
3438 +]
3439 +
3440 +[[package]]
3441 +name = "nalgebra"
3442 +version = "0.33.2"
3443 +source = "registry+https://github.com/rust-lang/crates.io-index"
3444 +checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b"
3445 +dependencies = [
3446 + "approx",
3447 + "matrixmultiply",
3448 + "num-complex",
3449 + "num-rational",
3450 + "num-traits",
3451 + "rand 0.8.5",
3452 + "rand_distr 0.4.3",
3453 + "simba",
3454 + "typenum",
3455 +]
3456 +
3457 +[[package]]
3458 +name = "native-tls"
3459 +version = "0.2.18"
3460 +source = "registry+https://github.com/rust-lang/crates.io-index"
3461 +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2"
3462 +dependencies = [
3463 + "libc",
3464 + "log",
3465 + "openssl",
3466 + "openssl-probe",
3467 + "openssl-sys",
3468 + "schannel",
3469 + "security-framework",
3470 + "security-framework-sys",
3471 + "tempfile",
3472 +]
3473 +
3474 +[[package]]
3475 +name = "new_debug_unreachable"
3476 +version = "1.0.6"
3477 +source = "registry+https://github.com/rust-lang/crates.io-index"
3478 +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
3479 +
3480 +[[package]]
3481 +name = "nibble_vec"
3482 +version = "0.1.0"
3483 +source = "registry+https://github.com/rust-lang/crates.io-index"
3484 +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
3485 +dependencies = [
3486 + "smallvec 1.15.1",
3487 +]
3488 +
3489 +[[package]]
3490 +name = "nohash-hasher"
3491 +version = "0.2.0"
3492 +source = "registry+https://github.com/rust-lang/crates.io-index"
3493 +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
3494 +
3495 +[[package]]
3496 +name = "nom"
3497 +version = "7.1.3"
3498 +source = "registry+https://github.com/rust-lang/crates.io-index"
3499 +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
3500 +dependencies = [
3501 + "memchr",
3502 + "minimal-lexical",
3503 +]
3504 +
3505 +[[package]]
3506 +name = "nom"
3507 +version = "8.0.0"
3508 +source = "registry+https://github.com/rust-lang/crates.io-index"
3509 +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
3510 +dependencies = [
3511 + "memchr",
3512 +]
3513 +
3514 +[[package]]
3515 +name = "noop_proc_macro"
3516 +version = "0.3.0"
3517 +source = "registry+https://github.com/rust-lang/crates.io-index"
3518 +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
3519 +
3520 +[[package]]
3521 +name = "ntapi"
3522 +version = "0.4.3"
3523 +source = "registry+https://github.com/rust-lang/crates.io-index"
3524 +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae"
3525 +dependencies = [
3526 + "winapi",
3527 +]
3528 +
3529 +[[package]]
3530 +name = "nu-ansi-term"
3531 +version = "0.50.3"
3532 +source = "registry+https://github.com/rust-lang/crates.io-index"
3533 +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
3534 +dependencies = [
3535 + "windows-sys 0.61.2",
3536 +]
3537 +
3538 +[[package]]
3539 +name = "num"
3540 +version = "0.4.3"
3541 +source = "registry+https://github.com/rust-lang/crates.io-index"
3542 +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
3543 +dependencies = [
3544 + "num-bigint",
3545 + "num-complex",
3546 + "num-integer",
3547 + "num-iter",
3548 + "num-rational",
3549 + "num-traits",
3550 +]
3551 +
3552 +[[package]]
3553 +name = "num-bigint"
3554 +version = "0.4.6"
3555 +source = "registry+https://github.com/rust-lang/crates.io-index"
3556 +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
3557 +dependencies = [
3558 + "num-integer",
3559 + "num-traits",
3560 +]
3561 +
3562 +[[package]]
3563 +name = "num-complex"
3564 +version = "0.4.6"
3565 +source = "registry+https://github.com/rust-lang/crates.io-index"
3566 +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
3567 +dependencies = [
3568 + "bytemuck",
3569 + "num-traits",
3570 +]
3571 +
3572 +[[package]]
3573 +name = "num-conv"
3574 +version = "0.2.0"
3575 +source = "registry+https://github.com/rust-lang/crates.io-index"
3576 +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
3577 +
3578 +[[package]]
3579 +name = "num-derive"
3580 +version = "0.4.2"
3581 +source = "registry+https://github.com/rust-lang/crates.io-index"
3582 +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
3583 +dependencies = [
3584 + "proc-macro2",
3585 + "quote",
3586 + "syn 2.0.117",
3587 +]
3588 +
3589 +[[package]]
3590 +name = "num-integer"
3591 +version = "0.1.46"
3592 +source = "registry+https://github.com/rust-lang/crates.io-index"
3593 +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
3594 +dependencies = [
3595 + "num-traits",
3596 +]
3597 +
3598 +[[package]]
3599 +name = "num-iter"
3600 +version = "0.1.45"
3601 +source = "registry+https://github.com/rust-lang/crates.io-index"
3602 +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
3603 +dependencies = [
3604 + "autocfg",
3605 + "num-integer",
3606 + "num-traits",
3607 +]
3608 +
3609 +[[package]]
3610 +name = "num-rational"
3611 +version = "0.4.2"
3612 +source = "registry+https://github.com/rust-lang/crates.io-index"
3613 +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
3614 +dependencies = [
3615 + "num-bigint",
3616 + "num-integer",
3617 + "num-traits",
3618 +]
3619 +
3620 +[[package]]
3621 +name = "num-traits"
3622 +version = "0.2.19"
3623 +source = "registry+https://github.com/rust-lang/crates.io-index"
3624 +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
3625 +dependencies = [
3626 + "autocfg",
3627 + "libm",
3628 +]
3629 +
3630 +[[package]]
3631 +name = "num_cpus"
3632 +version = "1.17.0"
3633 +source = "registry+https://github.com/rust-lang/crates.io-index"
3634 +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
3635 +dependencies = [
3636 + "hermit-abi 0.5.2",
3637 + "libc",
3638 +]
3639 +
3640 +[[package]]
3641 +name = "number_prefix"
3642 +version = "0.4.0"
3643 +source = "registry+https://github.com/rust-lang/crates.io-index"
3644 +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
3645 +
3646 +[[package]]
3647 +name = "objc"
3648 +version = "0.2.7"
3649 +source = "registry+https://github.com/rust-lang/crates.io-index"
3650 +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
3651 +dependencies = [
3652 + "malloc_buf",
3653 +]
3654 +
3655 +[[package]]
3656 +name = "objc2"
3657 +version = "0.6.4"
3658 +source = "registry+https://github.com/rust-lang/crates.io-index"
3659 +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
3660 +dependencies = [
3661 + "objc2-encode",
3662 +]
3663 +
3664 +[[package]]
3665 +name = "objc2-core-foundation"
3666 +version = "0.3.2"
3667 +source = "registry+https://github.com/rust-lang/crates.io-index"
3668 +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
3669 +dependencies = [
3670 + "bitflags 2.11.0",
3671 + "dispatch2",
3672 + "objc2",
3673 +]
3674 +
3675 +[[package]]
3676 +name = "objc2-encode"
3677 +version = "4.1.0"
3678 +source = "registry+https://github.com/rust-lang/crates.io-index"
3679 +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
3680 +
3681 +[[package]]
3682 +name = "objc2-foundation"
3683 +version = "0.3.2"
3684 +source = "registry+https://github.com/rust-lang/crates.io-index"
3685 +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
3686 +dependencies = [
3687 + "bitflags 2.11.0",
3688 + "block2",
3689 + "libc",
3690 + "objc2",
3691 + "objc2-core-foundation",
3692 +]
3693 +
3694 +[[package]]
3695 +name = "objc2-io-kit"
3696 +version = "0.3.2"
3697 +source = "registry+https://github.com/rust-lang/crates.io-index"
3698 +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
3699 +dependencies = [
3700 + "libc",
3701 + "objc2-core-foundation",
3702 +]
3703 +
3704 +[[package]]
3705 +name = "objc2-metal"
3706 +version = "0.3.2"
3707 +source = "registry+https://github.com/rust-lang/crates.io-index"
3708 +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794"
3709 +dependencies = [
3710 + "bitflags 2.11.0",
3711 + "block2",
3712 + "dispatch2",
3713 + "objc2",
3714 + "objc2-core-foundation",
3715 + "objc2-foundation",
3716 +]
3717 +
3718 +[[package]]
3719 +name = "once_cell"
3720 +version = "1.21.3"
3721 +source = "registry+https://github.com/rust-lang/crates.io-index"
3722 +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
3723 +
3724 +[[package]]
3725 +name = "once_cell_polyfill"
3726 +version = "1.70.2"
3727 +source = "registry+https://github.com/rust-lang/crates.io-index"
3728 +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
3729 +
3730 +[[package]]
3731 +name = "onde"
3732 +version = "0.1.0"
3733 +dependencies = [
3734 + "anyhow",
3735 + "cc",
3736 + "hf-hub",
3737 + "home",
3738 + "log",
3739 + "mistralrs",
3740 + "mistralrs-core",
3741 + "serde",
3742 + "thiserror 2.0.18",
3743 + "tokio",
3744 + "tsync",
3745 + "uniffi",
3746 +]
3747 +
3748 +[[package]]
3749 +name = "onde-ruby"
3750 +version = "0.1.0"
3751 +dependencies = [
3752 + "magnus",
3753 + "onde",
3754 + "serde",
3755 + "serde_json",
3756 +]
3757 +
3758 +[[package]]
3759 +name = "openai-harmony"
3760 +version = "0.0.8"
3761 +source = "registry+https://github.com/rust-lang/crates.io-index"
3762 +checksum = "e77e82af451fc95deeb728a40b84db8ee82d341e136c268de415123a560b9b72"
3763 +dependencies = [
3764 + "anyhow",
3765 + "base64 0.22.1",
3766 + "bstr",
3767 + "clap 4.5.60",
3768 + "fancy-regex 0.13.0",
3769 + "futures",
3770 + "image",
3771 + "regex",
3772 + "reqwest 0.12.28",
3773 + "rustc-hash 1.1.0",
3774 + "serde",
3775 + "serde_json",
3776 + "serde_with",
3777 + "sha1",
3778 + "sha2",
3779 + "thiserror 2.0.18",
3780 +]
3781 +
3782 +[[package]]
3783 +name = "openssl"
3784 +version = "0.10.75"
3785 +source = "registry+https://github.com/rust-lang/crates.io-index"
3786 +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
3787 +dependencies = [
3788 + "bitflags 2.11.0",
3789 + "cfg-if",
3790 + "foreign-types 0.3.2",
3791 + "libc",
3792 + "once_cell",
3793 + "openssl-macros",
3794 + "openssl-sys",
3795 +]
3796 +
3797 +[[package]]
3798 +name = "openssl-macros"
3799 +version = "0.1.1"
3800 +source = "registry+https://github.com/rust-lang/crates.io-index"
3801 +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
3802 +dependencies = [
3803 + "proc-macro2",
3804 + "quote",
3805 + "syn 2.0.117",
3806 +]
3807 +
3808 +[[package]]
3809 +name = "openssl-probe"
3810 +version = "0.2.1"
3811 +source = "registry+https://github.com/rust-lang/crates.io-index"
3812 +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
3813 +
3814 +[[package]]
3815 +name = "openssl-sys"
3816 +version = "0.9.111"
3817 +source = "registry+https://github.com/rust-lang/crates.io-index"
3818 +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
3819 +dependencies = [
3820 + "cc",
3821 + "libc",
3822 + "pkg-config",
3823 + "vcpkg",
3824 +]
3825 +
3826 +[[package]]
3827 +name = "option-ext"
3828 +version = "0.2.0"
3829 +source = "registry+https://github.com/rust-lang/crates.io-index"
3830 +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
3831 +
3832 +[[package]]
3833 +name = "ordered-float"
3834 +version = "5.1.0"
3835 +source = "registry+https://github.com/rust-lang/crates.io-index"
3836 +checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
3837 +dependencies = [
3838 + "num-traits",
3839 +]
3840 +
3841 +[[package]]
3842 +name = "packedvec"
3843 +version = "1.2.5"
3844 +source = "registry+https://github.com/rust-lang/crates.io-index"
3845 +checksum = "a69e0a534dd2e6aefce319af62a0aa0066a76bdfcec0201dfe02df226bc9ec70"
3846 +dependencies = [
3847 + "num-traits",
3848 +]
3849 +
3850 +[[package]]
3851 +name = "parking_lot"
3852 +version = "0.12.5"
3853 +source = "registry+https://github.com/rust-lang/crates.io-index"
3854 +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
3855 +dependencies = [
3856 + "lock_api",
3857 + "parking_lot_core",
3858 +]
3859 +
3860 +[[package]]
3861 +name = "parking_lot_core"
3862 +version = "0.9.12"
3863 +source = "registry+https://github.com/rust-lang/crates.io-index"
3864 +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
3865 +dependencies = [
3866 + "cfg-if",
3867 + "libc",
3868 + "redox_syscall",
3869 + "smallvec 1.15.1",
3870 + "windows-link 0.2.1",
3871 +]
3872 +
3873 +[[package]]
3874 +name = "paste"
3875 +version = "1.0.15"
3876 +source = "registry+https://github.com/rust-lang/crates.io-index"
3877 +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
3878 +
3879 +[[package]]
3880 +name = "pastey"
3881 +version = "0.1.1"
3882 +source = "registry+https://github.com/rust-lang/crates.io-index"
3883 +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
3884 +
3885 +[[package]]
3886 +name = "percent-encoding"
3887 +version = "2.3.2"
3888 +source = "registry+https://github.com/rust-lang/crates.io-index"
3889 +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
3890 +
3891 +[[package]]
3892 +name = "phf"
3893 +version = "0.13.1"
3894 +source = "registry+https://github.com/rust-lang/crates.io-index"
3895 +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
3896 +dependencies = [
3897 + "phf_macros",
3898 + "phf_shared",
3899 + "serde",
3900 +]
3901 +
3902 +[[package]]
3903 +name = "phf_codegen"
3904 +version = "0.13.1"
3905 +source = "registry+https://github.com/rust-lang/crates.io-index"
3906 +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1"
3907 +dependencies = [
3908 + "phf_generator",
3909 + "phf_shared",
3910 +]
3911 +
3912 +[[package]]
3913 +name = "phf_generator"
3914 +version = "0.13.1"
3915 +source = "registry+https://github.com/rust-lang/crates.io-index"
3916 +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
3917 +dependencies = [
3918 + "fastrand",
3919 + "phf_shared",
3920 +]
3921 +
3922 +[[package]]
3923 +name = "phf_macros"
3924 +version = "0.13.1"
3925 +source = "registry+https://github.com/rust-lang/crates.io-index"
3926 +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
3927 +dependencies = [
3928 + "phf_generator",
3929 + "phf_shared",
3930 + "proc-macro2",
3931 + "quote",
3932 + "syn 2.0.117",
3933 +]
3934 +
3935 +[[package]]
3936 +name = "phf_shared"
3937 +version = "0.13.1"
3938 +source = "registry+https://github.com/rust-lang/crates.io-index"
3939 +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
3940 +dependencies = [
3941 + "siphasher",
3942 +]
3943 +
3944 +[[package]]
3945 +name = "pin-project-lite"
3946 +version = "0.2.17"
3947 +source = "registry+https://github.com/rust-lang/crates.io-index"
3948 +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
3949 +
3950 +[[package]]
3951 +name = "pin-utils"
3952 +version = "0.1.0"
3953 +source = "registry+https://github.com/rust-lang/crates.io-index"
3954 +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
3955 +
3956 +[[package]]
3957 +name = "pkg-config"
3958 +version = "0.3.32"
3959 +source = "registry+https://github.com/rust-lang/crates.io-index"
3960 +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
3961 +
3962 +[[package]]
3963 +name = "plain"
3964 +version = "0.2.3"
3965 +source = "registry+https://github.com/rust-lang/crates.io-index"
3966 +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
3967 +
3968 +[[package]]
3969 +name = "png"
3970 +version = "0.18.1"
3971 +source = "registry+https://github.com/rust-lang/crates.io-index"
3972 +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
3973 +dependencies = [
3974 + "bitflags 2.11.0",
3975 + "crc32fast",
3976 + "fdeflate",
3977 + "flate2",
3978 + "miniz_oxide",
3979 +]
3980 +
3981 +[[package]]
3982 +name = "portable-atomic"
3983 +version = "1.13.1"
3984 +source = "registry+https://github.com/rust-lang/crates.io-index"
3985 +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
3986 +
3987 +[[package]]
3988 +name = "potential_utf"
3989 +version = "0.1.4"
3990 +source = "registry+https://github.com/rust-lang/crates.io-index"
3991 +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
3992 +dependencies = [
3993 + "zerovec",
3994 +]
3995 +
3996 +[[package]]
3997 +name = "powerfmt"
3998 +version = "0.2.0"
3999 +source = "registry+https://github.com/rust-lang/crates.io-index"
4000 +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
4001 +
4002 +[[package]]
4003 +name = "ppv-lite86"
4004 +version = "0.2.21"
4005 +source = "registry+https://github.com/rust-lang/crates.io-index"
4006 +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
4007 +dependencies = [
4008 + "zerocopy",
4009 +]
4010 +
4011 +[[package]]
4012 +name = "precomputed-hash"
4013 +version = "0.1.1"
4014 +source = "registry+https://github.com/rust-lang/crates.io-index"
4015 +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
4016 +
4017 +[[package]]
4018 +name = "prettyplease"
4019 +version = "0.2.37"
4020 +source = "registry+https://github.com/rust-lang/crates.io-index"
4021 +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
4022 +dependencies = [
4023 + "proc-macro2",
4024 + "syn 2.0.117",
4025 +]
4026 +
4027 +[[package]]
4028 +name = "primal-check"
4029 +version = "0.3.4"
4030 +source = "registry+https://github.com/rust-lang/crates.io-index"
4031 +checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08"
4032 +dependencies = [
4033 + "num-integer",
4034 +]
4035 +
4036 +[[package]]
4037 +name = "proc-macro-error"
4038 +version = "1.0.4"
4039 +source = "registry+https://github.com/rust-lang/crates.io-index"
4040 +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
4041 +dependencies = [
4042 + "proc-macro-error-attr",
4043 + "proc-macro2",
4044 + "quote",
4045 + "syn 1.0.109",
4046 + "version_check",
4047 +]
4048 +
4049 +[[package]]
4050 +name = "proc-macro-error-attr"
4051 +version = "1.0.4"
4052 +source = "registry+https://github.com/rust-lang/crates.io-index"
4053 +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
4054 +dependencies = [
4055 + "proc-macro2",
4056 + "quote",
4057 + "version_check",
4058 +]
4059 +
4060 +[[package]]
4061 +name = "proc-macro2"
4062 +version = "1.0.106"
4063 +source = "registry+https://github.com/rust-lang/crates.io-index"
4064 +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
4065 +dependencies = [
4066 + "unicode-ident",
4067 +]
4068 +
4069 +[[package]]
4070 +name = "profiling"
4071 +version = "1.0.17"
4072 +source = "registry+https://github.com/rust-lang/crates.io-index"
4073 +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
4074 +dependencies = [
4075 + "profiling-procmacros",
4076 +]
4077 +
4078 +[[package]]
4079 +name = "profiling-procmacros"
4080 +version = "1.0.17"
4081 +source = "registry+https://github.com/rust-lang/crates.io-index"
4082 +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
4083 +dependencies = [
4084 + "quote",
4085 + "syn 2.0.117",
4086 +]
4087 +
4088 +[[package]]
4089 +name = "pulp"
4090 +version = "0.21.5"
4091 +source = "registry+https://github.com/rust-lang/crates.io-index"
4092 +checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907"
4093 +dependencies = [
4094 + "bytemuck",
4095 + "cfg-if",
4096 + "libm",
4097 + "num-complex",
4098 + "reborrow",
4099 + "version_check",
4100 +]
4101 +
4102 +[[package]]
4103 +name = "pulp"
4104 +version = "0.22.2"
4105 +source = "registry+https://github.com/rust-lang/crates.io-index"
4106 +checksum = "2e205bb30d5b916c55e584c22201771bcf2bad9aabd5d4127f38387140c38632"
4107 +dependencies = [
4108 + "bytemuck",
4109 + "cfg-if",
4110 + "libm",
4111 + "num-complex",
4112 + "paste",
4113 + "pulp-wasm-simd-flag",
4114 + "raw-cpuid",
4115 + "reborrow",
4116 + "version_check",
4117 +]
4118 +
4119 +[[package]]
4120 +name = "pulp-wasm-simd-flag"
4121 +version = "0.1.0"
4122 +source = "registry+https://github.com/rust-lang/crates.io-index"
4123 +checksum = "40e24eee682d89fb193496edf918a7f407d30175b2e785fe057e4392dfd182e0"
4124 +
4125 +[[package]]
4126 +name = "pxfm"
4127 +version = "0.1.28"
4128 +source = "registry+https://github.com/rust-lang/crates.io-index"
4129 +checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d"
4130 +
4131 +[[package]]
4132 +name = "qoi"
4133 +version = "0.4.1"
4134 +source = "registry+https://github.com/rust-lang/crates.io-index"
4135 +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
4136 +dependencies = [
4137 + "bytemuck",
4138 +]
4139 +
4140 +[[package]]
4141 +name = "quick-error"
4142 +version = "2.0.1"
4143 +source = "registry+https://github.com/rust-lang/crates.io-index"
4144 +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
4145 +
4146 +[[package]]
4147 +name = "quinn"
4148 +version = "0.11.9"
4149 +source = "registry+https://github.com/rust-lang/crates.io-index"
4150 +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
4151 +dependencies = [
4152 + "bytes",
4153 + "cfg_aliases",
4154 + "pin-project-lite",
4155 + "quinn-proto",
4156 + "quinn-udp",
4157 + "rustc-hash 2.1.1",
4158 + "rustls",
4159 + "socket2",
4160 + "thiserror 2.0.18",
4161 + "tokio",
4162 + "tracing",
4163 + "web-time",
4164 +]
4165 +
4166 +[[package]]
4167 +name = "quinn-proto"
4168 +version = "0.11.13"
4169 +source = "registry+https://github.com/rust-lang/crates.io-index"
4170 +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
4171 +dependencies = [
4172 + "aws-lc-rs",
4173 + "bytes",
4174 + "getrandom 0.3.4",
4175 + "lru-slab",
4176 + "rand 0.9.2",
4177 + "ring",
4178 + "rustc-hash 2.1.1",
4179 + "rustls",
4180 + "rustls-pki-types",
4181 + "slab",
4182 + "thiserror 2.0.18",
4183 + "tinyvec",
4184 + "tracing",
4185 + "web-time",
4186 +]
4187 +
4188 +[[package]]
4189 +name = "quinn-udp"
4190 +version = "0.5.14"
4191 +source = "registry+https://github.com/rust-lang/crates.io-index"
4192 +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
4193 +dependencies = [
4194 + "cfg_aliases",
4195 + "libc",
4196 + "once_cell",
4197 + "socket2",
4198 + "tracing",
4199 + "windows-sys 0.60.2",
4200 +]
4201 +
4202 +[[package]]
4203 +name = "quote"
4204 +version = "1.0.45"
4205 +source = "registry+https://github.com/rust-lang/crates.io-index"
4206 +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
4207 +dependencies = [
4208 + "proc-macro2",
4209 +]
4210 +
4211 +[[package]]
4212 +name = "r-efi"
4213 +version = "5.3.0"
4214 +source = "registry+https://github.com/rust-lang/crates.io-index"
4215 +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
4216 +
4217 +[[package]]
4218 +name = "r-efi"
4219 +version = "6.0.0"
4220 +source = "registry+https://github.com/rust-lang/crates.io-index"
4221 +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
4222 +
4223 +[[package]]
4224 +name = "radix_trie"
4225 +version = "0.3.0"
4226 +source = "registry+https://github.com/rust-lang/crates.io-index"
4227 +checksum = "3b4431027dcd37fc2a73ef740b5f233aa805897935b8bce0195e41bbf9a3289a"
4228 +dependencies = [
4229 + "endian-type",
4230 + "nibble_vec",
4231 +]
4232 +
4233 +[[package]]
4234 +name = "rand"
4235 +version = "0.8.5"
4236 +source = "registry+https://github.com/rust-lang/crates.io-index"
4237 +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
4238 +dependencies = [
4239 + "libc",
4240 + "rand_chacha 0.3.1",
4241 + "rand_core 0.6.4",
4242 +]
4243 +
4244 +[[package]]
4245 +name = "rand"
4246 +version = "0.9.2"
4247 +source = "registry+https://github.com/rust-lang/crates.io-index"
4248 +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
4249 +dependencies = [
4250 + "rand_chacha 0.9.0",
4251 + "rand_core 0.9.5",
4252 +]
4253 +
4254 +[[package]]
4255 +name = "rand_chacha"
4256 +version = "0.3.1"
4257 +source = "registry+https://github.com/rust-lang/crates.io-index"
4258 +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
4259 +dependencies = [
4260 + "ppv-lite86",
4261 + "rand_core 0.6.4",
4262 +]
4263 +
4264 +[[package]]
4265 +name = "rand_chacha"
4266 +version = "0.9.0"
4267 +source = "registry+https://github.com/rust-lang/crates.io-index"
4268 +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
4269 +dependencies = [
4270 + "ppv-lite86",
4271 + "rand_core 0.9.5",
4272 +]
4273 +
4274 +[[package]]
4275 +name = "rand_core"
4276 +version = "0.6.4"
4277 +source = "registry+https://github.com/rust-lang/crates.io-index"
4278 +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
4279 +dependencies = [
4280 + "getrandom 0.2.17",
4281 +]
4282 +
4283 +[[package]]
4284 +name = "rand_core"
4285 +version = "0.9.5"
4286 +source = "registry+https://github.com/rust-lang/crates.io-index"
4287 +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
4288 +dependencies = [
4289 + "getrandom 0.3.4",
4290 +]
4291 +
4292 +[[package]]
4293 +name = "rand_distr"
4294 +version = "0.4.3"
4295 +source = "registry+https://github.com/rust-lang/crates.io-index"
4296 +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
4297 +dependencies = [
4298 + "num-traits",
4299 + "rand 0.8.5",
4300 +]
4301 +
4302 +[[package]]
4303 +name = "rand_distr"
4304 +version = "0.5.1"
4305 +source = "registry+https://github.com/rust-lang/crates.io-index"
4306 +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463"
4307 +dependencies = [
4308 + "num-traits",
4309 + "rand 0.9.2",
4310 +]
4311 +
4312 +[[package]]
4313 +name = "rand_isaac"
4314 +version = "0.4.0"
4315 +source = "registry+https://github.com/rust-lang/crates.io-index"
4316 +checksum = "3382fc9f0aad4f2e2a56b53d9133c8c810b4dbf21e7e370e24346161a5b2c7bd"
4317 +dependencies = [
4318 + "rand_core 0.9.5",
4319 +]
4320 +
4321 +[[package]]
4322 +name = "rav1e"
4323 +version = "0.8.1"
4324 +source = "registry+https://github.com/rust-lang/crates.io-index"
4325 +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b"
4326 +dependencies = [
4327 + "aligned-vec",
4328 + "arbitrary",
4329 + "arg_enum_proc_macro",
4330 + "arrayvec",
4331 + "av-scenechange",
4332 + "av1-grain",
4333 + "bitstream-io",
4334 + "built",
4335 + "cfg-if",
4336 + "interpolate_name",
4337 + "itertools 0.14.0",
4338 + "libc",
4339 + "libfuzzer-sys",
4340 + "log",
4341 + "maybe-rayon",
4342 + "new_debug_unreachable",
4343 + "noop_proc_macro",
4344 + "num-derive",
4345 + "num-traits",
4346 + "paste",
4347 + "profiling",
4348 + "rand 0.9.2",
4349 + "rand_chacha 0.9.0",
4350 + "simd_helpers",
4351 + "thiserror 2.0.18",
4352 + "v_frame",
4353 + "wasm-bindgen",
4354 +]
4355 +
4356 +[[package]]
4357 +name = "ravif"
4358 +version = "0.12.0"
4359 +source = "registry+https://github.com/rust-lang/crates.io-index"
4360 +checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285"
4361 +dependencies = [
4362 + "avif-serialize",
4363 + "imgref",
4364 + "loop9",
4365 + "quick-error",
4366 + "rav1e",
4367 + "rayon",
4368 + "rgb",
4369 +]
4370 +
4371 +[[package]]
4372 +name = "raw-cpuid"
4373 +version = "11.6.0"
4374 +source = "registry+https://github.com/rust-lang/crates.io-index"
4375 +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
4376 +dependencies = [
4377 + "bitflags 2.11.0",
4378 +]
4379 +
4380 +[[package]]
4381 +name = "rawpointer"
4382 +version = "0.2.1"
4383 +source = "registry+https://github.com/rust-lang/crates.io-index"
4384 +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
4385 +
4386 +[[package]]
4387 +name = "rayon"
4388 +version = "1.11.0"
4389 +source = "registry+https://github.com/rust-lang/crates.io-index"
4390 +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
4391 +dependencies = [
4392 + "either",
4393 + "rayon-core",
4394 +]
4395 +
4396 +[[package]]
4397 +name = "rayon-cond"
4398 +version = "0.4.0"
4399 +source = "registry+https://github.com/rust-lang/crates.io-index"
4400 +checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f"
4401 +dependencies = [
4402 + "either",
4403 + "itertools 0.14.0",
4404 + "rayon",
4405 +]
4406 +
4407 +[[package]]
4408 +name = "rayon-core"
4409 +version = "1.13.0"
4410 +source = "registry+https://github.com/rust-lang/crates.io-index"
4411 +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
4412 +dependencies = [
4413 + "crossbeam-deque",
4414 + "crossbeam-utils",
4415 +]
4416 +
4417 +[[package]]
4418 +name = "rb-sys"
4419 +version = "0.9.124"
4420 +source = "registry+https://github.com/rust-lang/crates.io-index"
4421 +checksum = "c85c4188462601e2aa1469def389c17228566f82ea72f137ed096f21591bc489"
4422 +dependencies = [
4423 + "rb-sys-build",
4424 +]
4425 +
4426 +[[package]]
4427 +name = "rb-sys-build"
4428 +version = "0.9.124"
4429 +source = "registry+https://github.com/rust-lang/crates.io-index"
4430 +checksum = "568068db4102230882e6d4ae8de6632e224ca75fe5970f6e026a04e91ed635d3"
4431 +dependencies = [
4432 + "bindgen",
4433 + "lazy_static",
4434 + "proc-macro2",
4435 + "quote",
4436 + "regex",
4437 + "shell-words",
4438 + "syn 2.0.117",
4439 +]
4440 +
4441 +[[package]]
4442 +name = "rb-sys-env"
4443 +version = "0.1.2"
4444 +source = "registry+https://github.com/rust-lang/crates.io-index"
4445 +checksum = "a35802679f07360454b418a5d1735c89716bde01d35b1560fc953c1415a0b3bb"
4446 +
4447 +[[package]]
4448 +name = "realfft"
4449 +version = "3.5.0"
4450 +source = "registry+https://github.com/rust-lang/crates.io-index"
4451 +checksum = "f821338fddb99d089116342c46e9f1fbf3828dba077674613e734e01d6ea8677"
4452 +dependencies = [
4453 + "rustfft",
4454 +]
4455 +
4456 +[[package]]
4457 +name = "reborrow"
4458 +version = "0.5.5"
4459 +source = "registry+https://github.com/rust-lang/crates.io-index"
4460 +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430"
4461 +
4462 +[[package]]
4463 +name = "recvmsg"
4464 +version = "1.0.0"
4465 +source = "registry+https://github.com/rust-lang/crates.io-index"
4466 +checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175"
4467 +
4468 +[[package]]
4469 +name = "redox_syscall"
4470 +version = "0.5.18"
4471 +source = "registry+https://github.com/rust-lang/crates.io-index"
4472 +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
4473 +dependencies = [
4474 + "bitflags 2.11.0",
4475 +]
4476 +
4477 +[[package]]
4478 +name = "redox_users"
4479 +version = "0.5.2"
4480 +source = "registry+https://github.com/rust-lang/crates.io-index"
4481 +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
4482 +dependencies = [
4483 + "getrandom 0.2.17",
4484 + "libredox",
4485 + "thiserror 2.0.18",
4486 +]
4487 +
4488 +[[package]]
4489 +name = "ref-cast"
4490 +version = "1.0.25"
4491 +source = "registry+https://github.com/rust-lang/crates.io-index"
4492 +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
4493 +dependencies = [
4494 + "ref-cast-impl",
4495 +]
4496 +
4497 +[[package]]
4498 +name = "ref-cast-impl"
4499 +version = "1.0.25"
4500 +source = "registry+https://github.com/rust-lang/crates.io-index"
4501 +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
4502 +dependencies = [
4503 + "proc-macro2",
4504 + "quote",
4505 + "syn 2.0.117",
4506 +]
4507 +
4508 +[[package]]
4509 +name = "regex"
4510 +version = "1.12.3"
4511 +source = "registry+https://github.com/rust-lang/crates.io-index"
4512 +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
4513 +dependencies = [
4514 + "aho-corasick",
4515 + "memchr",
4516 + "regex-automata",
4517 + "regex-syntax",
4518 +]
4519 +
4520 +[[package]]
4521 +name = "regex-automata"
4522 +version = "0.4.14"
4523 +source = "registry+https://github.com/rust-lang/crates.io-index"
4524 +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
4525 +dependencies = [
4526 + "aho-corasick",
4527 + "memchr",
4528 + "regex-syntax",
4529 +]
4530 +
4531 +[[package]]
4532 +name = "regex-syntax"
4533 +version = "0.8.10"
4534 +source = "registry+https://github.com/rust-lang/crates.io-index"
4535 +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
4536 +
4537 +[[package]]
4538 +name = "reqwest"
4539 +version = "0.12.28"
4540 +source = "registry+https://github.com/rust-lang/crates.io-index"
4541 +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
4542 +dependencies = [
4543 + "base64 0.22.1",
4544 + "bytes",
4545 + "encoding_rs",
4546 + "futures-channel",
4547 + "futures-core",
4548 + "futures-util",
4549 + "h2",
4550 + "http",
4551 + "http-body",
4552 + "http-body-util",
4553 + "hyper",
4554 + "hyper-rustls",
4555 + "hyper-tls",
4556 + "hyper-util",
4557 + "js-sys",
4558 + "log",
4559 + "mime",
4560 + "mime_guess",
4561 + "native-tls",
4562 + "percent-encoding",
4563 + "pin-project-lite",
4564 + "quinn",
4565 + "rustls",
4566 + "rustls-pki-types",
4567 + "serde",
4568 + "serde_json",
4569 + "serde_urlencoded",
4570 + "sync_wrapper",
4571 + "tokio",
4572 + "tokio-native-tls",
4573 + "tokio-rustls",
4574 + "tokio-util",
4575 + "tower",
4576 + "tower-http",
4577 + "tower-service",
4578 + "url",
4579 + "wasm-bindgen",
4580 + "wasm-bindgen-futures",
4581 + "wasm-streams 0.4.2",
4582 + "web-sys",
4583 + "webpki-roots 1.0.6",
4584 +]
4585 +
4586 +[[package]]
4587 +name = "reqwest"
4588 +version = "0.13.2"
4589 +source = "registry+https://github.com/rust-lang/crates.io-index"
4590 +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
4591 +dependencies = [
4592 + "base64 0.22.1",
4593 + "bytes",
4594 + "encoding_rs",
4595 + "futures-channel",
4596 + "futures-core",
4597 + "futures-util",
4598 + "h2",
4599 + "http",
4600 + "http-body",
4601 + "http-body-util",
4602 + "hyper",
4603 + "hyper-rustls",
4604 + "hyper-util",
4605 + "js-sys",
4606 + "log",
4607 + "mime",
4608 + "percent-encoding",
4609 + "pin-project-lite",
4610 + "quinn",
4611 + "rustls",
4612 + "rustls-pki-types",
4613 + "rustls-platform-verifier",
4614 + "serde",
4615 + "serde_json",
4616 + "sync_wrapper",
4617 + "tokio",
4618 + "tokio-rustls",
4619 + "tokio-util",
4620 + "tower",
4621 + "tower-http",
4622 + "tower-service",
4623 + "url",
4624 + "wasm-bindgen",
4625 + "wasm-bindgen-futures",
4626 + "wasm-streams 0.5.0",
4627 + "web-sys",
4628 +]
4629 +
4630 +[[package]]
4631 +name = "rgb"
4632 +version = "0.8.53"
4633 +source = "registry+https://github.com/rust-lang/crates.io-index"
4634 +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
4635 +
4636 +[[package]]
4637 +name = "ring"
4638 +version = "0.17.14"
4639 +source = "registry+https://github.com/rust-lang/crates.io-index"
4640 +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
4641 +dependencies = [
4642 + "cc",
4643 + "cfg-if",
4644 + "getrandom 0.2.17",
4645 + "libc",
4646 + "untrusted",
4647 + "windows-sys 0.52.0",
4648 +]
4649 +
4650 +[[package]]
4651 +name = "rubato"
4652 +version = "0.16.2"
4653 +source = "registry+https://github.com/rust-lang/crates.io-index"
4654 +checksum = "5258099699851cfd0082aeb645feb9c084d9a5e1f1b8d5372086b989fc5e56a1"
4655 +dependencies = [
4656 + "num-complex",
4657 + "num-integer",
4658 + "num-traits",
4659 + "realfft",
4660 +]
4661 +
4662 +[[package]]
4663 +name = "rust-mcp-schema"
4664 +version = "0.9.5"
4665 +source = "registry+https://github.com/rust-lang/crates.io-index"
4666 +checksum = "5ed324cdee4b735926a1eaa7741b63a5d103ee08bbe0d3701398279b0c3bf3ce"
4667 +dependencies = [
4668 + "serde",
4669 + "serde_json",
4670 +]
4671 +
4672 +[[package]]
4673 +name = "rust-stemmers"
4674 +version = "1.2.0"
4675 +source = "registry+https://github.com/rust-lang/crates.io-index"
4676 +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
4677 +dependencies = [
4678 + "serde",
4679 + "serde_derive",
4680 +]
4681 +
4682 +[[package]]
4683 +name = "rustc-hash"
4684 +version = "1.1.0"
4685 +source = "registry+https://github.com/rust-lang/crates.io-index"
4686 +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
4687 +
4688 +[[package]]
4689 +name = "rustc-hash"
4690 +version = "2.1.1"
4691 +source = "registry+https://github.com/rust-lang/crates.io-index"
4692 +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
4693 +
4694 +[[package]]
4695 +name = "rustc_version"
4696 +version = "0.4.1"
4697 +source = "registry+https://github.com/rust-lang/crates.io-index"
4698 +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
4699 +dependencies = [
4700 + "semver",
4701 +]
4702 +
4703 +[[package]]
4704 +name = "rustfft"
4705 +version = "6.4.1"
4706 +source = "registry+https://github.com/rust-lang/crates.io-index"
4707 +checksum = "21db5f9893e91f41798c88680037dba611ca6674703c1a18601b01a72c8adb89"
4708 +dependencies = [
4709 + "num-complex",
4710 + "num-integer",
4711 + "num-traits",
4712 + "primal-check",
4713 + "strength_reduce",
4714 + "transpose",
4715 +]
4716 +
4717 +[[package]]
4718 +name = "rustix"
4719 +version = "1.1.4"
4720 +source = "registry+https://github.com/rust-lang/crates.io-index"
4721 +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
4722 +dependencies = [
4723 + "bitflags 2.11.0",
4724 + "errno",
4725 + "libc",
4726 + "linux-raw-sys",
4727 + "windows-sys 0.61.2",
4728 +]
4729 +
4730 +[[package]]
4731 +name = "rustls"
4732 +version = "0.23.37"
4733 +source = "registry+https://github.com/rust-lang/crates.io-index"
4734 +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
4735 +dependencies = [
4736 + "aws-lc-rs",
4737 + "log",
4738 + "once_cell",
4739 + "ring",
4740 + "rustls-pki-types",
4741 + "rustls-webpki",
4742 + "subtle",
4743 + "zeroize",
4744 +]
4745 +
4746 +[[package]]
4747 +name = "rustls-native-certs"
4748 +version = "0.8.3"
4749 +source = "registry+https://github.com/rust-lang/crates.io-index"
4750 +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
4751 +dependencies = [
4752 + "openssl-probe",
4753 + "rustls-pki-types",
4754 + "schannel",
4755 + "security-framework",
4756 +]
4757 +
4758 +[[package]]
4759 +name = "rustls-pki-types"
4760 +version = "1.14.0"
4761 +source = "registry+https://github.com/rust-lang/crates.io-index"
4762 +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
4763 +dependencies = [
4764 + "web-time",
4765 + "zeroize",
4766 +]
4767 +
4768 +[[package]]
4769 +name = "rustls-platform-verifier"
4770 +version = "0.6.2"
4771 +source = "registry+https://github.com/rust-lang/crates.io-index"
4772 +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
4773 +dependencies = [
4774 + "core-foundation 0.10.1",
4775 + "core-foundation-sys",
4776 + "jni",
4777 + "log",
4778 + "once_cell",
4779 + "rustls",
4780 + "rustls-native-certs",
4781 + "rustls-platform-verifier-android",
4782 + "rustls-webpki",
4783 + "security-framework",
4784 + "security-framework-sys",
4785 + "webpki-root-certs",
4786 + "windows-sys 0.61.2",
4787 +]
4788 +
4789 +[[package]]
4790 +name = "rustls-platform-verifier-android"
4791 +version = "0.1.1"
4792 +source = "registry+https://github.com/rust-lang/crates.io-index"
4793 +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
4794 +
4795 +[[package]]
4796 +name = "rustls-webpki"
4797 +version = "0.103.9"
4798 +source = "registry+https://github.com/rust-lang/crates.io-index"
4799 +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
4800 +dependencies = [
4801 + "aws-lc-rs",
4802 + "ring",
4803 + "rustls-pki-types",
4804 + "untrusted",
4805 +]
4806 +
4807 +[[package]]
4808 +name = "rustversion"
4809 +version = "1.0.22"
4810 +source = "registry+https://github.com/rust-lang/crates.io-index"
4811 +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
4812 +
4813 +[[package]]
4814 +name = "ryu"
4815 +version = "1.0.23"
4816 +source = "registry+https://github.com/rust-lang/crates.io-index"
4817 +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
4818 +
4819 +[[package]]
4820 +name = "safe_arch"
4821 +version = "0.7.4"
4822 +source = "registry+https://github.com/rust-lang/crates.io-index"
4823 +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
4824 +dependencies = [
4825 + "bytemuck",
4826 +]
4827 +
4828 +[[package]]
4829 +name = "safetensors"
4830 +version = "0.4.5"
4831 +source = "registry+https://github.com/rust-lang/crates.io-index"
4832 +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6"
4833 +dependencies = [
4834 + "serde",
4835 + "serde_json",
4836 +]
4837 +
4838 +[[package]]
4839 +name = "safetensors"
4840 +version = "0.7.0"
4841 +source = "registry+https://github.com/rust-lang/crates.io-index"
4842 +checksum = "675656c1eabb620b921efea4f9199f97fc86e36dd6ffd1fbbe48d0f59a4987f5"
4843 +dependencies = [
4844 + "hashbrown 0.16.1",
4845 + "serde",
4846 + "serde_json",
4847 +]
4848 +
4849 +[[package]]
4850 +name = "same-file"
4851 +version = "1.0.6"
4852 +source = "registry+https://github.com/rust-lang/crates.io-index"
4853 +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
4854 +dependencies = [
4855 + "winapi-util",
4856 +]
4857 +
4858 +[[package]]
4859 +name = "saphyr-parser-bw"
4860 +version = "0.0.605"
4861 +source = "registry+https://github.com/rust-lang/crates.io-index"
4862 +checksum = "5e1aee7486406df3541b5a657204a11be97175a467d77bc98e6d94a66289fb80"
4863 +dependencies = [
4864 + "arraydeque",
4865 + "smallvec 2.0.0-alpha.12",
4866 + "thiserror 2.0.18",
4867 +]
4868 +
4869 +[[package]]
4870 +name = "schannel"
4871 +version = "0.1.28"
4872 +source = "registry+https://github.com/rust-lang/crates.io-index"
4873 +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
4874 +dependencies = [
4875 + "windows-sys 0.61.2",
4876 +]
4877 +
4878 +[[package]]
4879 +name = "schemars"
4880 +version = "0.9.0"
4881 +source = "registry+https://github.com/rust-lang/crates.io-index"
4882 +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
4883 +dependencies = [
4884 + "dyn-clone",
4885 + "ref-cast",
4886 + "serde",
4887 + "serde_json",
4888 +]
4889 +
4890 +[[package]]
4891 +name = "schemars"
4892 +version = "1.2.1"
4893 +source = "registry+https://github.com/rust-lang/crates.io-index"
4894 +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc"
4895 +dependencies = [
4896 + "dyn-clone",
4897 + "ref-cast",
4898 + "schemars_derive",
4899 + "serde",
4900 + "serde_json",
4901 +]
4902 +
4903 +[[package]]
4904 +name = "schemars_derive"
4905 +version = "1.2.1"
4906 +source = "registry+https://github.com/rust-lang/crates.io-index"
4907 +checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f"
4908 +dependencies = [
4909 + "proc-macro2",
4910 + "quote",
4911 + "serde_derive_internals",
4912 + "syn 2.0.117",
4913 +]
4914 +
4915 +[[package]]
4916 +name = "scoped-tls"
4917 +version = "1.0.1"
4918 +source = "registry+https://github.com/rust-lang/crates.io-index"
4919 +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
4920 +
4921 +[[package]]
4922 +name = "scopeguard"
4923 +version = "1.2.0"
4924 +source = "registry+https://github.com/rust-lang/crates.io-index"
4925 +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
4926 +
4927 +[[package]]
4928 +name = "scraper"
4929 +version = "0.25.0"
4930 +source = "registry+https://github.com/rust-lang/crates.io-index"
4931 +checksum = "93cecd86d6259499c844440546d02f55f3e17bd286e529e48d1f9f67e92315cb"
4932 +dependencies = [
4933 + "cssparser",
4934 + "ego-tree",
4935 + "getopts",
4936 + "html5ever 0.36.1",
4937 + "precomputed-hash",
4938 + "selectors",
4939 + "tendril 0.4.3",
4940 +]
4941 +
4942 +[[package]]
4943 +name = "scroll"
4944 +version = "0.12.0"
4945 +source = "registry+https://github.com/rust-lang/crates.io-index"
4946 +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
4947 +dependencies = [
4948 + "scroll_derive",
4949 +]
4950 +
4951 +[[package]]
4952 +name = "scroll_derive"
4953 +version = "0.12.1"
4954 +source = "registry+https://github.com/rust-lang/crates.io-index"
4955 +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
4956 +dependencies = [
4957 + "proc-macro2",
4958 + "quote",
4959 + "syn 2.0.117",
4960 +]
4961 +
4962 +[[package]]
4963 +name = "security-framework"
4964 +version = "3.7.0"
4965 +source = "registry+https://github.com/rust-lang/crates.io-index"
4966 +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
4967 +dependencies = [
4968 + "bitflags 2.11.0",
4969 + "core-foundation 0.10.1",
4970 + "core-foundation-sys",
4971 + "libc",
4972 + "security-framework-sys",
4973 +]
4974 +
4975 +[[package]]
4976 +name = "security-framework-sys"
4977 +version = "2.17.0"
4978 +source = "registry+https://github.com/rust-lang/crates.io-index"
4979 +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
4980 +dependencies = [
4981 + "core-foundation-sys",
4982 + "libc",
4983 +]
4984 +
4985 +[[package]]
4986 +name = "selectors"
4987 +version = "0.33.0"
4988 +source = "registry+https://github.com/rust-lang/crates.io-index"
4989 +checksum = "feef350c36147532e1b79ea5c1f3791373e61cbd9a6a2615413b3807bb164fb7"
4990 +dependencies = [
4991 + "bitflags 2.11.0",
4992 + "cssparser",
4993 + "derive_more",
4994 + "log",
4995 + "new_debug_unreachable",
4996 + "phf",
4997 + "phf_codegen",
4998 + "precomputed-hash",
4999 + "rustc-hash 2.1.1",

This file is too large to show in full.

sdk/gem/Cargo.toml new
+3
@@ -0,0 +1,3 @@
1 +[workspace]
2 +members = ["ext/onde-ruby"]
3 +resolver = "2"
sdk/gem/Gemfile new
+11
@@ -0,0 +1,11 @@
1 +# frozen_string_literal: true
2 +
3 +source 'https://rubygems.org'
4 +
5 +# Specify your gem's dependencies in onde.gemspec
6 +gemspec
7 +
8 +gem 'rake', '~> 13.0'
9 +
10 +gem 'rake-compiler'
11 +gem 'rb_sys', '~> 0.9.63'
sdk/gem/README.md new
+228
@@ -0,0 +1,228 @@
1 +# Onde — Ruby Gem
2 +
3 +Ruby bindings for the [Onde](https://ondeinference.com) on-device inference engine, powered by Rust via [magnus](https://github.com/matsadler/magnus).
4 +
5 +Manage HuggingFace model caches, inspect supported models, and access inference configuration — all from Ruby, with zero C dependencies.
6 +
7 +## Requirements
8 +
9 +- Ruby >= 3.0
10 +- Rust >= 1.87 (installed via [rustup](https://rustup.rs))
11 +- macOS, Linux, or Windows
12 +
13 +## Installation
14 +
15 +Add to your Gemfile:
16 +
17 +```ruby
18 +gem 'onde'
19 +```
20 +
21 +Then:
22 +
23 +```bash
24 +bundle install
25 +```
26 +
27 +Or install directly:
28 +
29 +```bash
30 +gem install onde
31 +```
32 +
33 +The gem compiles a native Rust extension on install. Rust must be available on your `$PATH`.
34 +
35 +## Development Setup
36 +
37 +```bash
38 +cd lib/crates/onde/gem
39 +
40 +# Install dependencies and compile the native extension
41 +bin/setup
42 +
43 +# Or step by step:
44 +bundle install
45 +bundle exec rake compile
46 +
47 +# Open an interactive console with the gem loaded
48 +bin/console
49 +```
50 +
51 +## Building & Testing
52 +
53 +```bash
54 +# Compile the Rust extension
55 +bundle exec rake compile
56 +
57 +# Build the gem package
58 +bundle exec rake build
59 +
60 +# Run the default task (compile)
61 +bundle exec rake
62 +```
63 +
64 +## API Reference
65 +
66 +### `Onde.list_local_models` → Hash
67 +
68 +Scans the local HuggingFace hub cache (`~/.cache/huggingface/hub/`) and returns all downloaded models that the inference engine supports.
69 +
70 +```ruby
71 +response = Onde.list_local_models
72 +
73 +response["cache_path"] # => "/Users/you/.cache/huggingface/hub"
74 +response["total_size_bytes"] # => 24768454656
75 +response["total_size_display"] # => "23.07 GB"
76 +response["models"].each do |model|
77 + puts "#{model["model_id"]} — #{model["size_display"]} (#{model["revisions"].length} revisions)"
78 + puts " Path: #{model["path"]}"
79 +end
80 +```
81 +
82 +### `Onde.list_supported_models` → Hash
83 +
84 +Returns all models the engine supports with download status flags.
85 +
86 +```ruby
87 +Onde.list_supported_models["models"].each do |m|
88 + status = if m["is_downloaded"]
89 + "✓ downloaded"
90 + elsif m["is_incomplete"]
91 + "⏳ incomplete (#{m["local_size_display"]} / #{m["expected_size_display"]})"
92 + else
93 + "✗ not downloaded"
94 + end
95 + puts "[#{status}] #{m["name"]} (#{m["org"]})"
96 + puts " #{m["description"]}"
97 +end
98 +```
99 +
100 +Each model Hash contains:
101 +
102 +| Key | Type | Description |
103 +|-------------------------|---------|----------------------------------------------------|
104 +| `model_id` | String | Full HuggingFace ID, e.g. `"bartowski/Qwen2.5-1.5B-Instruct-GGUF"` |
105 +| `name` | String | Human-friendly display name |
106 +| `org` | String | Organisation or publisher |
107 +| `description` | String | Short description of the model |
108 +| `is_downloaded` | Boolean | Fully downloaded locally |
109 +| `is_incomplete` | Boolean | Partial download exists on disk |
110 +| `local_size_bytes` | Integer | Bytes currently on disk |
111 +| `local_size_display` | String | Human-readable local size |
112 +| `expected_size_bytes` | Integer | Approximate total size when fully downloaded |
113 +| `expected_size_display` | String | Human-readable expected size |
114 +
115 +### `Onde.delete_model(model_id)` → nil
116 +
117 +Delete a locally cached model. Raises `RuntimeError` if the model is not found or deletion fails.
118 +
119 +```ruby
120 +Onde.delete_model("bartowski/Qwen2.5-1.5B-Instruct-GGUF")
121 +```
122 +
123 +### `Onde.model_info(model_id)` → Hash or nil
124 +
125 +Look up rich metadata for a single supported model. Returns `nil` if the model ID is not in the supported list.
126 +
127 +```ruby
128 +info = Onde.model_info("bartowski/Qwen2.5-1.5B-Instruct-GGUF")
129 +# => {
130 +# "id" => "bartowski/Qwen2.5-1.5B-Instruct-GGUF",
131 +# "name" => "Qwen 2.5 1.5B (GGUF)",
132 +# "org" => "Qwen / Alibaba",
133 +# "description" => "Lightest pre-quantized chat model — ideal for iOS & Android (~941 MB)...",
134 +# "expected_size_bytes" => 986048768
135 +# }
136 +```
137 +
138 +### `Onde.supported_model_ids` → Array
139 +
140 +Returns the list of all supported model IDs as strings.
141 +
142 +```ruby
143 +Onde.supported_model_ids
144 +# => ["black-forest-labs/FLUX.1-schnell", "google/gemma-3n-E2B-it", ...]
145 +```
146 +
147 +### `Onde.cache_path` → String or nil
148 +
149 +Returns the resolved HuggingFace cache directory path, or `nil` if it cannot be determined.
150 +
151 +```ruby
152 +Onde.cache_path
153 +# => "/Users/you/.cache/huggingface/hub"
154 +```
155 +
156 +### Sampling Config Helpers
157 +
158 +Return sampling parameter Hashes suitable for passing to inference engines:
159 +
160 +```ruby
161 +Onde.default_sampling_config
162 +# => { "temperature" => 0.7, "top_p" => 0.95, "max_tokens" => 512, ... }
163 +
164 +Onde.deterministic_sampling_config
165 +# => { "temperature" => 0.0, "max_tokens" => 512, ... }
166 +
167 +Onde.mobile_sampling_config
168 +# => { "temperature" => 0.7, "top_p" => 0.95, "max_tokens" => 128, ... }
169 +```
170 +
171 +### Constants
172 +
173 +```ruby
174 +Onde::VERSION # => "0.1.0" (gem version)
175 +Onde::NATIVE_VERSION # => "0.1.0" (Rust crate version)
176 +Onde::SUPPORTED_MODELS # => ["black-forest-labs/FLUX.1-schnell", ...] (frozen Array)
177 +Onde::SUPPORTED_MODEL_INFO # => [{ "id" => ..., "name" => ..., ... }, ...] (frozen Array of frozen Hashes)
178 +```
179 +
180 +## Example: Rails Admin Dashboard
181 +
182 +```ruby
183 +# app/controllers/admin/models_controller.rb
184 +class Admin::ModelsController < ApplicationController
185 + def index
186 + @supported = Onde.list_supported_models["models"]
187 + @local = Onde.list_local_models
188 + end
189 +
190 + def destroy
191 + Onde.delete_model(params[:model_id])
192 + redirect_to admin_models_path, notice: "Model deleted."
193 + rescue RuntimeError => e
194 + redirect_to admin_models_path, alert: e.message
195 + end
196 +end
197 +```
198 +
199 +## Architecture
200 +
201 +```
202 +gem/
203 +├── onde.gemspec # Gem specification
204 +├── Gemfile # Dev dependencies (rake-compiler, rb_sys)
205 +├── Rakefile # Build tasks via RbSys::ExtensionTask
206 +├── rust-toolchain.toml # Pinned Rust toolchain version
207 +├── lib/
208 +│ ├── onde.rb # Entry point — loads native ext + defines module
209 +│ └── onde/
210 +│ └── version.rb # Onde::VERSION
211 +├── ext/
212 +│ └── onde/
213 +│ ├── Cargo.toml # Rust crate — depends on `onde` + `magnus`
214 +│ ├── extconf.rb # rb_sys build hook
215 +│ └── src/
216 +│ └── lib.rs # Magnus bindings — the bridge between Rust and Ruby
217 +└── bin/
218 + ├── console # IRB with gem loaded
219 + └── setup # One-step dev setup
220 +```
221 +
222 +The native extension compiles the `onde` Rust crate (which wraps [mistral.rs](https://github.com/EricLBuehler/mistral.rs) for LLM inference and HuggingFace Hub for model management) into a shared library (`.bundle` on macOS, `.so` on Linux) that Ruby loads at require time.
223 +
224 +All Rust structs are converted to Ruby Hashes via `serde_json` serialization, keeping the binding layer thin and the Ruby API simple — no custom Ruby classes needed.
225 +
226 +## License
227 +
228 +MIT OR Apache-2.0 — same as the Onde crate.
sdk/gem/Rakefile new
+14
@@ -0,0 +1,14 @@
1 +# frozen_string_literal: true
2 +
3 +require 'bundler/gem_tasks'
4 +require 'rb_sys/extensiontask'
5 +
6 +task build: :compile
7 +
8 +GEMSPEC = Gem::Specification.load('onde.gemspec')
9 +
10 +RbSys::ExtensionTask.new('onde-ruby', GEMSPEC) do |ext|
11 + ext.lib_dir = 'lib/onde'
12 +end
13 +
14 +task default: :compile
sdk/gem/bin/console new
+8
@@ -0,0 +1,8 @@
1 +#!/usr/bin/env ruby
2 +# frozen_string_literal: true
3 +
4 +require 'bundler/setup'
5 +require 'onde'
6 +
7 +require 'irb'
8 +IRB.start(__FILE__)
sdk/gem/bin/setup new
+9
@@ -0,0 +1,9 @@
1 +#!/usr/bin/env bash
2 +set -euo pipefail
3 +IFS=$'\n\t'
4 +set -vx
5 +
6 +bundle install
7 +
8 +# Compile the Rust native extension
9 +bundle exec rake compile
sdk/gem/ext/onde-ruby/Cargo.lock new
+7697
@@ -0,0 +1,7697 @@
1 +# This file is automatically @generated by Cargo.
2 +# It is not intended for manual editing.
3 +version = 4
4 +
5 +[[package]]
6 +name = "Inflector"
7 +version = "0.11.4"
8 +source = "registry+https://github.com/rust-lang/crates.io-index"
9 +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
10 +dependencies = [
11 + "lazy_static",
12 + "regex",
13 +]
14 +
15 +[[package]]
16 +name = "adler2"
17 +version = "2.0.1"
18 +source = "registry+https://github.com/rust-lang/crates.io-index"
19 +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
20 +
21 +[[package]]
22 +name = "ahash"
23 +version = "0.8.12"
24 +source = "registry+https://github.com/rust-lang/crates.io-index"
25 +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
26 +dependencies = [
27 + "cfg-if",
28 + "getrandom 0.3.4",
29 + "once_cell",
30 + "serde",
31 + "version_check",
32 + "zerocopy",
33 +]
34 +
35 +[[package]]
36 +name = "aho-corasick"
37 +version = "1.1.4"
38 +source = "registry+https://github.com/rust-lang/crates.io-index"
39 +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
40 +dependencies = [
41 + "memchr",
42 +]
43 +
44 +[[package]]
45 +name = "akin"
46 +version = "0.4.0"
47 +source = "registry+https://github.com/rust-lang/crates.io-index"
48 +checksum = "1763692fc1416554cf051efc56a3de5595eca47299d731cc5c2b583adf8b4d2f"
49 +
50 +[[package]]
51 +name = "aligned"
52 +version = "0.4.3"
53 +source = "registry+https://github.com/rust-lang/crates.io-index"
54 +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
55 +dependencies = [
56 + "as-slice",
57 +]
58 +
59 +[[package]]
60 +name = "aligned-vec"
61 +version = "0.6.4"
62 +source = "registry+https://github.com/rust-lang/crates.io-index"
63 +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
64 +dependencies = [
65 + "equator",
66 +]
67 +
68 +[[package]]
69 +name = "allocator-api2"
70 +version = "0.2.21"
71 +source = "registry+https://github.com/rust-lang/crates.io-index"
72 +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
73 +
74 +[[package]]
75 +name = "android_system_properties"
76 +version = "0.1.5"
77 +source = "registry+https://github.com/rust-lang/crates.io-index"
78 +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
79 +dependencies = [
80 + "libc",
81 +]
82 +
83 +[[package]]
84 +name = "annotate-snippets"
85 +version = "0.12.12"
86 +source = "registry+https://github.com/rust-lang/crates.io-index"
87 +checksum = "c86cd1c51b95d71dde52bca69ed225008f6ff4c8cc825b08042aa1ef823e1980"
88 +dependencies = [
89 + "anstyle",
90 + "memchr",
91 + "unicode-width 0.2.2",
92 +]
93 +
94 +[[package]]
95 +name = "ansi_term"
96 +version = "0.12.1"
97 +source = "registry+https://github.com/rust-lang/crates.io-index"
98 +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
99 +dependencies = [
100 + "winapi",
101 +]
102 +
103 +[[package]]
104 +name = "anstream"
105 +version = "0.6.21"
106 +source = "registry+https://github.com/rust-lang/crates.io-index"
107 +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
108 +dependencies = [
109 + "anstyle",
110 + "anstyle-parse",
111 + "anstyle-query",
112 + "anstyle-wincon",
113 + "colorchoice",
114 + "is_terminal_polyfill",
115 + "utf8parse",
116 +]
117 +
118 +[[package]]
119 +name = "anstyle"
120 +version = "1.0.13"
121 +source = "registry+https://github.com/rust-lang/crates.io-index"
122 +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
123 +
124 +[[package]]
125 +name = "anstyle-parse"
126 +version = "0.2.7"
127 +source = "registry+https://github.com/rust-lang/crates.io-index"
128 +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
129 +dependencies = [
130 + "utf8parse",
131 +]
132 +
133 +[[package]]
134 +name = "anstyle-query"
135 +version = "1.1.5"
136 +source = "registry+https://github.com/rust-lang/crates.io-index"
137 +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
138 +dependencies = [
139 + "windows-sys 0.61.2",
140 +]
141 +
142 +[[package]]
143 +name = "anstyle-wincon"
144 +version = "3.0.11"
145 +source = "registry+https://github.com/rust-lang/crates.io-index"
146 +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
147 +dependencies = [
148 + "anstyle",
149 + "once_cell_polyfill",
150 + "windows-sys 0.61.2",
151 +]
152 +
153 +[[package]]
154 +name = "anyhow"
155 +version = "1.0.102"
156 +source = "registry+https://github.com/rust-lang/crates.io-index"
157 +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
158 +
159 +[[package]]
160 +name = "apodize"
161 +version = "1.0.0"
162 +source = "registry+https://github.com/rust-lang/crates.io-index"
163 +checksum = "fca387cdc0a1f9c7a7c26556d584aa2d07fc529843082e4861003cde4ab914ed"
164 +
165 +[[package]]
166 +name = "approx"
167 +version = "0.5.1"
168 +source = "registry+https://github.com/rust-lang/crates.io-index"
169 +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
170 +dependencies = [
171 + "num-traits",
172 +]
173 +
174 +[[package]]
175 +name = "arbitrary"
176 +version = "1.4.2"
177 +source = "registry+https://github.com/rust-lang/crates.io-index"
178 +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
179 +
180 +[[package]]
181 +name = "arg_enum_proc_macro"
182 +version = "0.3.4"
183 +source = "registry+https://github.com/rust-lang/crates.io-index"
184 +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
185 +dependencies = [
186 + "proc-macro2",
187 + "quote",
188 + "syn 2.0.117",
189 +]
190 +
191 +[[package]]
192 +name = "arraydeque"
193 +version = "0.5.1"
194 +source = "registry+https://github.com/rust-lang/crates.io-index"
195 +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
196 +
197 +[[package]]
198 +name = "arrayvec"
199 +version = "0.7.6"
200 +source = "registry+https://github.com/rust-lang/crates.io-index"
201 +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
202 +
203 +[[package]]
204 +name = "as-any"
205 +version = "0.3.2"
206 +source = "registry+https://github.com/rust-lang/crates.io-index"
207 +checksum = "b0f477b951e452a0b6b4a10b53ccd569042d1d01729b519e02074a9c0958a063"
208 +
209 +[[package]]
210 +name = "as-slice"
211 +version = "0.2.1"
212 +source = "registry+https://github.com/rust-lang/crates.io-index"
213 +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
214 +dependencies = [
215 + "stable_deref_trait",
216 +]
217 +
218 +[[package]]
219 +name = "askama"
220 +version = "0.14.0"
221 +source = "registry+https://github.com/rust-lang/crates.io-index"
222 +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
223 +dependencies = [
224 + "askama_derive",
225 + "itoa",
226 + "percent-encoding",
227 + "serde",
228 + "serde_json",
229 +]
230 +
231 +[[package]]
232 +name = "askama_derive"
233 +version = "0.14.0"
234 +source = "registry+https://github.com/rust-lang/crates.io-index"
235 +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
236 +dependencies = [
237 + "askama_parser",
238 + "basic-toml",
239 + "memchr",
240 + "proc-macro2",
241 + "quote",
242 + "rustc-hash 2.1.1",
243 + "serde",
244 + "serde_derive",
245 + "syn 2.0.117",
246 +]
247 +
248 +[[package]]
249 +name = "askama_parser"
250 +version = "0.14.0"
251 +source = "registry+https://github.com/rust-lang/crates.io-index"
252 +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
253 +dependencies = [
254 + "memchr",
255 + "serde",
256 + "serde_derive",
257 + "winnow",
258 +]
259 +
260 +[[package]]
261 +name = "async-compat"
262 +version = "0.2.5"
263 +source = "registry+https://github.com/rust-lang/crates.io-index"
264 +checksum = "a1ba85bc55464dcbf728b56d97e119d673f4cf9062be330a9a26f3acf504a590"
265 +dependencies = [
266 + "futures-core",
267 + "futures-io",
268 + "once_cell",
269 + "pin-project-lite",
270 + "tokio",
271 +]
272 +
273 +[[package]]
274 +name = "async-trait"
275 +version = "0.1.89"
276 +source = "registry+https://github.com/rust-lang/crates.io-index"
277 +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
278 +dependencies = [
279 + "proc-macro2",
280 + "quote",
281 + "syn 2.0.117",
282 +]
283 +
284 +[[package]]
285 +name = "atomic-waker"
286 +version = "1.1.2"
287 +source = "registry+https://github.com/rust-lang/crates.io-index"
288 +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
289 +
290 +[[package]]
291 +name = "atty"
292 +version = "0.2.14"
293 +source = "registry+https://github.com/rust-lang/crates.io-index"
294 +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
295 +dependencies = [
296 + "hermit-abi 0.1.19",
297 + "libc",
298 + "winapi",
299 +]
300 +
301 +[[package]]
302 +name = "autocfg"
303 +version = "1.5.0"
304 +source = "registry+https://github.com/rust-lang/crates.io-index"
305 +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
306 +
307 +[[package]]
308 +name = "av-scenechange"
309 +version = "0.14.1"
310 +source = "registry+https://github.com/rust-lang/crates.io-index"
311 +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394"
312 +dependencies = [
313 + "aligned",
314 + "anyhow",
315 + "arg_enum_proc_macro",
316 + "arrayvec",
317 + "log",
318 + "num-rational",
319 + "num-traits",
320 + "pastey",
321 + "rayon",
322 + "thiserror 2.0.18",
323 + "v_frame",
324 + "y4m",
325 +]
326 +
327 +[[package]]
328 +name = "av1-grain"
329 +version = "0.2.5"
330 +source = "registry+https://github.com/rust-lang/crates.io-index"
331 +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
332 +dependencies = [
333 + "anyhow",
334 + "arrayvec",
335 + "log",
336 + "nom 8.0.0",
337 + "num-rational",
338 + "v_frame",
339 +]
340 +
341 +[[package]]
342 +name = "avif-serialize"
343 +version = "0.8.8"
344 +source = "registry+https://github.com/rust-lang/crates.io-index"
345 +checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d"
346 +dependencies = [
347 + "arrayvec",
348 +]
349 +
350 +[[package]]
351 +name = "aws-lc-rs"
352 +version = "1.16.1"
353 +source = "registry+https://github.com/rust-lang/crates.io-index"
354 +checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf"
355 +dependencies = [
356 + "aws-lc-sys",
357 + "zeroize",
358 +]
359 +
360 +[[package]]
361 +name = "aws-lc-sys"
362 +version = "0.38.0"
363 +source = "registry+https://github.com/rust-lang/crates.io-index"
364 +checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e"
365 +dependencies = [
366 + "cc",
367 + "cmake",
368 + "dunce",
369 + "fs_extra",
370 +]
371 +
372 +[[package]]
373 +name = "base64"
374 +version = "0.13.1"
375 +source = "registry+https://github.com/rust-lang/crates.io-index"
376 +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
377 +
378 +[[package]]
379 +name = "base64"
380 +version = "0.22.1"
381 +source = "registry+https://github.com/rust-lang/crates.io-index"
382 +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
383 +
384 +[[package]]
385 +name = "basic-toml"
386 +version = "0.1.10"
387 +source = "registry+https://github.com/rust-lang/crates.io-index"
388 +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
389 +dependencies = [
390 + "serde",
391 +]
392 +
393 +[[package]]
394 +name = "bindgen"
395 +version = "0.69.5"
396 +source = "registry+https://github.com/rust-lang/crates.io-index"
397 +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
398 +dependencies = [
399 + "bitflags 2.11.0",
400 + "cexpr",
401 + "clang-sys",
402 + "itertools 0.12.1",
403 + "lazy_static",
404 + "lazycell",
405 + "proc-macro2",
406 + "quote",
407 + "regex",
408 + "rustc-hash 1.1.0",
409 + "shlex",
410 + "syn 2.0.117",
411 +]
412 +
413 +[[package]]
414 +name = "bit-set"
415 +version = "0.5.3"
416 +source = "registry+https://github.com/rust-lang/crates.io-index"
417 +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
418 +dependencies = [
419 + "bit-vec 0.6.3",
420 +]
421 +
422 +[[package]]
423 +name = "bit-set"
424 +version = "0.8.0"
425 +source = "registry+https://github.com/rust-lang/crates.io-index"
426 +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
427 +dependencies = [
428 + "bit-vec 0.8.0",
429 +]
430 +
431 +[[package]]
432 +name = "bit-vec"
433 +version = "0.6.3"
434 +source = "registry+https://github.com/rust-lang/crates.io-index"
435 +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
436 +
437 +[[package]]
438 +name = "bit-vec"
439 +version = "0.8.0"
440 +source = "registry+https://github.com/rust-lang/crates.io-index"
441 +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
442 +
443 +[[package]]
444 +name = "bit_field"
445 +version = "0.10.3"
446 +source = "registry+https://github.com/rust-lang/crates.io-index"
447 +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
448 +
449 +[[package]]
450 +name = "bitflags"
451 +version = "1.3.2"
452 +source = "registry+https://github.com/rust-lang/crates.io-index"
453 +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
454 +
455 +[[package]]
456 +name = "bitflags"
457 +version = "2.11.0"
458 +source = "registry+https://github.com/rust-lang/crates.io-index"
459 +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
460 +
461 +[[package]]
462 +name = "bitstream-io"
463 +version = "4.9.0"
464 +source = "registry+https://github.com/rust-lang/crates.io-index"
465 +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757"
466 +dependencies = [
467 + "core2",
468 +]
469 +
470 +[[package]]
471 +name = "block"
472 +version = "0.1.6"
473 +source = "registry+https://github.com/rust-lang/crates.io-index"
474 +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
475 +
476 +[[package]]
477 +name = "block-buffer"
478 +version = "0.10.4"
479 +source = "registry+https://github.com/rust-lang/crates.io-index"
480 +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
481 +dependencies = [
482 + "generic-array",
483 +]
484 +
485 +[[package]]
486 +name = "block2"
487 +version = "0.6.2"
488 +source = "registry+https://github.com/rust-lang/crates.io-index"
489 +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
490 +dependencies = [
491 + "objc2",
492 +]
493 +
494 +[[package]]
495 +name = "bm25"
496 +version = "2.3.2"
497 +source = "registry+https://github.com/rust-lang/crates.io-index"
498 +checksum = "1cbd8ffdfb7b4c2ff038726178a780a94f90525ed0ad264c0afaa75dd8c18a64"
499 +dependencies = [
500 + "cached",
501 + "deunicode",
502 + "fxhash",
503 + "rust-stemmers",
504 + "stop-words",
505 + "unicode-segmentation",
506 +]
507 +
508 +[[package]]
509 +name = "bstr"
510 +version = "1.12.1"
511 +source = "registry+https://github.com/rust-lang/crates.io-index"
512 +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
513 +dependencies = [
514 + "memchr",
515 + "regex-automata",
516 + "serde",
517 +]
518 +
519 +[[package]]
520 +name = "built"
521 +version = "0.8.0"
522 +source = "registry+https://github.com/rust-lang/crates.io-index"
523 +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64"
524 +
525 +[[package]]
526 +name = "bumpalo"
527 +version = "3.20.2"
528 +source = "registry+https://github.com/rust-lang/crates.io-index"
529 +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
530 +
531 +[[package]]
532 +name = "bytemuck"
533 +version = "1.25.0"
534 +source = "registry+https://github.com/rust-lang/crates.io-index"
535 +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
536 +dependencies = [
537 + "bytemuck_derive",
538 +]
539 +
540 +[[package]]
541 +name = "bytemuck_derive"
542 +version = "1.10.2"
543 +source = "registry+https://github.com/rust-lang/crates.io-index"
544 +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
545 +dependencies = [
546 + "proc-macro2",
547 + "quote",
548 + "syn 2.0.117",
549 +]
550 +
551 +[[package]]
552 +name = "byteorder"
553 +version = "1.5.0"
554 +source = "registry+https://github.com/rust-lang/crates.io-index"
555 +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
556 +
557 +[[package]]
558 +name = "byteorder-lite"
559 +version = "0.1.0"
560 +source = "registry+https://github.com/rust-lang/crates.io-index"
561 +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
562 +
563 +[[package]]
564 +name = "bytes"
565 +version = "1.11.1"
566 +source = "registry+https://github.com/rust-lang/crates.io-index"
567 +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
568 +
569 +[[package]]
570 +name = "cached"
571 +version = "0.56.0"
572 +source = "registry+https://github.com/rust-lang/crates.io-index"
573 +checksum = "801927ee168e17809ab8901d9f01f700cd7d8d6a6527997fee44e4b0327a253c"
574 +dependencies = [
575 + "ahash",
576 + "cached_proc_macro",
577 + "cached_proc_macro_types",
578 + "hashbrown 0.15.5",
579 + "once_cell",
580 + "thiserror 2.0.18",
581 + "web-time",
582 +]
583 +
584 +[[package]]
585 +name = "cached_proc_macro"
586 +version = "0.25.0"
587 +source = "registry+https://github.com/rust-lang/crates.io-index"
588 +checksum = "9225bdcf4e4a9a4c08bf16607908eb2fbf746828d5e0b5e019726dbf6571f201"
589 +dependencies = [
590 + "darling 0.20.11",
591 + "proc-macro2",
592 + "quote",
593 + "syn 2.0.117",
594 +]
595 +
596 +[[package]]
597 +name = "cached_proc_macro_types"
598 +version = "0.1.1"
599 +source = "registry+https://github.com/rust-lang/crates.io-index"
600 +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
601 +
602 +[[package]]
603 +name = "camino"
604 +version = "1.2.2"
605 +source = "registry+https://github.com/rust-lang/crates.io-index"
606 +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48"
607 +dependencies = [
608 + "serde_core",
609 +]
610 +
611 +[[package]]
612 +name = "candle-core"
613 +version = "0.9.2"
614 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
615 +dependencies = [
616 + "byteorder",
617 + "candle-metal-kernels",
618 + "candle-ug",
619 + "float8",
620 + "gemm 0.19.0",
621 + "half",
622 + "libm",
623 + "memmap2",
624 + "num-traits",
625 + "num_cpus",
626 + "objc2-foundation",
627 + "objc2-metal",
628 + "rand 0.9.2",
629 + "rand_distr 0.5.1",
630 + "rayon",
631 + "safetensors 0.7.0",
632 + "thiserror 2.0.18",
633 + "yoke 0.8.1",
634 + "zip",
635 +]
636 +
637 +[[package]]
638 +name = "candle-metal-kernels"
639 +version = "0.9.2"
640 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
641 +dependencies = [
642 + "half",
643 + "objc2",
644 + "objc2-foundation",
645 + "objc2-metal",
646 + "once_cell",
647 + "thiserror 2.0.18",
648 + "tracing",
649 +]
650 +
651 +[[package]]
652 +name = "candle-nn"
653 +version = "0.9.2"
654 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
655 +dependencies = [
656 + "candle-core",
657 + "candle-metal-kernels",
658 + "half",
659 + "libc",
660 + "num-traits",
661 + "objc2-metal",
662 + "rayon",
663 + "safetensors 0.7.0",
664 + "serde",
665 + "thiserror 2.0.18",
666 +]
667 +
668 +[[package]]
669 +name = "candle-ug"
670 +version = "0.9.2"
671 +source = "git+https://github.com/huggingface/candle.git?rev=c3bb5bf#c3bb5bfb90c9cb5e003a803e3d8941067f32d880"
672 +dependencies = [
673 + "ug",
674 + "ug-metal",
675 +]
676 +
677 +[[package]]
678 +name = "cargo-platform"
679 +version = "0.1.9"
680 +source = "registry+https://github.com/rust-lang/crates.io-index"
681 +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
682 +dependencies = [
683 + "serde",
684 +]
685 +
686 +[[package]]
687 +name = "cargo_metadata"
688 +version = "0.19.2"
689 +source = "registry+https://github.com/rust-lang/crates.io-index"
690 +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
691 +dependencies = [
692 + "camino",
693 + "cargo-platform",
694 + "semver",
695 + "serde",
696 + "serde_json",
697 + "thiserror 2.0.18",
698 +]
699 +
700 +[[package]]
701 +name = "castaway"
702 +version = "0.2.4"
703 +source = "registry+https://github.com/rust-lang/crates.io-index"
704 +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
705 +dependencies = [
706 + "rustversion",
707 +]
708 +
709 +[[package]]
710 +name = "cc"
711 +version = "1.2.56"
712 +source = "registry+https://github.com/rust-lang/crates.io-index"
713 +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
714 +dependencies = [
715 + "find-msvc-tools",
716 + "jobserver",
717 + "libc",
718 + "shlex",
719 +]
720 +
721 +[[package]]
722 +name = "cesu8"
723 +version = "1.1.0"
724 +source = "registry+https://github.com/rust-lang/crates.io-index"
725 +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
726 +
727 +[[package]]
728 +name = "cexpr"
729 +version = "0.6.0"
730 +source = "registry+https://github.com/rust-lang/crates.io-index"
731 +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
732 +dependencies = [
733 + "nom 7.1.3",
734 +]
735 +
736 +[[package]]
737 +name = "cfg-if"
738 +version = "1.0.4"
739 +source = "registry+https://github.com/rust-lang/crates.io-index"
740 +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
741 +
742 +[[package]]
743 +name = "cfg_aliases"
744 +version = "0.2.1"
745 +source = "registry+https://github.com/rust-lang/crates.io-index"
746 +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
747 +
748 +[[package]]
749 +name = "cfgrammar"
750 +version = "0.14.1"
751 +source = "registry+https://github.com/rust-lang/crates.io-index"
752 +checksum = "3efdd8f0bddcc9e33f4a664d0f28bc4e51cd5367c16284087a95313104371865"
753 +dependencies = [
754 + "indexmap 2.13.0",
755 + "num-traits",
756 + "proc-macro2",
757 + "quote",
758 + "regex",
759 + "vob",
760 +]
761 +
762 +[[package]]
763 +name = "chrono"
764 +version = "0.4.44"
765 +source = "registry+https://github.com/rust-lang/crates.io-index"
766 +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
767 +dependencies = [
768 + "iana-time-zone",
769 + "js-sys",
770 + "num-traits",
771 + "serde",
772 + "wasm-bindgen",
773 + "windows-link 0.2.1",
774 +]
775 +
776 +[[package]]
777 +name = "clang-sys"
778 +version = "1.8.1"
779 +source = "registry+https://github.com/rust-lang/crates.io-index"
780 +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
781 +dependencies = [
782 + "glob",
783 + "libc",
784 + "libloading",
785 +]
786 +
787 +[[package]]
788 +name = "clap"
789 +version = "2.34.0"
790 +source = "registry+https://github.com/rust-lang/crates.io-index"
791 +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
792 +dependencies = [
793 + "ansi_term",
794 + "atty",
795 + "bitflags 1.3.2",
796 + "strsim 0.8.0",
797 + "textwrap 0.11.0",
798 + "unicode-width 0.1.14",
799 + "vec_map",
800 +]
801 +
802 +[[package]]
803 +name = "clap"
804 +version = "4.5.60"
805 +source = "registry+https://github.com/rust-lang/crates.io-index"
806 +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
807 +dependencies = [
808 + "clap_builder",
809 + "clap_derive",
810 +]
811 +
812 +[[package]]
813 +name = "clap_builder"
814 +version = "4.5.60"
815 +source = "registry+https://github.com/rust-lang/crates.io-index"
816 +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
817 +dependencies = [
818 + "anstream",
819 + "anstyle",
820 + "clap_lex",
821 + "strsim 0.11.1",
822 + "terminal_size",
823 +]
824 +
825 +[[package]]
826 +name = "clap_derive"
827 +version = "4.5.55"
828 +source = "registry+https://github.com/rust-lang/crates.io-index"
829 +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
830 +dependencies = [
831 + "heck 0.5.0",
832 + "proc-macro2",
833 + "quote",
834 + "syn 2.0.117",
835 +]
836 +
837 +[[package]]
838 +name = "clap_lex"
839 +version = "1.0.0"
840 +source = "registry+https://github.com/rust-lang/crates.io-index"
841 +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
842 +
843 +[[package]]
844 +name = "cmake"
845 +version = "0.1.57"
846 +source = "registry+https://github.com/rust-lang/crates.io-index"
847 +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
848 +dependencies = [
849 + "cc",
850 +]
851 +
852 +[[package]]
853 +name = "color_quant"
854 +version = "1.1.0"
855 +source = "registry+https://github.com/rust-lang/crates.io-index"
856 +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
857 +
858 +[[package]]
859 +name = "colorchoice"
860 +version = "1.0.4"
861 +source = "registry+https://github.com/rust-lang/crates.io-index"
862 +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
863 +
864 +[[package]]
865 +name = "combine"
866 +version = "4.6.7"
867 +source = "registry+https://github.com/rust-lang/crates.io-index"
868 +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
869 +dependencies = [
870 + "bytes",
871 + "memchr",
872 +]
873 +
874 +[[package]]
875 +name = "compact_str"
876 +version = "0.9.0"
877 +source = "registry+https://github.com/rust-lang/crates.io-index"
878 +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
879 +dependencies = [
880 + "castaway",
881 + "cfg-if",
882 + "itoa",
883 + "rustversion",
884 + "ryu",
885 + "serde",
886 + "static_assertions",
887 +]
888 +
889 +[[package]]
890 +name = "console"
891 +version = "0.15.11"
892 +source = "registry+https://github.com/rust-lang/crates.io-index"
893 +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
894 +dependencies = [
895 + "encode_unicode",
896 + "libc",
897 + "once_cell",
898 + "unicode-width 0.2.2",
899 + "windows-sys 0.59.0",
900 +]
901 +
902 +[[package]]
903 +name = "console"
904 +version = "0.16.2"
905 +source = "registry+https://github.com/rust-lang/crates.io-index"
906 +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4"
907 +dependencies = [
908 + "encode_unicode",
909 + "libc",
910 + "once_cell",
911 + "unicode-width 0.2.2",
912 + "windows-sys 0.61.2",
913 +]
914 +
915 +[[package]]
916 +name = "convert_case"
917 +version = "0.6.0"
918 +source = "registry+https://github.com/rust-lang/crates.io-index"
919 +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
920 +dependencies = [
921 + "unicode-segmentation",
922 +]
923 +
924 +[[package]]
925 +name = "core-foundation"
926 +version = "0.9.4"
927 +source = "registry+https://github.com/rust-lang/crates.io-index"
928 +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
929 +dependencies = [
930 + "core-foundation-sys",
931 + "libc",
932 +]
933 +
934 +[[package]]
935 +name = "core-foundation"
936 +version = "0.10.1"
937 +source = "registry+https://github.com/rust-lang/crates.io-index"
938 +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
939 +dependencies = [
940 + "core-foundation-sys",
941 + "libc",
942 +]
943 +
944 +[[package]]
945 +name = "core-foundation-sys"
946 +version = "0.8.7"
947 +source = "registry+https://github.com/rust-lang/crates.io-index"
948 +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
949 +
950 +[[package]]
951 +name = "core-graphics-types"
952 +version = "0.1.3"
953 +source = "registry+https://github.com/rust-lang/crates.io-index"
954 +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
955 +dependencies = [
956 + "bitflags 1.3.2",
957 + "core-foundation 0.9.4",
958 + "libc",
959 +]
960 +
961 +[[package]]
962 +name = "core2"
963 +version = "0.4.0"
964 +source = "registry+https://github.com/rust-lang/crates.io-index"
965 +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
966 +dependencies = [
967 + "memchr",
968 +]
969 +
970 +[[package]]
971 +name = "cpufeatures"
972 +version = "0.2.17"
973 +source = "registry+https://github.com/rust-lang/crates.io-index"
974 +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
975 +dependencies = [
976 + "libc",
977 +]
978 +
979 +[[package]]
980 +name = "crc32fast"
981 +version = "1.5.0"
982 +source = "registry+https://github.com/rust-lang/crates.io-index"
983 +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
984 +dependencies = [
985 + "cfg-if",
986 +]
987 +
988 +[[package]]
989 +name = "crossbeam-deque"
990 +version = "0.8.6"
991 +source = "registry+https://github.com/rust-lang/crates.io-index"
992 +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
993 +dependencies = [
994 + "crossbeam-epoch",
995 + "crossbeam-utils",
996 +]
997 +
998 +[[package]]
999 +name = "crossbeam-epoch"
1000 +version = "0.9.18"
1001 +source = "registry+https://github.com/rust-lang/crates.io-index"
1002 +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
1003 +dependencies = [
1004 + "crossbeam-utils",
1005 +]
1006 +
1007 +[[package]]
1008 +name = "crossbeam-utils"
1009 +version = "0.8.21"
1010 +source = "registry+https://github.com/rust-lang/crates.io-index"
1011 +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
1012 +
1013 +[[package]]
1014 +name = "crossterm"
1015 +version = "0.25.0"
1016 +source = "registry+https://github.com/rust-lang/crates.io-index"
1017 +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
1018 +dependencies = [
1019 + "bitflags 1.3.2",
1020 + "crossterm_winapi",
1021 + "libc",
1022 + "mio 0.8.11",
1023 + "parking_lot",
1024 + "signal-hook",
1025 + "signal-hook-mio",
1026 + "winapi",
1027 +]
1028 +
1029 +[[package]]
1030 +name = "crossterm_winapi"
1031 +version = "0.9.1"
1032 +source = "registry+https://github.com/rust-lang/crates.io-index"
1033 +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
1034 +dependencies = [
1035 + "winapi",
1036 +]
1037 +
1038 +[[package]]
1039 +name = "crunchy"
1040 +version = "0.2.4"
1041 +source = "registry+https://github.com/rust-lang/crates.io-index"
1042 +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
1043 +
1044 +[[package]]
1045 +name = "crypto-common"
1046 +version = "0.1.7"
1047 +source = "registry+https://github.com/rust-lang/crates.io-index"
1048 +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
1049 +dependencies = [
1050 + "generic-array",
1051 + "typenum",
1052 +]
1053 +
1054 +[[package]]
1055 +name = "cssparser"
1056 +version = "0.36.0"
1057 +source = "registry+https://github.com/rust-lang/crates.io-index"
1058 +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2"
1059 +dependencies = [
1060 + "cssparser-macros",
1061 + "dtoa-short",
1062 + "itoa",
1063 + "phf",
1064 + "smallvec 1.15.1",
1065 +]
1066 +
1067 +[[package]]
1068 +name = "cssparser-macros"
1069 +version = "0.6.1"
1070 +source = "registry+https://github.com/rust-lang/crates.io-index"
1071 +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
1072 +dependencies = [
1073 + "quote",
1074 + "syn 2.0.117",
1075 +]
1076 +
1077 +[[package]]
1078 +name = "csv"
1079 +version = "1.4.0"
1080 +source = "registry+https://github.com/rust-lang/crates.io-index"
1081 +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
1082 +dependencies = [
1083 + "csv-core",
1084 + "itoa",
1085 + "ryu",
1086 + "serde_core",
1087 +]
1088 +
1089 +[[package]]
1090 +name = "csv-core"
1091 +version = "0.1.13"
1092 +source = "registry+https://github.com/rust-lang/crates.io-index"
1093 +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
1094 +dependencies = [
1095 + "memchr",
1096 +]
1097 +
1098 +[[package]]
1099 +name = "darling"
1100 +version = "0.11.0"
1101 +source = "registry+https://github.com/rust-lang/crates.io-index"
1102 +checksum = "dbffa8f8e38810422f320ca457a93cf1cd0056dc9c06c556b867558e0d471463"
1103 +dependencies = [
1104 + "darling_core 0.11.0",
1105 + "darling_macro 0.11.0",
1106 +]
1107 +
1108 +[[package]]
1109 +name = "darling"
1110 +version = "0.20.11"
1111 +source = "registry+https://github.com/rust-lang/crates.io-index"
1112 +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
1113 +dependencies = [
1114 + "darling_core 0.20.11",
1115 + "darling_macro 0.20.11",
1116 +]
1117 +
1118 +[[package]]
1119 +name = "darling"
1120 +version = "0.21.3"
1121 +source = "registry+https://github.com/rust-lang/crates.io-index"
1122 +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
1123 +dependencies = [
1124 + "darling_core 0.21.3",
1125 + "darling_macro 0.21.3",
1126 +]
1127 +
1128 +[[package]]
1129 +name = "darling"
1130 +version = "0.23.0"
1131 +source = "registry+https://github.com/rust-lang/crates.io-index"
1132 +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
1133 +dependencies = [
1134 + "darling_core 0.23.0",
1135 + "darling_macro 0.23.0",
1136 +]
1137 +
1138 +[[package]]
1139 +name = "darling_core"
1140 +version = "0.11.0"
1141 +source = "registry+https://github.com/rust-lang/crates.io-index"
1142 +checksum = "06e172685d94b7b83800e3256a63261537b9d6129e10f21c8e13ddf9dba8c64d"
1143 +dependencies = [
1144 + "fnv",
1145 + "ident_case",
1146 + "proc-macro2",
1147 + "quote",
1148 + "strsim 0.10.0",
1149 + "syn 1.0.109",
1150 +]
1151 +
1152 +[[package]]
1153 +name = "darling_core"
1154 +version = "0.20.11"
1155 +source = "registry+https://github.com/rust-lang/crates.io-index"
1156 +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
1157 +dependencies = [
1158 + "fnv",
1159 + "ident_case",
1160 + "proc-macro2",
1161 + "quote",
1162 + "strsim 0.11.1",
1163 + "syn 2.0.117",
1164 +]
1165 +
1166 +[[package]]
1167 +name = "darling_core"
1168 +version = "0.21.3"
1169 +source = "registry+https://github.com/rust-lang/crates.io-index"
1170 +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
1171 +dependencies = [
1172 + "fnv",
1173 + "ident_case",
1174 + "proc-macro2",
1175 + "quote",
1176 + "strsim 0.11.1",
1177 + "syn 2.0.117",
1178 +]
1179 +
1180 +[[package]]
1181 +name = "darling_core"
1182 +version = "0.23.0"
1183 +source = "registry+https://github.com/rust-lang/crates.io-index"
1184 +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
1185 +dependencies = [
1186 + "ident_case",
1187 + "proc-macro2",
1188 + "quote",
1189 + "strsim 0.11.1",
1190 + "syn 2.0.117",
1191 +]
1192 +
1193 +[[package]]
1194 +name = "darling_macro"
1195 +version = "0.11.0"
1196 +source = "registry+https://github.com/rust-lang/crates.io-index"
1197 +checksum = "f0618ac802792cebd1918ac6042a6ea1eeab92db34b35656afaa577929820788"
1198 +dependencies = [
1199 + "darling_core 0.11.0",
1200 + "quote",
1201 + "syn 1.0.109",
1202 +]
1203 +
1204 +[[package]]
1205 +name = "darling_macro"
1206 +version = "0.20.11"
1207 +source = "registry+https://github.com/rust-lang/crates.io-index"
1208 +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
1209 +dependencies = [
1210 + "darling_core 0.20.11",
1211 + "quote",
1212 + "syn 2.0.117",
1213 +]
1214 +
1215 +[[package]]
1216 +name = "darling_macro"
1217 +version = "0.21.3"
1218 +source = "registry+https://github.com/rust-lang/crates.io-index"
1219 +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
1220 +dependencies = [
1221 + "darling_core 0.21.3",
1222 + "quote",
1223 + "syn 2.0.117",
1224 +]
1225 +
1226 +[[package]]
1227 +name = "darling_macro"
1228 +version = "0.23.0"
1229 +source = "registry+https://github.com/rust-lang/crates.io-index"
1230 +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
1231 +dependencies = [
1232 + "darling_core 0.23.0",
1233 + "quote",
1234 + "syn 2.0.117",
1235 +]
1236 +
1237 +[[package]]
1238 +name = "dary_heap"
1239 +version = "0.3.8"
1240 +source = "registry+https://github.com/rust-lang/crates.io-index"
1241 +checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04"
1242 +dependencies = [
1243 + "serde",
1244 +]
1245 +
1246 +[[package]]
1247 +name = "data-encoding"
1248 +version = "2.10.0"
1249 +source = "registry+https://github.com/rust-lang/crates.io-index"
1250 +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
1251 +
1252 +[[package]]
1253 +name = "defmac"
1254 +version = "0.1.3"
1255 +source = "registry+https://github.com/rust-lang/crates.io-index"
1256 +checksum = "aafbece59594ed57696a1a69e8bb3ca1683fbc9cdb41d5c02726070b2cd8f19d"
1257 +
1258 +[[package]]
1259 +name = "deranged"
1260 +version = "0.5.8"
1261 +source = "registry+https://github.com/rust-lang/crates.io-index"
1262 +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
1263 +dependencies = [
1264 + "powerfmt",
1265 + "serde_core",
1266 +]
1267 +
1268 +[[package]]
1269 +name = "derive-new"
1270 +version = "0.7.0"
1271 +source = "registry+https://github.com/rust-lang/crates.io-index"
1272 +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc"
1273 +dependencies = [
1274 + "proc-macro2",
1275 + "quote",
1276 + "syn 2.0.117",
1277 +]
1278 +
1279 +[[package]]
1280 +name = "derive_builder"
1281 +version = "0.20.2"
1282 +source = "registry+https://github.com/rust-lang/crates.io-index"
1283 +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
1284 +dependencies = [
1285 + "derive_builder_macro",
1286 +]
1287 +
1288 +[[package]]
1289 +name = "derive_builder_core"
1290 +version = "0.20.2"
1291 +source = "registry+https://github.com/rust-lang/crates.io-index"
1292 +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
1293 +dependencies = [
1294 + "darling 0.20.11",
1295 + "proc-macro2",
1296 + "quote",
1297 + "syn 2.0.117",
1298 +]
1299 +
1300 +[[package]]
1301 +name = "derive_builder_macro"
1302 +version = "0.20.2"
1303 +source = "registry+https://github.com/rust-lang/crates.io-index"
1304 +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
1305 +dependencies = [
1306 + "derive_builder_core",
1307 + "syn 2.0.117",
1308 +]
1309 +
1310 +[[package]]
1311 +name = "derive_more"
1312 +version = "2.1.1"
1313 +source = "registry+https://github.com/rust-lang/crates.io-index"
1314 +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
1315 +dependencies = [
1316 + "derive_more-impl",
1317 +]
1318 +
1319 +[[package]]
1320 +name = "derive_more-impl"
1321 +version = "2.1.1"
1322 +source = "registry+https://github.com/rust-lang/crates.io-index"
1323 +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
1324 +dependencies = [
1325 + "proc-macro2",
1326 + "quote",
1327 + "rustc_version",
1328 + "syn 2.0.117",
1329 +]
1330 +
1331 +[[package]]
1332 +name = "derivre"
1333 +version = "0.3.8"
1334 +source = "registry+https://github.com/rust-lang/crates.io-index"
1335 +checksum = "786c7c65c4ef0c7deb05de3005e01991612a8f09fe0844fc0969c68b90468ba8"
1336 +dependencies = [
1337 + "anyhow",
1338 + "bytemuck",
1339 + "bytemuck_derive",
1340 + "hashbrown 0.15.5",
1341 + "regex-syntax",
1342 + "strum",
1343 +]
1344 +
1345 +[[package]]
1346 +name = "deunicode"
1347 +version = "1.6.2"
1348 +source = "registry+https://github.com/rust-lang/crates.io-index"
1349 +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04"
1350 +
1351 +[[package]]
1352 +name = "digest"
1353 +version = "0.10.7"
1354 +source = "registry+https://github.com/rust-lang/crates.io-index"
1355 +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
1356 +dependencies = [
1357 + "block-buffer",
1358 + "crypto-common",
1359 +]
1360 +
1361 +[[package]]
1362 +name = "dirs"
1363 +version = "6.0.0"
1364 +source = "registry+https://github.com/rust-lang/crates.io-index"
1365 +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
1366 +dependencies = [
1367 + "dirs-sys",
1368 +]
1369 +
1370 +[[package]]
1371 +name = "dirs-sys"
1372 +version = "0.5.0"
1373 +source = "registry+https://github.com/rust-lang/crates.io-index"
1374 +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
1375 +dependencies = [
1376 + "libc",
1377 + "option-ext",
1378 + "redox_users",
1379 + "windows-sys 0.61.2",
1380 +]
1381 +
1382 +[[package]]
1383 +name = "dispatch2"
1384 +version = "0.3.1"
1385 +source = "registry+https://github.com/rust-lang/crates.io-index"
1386 +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
1387 +dependencies = [
1388 + "bitflags 2.11.0",
1389 + "block2",
1390 + "objc2",
1391 +]
1392 +
1393 +[[package]]
1394 +name = "displaydoc"
1395 +version = "0.2.5"
1396 +source = "registry+https://github.com/rust-lang/crates.io-index"
1397 +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
1398 +dependencies = [
1399 + "proc-macro2",
1400 + "quote",
1401 + "syn 2.0.117",
1402 +]
1403 +
1404 +[[package]]
1405 +name = "doctest-file"
1406 +version = "1.0.0"
1407 +source = "registry+https://github.com/rust-lang/crates.io-index"
1408 +checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562"
1409 +
1410 +[[package]]
1411 +name = "dtoa"
1412 +version = "1.0.11"
1413 +source = "registry+https://github.com/rust-lang/crates.io-index"
1414 +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590"
1415 +
1416 +[[package]]
1417 +name = "dtoa-short"
1418 +version = "0.3.5"
1419 +source = "registry+https://github.com/rust-lang/crates.io-index"
1420 +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
1421 +dependencies = [
1422 + "dtoa",
1423 +]
1424 +
1425 +[[package]]
1426 +name = "dunce"
1427 +version = "1.0.5"
1428 +source = "registry+https://github.com/rust-lang/crates.io-index"
1429 +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
1430 +
1431 +[[package]]
1432 +name = "dyn-clone"
1433 +version = "1.0.20"
1434 +source = "registry+https://github.com/rust-lang/crates.io-index"
1435 +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
1436 +
1437 +[[package]]
1438 +name = "dyn-stack"
1439 +version = "0.13.2"
1440 +source = "registry+https://github.com/rust-lang/crates.io-index"
1441 +checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8"
1442 +dependencies = [
1443 + "bytemuck",
1444 + "dyn-stack-macros",
1445 +]
1446 +
1447 +[[package]]
1448 +name = "dyn-stack-macros"
1449 +version = "0.1.3"
1450 +source = "registry+https://github.com/rust-lang/crates.io-index"
1451 +checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9"
1452 +
1453 +[[package]]
1454 +name = "ego-tree"
1455 +version = "0.10.0"
1456 +source = "registry+https://github.com/rust-lang/crates.io-index"
1457 +checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8"
1458 +
1459 +[[package]]
1460 +name = "either"
1461 +version = "1.15.0"
1462 +source = "registry+https://github.com/rust-lang/crates.io-index"
1463 +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
1464 +dependencies = [
1465 + "serde",
1466 +]
1467 +
1468 +[[package]]
1469 +name = "encode_unicode"
1470 +version = "1.0.0"
1471 +source = "registry+https://github.com/rust-lang/crates.io-index"
1472 +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
1473 +
1474 +[[package]]
1475 +name = "encoding_rs"
1476 +version = "0.8.35"
1477 +source = "registry+https://github.com/rust-lang/crates.io-index"
1478 +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
1479 +dependencies = [
1480 + "cfg-if",
1481 +]
1482 +
1483 +[[package]]
1484 +name = "encoding_rs_io"
1485 +version = "0.1.7"
1486 +source = "registry+https://github.com/rust-lang/crates.io-index"
1487 +checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83"
1488 +dependencies = [
1489 + "encoding_rs",
1490 +]
1491 +
1492 +[[package]]
1493 +name = "endian-type"
1494 +version = "0.2.0"
1495 +source = "registry+https://github.com/rust-lang/crates.io-index"
1496 +checksum = "869b0adbda23651a9c5c0c3d270aac9fcb52e8622a8f2b17e57802d7791962f2"
1497 +
1498 +[[package]]
1499 +name = "enum-as-inner"
1500 +version = "0.6.1"
1501 +source = "registry+https://github.com/rust-lang/crates.io-index"
1502 +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
1503 +dependencies = [
1504 + "heck 0.5.0",
1505 + "proc-macro2",
1506 + "quote",
1507 + "syn 2.0.117",
1508 +]
1509 +
1510 +[[package]]
1511 +name = "equator"
1512 +version = "0.4.2"
1513 +source = "registry+https://github.com/rust-lang/crates.io-index"
1514 +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
1515 +dependencies = [
1516 + "equator-macro",
1517 +]
1518 +
1519 +[[package]]
1520 +name = "equator-macro"
1521 +version = "0.4.2"
1522 +source = "registry+https://github.com/rust-lang/crates.io-index"
1523 +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
1524 +dependencies = [
1525 + "proc-macro2",
1526 + "quote",
1527 + "syn 2.0.117",
1528 +]
1529 +
1530 +[[package]]
1531 +name = "equivalent"
1532 +version = "1.0.2"
1533 +source = "registry+https://github.com/rust-lang/crates.io-index"
1534 +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
1535 +
1536 +[[package]]
1537 +name = "errno"
1538 +version = "0.3.14"
1539 +source = "registry+https://github.com/rust-lang/crates.io-index"
1540 +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
1541 +dependencies = [
1542 + "libc",
1543 + "windows-sys 0.61.2",
1544 +]
1545 +
1546 +[[package]]
1547 +name = "esaxx-rs"
1548 +version = "0.1.10"
1549 +source = "registry+https://github.com/rust-lang/crates.io-index"
1550 +checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6"
1551 +
1552 +[[package]]
1553 +name = "exr"
1554 +version = "1.74.0"
1555 +source = "registry+https://github.com/rust-lang/crates.io-index"
1556 +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
1557 +dependencies = [
1558 + "bit_field",
1559 + "half",
1560 + "lebe",
1561 + "miniz_oxide",
1562 + "rayon-core",
1563 + "smallvec 1.15.1",
1564 + "zune-inflate",
1565 +]
1566 +
1567 +[[package]]
1568 +name = "extended"
1569 +version = "0.1.0"
1570 +source = "registry+https://github.com/rust-lang/crates.io-index"
1571 +checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365"
1572 +
1573 +[[package]]
1574 +name = "fancy-regex"
1575 +version = "0.13.0"
1576 +source = "registry+https://github.com/rust-lang/crates.io-index"
1577 +checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2"
1578 +dependencies = [
1579 + "bit-set 0.5.3",
1580 + "regex-automata",
1581 + "regex-syntax",
1582 +]
1583 +
1584 +[[package]]
1585 +name = "fancy-regex"
1586 +version = "0.14.0"
1587 +source = "registry+https://github.com/rust-lang/crates.io-index"
1588 +checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"
1589 +dependencies = [
1590 + "bit-set 0.8.0",
1591 + "regex-automata",
1592 + "regex-syntax",
1593 +]
1594 +
1595 +[[package]]
1596 +name = "fastrand"
1597 +version = "2.3.0"
1598 +source = "registry+https://github.com/rust-lang/crates.io-index"
1599 +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
1600 +
1601 +[[package]]
1602 +name = "fax"
1603 +version = "0.2.6"
1604 +source = "registry+https://github.com/rust-lang/crates.io-index"
1605 +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab"
1606 +dependencies = [
1607 + "fax_derive",
1608 +]
1609 +
1610 +[[package]]
1611 +name = "fax_derive"
1612 +version = "0.2.0"
1613 +source = "registry+https://github.com/rust-lang/crates.io-index"
1614 +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
1615 +dependencies = [
1616 + "proc-macro2",
1617 + "quote",
1618 + "syn 2.0.117",
1619 +]
1620 +
1621 +[[package]]
1622 +name = "fdeflate"
1623 +version = "0.3.7"
1624 +source = "registry+https://github.com/rust-lang/crates.io-index"
1625 +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
1626 +dependencies = [
1627 + "simd-adler32",
1628 +]
1629 +
1630 +[[package]]
1631 +name = "find-msvc-tools"
1632 +version = "0.1.9"
1633 +source = "registry+https://github.com/rust-lang/crates.io-index"
1634 +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
1635 +
1636 +[[package]]
1637 +name = "flate2"
1638 +version = "1.1.9"
1639 +source = "registry+https://github.com/rust-lang/crates.io-index"
1640 +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
1641 +dependencies = [
1642 + "crc32fast",
1643 + "miniz_oxide",
1644 +]
1645 +
1646 +[[package]]
1647 +name = "float8"
1648 +version = "0.7.0"
1649 +source = "registry+https://github.com/rust-lang/crates.io-index"
1650 +checksum = "c2d1f04709a8ac06e8e8042875a3c466cc4832d3c1a18dbcb9dba3c6e83046bc"
1651 +dependencies = [
1652 + "half",
1653 + "num-traits",
1654 + "rand 0.9.2",
1655 + "rand_distr 0.5.1",
1656 +]
1657 +
1658 +[[package]]
1659 +name = "fnv"
1660 +version = "1.0.7"
1661 +source = "registry+https://github.com/rust-lang/crates.io-index"
1662 +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
1663 +
1664 +[[package]]
1665 +name = "foldhash"
1666 +version = "0.1.5"
1667 +source = "registry+https://github.com/rust-lang/crates.io-index"
1668 +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
1669 +
1670 +[[package]]
1671 +name = "foldhash"
1672 +version = "0.2.0"
1673 +source = "registry+https://github.com/rust-lang/crates.io-index"
1674 +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
1675 +
1676 +[[package]]
1677 +name = "foreign-types"
1678 +version = "0.3.2"
1679 +source = "registry+https://github.com/rust-lang/crates.io-index"
1680 +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
1681 +dependencies = [
1682 + "foreign-types-shared 0.1.1",
1683 +]
1684 +
1685 +[[package]]
1686 +name = "foreign-types"
1687 +version = "0.5.0"
1688 +source = "registry+https://github.com/rust-lang/crates.io-index"
1689 +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
1690 +dependencies = [
1691 + "foreign-types-macros",
1692 + "foreign-types-shared 0.3.1",
1693 +]
1694 +
1695 +[[package]]
1696 +name = "foreign-types-macros"
1697 +version = "0.2.3"
1698 +source = "registry+https://github.com/rust-lang/crates.io-index"
1699 +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
1700 +dependencies = [
1701 + "proc-macro2",
1702 + "quote",
1703 + "syn 2.0.117",
1704 +]
1705 +
1706 +[[package]]
1707 +name = "foreign-types-shared"
1708 +version = "0.1.1"
1709 +source = "registry+https://github.com/rust-lang/crates.io-index"
1710 +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
1711 +
1712 +[[package]]
1713 +name = "foreign-types-shared"
1714 +version = "0.3.1"
1715 +source = "registry+https://github.com/rust-lang/crates.io-index"
1716 +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
1717 +
1718 +[[package]]
1719 +name = "form_urlencoded"
1720 +version = "1.2.2"
1721 +source = "registry+https://github.com/rust-lang/crates.io-index"
1722 +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
1723 +dependencies = [
1724 + "percent-encoding",
1725 +]
1726 +
1727 +[[package]]
1728 +name = "fs-err"
1729 +version = "2.11.0"
1730 +source = "registry+https://github.com/rust-lang/crates.io-index"
1731 +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
1732 +dependencies = [
1733 + "autocfg",
1734 +]
1735 +
1736 +[[package]]
1737 +name = "fs_extra"
1738 +version = "1.3.0"
1739 +source = "registry+https://github.com/rust-lang/crates.io-index"
1740 +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
1741 +
1742 +[[package]]
1743 +name = "futf"
1744 +version = "0.1.5"
1745 +source = "registry+https://github.com/rust-lang/crates.io-index"
1746 +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
1747 +dependencies = [
1748 + "mac",
1749 + "new_debug_unreachable",
1750 +]
1751 +
1752 +[[package]]
1753 +name = "futures"
1754 +version = "0.3.32"
1755 +source = "registry+https://github.com/rust-lang/crates.io-index"
1756 +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
1757 +dependencies = [
1758 + "futures-channel",
1759 + "futures-core",
1760 + "futures-executor",
1761 + "futures-io",
1762 + "futures-sink",
1763 + "futures-task",
1764 + "futures-util",
1765 +]
1766 +
1767 +[[package]]
1768 +name = "futures-channel"
1769 +version = "0.3.32"
1770 +source = "registry+https://github.com/rust-lang/crates.io-index"
1771 +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
1772 +dependencies = [
1773 + "futures-core",
1774 + "futures-sink",
1775 +]
1776 +
1777 +[[package]]
1778 +name = "futures-core"
1779 +version = "0.3.32"
1780 +source = "registry+https://github.com/rust-lang/crates.io-index"
1781 +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
1782 +
1783 +[[package]]
1784 +name = "futures-executor"
1785 +version = "0.3.32"
1786 +source = "registry+https://github.com/rust-lang/crates.io-index"
1787 +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
1788 +dependencies = [
1789 + "futures-core",
1790 + "futures-task",
1791 + "futures-util",
1792 +]
1793 +
1794 +[[package]]
1795 +name = "futures-io"
1796 +version = "0.3.32"
1797 +source = "registry+https://github.com/rust-lang/crates.io-index"
1798 +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
1799 +
1800 +[[package]]
1801 +name = "futures-macro"
1802 +version = "0.3.32"
1803 +source = "registry+https://github.com/rust-lang/crates.io-index"
1804 +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
1805 +dependencies = [
1806 + "proc-macro2",
1807 + "quote",
1808 + "syn 2.0.117",
1809 +]
1810 +
1811 +[[package]]
1812 +name = "futures-sink"
1813 +version = "0.3.32"
1814 +source = "registry+https://github.com/rust-lang/crates.io-index"
1815 +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
1816 +
1817 +[[package]]
1818 +name = "futures-task"
1819 +version = "0.3.32"
1820 +source = "registry+https://github.com/rust-lang/crates.io-index"
1821 +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
1822 +
1823 +[[package]]
1824 +name = "futures-util"
1825 +version = "0.3.32"
1826 +source = "registry+https://github.com/rust-lang/crates.io-index"
1827 +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
1828 +dependencies = [
1829 + "futures-channel",
1830 + "futures-core",
1831 + "futures-io",
1832 + "futures-macro",
1833 + "futures-sink",
1834 + "futures-task",
1835 + "memchr",
1836 + "pin-project-lite",
1837 + "slab",
1838 +]
1839 +
1840 +[[package]]
1841 +name = "fxhash"
1842 +version = "0.2.1"
1843 +source = "registry+https://github.com/rust-lang/crates.io-index"
1844 +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
1845 +dependencies = [
1846 + "byteorder",
1847 +]
1848 +
1849 +[[package]]
1850 +name = "galil-seiferas"
1851 +version = "0.1.5"
1852 +source = "registry+https://github.com/rust-lang/crates.io-index"
1853 +checksum = "794ac25cfda3fa11d2b07ff8c65889c6c03411646df54e59e606878d899e1d5a"
1854 +dependencies = [
1855 + "defmac",
1856 + "unchecked-index",
1857 +]
1858 +
1859 +[[package]]
1860 +name = "gemm"
1861 +version = "0.18.2"
1862 +source = "registry+https://github.com/rust-lang/crates.io-index"
1863 +checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451"
1864 +dependencies = [
1865 + "dyn-stack",
1866 + "gemm-c32 0.18.2",
1867 + "gemm-c64 0.18.2",
1868 + "gemm-common 0.18.2",
1869 + "gemm-f16 0.18.2",
1870 + "gemm-f32 0.18.2",
1871 + "gemm-f64 0.18.2",
1872 + "num-complex",
1873 + "num-traits",
1874 + "paste",
1875 + "raw-cpuid",
1876 + "seq-macro",
1877 +]
1878 +
1879 +[[package]]
1880 +name = "gemm"
1881 +version = "0.19.0"
1882 +source = "registry+https://github.com/rust-lang/crates.io-index"
1883 +checksum = "aa0673db364b12263d103b68337a68fbecc541d6f6b61ba72fe438654709eacb"
1884 +dependencies = [
1885 + "dyn-stack",
1886 + "gemm-c32 0.19.0",
1887 + "gemm-c64 0.19.0",
1888 + "gemm-common 0.19.0",
1889 + "gemm-f16 0.19.0",
1890 + "gemm-f32 0.19.0",
1891 + "gemm-f64 0.19.0",
1892 + "num-complex",
1893 + "num-traits",
1894 + "paste",
1895 + "raw-cpuid",
1896 + "seq-macro",
1897 +]
1898 +
1899 +[[package]]
1900 +name = "gemm-c32"
1901 +version = "0.18.2"
1902 +source = "registry+https://github.com/rust-lang/crates.io-index"
1903 +checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847"
1904 +dependencies = [
1905 + "dyn-stack",
1906 + "gemm-common 0.18.2",
1907 + "num-complex",
1908 + "num-traits",
1909 + "paste",
1910 + "raw-cpuid",
1911 + "seq-macro",
1912 +]
1913 +
1914 +[[package]]
1915 +name = "gemm-c32"
1916 +version = "0.19.0"
1917 +source = "registry+https://github.com/rust-lang/crates.io-index"
1918 +checksum = "086936dbdcb99e37aad81d320f98f670e53c1e55a98bee70573e83f95beb128c"
1919 +dependencies = [
1920 + "dyn-stack",
1921 + "gemm-common 0.19.0",
1922 + "num-complex",
1923 + "num-traits",
1924 + "paste",
1925 + "raw-cpuid",
1926 + "seq-macro",
1927 +]
1928 +
1929 +[[package]]
1930 +name = "gemm-c64"
1931 +version = "0.18.2"
1932 +source = "registry+https://github.com/rust-lang/crates.io-index"
1933 +checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf"
1934 +dependencies = [
1935 + "dyn-stack",
1936 + "gemm-common 0.18.2",
1937 + "num-complex",
1938 + "num-traits",
1939 + "paste",
1940 + "raw-cpuid",
1941 + "seq-macro",
1942 +]
1943 +
1944 +[[package]]
1945 +name = "gemm-c64"
1946 +version = "0.19.0"
1947 +source = "registry+https://github.com/rust-lang/crates.io-index"
1948 +checksum = "20c8aeeeec425959bda4d9827664029ba1501a90a0d1e6228e48bef741db3a3f"
1949 +dependencies = [
1950 + "dyn-stack",
1951 + "gemm-common 0.19.0",
1952 + "num-complex",
1953 + "num-traits",
1954 + "paste",
1955 + "raw-cpuid",
1956 + "seq-macro",
1957 +]
1958 +
1959 +[[package]]
1960 +name = "gemm-common"
1961 +version = "0.18.2"
1962 +source = "registry+https://github.com/rust-lang/crates.io-index"
1963 +checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3"
1964 +dependencies = [
1965 + "bytemuck",
1966 + "dyn-stack",
1967 + "half",
1968 + "libm",
1969 + "num-complex",
1970 + "num-traits",
1971 + "once_cell",
1972 + "paste",
1973 + "pulp 0.21.5",
1974 + "raw-cpuid",
1975 + "rayon",
1976 + "seq-macro",
1977 + "sysctl",
1978 +]
1979 +
1980 +[[package]]
1981 +name = "gemm-common"
1982 +version = "0.19.0"
1983 +source = "registry+https://github.com/rust-lang/crates.io-index"
1984 +checksum = "88027625910cc9b1085aaaa1c4bc46bb3a36aad323452b33c25b5e4e7c8e2a3e"
1985 +dependencies = [
1986 + "bytemuck",
1987 + "dyn-stack",
1988 + "half",
1989 + "libm",
1990 + "num-complex",
1991 + "num-traits",
1992 + "once_cell",
1993 + "paste",
1994 + "pulp 0.22.2",
1995 + "raw-cpuid",
1996 + "rayon",
1997 + "seq-macro",
1998 + "sysctl",
1999 +]
2000 +
2001 +[[package]]
2002 +name = "gemm-f16"
2003 +version = "0.18.2"
2004 +source = "registry+https://github.com/rust-lang/crates.io-index"
2005 +checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109"
2006 +dependencies = [
2007 + "dyn-stack",
2008 + "gemm-common 0.18.2",
2009 + "gemm-f32 0.18.2",
2010 + "half",
2011 + "num-complex",
2012 + "num-traits",
2013 + "paste",
2014 + "raw-cpuid",
2015 + "rayon",
2016 + "seq-macro",
2017 +]
2018 +
2019 +[[package]]
2020 +name = "gemm-f16"
2021 +version = "0.19.0"
2022 +source = "registry+https://github.com/rust-lang/crates.io-index"
2023 +checksum = "e3df7a55202e6cd6739d82ae3399c8e0c7e1402859b30e4cb780e61525d9486e"
2024 +dependencies = [
2025 + "dyn-stack",
2026 + "gemm-common 0.19.0",
2027 + "gemm-f32 0.19.0",
2028 + "half",
2029 + "num-complex",
2030 + "num-traits",
2031 + "paste",
2032 + "raw-cpuid",
2033 + "rayon",
2034 + "seq-macro",
2035 +]
2036 +
2037 +[[package]]
2038 +name = "gemm-f32"
2039 +version = "0.18.2"
2040 +source = "registry+https://github.com/rust-lang/crates.io-index"
2041 +checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864"
2042 +dependencies = [
2043 + "dyn-stack",
2044 + "gemm-common 0.18.2",
2045 + "num-complex",
2046 + "num-traits",
2047 + "paste",
2048 + "raw-cpuid",
2049 + "seq-macro",
2050 +]
2051 +
2052 +[[package]]
2053 +name = "gemm-f32"
2054 +version = "0.19.0"
2055 +source = "registry+https://github.com/rust-lang/crates.io-index"
2056 +checksum = "02e0b8c9da1fbec6e3e3ab2ce6bc259ef18eb5f6f0d3e4edf54b75f9fd41a81c"
2057 +dependencies = [
2058 + "dyn-stack",
2059 + "gemm-common 0.19.0",
2060 + "num-complex",
2061 + "num-traits",
2062 + "paste",
2063 + "raw-cpuid",
2064 + "seq-macro",
2065 +]
2066 +
2067 +[[package]]
2068 +name = "gemm-f64"
2069 +version = "0.18.2"
2070 +source = "registry+https://github.com/rust-lang/crates.io-index"
2071 +checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd"
2072 +dependencies = [
2073 + "dyn-stack",
2074 + "gemm-common 0.18.2",
2075 + "num-complex",
2076 + "num-traits",
2077 + "paste",
2078 + "raw-cpuid",
2079 + "seq-macro",
2080 +]
2081 +
2082 +[[package]]
2083 +name = "gemm-f64"
2084 +version = "0.19.0"
2085 +source = "registry+https://github.com/rust-lang/crates.io-index"
2086 +checksum = "056131e8f2a521bfab322f804ccd652520c79700d81209e9d9275bbdecaadc6a"
2087 +dependencies = [
2088 + "dyn-stack",
2089 + "gemm-common 0.19.0",
2090 + "num-complex",
2091 + "num-traits",
2092 + "paste",
2093 + "raw-cpuid",
2094 + "seq-macro",
2095 +]
2096 +
2097 +[[package]]
2098 +name = "generator"
2099 +version = "0.7.5"
2100 +source = "registry+https://github.com/rust-lang/crates.io-index"
2101 +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e"
2102 +dependencies = [
2103 + "cc",
2104 + "libc",
2105 + "log",
2106 + "rustversion",
2107 + "windows 0.48.0",
2108 +]
2109 +
2110 +[[package]]
2111 +name = "generic-array"
2112 +version = "0.14.7"
2113 +source = "registry+https://github.com/rust-lang/crates.io-index"
2114 +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
2115 +dependencies = [
2116 + "typenum",
2117 + "version_check",
2118 +]
2119 +
2120 +[[package]]
2121 +name = "getopts"
2122 +version = "0.2.24"
2123 +source = "registry+https://github.com/rust-lang/crates.io-index"
2124 +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
2125 +dependencies = [
2126 + "unicode-width 0.2.2",
2127 +]
2128 +
2129 +[[package]]
2130 +name = "getrandom"
2131 +version = "0.2.17"
2132 +source = "registry+https://github.com/rust-lang/crates.io-index"
2133 +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
2134 +dependencies = [
2135 + "cfg-if",
2136 + "js-sys",
2137 + "libc",
2138 + "wasi",
2139 + "wasm-bindgen",
2140 +]
2141 +
2142 +[[package]]
2143 +name = "getrandom"
2144 +version = "0.3.4"
2145 +source = "registry+https://github.com/rust-lang/crates.io-index"
2146 +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
2147 +dependencies = [
2148 + "cfg-if",
2149 + "js-sys",
2150 + "libc",
2151 + "r-efi 5.3.0",
2152 + "wasip2",
2153 + "wasm-bindgen",
2154 +]
2155 +
2156 +[[package]]
2157 +name = "getrandom"
2158 +version = "0.4.2"
2159 +source = "registry+https://github.com/rust-lang/crates.io-index"
2160 +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
2161 +dependencies = [
2162 + "cfg-if",
2163 + "libc",
2164 + "r-efi 6.0.0",
2165 + "wasip2",
2166 + "wasip3",
2167 +]
2168 +
2169 +[[package]]
2170 +name = "gif"
2171 +version = "0.14.1"
2172 +source = "registry+https://github.com/rust-lang/crates.io-index"
2173 +checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e"
2174 +dependencies = [
2175 + "color_quant",
2176 + "weezl",
2177 +]
2178 +
2179 +[[package]]
2180 +name = "glob"
2181 +version = "0.3.3"
2182 +source = "registry+https://github.com/rust-lang/crates.io-index"
2183 +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
2184 +
2185 +[[package]]
2186 +name = "goblin"
2187 +version = "0.8.2"
2188 +source = "registry+https://github.com/rust-lang/crates.io-index"
2189 +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"
2190 +dependencies = [
2191 + "log",
2192 + "plain",
2193 + "scroll",
2194 +]
2195 +
2196 +[[package]]
2197 +name = "h2"
2198 +version = "0.4.13"
2199 +source = "registry+https://github.com/rust-lang/crates.io-index"
2200 +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
2201 +dependencies = [
2202 + "atomic-waker",
2203 + "bytes",
2204 + "fnv",
2205 + "futures-core",
2206 + "futures-sink",
2207 + "http",
2208 + "indexmap 2.13.0",
2209 + "slab",
2210 + "tokio",
2211 + "tokio-util",
2212 + "tracing",
2213 +]
2214 +
2215 +[[package]]
2216 +name = "half"
2217 +version = "2.7.1"
2218 +source = "registry+https://github.com/rust-lang/crates.io-index"
2219 +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
2220 +dependencies = [
2221 + "bytemuck",
2222 + "cfg-if",
2223 + "crunchy",
2224 + "num-traits",
2225 + "rand 0.9.2",
2226 + "rand_distr 0.5.1",
2227 + "zerocopy",
2228 +]
2229 +
2230 +[[package]]
2231 +name = "hashbrown"
2232 +version = "0.12.3"
2233 +source = "registry+https://github.com/rust-lang/crates.io-index"
2234 +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
2235 +
2236 +[[package]]
2237 +name = "hashbrown"
2238 +version = "0.15.5"
2239 +source = "registry+https://github.com/rust-lang/crates.io-index"
2240 +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
2241 +dependencies = [
2242 + "allocator-api2",
2243 + "equivalent",
2244 + "foldhash 0.1.5",
2245 +]
2246 +
2247 +[[package]]
2248 +name = "hashbrown"
2249 +version = "0.16.1"
2250 +source = "registry+https://github.com/rust-lang/crates.io-index"
2251 +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
2252 +dependencies = [
2253 + "allocator-api2",
2254 + "equivalent",
2255 + "foldhash 0.2.0",
2256 + "serde",
2257 + "serde_core",
2258 +]
2259 +
2260 +[[package]]
2261 +name = "heck"
2262 +version = "0.3.3"
2263 +source = "registry+https://github.com/rust-lang/crates.io-index"
2264 +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
2265 +dependencies = [
2266 + "unicode-segmentation",
2267 +]
2268 +
2269 +[[package]]
2270 +name = "heck"
2271 +version = "0.5.0"
2272 +source = "registry+https://github.com/rust-lang/crates.io-index"
2273 +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
2274 +
2275 +[[package]]
2276 +name = "hermit-abi"
2277 +version = "0.1.19"
2278 +source = "registry+https://github.com/rust-lang/crates.io-index"
2279 +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
2280 +dependencies = [
2281 + "libc",
2282 +]
2283 +
2284 +[[package]]
2285 +name = "hermit-abi"
2286 +version = "0.5.2"
2287 +source = "registry+https://github.com/rust-lang/crates.io-index"
2288 +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
2289 +
2290 +[[package]]
2291 +name = "hex"
2292 +version = "0.4.3"
2293 +source = "registry+https://github.com/rust-lang/crates.io-index"
2294 +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
2295 +
2296 +[[package]]
2297 +name = "hf-hub"
2298 +version = "0.4.3"
2299 +source = "registry+https://github.com/rust-lang/crates.io-index"
2300 +checksum = "629d8f3bbeda9d148036d6b0de0a3ab947abd08ce90626327fc3547a49d59d97"
2301 +dependencies = [
2302 + "dirs",
2303 + "futures",
2304 + "http",
2305 + "indicatif 0.17.11",
2306 + "libc",
2307 + "log",
2308 + "native-tls",
2309 + "num_cpus",
2310 + "rand 0.9.2",
2311 + "reqwest 0.12.28",
2312 + "serde",
2313 + "serde_json",
2314 + "thiserror 2.0.18",
2315 + "tokio",
2316 + "ureq",
2317 + "windows-sys 0.60.2",
2318 +]
2319 +
2320 +[[package]]
2321 +name = "home"
2322 +version = "0.5.12"
2323 +source = "registry+https://github.com/rust-lang/crates.io-index"
2324 +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
2325 +dependencies = [
2326 + "windows-sys 0.61.2",
2327 +]
2328 +
2329 +[[package]]
2330 +name = "hound"
2331 +version = "3.5.1"
2332 +source = "registry+https://github.com/rust-lang/crates.io-index"
2333 +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f"
2334 +
2335 +[[package]]
2336 +name = "html2text"
2337 +version = "0.16.7"
2338 +source = "registry+https://github.com/rust-lang/crates.io-index"
2339 +checksum = "12d23156ea4dbe6b37ad48fab2da56ff27b0f6192fb5db210c44eb07bfe6e787"
2340 +dependencies = [
2341 + "html5ever 0.38.0",
2342 + "tendril 0.5.0",
2343 + "thiserror 2.0.18",
2344 + "unicode-width 0.2.2",
2345 +]
2346 +
2347 +[[package]]
2348 +name = "html5ever"
2349 +version = "0.36.1"
2350 +source = "registry+https://github.com/rust-lang/crates.io-index"
2351 +checksum = "6452c4751a24e1b99c3260d505eaeee76a050573e61f30ac2c924ddc7236f01e"
2352 +dependencies = [
2353 + "log",
2354 + "markup5ever 0.36.1",
2355 +]
2356 +
2357 +[[package]]
2358 +name = "html5ever"
2359 +version = "0.38.0"
2360 +source = "registry+https://github.com/rust-lang/crates.io-index"
2361 +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2"
2362 +dependencies = [
2363 + "log",
2364 + "markup5ever 0.38.0",
2365 +]
2366 +
2367 +[[package]]
2368 +name = "http"
2369 +version = "1.4.0"
2370 +source = "registry+https://github.com/rust-lang/crates.io-index"
2371 +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
2372 +dependencies = [
2373 + "bytes",
2374 + "itoa",
2375 +]
2376 +
2377 +[[package]]
2378 +name = "http-body"
2379 +version = "1.0.1"
2380 +source = "registry+https://github.com/rust-lang/crates.io-index"
2381 +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
2382 +dependencies = [
2383 + "bytes",
2384 + "http",
2385 +]
2386 +
2387 +[[package]]
2388 +name = "http-body-util"
2389 +version = "0.1.3"
2390 +source = "registry+https://github.com/rust-lang/crates.io-index"
2391 +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
2392 +dependencies = [
2393 + "bytes",
2394 + "futures-core",
2395 + "http",
2396 + "http-body",
2397 + "pin-project-lite",
2398 +]
2399 +
2400 +[[package]]
2401 +name = "httparse"
2402 +version = "1.10.1"
2403 +source = "registry+https://github.com/rust-lang/crates.io-index"
2404 +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
2405 +
2406 +[[package]]
2407 +name = "hyper"
2408 +version = "1.8.1"
2409 +source = "registry+https://github.com/rust-lang/crates.io-index"
2410 +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
2411 +dependencies = [
2412 + "atomic-waker",
2413 + "bytes",
2414 + "futures-channel",
2415 + "futures-core",
2416 + "h2",
2417 + "http",
2418 + "http-body",
2419 + "httparse",
2420 + "itoa",
2421 + "pin-project-lite",
2422 + "pin-utils",
2423 + "smallvec 1.15.1",
2424 + "tokio",
2425 + "want",
2426 +]
2427 +
2428 +[[package]]
2429 +name = "hyper-rustls"
2430 +version = "0.27.7"
2431 +source = "registry+https://github.com/rust-lang/crates.io-index"
2432 +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
2433 +dependencies = [
2434 + "http",
2435 + "hyper",
2436 + "hyper-util",
2437 + "rustls",
2438 + "rustls-pki-types",
2439 + "tokio",
2440 + "tokio-rustls",
2441 + "tower-service",
2442 + "webpki-roots 1.0.6",
2443 +]
2444 +
2445 +[[package]]
2446 +name = "hyper-tls"
2447 +version = "0.6.0"
2448 +source = "registry+https://github.com/rust-lang/crates.io-index"
2449 +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
2450 +dependencies = [
2451 + "bytes",
2452 + "http-body-util",
2453 + "hyper",
2454 + "hyper-util",
2455 + "native-tls",
2456 + "tokio",
2457 + "tokio-native-tls",
2458 + "tower-service",
2459 +]
2460 +
2461 +[[package]]
2462 +name = "hyper-util"
2463 +version = "0.1.20"
2464 +source = "registry+https://github.com/rust-lang/crates.io-index"
2465 +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
2466 +dependencies = [
2467 + "base64 0.22.1",
2468 + "bytes",
2469 + "futures-channel",
2470 + "futures-util",
2471 + "http",
2472 + "http-body",
2473 + "hyper",
2474 + "ipnet",
2475 + "libc",
2476 + "percent-encoding",
2477 + "pin-project-lite",
2478 + "socket2",
2479 + "system-configuration",
2480 + "tokio",
2481 + "tower-service",
2482 + "tracing",
2483 + "windows-registry",
2484 +]
2485 +
2486 +[[package]]
2487 +name = "iana-time-zone"
2488 +version = "0.1.65"
2489 +source = "registry+https://github.com/rust-lang/crates.io-index"
2490 +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
2491 +dependencies = [
2492 + "android_system_properties",
2493 + "core-foundation-sys",
2494 + "iana-time-zone-haiku",
2495 + "js-sys",
2496 + "log",
2497 + "wasm-bindgen",
2498 + "windows-core 0.62.2",
2499 +]
2500 +
2501 +[[package]]
2502 +name = "iana-time-zone-haiku"
2503 +version = "0.1.2"
2504 +source = "registry+https://github.com/rust-lang/crates.io-index"
2505 +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
2506 +dependencies = [
2507 + "cc",
2508 +]
2509 +
2510 +[[package]]
2511 +name = "icu_collections"
2512 +version = "2.1.1"
2513 +source = "registry+https://github.com/rust-lang/crates.io-index"
2514 +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
2515 +dependencies = [
2516 + "displaydoc",
2517 + "potential_utf",
2518 + "yoke 0.8.1",
2519 + "zerofrom",
2520 + "zerovec",
2521 +]
2522 +
2523 +[[package]]
2524 +name = "icu_locale_core"
2525 +version = "2.1.1"
2526 +source = "registry+https://github.com/rust-lang/crates.io-index"
2527 +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
2528 +dependencies = [
2529 + "displaydoc",
2530 + "litemap",
2531 + "tinystr",
2532 + "writeable",
2533 + "zerovec",
2534 +]
2535 +
2536 +[[package]]
2537 +name = "icu_normalizer"
2538 +version = "2.1.1"
2539 +source = "registry+https://github.com/rust-lang/crates.io-index"
2540 +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
2541 +dependencies = [
2542 + "icu_collections",
2543 + "icu_normalizer_data",
2544 + "icu_properties",
2545 + "icu_provider",
2546 + "smallvec 1.15.1",
2547 + "zerovec",
2548 +]
2549 +
2550 +[[package]]
2551 +name = "icu_normalizer_data"
2552 +version = "2.1.1"
2553 +source = "registry+https://github.com/rust-lang/crates.io-index"
2554 +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
2555 +
2556 +[[package]]
2557 +name = "icu_properties"
2558 +version = "2.1.2"
2559 +source = "registry+https://github.com/rust-lang/crates.io-index"
2560 +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
2561 +dependencies = [
2562 + "icu_collections",
2563 + "icu_locale_core",
2564 + "icu_properties_data",
2565 + "icu_provider",
2566 + "zerotrie",
2567 + "zerovec",
2568 +]
2569 +
2570 +[[package]]
2571 +name = "icu_properties_data"
2572 +version = "2.1.2"
2573 +source = "registry+https://github.com/rust-lang/crates.io-index"
2574 +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
2575 +
2576 +[[package]]
2577 +name = "icu_provider"
2578 +version = "2.1.1"
2579 +source = "registry+https://github.com/rust-lang/crates.io-index"
2580 +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
2581 +dependencies = [
2582 + "displaydoc",
2583 + "icu_locale_core",
2584 + "writeable",
2585 + "yoke 0.8.1",
2586 + "zerofrom",
2587 + "zerotrie",
2588 + "zerovec",
2589 +]
2590 +
2591 +[[package]]
2592 +name = "id-arena"
2593 +version = "2.3.0"
2594 +source = "registry+https://github.com/rust-lang/crates.io-index"
2595 +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
2596 +
2597 +[[package]]
2598 +name = "ident_case"
2599 +version = "1.0.1"
2600 +source = "registry+https://github.com/rust-lang/crates.io-index"
2601 +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
2602 +
2603 +[[package]]
2604 +name = "idna"
2605 +version = "1.1.0"
2606 +source = "registry+https://github.com/rust-lang/crates.io-index"
2607 +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
2608 +dependencies = [
2609 + "idna_adapter",
2610 + "smallvec 1.15.1",
2611 + "utf8_iter",
2612 +]
2613 +
2614 +[[package]]
2615 +name = "idna_adapter"
2616 +version = "1.2.1"
2617 +source = "registry+https://github.com/rust-lang/crates.io-index"
2618 +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
2619 +dependencies = [
2620 + "icu_normalizer",
2621 + "icu_properties",
2622 +]
2623 +
2624 +[[package]]
2625 +name = "image"
2626 +version = "0.25.9"
2627 +source = "registry+https://github.com/rust-lang/crates.io-index"
2628 +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a"
2629 +dependencies = [
2630 + "bytemuck",
2631 + "byteorder-lite",
2632 + "color_quant",
2633 + "exr",
2634 + "gif",
2635 + "image-webp",
2636 + "moxcms",
2637 + "num-traits",
2638 + "png",
2639 + "qoi",
2640 + "ravif",
2641 + "rayon",
2642 + "rgb",
2643 + "tiff",
2644 + "zune-core 0.5.1",
2645 + "zune-jpeg 0.5.12",
2646 +]
2647 +
2648 +[[package]]
2649 +name = "image-webp"
2650 +version = "0.2.4"
2651 +source = "registry+https://github.com/rust-lang/crates.io-index"
2652 +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
2653 +dependencies = [
2654 + "byteorder-lite",
2655 + "quick-error",
2656 +]
2657 +
2658 +[[package]]
2659 +name = "imgref"
2660 +version = "1.12.0"
2661 +source = "registry+https://github.com/rust-lang/crates.io-index"
2662 +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8"
2663 +
2664 +[[package]]
2665 +name = "indexmap"
2666 +version = "1.9.3"
2667 +source = "registry+https://github.com/rust-lang/crates.io-index"
2668 +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
2669 +dependencies = [
2670 + "autocfg",
2671 + "hashbrown 0.12.3",
2672 + "serde",
2673 +]
2674 +
2675 +[[package]]
2676 +name = "indexmap"
2677 +version = "2.13.0"
2678 +source = "registry+https://github.com/rust-lang/crates.io-index"
2679 +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
2680 +dependencies = [
2681 + "equivalent",
2682 + "hashbrown 0.16.1",
2683 + "serde",
2684 + "serde_core",
2685 +]
2686 +
2687 +[[package]]
2688 +name = "indicatif"
2689 +version = "0.17.11"
2690 +source = "registry+https://github.com/rust-lang/crates.io-index"
2691 +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
2692 +dependencies = [
2693 + "console 0.15.11",
2694 + "number_prefix",
2695 + "portable-atomic",
2696 + "unicode-width 0.2.2",
2697 + "web-time",
2698 +]
2699 +
2700 +[[package]]
2701 +name = "indicatif"
2702 +version = "0.18.4"
2703 +source = "registry+https://github.com/rust-lang/crates.io-index"
2704 +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb"
2705 +dependencies = [
2706 + "console 0.16.2",
2707 + "portable-atomic",
2708 + "rayon",
2709 + "unicode-width 0.2.2",
2710 + "unit-prefix",
2711 + "web-time",
2712 +]
2713 +
2714 +[[package]]
2715 +name = "interpolate_name"
2716 +version = "0.2.4"
2717 +source = "registry+https://github.com/rust-lang/crates.io-index"
2718 +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
2719 +dependencies = [
2720 + "proc-macro2",
2721 + "quote",
2722 + "syn 2.0.117",
2723 +]
2724 +
2725 +[[package]]
2726 +name = "interprocess"
2727 +version = "2.4.0"
2728 +source = "registry+https://github.com/rust-lang/crates.io-index"
2729 +checksum = "6be5e5c847dbdb44564bd85294740d031f4f8aeb3464e5375ef7141f7538db69"
2730 +dependencies = [
2731 + "doctest-file",
2732 + "libc",
2733 + "recvmsg",
2734 + "widestring",
2735 + "windows-sys 0.52.0",
2736 +]
2737 +
2738 +[[package]]
2739 +name = "ipnet"
2740 +version = "2.12.0"
2741 +source = "registry+https://github.com/rust-lang/crates.io-index"
2742 +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
2743 +
2744 +[[package]]
2745 +name = "iri-string"
2746 +version = "0.7.10"
2747 +source = "registry+https://github.com/rust-lang/crates.io-index"
2748 +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
2749 +dependencies = [
2750 + "memchr",
2751 + "serde",
2752 +]
2753 +
2754 +[[package]]
2755 +name = "is_terminal_polyfill"
2756 +version = "1.70.2"
2757 +source = "registry+https://github.com/rust-lang/crates.io-index"
2758 +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
2759 +
2760 +[[package]]
2761 +name = "itertools"
2762 +version = "0.12.1"
2763 +source = "registry+https://github.com/rust-lang/crates.io-index"
2764 +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
2765 +dependencies = [
2766 + "either",
2767 +]
2768 +
2769 +[[package]]
2770 +name = "itertools"
2771 +version = "0.14.0"
2772 +source = "registry+https://github.com/rust-lang/crates.io-index"
2773 +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
2774 +dependencies = [
2775 + "either",
2776 +]
2777 +
2778 +[[package]]
2779 +name = "itoa"
2780 +version = "1.0.17"
2781 +source = "registry+https://github.com/rust-lang/crates.io-index"
2782 +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
2783 +
2784 +[[package]]
2785 +name = "jni"
2786 +version = "0.21.1"
2787 +source = "registry+https://github.com/rust-lang/crates.io-index"
2788 +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
2789 +dependencies = [
2790 + "cesu8",
2791 + "cfg-if",
2792 + "combine",
2793 + "jni-sys",
2794 + "log",
2795 + "thiserror 1.0.69",
2796 + "walkdir",
2797 + "windows-sys 0.45.0",
2798 +]
2799 +
2800 +[[package]]
2801 +name = "jni-sys"
2802 +version = "0.3.0"
2803 +source = "registry+https://github.com/rust-lang/crates.io-index"
2804 +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
2805 +
2806 +[[package]]
2807 +name = "jobserver"
2808 +version = "0.1.34"
2809 +source = "registry+https://github.com/rust-lang/crates.io-index"
2810 +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
2811 +dependencies = [
2812 + "getrandom 0.3.4",
2813 + "libc",
2814 +]
2815 +
2816 +[[package]]
2817 +name = "js-sys"
2818 +version = "0.3.91"
2819 +source = "registry+https://github.com/rust-lang/crates.io-index"
2820 +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
2821 +dependencies = [
2822 + "once_cell",
2823 + "wasm-bindgen",
2824 +]
2825 +
2826 +[[package]]
2827 +name = "lazy_static"
2828 +version = "1.5.0"
2829 +source = "registry+https://github.com/rust-lang/crates.io-index"
2830 +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
2831 +
2832 +[[package]]
2833 +name = "lazycell"
2834 +version = "1.3.0"
2835 +source = "registry+https://github.com/rust-lang/crates.io-index"
2836 +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
2837 +
2838 +[[package]]
2839 +name = "leb128fmt"
2840 +version = "0.1.0"
2841 +source = "registry+https://github.com/rust-lang/crates.io-index"
2842 +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
2843 +
2844 +[[package]]
2845 +name = "lebe"
2846 +version = "0.5.3"
2847 +source = "registry+https://github.com/rust-lang/crates.io-index"
2848 +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
2849 +
2850 +[[package]]
2851 +name = "libc"
2852 +version = "0.2.182"
2853 +source = "registry+https://github.com/rust-lang/crates.io-index"
2854 +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
2855 +
2856 +[[package]]
2857 +name = "libfuzzer-sys"
2858 +version = "0.4.12"
2859 +source = "registry+https://github.com/rust-lang/crates.io-index"
2860 +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
2861 +dependencies = [
2862 + "arbitrary",
2863 + "cc",
2864 +]
2865 +
2866 +[[package]]
2867 +name = "libloading"
2868 +version = "0.8.9"
2869 +source = "registry+https://github.com/rust-lang/crates.io-index"
2870 +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
2871 +dependencies = [
2872 + "cfg-if",
2873 + "windows-link 0.2.1",
2874 +]
2875 +
2876 +[[package]]
2877 +name = "libm"
2878 +version = "0.2.16"
2879 +source = "registry+https://github.com/rust-lang/crates.io-index"
2880 +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
2881 +
2882 +[[package]]
2883 +name = "libredox"
2884 +version = "0.1.14"
2885 +source = "registry+https://github.com/rust-lang/crates.io-index"
2886 +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
2887 +dependencies = [
2888 + "libc",
2889 +]
2890 +
2891 +[[package]]
2892 +name = "linux-raw-sys"
2893 +version = "0.12.1"
2894 +source = "registry+https://github.com/rust-lang/crates.io-index"
2895 +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
2896 +
2897 +[[package]]
2898 +name = "litemap"
2899 +version = "0.8.1"
2900 +source = "registry+https://github.com/rust-lang/crates.io-index"
2901 +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
2902 +
2903 +[[package]]
2904 +name = "llguidance"
2905 +version = "1.6.1"
2906 +source = "registry+https://github.com/rust-lang/crates.io-index"
2907 +checksum = "fd6bd9b883ab54097b0651668e5b590be1c7ca906500db40d4de74522382e011"
2908 +dependencies = [
2909 + "anyhow",
2910 + "derivre",
2911 + "indexmap 2.13.0",
2912 + "regex-syntax",
2913 + "serde",
2914 + "serde_json",
2915 + "toktrie",
2916 +]
2917 +
2918 +[[package]]
2919 +name = "lock_api"
2920 +version = "0.4.14"
2921 +source = "registry+https://github.com/rust-lang/crates.io-index"
2922 +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
2923 +dependencies = [
2924 + "scopeguard",
2925 +]
2926 +
2927 +[[package]]
2928 +name = "log"
2929 +version = "0.4.29"
2930 +source = "registry+https://github.com/rust-lang/crates.io-index"
2931 +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
2932 +
2933 +[[package]]
2934 +name = "loom"
2935 +version = "0.5.6"
2936 +source = "registry+https://github.com/rust-lang/crates.io-index"
2937 +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
2938 +dependencies = [
2939 + "cfg-if",
2940 + "generator",
2941 + "scoped-tls",
2942 + "serde",
2943 + "serde_json",
2944 + "tracing",
2945 + "tracing-subscriber",
2946 +]
2947 +
2948 +[[package]]
2949 +name = "loop9"
2950 +version = "0.1.5"
2951 +source = "registry+https://github.com/rust-lang/crates.io-index"
2952 +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
2953 +dependencies = [
2954 + "imgref",
2955 +]
2956 +
2957 +[[package]]
2958 +name = "lrtable"
2959 +version = "0.14.1"
2960 +source = "registry+https://github.com/rust-lang/crates.io-index"
2961 +checksum = "b15ad6a43e5cff4ac046d51281d2256a36d1440065eab53ccce9362b48db5b42"
2962 +dependencies = [
2963 + "cfgrammar",
2964 + "fnv",
2965 + "num-traits",
2966 + "sparsevec",
2967 + "vob",
2968 +]
2969 +
2970 +[[package]]
2971 +name = "lru-slab"
2972 +version = "0.1.2"
2973 +source = "registry+https://github.com/rust-lang/crates.io-index"
2974 +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
2975 +
2976 +[[package]]
2977 +name = "mac"
2978 +version = "0.1.1"
2979 +source = "registry+https://github.com/rust-lang/crates.io-index"
2980 +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
2981 +
2982 +[[package]]
2983 +name = "macro_rules_attribute"
2984 +version = "0.2.2"
2985 +source = "registry+https://github.com/rust-lang/crates.io-index"
2986 +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520"
2987 +dependencies = [
2988 + "macro_rules_attribute-proc_macro",
2989 + "paste",
2990 +]
2991 +
2992 +[[package]]
2993 +name = "macro_rules_attribute-proc_macro"
2994 +version = "0.2.2"
2995 +source = "registry+https://github.com/rust-lang/crates.io-index"
2996 +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
2997 +
2998 +[[package]]
2999 +name = "magnus"
3000 +version = "0.7.1"
3001 +source = "registry+https://github.com/rust-lang/crates.io-index"
3002 +checksum = "3d87ae53030f3a22e83879e666cb94e58a7bdf31706878a0ba48752994146dab"
3003 +dependencies = [
3004 + "magnus-macros",
3005 + "rb-sys",
3006 + "rb-sys-env",
3007 + "seq-macro",
3008 +]
3009 +
3010 +[[package]]
3011 +name = "magnus-macros"
3012 +version = "0.6.0"
3013 +source = "registry+https://github.com/rust-lang/crates.io-index"
3014 +checksum = "5968c820e2960565f647819f5928a42d6e874551cab9d88d75e3e0660d7f71e3"
3015 +dependencies = [
3016 + "proc-macro2",
3017 + "quote",
3018 + "syn 2.0.117",
3019 +]
3020 +
3021 +[[package]]
3022 +name = "malloc_buf"
3023 +version = "0.0.6"
3024 +source = "registry+https://github.com/rust-lang/crates.io-index"
3025 +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
3026 +dependencies = [
3027 + "libc",
3028 +]
3029 +
3030 +[[package]]
3031 +name = "markup5ever"
3032 +version = "0.36.1"
3033 +source = "registry+https://github.com/rust-lang/crates.io-index"
3034 +checksum = "6c3294c4d74d0742910f8c7b466f44dda9eb2d5742c1e430138df290a1e8451c"
3035 +dependencies = [
3036 + "log",
3037 + "tendril 0.4.3",
3038 + "web_atoms",
3039 +]
3040 +
3041 +[[package]]
3042 +name = "markup5ever"
3043 +version = "0.38.0"
3044 +source = "registry+https://github.com/rust-lang/crates.io-index"
3045 +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862"
3046 +dependencies = [
3047 + "log",
3048 + "tendril 0.5.0",
3049 + "web_atoms",
3050 +]
3051 +
3052 +[[package]]
3053 +name = "matchers"
3054 +version = "0.2.0"
3055 +source = "registry+https://github.com/rust-lang/crates.io-index"
3056 +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
3057 +dependencies = [
3058 + "regex-automata",
3059 +]
3060 +
3061 +[[package]]
3062 +name = "matrixmultiply"
3063 +version = "0.3.10"
3064 +source = "registry+https://github.com/rust-lang/crates.io-index"
3065 +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08"
3066 +dependencies = [
3067 + "autocfg",
3068 + "rawpointer",
3069 +]
3070 +
3071 +[[package]]
3072 +name = "maybe-rayon"
3073 +version = "0.1.1"
3074 +source = "registry+https://github.com/rust-lang/crates.io-index"
3075 +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
3076 +dependencies = [
3077 + "cfg-if",
3078 + "rayon",
3079 +]
3080 +
3081 +[[package]]
3082 +name = "memchr"
3083 +version = "2.8.0"
3084 +source = "registry+https://github.com/rust-lang/crates.io-index"
3085 +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
3086 +
3087 +[[package]]
3088 +name = "memmap2"
3089 +version = "0.9.10"
3090 +source = "registry+https://github.com/rust-lang/crates.io-index"
3091 +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
3092 +dependencies = [
3093 + "libc",
3094 + "stable_deref_trait",
3095 +]
3096 +
3097 +[[package]]
3098 +name = "metal"
3099 +version = "0.29.0"
3100 +source = "registry+https://github.com/rust-lang/crates.io-index"
3101 +checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
3102 +dependencies = [
3103 + "bitflags 2.11.0",
3104 + "block",
3105 + "core-graphics-types",
3106 + "foreign-types 0.5.0",
3107 + "log",
3108 + "objc",
3109 + "paste",
3110 +]
3111 +
3112 +[[package]]
3113 +name = "mime"
3114 +version = "0.3.17"
3115 +source = "registry+https://github.com/rust-lang/crates.io-index"
3116 +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
3117 +
3118 +[[package]]
3119 +name = "mime_guess"
3120 +version = "2.0.5"
3121 +source = "registry+https://github.com/rust-lang/crates.io-index"
3122 +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
3123 +dependencies = [
3124 + "mime",
3125 + "unicase",
3126 +]
3127 +
3128 +[[package]]
3129 +name = "minijinja"
3130 +version = "2.16.0"
3131 +source = "registry+https://github.com/rust-lang/crates.io-index"
3132 +checksum = "5c54f3bcc034dd74496b5ca929fd0b710186672d5ff0b0f255a9ceb259042ece"
3133 +dependencies = [
3134 + "serde",
3135 + "serde_json",
3136 +]
3137 +
3138 +[[package]]
3139 +name = "minijinja-contrib"
3140 +version = "2.16.0"
3141 +source = "registry+https://github.com/rust-lang/crates.io-index"
3142 +checksum = "86201a560fde90bf270d3c9d5da0c2a5a0c25bd3242d674fcf03e6a35fcfa7ba"
3143 +dependencies = [
3144 + "minijinja",
3145 + "serde",
3146 +]
3147 +
3148 +[[package]]
3149 +name = "minimal-lexical"
3150 +version = "0.2.1"
3151 +source = "registry+https://github.com/rust-lang/crates.io-index"
3152 +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
3153 +
3154 +[[package]]
3155 +name = "miniz_oxide"
3156 +version = "0.8.9"
3157 +source = "registry+https://github.com/rust-lang/crates.io-index"
3158 +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
3159 +dependencies = [
3160 + "adler2",
3161 + "simd-adler32",
3162 +]
3163 +
3164 +[[package]]
3165 +name = "mio"
3166 +version = "0.8.11"
3167 +source = "registry+https://github.com/rust-lang/crates.io-index"
3168 +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
3169 +dependencies = [
3170 + "libc",
3171 + "log",
3172 + "wasi",
3173 + "windows-sys 0.48.0",
3174 +]
3175 +
3176 +[[package]]
3177 +name = "mio"
3178 +version = "1.1.1"
3179 +source = "registry+https://github.com/rust-lang/crates.io-index"
3180 +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
3181 +dependencies = [
3182 + "libc",
3183 + "wasi",
3184 + "windows-sys 0.61.2",
3185 +]
3186 +
3187 +[[package]]
3188 +name = "mistralrs"
3189 +version = "0.7.1-alpha.1"
3190 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3191 +dependencies = [
3192 + "anyhow",
3193 + "candle-core",
3194 + "candle-nn",
3195 + "clap 4.5.60",
3196 + "either",
3197 + "futures",
3198 + "image",
3199 + "indexmap 2.13.0",
3200 + "mistralrs-core",
3201 + "mistralrs-macros",
3202 + "rand 0.9.2",
3203 + "reqwest 0.13.2",
3204 + "schemars 1.2.1",
3205 + "serde",
3206 + "serde_json",
3207 + "thiserror 2.0.18",
3208 + "tokio",
3209 + "tracing",
3210 + "tracing-subscriber",
3211 + "walkdir",
3212 +]
3213 +
3214 +[[package]]
3215 +name = "mistralrs-audio"
3216 +version = "0.7.1-alpha.1"
3217 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3218 +dependencies = [
3219 + "anyhow",
3220 + "apodize",
3221 + "hound",
3222 + "symphonia",
3223 +]
3224 +
3225 +[[package]]
3226 +name = "mistralrs-core"
3227 +version = "0.7.1-alpha.1"
3228 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3229 +dependencies = [
3230 + "ahash",
3231 + "akin",
3232 + "anyhow",
3233 + "apodize",
3234 + "as-any",
3235 + "async-trait",
3236 + "base64 0.22.1",
3237 + "bm25",
3238 + "bytemuck",
3239 + "bytemuck_derive",
3240 + "candle-core",
3241 + "candle-metal-kernels",
3242 + "candle-nn",
3243 + "cfgrammar",
3244 + "chrono",
3245 + "clap 4.5.60",
3246 + "csv",
3247 + "derive-new",
3248 + "derive_more",
3249 + "dirs",
3250 + "either",
3251 + "float8",
3252 + "futures",
3253 + "galil-seiferas",
3254 + "half",
3255 + "hashbrown 0.16.1",
3256 + "hf-hub",
3257 + "hound",
3258 + "html2text",
3259 + "http",
3260 + "image",
3261 + "indexmap 2.13.0",
3262 + "indicatif 0.18.4",
3263 + "interprocess",
3264 + "itertools 0.14.0",
3265 + "libc",
3266 + "llguidance",
3267 + "lrtable",
3268 + "minijinja",
3269 + "minijinja-contrib",
3270 + "mistralrs-audio",
3271 + "mistralrs-mcp",
3272 + "mistralrs-paged-attn",
3273 + "mistralrs-quant",
3274 + "mistralrs-vision",
3275 + "num-traits",
3276 + "objc",
3277 + "objc2-metal",
3278 + "openai-harmony",
3279 + "ordered-float",
3280 + "parking_lot",
3281 + "radix_trie",
3282 + "rand 0.9.2",
3283 + "rand_distr 0.5.1",
3284 + "rand_isaac",
3285 + "rayon",
3286 + "regex",
3287 + "regex-automata",
3288 + "reqwest 0.13.2",
3289 + "rubato",
3290 + "rust-mcp-schema",
3291 + "rustc-hash 2.1.1",
3292 + "rustfft",
3293 + "safetensors 0.7.0",
3294 + "schemars 1.2.1",
3295 + "scraper",
3296 + "serde",
3297 + "serde-big-array",
3298 + "serde-saphyr",
3299 + "serde_json",
3300 + "serde_plain",
3301 + "statrs",
3302 + "strum",
3303 + "symphonia",
3304 + "sysinfo",
3305 + "thiserror 2.0.18",
3306 + "tokenizers",
3307 + "tokio",
3308 + "tokio-rayon",
3309 + "tokio-tungstenite",
3310 + "toktrie",
3311 + "toktrie_hf_tokenizers",
3312 + "toml",
3313 + "tqdm",
3314 + "tracing",
3315 + "tracing-subscriber",
3316 + "urlencoding",
3317 + "uuid 1.21.0",
3318 + "variantly",
3319 + "vob",
3320 +]
3321 +
3322 +[[package]]
3323 +name = "mistralrs-macros"
3324 +version = "0.7.1-alpha.1"
3325 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3326 +dependencies = [
3327 + "darling 0.23.0",
3328 + "proc-macro2",
3329 + "quote",
3330 + "syn 2.0.117",
3331 +]
3332 +
3333 +[[package]]
3334 +name = "mistralrs-mcp"
3335 +version = "0.7.1-alpha.1"
3336 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3337 +dependencies = [
3338 + "anyhow",
3339 + "async-trait",
3340 + "futures-util",
3341 + "http",
3342 + "reqwest 0.13.2",
3343 + "rust-mcp-schema",
3344 + "serde",
3345 + "serde_json",
3346 + "tokio",
3347 + "tokio-tungstenite",
3348 + "tracing",
3349 + "utoipa",
3350 + "uuid 1.21.0",
3351 +]
3352 +
3353 +[[package]]
3354 +name = "mistralrs-paged-attn"
3355 +version = "0.7.1-alpha.1"
3356 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3357 +dependencies = [
3358 + "anyhow",
3359 + "candle-core",
3360 + "candle-metal-kernels",
3361 + "dispatch2",
3362 + "float8",
3363 + "half",
3364 + "objc2-foundation",
3365 + "objc2-metal",
3366 + "thiserror 2.0.18",
3367 +]
3368 +
3369 +[[package]]
3370 +name = "mistralrs-quant"
3371 +version = "0.7.1-alpha.1"
3372 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3373 +dependencies = [
3374 + "byteorder",
3375 + "candle-core",
3376 + "candle-metal-kernels",
3377 + "candle-nn",
3378 + "dispatch2",
3379 + "float8",
3380 + "half",
3381 + "hf-hub",
3382 + "lazy_static",
3383 + "memmap2",
3384 + "objc2-foundation",
3385 + "objc2-metal",
3386 + "paste",
3387 + "rayon",
3388 + "regex",
3389 + "safetensors 0.7.0",
3390 + "serde",
3391 + "serde_json",
3392 + "thiserror 2.0.18",
3393 + "tokio",
3394 + "tracing",
3395 + "yoke 0.8.1",
3396 +]
3397 +
3398 +[[package]]
3399 +name = "mistralrs-vision"
3400 +version = "0.7.1-alpha.1"
3401 +source = "git+https://github.com/setoelkahfi/mistral.rs?branch=fix%2Fall-platform-fixes#197e02c33bcb8004740e08db46d764daf201aa8e"
3402 +dependencies = [
3403 + "candle-core",
3404 + "image",
3405 + "rayon",
3406 +]
3407 +
3408 +[[package]]
3409 +name = "monostate"
3410 +version = "0.1.18"
3411 +source = "registry+https://github.com/rust-lang/crates.io-index"
3412 +checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67"
3413 +dependencies = [
3414 + "monostate-impl",
3415 + "serde",
3416 + "serde_core",
3417 +]
3418 +
3419 +[[package]]
3420 +name = "monostate-impl"
3421 +version = "0.1.18"
3422 +source = "registry+https://github.com/rust-lang/crates.io-index"
3423 +checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9"
3424 +dependencies = [
3425 + "proc-macro2",
3426 + "quote",
3427 + "syn 2.0.117",
3428 +]
3429 +
3430 +[[package]]
3431 +name = "moxcms"
3432 +version = "0.7.11"
3433 +source = "registry+https://github.com/rust-lang/crates.io-index"
3434 +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
3435 +dependencies = [
3436 + "num-traits",
3437 + "pxfm",
3438 +]
3439 +
3440 +[[package]]
3441 +name = "nalgebra"
3442 +version = "0.33.2"
3443 +source = "registry+https://github.com/rust-lang/crates.io-index"
3444 +checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b"
3445 +dependencies = [
3446 + "approx",
3447 + "matrixmultiply",
3448 + "num-complex",
3449 + "num-rational",
3450 + "num-traits",
3451 + "rand 0.8.5",
3452 + "rand_distr 0.4.3",
3453 + "simba",
3454 + "typenum",
3455 +]
3456 +
3457 +[[package]]
3458 +name = "native-tls"
3459 +version = "0.2.18"
3460 +source = "registry+https://github.com/rust-lang/crates.io-index"
3461 +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2"
3462 +dependencies = [
3463 + "libc",
3464 + "log",
3465 + "openssl",
3466 + "openssl-probe",
3467 + "openssl-sys",
3468 + "schannel",
3469 + "security-framework",
3470 + "security-framework-sys",
3471 + "tempfile",
3472 +]
3473 +
3474 +[[package]]
3475 +name = "new_debug_unreachable"
3476 +version = "1.0.6"
3477 +source = "registry+https://github.com/rust-lang/crates.io-index"
3478 +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
3479 +
3480 +[[package]]
3481 +name = "nibble_vec"
3482 +version = "0.1.0"
3483 +source = "registry+https://github.com/rust-lang/crates.io-index"
3484 +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
3485 +dependencies = [
3486 + "smallvec 1.15.1",
3487 +]
3488 +
3489 +[[package]]
3490 +name = "nohash-hasher"
3491 +version = "0.2.0"
3492 +source = "registry+https://github.com/rust-lang/crates.io-index"
3493 +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
3494 +
3495 +[[package]]
3496 +name = "nom"
3497 +version = "7.1.3"
3498 +source = "registry+https://github.com/rust-lang/crates.io-index"
3499 +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
3500 +dependencies = [
3501 + "memchr",
3502 + "minimal-lexical",
3503 +]
3504 +
3505 +[[package]]
3506 +name = "nom"
3507 +version = "8.0.0"
3508 +source = "registry+https://github.com/rust-lang/crates.io-index"
3509 +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
3510 +dependencies = [
3511 + "memchr",
3512 +]
3513 +
3514 +[[package]]
3515 +name = "noop_proc_macro"
3516 +version = "0.3.0"
3517 +source = "registry+https://github.com/rust-lang/crates.io-index"
3518 +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
3519 +
3520 +[[package]]
3521 +name = "ntapi"
3522 +version = "0.4.3"
3523 +source = "registry+https://github.com/rust-lang/crates.io-index"
3524 +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae"
3525 +dependencies = [
3526 + "winapi",
3527 +]
3528 +
3529 +[[package]]
3530 +name = "nu-ansi-term"
3531 +version = "0.50.3"
3532 +source = "registry+https://github.com/rust-lang/crates.io-index"
3533 +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
3534 +dependencies = [
3535 + "windows-sys 0.61.2",
3536 +]
3537 +
3538 +[[package]]
3539 +name = "num"
3540 +version = "0.4.3"
3541 +source = "registry+https://github.com/rust-lang/crates.io-index"
3542 +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
3543 +dependencies = [
3544 + "num-bigint",
3545 + "num-complex",
3546 + "num-integer",
3547 + "num-iter",
3548 + "num-rational",
3549 + "num-traits",
3550 +]
3551 +
3552 +[[package]]
3553 +name = "num-bigint"
3554 +version = "0.4.6"
3555 +source = "registry+https://github.com/rust-lang/crates.io-index"
3556 +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
3557 +dependencies = [
3558 + "num-integer",
3559 + "num-traits",
3560 +]
3561 +
3562 +[[package]]
3563 +name = "num-complex"
3564 +version = "0.4.6"
3565 +source = "registry+https://github.com/rust-lang/crates.io-index"
3566 +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
3567 +dependencies = [
3568 + "bytemuck",
3569 + "num-traits",
3570 +]
3571 +
3572 +[[package]]
3573 +name = "num-conv"
3574 +version = "0.2.0"
3575 +source = "registry+https://github.com/rust-lang/crates.io-index"
3576 +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
3577 +
3578 +[[package]]
3579 +name = "num-derive"
3580 +version = "0.4.2"
3581 +source = "registry+https://github.com/rust-lang/crates.io-index"
3582 +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
3583 +dependencies = [
3584 + "proc-macro2",
3585 + "quote",
3586 + "syn 2.0.117",
3587 +]
3588 +
3589 +[[package]]
3590 +name = "num-integer"
3591 +version = "0.1.46"
3592 +source = "registry+https://github.com/rust-lang/crates.io-index"
3593 +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
3594 +dependencies = [
3595 + "num-traits",
3596 +]
3597 +
3598 +[[package]]
3599 +name = "num-iter"
3600 +version = "0.1.45"
3601 +source = "registry+https://github.com/rust-lang/crates.io-index"
3602 +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
3603 +dependencies = [
3604 + "autocfg",
3605 + "num-integer",
3606 + "num-traits",
3607 +]
3608 +
3609 +[[package]]
3610 +name = "num-rational"
3611 +version = "0.4.2"
3612 +source = "registry+https://github.com/rust-lang/crates.io-index"
3613 +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
3614 +dependencies = [
3615 + "num-bigint",
3616 + "num-integer",
3617 + "num-traits",
3618 +]
3619 +
3620 +[[package]]
3621 +name = "num-traits"
3622 +version = "0.2.19"
3623 +source = "registry+https://github.com/rust-lang/crates.io-index"
3624 +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
3625 +dependencies = [
3626 + "autocfg",
3627 + "libm",
3628 +]
3629 +
3630 +[[package]]
3631 +name = "num_cpus"
3632 +version = "1.17.0"
3633 +source = "registry+https://github.com/rust-lang/crates.io-index"
3634 +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
3635 +dependencies = [
3636 + "hermit-abi 0.5.2",
3637 + "libc",
3638 +]
3639 +
3640 +[[package]]
3641 +name = "number_prefix"
3642 +version = "0.4.0"
3643 +source = "registry+https://github.com/rust-lang/crates.io-index"
3644 +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
3645 +
3646 +[[package]]
3647 +name = "objc"
3648 +version = "0.2.7"
3649 +source = "registry+https://github.com/rust-lang/crates.io-index"
3650 +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
3651 +dependencies = [
3652 + "malloc_buf",
3653 +]
3654 +
3655 +[[package]]
3656 +name = "objc2"
3657 +version = "0.6.4"
3658 +source = "registry+https://github.com/rust-lang/crates.io-index"
3659 +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
3660 +dependencies = [
3661 + "objc2-encode",
3662 +]
3663 +
3664 +[[package]]
3665 +name = "objc2-core-foundation"
3666 +version = "0.3.2"
3667 +source = "registry+https://github.com/rust-lang/crates.io-index"
3668 +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
3669 +dependencies = [
3670 + "bitflags 2.11.0",
3671 + "dispatch2",
3672 + "objc2",
3673 +]
3674 +
3675 +[[package]]
3676 +name = "objc2-encode"
3677 +version = "4.1.0"
3678 +source = "registry+https://github.com/rust-lang/crates.io-index"
3679 +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
3680 +
3681 +[[package]]
3682 +name = "objc2-foundation"
3683 +version = "0.3.2"
3684 +source = "registry+https://github.com/rust-lang/crates.io-index"
3685 +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
3686 +dependencies = [
3687 + "bitflags 2.11.0",
3688 + "block2",
3689 + "libc",
3690 + "objc2",
3691 + "objc2-core-foundation",
3692 +]
3693 +
3694 +[[package]]
3695 +name = "objc2-io-kit"
3696 +version = "0.3.2"
3697 +source = "registry+https://github.com/rust-lang/crates.io-index"
3698 +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
3699 +dependencies = [
3700 + "libc",
3701 + "objc2-core-foundation",
3702 +]
3703 +
3704 +[[package]]
3705 +name = "objc2-metal"
3706 +version = "0.3.2"
3707 +source = "registry+https://github.com/rust-lang/crates.io-index"
3708 +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794"
3709 +dependencies = [
3710 + "bitflags 2.11.0",
3711 + "block2",
3712 + "dispatch2",
3713 + "objc2",
3714 + "objc2-core-foundation",
3715 + "objc2-foundation",
3716 +]
3717 +
3718 +[[package]]
3719 +name = "once_cell"
3720 +version = "1.21.3"
3721 +source = "registry+https://github.com/rust-lang/crates.io-index"
3722 +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
3723 +
3724 +[[package]]
3725 +name = "once_cell_polyfill"
3726 +version = "1.70.2"
3727 +source = "registry+https://github.com/rust-lang/crates.io-index"
3728 +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
3729 +
3730 +[[package]]
3731 +name = "onde"
3732 +version = "0.1.0"
3733 +dependencies = [
3734 + "anyhow",
3735 + "cc",
3736 + "hf-hub",
3737 + "home",
3738 + "log",
3739 + "mistralrs",
3740 + "mistralrs-core",
3741 + "serde",
3742 + "thiserror 2.0.18",
3743 + "tokio",
3744 + "tsync",
3745 + "uniffi",
3746 +]
3747 +
3748 +[[package]]
3749 +name = "onde-ruby"
3750 +version = "0.1.0"
3751 +dependencies = [
3752 + "magnus",
3753 + "onde",
3754 + "serde",
3755 + "serde_json",
3756 +]
3757 +
3758 +[[package]]
3759 +name = "openai-harmony"
3760 +version = "0.0.8"
3761 +source = "registry+https://github.com/rust-lang/crates.io-index"
3762 +checksum = "e77e82af451fc95deeb728a40b84db8ee82d341e136c268de415123a560b9b72"
3763 +dependencies = [
3764 + "anyhow",
3765 + "base64 0.22.1",
3766 + "bstr",
3767 + "clap 4.5.60",
3768 + "fancy-regex 0.13.0",
3769 + "futures",
3770 + "image",
3771 + "regex",
3772 + "reqwest 0.12.28",
3773 + "rustc-hash 1.1.0",
3774 + "serde",
3775 + "serde_json",
3776 + "serde_with",
3777 + "sha1",
3778 + "sha2",
3779 + "thiserror 2.0.18",
3780 +]
3781 +
3782 +[[package]]
3783 +name = "openssl"
3784 +version = "0.10.75"
3785 +source = "registry+https://github.com/rust-lang/crates.io-index"
3786 +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
3787 +dependencies = [
3788 + "bitflags 2.11.0",
3789 + "cfg-if",
3790 + "foreign-types 0.3.2",
3791 + "libc",
3792 + "once_cell",
3793 + "openssl-macros",
3794 + "openssl-sys",
3795 +]
3796 +
3797 +[[package]]
3798 +name = "openssl-macros"
3799 +version = "0.1.1"
3800 +source = "registry+https://github.com/rust-lang/crates.io-index"
3801 +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
3802 +dependencies = [
3803 + "proc-macro2",
3804 + "quote",
3805 + "syn 2.0.117",
3806 +]
3807 +
3808 +[[package]]
3809 +name = "openssl-probe"
3810 +version = "0.2.1"
3811 +source = "registry+https://github.com/rust-lang/crates.io-index"
3812 +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
3813 +
3814 +[[package]]
3815 +name = "openssl-sys"
3816 +version = "0.9.111"
3817 +source = "registry+https://github.com/rust-lang/crates.io-index"
3818 +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
3819 +dependencies = [
3820 + "cc",
3821 + "libc",
3822 + "pkg-config",
3823 + "vcpkg",
3824 +]
3825 +
3826 +[[package]]
3827 +name = "option-ext"
3828 +version = "0.2.0"
3829 +source = "registry+https://github.com/rust-lang/crates.io-index"
3830 +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
3831 +
3832 +[[package]]
3833 +name = "ordered-float"
3834 +version = "5.1.0"
3835 +source = "registry+https://github.com/rust-lang/crates.io-index"
3836 +checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
3837 +dependencies = [
3838 + "num-traits",
3839 +]
3840 +
3841 +[[package]]
3842 +name = "packedvec"
3843 +version = "1.2.5"
3844 +source = "registry+https://github.com/rust-lang/crates.io-index"
3845 +checksum = "a69e0a534dd2e6aefce319af62a0aa0066a76bdfcec0201dfe02df226bc9ec70"
3846 +dependencies = [
3847 + "num-traits",
3848 +]
3849 +
3850 +[[package]]
3851 +name = "parking_lot"
3852 +version = "0.12.5"
3853 +source = "registry+https://github.com/rust-lang/crates.io-index"
3854 +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
3855 +dependencies = [
3856 + "lock_api",
3857 + "parking_lot_core",
3858 +]
3859 +
3860 +[[package]]
3861 +name = "parking_lot_core"
3862 +version = "0.9.12"
3863 +source = "registry+https://github.com/rust-lang/crates.io-index"
3864 +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
3865 +dependencies = [
3866 + "cfg-if",
3867 + "libc",
3868 + "redox_syscall",
3869 + "smallvec 1.15.1",
3870 + "windows-link 0.2.1",
3871 +]
3872 +
3873 +[[package]]
3874 +name = "paste"
3875 +version = "1.0.15"
3876 +source = "registry+https://github.com/rust-lang/crates.io-index"
3877 +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
3878 +
3879 +[[package]]
3880 +name = "pastey"
3881 +version = "0.1.1"
3882 +source = "registry+https://github.com/rust-lang/crates.io-index"
3883 +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
3884 +
3885 +[[package]]
3886 +name = "percent-encoding"
3887 +version = "2.3.2"
3888 +source = "registry+https://github.com/rust-lang/crates.io-index"
3889 +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
3890 +
3891 +[[package]]
3892 +name = "phf"
3893 +version = "0.13.1"
3894 +source = "registry+https://github.com/rust-lang/crates.io-index"
3895 +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
3896 +dependencies = [
3897 + "phf_macros",
3898 + "phf_shared",
3899 + "serde",
3900 +]
3901 +
3902 +[[package]]
3903 +name = "phf_codegen"
3904 +version = "0.13.1"
3905 +source = "registry+https://github.com/rust-lang/crates.io-index"
3906 +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1"
3907 +dependencies = [
3908 + "phf_generator",
3909 + "phf_shared",
3910 +]
3911 +
3912 +[[package]]
3913 +name = "phf_generator"
3914 +version = "0.13.1"
3915 +source = "registry+https://github.com/rust-lang/crates.io-index"
3916 +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
3917 +dependencies = [
3918 + "fastrand",
3919 + "phf_shared",
3920 +]
3921 +
3922 +[[package]]
3923 +name = "phf_macros"
3924 +version = "0.13.1"
3925 +source = "registry+https://github.com/rust-lang/crates.io-index"
3926 +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
3927 +dependencies = [
3928 + "phf_generator",
3929 + "phf_shared",
3930 + "proc-macro2",
3931 + "quote",
3932 + "syn 2.0.117",
3933 +]
3934 +
3935 +[[package]]
3936 +name = "phf_shared"
3937 +version = "0.13.1"
3938 +source = "registry+https://github.com/rust-lang/crates.io-index"
3939 +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
3940 +dependencies = [
3941 + "siphasher",
3942 +]
3943 +
3944 +[[package]]
3945 +name = "pin-project-lite"
3946 +version = "0.2.17"
3947 +source = "registry+https://github.com/rust-lang/crates.io-index"
3948 +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
3949 +
3950 +[[package]]
3951 +name = "pin-utils"
3952 +version = "0.1.0"
3953 +source = "registry+https://github.com/rust-lang/crates.io-index"
3954 +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
3955 +
3956 +[[package]]
3957 +name = "pkg-config"
3958 +version = "0.3.32"
3959 +source = "registry+https://github.com/rust-lang/crates.io-index"
3960 +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
3961 +
3962 +[[package]]
3963 +name = "plain"
3964 +version = "0.2.3"
3965 +source = "registry+https://github.com/rust-lang/crates.io-index"
3966 +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
3967 +
3968 +[[package]]
3969 +name = "png"
3970 +version = "0.18.1"
3971 +source = "registry+https://github.com/rust-lang/crates.io-index"
3972 +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
3973 +dependencies = [
3974 + "bitflags 2.11.0",
3975 + "crc32fast",
3976 + "fdeflate",
3977 + "flate2",
3978 + "miniz_oxide",
3979 +]
3980 +
3981 +[[package]]
3982 +name = "portable-atomic"
3983 +version = "1.13.1"
3984 +source = "registry+https://github.com/rust-lang/crates.io-index"
3985 +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
3986 +
3987 +[[package]]
3988 +name = "potential_utf"
3989 +version = "0.1.4"
3990 +source = "registry+https://github.com/rust-lang/crates.io-index"
3991 +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
3992 +dependencies = [
3993 + "zerovec",
3994 +]
3995 +
3996 +[[package]]
3997 +name = "powerfmt"
3998 +version = "0.2.0"
3999 +source = "registry+https://github.com/rust-lang/crates.io-index"
4000 +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
4001 +
4002 +[[package]]
4003 +name = "ppv-lite86"
4004 +version = "0.2.21"
4005 +source = "registry+https://github.com/rust-lang/crates.io-index"
4006 +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
4007 +dependencies = [
4008 + "zerocopy",
4009 +]
4010 +
4011 +[[package]]
4012 +name = "precomputed-hash"
4013 +version = "0.1.1"
4014 +source = "registry+https://github.com/rust-lang/crates.io-index"
4015 +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
4016 +
4017 +[[package]]
4018 +name = "prettyplease"
4019 +version = "0.2.37"
4020 +source = "registry+https://github.com/rust-lang/crates.io-index"
4021 +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
4022 +dependencies = [
4023 + "proc-macro2",
4024 + "syn 2.0.117",
4025 +]
4026 +
4027 +[[package]]
4028 +name = "primal-check"
4029 +version = "0.3.4"
4030 +source = "registry+https://github.com/rust-lang/crates.io-index"
4031 +checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08"
4032 +dependencies = [
4033 + "num-integer",
4034 +]
4035 +
4036 +[[package]]
4037 +name = "proc-macro-error"
4038 +version = "1.0.4"
4039 +source = "registry+https://github.com/rust-lang/crates.io-index"
4040 +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
4041 +dependencies = [
4042 + "proc-macro-error-attr",
4043 + "proc-macro2",
4044 + "quote",
4045 + "syn 1.0.109",
4046 + "version_check",
4047 +]
4048 +
4049 +[[package]]
4050 +name = "proc-macro-error-attr"
4051 +version = "1.0.4"
4052 +source = "registry+https://github.com/rust-lang/crates.io-index"
4053 +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
4054 +dependencies = [
4055 + "proc-macro2",
4056 + "quote",
4057 + "version_check",
4058 +]
4059 +
4060 +[[package]]
4061 +name = "proc-macro2"
4062 +version = "1.0.106"
4063 +source = "registry+https://github.com/rust-lang/crates.io-index"
4064 +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
4065 +dependencies = [
4066 + "unicode-ident",
4067 +]
4068 +
4069 +[[package]]
4070 +name = "profiling"
4071 +version = "1.0.17"
4072 +source = "registry+https://github.com/rust-lang/crates.io-index"
4073 +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
4074 +dependencies = [
4075 + "profiling-procmacros",
4076 +]
4077 +
4078 +[[package]]
4079 +name = "profiling-procmacros"
4080 +version = "1.0.17"
4081 +source = "registry+https://github.com/rust-lang/crates.io-index"
4082 +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
4083 +dependencies = [
4084 + "quote",
4085 + "syn 2.0.117",
4086 +]
4087 +
4088 +[[package]]
4089 +name = "pulp"
4090 +version = "0.21.5"
4091 +source = "registry+https://github.com/rust-lang/crates.io-index"
4092 +checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907"
4093 +dependencies = [
4094 + "bytemuck",
4095 + "cfg-if",
4096 + "libm",
4097 + "num-complex",
4098 + "reborrow",
4099 + "version_check",
4100 +]
4101 +
4102 +[[package]]
4103 +name = "pulp"
4104 +version = "0.22.2"
4105 +source = "registry+https://github.com/rust-lang/crates.io-index"
4106 +checksum = "2e205bb30d5b916c55e584c22201771bcf2bad9aabd5d4127f38387140c38632"
4107 +dependencies = [
4108 + "bytemuck",
4109 + "cfg-if",
4110 + "libm",
4111 + "num-complex",
4112 + "paste",
4113 + "pulp-wasm-simd-flag",
4114 + "raw-cpuid",
4115 + "reborrow",
4116 + "version_check",
4117 +]
4118 +
4119 +[[package]]
4120 +name = "pulp-wasm-simd-flag"
4121 +version = "0.1.0"
4122 +source = "registry+https://github.com/rust-lang/crates.io-index"
4123 +checksum = "40e24eee682d89fb193496edf918a7f407d30175b2e785fe057e4392dfd182e0"
4124 +
4125 +[[package]]
4126 +name = "pxfm"
4127 +version = "0.1.28"
4128 +source = "registry+https://github.com/rust-lang/crates.io-index"
4129 +checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d"
4130 +
4131 +[[package]]
4132 +name = "qoi"
4133 +version = "0.4.1"
4134 +source = "registry+https://github.com/rust-lang/crates.io-index"
4135 +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
4136 +dependencies = [
4137 + "bytemuck",
4138 +]
4139 +
4140 +[[package]]
4141 +name = "quick-error"
4142 +version = "2.0.1"
4143 +source = "registry+https://github.com/rust-lang/crates.io-index"
4144 +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
4145 +
4146 +[[package]]
4147 +name = "quinn"
4148 +version = "0.11.9"
4149 +source = "registry+https://github.com/rust-lang/crates.io-index"
4150 +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
4151 +dependencies = [
4152 + "bytes",
4153 + "cfg_aliases",
4154 + "pin-project-lite",
4155 + "quinn-proto",
4156 + "quinn-udp",
4157 + "rustc-hash 2.1.1",
4158 + "rustls",
4159 + "socket2",
4160 + "thiserror 2.0.18",
4161 + "tokio",
4162 + "tracing",
4163 + "web-time",
4164 +]
4165 +
4166 +[[package]]
4167 +name = "quinn-proto"
4168 +version = "0.11.13"
4169 +source = "registry+https://github.com/rust-lang/crates.io-index"
4170 +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
4171 +dependencies = [
4172 + "aws-lc-rs",
4173 + "bytes",
4174 + "getrandom 0.3.4",
4175 + "lru-slab",
4176 + "rand 0.9.2",
4177 + "ring",
4178 + "rustc-hash 2.1.1",
4179 + "rustls",
4180 + "rustls-pki-types",
4181 + "slab",
4182 + "thiserror 2.0.18",
4183 + "tinyvec",
4184 + "tracing",
4185 + "web-time",
4186 +]
4187 +
4188 +[[package]]
4189 +name = "quinn-udp"
4190 +version = "0.5.14"
4191 +source = "registry+https://github.com/rust-lang/crates.io-index"
4192 +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
4193 +dependencies = [
4194 + "cfg_aliases",
4195 + "libc",
4196 + "once_cell",
4197 + "socket2",
4198 + "tracing",
4199 + "windows-sys 0.60.2",
4200 +]
4201 +
4202 +[[package]]
4203 +name = "quote"
4204 +version = "1.0.44"
4205 +source = "registry+https://github.com/rust-lang/crates.io-index"
4206 +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
4207 +dependencies = [
4208 + "proc-macro2",
4209 +]
4210 +
4211 +[[package]]
4212 +name = "r-efi"
4213 +version = "5.3.0"
4214 +source = "registry+https://github.com/rust-lang/crates.io-index"
4215 +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
4216 +
4217 +[[package]]
4218 +name = "r-efi"
4219 +version = "6.0.0"
4220 +source = "registry+https://github.com/rust-lang/crates.io-index"
4221 +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
4222 +
4223 +[[package]]
4224 +name = "radix_trie"
4225 +version = "0.3.0"
4226 +source = "registry+https://github.com/rust-lang/crates.io-index"
4227 +checksum = "3b4431027dcd37fc2a73ef740b5f233aa805897935b8bce0195e41bbf9a3289a"
4228 +dependencies = [
4229 + "endian-type",
4230 + "nibble_vec",
4231 +]
4232 +
4233 +[[package]]
4234 +name = "rand"
4235 +version = "0.8.5"
4236 +source = "registry+https://github.com/rust-lang/crates.io-index"
4237 +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
4238 +dependencies = [
4239 + "libc",
4240 + "rand_chacha 0.3.1",
4241 + "rand_core 0.6.4",
4242 +]
4243 +
4244 +[[package]]
4245 +name = "rand"
4246 +version = "0.9.2"
4247 +source = "registry+https://github.com/rust-lang/crates.io-index"
4248 +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
4249 +dependencies = [
4250 + "rand_chacha 0.9.0",
4251 + "rand_core 0.9.5",
4252 +]
4253 +
4254 +[[package]]
4255 +name = "rand_chacha"
4256 +version = "0.3.1"
4257 +source = "registry+https://github.com/rust-lang/crates.io-index"
4258 +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
4259 +dependencies = [
4260 + "ppv-lite86",
4261 + "rand_core 0.6.4",
4262 +]
4263 +
4264 +[[package]]
4265 +name = "rand_chacha"
4266 +version = "0.9.0"
4267 +source = "registry+https://github.com/rust-lang/crates.io-index"
4268 +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
4269 +dependencies = [
4270 + "ppv-lite86",
4271 + "rand_core 0.9.5",
4272 +]
4273 +
4274 +[[package]]
4275 +name = "rand_core"
4276 +version = "0.6.4"
4277 +source = "registry+https://github.com/rust-lang/crates.io-index"
4278 +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
4279 +dependencies = [
4280 + "getrandom 0.2.17",
4281 +]
4282 +
4283 +[[package]]
4284 +name = "rand_core"
4285 +version = "0.9.5"
4286 +source = "registry+https://github.com/rust-lang/crates.io-index"
4287 +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
4288 +dependencies = [
4289 + "getrandom 0.3.4",
4290 +]
4291 +
4292 +[[package]]
4293 +name = "rand_distr"
4294 +version = "0.4.3"
4295 +source = "registry+https://github.com/rust-lang/crates.io-index"
4296 +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
4297 +dependencies = [
4298 + "num-traits",
4299 + "rand 0.8.5",
4300 +]
4301 +
4302 +[[package]]
4303 +name = "rand_distr"
4304 +version = "0.5.1"
4305 +source = "registry+https://github.com/rust-lang/crates.io-index"
4306 +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463"
4307 +dependencies = [
4308 + "num-traits",
4309 + "rand 0.9.2",
4310 +]
4311 +
4312 +[[package]]
4313 +name = "rand_isaac"
4314 +version = "0.4.0"
4315 +source = "registry+https://github.com/rust-lang/crates.io-index"
4316 +checksum = "3382fc9f0aad4f2e2a56b53d9133c8c810b4dbf21e7e370e24346161a5b2c7bd"
4317 +dependencies = [
4318 + "rand_core 0.9.5",
4319 +]
4320 +
4321 +[[package]]
4322 +name = "rav1e"
4323 +version = "0.8.1"
4324 +source = "registry+https://github.com/rust-lang/crates.io-index"
4325 +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b"
4326 +dependencies = [
4327 + "aligned-vec",
4328 + "arbitrary",
4329 + "arg_enum_proc_macro",
4330 + "arrayvec",
4331 + "av-scenechange",
4332 + "av1-grain",
4333 + "bitstream-io",
4334 + "built",
4335 + "cfg-if",
4336 + "interpolate_name",
4337 + "itertools 0.14.0",
4338 + "libc",
4339 + "libfuzzer-sys",
4340 + "log",
4341 + "maybe-rayon",
4342 + "new_debug_unreachable",
4343 + "noop_proc_macro",
4344 + "num-derive",
4345 + "num-traits",
4346 + "paste",
4347 + "profiling",
4348 + "rand 0.9.2",
4349 + "rand_chacha 0.9.0",
4350 + "simd_helpers",
4351 + "thiserror 2.0.18",
4352 + "v_frame",
4353 + "wasm-bindgen",
4354 +]
4355 +
4356 +[[package]]
4357 +name = "ravif"
4358 +version = "0.12.0"
4359 +source = "registry+https://github.com/rust-lang/crates.io-index"
4360 +checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285"
4361 +dependencies = [
4362 + "avif-serialize",
4363 + "imgref",
4364 + "loop9",
4365 + "quick-error",
4366 + "rav1e",
4367 + "rayon",
4368 + "rgb",
4369 +]
4370 +
4371 +[[package]]
4372 +name = "raw-cpuid"
4373 +version = "11.6.0"
4374 +source = "registry+https://github.com/rust-lang/crates.io-index"
4375 +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
4376 +dependencies = [
4377 + "bitflags 2.11.0",
4378 +]
4379 +
4380 +[[package]]
4381 +name = "rawpointer"
4382 +version = "0.2.1"
4383 +source = "registry+https://github.com/rust-lang/crates.io-index"
4384 +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
4385 +
4386 +[[package]]
4387 +name = "rayon"
4388 +version = "1.11.0"
4389 +source = "registry+https://github.com/rust-lang/crates.io-index"
4390 +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
4391 +dependencies = [
4392 + "either",
4393 + "rayon-core",
4394 +]
4395 +
4396 +[[package]]
4397 +name = "rayon-cond"
4398 +version = "0.4.0"
4399 +source = "registry+https://github.com/rust-lang/crates.io-index"
4400 +checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f"
4401 +dependencies = [
4402 + "either",
4403 + "itertools 0.14.0",
4404 + "rayon",
4405 +]
4406 +
4407 +[[package]]
4408 +name = "rayon-core"
4409 +version = "1.13.0"
4410 +source = "registry+https://github.com/rust-lang/crates.io-index"
4411 +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
4412 +dependencies = [
4413 + "crossbeam-deque",
4414 + "crossbeam-utils",
4415 +]
4416 +
4417 +[[package]]
4418 +name = "rb-sys"
4419 +version = "0.9.124"
4420 +source = "registry+https://github.com/rust-lang/crates.io-index"
4421 +checksum = "c85c4188462601e2aa1469def389c17228566f82ea72f137ed096f21591bc489"
4422 +dependencies = [
4423 + "rb-sys-build",
4424 +]
4425 +
4426 +[[package]]
4427 +name = "rb-sys-build"
4428 +version = "0.9.124"
4429 +source = "registry+https://github.com/rust-lang/crates.io-index"
4430 +checksum = "568068db4102230882e6d4ae8de6632e224ca75fe5970f6e026a04e91ed635d3"
4431 +dependencies = [
4432 + "bindgen",
4433 + "lazy_static",
4434 + "proc-macro2",
4435 + "quote",
4436 + "regex",
4437 + "shell-words",
4438 + "syn 2.0.117",
4439 +]
4440 +
4441 +[[package]]
4442 +name = "rb-sys-env"
4443 +version = "0.1.2"
4444 +source = "registry+https://github.com/rust-lang/crates.io-index"
4445 +checksum = "a35802679f07360454b418a5d1735c89716bde01d35b1560fc953c1415a0b3bb"
4446 +
4447 +[[package]]
4448 +name = "realfft"
4449 +version = "3.5.0"
4450 +source = "registry+https://github.com/rust-lang/crates.io-index"
4451 +checksum = "f821338fddb99d089116342c46e9f1fbf3828dba077674613e734e01d6ea8677"
4452 +dependencies = [
4453 + "rustfft",
4454 +]
4455 +
4456 +[[package]]
4457 +name = "reborrow"
4458 +version = "0.5.5"
4459 +source = "registry+https://github.com/rust-lang/crates.io-index"
4460 +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430"
4461 +
4462 +[[package]]
4463 +name = "recvmsg"
4464 +version = "1.0.0"
4465 +source = "registry+https://github.com/rust-lang/crates.io-index"
4466 +checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175"
4467 +
4468 +[[package]]
4469 +name = "redox_syscall"
4470 +version = "0.5.18"
4471 +source = "registry+https://github.com/rust-lang/crates.io-index"
4472 +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
4473 +dependencies = [
4474 + "bitflags 2.11.0",
4475 +]
4476 +
4477 +[[package]]
4478 +name = "redox_users"
4479 +version = "0.5.2"
4480 +source = "registry+https://github.com/rust-lang/crates.io-index"
4481 +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
4482 +dependencies = [
4483 + "getrandom 0.2.17",
4484 + "libredox",
4485 + "thiserror 2.0.18",
4486 +]
4487 +
4488 +[[package]]
4489 +name = "ref-cast"
4490 +version = "1.0.25"
4491 +source = "registry+https://github.com/rust-lang/crates.io-index"
4492 +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
4493 +dependencies = [
4494 + "ref-cast-impl",
4495 +]
4496 +
4497 +[[package]]
4498 +name = "ref-cast-impl"
4499 +version = "1.0.25"
4500 +source = "registry+https://github.com/rust-lang/crates.io-index"
4501 +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
4502 +dependencies = [
4503 + "proc-macro2",
4504 + "quote",
4505 + "syn 2.0.117",
4506 +]
4507 +
4508 +[[package]]
4509 +name = "regex"
4510 +version = "1.12.3"
4511 +source = "registry+https://github.com/rust-lang/crates.io-index"
4512 +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
4513 +dependencies = [
4514 + "aho-corasick",
4515 + "memchr",
4516 + "regex-automata",
4517 + "regex-syntax",
4518 +]
4519 +
4520 +[[package]]
4521 +name = "regex-automata"
4522 +version = "0.4.14"
4523 +source = "registry+https://github.com/rust-lang/crates.io-index"
4524 +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
4525 +dependencies = [
4526 + "aho-corasick",
4527 + "memchr",
4528 + "regex-syntax",
4529 +]
4530 +
4531 +[[package]]
4532 +name = "regex-syntax"
4533 +version = "0.8.10"
4534 +source = "registry+https://github.com/rust-lang/crates.io-index"
4535 +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
4536 +
4537 +[[package]]
4538 +name = "reqwest"
4539 +version = "0.12.28"
4540 +source = "registry+https://github.com/rust-lang/crates.io-index"
4541 +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
4542 +dependencies = [
4543 + "base64 0.22.1",
4544 + "bytes",
4545 + "encoding_rs",
4546 + "futures-channel",
4547 + "futures-core",
4548 + "futures-util",
4549 + "h2",
4550 + "http",
4551 + "http-body",
4552 + "http-body-util",
4553 + "hyper",
4554 + "hyper-rustls",
4555 + "hyper-tls",
4556 + "hyper-util",
4557 + "js-sys",
4558 + "log",
4559 + "mime",
4560 + "mime_guess",
4561 + "native-tls",
4562 + "percent-encoding",
4563 + "pin-project-lite",
4564 + "quinn",
4565 + "rustls",
4566 + "rustls-pki-types",
4567 + "serde",
4568 + "serde_json",
4569 + "serde_urlencoded",
4570 + "sync_wrapper",
4571 + "tokio",
4572 + "tokio-native-tls",
4573 + "tokio-rustls",
4574 + "tokio-util",
4575 + "tower",
4576 + "tower-http",
4577 + "tower-service",
4578 + "url",
4579 + "wasm-bindgen",
4580 + "wasm-bindgen-futures",
4581 + "wasm-streams 0.4.2",
4582 + "web-sys",
4583 + "webpki-roots 1.0.6",
4584 +]
4585 +
4586 +[[package]]
4587 +name = "reqwest"
4588 +version = "0.13.2"
4589 +source = "registry+https://github.com/rust-lang/crates.io-index"
4590 +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
4591 +dependencies = [
4592 + "base64 0.22.1",
4593 + "bytes",
4594 + "encoding_rs",
4595 + "futures-channel",
4596 + "futures-core",
4597 + "futures-util",
4598 + "h2",
4599 + "http",
4600 + "http-body",
4601 + "http-body-util",
4602 + "hyper",
4603 + "hyper-rustls",
4604 + "hyper-util",
4605 + "js-sys",
4606 + "log",
4607 + "mime",
4608 + "percent-encoding",
4609 + "pin-project-lite",
4610 + "quinn",
4611 + "rustls",
4612 + "rustls-pki-types",
4613 + "rustls-platform-verifier",
4614 + "serde",
4615 + "serde_json",
4616 + "sync_wrapper",
4617 + "tokio",
4618 + "tokio-rustls",
4619 + "tokio-util",
4620 + "tower",
4621 + "tower-http",
4622 + "tower-service",
4623 + "url",
4624 + "wasm-bindgen",
4625 + "wasm-bindgen-futures",
4626 + "wasm-streams 0.5.0",
4627 + "web-sys",
4628 +]
4629 +
4630 +[[package]]
4631 +name = "rgb"
4632 +version = "0.8.53"
4633 +source = "registry+https://github.com/rust-lang/crates.io-index"
4634 +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
4635 +
4636 +[[package]]
4637 +name = "ring"
4638 +version = "0.17.14"
4639 +source = "registry+https://github.com/rust-lang/crates.io-index"
4640 +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
4641 +dependencies = [
4642 + "cc",
4643 + "cfg-if",
4644 + "getrandom 0.2.17",
4645 + "libc",
4646 + "untrusted",
4647 + "windows-sys 0.52.0",
4648 +]
4649 +
4650 +[[package]]
4651 +name = "rubato"
4652 +version = "0.16.2"
4653 +source = "registry+https://github.com/rust-lang/crates.io-index"
4654 +checksum = "5258099699851cfd0082aeb645feb9c084d9a5e1f1b8d5372086b989fc5e56a1"
4655 +dependencies = [
4656 + "num-complex",
4657 + "num-integer",
4658 + "num-traits",
4659 + "realfft",
4660 +]
4661 +
4662 +[[package]]
4663 +name = "rust-mcp-schema"
4664 +version = "0.9.5"
4665 +source = "registry+https://github.com/rust-lang/crates.io-index"
4666 +checksum = "5ed324cdee4b735926a1eaa7741b63a5d103ee08bbe0d3701398279b0c3bf3ce"
4667 +dependencies = [
4668 + "serde",
4669 + "serde_json",
4670 +]
4671 +
4672 +[[package]]
4673 +name = "rust-stemmers"
4674 +version = "1.2.0"
4675 +source = "registry+https://github.com/rust-lang/crates.io-index"
4676 +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
4677 +dependencies = [
4678 + "serde",
4679 + "serde_derive",
4680 +]
4681 +
4682 +[[package]]
4683 +name = "rustc-hash"
4684 +version = "1.1.0"
4685 +source = "registry+https://github.com/rust-lang/crates.io-index"
4686 +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
4687 +
4688 +[[package]]
4689 +name = "rustc-hash"
4690 +version = "2.1.1"
4691 +source = "registry+https://github.com/rust-lang/crates.io-index"
4692 +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
4693 +
4694 +[[package]]
4695 +name = "rustc_version"
4696 +version = "0.4.1"
4697 +source = "registry+https://github.com/rust-lang/crates.io-index"
4698 +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
4699 +dependencies = [
4700 + "semver",
4701 +]
4702 +
4703 +[[package]]
4704 +name = "rustfft"
4705 +version = "6.4.1"
4706 +source = "registry+https://github.com/rust-lang/crates.io-index"
4707 +checksum = "21db5f9893e91f41798c88680037dba611ca6674703c1a18601b01a72c8adb89"
4708 +dependencies = [
4709 + "num-complex",
4710 + "num-integer",
4711 + "num-traits",
4712 + "primal-check",
4713 + "strength_reduce",
4714 + "transpose",
4715 +]
4716 +
4717 +[[package]]
4718 +name = "rustix"
4719 +version = "1.1.4"
4720 +source = "registry+https://github.com/rust-lang/crates.io-index"
4721 +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
4722 +dependencies = [
4723 + "bitflags 2.11.0",
4724 + "errno",
4725 + "libc",
4726 + "linux-raw-sys",
4727 + "windows-sys 0.61.2",
4728 +]
4729 +
4730 +[[package]]
4731 +name = "rustls"
4732 +version = "0.23.37"
4733 +source = "registry+https://github.com/rust-lang/crates.io-index"
4734 +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
4735 +dependencies = [
4736 + "aws-lc-rs",
4737 + "log",
4738 + "once_cell",
4739 + "ring",
4740 + "rustls-pki-types",
4741 + "rustls-webpki",
4742 + "subtle",
4743 + "zeroize",
4744 +]
4745 +
4746 +[[package]]
4747 +name = "rustls-native-certs"
4748 +version = "0.8.3"
4749 +source = "registry+https://github.com/rust-lang/crates.io-index"
4750 +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
4751 +dependencies = [
4752 + "openssl-probe",
4753 + "rustls-pki-types",
4754 + "schannel",
4755 + "security-framework",
4756 +]
4757 +
4758 +[[package]]
4759 +name = "rustls-pki-types"
4760 +version = "1.14.0"
4761 +source = "registry+https://github.com/rust-lang/crates.io-index"
4762 +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
4763 +dependencies = [
4764 + "web-time",
4765 + "zeroize",
4766 +]
4767 +
4768 +[[package]]
4769 +name = "rustls-platform-verifier"
4770 +version = "0.6.2"
4771 +source = "registry+https://github.com/rust-lang/crates.io-index"
4772 +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
4773 +dependencies = [
4774 + "core-foundation 0.10.1",
4775 + "core-foundation-sys",
4776 + "jni",
4777 + "log",
4778 + "once_cell",
4779 + "rustls",
4780 + "rustls-native-certs",
4781 + "rustls-platform-verifier-android",
4782 + "rustls-webpki",
4783 + "security-framework",
4784 + "security-framework-sys",
4785 + "webpki-root-certs",
4786 + "windows-sys 0.61.2",
4787 +]
4788 +
4789 +[[package]]
4790 +name = "rustls-platform-verifier-android"
4791 +version = "0.1.1"
4792 +source = "registry+https://github.com/rust-lang/crates.io-index"
4793 +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
4794 +
4795 +[[package]]
4796 +name = "rustls-webpki"
4797 +version = "0.103.9"
4798 +source = "registry+https://github.com/rust-lang/crates.io-index"
4799 +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
4800 +dependencies = [
4801 + "aws-lc-rs",
4802 + "ring",
4803 + "rustls-pki-types",
4804 + "untrusted",
4805 +]
4806 +
4807 +[[package]]
4808 +name = "rustversion"
4809 +version = "1.0.22"
4810 +source = "registry+https://github.com/rust-lang/crates.io-index"
4811 +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
4812 +
4813 +[[package]]
4814 +name = "ryu"
4815 +version = "1.0.23"
4816 +source = "registry+https://github.com/rust-lang/crates.io-index"
4817 +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
4818 +
4819 +[[package]]
4820 +name = "safe_arch"
4821 +version = "0.7.4"
4822 +source = "registry+https://github.com/rust-lang/crates.io-index"
4823 +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
4824 +dependencies = [
4825 + "bytemuck",
4826 +]
4827 +
4828 +[[package]]
4829 +name = "safetensors"
4830 +version = "0.4.5"
4831 +source = "registry+https://github.com/rust-lang/crates.io-index"
4832 +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6"
4833 +dependencies = [
4834 + "serde",
4835 + "serde_json",
4836 +]
4837 +
4838 +[[package]]
4839 +name = "safetensors"
4840 +version = "0.7.0"
4841 +source = "registry+https://github.com/rust-lang/crates.io-index"
4842 +checksum = "675656c1eabb620b921efea4f9199f97fc86e36dd6ffd1fbbe48d0f59a4987f5"
4843 +dependencies = [
4844 + "hashbrown 0.16.1",
4845 + "serde",
4846 + "serde_json",
4847 +]
4848 +
4849 +[[package]]
4850 +name = "same-file"
4851 +version = "1.0.6"
4852 +source = "registry+https://github.com/rust-lang/crates.io-index"
4853 +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
4854 +dependencies = [
4855 + "winapi-util",
4856 +]
4857 +
4858 +[[package]]
4859 +name = "saphyr-parser-bw"
4860 +version = "0.0.605"
4861 +source = "registry+https://github.com/rust-lang/crates.io-index"
4862 +checksum = "5e1aee7486406df3541b5a657204a11be97175a467d77bc98e6d94a66289fb80"
4863 +dependencies = [
4864 + "arraydeque",
4865 + "smallvec 2.0.0-alpha.12",
4866 + "thiserror 2.0.18",
4867 +]
4868 +
4869 +[[package]]
4870 +name = "schannel"
4871 +version = "0.1.28"
4872 +source = "registry+https://github.com/rust-lang/crates.io-index"
4873 +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
4874 +dependencies = [
4875 + "windows-sys 0.61.2",
4876 +]
4877 +
4878 +[[package]]
4879 +name = "schemars"
4880 +version = "0.9.0"
4881 +source = "registry+https://github.com/rust-lang/crates.io-index"
4882 +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
4883 +dependencies = [
4884 + "dyn-clone",
4885 + "ref-cast",
4886 + "serde",
4887 + "serde_json",
4888 +]
4889 +
4890 +[[package]]
4891 +name = "schemars"
4892 +version = "1.2.1"
4893 +source = "registry+https://github.com/rust-lang/crates.io-index"
4894 +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc"
4895 +dependencies = [
4896 + "dyn-clone",
4897 + "ref-cast",
4898 + "schemars_derive",
4899 + "serde",
4900 + "serde_json",
4901 +]
4902 +
4903 +[[package]]
4904 +name = "schemars_derive"
4905 +version = "1.2.1"
4906 +source = "registry+https://github.com/rust-lang/crates.io-index"
4907 +checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f"
4908 +dependencies = [
4909 + "proc-macro2",
4910 + "quote",
4911 + "serde_derive_internals",
4912 + "syn 2.0.117",
4913 +]
4914 +
4915 +[[package]]
4916 +name = "scoped-tls"
4917 +version = "1.0.1"
4918 +source = "registry+https://github.com/rust-lang/crates.io-index"
4919 +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
4920 +
4921 +[[package]]
4922 +name = "scopeguard"
4923 +version = "1.2.0"
4924 +source = "registry+https://github.com/rust-lang/crates.io-index"
4925 +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
4926 +
4927 +[[package]]
4928 +name = "scraper"
4929 +version = "0.25.0"
4930 +source = "registry+https://github.com/rust-lang/crates.io-index"
4931 +checksum = "93cecd86d6259499c844440546d02f55f3e17bd286e529e48d1f9f67e92315cb"
4932 +dependencies = [
4933 + "cssparser",
4934 + "ego-tree",
4935 + "getopts",
4936 + "html5ever 0.36.1",
4937 + "precomputed-hash",
4938 + "selectors",
4939 + "tendril 0.4.3",
4940 +]
4941 +
4942 +[[package]]
4943 +name = "scroll"
4944 +version = "0.12.0"
4945 +source = "registry+https://github.com/rust-lang/crates.io-index"
4946 +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
4947 +dependencies = [
4948 + "scroll_derive",
4949 +]
4950 +
4951 +[[package]]
4952 +name = "scroll_derive"
4953 +version = "0.12.1"
4954 +source = "registry+https://github.com/rust-lang/crates.io-index"
4955 +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
4956 +dependencies = [
4957 + "proc-macro2",
4958 + "quote",
4959 + "syn 2.0.117",
4960 +]
4961 +
4962 +[[package]]
4963 +name = "security-framework"
4964 +version = "3.7.0"
4965 +source = "registry+https://github.com/rust-lang/crates.io-index"
4966 +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
4967 +dependencies = [
4968 + "bitflags 2.11.0",
4969 + "core-foundation 0.10.1",
4970 + "core-foundation-sys",
4971 + "libc",
4972 + "security-framework-sys",
4973 +]
4974 +
4975 +[[package]]
4976 +name = "security-framework-sys"
4977 +version = "2.17.0"
4978 +source = "registry+https://github.com/rust-lang/crates.io-index"
4979 +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
4980 +dependencies = [
4981 + "core-foundation-sys",
4982 + "libc",
4983 +]
4984 +
4985 +[[package]]
4986 +name = "selectors"
4987 +version = "0.33.0"
4988 +source = "registry+https://github.com/rust-lang/crates.io-index"
4989 +checksum = "feef350c36147532e1b79ea5c1f3791373e61cbd9a6a2615413b3807bb164fb7"
4990 +dependencies = [
4991 + "bitflags 2.11.0",
4992 + "cssparser",
4993 + "derive_more",
4994 + "log",
4995 + "new_debug_unreachable",
4996 + "phf",
4997 + "phf_codegen",
4998 + "precomputed-hash",
4999 + "rustc-hash 2.1.1",

This file is too large to show in full.

sdk/gem/ext/onde-ruby/Cargo.toml new
+26
@@ -0,0 +1,26 @@
1 +[package]
2 +name = "onde-ruby"
3 +version = "0.1.0"
4 +edition = "2021"
5 +authors = ["Seto Elkahfi <setoelkahfi@gmail.com>"]
6 +publish = false
7 +
8 +[lib]
9 +name = "onde_ruby"
10 +crate-type = ["cdylib"]
11 +
12 +[dependencies]
13 +magnus = { version = "0.7" }
14 +serde = { version = "1.0", features = ["derive"] }
15 +serde_json = "1"
16 +
17 +# The onde crate — referenced via relative path from the monorepo.
18 +# We only pull in the pure-Rust surface (hf_cache, inference::models,
19 +# inference::types) so we do NOT enable the `whisper` feature or any
20 +# platform-specific mistralrs re-exports that require GPU SDKs.
21 +#
22 +# NOTE: onde's Cargo.toml gates mistralrs behind cfg(target_os = …) so on
23 +# the host OS (macOS/Linux) it will be pulled in automatically. If this
24 +# causes build issues in CI, consider adding a `ruby` feature to the onde
25 +# crate that disables the heavy deps.
26 +onde = { path = "../../../", default-features = false }
sdk/gem/ext/onde-ruby/extconf.rb new
+6
@@ -0,0 +1,6 @@
1 +# frozen_string_literal: true
2 +
3 +require "mkmf"
4 +require "rb_sys/mkmf"
5 +
6 +create_rust_makefile("onde/onde_ruby")
sdk/gem/ext/onde-ruby/src/lib.rs new
+272
@@ -0,0 +1,272 @@
1 +//! Ruby native extension for the Onde on-device inference engine.
2 +//!
3 +//! This crate uses [magnus](https://github.com/matsadler/magnus) to expose
4 +//! Onde's HuggingFace cache management, supported model metadata, and
5 +//! inference types to Ruby as the `Onde` module.
6 +//!
7 +//! ## Ruby usage
8 +//!
9 +//! ```ruby
10 +//! require "onde"
11 +//!
12 +//! # List models cached locally on disk.
13 +//! response = Onde.list_local_models
14 +//! response["models"].each do |m|
15 +//! puts "#{m["model_id"]} — #{m["size_display"]}"
16 +//! end
17 +//!
18 +//! # List all supported models (with download status).
19 +//! Onde.list_supported_models["models"].each do |m|
20 +//! status = m["is_downloaded"] ? "✓" : "✗"
21 +//! puts "[#{status}] #{m["name"]} (#{m["org"]}) — #{m["expected_size_display"]}"
22 +//! end
23 +//!
24 +//! # Delete a cached model.
25 +//! Onde.delete_model("bartowski/Qwen2.5-1.5B-Instruct-GGUF")
26 +//!
27 +//! # Inspect supported model IDs.
28 +//! Onde::SUPPORTED_MODELS # => ["black-forest-labs/FLUX.1-schnell", ...]
29 +//!
30 +//! # Access model metadata.
31 +//! Onde.model_info("bartowski/Qwen2.5-1.5B-Instruct-GGUF")
32 +//! # => { "id" => "bartowski/…", "name" => "Qwen 2.5 1.5B (GGUF)", … }
33 +//!
34 +//! # Sampling config helpers.
35 +//! Onde.default_sampling_config
36 +//! Onde.deterministic_sampling_config
37 +//! Onde.mobile_sampling_config
38 +//! ```
39 +
40 +use magnus::{function, prelude::*, Error, RHash, Ruby};
41 +
42 +use onde::hf_cache;
43 +use onde::inference::models::{SUPPORTED_MODELS, SUPPORTED_MODEL_INFO};
44 +use onde::inference::types::SamplingConfig;
45 +
46 +// ---------------------------------------------------------------------------
47 +// Helpers — convert Rust structs to Ruby hashes via serde_json
48 +// ---------------------------------------------------------------------------
49 +
50 +/// Serialize any `serde::Serialize` value into a Ruby Hash (or Array of
51 +/// Hashes) by round-tripping through serde_json. This keeps the binding
52 +/// layer thin — we don't need to define Ruby classes for every Onde struct.
53 +fn to_ruby_value<T: serde::Serialize>(ruby: &Ruby, value: &T) -> Result<magnus::Value, Error> {
54 + let json = serde_json::to_value(value).map_err(|e| {
55 + Error::new(
56 + ruby.exception_runtime_error(),
57 + format!("serialization error: {e}"),
58 + )
59 + })?;
60 + json_to_ruby(ruby, &json)
61 +}
62 +
63 +fn json_to_ruby(ruby: &Ruby, value: &serde_json::Value) -> Result<magnus::Value, Error> {
64 + match value {
65 + serde_json::Value::Null => Ok(ruby.qnil().as_value()),
66 + serde_json::Value::Bool(b) => {
67 + if *b {
68 + Ok(ruby.qtrue().as_value())
69 + } else {
70 + Ok(ruby.qfalse().as_value())
71 + }
72 + }
73 + serde_json::Value::Number(n) => {
74 + if let Some(i) = n.as_i64() {
75 + Ok(ruby.integer_from_i64(i).as_value())
76 + } else if let Some(f) = n.as_f64() {
77 + Ok(ruby.float_from_f64(f).as_value())
78 + } else {
79 + Ok(ruby.qnil().as_value())
80 + }
81 + }
82 + serde_json::Value::String(s) => Ok(ruby.str_new(s).as_value()),
83 + serde_json::Value::Array(arr) => {
84 + let ary = ruby.ary_new_capa(arr.len());
85 + for item in arr {
86 + ary.push(json_to_ruby(ruby, item)?)?;
87 + }
88 + Ok(ary.as_value())
89 + }
90 + serde_json::Value::Object(map) => {
91 + let hash = ruby.hash_new();
92 + for (k, v) in map {
93 + hash.aset(ruby.str_new(k), json_to_ruby(ruby, v)?)?;
94 + }
95 + Ok(hash.as_value())
96 + }
97 + }
98 +}
99 +
100 +// ---------------------------------------------------------------------------
101 +// Exported Ruby methods
102 +// ---------------------------------------------------------------------------
103 +
104 +/// `Onde.list_local_models` → Hash
105 +///
106 +/// Scans the local HuggingFace hub cache and returns all downloaded models
107 +/// that the inference engine supports.
108 +///
109 +/// Returns a Hash with keys: `"models"`, `"cache_path"`,
110 +/// `"total_size_bytes"`, `"total_size_display"`.
111 +fn list_local_models() -> Result<magnus::Value, Error> {
112 + let ruby = Ruby::get().expect("called outside Ruby");
113 + let response = hf_cache::list_local_hf_models();
114 + to_ruby_value(&ruby, &response)
115 +}
116 +
117 +/// `Onde.list_supported_models` → Hash
118 +///
119 +/// Returns all models the engine supports, together with flags indicating
120 +/// whether each one is fully downloaded, partially downloaded, or absent.
121 +///
122 +/// Returns a Hash with key `"models"` containing an Array of model Hashes.
123 +fn list_supported_models() -> Result<magnus::Value, Error> {
124 + let ruby = Ruby::get().expect("called outside Ruby");
125 + let response = hf_cache::list_supported_hf_models();
126 + to_ruby_value(&ruby, &response)
127 +}
128 +
129 +/// `Onde.delete_model(model_id)` → nil
130 +///
131 +/// Delete a locally cached HuggingFace model.
132 +/// `model_id` is the full identifier, e.g. `"black-forest-labs/FLUX.1-schnell"`.
133 +///
134 +/// Raises `RuntimeError` if the model is not found or deletion fails.
135 +fn delete_model(model_id: String) -> Result<magnus::Value, Error> {
136 + let ruby = Ruby::get().expect("called outside Ruby");
137 + hf_cache::delete_local_hf_model(model_id)
138 + .map_err(|e| Error::new(ruby.exception_runtime_error(), e))?;
139 + Ok(ruby.qnil().as_value())
140 +}
141 +
142 +/// `Onde.model_info(model_id)` → Hash or nil
143 +///
144 +/// Look up rich metadata for a supported model by its ID.
145 +/// Returns `nil` if the model ID is not in the supported list.
146 +fn model_info(model_id: String) -> Result<magnus::Value, Error> {
147 + let ruby = Ruby::get().expect("called outside Ruby");
148 +
149 + let info = SUPPORTED_MODEL_INFO.iter().find(|i| i.id == model_id);
150 +
151 + match info {
152 + None => Ok(ruby.qnil().as_value()),
153 + Some(i) => {
154 + let hash = ruby.hash_new();
155 + hash.aset(ruby.str_new("id"), ruby.str_new(i.id))?;
156 + hash.aset(ruby.str_new("name"), ruby.str_new(i.name))?;
157 + hash.aset(ruby.str_new("org"), ruby.str_new(i.org))?;
158 + hash.aset(ruby.str_new("description"), ruby.str_new(i.description))?;
159 + hash.aset(
160 + ruby.str_new("expected_size_bytes"),
161 + ruby.integer_from_u64(i.expected_size_bytes),
162 + )?;
163 + Ok(hash.as_value())
164 + }
165 + }
166 +}
167 +
168 +/// `Onde.supported_model_ids` → Array of String
169 +///
170 +/// Returns the list of all supported model IDs.
171 +fn supported_model_ids() -> Result<magnus::Value, Error> {
172 + let ruby = Ruby::get().expect("called outside Ruby");
173 + let ary = ruby.ary_new_capa(SUPPORTED_MODELS.len());
174 + for id in SUPPORTED_MODELS {
175 + ary.push(ruby.str_new(id))?;
176 + }
177 + Ok(ary.as_value())
178 +}
179 +
180 +/// `Onde.default_sampling_config` → Hash
181 +fn default_sampling_config() -> Result<magnus::Value, Error> {
182 + let ruby = Ruby::get().expect("called outside Ruby");
183 + to_ruby_value(&ruby, &SamplingConfig::default())
184 +}
185 +
186 +/// `Onde.deterministic_sampling_config` → Hash
187 +fn deterministic_sampling_config() -> Result<magnus::Value, Error> {
188 + let ruby = Ruby::get().expect("called outside Ruby");
189 + to_ruby_value(&ruby, &SamplingConfig::deterministic())
190 +}
191 +
192 +/// `Onde.mobile_sampling_config` → Hash
193 +fn mobile_sampling_config() -> Result<magnus::Value, Error> {
194 + let ruby = Ruby::get().expect("called outside Ruby");
195 + to_ruby_value(&ruby, &SamplingConfig::mobile())
196 +}
197 +
198 +/// `Onde.cache_path` → String or nil
199 +///
200 +/// Returns the resolved HuggingFace cache directory path, or nil if it
201 +/// cannot be determined (e.g. `$HOME` is unset).
202 +fn cache_path() -> Result<magnus::Value, Error> {
203 + let ruby = Ruby::get().expect("called outside Ruby");
204 + let response = hf_cache::list_local_hf_models();
205 + if response.cache_path.is_empty() {
206 + Ok(ruby.qnil().as_value())
207 + } else {
208 + Ok(ruby.str_new(&response.cache_path).as_value())
209 + }
210 +}
211 +
212 +// ---------------------------------------------------------------------------
213 +// Init — called by Ruby when `require "onde/onde"` loads the shared library
214 +// ---------------------------------------------------------------------------
215 +
216 +#[magnus::init]
217 +fn init(ruby: &Ruby) -> Result<(), Error> {
218 + let module = ruby.define_module("Onde")?;
219 +
220 + // -- Singleton methods ----------------------------------------------------
221 + module.define_singleton_method("list_local_models", function!(list_local_models, 0))?;
222 + module.define_singleton_method("list_supported_models", function!(list_supported_models, 0))?;
223 + module.define_singleton_method("delete_model", function!(delete_model, 1))?;
224 + module.define_singleton_method("model_info", function!(model_info, 1))?;
225 + module.define_singleton_method("supported_model_ids", function!(supported_model_ids, 0))?;
226 + module.define_singleton_method(
227 + "default_sampling_config",
228 + function!(default_sampling_config, 0),
229 + )?;
230 + module.define_singleton_method(
231 + "deterministic_sampling_config",
232 + function!(deterministic_sampling_config, 0),
233 + )?;
234 + module.define_singleton_method(
235 + "mobile_sampling_config",
236 + function!(mobile_sampling_config, 0),
237 + )?;
238 + module.define_singleton_method("cache_path", function!(cache_path, 0))?;
239 +
240 + // -- Constants ------------------------------------------------------------
241 +
242 + // Onde::NATIVE_VERSION (Rust crate version for parity checks).
243 + module.const_set("NATIVE_VERSION", ruby.str_new(env!("CARGO_PKG_VERSION")))?;
244 +
245 + // Onde::SUPPORTED_MODELS — frozen Array of model ID strings.
246 + let model_ids = ruby.ary_new_capa(SUPPORTED_MODELS.len());
247 + for id in SUPPORTED_MODELS {
248 + model_ids.push(ruby.str_new(id))?;
249 + }
250 + model_ids.freeze();
251 + module.const_set("SUPPORTED_MODELS", model_ids)?;
252 +
253 + // Onde::SUPPORTED_MODEL_INFO — frozen Array of frozen Hashes.
254 + let info_ary = ruby.ary_new_capa(SUPPORTED_MODEL_INFO.len());
255 + for info in SUPPORTED_MODEL_INFO {
256 + let hash: RHash = ruby.hash_new();
257 + hash.aset(ruby.str_new("id"), ruby.str_new(info.id))?;
258 + hash.aset(ruby.str_new("name"), ruby.str_new(info.name))?;
259 + hash.aset(ruby.str_new("org"), ruby.str_new(info.org))?;
260 + hash.aset(ruby.str_new("description"), ruby.str_new(info.description))?;
261 + hash.aset(
262 + ruby.str_new("expected_size_bytes"),
263 + ruby.integer_from_u64(info.expected_size_bytes),
264 + )?;
265 + hash.freeze();
266 + info_ary.push(hash)?;
267 + }
268 + info_ary.freeze();
269 + module.const_set("SUPPORTED_MODEL_INFO", info_ary)?;
270 +
271 + Ok(())
272 +}
sdk/gem/lib/onde.rb new
+8
@@ -0,0 +1,8 @@
1 +# frozen_string_literal: true
2 +
3 +require_relative 'onde/version'
4 +require_relative 'onde/onde_ruby'
5 +
6 +module Onde
7 + class Error < StandardError; end
8 +end
sdk/gem/lib/onde/version.rb new
+5
@@ -0,0 +1,5 @@
1 +# frozen_string_literal: true
2 +
3 +module Onde
4 + VERSION = '0.1.0'
5 +end
sdk/gem/onde.gemspec new
+49
@@ -0,0 +1,49 @@
1 +# frozen_string_literal: true
2 +
3 +require_relative 'lib/onde/version'
4 +
5 +Gem::Specification.new do |spec|
6 + spec.name = 'onde-inference'
7 + spec.version = Onde::VERSION
8 + spec.authors = ['Seto Elkahfi']
9 + spec.email = ['setoelkahfi@gmail.com']
10 +
11 + spec.summary = 'On-device AI inference for Ruby — powered by Rust.'
12 + spec.description = 'Ruby bindings for the Onde inference engine. ' \
13 + 'Run LLMs and speech-to-text locally with automatic ' \
14 + 'HuggingFace model management, cache inspection, and GPU acceleration.'
15 + spec.homepage = 'https://ondeinference.com'
16 + spec.license = 'MIT'
17 + spec.required_ruby_version = '>= 3.0.0'
18 + spec.required_rubygems_version = '>= 3.3.11'
19 +
20 + spec.metadata['homepage_uri'] = spec.homepage
21 + spec.metadata['source_code_uri'] = 'https://github.com/ondeinference/onde'
22 + spec.metadata['changelog_uri'] = 'https://github.com/ondeinference/onde/blob/main/CHANGELOG.md'
23 + # Tell rb_sys / RbSys::ExtensionTask the actual Rust crate name so it
24 + # resolves gem/ext/onde-ruby/Cargo.toml instead of walking up to the
25 + # parent lib/crates/onde/Cargo.toml (name = "onde").
26 + spec.metadata['cargo_crate_name'] = 'onde-ruby'
27 +
28 + # Explicit file list — git ls-files does not work reliably in monorepo
29 + # subdirectories that may be untracked or partially ignored.
30 + # We exclude target/ directories (Cargo build artifacts), compiled native
31 + # extensions (.bundle, .so, .dylib, .dll, .o, .a), and tmp/ build staging.
32 + spec.files = Dir.chdir(__dir__) do
33 + Dir.glob('{lib,ext}/**/*').select { |f| File.file?(f) }
34 + .reject { |f| f.include?('/target/') }
35 + .reject { |f| f.match?(/\.(bundle|so|dylib|dll|o|a|dSYM)$/) }
36 + .reject { |f| f.start_with?('tmp/') } +
37 + %w[
38 + Cargo.toml
39 + Cargo.lock
40 + README.md
41 + rust-toolchain.toml
42 + ]
43 + end.select { |f| File.exist?(File.join(__dir__, f)) }
44 +
45 + spec.bindir = 'exe'
46 + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
47 + spec.require_paths = ['lib']
48 + spec.extensions = ['ext/onde-ruby/Cargo.toml']
49 +end
sdk/gem/rust-toolchain.toml new
+2
@@ -0,0 +1,2 @@
1 +[toolchain]
2 +channel = "1.92"
sdk/kotlin/.gitignore new
+29
@@ -0,0 +1,29 @@
1 +# Gradle
2 +.gradle/
3 +build/
4 +!gradle/wrapper/gradle-wrapper.jar
5 +
6 +# IDE
7 +.idea/
8 +*.iml
9 +local.properties
10 +
11 +# Native shared libraries — these are build artifacts produced by
12 +# `build-kotlin.sh` and should not be committed to version control.
13 +# Each developer / CI run cross-compiles them from the Rust source.
14 +onde/src/main/jniLibs/**/*.so
15 +
16 +# UniFFI-generated Kotlin source — regenerated by `build-kotlin.sh`.
17 +# Keeping it out of VCS avoids stale-binding bugs after Rust API changes.
18 +onde/src/main/kotlin/com/ondeinference/onde/onde.kt
19 +
20 +# Gradle wrapper jar (use `gradle wrapper` to regenerate)
21 +# Uncomment the next line if you prefer to commit the wrapper jar:
22 +# !gradle/wrapper/gradle-wrapper.jar
23 +
24 +# macOS
25 +.DS_Store
26 +
27 +# Android Studio / IntelliJ
28 +captures/
29 +*.hprof
sdk/kotlin/README.md new
+432
@@ -0,0 +1,432 @@
1 +# Onde — Kotlin (Android) Library
2 +
3 +Kotlin bindings for the [Onde](https://ondeinference.com) on-device inference engine, generated via [UniFFI](https://github.com/mozilla/uniffi-rs).
4 +
5 +This library provides Android apps with:
6 +
7 +- **LLM chat inference** — load GGUF-quantized models (Qwen 2.5) and run multi-turn conversations entirely on-device.
8 +- **Streaming generation** — token-by-token callbacks for real-time UI updates.
9 +- **Whisper speech-to-text** — transcribe audio files and raw PCM samples using whisper.cpp (feature-gated behind `whisper`).
10 +- **HuggingFace Hub integration** — download, cache, inspect, and manage models from HuggingFace.
11 +
12 +All inference runs locally on the device CPU (ARM NEON). No network connection is required after the model is downloaded.
13 +
14 +## Prerequisites
15 +
16 +| Tool | Version | Notes |
17 +|------|---------|-------|
18 +| Rust | stable (1.80+) | `rustup update stable` |
19 +| Android NDK | r27+ | Via Android Studio SDK Manager |
20 +| Android SDK | compileSdk 36 | API 24+ (minSdk) |
21 +| Cargo | latest | Ships with Rust |
22 +
23 +Install the Rust Android cross-compilation targets:
24 +
25 +```sh
26 +rustup target add \
27 + aarch64-linux-android \
28 + armv7-linux-androideabi \
29 + x86_64-linux-android \
30 + i686-linux-android
31 +```
32 +
33 +Set the NDK path (or let the build script auto-detect it):
34 +
35 +```sh
36 +export ANDROID_NDK_HOME="$HOME/Library/Android/sdk/ndk/27.2.12479018"
37 +# — or —
38 +export ANDROID_HOME="$HOME/Library/Android/sdk" # NDK auto-detected under ndk/
39 +```
40 +
41 +## Building
42 +
43 +From the `onde/` crate root:
44 +
45 +```sh
46 +# Full release build for all four Android ABIs + Kotlin codegen
47 +./build-kotlin.sh
48 +
49 +# Debug build, arm64 only (faster iteration)
50 +./build-kotlin.sh --debug --target aarch64-linux-android
51 +
52 +# Regenerate Kotlin source without recompiling Rust
53 +./build-kotlin.sh --generate-only
54 +
55 +# Build with the Whisper feature enabled
56 +ONDE_FEATURES=whisper ./build-kotlin.sh
57 +```
58 +
59 +The script performs three steps:
60 +
61 +1. **Builds `uniffi-bindgen`** — a host binary that reads UniFFI metadata from the compiled library.
62 +2. **Cross-compiles `libonde.so`** — for each Android target (`arm64-v8a`, `armeabi-v7a`, `x86_64`, `x86`).
63 +3. **Generates Kotlin source** — runs `uniffi-bindgen generate --language kotlin` to produce `onde.kt` in the library's source set.
64 +
65 +After a successful build, the directory structure looks like:
66 +
67 +```
68 +kotlin/
69 +├── onde/
70 +│ └── src/main/
71 +│ ├── jniLibs/
72 +│ │ ├── arm64-v8a/libonde.so
73 +│ │ ├── armeabi-v7a/libonde.so
74 +│ │ ├── x86_64/libonde.so
75 +│ │ └── x86/libonde.so
76 +│ └── kotlin/com/ondeinference/onde/
77 +│ └── onde.kt ← generated UniFFI bindings
78 +├── build.gradle.kts
79 +├── settings.gradle.kts
80 +└── ...
81 +```
82 +
83 +## Integration
84 +
85 +### Option A: Composite build (recommended for monorepo)
86 +
87 +In your app's `settings.gradle.kts`:
88 +
89 +```kotlin
90 +includeBuild("path/to/onde/kotlin") {
91 + dependencySubstitution {
92 + substitute(module("com.ondeinference:onde")).using(project(":onde"))
93 + }
94 +}
95 +```
96 +
97 +Then in your app's `build.gradle.kts`:
98 +
99 +```kotlin
100 +dependencies {
101 + implementation("com.ondeinference:onde")
102 +}
103 +```
104 +
105 +### Option B: Direct project dependency
106 +
107 +In your app's `settings.gradle.kts`:
108 +
109 +```kotlin
110 +include(":onde")
111 +project(":onde").projectDir = file("path/to/onde/kotlin/onde")
112 +```
113 +
114 +Then in your app's `build.gradle.kts`:
115 +
116 +```kotlin
117 +dependencies {
118 + implementation(project(":onde"))
119 +}
120 +```
121 +
122 +### Option C: Publish as AAR
123 +
124 +```sh
125 +cd kotlin
126 +./gradlew :onde:assembleRelease
127 +```
128 +
129 +The AAR is produced at `onde/build/outputs/aar/onde-release.aar`. Publish it to your local Maven repository or a private artifact server.
130 +
131 +## API Usage
132 +
133 +### Chat Inference
134 +
135 +```kotlin
136 +import com.ondeinference.onde.*
137 +import kotlinx.coroutines.*
138 +
139 +// Create an engine instance.
140 +val engine = OndeChatEngine()
141 +
142 +// Load the platform-appropriate default model (Qwen 2.5 1.5B on Android).
143 +val loadTimeSecs = engine.loadDefaultModel(
144 + systemPrompt = "You are a helpful assistant.",
145 + sampling = null // use defaults
146 +)
147 +println("Model loaded in ${loadTimeSecs}s")
148 +
149 +// Multi-turn chat — history is managed automatically.
150 +val reply = engine.sendMessage("What is Kotlin?")
151 +println(reply.text) // "Kotlin is a modern programming language..."
152 +println(reply.durationDisplay) // "4.2s"
153 +
154 +// One-shot generation (does NOT modify conversation history).
155 +val enhanced = engine.generate(
156 + messages = listOf(userMessage("Expand: a cat in space")),
157 + sampling = deterministicSamplingConfig()
158 +)
159 +println(enhanced.text)
160 +
161 +// Check engine status.
162 +val info = engine.info()
163 +println("Status: ${info.status}, History: ${info.historyLength} turns")
164 +
165 +// Conversation management.
166 +val history: List<ChatMessage> = engine.history()
167 +engine.clearHistory()
168 +engine.setSystemPrompt("You are a pirate.")
169 +
170 +// Cleanup — frees model memory.
171 +engine.unloadModel()
172 +```
173 +
174 +### Streaming Inference
175 +
176 +```kotlin
177 +import com.ondeinference.onde.*
178 +
179 +// Implement the callback interface.
180 +class MyStreamHandler : StreamChunkListener {
181 + private val buffer = StringBuilder()
182 +
183 + override fun onChunk(chunk: StreamChunk): Boolean {
184 + buffer.append(chunk.delta)
185 + print(chunk.delta) // Real-time token output
186 +
187 + // Return true to continue, false to cancel early.
188 + return !chunk.done
189 + }
190 +}
191 +
192 +// Stream through the free function (UniFFI 0.31 callback_interface pattern).
193 +streamChatMessage(
194 + engine = engine,
195 + message = "Tell me a story about a brave robot.",
196 + listener = MyStreamHandler()
197 +)
198 +```
199 +
200 +### Model Configuration
201 +
202 +```kotlin
203 +import com.ondeinference.onde.*
204 +
205 +// Platform default (Qwen 2.5 1.5B on Android, 3B on desktop).
206 +val defaultConfig = defaultModelConfig()
207 +
208 +// Explicit model configs.
209 +val small = qwen251_5bConfig() // ~941 MB, ideal for mobile
210 +val medium = qwen253bConfig() // ~1.93 GB, for devices with more RAM
211 +
212 +// Custom config.
213 +val custom = GgufModelConfig(
214 + modelId = "bartowski/Qwen2.5-1.5B-Instruct-GGUF",
215 + files = listOf("Qwen2.5-1.5B-Instruct-Q4_K_M.gguf"),
216 + tokModelId = "Qwen/Qwen2.5-1.5B-Instruct", // required on Android
217 + displayName = "Qwen 2.5 1.5B",
218 + approxMemory = "~941 MB (GGUF Q4_K_M)"
219 +)
220 +
221 +engine.loadGgufModel(
222 + config = custom,
223 + systemPrompt = "You are helpful.",
224 + sampling = mobileSamplingConfig() // conservative defaults for mobile
225 +)
226 +```
227 +
228 +### Sampling Configuration
229 +
230 +```kotlin
231 +import com.ondeinference.onde.*
232 +
233 +// Creative chat defaults (temperature=0.7, top_p=0.95, max_tokens=512).
234 +val creative = defaultSamplingConfig()
235 +
236 +// Deterministic / greedy (temperature=0.0).
237 +val greedy = deterministicSamplingConfig()
238 +
239 +// Mobile-optimised (max_tokens=128 for faster response on CPU).
240 +val mobile = mobileSamplingConfig()
241 +
242 +// Fully custom.
243 +val custom = SamplingConfig(
244 + temperature = 0.9,
245 + topP = 0.95,
246 + topK = 50u,
247 + minP = null,
248 + maxTokens = 256u,
249 + frequencyPenalty = 0.1f,
250 + presencePenalty = 0.1f
251 +)
252 +
253 +engine.setSampling(custom)
254 +```
255 +
256 +### Whisper Speech-to-Text (requires `whisper` feature)
257 +
258 +```kotlin
259 +import com.ondeinference.onde.*
260 +
261 +// Create and load a Whisper engine.
262 +val whisper = OndeWhisperEngine()
263 +
264 +// Download or find a cached model.
265 +val modelPath = findOrDownloadWhisperModelFfi(
266 + modelDir = "/data/user/0/com.myapp/files/whisper",
267 + modelName = null, // platform default (ggml-base.bin on Android)
268 + listener = object : WhisperProgressListener {
269 + override fun onProgress(progress: WhisperModelDownloadProgress) {
270 + println("${progress.downloadedDisplay} / ${progress.totalDisplay}")
271 + }
272 + },
273 + appDataDir = context.filesDir.absolutePath
274 +)
275 +
276 +whisper.loadModel(modelPath)
277 +
278 +// Transcribe from a file.
279 +val result = whisper.transcribeFile(
280 + path = "/path/to/audio.wav",
281 + language = "en" // or null for auto-detect
282 +)
283 +println(result.text)
284 +result.segments.forEach { seg ->
285 + println("[${seg.startSecs}s - ${seg.endSecs}s] ${seg.text}")
286 +}
287 +
288 +// Transcribe from raw PCM samples.
289 +val samples: List<Float> = readWavSamplesFfi("/path/to/audio.wav")
290 +val result2 = whisper.transcribeSamples(samples, language = null)
291 +println(result2.text)
292 +```
293 +
294 +### Helper Functions
295 +
296 +```kotlin
297 +import com.ondeinference.onde.*
298 +
299 +// Message constructors.
300 +val sys = systemMessage("You are helpful.")
301 +val usr = userMessage("Hello!")
302 +val ast = assistantMessage("Hi there!")
303 +
304 +// Platform default Whisper model name.
305 +val whisperModel = defaultModelForPlatform() // "ggml-base.bin" on Android
306 +
307 +// All available Whisper model candidates.
308 +val candidates = whisperModelCandidates()
309 +// ["ggml-large-v3-turbo.bin", "ggml-large-v3.bin", ..., "ggml-tiny.en.bin"]
310 +```
311 +
312 +## Error Handling
313 +
314 +All fallible operations throw typed exceptions generated from the Rust error enums:
315 +
316 +```kotlin
317 +try {
318 + engine.sendMessage("Hello")
319 +} catch (e: InferenceError.NoModelLoaded) {
320 + // No model loaded — call loadGgufModel() or loadDefaultModel() first.
321 +} catch (e: InferenceError.Inference) {
322 + // Inference failed: ${e.reason}
323 +} catch (e: InferenceError.ModelBuild) {
324 + // Failed to build model: ${e.reason}
325 +} catch (e: InferenceError.AlreadyLoaded) {
326 + // Model is already loaded: ${e.modelName}
327 +} catch (e: InferenceError.Cancelled) {
328 + // Model loading was cancelled.
329 +} catch (e: InferenceError.Other) {
330 + // Generic error: ${e.reason}
331 +}
332 +```
333 +
334 +Whisper operations throw `WhisperError` variants:
335 +
336 +```kotlin
337 +try {
338 + whisper.transcribeFile(path, language)
339 +} catch (e: WhisperError.ModelNotLoaded) { ... }
340 + catch (e: WhisperError.ModelLoadFailed) { ... }
341 + catch (e: WhisperError.TranscriptionFailed) { ... }
342 + catch (e: WhisperError.DownloadFailed) { ... }
343 + catch (e: WhisperError.Io) { ... }
344 +```
345 +
346 +## Threading Model
347 +
348 +- **`OndeChatEngine`** methods are `suspend` functions — call them from a coroutine scope (e.g. `viewModelScope`, `lifecycleScope`).
349 +- **`OndeWhisperEngine`** methods are synchronous (blocking). Call them from `Dispatchers.IO` or a background thread:
350 +
351 + ```kotlin
352 + withContext(Dispatchers.IO) {
353 + whisper.loadModel(path)
354 + val result = whisper.transcribeFile(audioPath, "en")
355 + }
356 + ```
357 +
358 +- The underlying Rust engine is thread-safe (`Send + Sync`). Multiple coroutines can safely share a single `OndeChatEngine` instance.
359 +
360 +## Project Structure
361 +
362 +```
363 +onde/
364 +├── build-kotlin.sh # Build script (cross-compile + bindgen)
365 +├── uniffi.toml # UniFFI config (Kotlin package name)
366 +├── uniffi-bindgen/ # Host binary for generating bindings
367 +│ ├── Cargo.toml
368 +│ └── uniffi-bindgen.rs
369 +├── kotlin/ # Android library project (Gradle)
370 +│ ├── build.gradle.kts # Root Gradle build
371 +│ ├── settings.gradle.kts
372 +│ ├── gradle.properties
373 +│ ├── README.md # ← You are here
374 +│ └── onde/ # Library module
375 +│ ├── build.gradle.kts
376 +│ ├── proguard-rules.pro
377 +│ ├── consumer-rules.pro
378 +│ └── src/main/
379 +│ ├── AndroidManifest.xml
380 +│ ├── jniLibs/ # Native .so files (build artifact)
381 +│ └── kotlin/com/ondeinference/onde/
382 +│ └── onde.kt # Generated UniFFI Kotlin bindings
383 +├── src/ # Rust source (the actual engine)
384 +│ ├── lib.rs
385 +│ ├── hf_cache.rs
386 +│ ├── whisper.rs
387 +│ └── inference/
388 +│ ├── engine.rs
389 +│ ├── ffi.rs # UniFFI-exported wrappers
390 +│ ├── models.rs
391 +│ ├── token.rs
392 +│ └── types.rs # Records, Enums, Errors
393 +└── Cargo.toml
394 +```
395 +
396 +## Troubleshooting
397 +
398 +### `ANDROID_NDK_HOME not found`
399 +
400 +Set the environment variable to your NDK installation:
401 +
402 +```sh
403 +export ANDROID_NDK_HOME="$HOME/Library/Android/sdk/ndk/27.2.12479018"
404 +```
405 +
406 +Or install the NDK via Android Studio → SDK Manager → SDK Tools → NDK (Side by side).
407 +
408 +### `linker not found` during cross-compilation
409 +
410 +Ensure the NDK toolchain binaries are present:
411 +
412 +```sh
413 +ls $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android24-clang
414 +```
415 +
416 +If missing, your NDK installation may be incomplete. Reinstall it.
417 +
418 +### `UnsatisfiedLinkError: libonde.so` at runtime
419 +
420 +The `.so` file is missing from the APK's `jniLibs` for the device's ABI. Verify:
421 +
422 +1. `build-kotlin.sh` completed successfully for the target ABI.
423 +2. The `.so` exists at `onde/src/main/jniLibs/<abi>/libonde.so`.
424 +3. Your app's `build.gradle.kts` doesn't filter out the ABI via `ndk { abiFilters ... }`.
425 +
426 +### `uniffi-bindgen` version mismatch
427 +
428 +The `uniffi` version in `uniffi-bindgen/Cargo.toml` **must** exactly match the version in the main `onde` crate's `Cargo.toml` (`=0.31.0`). A mismatch causes a runtime panic with a checksum error.
429 +
430 +## License
431 +
432 +MIT OR Apache-2.0 — same as the `onde` crate.
sdk/kotlin/build.gradle.kts new
+7
@@ -0,0 +1,7 @@
1 +// Root build.gradle.kts for the Onde Kotlin library project.
2 +// This file configures the Gradle build system and declares plugin versions.
3 +
4 +plugins {
5 + id("com.android.library") version "8.7.3" apply false
6 + id("org.jetbrains.kotlin.android") version "2.0.21" apply false
7 +}
sdk/kotlin/gradle.properties new
+4
@@ -0,0 +1,4 @@
1 +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
2 +android.useAndroidX=true
3 +kotlin.code.style=official
4 +android.nonTransitiveRClass=true
sdk/kotlin/gradle/wrapper/gradle-wrapper.properties new
+7
@@ -0,0 +1,7 @@
1 +distributionBase=GRADLE_USER_HOME
2 +distributionPath=wrapper/dists
3 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
4 +networkTimeout=10000
5 +validateDistributionUrl=true
6 +zipStoreBase=GRADLE_USER_HOME
7 +zipStorePath=wrapper/dists
sdk/kotlin/onde/build.gradle.kts new
+208
@@ -0,0 +1,208 @@
1 +plugins {
2 + id("com.android.library")
3 + id("org.jetbrains.kotlin.android")
4 + `maven-publish`
5 + signing
6 +}
7 +
8 +// ── Coordinates ──────────────────────────────────────────────────────────────
9 +// Read from gradle.properties or fall back to defaults.
10 +val libGroupId: String = findProperty("onde.groupId") as? String ?: "com.ondeinference"
11 +val libArtifactId: String = findProperty("onde.artifactId") as? String ?: "onde"
12 +val libVersion: String = findProperty("onde.version") as? String ?: "0.1.0"
13 +
14 +group = libGroupId
15 +version = libVersion
16 +
17 +android {
18 + namespace = "com.ondeinference.onde"
19 + compileSdk = 36
20 +
21 + defaultConfig {
22 + minSdk = 24
23 +
24 + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
25 + consumerProguardFiles("consumer-rules.pro")
26 +
27 + aarMetadata {
28 + minCompileSdk = 24
29 + }
30 + }
31 +
32 + buildTypes {
33 + release {
34 + isMinifyEnabled = false
35 + proguardFiles(
36 + getDefaultProguardFile("proguard-android-optimize.txt"),
37 + "proguard-rules.pro"
38 + )
39 + }
40 + }
41 +
42 + compileOptions {
43 + sourceCompatibility = JavaVersion.VERSION_1_8
44 + targetCompatibility = JavaVersion.VERSION_1_8
45 + }
46 +
47 + kotlinOptions {
48 + jvmTarget = "1.8"
49 + }
50 +
51 + // The generated Kotlin source from UniFFI lives alongside hand-written
52 + // Kotlin code. Point the source set at the generated directory so
53 + // Gradle picks it up automatically after `build-kotlin.sh` runs.
54 + sourceSets {
55 + getByName("main") {
56 + java.srcDir("src/main/kotlin")
57 + }
58 + }
59 +
60 + publishing {
61 + singleVariant("release") {
62 + withSourcesJar()
63 + }
64 + }
65 +}
66 +
67 +dependencies {
68 + // JNA is required by UniFFI-generated Kotlin code to call into the
69 + // native shared library (libonde.so) via JNI.
70 + implementation("net.java.dev.jna:jna:5.14.0@aar")
71 +
72 + // Kotlin coroutines — the generated async bindings use
73 + // kotlinx.coroutines suspend functions under the hood.
74 + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
75 + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
76 +
77 + // AndroidX core (transitive, but explicit for clarity)
78 + implementation("androidx.annotation:annotation:1.9.1")
79 +
80 + // Test dependencies
81 + testImplementation("junit:junit:4.13.2")
82 + androidTestImplementation("androidx.test.ext:junit:1.2.1")
83 + androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
84 +}
85 +
86 +// ── Maven Publishing ─────────────────────────────────────────────────────────
87 +
88 +afterEvaluate {
89 + publishing {
90 + publications {
91 + create<MavenPublication>("release") {
92 + from(components["release"])
93 +
94 + groupId = libGroupId
95 + artifactId = libArtifactId
96 + version = libVersion
97 +
98 + pom {
99 + name.set("Onde")
100 + description.set(
101 + "On-device inference for Android — run LLMs, diffusion models, " +
102 + "and speech-to-text locally with automatic model management."
103 + )
104 + url.set("https://github.com/ondeinference/onde")
105 + inceptionYear.set("2025")
106 +
107 + licenses {
108 + license {
109 + name.set("MIT License")
110 + url.set("https://opensource.org/licenses/MIT")
111 + distribution.set("repo")
112 + }
113 + license {
114 + name.set("Apache License 2.0")
115 + url.set("https://www.apache.org/licenses/LICENSE-2.0")
116 + distribution.set("repo")
117 + }
118 + }
119 +
120 + developers {
121 + developer {
122 + id.set("ondeinference")
123 + name.set("Onde Inference")
124 + url.set("https://ondeinference.com")
125 + }
126 + }
127 +
128 + scm {
129 + url.set("https://github.com/ondeinference/onde")
130 + connection.set("scm:git:git://github.com/ondeinference/onde.git")
131 + developerConnection.set("scm:git:ssh://git@github.com/ondeinference/onde.git")
132 + }
133 +
134 + issueManagement {
135 + system.set("GitHub Issues")
136 + url.set("https://github.com/ondeinference/onde/issues")
137 + }
138 + }
139 + }
140 + }
141 +
142 + repositories {
143 + // ── Local Maven (~/.m2/repository) ───────────────────────────────
144 + // Publish: ./gradlew :onde:publishReleasePublicationToMavenLocal
145 + mavenLocal()
146 +
147 + // ── Maven Central (Sonatype OSSRH) ──────────────────────────────
148 + // Publish: ./gradlew :onde:publishReleasePublicationToSonatypeRepository
149 + //
150 + // Required properties (in ~/.gradle/gradle.properties or passed via -P):
151 + // sonatypeUsername
152 + // sonatypePassword
153 + maven {
154 + name = "Sonatype"
155 + val releasesUrl = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
156 + val snapshotsUrl = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
157 + url = if (libVersion.endsWith("-SNAPSHOT")) snapshotsUrl else releasesUrl
158 +
159 + credentials {
160 + username = findProperty("sonatypeUsername") as? String ?: System.getenv("SONATYPE_USERNAME") ?: ""
161 + password = findProperty("sonatypePassword") as? String ?: System.getenv("SONATYPE_PASSWORD") ?: ""
162 + }
163 + }
164 +
165 + // ── GitHub Packages ──────────────────────────────────────────────
166 + // Publish: ./gradlew :onde:publishReleasePublicationToGitHubPackagesRepository
167 + //
168 + // Required properties:
169 + // gpr.user — GitHub username
170 + // gpr.token — GitHub personal access token (write:packages)
171 + maven {
172 + name = "GitHubPackages"
173 + url = uri("https://maven.pkg.github.com/ondeinference/onde")
174 +
175 + credentials {
176 + username = findProperty("gpr.user") as? String ?: System.getenv("GITHUB_ACTOR") ?: ""
177 + password = findProperty("gpr.token") as? String ?: System.getenv("GITHUB_TOKEN") ?: ""
178 + }
179 + }
180 + }
181 + }
182 +
183 + // ── GPG Signing ──────────────────────────────────────────────────────────
184 + // Required for Maven Central. Skipped entirely when signing credentials
185 + // are absent (e.g. local development, CI dry-runs, mavenLocal publishes).
186 + //
187 + // Configure in ~/.gradle/gradle.properties:
188 + // signing.keyId=AABBCCDD (last 8 chars of your GPG key ID)
189 + // signing.password=<passphrase>
190 + // signing.secretKeyRingFile=/path/to/secring.gpg
191 + //
192 + // Or use in-memory key (CI-friendly):
193 + // ORG_GRADLE_PROJECT_signingKey=<ascii-armored-key>
194 + // ORG_GRADLE_PROJECT_signingPassword=<passphrase>
195 + val signingKey: String? = findProperty("signingKey") as? String ?: System.getenv("GPG_SIGNING_KEY")
196 + val signingPassword: String? = findProperty("signingPassword") as? String ?: System.getenv("GPG_SIGNING_PASSWORD")
197 + val hasKeyRingFile = findProperty("signing.secretKeyRingFile") != null
198 + val hasSigningCredentials = (signingKey != null && signingPassword != null) || hasKeyRingFile
199 +
200 + if (hasSigningCredentials) {
201 + signing {
202 + if (signingKey != null && signingPassword != null) {
203 + useInMemoryPgpKeys(signingKey, signingPassword)
204 + }
205 + sign(publishing.publications["release"])
206 + }
207 + }
208 +}
sdk/kotlin/onde/consumer-rules.pro new
+37
@@ -0,0 +1,37 @@
1 +# ──────────────────────────────────────────────────────────────────────────────
2 +# Consumer ProGuard / R8 rules for the Onde AAR
3 +#
4 +# These rules are automatically applied to any app that depends on this library
5 +# via the AAR's consumer-rules mechanism. They ensure that JNA, the UniFFI
6 +# generated bindings, and the native bridge survive minification and name
7 +# mangling in the consuming app's release build.
8 +# ──────────────────────────────────────────────────────────────────────────────
9 +
10 +# ── JNA ───────────────────────────────────────────────────────────────────────
11 +# JNA resolves native function pointers and struct layouts via reflection.
12 +# Any renaming or stripping breaks the JNI bridge at runtime.
13 +-keep class com.sun.jna.** { *; }
14 +-keep class * implements com.sun.jna.** { *; }
15 +-keep class * implements com.sun.jna.Callback { *; }
16 +-keepclassmembers class * extends com.sun.jna.Structure {
17 + <fields>;
18 +}
19 +-dontwarn com.sun.jna.**
20 +
21 +# ── UniFFI-generated bindings ─────────────────────────────────────────────────
22 +# The generated Kotlin code in com.ondeinference.onde contains JNA Library
23 +# interfaces, Structure subclasses, callback interfaces, and companion objects
24 +# with @JvmStatic native method declarations — all resolved by name or via
25 +# reflection at runtime.
26 +-keep class com.ondeinference.onde.** { *; }
27 +-keepclassmembers class com.ondeinference.onde.** { *; }
28 +
29 +# ── Kotlin coroutines ─────────────────────────────────────────────────────────
30 +# UniFFI async exports generate suspend functions that rely on coroutine
31 +# continuation internals.
32 +-keepclassmembers class kotlin.coroutines.** { *; }
33 +-dontwarn kotlinx.coroutines.**
34 +
35 +# ── General safety ────────────────────────────────────────────────────────────
36 +-dontwarn javax.annotation.**
37 +-dontwarn kotlin.annotations.jvm.**
sdk/kotlin/onde/proguard-rules.pro new
+43
@@ -0,0 +1,43 @@
1 +# ──────────────────────────────────────────────────────────────────────────────
2 +# ProGuard / R8 rules for the Onde Kotlin library (UniFFI + JNA)
3 +# ──────────────────────────────────────────────────────────────────────────────
4 +
5 +# ── JNA ───────────────────────────────────────────────────────────────────────
6 +# JNA uses reflection extensively to map Java/Kotlin interfaces to native
7 +# function pointers. Stripping or renaming any of these classes breaks the
8 +# native call bridge at runtime.
9 +-keep class com.sun.jna.** { *; }
10 +-keep class * implements com.sun.jna.** { *; }
11 +-dontwarn com.sun.jna.**
12 +
13 +# ── UniFFI-generated bindings ─────────────────────────────────────────────────
14 +# The generated Kotlin code in com.ondeinference.onde contains:
15 +# - JNA Library interface (extends com.sun.jna.Library)
16 +# - JNA Structure subclasses (RustBuffer, ForeignBytes, etc.)
17 +# - Callback interfaces mapped to Rust trait objects
18 +# - Companion objects with @JvmStatic native method declarations
19 +# All of these are resolved by name or via reflection — none may be renamed
20 +# or removed.
21 +-keep class com.ondeinference.onde.** { *; }
22 +-keepclassmembers class com.ondeinference.onde.** { *; }
23 +
24 +# Keep the JNA callback interfaces (UniFFI registers them by concrete class
25 +# name at runtime via JNA's CallbackReference).
26 +-keep class * implements com.sun.jna.Callback { *; }
27 +
28 +# Keep JNA Structure fields — JNA maps struct fields by name and order.
29 +-keepclassmembers class * extends com.sun.jna.Structure {
30 + <fields>;
31 +}
32 +
33 +# ── Kotlin coroutines ─────────────────────────────────────────────────────────
34 +# UniFFI async exports generate suspend functions that depend on coroutine
35 +# internals. The default kotlin-stdlib rules handle most of this, but we
36 +# explicitly keep the continuation classes to be safe.
37 +-keepclassmembers class kotlin.coroutines.** { *; }
38 +-dontwarn kotlinx.coroutines.**
39 +
40 +# ── General safety ────────────────────────────────────────────────────────────
41 +# Suppress warnings for annotations that are compile-time only.
42 +-dontwarn javax.annotation.**
43 +-dontwarn kotlin.annotations.jvm.**
sdk/kotlin/onde/src/main/AndroidManifest.xml new
+6
@@ -0,0 +1,6 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<manifest xmlns:android="http://schemas.android.com/apk/res/android">
3 + <!-- No permissions required by the library itself.
4 + Apps consuming this library should declare INTERNET permission
5 + if they need to download models from HuggingFace Hub. -->
6 +</manifest>
sdk/kotlin/settings.gradle.kts new
+18
@@ -0,0 +1,18 @@
1 +pluginManagement {
2 + repositories {
3 + google()
4 + mavenCentral()
5 + gradlePluginPortal()
6 + }
7 +}
8 +
9 +dependencyResolutionManagement {
10 + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
11 + repositories {
12 + google()
13 + mavenCentral()
14 + }
15 +}
16 +
17 +rootProject.name = "onde-kotlin"
18 +include(":onde")
sdk/python/.gitignore new
+27
@@ -0,0 +1,27 @@
1 +# Python
2 +__pycache__/
3 +*.py[cod]
4 +*.egg-info/
5 +dist/
6 +build/
7 +*.whl
8 +*.so
9 +*.dylib
10 +*.dll
11 +*.pyd
12 +
13 +# Maturin
14 +target/
15 +
16 +# Virtual environments
17 +.venv/
18 +venv/
19 +
20 +# IDE
21 +.idea/
22 +.vscode/
23 +
24 +# Testing
25 +.pytest_cache/
26 +.coverage
27 +htmlcov/
\ No newline at end of file
sdk/python/README.md new
+225
@@ -0,0 +1,225 @@
1 +<p align="center">
2 + <h1 align="center">onde-inference</h1>
3 + <p align="center"><strong>On-device AI inference for Python</strong></p>
4 +</p>
5 +
6 +<p align="center">
7 + <a href="https://pypi.org/project/onde-inference/"><img src="https://img.shields.io/pypi/v/onde-inference.svg" alt="PyPI version"></a>
8 + <a href="https://pypi.org/project/onde-inference/"><img src="https://img.shields.io/pypi/pyversions/onde-inference.svg" alt="Python 3.9+"></a>
9 + <a href="#license"><img src="https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg" alt="License"></a>
10 +</p>
11 +
12 +---
13 +
14 +Run LLMs and speech-to-text locally — no cloud, no latency, no data leaving the device. Powered by Rust via [mistral.rs](https://github.com/EricLBuehler/mistral.rs).
15 +
16 +`onde-inference` is a Python binding for the [Onde](https://github.com/ondeinference/onde) Rust crate. It wraps the Rust inference engine via [UniFFI](https://mozilla.github.io/uniffi-rs/) bindings, giving you native-speed on-device inference with a simple, async Python API.
17 +
18 +## Installation
19 +
20 +```bash
21 +pip install onde-inference
22 +```
23 +
24 +## Quick Start
25 +
26 +### Basic Chat
27 +
28 +```python
29 +import asyncio
30 +from onde_inference import OndeChatEngine, default_model_config
31 +
32 +
33 +async def main():
34 + # Create the engine (starts with no model loaded).
35 + engine = OndeChatEngine()
36 +
37 + # Load the platform-appropriate default model.
38 + # macOS → Qwen 2.5 3B (~1.93 GB), Linux/Windows → Qwen 2.5 3B (~1.93 GB)
39 + elapsed = await engine.load_default_model(
40 + system_prompt="You are a helpful assistant.",
41 + sampling=None,
42 + )
43 + print(f"Model loaded in {elapsed:.1f}s")
44 +
45 + # Send a message — history is managed automatically.
46 + result = await engine.send_message("What is Rust?")
47 + print(result.text)
48 + print(f"Generated in {result.duration_display}")
49 +
50 + # Multi-turn conversation.
51 + follow_up = await engine.send_message("How does its ownership model work?")
52 + print(follow_up.text)
53 +
54 + # Cleanup.
55 + await engine.unload_model()
56 +
57 +
58 +asyncio.run(main())
59 +```
60 +
61 +### Model Configuration Helpers
62 +
63 +Choose a specific model instead of the platform default:
64 +
65 +```python
66 +from onde_inference import default_model_config, qwen25_1_5b_config, qwen25_3b_config
67 +
68 +# Platform-appropriate default (3B on desktop, 1.5B on mobile).
69 +config = default_model_config()
70 +
71 +# Explicitly pick a model.
72 +small = qwen25_1_5b_config() # Qwen 2.5 1.5B — ~941 MB
73 +medium = qwen25_3b_config() # Qwen 2.5 3B — ~1.93 GB
74 +
75 +# Load a specific model config.
76 +elapsed = await engine.load_gguf_model(
77 + config=small,
78 + system_prompt="You are a helpful assistant.",
79 + sampling=None,
80 +)
81 +```
82 +
83 +### Sampling Configuration
84 +
85 +Control how the model generates text:
86 +
87 +```python
88 +from onde_inference import (
89 + default_sampling_config,
90 + deterministic_sampling_config,
91 + mobile_sampling_config,
92 +)
93 +
94 +# Creative chat (temperature=0.7, top_p=0.95, max_tokens=512).
95 +creative = default_sampling_config()
96 +
97 +# Greedy decoding (temperature=0.0) — deterministic output.
98 +greedy = deterministic_sampling_config()
99 +
100 +# Conservative settings for constrained devices (max_tokens=128).
101 +mobile = mobile_sampling_config()
102 +
103 +# Pass to load or update at any time.
104 +await engine.load_default_model(system_prompt="You are helpful.", sampling=greedy)
105 +await engine.set_sampling(creative)
106 +```
107 +
108 +### Streaming
109 +
110 +Stream tokens as they are generated using a callback class that implements `StreamChunkListener`:
111 +
112 +```python
113 +import asyncio
114 +from onde_inference import (
115 + OndeChatEngine,
116 + StreamChunkListener,
117 + StreamChunk,
118 + stream_chat_message,
119 +)
120 +
121 +
122 +class MyStreamHandler(StreamChunkListener):
123 + def on_chunk(self, chunk: StreamChunk) -> bool:
124 + """Called for each token. Return True to continue, False to cancel."""
125 + if chunk.delta:
126 + print(chunk.delta, end="", flush=True)
127 + if chunk.done:
128 + print() # newline at the end
129 + return True
130 +
131 +
132 +async def main():
133 + engine = OndeChatEngine()
134 + await engine.load_default_model(
135 + system_prompt="You are a helpful assistant.",
136 + sampling=None,
137 + )
138 +
139 + # stream_chat_message is a free function (UniFFI requirement).
140 + await stream_chat_message(
141 + engine=engine,
142 + message="Tell me a short story about a robot learning to paint.",
143 + listener=MyStreamHandler(),
144 + )
145 +
146 + await engine.unload_model()
147 +
148 +
149 +asyncio.run(main())
150 +```
151 +
152 +### Message Helpers
153 +
154 +Build message lists for one-shot generation without modifying conversation history:
155 +
156 +```python
157 +from onde_inference import system_message, user_message, assistant_message
158 +
159 +messages = [
160 + system_message("You expand short prompts into detailed descriptions."),
161 + user_message("a cat in space"),
162 +]
163 +
164 +result = await engine.generate(messages=messages, sampling=None)
165 +print(result.text)
166 +```
167 +
168 +### Engine Introspection
169 +
170 +```python
171 +# Check engine state.
172 +info = await engine.info()
173 +print(info.status) # "ready", "unloaded", "generating", etc.
174 +print(info.model_name) # "Qwen 2.5 3B" or None
175 +print(info.history_length) # number of conversation turns
176 +
177 +# Access or clear history.
178 +history = await engine.history()
179 +cleared = await engine.clear_history()
180 +
181 +# Check if a model is loaded.
182 +if await engine.is_loaded():
183 + print("Ready to chat!")
184 +```
185 +
186 +## Platform Support
187 +
188 +| Platform | Accelerator | Notes |
189 +|----------|-------------|-------|
190 +| **macOS** | Metal GPU | Apple Silicon and Intel Macs |
191 +| **Linux** | CPU / CUDA | NVIDIA GPU acceleration with CUDA builds |
192 +| **Windows** | CPU / CUDA | NVIDIA GPU acceleration with CUDA builds |
193 +
194 +## Supported Models
195 +
196 +| Model | Size | Best For |
197 +|-------|------|----------|
198 +| **Qwen 2.5 1.5B** (GGUF Q4_K_M) | ~941 MB | Lightweight / memory-constrained environments |
199 +| **Qwen 2.5 3B** (GGUF Q4_K_M) | ~1.93 GB | Balanced quality and performance on desktop |
200 +
201 +Models are automatically downloaded from HuggingFace Hub on first use and cached locally.
202 +
203 +## How It Works
204 +
205 +`onde-inference` is a thin Python layer over the **Onde** Rust crate. [UniFFI](https://mozilla.github.io/uniffi-rs/) generates Python bindings from the Rust source, so every call goes directly into native compiled code — there is no Python inference loop. Async methods use Python's `asyncio` (UniFFI generates async Python wrappers for Rust async functions backed by Tokio).
206 +
207 +## Links
208 +
209 +- **Source**: [github.com/ondeinference/onde](https://github.com/ondeinference/onde)
210 +- **Rust crate**: [crates.io/crates/onde](https://crates.io/crates/onde)
211 +- **Documentation**: [docs.rs/onde](https://docs.rs/onde)
212 +- **Inference engine**: [mistral.rs](https://github.com/EricLBuehler/mistral.rs)
213 +
214 +## License
215 +
216 +Licensed under either of:
217 +
218 +- Apache License, Version 2.0 ([LICENSE-APACHE](https://github.com/ondeinference/onde/blob/main/LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
219 +- MIT License ([LICENSE-MIT](https://github.com/ondeinference/onde/blob/main/LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
220 +
221 +at your option.
222 +
223 +## Copyright
224 +
225 +Copyright 2026 [Onde Inference](https://ondeinference.com)
\ No newline at end of file
sdk/python/build-python.sh new
+438
@@ -0,0 +1,438 @@
1 +#!/usr/bin/env bash
2 +# ──────────────────────────────────────────────────────────────────────────────
3 +# build-python.sh — Build the onde Python package using Maturin
4 +# ──────────────────────────────────────────────────────────────────────────────
5 +#
6 +# This script:
7 +# 1. Checks that `maturin` is available (or installs it).
8 +# 2. Builds the Python wheel using `maturin build --release` from the
9 +# python/ directory.
10 +# 3. Optionally runs `maturin develop` for development installs.
11 +# 4. Shows a summary with the output wheel location.
12 +#
13 +# Prerequisites:
14 +# - Rust toolchain (cargo, rustc on PATH)
15 +# - Python 3.9+ with pip or uv
16 +# - uniffi-bindgen ==0.31.0 on PATH (auto-installed if missing)
17 +#
18 +# Usage:
19 +# ./build-python.sh # Build release wheel
20 +# ./build-python.sh --develop # Install into current venv (editable)
21 +# ./build-python.sh --release # Build release wheel (explicit, default)
22 +# ./build-python.sh --help # Show usage
23 +#
24 +# Environment variables:
25 +# ONDE_FEATURES — Extra Cargo features to enable (e.g. "whisper")
26 +# CARGO — Path to cargo binary (default: cargo)
27 +# PYTHON — Path to python binary (default: python3)
28 +# MATURIN — Path to maturin binary (default: auto-detected)
29 +# UNIFFI_BINDGEN — Path to uniffi-bindgen binary (default: auto-detected)
30 +# ──────────────────────────────────────────────────────────────────────────────
31 +set -euo pipefail
32 +
33 +# ── Constants ─────────────────────────────────────────────────────────────────
34 +
35 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
36 +CRATE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
37 +PYTHON_DIR="$SCRIPT_DIR"
38 +
39 +CARGO="${CARGO:-cargo}"
40 +PYTHON="${PYTHON:-python3}"
41 +
42 +# ── Helpers ───────────────────────────────────────────────────────────────────
43 +
44 +RED='\033[0;31m'
45 +GREEN='\033[0;32m'
46 +YELLOW='\033[0;33m'
47 +CYAN='\033[0;36m'
48 +BOLD='\033[1m'
49 +NC='\033[0m' # No Color
50 +
51 +log() { echo -e "${CYAN}[onde]${NC} $*"; }
52 +ok() { echo -e "${GREEN}[onde]${NC} $*"; }
53 +warn() { echo -e "${YELLOW}[onde]${NC} $*"; }
54 +err() { echo -e "${RED}[onde]${NC} $*" >&2; }
55 +die() { err "$@"; exit 1; }
56 +
57 +usage() {
58 + cat <<EOF
59 +Usage: $(basename "$0") [OPTIONS]
60 +
61 +Build the onde Python package using Maturin.
62 +
63 +Options:
64 + --release Build a release wheel (default).
65 + --develop Install the package into the current virtualenv
66 + using \`maturin develop\` (editable/debug build).
67 + --publish Build and publish to PyPI (skips sdist).
68 + --help, -h Show this help message.
69 +
70 +Environment:
71 + ONDE_FEATURES Extra Cargo features, e.g. "whisper"
72 + CARGO Path to cargo (default: cargo)
73 + PYTHON Path to python3 (default: python3)
74 + MATURIN Path to maturin (default: auto-detected)
75 + UNIFFI_BINDGEN Path to uniffi-bindgen (default: auto-detected)
76 +
77 +Examples:
78 + # Build a release wheel
79 + ./build-python.sh
80 +
81 + # Development install into current venv
82 + ./build-python.sh --develop
83 +
84 + # Build with whisper feature enabled
85 + ONDE_FEATURES=whisper ./build-python.sh
86 +
87 + # Publish to PyPI (requires MATURIN_PYPI_TOKEN or ~/.pypirc)
88 + ./build-python.sh --publish
89 +EOF
90 + exit 0
91 +}
92 +
93 +# ── Argument parsing ──────────────────────────────────────────────────────────
94 +
95 +MODE="release"
96 +
97 +while [[ $# -gt 0 ]]; do
98 + case "$1" in
99 + --release)
100 + MODE="release"
101 + shift
102 + ;;
103 + --develop)
104 + MODE="develop"
105 + shift
106 + ;;
107 + --publish)
108 + MODE="publish"
109 + shift
110 + ;;
111 + --help|-h)
112 + usage
113 + ;;
114 + *)
115 + die "Unknown option: $1 (try --help)"
116 + ;;
117 + esac
118 +done
119 +
120 +# ── Step 1: Ensure maturin is available ───────────────────────────────────────
121 +
122 +find_or_install_maturin() {
123 + # 1. Explicit MATURIN env var.
124 + if [[ -n "${MATURIN:-}" ]]; then
125 + if command -v "$MATURIN" &>/dev/null; then
126 + echo "$MATURIN"
127 + return
128 + else
129 + die "MATURIN is set to '$MATURIN' but it is not executable."
130 + fi
131 + fi
132 +
133 + # 2. Already on PATH.
134 + if command -v maturin &>/dev/null; then
135 + echo "maturin"
136 + return
137 + fi
138 +
139 + # 3. Try installing via uv (preferred — fast, no venv needed).
140 + if command -v uv &>/dev/null; then
141 + warn "maturin not found. Installing via ${BOLD}uv tool install maturin${NC}..."
142 + uv tool install maturin >/dev/null 2>&1 || true
143 + if command -v maturin &>/dev/null; then
144 + echo "maturin"
145 + return
146 + fi
147 + fi
148 +
149 + # 4. Try installing via pip.
150 + if command -v pip3 &>/dev/null; then
151 + warn "maturin not found. Installing via ${BOLD}pip3 install maturin${NC}..."
152 + pip3 install maturin >/dev/null 2>&1 || true
153 + if command -v maturin &>/dev/null; then
154 + echo "maturin"
155 + return
156 + fi
157 + elif command -v pip &>/dev/null; then
158 + warn "maturin not found. Installing via ${BOLD}pip install maturin${NC}..."
159 + pip install maturin >/dev/null 2>&1 || true
160 + if command -v maturin &>/dev/null; then
161 + echo "maturin"
162 + return
163 + fi
164 + fi
165 +
166 + return 1
167 +}
168 +
169 +log "Checking for ${BOLD}maturin${NC}..."
170 +
171 +MATURIN_BIN=$(find_or_install_maturin) || die \
172 + "maturin not found and could not be installed.\n" \
173 + "Install it manually: ${BOLD}pip install maturin${NC} or ${BOLD}uv tool install maturin${NC}"
174 +
175 +MATURIN_VERSION=$($MATURIN_BIN --version 2>/dev/null || echo "unknown")
176 +ok "maturin ready: ${BOLD}$MATURIN_BIN${NC} ($MATURIN_VERSION)"
177 +
178 +# ── Step 2: Ensure uniffi-bindgen is available ────────────────────────────────
179 +#
180 +# Maturin with `bindings = "uniffi"` shells out to `uniffi-bindgen` to generate
181 +# the Python bindings. The version MUST match the `uniffi` crate version
182 +# pinned in Cargo.toml (==0.31.0). We check several locations:
183 +# 1. Explicit UNIFFI_BINDGEN env var
184 +# 2. Already on PATH
185 +# 3. The project's local uniffi-bindgen binary (uniffi-bindgen/ crate)
186 +# 4. pip install uniffi-bindgen==0.31.0
187 +
188 +UNIFFI_VERSION="0.31.0"
189 +
190 +find_or_install_uniffi_bindgen() {
191 + # 1. Explicit env var.
192 + if [[ -n "${UNIFFI_BINDGEN:-}" ]]; then
193 + if command -v "$UNIFFI_BINDGEN" &>/dev/null; then
194 + echo "$UNIFFI_BINDGEN"
195 + return
196 + elif [[ -x "$UNIFFI_BINDGEN" ]]; then
197 + echo "$UNIFFI_BINDGEN"
198 + return
199 + else
200 + die "UNIFFI_BINDGEN is set to '$UNIFFI_BINDGEN' but it is not executable."
201 + fi
202 + fi
203 +
204 + # 2. Already on PATH.
205 + if command -v uniffi-bindgen &>/dev/null; then
206 + echo "uniffi-bindgen"
207 + return
208 + fi
209 +
210 + # 3. Project-local binary — use it if already built, otherwise build it.
211 + local local_bin="$CRATE_DIR/uniffi-bindgen/target/release/uniffi-bindgen"
212 + if [[ -x "$local_bin" ]]; then
213 + echo "$local_bin"
214 + return
215 + fi
216 +
217 + # 3b. Binary not built yet — try to compile the local uniffi-bindgen crate.
218 + local local_crate="$CRATE_DIR/uniffi-bindgen"
219 + if [[ -f "$local_crate/Cargo.toml" ]]; then
220 + warn "Local uniffi-bindgen binary not found. Building from ${BOLD}$local_crate${NC}..."
221 + if $CARGO build --release --manifest-path "$local_crate/Cargo.toml" 2>&1; then
222 + if [[ -x "$local_bin" ]]; then
223 + echo "$local_bin"
224 + return
225 + fi
226 + else
227 + warn "Failed to build local uniffi-bindgen crate, trying other methods..."
228 + fi
229 + fi
230 +
231 + # 4. Check common pip --user bin directories.
232 + for candidate in \
233 + "$HOME/Library/Python/3.9/bin/uniffi-bindgen" \
234 + "$HOME/Library/Python/3.10/bin/uniffi-bindgen" \
235 + "$HOME/Library/Python/3.11/bin/uniffi-bindgen" \
236 + "$HOME/Library/Python/3.12/bin/uniffi-bindgen" \
237 + "$HOME/Library/Python/3.13/bin/uniffi-bindgen" \
238 + "$HOME/.local/bin/uniffi-bindgen"; do
239 + if [[ -x "$candidate" ]]; then
240 + echo "$candidate"
241 + return
242 + fi
243 + done
244 +
245 + # 5. Install via pip.
246 + warn "uniffi-bindgen not found. Installing ${BOLD}uniffi-bindgen==$UNIFFI_VERSION${NC} via pip..."
247 + if command -v pip3 &>/dev/null; then
248 + pip3 install "uniffi-bindgen==$UNIFFI_VERSION" >/dev/null 2>&1 || true
249 + elif command -v pip &>/dev/null; then
250 + pip install "uniffi-bindgen==$UNIFFI_VERSION" >/dev/null 2>&1 || true
251 + fi
252 +
253 + # Re-check PATH and common locations after install.
254 + if command -v uniffi-bindgen &>/dev/null; then
255 + echo "uniffi-bindgen"
256 + return
257 + fi
258 + for candidate in \
259 + "$HOME/Library/Python/3.9/bin/uniffi-bindgen" \
260 + "$HOME/Library/Python/3.10/bin/uniffi-bindgen" \
261 + "$HOME/Library/Python/3.11/bin/uniffi-bindgen" \
262 + "$HOME/Library/Python/3.12/bin/uniffi-bindgen" \
263 + "$HOME/Library/Python/3.13/bin/uniffi-bindgen" \
264 + "$HOME/.local/bin/uniffi-bindgen"; do
265 + if [[ -x "$candidate" ]]; then
266 + echo "$candidate"
267 + return
268 + fi
269 + done
270 +
271 + return 1
272 +}
273 +
274 +log "Checking for ${BOLD}uniffi-bindgen${NC} (==$UNIFFI_VERSION)..."
275 +
276 +UNIFFI_BIN=$(find_or_install_uniffi_bindgen) || die \
277 + "uniffi-bindgen not found and could not be installed.\n" \
278 + "Install it manually: ${BOLD}pip install uniffi-bindgen==$UNIFFI_VERSION${NC}\n" \
279 + "The version MUST match the uniffi crate version in Cargo.toml."
280 +
281 +# Ensure the discovered binary is on PATH so maturin can find it.
282 +UNIFFI_BIN_DIR="$(dirname "$UNIFFI_BIN")"
283 +case ":$PATH:" in
284 + *":$UNIFFI_BIN_DIR:"*) ;;
285 + *) export PATH="$UNIFFI_BIN_DIR:$PATH" ;;
286 +esac
287 +
288 +UNIFFI_DETECTED_VERSION=$($UNIFFI_BIN --version 2>/dev/null || echo "unknown")
289 +ok "uniffi-bindgen ready: ${BOLD}$UNIFFI_BIN${NC} ($UNIFFI_DETECTED_VERSION)"
290 +
291 +# ── Step 3: Verify Python & Rust toolchains ───────────────────────────────────
292 +
293 +if ! command -v "$PYTHON" &>/dev/null; then
294 + die "Python not found at '$PYTHON'. Set the PYTHON env var or install Python 3.8+."
295 +fi
296 +
297 +PYTHON_VERSION=$($PYTHON --version 2>&1)
298 +log "Python: ${BOLD}$PYTHON_VERSION${NC}"
299 +
300 +if ! command -v "$CARGO" &>/dev/null; then
301 + die "Cargo not found at '$CARGO'. Install Rust: https://rustup.rs"
302 +fi
303 +
304 +CARGO_VERSION=$($CARGO --version 2>&1)
305 +log "Cargo: ${BOLD}$CARGO_VERSION${NC}"
306 +
307 +# ── Step 4: Prepare feature flags ────────────────────────────────────────────
308 +
309 +FEATURES_ARGS=()
310 +if [[ -n "${ONDE_FEATURES:-}" ]]; then
311 + # Split comma-separated features and pass each via --features
312 + IFS=',' read -ra FEAT_LIST <<< "$ONDE_FEATURES"
313 + for feat in "${FEAT_LIST[@]}"; do
314 + feat=$(echo "$feat" | xargs) # trim whitespace
315 + if [[ -n "$feat" ]]; then
316 + FEATURES_ARGS+=("--cargo-extra-args=--features=$feat")
317 + fi
318 + done
319 + log "Features: ${BOLD}${ONDE_FEATURES}${NC}"
320 +fi
321 +
322 +# ── Step 5: Build / develop / publish ─────────────────────────────────────────
323 +
324 +cd "$PYTHON_DIR"
325 +
326 +if [[ "$MODE" == "develop" ]]; then
327 + # ── Development install ───────────────────────────────────────────────
328 + log "Running ${BOLD}maturin develop${NC} (editable install into current venv)..."
329 + echo ""
330 +
331 + $MATURIN_BIN develop \
332 + --manifest-path "$CRATE_DIR/Cargo.toml" \
333 + "${FEATURES_ARGS[@]+"${FEATURES_ARGS[@]}"}"
334 +
335 + echo ""
336 + ok "Development install complete."
337 + ok "The ${BOLD}onde_inference${NC} package is now available in your current Python environment."
338 +
339 +elif [[ "$MODE" == "publish" ]]; then
340 + # ── Publish to PyPI ───────────────────────────────────────────────────
341 + # All Rust deps use git refs (no local path deps), and
342 + # uniffi-bindgen==0.31.0 is in [build-system] requires so PEP 517
343 + # isolated builds install it automatically.
344 + log "Running ${BOLD}maturin publish${NC}..."
345 + echo ""
346 +
347 + $MATURIN_BIN publish \
348 + --manifest-path "$CRATE_DIR/Cargo.toml" \
349 + --skip-existing \
350 + --compatibility pypi \
351 + "${FEATURES_ARGS[@]+"${FEATURES_ARGS[@]}"}"
352 +
353 + echo ""
354 + ok "Published to PyPI."
355 +
356 +else
357 + # ── Release wheel build ───────────────────────────────────────────────
358 + log "Running ${BOLD}maturin build --release${NC}..."
359 + echo ""
360 +
361 + $MATURIN_BIN build \
362 + --release \
363 + --manifest-path "$CRATE_DIR/Cargo.toml" \
364 + --out "$PYTHON_DIR/dist" \
365 + "${FEATURES_ARGS[@]+"${FEATURES_ARGS[@]}"}"
366 +
367 + echo ""
368 +
369 + # Find the built wheel(s).
370 + WHEEL_DIR="$PYTHON_DIR/dist"
371 + if [[ -d "$WHEEL_DIR" ]]; then
372 + WHEEL_FILES=()
373 + while IFS= read -r -d '' whl; do
374 + WHEEL_FILES+=("$whl")
375 + done < <(find "$WHEEL_DIR" -name '*.whl' -newer "$PYTHON_DIR" -print0 2>/dev/null || true)
376 +
377 + # If the timestamp trick didn't find any, just list all wheels.
378 + if [[ ${#WHEEL_FILES[@]} -eq 0 ]]; then
379 + while IFS= read -r -d '' whl; do
380 + WHEEL_FILES+=("$whl")
381 + done < <(find "$WHEEL_DIR" -name '*.whl' -print0 2>/dev/null || true)
382 + fi
383 + fi
384 +fi
385 +
386 +# ── Step 6: Summary ──────────────────────────────────────────────────────────
387 +
388 +echo ""
389 +ok "════════════════════════════════════════════════════════════════════"
390 +ok " Onde Python package build complete!"
391 +ok "════════════════════════════════════════════════════════════════════"
392 +echo ""
393 +
394 +if [[ "$MODE" == "develop" ]]; then
395 + log "Mode: ${BOLD}develop${NC} (editable install)"
396 + log "Python: ${BOLD}$PYTHON_VERSION${NC}"
397 + echo ""
398 + log "Verify the install:"
399 + log " ${BOLD}$PYTHON -c \"from onde_inference import __version__; print(__version__)\"${NC}"
400 +
401 +elif [[ "$MODE" == "publish" ]]; then
402 + log "Mode: ${BOLD}publish${NC} (PyPI)"
403 + log "Python: ${BOLD}$PYTHON_VERSION${NC}"
404 + echo ""
405 + log "Install from PyPI:"
406 + log " ${BOLD}pip install onde-inference${NC}"
407 +
408 +else
409 + log "Mode: ${BOLD}release${NC} (wheel)"
410 + log "Python: ${BOLD}$PYTHON_VERSION${NC}"
411 +
412 + if [[ ${#WHEEL_FILES[@]} -gt 0 ]]; then
413 + echo ""
414 + log "Built wheel(s):"
415 + for whl in "${WHEEL_FILES[@]}"; do
416 + SIZE=$(du -h "$whl" | cut -f1)
417 + ok " $(basename "$whl") (${SIZE})"
418 + log " ${BOLD}$whl${NC}"
419 + done
420 + else
421 + warn "No .whl files found in $WHEEL_DIR"
422 + fi
423 +
424 + echo ""
425 + log "Install the wheel:"
426 + if [[ ${#WHEEL_FILES[@]} -gt 0 ]]; then
427 + log " ${BOLD}pip install ${WHEEL_FILES[-1]}${NC}"
428 + else
429 + log " ${BOLD}pip install $WHEEL_DIR/<wheel-file>.whl${NC}"
430 + fi
431 +fi
432 +
433 +if [[ -n "${ONDE_FEATURES:-}" ]]; then
434 + echo ""
435 + log "Features: ${BOLD}${ONDE_FEATURES}${NC}"
436 +fi
437 +
438 +echo ""
sdk/python/pyproject.toml new
+43
@@ -0,0 +1,43 @@
1 +[build-system]
2 +requires = ["maturin>=1.7,<2.0", "uniffi-bindgen==0.31.0"]
3 +build-backend = "maturin"
4 +
5 +[project]
6 +name = "onde-inference"
7 +version = "0.1.0"
8 +description = "On-device AI inference for Python — run LLMs and speech-to-text locally with automatic model management. Powered by Rust."
9 +license = "MIT OR Apache-2.0"
10 +authors = [
11 + { name = "Seto Elkahfi", email = "setoelkahfi@gmail.com" },
12 + { name = "Onde Inference" },
13 +]
14 +homepage = "https://ondeinference.com"
15 +repository = "https://github.com/ondeinference/onde"
16 +documentation = "https://docs.rs/onde"
17 +keywords = ["inference", "on-device", "whisper", "llm", "ai"]
18 +classifiers = [
19 + "Development Status :: 3 - Alpha",
20 + "Intended Audience :: Developers",
21 + "License :: OSI Approved :: MIT License",
22 + "Topic :: Scientific/Engineering :: Artificial Intelligence",
23 + "Programming Language :: Python :: 3.9",
24 + "Programming Language :: Python :: 3.10",
25 + "Programming Language :: Python :: 3.11",
26 + "Programming Language :: Python :: 3.12",
27 + "Programming Language :: Python :: 3.13",
28 +]
29 +readme = "README.md"
30 +requires-python = ">=3.9"
31 +
32 +[tool.maturin]
33 +bindings = "uniffi"
34 +manifest-path = "../Cargo.toml"
35 +uniffi-bindgen-path = "../uniffi-bindgen/target/release/uniffi-bindgen"
36 +module-name = "onde_inference._native"
37 +python-source = "python"
38 +compatibility = "manylinux2014"
39 +features = []
40 +strip = true
41 +
42 +[tool.pytest.ini_options]
43 +testpaths = ["tests"]
\ No newline at end of file
sdk/python/python/onde_inference/__init__.py new
+93
@@ -0,0 +1,93 @@
1 +"""onde-inference — lightweight LLM inference powered by Rust.
2 +
3 +This package wraps the native Rust ``onde`` crate via UniFFI bindings that are
4 +generated at build time by *maturin*. The native extension module lives at
5 +``onde_inference._native``; everything useful is re-exported here so you can
6 +simply write::
7 +
8 + from onde_inference import OndeChatEngine, user_message, ChatRole
9 +
10 +Public API
11 +----------
12 +Classes
13 + OndeChatEngine
14 +Enums
15 + ChatRole, EngineStatus
16 +Records (dataclasses)
17 + ChatMessage, SamplingConfig, GgufModelConfig, InferenceResult,
18 + StreamChunk, EngineInfo
19 +Errors
20 + InferenceError
21 +Callback interfaces (protocols)
22 + StreamChunkListener
23 +Free functions
24 + stream_chat_message, default_model_config, qwen25_1_5b_config,
25 + qwen25_3b_config, default_sampling_config,
26 + deterministic_sampling_config, mobile_sampling_config,
27 + system_message, user_message, assistant_message
28 +"""
29 +
30 +from onde_inference._native import * # noqa: F401,F403
31 +from onde_inference._native import (
32 + # Classes
33 + OndeChatEngine,
34 + # Enums
35 + ChatRole,
36 + EngineStatus,
37 + # Records (dataclasses)
38 + ChatMessage,
39 + SamplingConfig,
40 + GgufModelConfig,
41 + InferenceResult,
42 + StreamChunk,
43 + EngineInfo,
44 + # Errors
45 + InferenceError,
46 + # Callback interfaces (protocols)
47 + StreamChunkListener,
48 + # Free functions
49 + stream_chat_message,
50 + default_model_config,
51 + qwen25_1_5b_config,
52 + qwen25_3b_config,
53 + default_sampling_config,
54 + deterministic_sampling_config,
55 + mobile_sampling_config,
56 + system_message,
57 + user_message,
58 + assistant_message,
59 +)
60 +
61 +__version__ = "0.1.0"
62 +
63 +__all__ = [
64 + # Metadata
65 + "__version__",
66 + # Classes
67 + "OndeChatEngine",
68 + # Enums
69 + "ChatRole",
70 + "EngineStatus",
71 + # Records (dataclasses)
72 + "ChatMessage",
73 + "SamplingConfig",
74 + "GgufModelConfig",
75 + "InferenceResult",
76 + "StreamChunk",
77 + "EngineInfo",
78 + # Errors
79 + "InferenceError",
80 + # Callback interfaces (protocols)
81 + "StreamChunkListener",
82 + # Free functions
83 + "stream_chat_message",
84 + "default_model_config",
85 + "qwen25_1_5b_config",
86 + "qwen25_3b_config",
87 + "default_sampling_config",
88 + "deterministic_sampling_config",
89 + "mobile_sampling_config",
90 + "system_message",
91 + "user_message",
92 + "assistant_message",
93 +]
\ No newline at end of file
sdk/python/python/onde_inference/py.typed
sdk/python/tests/__init__.py
sdk/python/tests/test_onde.py new
+154
@@ -0,0 +1,154 @@
1 +"""Tests for onde-inference Python bindings.
2 +
3 +These tests verify the UniFFI-generated Python bindings work correctly.
4 +They test the public API surface without requiring model downloads or
5 +GPU hardware — focusing on construction, configuration, and error handling.
6 +"""
7 +import pytest
8 +
9 +# All imports should come from the public package
10 +from onde_inference import (
11 + OndeChatEngine,
12 + ChatMessage,
13 + ChatRole,
14 + SamplingConfig,
15 + GgufModelConfig,
16 + EngineInfo,
17 + EngineStatus,
18 + InferenceError,
19 + StreamChunk,
20 + # Free functions
21 + default_model_config,
22 + qwen25_1_5b_config,
23 + qwen25_3b_config,
24 + default_sampling_config,
25 + deterministic_sampling_config,
26 + mobile_sampling_config,
27 + system_message,
28 + user_message,
29 + assistant_message,
30 + # Version
31 + __version__,
32 +)
33 +
34 +
35 +class TestVersion:
36 + def test_version_is_string(self):
37 + assert isinstance(__version__, str)
38 +
39 + def test_version_is_semver(self):
40 + parts = __version__.split(".")
41 + assert len(parts) == 3
42 + assert all(p.isdigit() for p in parts)
43 +
44 +
45 +class TestModelConfigs:
46 + def test_default_model_config_not_empty(self):
47 + cfg = default_model_config()
48 + assert isinstance(cfg, GgufModelConfig)
49 + assert cfg.model_id != ""
50 + assert len(cfg.files) > 0
51 + assert cfg.display_name != ""
52 +
53 + def test_qwen25_1_5b_config(self):
54 + cfg = qwen25_1_5b_config()
55 + assert "1.5B" in cfg.model_id
56 + assert len(cfg.files) == 1
57 + assert cfg.files[0].endswith(".gguf")
58 +
59 + def test_qwen25_3b_config(self):
60 + cfg = qwen25_3b_config()
61 + assert "3B" in cfg.model_id
62 + assert len(cfg.files) == 1
63 + assert cfg.files[0].endswith(".gguf")
64 +
65 +
66 +class TestSamplingConfigs:
67 + def test_default_sampling(self):
68 + s = default_sampling_config()
69 + assert isinstance(s, SamplingConfig)
70 + assert s.temperature == 0.7
71 + assert s.top_p == 0.95
72 + assert s.max_tokens == 512
73 +
74 + def test_deterministic_sampling(self):
75 + s = deterministic_sampling_config()
76 + assert s.temperature == 0.0
77 + assert s.top_p is None
78 +
79 + def test_mobile_sampling(self):
80 + s = mobile_sampling_config()
81 + assert s.max_tokens == 128
82 +
83 +
84 +class TestMessageHelpers:
85 + def test_system_message(self):
86 + m = system_message("You are helpful.")
87 + assert isinstance(m, ChatMessage)
88 + assert m.role == ChatRole.SYSTEM
89 + assert m.content == "You are helpful."
90 +
91 + def test_user_message(self):
92 + m = user_message("Hello")
93 + assert m.role == ChatRole.USER
94 + assert m.content == "Hello"
95 +
96 + def test_assistant_message(self):
97 + m = assistant_message("Hi!")
98 + assert m.role == ChatRole.ASSISTANT
99 + assert m.content == "Hi!"
100 +
101 +
102 +class TestChatRole:
103 + def test_enum_variants_exist(self):
104 + assert ChatRole.SYSTEM is not None
105 + assert ChatRole.USER is not None
106 + assert ChatRole.ASSISTANT is not None
107 +
108 +
109 +class TestEngineStatus:
110 + def test_enum_variants_exist(self):
111 + assert EngineStatus.UNLOADED is not None
112 + assert EngineStatus.LOADING is not None
113 + assert EngineStatus.READY is not None
114 + assert EngineStatus.GENERATING is not None
115 + assert EngineStatus.ERROR is not None
116 +
117 +
118 +@pytest.mark.asyncio
119 +class TestOndeChatEngine:
120 + async def test_new_engine(self):
121 + engine = OndeChatEngine()
122 + assert engine is not None
123 +
124 + async def test_engine_not_loaded_initially(self):
125 + engine = OndeChatEngine()
126 + assert await engine.is_loaded() is False
127 +
128 + async def test_engine_info_initial_state(self):
129 + engine = OndeChatEngine()
130 + info = await engine.info()
131 + assert isinstance(info, EngineInfo)
132 + assert info.status == EngineStatus.UNLOADED
133 + assert info.history_length == 0
134 + assert info.model_name is None
135 +
136 + async def test_send_message_without_model_raises(self):
137 + engine = OndeChatEngine()
138 + with pytest.raises(InferenceError):
139 + await engine.send_message("hello")
140 +
141 + async def test_history_empty_initially(self):
142 + engine = OndeChatEngine()
143 + history = await engine.history()
144 + assert history == []
145 +
146 + async def test_clear_history_returns_zero(self):
147 + engine = OndeChatEngine()
148 + removed = await engine.clear_history()
149 + assert removed == 0
150 +
151 + async def test_unload_when_none_returns_none(self):
152 + engine = OndeChatEngine()
153 + result = await engine.unload_model()
154 + assert result is None
\ No newline at end of file
src/hf_cache.rs new
+1230
@@ -0,0 +1,1230 @@
1 +//! HuggingFace hub cache inspection, repair, and model download.
2 +//!
3 +//! This module owns all on-disk state management for locally cached
4 +//! HuggingFace models and exposes a progress-callback-based download API
5 +//! that is completely decoupled from any application framework.
6 +//!
7 +//! 1. Call [`list_local_hf_models`] / [`list_supported_hf_models`] /
8 +//! [`delete_local_hf_model`] directly from your command handlers.
9 +//! 2. Call [`download_model`] with an `Arc<dyn Fn(ModelDownloadProgress)>`
10 +//! that forwards progress to whatever event system your app uses.
11 +
12 +use {
13 + crate::inference::models::{SUPPORTED_MODELS, SUPPORTED_MODEL_INFO},
14 + log::{debug, info, warn},
15 + serde::{Deserialize, Serialize},
16 + std::{fs, path::PathBuf},
17 + tsync::tsync,
18 +};
19 +
20 +// ---------------------------------------------------------------------------
21 +// Public types
22 +// ---------------------------------------------------------------------------
23 +
24 +/// Information about a locally cached HuggingFace model.
25 +#[tsync]
26 +#[derive(Debug, Clone, Serialize, Deserialize)]
27 +pub struct LocalHfModel {
28 + /// The full model identifier, e.g. "black-forest-labs/FLUX.1-schnell".
29 + pub model_id: String,
30 + /// The organisation or user that published the model.
31 + pub org: String,
32 + /// The model name without the org prefix.
33 + pub name: String,
34 + /// Total size on disk in bytes.
35 + pub size_bytes: u64,
36 + /// Human-readable size string, e.g. "4.2 GB".
37 + pub size_display: String,
38 + /// Absolute path to the model cache directory.
39 + pub path: String,
40 + /// List of snapshot revisions that are locally available.
41 + pub revisions: Vec<String>,
42 +}
43 +
44 +/// Response returned by [`list_local_hf_models`].
45 +#[tsync]
46 +#[derive(Debug, Clone, Serialize, Deserialize)]
47 +pub struct LocalHfModelsResponse {
48 + /// The models found in the local HuggingFace cache.
49 + pub models: Vec<LocalHfModel>,
50 + /// The path that was scanned.
51 + pub cache_path: String,
52 + /// Total size of all cached models in bytes.
53 + pub total_size_bytes: u64,
54 + /// Human-readable total size string.
55 + pub total_size_display: String,
56 +}
57 +
58 +/// A supported model that may or may not be downloaded locally.
59 +#[tsync]
60 +#[derive(Debug, Clone, Serialize, Deserialize)]
61 +pub struct SupportedHfModel {
62 + /// The full model identifier, e.g. "black-forest-labs/FLUX.1-schnell".
63 + pub model_id: String,
64 + /// Human-friendly display name.
65 + pub name: String,
66 + /// Organisation or publisher display name.
67 + pub org: String,
68 + /// Short description of the model.
69 + pub description: String,
70 + /// Whether this model is fully downloaded locally.
71 + pub is_downloaded: bool,
72 + /// Whether a partial (incomplete) download exists on disk.
73 + /// True when a cache directory exists but its size is less than 99 %
74 + /// of `expected_size_bytes`.
75 + pub is_incomplete: bool,
76 + /// Bytes currently on disk for this model (0 when not present at all).
77 + pub local_size_bytes: u64,
78 + /// Human-readable local size string, e.g. "4.2 GB".
79 + pub local_size_display: String,
80 + /// Approximate total size in bytes when fully downloaded.
81 + pub expected_size_bytes: u64,
82 + /// Human-readable expected size string, e.g. "23.80 GB".
83 + pub expected_size_display: String,
84 +}
85 +
86 +/// Response returned by [`list_supported_hf_models`].
87 +#[tsync]
88 +#[derive(Debug, Clone, Serialize, Deserialize)]
89 +pub struct SupportedHfModelsResponse {
90 + /// All models the app supports, with download status.
91 + pub models: Vec<SupportedHfModel>,
92 +}
93 +
94 +/// Progress payload passed to the [`download_model`] callback on every poll
95 +/// tick and on completion.
96 +///
97 +/// Forward this value to your app's event system so the frontend can render
98 +/// a progress bar.
99 +#[tsync]
100 +#[derive(Debug, Clone, Serialize, Deserialize)]
101 +pub struct ModelDownloadProgress {
102 + /// The model being downloaded.
103 + pub model_id: String,
104 + /// Bytes downloaded so far (observed from cache directory size).
105 + pub downloaded_bytes: u64,
106 + /// Human-readable downloaded size, e.g. "1.2 GB".
107 + pub downloaded_display: String,
108 + /// Expected total size in bytes (approximate).
109 + pub total_bytes: u64,
110 + /// Human-readable total size, e.g. "23.80 GB".
111 + pub total_display: String,
112 + /// Download progress as a value between 0.0 and 1.0.
113 + pub progress: f64,
114 + /// Whether the download has completed.
115 + pub done: bool,
116 +}
117 +
118 +// ---------------------------------------------------------------------------
119 +// Internal constants
120 +// ---------------------------------------------------------------------------
121 +
122 +/// Fraction of `expected_size_bytes` that must be present on disk for a
123 +/// model to be considered fully downloaded (99 %).
124 +const DOWNLOAD_COMPLETE_THRESHOLD: f64 = 0.99;
125 +
126 +// ---------------------------------------------------------------------------
127 +// Private helpers
128 +// ---------------------------------------------------------------------------
129 +
130 +/// Resolve the HuggingFace hub cache directory.
131 +///
132 +/// Respects the `HF_HOME` / `HUGGINGFACE_HUB_CACHE` environment variables.
133 +/// Falls back to `~/.cache/huggingface/hub`.
134 +///
135 +/// On iOS the `HF_HOME` variable is set during app setup (see
136 +/// `setup_application_filesystem`) to a path inside the app's writable
137 +/// `Library/Application Support/` container. We create the directory if it
138 +/// doesn't exist yet so that first-run and freshly-installed apps work
139 +/// correctly.
140 +fn hf_cache_dir() -> Option<PathBuf> {
141 + // 1. Explicit hub cache override
142 + if let Ok(cache) = std::env::var("HUGGINGFACE_HUB_CACHE") {
143 + let p = PathBuf::from(cache);
144 + let _ = fs::create_dir_all(&p);
145 + if p.is_dir() {
146 + return Some(p);
147 + }
148 + }
149 +
150 + // 2. HF_HOME override (hub is a subdirectory)
151 + if let Ok(hf_home) = std::env::var("HF_HOME") {
152 + let p = PathBuf::from(hf_home).join("hub");
153 + let _ = fs::create_dir_all(&p);
154 + if p.is_dir() {
155 + return Some(p);
156 + }
157 + }
158 +
159 + // 3. Default: ~/.cache/huggingface/hub
160 + if let Some(home) = home::home_dir() {
161 + let p = home.join(".cache").join("huggingface").join("hub");
162 + let _ = fs::create_dir_all(&p);
163 + if p.is_dir() {
164 + return Some(p);
165 + }
166 + }
167 +
168 + None
169 +}
170 +
171 +/// Recursively compute the total size of a directory in bytes.
172 +///
173 +/// Follows symlinks to count the real file size and also counts in-progress
174 +/// `.incomplete` staging files so that progress polling reflects partial
175 +/// downloads before they are renamed to their final blob name.
176 +fn dir_size(path: &PathBuf) -> u64 {
177 + let mut total: u64 = 0;
178 + if let Ok(entries) = fs::read_dir(path) {
179 + for entry in entries.flatten() {
180 + let entry_path = entry.path();
181 + if entry_path.is_dir() {
182 + total += dir_size(&entry_path);
183 + } else {
184 + // Count both completed blobs AND in-progress staging files
185 + // (hf-hub downloads to `<sha256>.incomplete` and renames on
186 + // completion — without this, progress stays at 0% for the
187 + // entire download and jumps to 100% at the end).
188 + if let Ok(meta) = entry_path.symlink_metadata() {
189 + if meta.is_symlink() {
190 + // Follow the symlink to get the real file size.
191 + if let Ok(real_meta) = entry_path.metadata() {
192 + total += real_meta.len();
193 + }
194 + } else {
195 + total += meta.len();
196 + }
197 + }
198 + }
199 + }
200 + }
201 + total
202 +}
203 +
204 +/// Format a byte count into a human-readable string.
205 +fn format_size(bytes: u64) -> String {
206 + const KB: u64 = 1024;
207 + const MB: u64 = KB * 1024;
208 + const GB: u64 = MB * 1024;
209 + const TB: u64 = GB * 1024;
210 +
211 + if bytes >= TB {
212 + format!("{:.2} TB", bytes as f64 / TB as f64)
213 + } else if bytes >= GB {
214 + format!("{:.2} GB", bytes as f64 / GB as f64)
215 + } else if bytes >= MB {
216 + format!("{:.1} MB", bytes as f64 / MB as f64)
217 + } else if bytes >= KB {
218 + format!("{:.0} KB", bytes as f64 / KB as f64)
219 + } else {
220 + format!("{} B", bytes)
221 + }
222 +}
223 +
224 +/// List the snapshot revisions available for a cached model directory.
225 +fn list_revisions(model_dir: &PathBuf) -> Vec<String> {
226 + let snapshots_dir = model_dir.join("snapshots");
227 + if !snapshots_dir.is_dir() {
228 + return Vec::new();
229 + }
230 +
231 + let mut revisions = Vec::new();
232 + if let Ok(entries) = fs::read_dir(&snapshots_dir) {
233 + for entry in entries.flatten() {
234 + if entry.path().is_dir() {
235 + if let Some(name) = entry.file_name().to_str() {
236 + revisions.push(name.to_string());
237 + }
238 + }
239 + }
240 + }
241 + revisions.sort();
242 + revisions
243 +}
244 +
245 +/// Build a [`ModelDownloadProgress`] payload from raw byte counts.
246 +fn make_progress(model_id: &str, downloaded: u64, total: u64, done: bool) -> ModelDownloadProgress {
247 + let progress = if total > 0 {
248 + (downloaded as f64 / total as f64).min(1.0)
249 + } else {
250 + 0.0
251 + };
252 + ModelDownloadProgress {
253 + model_id: model_id.to_string(),
254 + downloaded_bytes: downloaded,
255 + downloaded_display: format_size(downloaded),
256 + total_bytes: total,
257 + total_display: format_size(total),
258 + progress,
259 + done,
260 + }
261 +}
262 +
263 +// ---------------------------------------------------------------------------
264 +// Public cache utilities
265 +// ---------------------------------------------------------------------------
266 +
267 +/// Return the cache sub-directory path for a given model ID.
268 +///
269 +/// E.g. for `"black-forest-labs/FLUX.1-schnell"` the cache directory is
270 +/// `<hf_cache>/models--black-forest-labs--FLUX.1-schnell`.
271 +pub fn model_cache_path(model_id: &str) -> Option<PathBuf> {
272 + let cache_dir = hf_cache_dir()?;
273 + let dir_name = format!("models--{}", model_id.replace('/', "--"));
274 + Some(cache_dir.join(dir_name))
275 +}
276 +
277 +/// Pre-create the HuggingFace cache directory tree for `model_id` so that the
278 +/// progress-monitor thread can find a valid path immediately, even before
279 +/// hf-hub creates it during the first download.
280 +///
281 +/// hf-hub won't be confused by a pre-existing (empty) directory — it will
282 +/// simply populate it as normal.
283 +pub fn ensure_model_cache_dir(model_id: &str) {
284 + if let Some(model_path) = model_cache_path(model_id) {
285 + let blobs_dir = model_path.join("blobs");
286 + if let Err(e) = fs::create_dir_all(&blobs_dir) {
287 + warn!(
288 + "Could not pre-create model cache dir {}: {}",
289 + blobs_dir.display(),
290 + e
291 + );
292 + } else {
293 + info!("Pre-created model cache dir: {}", model_path.display());
294 + }
295 + }
296 +}
297 +
298 +/// Remove stale `.lock` and orphaned `.part` files from the HF cache
299 +/// `blobs/` directory for a model.
300 +///
301 +/// The HF hub client creates `.lock` files during download. If a download is
302 +/// interrupted these locks persist and prevent any subsequent access (download
303 +/// **or** model load). Calling this before loading or resuming a download
304 +/// allows the hub client to re-acquire the lock and proceed normally.
305 +pub fn clean_stale_lock_files(model_id: &str) {
306 + if let Some(cache_path) = model_cache_path(model_id) {
307 + let blobs_dir = cache_path.join("blobs");
308 + if blobs_dir.is_dir() {
309 + // Collect the names of complete blobs (no extension) so we can
310 + // decide whether a `.part` file is stale.
311 + let complete_blobs: Vec<String> = fs::read_dir(&blobs_dir)
312 + .into_iter()
313 + .flatten()
314 + .flatten()
315 + .filter_map(|e| {
316 + let p = e.path();
317 + if p.is_file() && p.extension().is_none() {
318 + p.file_name().map(|n| n.to_string_lossy().to_string())
319 + } else {
320 + None
321 + }
322 + })
323 + .collect();
324 +
325 + if let Ok(entries) = fs::read_dir(&blobs_dir) {
326 + for entry in entries.flatten() {
327 + let path = entry.path();
328 + let ext = path.extension().and_then(|e| e.to_str());
329 +
330 + match ext {
331 + Some("lock") => {
332 + info!("Removing stale lock file: {}", path.display());
333 + if let Err(e) = fs::remove_file(&path) {
334 + warn!("Failed to remove lock file {}: {}", path.display(), e);
335 + }
336 + }
337 + Some("part") => {
338 + // A `.part` file is a partial download left by hf-hub.
339 + // If the corresponding complete blob exists (same name
340 + // without `.part`), the partial file is stale and
341 + // causes hf-hub to issue a spurious Range-resume
342 + // download instead of using the complete blob.
343 + let stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or("");
344 + if complete_blobs.iter().any(|b| b == stem) {
345 + let part_size = fs::metadata(&path).map(|m| m.len()).unwrap_or(0);
346 + info!(
347 + "Removing stale .part file ({} bytes, complete blob exists): {}",
348 + part_size,
349 + path.display()
350 + );
351 + if let Err(e) = fs::remove_file(&path) {
352 + warn!("Failed to remove .part file {}: {}", path.display(), e);
353 + }
354 + } else {
355 + let part_size = fs::metadata(&path).map(|m| m.len()).unwrap_or(0);
356 + debug!(
357 + "Keeping .part file ({} bytes, no complete blob yet): {}",
358 + part_size,
359 + path.display()
360 + );
361 + }
362 + }
363 + _ => {}
364 + }
365 + }
366 + }
367 + }
368 + }
369 +}
370 +
371 +/// Log the complete HF cache structure for a model to aid debugging.
372 +///
373 +/// This is called before model load so the developer can see exactly what's
374 +/// present in the cache, whether `refs/main` resolves, whether symlinks are
375 +/// intact, and whether any `.part` files are left over from interrupted
376 +/// downloads.
377 +pub fn diagnose_hf_cache(model_id: &str) {
378 + let cache_path = match model_cache_path(model_id) {
379 + Some(p) => p,
380 + None => {
381 + info!("diagnose_hf_cache({}): cache path not found", model_id);
382 + return;
383 + }
384 + };
385 +
386 + if !cache_path.is_dir() {
387 + info!(
388 + "diagnose_hf_cache({}): directory does not exist: {}",
389 + model_id,
390 + cache_path.display()
391 + );
392 + return;
393 + }
394 +
395 + info!(
396 + "diagnose_hf_cache({}): scanning {}",
397 + model_id,
398 + cache_path.display()
399 + );
400 +
401 + // ── refs/ ────────────────────────────────────────────────────────────
402 + let refs_dir = cache_path.join("refs");
403 + if refs_dir.is_dir() {
404 + if let Ok(entries) = fs::read_dir(&refs_dir) {
405 + for entry in entries.flatten() {
406 + let name = entry.file_name().to_string_lossy().to_string();
407 + match fs::read_to_string(entry.path()) {
408 + Ok(content) => {
409 + let hash = content.trim();
410 + info!(
411 + " refs/{} → \"{}\" (len={})",
412 + name,
413 + if hash.len() > 12 {
414 + format!("{}…", &hash[..12])
415 + } else {
416 + hash.to_string()
417 + },
418 + hash.len()
419 + );
420 + }
421 + Err(e) => {
422 + warn!(" refs/{} → <unreadable: {}>", name, e);
423 + }
424 + }
425 + }
426 + }
427 + } else {
428 + warn!(" refs/ directory missing!");
429 + }
430 +
431 + // ── blobs/ ───────────────────────────────────────────────────────────
432 + let blobs_dir = cache_path.join("blobs");
433 + if blobs_dir.is_dir() {
434 + if let Ok(entries) = fs::read_dir(&blobs_dir) {
435 + for entry in entries.flatten() {
436 + let path = entry.path();
437 + let name = entry.file_name().to_string_lossy().to_string();
438 + let size = fs::metadata(&path).map(|m| m.len()).unwrap_or(0);
439 + let kind = if name.ends_with(".lock") {
440 + "LOCK"
441 + } else if name.ends_with(".part") {
442 + "PART (incomplete)"
443 + } else {
444 + "blob"
445 + };
446 + info!(
447 + " blobs/{} — {} ({} bytes / {:.1} MB)",
448 + name,
449 + kind,
450 + size,
451 + size as f64 / 1_048_576.0
452 + );
453 + }
454 + }
455 + } else {
456 + warn!(" blobs/ directory missing!");
457 + }
458 +
459 + // ── snapshots/ ───────────────────────────────────────────────────────
460 + let snapshots_dir = cache_path.join("snapshots");
461 + if snapshots_dir.is_dir() {
462 + if let Ok(revs) = fs::read_dir(&snapshots_dir) {
463 + for rev_entry in revs.flatten() {
464 + let rev_name = rev_entry.file_name().to_string_lossy().to_string();
465 + let rev_display = if rev_name.len() > 12 {
466 + format!("{}…", &rev_name[..12])
467 + } else {
468 + rev_name.clone()
469 + };
470 + info!(" snapshots/{}/", rev_display);
471 +
472 + if let Ok(files) = fs::read_dir(rev_entry.path()) {
473 + for file_entry in files.flatten() {
474 + let file_name = file_entry.file_name().to_string_lossy().to_string();
475 + let file_path = file_entry.path();
476 +
477 + if file_path.is_symlink() {
478 + let target = fs::read_link(&file_path)
479 + .map(|t| t.to_string_lossy().to_string())
480 + .unwrap_or_else(|_| "<unreadable>".to_string());
481 + let accessible = fs::metadata(&file_path).is_ok();
482 + let status = if accessible { "OK" } else { "BROKEN" };
483 + info!(" {} → {} [symlink: {}]", file_name, target, status);
484 + } else if file_path.is_file() {
485 + let size = fs::metadata(&file_path).map(|m| m.len()).unwrap_or(0);
486 + info!(
487 + " {} [{} bytes / {:.1} MB, real file]",
488 + file_name,
489 + size,
490 + size as f64 / 1_048_576.0
491 + );
492 + } else {
493 + warn!(" {} [not a file or symlink!]", file_name);
494 + }
495 + }
496 + }
497 + }
498 + }
499 + } else {
500 + warn!(" snapshots/ directory missing!");
501 + }
502 +
503 + info!("diagnose_hf_cache({}): done", model_id);
504 +}
505 +
506 +/// Repair broken symlinks in the HF hub cache for a given model.
507 +///
508 +/// The `hf-hub` crate stores downloaded files as blobs keyed by SHA-256 and
509 +/// creates **symlinks** from `snapshots/<rev>/<filename>` → `../../blobs/<hash>`.
510 +/// When the cache directory is copied into an iOS app container (e.g. via
511 +/// Xcode "Replace Container" or `ideviceinstaller`), symlinks are often
512 +/// silently dropped or broken. The `hf-hub` client then thinks the file is
513 +/// missing and re-downloads it — even though the 940 MB blob is right there.
514 +///
515 +/// This function walks every snapshot entry for `model_id`. If a path is a
516 +/// broken symlink **or** a missing file, and a matching blob exists, it
517 +/// replaces the symlink with a hard copy of the blob so that `hf-hub`'s
518 +/// `Cache::get()` finds a real file at the expected path.
519 +///
520 +/// It also ensures a `refs/main` file exists pointing at the snapshot
521 +/// revision, since that file is needed for `hf-hub` to resolve the "main"
522 +/// ref to a concrete snapshot directory.
523 +///
524 +/// This is idempotent and safe to call on every app launch.
525 +pub fn repair_hf_cache_symlinks(model_id: &str) {
526 + let cache_path = match model_cache_path(model_id) {
527 + Some(p) if p.is_dir() => p,
528 + _ => return,
529 + };
530 +
531 + let blobs_dir = cache_path.join("blobs");
532 + let snapshots_dir = cache_path.join("snapshots");
533 + let refs_dir = cache_path.join("refs");
534 +
535 + if !blobs_dir.is_dir() || !snapshots_dir.is_dir() {
536 + return;
537 + }
538 +
539 + // Collect blob filenames (excluding .lock files) for lookup.
540 + let blob_names: Vec<String> = match fs::read_dir(&blobs_dir) {
541 + Ok(entries) => entries
542 + .flatten()
543 + .filter_map(|e| {
544 + let name = e.file_name().to_string_lossy().to_string();
545 + if name.ends_with(".lock") {
546 + None
547 + } else if e.path().is_file() {
548 + Some(name)
549 + } else {
550 + None
551 + }
552 + })
553 + .collect(),
554 + Err(_) => return,
555 + };
556 +
557 + if blob_names.is_empty() {
558 + return;
559 + }
560 +
561 + // Walk each snapshot revision directory.
562 + let snapshot_revs: Vec<(String, PathBuf)> = match fs::read_dir(&snapshots_dir) {
563 + Ok(entries) => entries
564 + .flatten()
565 + .filter(|e| e.path().is_dir())
566 + .filter_map(|e| {
567 + let rev = e.file_name().to_string_lossy().to_string();
568 + Some((rev, e.path()))
569 + })
570 + .collect(),
571 + Err(_) => return,
572 + };
573 +
574 + for (rev, snap_dir) in &snapshot_revs {
575 + let entries = match fs::read_dir(snap_dir) {
576 + Ok(e) => e,
577 + Err(_) => continue,
578 + };
579 +
580 + for entry in entries.flatten() {
581 + let snap_file = entry.path();
582 + let file_name = entry.file_name().to_string_lossy().to_string();
583 +
584 + // Check if the file is accessible (broken symlink → metadata fails).
585 + let needs_repair = if snap_file.is_symlink() {
586 + // Symlink exists but may be broken — check if target is readable.
587 + fs::metadata(&snap_file).is_err()
588 + } else if snap_file.exists() {
589 + // Real file, no repair needed.
590 + false
591 + } else {
592 + // Path doesn't exist at all (dangling entry in readdir).
593 + true
594 + };
595 +
596 + if !needs_repair {
597 + continue;
598 + }
599 +
600 + // Try to find a matching blob. For GGUF repos there's usually
601 + // just one blob; for multi-file repos we match by the symlink
602 + // target name if we can read it, otherwise fall back to the
603 + // single-blob heuristic.
604 + let blob_name = if let Ok(target) = fs::read_link(&snap_file) {
605 + target
606 + .file_name()
607 + .map(|n| n.to_string_lossy().to_string())
608 + .filter(|n| blob_names.contains(n))
609 + } else {
610 + None
611 + };
612 +
613 + let resolved_blob = if let Some(ref name) = blob_name {
614 + Some(blobs_dir.join(name))
615 + } else if blob_names.len() == 1 {
616 + // Single-blob repo (typical for GGUF) — safe to assume it
617 + // corresponds to this snapshot entry.
618 + Some(blobs_dir.join(&blob_names[0]))
619 + } else {
620 + None
621 + };
622 +
623 + if let Some(blob_path) = resolved_blob {
624 + if !blob_path.is_file() {
625 + continue;
626 + }
627 +
628 + // Remove the broken symlink before copying.
629 + if snap_file.is_symlink() || snap_file.exists() {
630 + let _ = fs::remove_file(&snap_file);
631 + }
632 +
633 + info!(
634 + "repair_hf_cache_symlinks: replacing broken symlink with copy: {} → {}",
635 + blob_path.display(),
636 + snap_file.display()
637 + );
638 +
639 + // Prefer hard link (instant, no extra disk space) over copy.
640 + if fs::hard_link(&blob_path, &snap_file).is_err() {
641 + if let Err(e) = fs::copy(&blob_path, &snap_file) {
642 + warn!(
643 + "repair_hf_cache_symlinks: failed to copy blob to snapshot: {}",
644 + e
645 + );
646 + }
647 + }
648 + } else {
649 + warn!(
650 + "repair_hf_cache_symlinks: broken symlink for '{}' but no matching blob found",
651 + file_name
652 + );
653 + }
654 + }
655 +
656 + // Ensure refs/main exists and points to this revision so that
657 + // `hf-hub` can resolve the snapshot.
658 + if !refs_dir.join("main").is_file() {
659 + let _ = fs::create_dir_all(&refs_dir);
660 + if let Err(e) = fs::write(refs_dir.join("main"), rev.as_bytes()) {
661 + warn!("repair_hf_cache_symlinks: failed to write refs/main: {}", e);
662 + } else {
663 + info!("repair_hf_cache_symlinks: created refs/main → {}", rev);
664 + }
665 + }
666 + }
667 +}
668 +
669 +// ---------------------------------------------------------------------------
670 +// Query / mutation functions
671 +// ---------------------------------------------------------------------------
672 +
673 +/// Scan the local HuggingFace hub cache and return all downloaded models that
674 +/// the inference engine supports.
675 +///
676 +/// The cache directory is typically `~/.cache/huggingface/hub/` and contains
677 +/// sub-directories named `models--{org}--{model}` for each cached model.
678 +pub fn list_local_hf_models() -> LocalHfModelsResponse {
679 + let cache_dir = match hf_cache_dir() {
680 + Some(dir) => dir,
681 + None => {
682 + debug!("HuggingFace cache directory not found.");
683 + return LocalHfModelsResponse {
684 + models: Vec::new(),
685 + cache_path: String::new(),
686 + total_size_bytes: 0,
687 + total_size_display: "0 B".to_string(),
688 + };
689 + }
690 + };
691 +
692 + let cache_path_str = cache_dir.to_string_lossy().to_string();
693 + debug!("Scanning HuggingFace cache at: {}", cache_path_str);
694 +
695 + let mut models: Vec<LocalHfModel> = Vec::new();
696 +
697 + let entries = match fs::read_dir(&cache_dir) {
698 + Ok(entries) => entries,
699 + Err(e) => {
700 + warn!("Failed to read HuggingFace cache directory: {:?}", e);
701 + return LocalHfModelsResponse {
702 + models: Vec::new(),
703 + cache_path: cache_path_str,
704 + total_size_bytes: 0,
705 + total_size_display: "0 B".to_string(),
706 + };
707 + }
708 + };
709 +
710 + for entry in entries.flatten() {
711 + let entry_path = entry.path();
712 + if !entry_path.is_dir() {
713 + continue;
714 + }
715 +
716 + let dir_name = match entry.file_name().to_str() {
717 + Some(name) => name.to_string(),
718 + None => continue,
719 + };
720 +
721 + // HuggingFace hub caches model repos as "models--{org}--{name}"
722 + if !dir_name.starts_with("models--") {
723 + continue;
724 + }
725 +
726 + // Strip the "models--" prefix and split by "--" to get org/name
727 + let remainder = &dir_name["models--".len()..];
728 + let parts: Vec<&str> = remainder.splitn(2, "--").collect();
729 + if parts.len() != 2 {
730 + // Some models have no org (single segment), handle gracefully
731 + let model_id = remainder.replace("--", "/");
732 + let size = dir_size(&entry_path);
733 + let revisions = list_revisions(&entry_path);
734 +
735 + models.push(LocalHfModel {
736 + model_id: model_id.clone(),
737 + org: String::new(),
738 + name: model_id,
739 + size_bytes: size,
740 + size_display: format_size(size),
741 + path: entry_path.to_string_lossy().to_string(),
742 + revisions,
743 + });
744 + continue;
745 + }
746 +
747 + let org = parts[0].to_string();
748 + let name = parts[1].to_string();
749 + let model_id = format!("{}/{}", org, name);
750 + let size = dir_size(&entry_path);
751 + let revisions = list_revisions(&entry_path);
752 +
753 + models.push(LocalHfModel {
754 + model_id,
755 + org,
756 + name,
757 + size_bytes: size,
758 + size_display: format_size(size),
759 + path: entry_path.to_string_lossy().to_string(),
760 + revisions,
761 + });
762 + }
763 +
764 + // Only keep models that the inference engine actually supports.
765 + models.retain(|m| SUPPORTED_MODELS.iter().any(|&s| s == m.model_id));
766 +
767 + // Sort by model_id for a stable, predictable order.
768 + models.sort_by(|a, b| a.model_id.to_lowercase().cmp(&b.model_id.to_lowercase()));
769 +
770 + let total_size_bytes: u64 = models.iter().map(|m| m.size_bytes).sum();
771 +
772 + debug!(
773 + "Found {} local HuggingFace model(s), total size: {}",
774 + models.len(),
775 + format_size(total_size_bytes)
776 + );
777 +
778 + LocalHfModelsResponse {
779 + models,
780 + cache_path: cache_path_str,
781 + total_size_bytes,
782 + total_size_display: format_size(total_size_bytes),
783 + }
784 +}
785 +
786 +/// Delete a locally cached HuggingFace model by removing its directory from
787 +/// the hub cache.
788 +///
789 +/// `model_id` should be the full identifier, e.g. "black-forest-labs/FLUX.1-schnell".
790 +/// Returns `Ok(())` on success or an error string describing what went wrong.
791 +pub fn delete_local_hf_model(model_id: String) -> Result<(), String> {
792 + let cache_dir = hf_cache_dir().ok_or("HuggingFace cache directory not found.".to_string())?;
793 +
794 + // Convert model_id (e.g. "org/name") to the cache directory name ("models--org--name")
795 + let dir_name = format!("models--{}", model_id.replace('/', "--"));
796 + let model_path = cache_dir.join(&dir_name);
797 +
798 + if !model_path.exists() {
799 + return Err(format!(
800 + "Model cache directory not found: {}",
801 + model_path.display()
802 + ));
803 + }
804 +
805 + if !model_path.is_dir() {
806 + return Err(format!(
807 + "Expected a directory but found a file: {}",
808 + model_path.display()
809 + ));
810 + }
811 +
812 + debug!(
813 + "Deleting local HuggingFace model: {} at {:?}",
814 + model_id, model_path
815 + );
816 +
817 + fs::remove_dir_all(&model_path).map_err(|e| {
818 + let msg = format!("Failed to delete model {}: {}", model_id, e);
819 + warn!("{}", msg);
820 + msg
821 + })?;
822 +
823 + debug!("Successfully deleted local model: {}", model_id);
824 + Ok(())
825 +}
826 +
827 +/// Return the full list of models the inference engine supports, together with
828 +/// flags indicating whether each one is fully downloaded, partially downloaded,
829 +/// or not present at all.
830 +pub fn list_supported_hf_models() -> SupportedHfModelsResponse {
831 + let models = SUPPORTED_MODEL_INFO
832 + .iter()
833 + .map(|info| {
834 + let cache_path = model_cache_path(info.id);
835 + let local_size = cache_path
836 + .as_ref()
837 + .filter(|p| p.exists())
838 + .map(|p| dir_size(p))
839 + .unwrap_or(0);
840 +
841 + let has_cache = local_size > 0;
842 + let is_complete = info.expected_size_bytes > 0
843 + && local_size as f64
844 + >= info.expected_size_bytes as f64 * DOWNLOAD_COMPLETE_THRESHOLD;
845 +
846 + SupportedHfModel {
847 + model_id: info.id.to_string(),
848 + name: info.name.to_string(),
849 + org: info.org.to_string(),
850 + description: info.description.to_string(),
851 + is_downloaded: has_cache && is_complete,
852 + is_incomplete: has_cache && !is_complete,
853 + local_size_bytes: local_size,
854 + local_size_display: format_size(local_size),
855 + expected_size_bytes: info.expected_size_bytes,
856 + expected_size_display: format_size(info.expected_size_bytes),
857 + }
858 + })
859 + .collect();
860 +
861 + SupportedHfModelsResponse { models }
862 +}
863 +
864 +// ---------------------------------------------------------------------------
865 +// Model download — platform-specific implementations
866 +// ---------------------------------------------------------------------------
867 +//
868 +// The download function accepts a generic progress callback so that callers
869 +// can forward progress to any event system without coupling to this crate.
870 +//
871 +// Callback signature: `Fn(ModelDownloadProgress) + Send + Sync + Clone + 'static`
872 +// - Called every ~2 s from a native monitor thread.
873 +// - Called once with `done: true` after the build completes.
874 +
875 +// ── Apple (macOS + iOS): Metal-accelerated, all model types ─────────────────
876 +
877 +#[cfg(any(target_os = "macos", target_os = "ios"))]
878 +pub async fn download_model<F>(
879 + model_id: String,
880 + on_progress: F,
881 + app_data_dir: Option<PathBuf>,
882 +) -> Result<(), String>
883 +where
884 + F: Fn(ModelDownloadProgress) + Send + Sync + Clone + 'static,
885 +{
886 + use crate::inference::models::{
887 + BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF, BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF, BFL_FLUX_1_SCHNELL,
888 + GOOGLE_GEMMA_3N_E2B_IT, GOOGLE_GEMMA_3N_E4B_IT, MICROSOFT_PHI_35_MINI_INSTRUCT,
889 + QWEN25_1_5B_GGUF_FILE, QWEN25_3B_GGUF_FILE,
890 + };
891 + use crate::inference::token::hf_token_source;
892 + use mistralrs::{
893 + DiffusionLoaderType, DiffusionModelBuilder, GgufModelBuilder, IsqType, ModelDType,
894 + TextModelBuilder, VisionModelBuilder,
895 + };
896 + use std::sync::{
897 + atomic::{AtomicBool, Ordering},
898 + Arc,
899 + };
900 + use std::time::Duration;
901 +
902 + // When app_data_dir is provided, seed the HF env vars so that hf-hub,
903 + // mistral.rs, and hf_cache_dir() all write inside the app's writable
904 + // container. This is required on every sandboxed platform:
905 + // - iOS: ~/.cache is outside the container (os error 1).
906 + // - macOS App Store: the app is sandboxed, ~/.cache is inaccessible.
907 + // It is harmless on non-sandboxed desktop builds (the cache simply
908 + // lives under the app data dir instead of ~/.cache).
909 + if let Some(ref data_dir) = app_data_dir {
910 + let hf_home = data_dir.join("huggingface");
911 + let hf_hub_cache = hf_home.join("hub");
912 + fs::create_dir_all(&hf_hub_cache)
913 + .map_err(|e| format!("Cannot create HF cache dir: {e}"))?;
914 + std::env::set_var("HF_HUB_CACHE", &hf_hub_cache);
915 + std::env::set_var("HF_HOME", &hf_home);
916 + info!(
917 + "HF hub cache resolved to app data path: {}",
918 + hf_hub_cache.display()
919 + );
920 + }
921 +
922 + if !SUPPORTED_MODELS.contains(&model_id.as_str()) {
923 + return Err(format!("Model {} is not supported.", model_id));
924 + }
925 +
926 + let expected_size = SUPPORTED_MODEL_INFO
927 + .iter()
928 + .find(|m| m.id == model_id)
929 + .map(|m| m.expected_size_bytes)
930 + .unwrap_or(0);
931 +
932 + info!(
933 + "Starting download for model: {} (expected ~{})",
934 + model_id,
935 + format_size(expected_size)
936 + );
937 +
938 + clean_stale_lock_files(&model_id);
939 + repair_hf_cache_symlinks(&model_id);
940 + ensure_model_cache_dir(&model_id);
941 +
942 + // Emit an initial progress event based on the actual cache size so that
943 + // resumed downloads don't visually restart from 0%.
944 + let initial_bytes = model_cache_path(&model_id)
945 + .filter(|p| p.exists())
946 + .map(|p| dir_size(&p))
947 + .unwrap_or(0);
948 + on_progress(make_progress(
949 + &model_id,
950 + initial_bytes,
951 + expected_size,
952 + false,
953 + ));
954 +
955 + // Shared flag so the monitor task knows when to stop.
956 + let finished = Arc::new(AtomicBool::new(false));
957 + let finished_clone = Arc::clone(&finished);
958 + let monitor_model_id = model_id.clone();
959 + let monitor_cb = on_progress.clone();
960 +
961 + // Spawn a native OS thread to poll the cache directory size every 2 seconds.
962 + // We use std::thread instead of tokio::spawn because the model builder's
963 + // .build().await internally calls the synchronous hf-hub API (api.get()),
964 + // which blocks the tokio worker thread. This starves any tokio-spawned
965 + // monitor tasks, preventing progress updates. A native thread runs
966 + // independently of the tokio runtime and is immune to this starvation.
967 + let monitor_handle = std::thread::spawn(move || loop {
968 + std::thread::sleep(Duration::from_secs(2));
969 +
970 + if finished_clone.load(Ordering::Relaxed) {
971 + break;
972 + }
973 +
974 + let current_bytes = model_cache_path(&monitor_model_id)
975 + .filter(|p| p.exists())
976 + .map(|p| dir_size(&p))
977 + .unwrap_or(0);
978 +
979 + monitor_cb(make_progress(
980 + &monitor_model_id,
981 + current_bytes,
982 + expected_size,
983 + false,
984 + ));
985 + });
986 +
987 + // Build (and immediately drop) the model using the correct builder for
988 + // each model type. Building triggers the HuggingFace hub download.
989 + let result: Result<mistralrs::Model, anyhow::Error> = match model_id.as_str() {
990 + BFL_FLUX_1_SCHNELL => {
991 + DiffusionModelBuilder::new(&model_id, DiffusionLoaderType::FluxOffloaded)
992 + .with_token_source(hf_token_source())
993 + .build()
994 + .await
995 + }
996 + GOOGLE_GEMMA_3N_E2B_IT => {
997 + VisionModelBuilder::new(&model_id)
998 + .with_token_source(hf_token_source())
999 + .with_isq(IsqType::Q4K)
1000 + .build()
1001 + .await
1002 + }
1003 + GOOGLE_GEMMA_3N_E4B_IT => {
1004 + VisionModelBuilder::new(&model_id)
1005 + .with_token_source(hf_token_source())
1006 + .with_dtype(ModelDType::F16)
1007 + .build()
1008 + .await
1009 + }
1010 + MICROSOFT_PHI_35_MINI_INSTRUCT => {
1011 + TextModelBuilder::new(&model_id)
1012 + .with_token_source(hf_token_source())
1013 + .with_isq(IsqType::Q4K)
1014 + .build()
1015 + .await
1016 + }
1017 + BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF => {
1018 + GgufModelBuilder::new(&model_id, vec![QWEN25_1_5B_GGUF_FILE])
1019 + .with_token_source(hf_token_source())
1020 + .build()
1021 + .await
1022 + }
1023 + BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF => {
1024 + GgufModelBuilder::new(&model_id, vec![QWEN25_3B_GGUF_FILE])
1025 + .with_token_source(hf_token_source())
1026 + .build()
1027 + .await
1028 + }
1029 + _ => {
1030 + DiffusionModelBuilder::new(&model_id, DiffusionLoaderType::FluxOffloaded)
1031 + .with_token_source(hf_token_source())
1032 + .build()
1033 + .await
1034 + }
1035 + };
1036 +
1037 + finished.store(true, Ordering::Relaxed);
1038 + let _ = monitor_handle.join();
1039 +
1040 + match result {
1041 + Ok(_model) => {
1042 + let final_bytes = model_cache_path(&model_id)
1043 + .filter(|p| p.exists())
1044 + .map(|p| dir_size(&p))
1045 + .unwrap_or(expected_size);
1046 + on_progress(make_progress(&model_id, final_bytes, final_bytes, true));
1047 + info!("Successfully downloaded model: {}", model_id);
1048 + Ok(())
1049 + }
1050 + Err(e) => {
1051 + let msg = format!("Failed to download model {}: {}", model_id, e);
1052 + warn!("{}", msg);
1053 + Err(msg)
1054 + }
1055 + }
1056 +}
1057 +
1058 +// ── Android: GGUF-only download ───────────────────────────────────────────
1059 +//
1060 +// On Android there is no Metal GPU, so only pre-quantized GGUF models
1061 +// (CPU inference via candle) are supported. We mirror the Apple
1062 +// implementation but restrict to GGUF presets and skip all Metal / ISQ
1063 +// model builders.
1064 +//
1065 +// `app_data_dir` is **required** on Android: `dirs::home_dir()` returns
1066 +// `None` inside the Android sandbox, which causes `hf_hub::Cache::default()`
1067 +// to panic. The caller resolves the app data directory and passes it here.
1068 +
1069 +#[cfg(target_os = "android")]
1070 +pub async fn download_model<F>(
1071 + model_id: String,
1072 + on_progress: F,
1073 + app_data_dir: Option<PathBuf>,
1074 +) -> Result<(), String>
1075 +where
1076 + F: Fn(ModelDownloadProgress) + Send + Sync + Clone + 'static,
1077 +{
1078 + use crate::inference::models::{
1079 + BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF, BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF,
1080 + QWEN25_1_5B_GGUF_FILE, QWEN25_1_5B_TOK_MODEL_ID, QWEN25_3B_GGUF_FILE,
1081 + QWEN25_3B_TOK_MODEL_ID,
1082 + };
1083 + use crate::inference::token::hf_token_source;
1084 + use hf_hub::Cache;
1085 + use mistralrs::GgufModelBuilder;
1086 + use mistralrs_core::GLOBAL_HF_CACHE;
1087 + use std::sync::{
1088 + atomic::{AtomicBool, Ordering},
1089 + Arc,
1090 + };
1091 + use std::time::Duration;
1092 +
1093 + let (gguf_file, tok_model_id) = match model_id.as_str() {
1094 + id if id == BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF => {
1095 + (QWEN25_1_5B_GGUF_FILE, QWEN25_1_5B_TOK_MODEL_ID)
1096 + }
1097 + id if id == BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF => {
1098 + (QWEN25_3B_GGUF_FILE, QWEN25_3B_TOK_MODEL_ID)
1099 + }
1100 + _ => {
1101 + return Err(format!(
1102 + "Model '{}' is not supported on Android. \
1103 + Only Qwen 2.5 1.5B or 3B (GGUF) are available.",
1104 + model_id
1105 + ));
1106 + }
1107 + };
1108 +
1109 + // ── Resolve the HF cache path ─────────────────────────────────────────
1110 + //
1111 + // `app_data_dir` is required on Android — `dirs::home_dir()` returns None
1112 + // in the Android sandbox and causes Cache::default() to panic.
1113 + let resolved_app_data = app_data_dir
1114 + .ok_or_else(|| "app_data_dir is required on Android for HF cache resolution".to_string())?;
1115 +
1116 + let hf_home = resolved_app_data.join("huggingface");
1117 + let hf_hub_cache = hf_home.join("hub");
1118 +
1119 + fs::create_dir_all(&hf_hub_cache)
1120 + .map_err(|e| format!("Failed to create HF hub cache dir: {e}"))?;
1121 +
1122 + // Seed GLOBAL_HF_CACHE so get_paths_gguf! never falls back to Cache::default().
1123 + GLOBAL_HF_CACHE.get_or_init(|| Cache::new(hf_hub_cache.clone()));
1124 +
1125 + // Keep env vars in sync so hf_hub_cache_dir() and hf_cache_dir() agree.
1126 + std::env::set_var("HF_HUB_CACHE", &hf_hub_cache);
1127 + std::env::set_var("HF_HOME", &hf_home);
1128 +
1129 + info!(
1130 + "Android HF hub cache resolved to: {}",
1131 + hf_hub_cache.display()
1132 + );
1133 +
1134 + let expected_size = SUPPORTED_MODEL_INFO
1135 + .iter()
1136 + .find(|m| m.id == model_id)
1137 + .map(|m| m.expected_size_bytes)
1138 + .unwrap_or(0);
1139 +
1140 + info!(
1141 + "Starting Android download for model: {} (expected ~{})",
1142 + model_id,
1143 + format_size(expected_size)
1144 + );
1145 +
1146 + clean_stale_lock_files(&model_id);
1147 + ensure_model_cache_dir(&model_id);
1148 +
1149 + let initial_bytes = model_cache_path(&model_id)
1150 + .filter(|p| p.exists())
1151 + .map(|p| dir_size(&p))
1152 + .unwrap_or(0);
1153 + on_progress(make_progress(
1154 + &model_id,
1155 + initial_bytes,
1156 + expected_size,
1157 + false,
1158 + ));
1159 +
1160 + // Native monitor thread — same reasoning as the Apple implementation.
1161 + let finished = Arc::new(AtomicBool::new(false));
1162 + let finished_clone = Arc::clone(&finished);
1163 + let monitor_model_id = model_id.clone();
1164 + let monitor_cb = on_progress.clone();
1165 +
1166 + let monitor_handle = std::thread::spawn(move || loop {
1167 + std::thread::sleep(Duration::from_secs(2));
1168 + if finished_clone.load(Ordering::Relaxed) {
1169 + break;
1170 + }
1171 + let current_bytes = model_cache_path(&monitor_model_id)
1172 + .filter(|p| p.exists())
1173 + .map(|p| dir_size(&p))
1174 + .unwrap_or(0);
1175 + monitor_cb(make_progress(
1176 + &monitor_model_id,
1177 + current_bytes,
1178 + expected_size,
1179 + false,
1180 + ));
1181 + });
1182 +
1183 + let result = GgufModelBuilder::new(&model_id, vec![gguf_file])
1184 + .with_tok_model_id(tok_model_id)
1185 + .with_token_source(hf_token_source())
1186 + .with_logging()
1187 + .build()
1188 + .await;
1189 +
1190 + finished.store(true, Ordering::Relaxed);
1191 + let _ = monitor_handle.join();
1192 +
1193 + match result {
1194 + Ok(_model) => {
1195 + let final_bytes = model_cache_path(&model_id)
1196 + .filter(|p| p.exists())
1197 + .map(|p| dir_size(&p))
1198 + .unwrap_or(expected_size);
1199 + on_progress(make_progress(&model_id, final_bytes, final_bytes, true));
1200 + info!("Successfully downloaded model on Android: {}", model_id);
1201 + Ok(())
1202 + }
1203 + Err(e) => {
1204 + let msg = format!("Failed to download model {}: {}", model_id, e);
1205 + warn!("{}", msg);
1206 + Err(msg)
1207 + }
1208 + }
1209 +}
1210 +
1211 +// ── Other platforms: no-op ────────────────────────────────────────────────
1212 +
1213 +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
1214 +pub async fn download_model<F>(
1215 + model_id: String,
1216 + _on_progress: F,
1217 + _app_data_dir: Option<PathBuf>,
1218 +) -> Result<(), String>
1219 +where
1220 + F: Fn(ModelDownloadProgress) + Send + Sync + Clone + 'static,
1221 +{
1222 + debug!(
1223 + "download_model: not supported on this platform, ignoring request for {}.",
1224 + model_id
1225 + );
1226 + Err(format!(
1227 + "Model downloads are not supported on this platform (requested: {}).",
1228 + model_id
1229 + ))
1230 +}
src/inference/engine.rs new
+1213
@@ -0,0 +1,1213 @@
1 +//! On-device LLM chat inference engine powered by [mistral.rs](https://github.com/EricLBuehler/mistral.rs).
2 +//!
3 +//! `ChatEngine` provides a high-level, framework-agnostic API for:
4 +//!
5 +//! - Loading GGUF-quantized models (the primary format for mobile/desktop)
6 +//! - Multi-turn chat with conversation history management
7 +//! - Both blocking (non-streaming) and streaming inference
8 +//! - Model lifecycle management (load / unload / status)
9 +//!
10 +//! # Architecture
11 +//!
12 +//! ```text
13 +//! ┌──────────────────────────────────────────┐
14 +//! │ App / UniFFI binding / test │
15 +//! └──────────────┬───────────────────────────┘
16 +//! │ (framework-agnostic API)
17 +//! ▼
18 +//! ┌──────────────────────────────────────────┐
19 +//! │ ChatEngine │
20 +//! │ ┌────────────────────────────────────┐ │
21 +//! │ │ Mutex<Option<LoadedModel>> │ │
22 +//! │ │ · Arc<mistralrs::Model> │ │
23 +//! │ │ · config (GgufModelConfig) │ │
24 +//! │ │ · history (Vec<ChatMessage>) │ │
25 +//! │ │ · sampling (SamplingConfig) │ │
26 +//! │ └────────────────────────────────────┘ │
27 +//! └──────────────┬───────────────────────────┘
28 +//! │ (delegates to)
29 +//! ▼
30 +//! ┌──────────────────────────────────────────┐
31 +//! │ mistralrs::Model │
32 +//! │ (wraps Arc<MistralRs> engine thread) │
33 +//! └──────────────────────────────────────────┘
34 +//! ```
35 +//!
36 +//! # Example
37 +//!
38 +//! ```rust,ignore
39 +//! use onde::inference::engine::ChatEngine;
40 +//! use onde::inference::types::*;
41 +//!
42 +//! let engine = ChatEngine::new();
43 +//!
44 +//! let config = GgufModelConfig {
45 +//! model_id: "bartowski/Qwen2.5-1.5B-Instruct-GGUF".into(),
46 +//! files: vec!["Qwen2.5-1.5B-Instruct-Q4_K_M.gguf".into()],
47 +//! tok_model_id: None,
48 +//! display_name: "Qwen 2.5 1.5B".into(),
49 +//! approx_memory: "~941 MB".into(),
50 +//! };
51 +//!
52 +//! engine.load_gguf_model(config, None).await?;
53 +//! engine.set_system_prompt("You are a helpful assistant.");
54 +//!
55 +//! let result = engine.send_message("Hello!").await?;
56 +//! println!("{}", result.text);
57 +//! ```
58 +
59 +#[cfg(any(
60 + target_os = "macos",
61 + target_os = "ios",
62 + target_os = "tvos",
63 + target_os = "windows",
64 + target_os = "linux",
65 + target_os = "android"
66 +))]
67 +use std::sync::Arc;
68 +
69 +#[cfg(any(
70 + target_os = "macos",
71 + target_os = "ios",
72 + target_os = "tvos",
73 + target_os = "windows",
74 + target_os = "linux",
75 + target_os = "android"
76 +))]
77 +use tokio::sync::Mutex;
78 +
79 +use super::types::*;
80 +
81 +// ── Platform-gated mistralrs imports ─────────────────────────────────────────
82 +
83 +#[cfg(any(
84 + target_os = "macos",
85 + target_os = "ios",
86 + target_os = "tvos",
87 + target_os = "windows",
88 + target_os = "linux",
89 + target_os = "android"
90 +))]
91 +use mistralrs::{
92 + GgufModelBuilder, IsqBits, Model, RequestBuilder, TextMessageRole, TextModelBuilder,
93 +};
94 +
95 +// ── Internals ────────────────────────────────────────────────────────────────
96 +
97 +/// How a model was loaded — carries the data needed for status reporting.
98 +#[cfg(any(
99 + target_os = "macos",
100 + target_os = "ios",
101 + target_os = "tvos",
102 + target_os = "windows",
103 + target_os = "linux",
104 + target_os = "android"
105 +))]
106 +enum LoadedModelConfig {
107 + Gguf(GgufModelConfig),
108 + Isq(IsqModelConfig),
109 +}
110 +
111 +#[cfg(any(
112 + target_os = "macos",
113 + target_os = "ios",
114 + target_os = "tvos",
115 + target_os = "windows",
116 + target_os = "linux",
117 + target_os = "android"
118 +))]
119 +impl LoadedModelConfig {
120 + fn display_name(&self) -> &str {
121 + match self {
122 + LoadedModelConfig::Gguf(c) => &c.display_name,
123 + LoadedModelConfig::Isq(c) => &c.display_name,
124 + }
125 + }
126 +
127 + fn approx_memory(&self) -> &str {
128 + match self {
129 + LoadedModelConfig::Gguf(c) => &c.approx_memory,
130 + LoadedModelConfig::Isq(c) => &c.approx_memory,
131 + }
132 + }
133 +}
134 +
135 +/// State of a loaded model held inside the engine's mutex.
136 +#[cfg(any(
137 + target_os = "macos",
138 + target_os = "ios",
139 + target_os = "tvos",
140 + target_os = "windows",
141 + target_os = "linux",
142 + target_os = "android"
143 +))]
144 +struct LoadedModel {
145 + /// The mistral.rs model handle. `Model` wraps `Arc<MistralRs>` so
146 + /// cloning is a cheap pointer copy — safe to snapshot before inference
147 + /// while releasing the mutex.
148 + model: Arc<Model>,
149 + /// Configuration used to load this model (kept for status reporting).
150 + config: LoadedModelConfig,
151 + /// Conversation history (system prompt is stored separately).
152 + history: Vec<ChatMessage>,
153 + /// System prompt prepended to every request.
154 + system_prompt: Option<String>,
155 + /// Sampling parameters for generation.
156 + sampling: SamplingConfig,
157 +}
158 +
159 +// ═════════════════════════════════════════════════════════════════════════════
160 +// ChatEngine — the public API
161 +// ═════════════════════════════════════════════════════════════════════════════
162 +
163 +/// A reusable on-device LLM chat inference engine.
164 +///
165 +/// Thread-safe (`Send + Sync`) — safe to store in a `once_cell::sync::Lazy`,
166 +/// `tokio::sync::OnceCell`, or shared application state.
167 +///
168 +/// All mutating operations acquire an internal `tokio::sync::Mutex`. The
169 +/// mutex is released *before* the actual (potentially slow) model inference
170 +/// runs, so other tasks can still query status or history while generation
171 +/// is in progress.
172 +#[cfg(any(
173 + target_os = "macos",
174 + target_os = "ios",
175 + target_os = "tvos",
176 + target_os = "windows",
177 + target_os = "linux",
178 + target_os = "android"
179 +))]
180 +pub struct ChatEngine {
181 + inner: Mutex<Option<LoadedModel>>,
182 +}
183 +
184 +#[cfg(any(
185 + target_os = "macos",
186 + target_os = "ios",
187 + target_os = "tvos",
188 + target_os = "windows",
189 + target_os = "linux",
190 + target_os = "android"
191 +))]
192 +impl ChatEngine {
193 + // ── Construction ─────────────────────────────────────────────────────
194 +
195 + /// Create a new engine with no model loaded.
196 + pub fn new() -> Self {
197 + Self {
198 + inner: Mutex::new(None),
199 + }
200 + }
201 +
202 + // ── Model lifecycle ──────────────────────────────────────────────────
203 +
204 + /// Load a GGUF model into the engine.
205 + ///
206 + /// If a model is already loaded it will be unloaded first (the previous
207 + /// `Model` is dropped, which terminates its engine thread).
208 + ///
209 + /// # Arguments
210 + ///
211 + /// * `config` — Which model to load (repo ID, filename, etc.).
212 + /// * `system_prompt` — Optional system prompt to prepend to every request.
213 + /// * `sampling` — Sampling parameters; pass `None` for platform-aware
214 + /// defaults (mobile gets [`SamplingConfig::mobile`],
215 + /// desktop gets [`SamplingConfig::default`]).
216 + ///
217 + /// # Errors
218 + ///
219 + /// Returns [`InferenceError::ModelBuild`] if the model fails to download
220 + /// or load.
221 + pub async fn load_gguf_model(
222 + &self,
223 + config: GgufModelConfig,
224 + system_prompt: Option<String>,
225 + sampling: Option<SamplingConfig>,
226 + ) -> Result<std::time::Duration, InferenceError> {
227 + use log::info;
228 + use std::time::Instant;
229 +
230 + info!(
231 + "ChatEngine: loading GGUF model {} (files: {:?})",
232 + config.model_id, config.files
233 + );
234 +
235 + // ── Android: seed GLOBAL_HF_CACHE ────────────────────────────────
236 + //
237 + // On Android, `dirs::home_dir()` returns `None`, so
238 + // `hf_hub::Cache::default()` panics with "Cache directory cannot be
239 + // found". The `get_paths_gguf!` macro in mistralrs falls back to
240 + // `Cache::default()` when `GLOBAL_HF_CACHE` (a OnceLock) is empty.
241 + //
242 + // `HF_HOME` is always set by `setup_hf_home()` before any command
243 + // runs, so we read it here. `get_or_init` is a no-op if already
244 + // seeded by `download_model` — safe to call repeatedly.
245 + #[cfg(target_os = "android")]
246 + {
247 + let hf_home = std::env::var("HF_HOME")
248 + .map(std::path::PathBuf::from)
249 + .map_err(|_| InferenceError::ModelBuild {
250 + reason: "HF_HOME is not set — cannot initialise HF cache on Android. \
251 + Ensure setup_hf_home() ran before load_gguf_model()."
252 + .to_string(),
253 + })?;
254 + let hf_hub_cache = hf_home.join("hub");
255 + if let Err(e) = std::fs::create_dir_all(&hf_hub_cache) {
256 + log::warn!(
257 + "ChatEngine: could not create HF hub cache dir {}: {}",
258 + hf_hub_cache.display(),
259 + e
260 + );
261 + }
262 + mistralrs_core::GLOBAL_HF_CACHE
263 + .get_or_init(|| hf_hub::Cache::new(hf_hub_cache.clone()));
264 + std::env::set_var("HF_HUB_CACHE", &hf_hub_cache);
265 + log::debug!(
266 + "ChatEngine: GLOBAL_HF_CACHE seeded at {}",
267 + hf_hub_cache.display()
268 + );
269 + }
270 +
271 + // Clean up stale HF cache artefacts before loading.
272 + crate::hf_cache::clean_stale_lock_files(&config.model_id);
273 + crate::hf_cache::repair_hf_cache_symlinks(&config.model_id);
274 +
275 + let start = Instant::now();
276 +
277 + let mut builder = GgufModelBuilder::new(&config.model_id, config.files.clone())
278 + .with_token_source(super::token::hf_token_source())
279 + .with_logging();
280 +
281 + // On Android the GGUF embedded tokenizer is not supported by the
282 + // candle backend — an explicit tok_model_id is required.
283 + if let Some(ref tok_id) = config.tok_model_id {
284 + builder = builder.with_tok_model_id(tok_id);
285 + }
286 +
287 + let model = builder
288 + .build()
289 + .await
290 + .map_err(|e| InferenceError::ModelBuild {
291 + reason: format!("Failed to build {} model: {}", config.display_name, e),
292 + })?;
293 +
294 + let elapsed = start.elapsed();
295 +
296 + let sampling = sampling.unwrap_or_else(|| {
297 + if cfg!(any(
298 + target_os = "ios",
299 + target_os = "tvos",
300 + target_os = "android"
301 + )) {
302 + SamplingConfig::mobile()
303 + } else {
304 + SamplingConfig::default()
305 + }
306 + });
307 +
308 + info!(
309 + "ChatEngine: model {} loaded in {} (sampling: temp={:?}, max_tokens={:?})",
310 + config.display_name,
311 + format_duration(elapsed),
312 + sampling.temperature,
313 + sampling.max_tokens,
314 + );
315 +
316 + let mut guard = self.inner.lock().await;
317 + *guard = Some(LoadedModel {
318 + model: Arc::new(model),
319 + config: LoadedModelConfig::Gguf(config),
320 + history: Vec::new(),
321 + system_prompt,
322 + sampling,
323 + });
324 +
325 + Ok(elapsed)
326 + }
327 +
328 + /// Load an ISQ (in-situ quantised) model into the engine.
329 + ///
330 + /// Unlike [`load_gguf_model`], this downloads the full-precision safetensors
331 + /// from HuggingFace and quantises the weights in-situ on Metal (macOS only).
332 + /// The quantisation happens once at load time; subsequent inference uses the
333 + /// compressed weights.
334 + ///
335 + /// # macOS only
336 + ///
337 + /// ISQ with Metal requires the `metal` feature on mistral.rs and is therefore
338 + /// restricted to macOS at the Rust level. Other platforms should continue to
339 + /// use [`load_gguf_model`] with pre-quantised GGUF files.
340 + ///
341 + /// # Arguments
342 + ///
343 + /// * `config` — Which model to load and with how many ISQ bits.
344 + /// * `system_prompt` — Optional system prompt prepended to every request.
345 + /// * `sampling` — Sampling parameters; `None` uses [`SamplingConfig::default`].
346 + ///
347 + /// # Errors
348 + ///
349 + /// Returns [`InferenceError::ModelBuild`] if the model fails to download
350 + /// or quantise.
351 + #[cfg(target_os = "macos")]
352 + pub async fn load_isq_model(
353 + &self,
354 + config: IsqModelConfig,
355 + system_prompt: Option<String>,
356 + sampling: Option<SamplingConfig>,
357 + ) -> Result<std::time::Duration, InferenceError> {
358 + use log::info;
359 + use std::time::Instant;
360 +
361 + info!(
362 + "ChatEngine: loading ISQ model {} (bits={})",
363 + config.model_id, config.isq_bits
364 + );
365 +
366 + // Clean up stale HF cache artefacts before loading.
367 + crate::hf_cache::clean_stale_lock_files(&config.model_id);
368 + crate::hf_cache::repair_hf_cache_symlinks(&config.model_id);
369 +
370 + let start = Instant::now();
371 +
372 + // Choose ISQ bit width.
373 + let isq_bits = match config.isq_bits {
374 + 8 => IsqBits::Eight,
375 + _ => IsqBits::Four, // default to 4-bit
376 + };
377 +
378 + let model = TextModelBuilder::new(&config.model_id)
379 + .with_token_source(super::token::hf_token_source())
380 + .with_auto_isq(isq_bits)
381 + .with_logging()
382 + .build()
383 + .await
384 + .map_err(|e| InferenceError::ModelBuild {
385 + reason: format!("Failed to build ISQ model {}: {}", config.display_name, e),
386 + })?;
387 +
388 + let elapsed = start.elapsed();
389 +
390 + let sampling = sampling.unwrap_or_else(SamplingConfig::default);
391 +
392 + info!(
393 + "ChatEngine: ISQ model {} loaded in {} (sampling: temp={:?}, max_tokens={:?})",
394 + config.display_name,
395 + format_duration(elapsed),
396 + sampling.temperature,
397 + sampling.max_tokens,
398 + );
399 +
400 + let mut guard = self.inner.lock().await;
401 + *guard = Some(LoadedModel {
402 + model: Arc::new(model),
403 + config: LoadedModelConfig::Isq(config),
404 + history: Vec::new(),
405 + system_prompt,
406 + sampling,
407 + });
408 +
409 + Ok(elapsed)
410 + }
411 +
412 + /// Unload the current model, freeing all memory.
413 + ///
414 + /// Dropping the `Model` sends a `Terminate` message to the mistral.rs
415 + /// engine thread, which tears down the KV cache, activations, and model
416 + /// weights.
417 + ///
418 + /// Returns the display name of the model that was unloaded, or `None`
419 + /// if no model was loaded.
420 + pub async fn unload_model(&self) -> Option<String> {
421 + let mut guard = self.inner.lock().await;
422 + if let Some(loaded) = guard.take() {
423 + let name = loaded.config.display_name().to_string();
424 + log::info!("ChatEngine: unloading model {}", name);
425 + // `loaded` is dropped here → Model → Arc<MistralRs> (last ref)
426 + // → MistralRs::drop() → engine thread termination.
427 + Some(name)
428 + } else {
429 + log::debug!("ChatEngine: unload_model called but no model was loaded.");
430 + None
431 + }
432 + }
433 +
434 + /// Check whether a model is currently loaded.
435 + pub async fn is_loaded(&self) -> bool {
436 + self.inner.lock().await.is_some()
437 + }
438 +
439 + /// Get a snapshot of the engine's current state.
440 + pub async fn info(&self) -> EngineInfo {
441 + let guard = self.inner.lock().await;
442 + match guard.as_ref() {
443 + Some(loaded) => EngineInfo {
444 + status: EngineStatus::Ready,
445 + model_name: Some(loaded.config.display_name().to_string()),
446 + approx_memory: Some(loaded.config.approx_memory().to_string()),
447 + history_length: loaded.history.len() as u64,
448 + },
449 + None => EngineInfo {
450 + status: EngineStatus::Unloaded,
451 + model_name: None,
452 + approx_memory: None,
453 + history_length: 0u64,
454 + },
455 + }
456 + }
457 +
458 + // ── System prompt ────────────────────────────────────────────────────
459 +
460 + /// Set or replace the system prompt.
461 + ///
462 + /// The system prompt is prepended to every inference request (it is NOT
463 + /// stored in the conversation history).
464 + pub async fn set_system_prompt(&self, prompt: impl Into<String>) {
465 + if let Some(loaded) = self.inner.lock().await.as_mut() {
466 + loaded.system_prompt = Some(prompt.into());
467 + }
468 + }
469 +
470 + /// Clear the system prompt.
471 + pub async fn clear_system_prompt(&self) {
472 + if let Some(loaded) = self.inner.lock().await.as_mut() {
473 + loaded.system_prompt = None;
474 + }
475 + }
476 +
477 + // ── Sampling configuration ───────────────────────────────────────────
478 +
479 + /// Replace the sampling configuration.
480 + pub async fn set_sampling(&self, sampling: SamplingConfig) {
481 + if let Some(loaded) = self.inner.lock().await.as_mut() {
482 + loaded.sampling = sampling;
483 + }
484 + }
485 +
486 + // ── Conversation history ─────────────────────────────────────────────
487 +
488 + /// Get a clone of the full conversation history.
489 + pub async fn history(&self) -> Vec<ChatMessage> {
490 + let guard = self.inner.lock().await;
491 + match guard.as_ref() {
492 + Some(loaded) => loaded.history.clone(),
493 + None => Vec::new(),
494 + }
495 + }
496 +
497 + /// Clear the conversation history but keep the model loaded.
498 + ///
499 + /// Returns the number of turns that were removed.
500 + pub async fn clear_history(&self) -> usize {
501 + let mut guard = self.inner.lock().await;
502 + match guard.as_mut() {
503 + Some(loaded) => {
504 + let count = loaded.history.len();
505 + loaded.history.clear();
506 + log::info!("ChatEngine: cleared {} history turns.", count);
507 + count
508 + }
509 + None => 0,
510 + }
511 + }
512 +
513 + /// Append a message to history without running inference.
514 + ///
515 + /// Useful for restoring a saved conversation or injecting context.
516 + pub async fn push_history(&self, message: ChatMessage) {
517 + if let Some(loaded) = self.inner.lock().await.as_mut() {
518 + loaded.history.push(message);
519 + }
520 + }
521 +
522 + // ── Non-streaming inference ──────────────────────────────────────────
523 +
524 + /// Send a user message and receive a complete assistant reply.
525 + ///
526 + /// The user message and assistant reply are automatically appended to
527 + /// the conversation history on success.
528 + ///
529 + /// # Errors
530 + ///
531 + /// - [`InferenceError::NoModelLoaded`] if no model is loaded.
532 + /// - [`InferenceError::Inference`] if the model fails to generate.
533 + pub async fn send_message(
534 + &self,
535 + user_message: impl Into<String>,
536 + ) -> Result<InferenceResult, InferenceError> {
537 + let user_message = user_message.into();
538 +
539 + // ── 1. Snapshot model handle + build request, then release lock ──
540 + let (model, request) = {
541 + let guard = self.inner.lock().await;
542 + let loaded = guard.as_ref().ok_or(InferenceError::NoModelLoaded)?;
543 + let request = self::build_request(loaded, &user_message);
544 + (loaded.model.clone(), request)
545 + }; // ← mutex released before inference
546 +
547 + log::info!(
548 + "ChatEngine: inference START — message: \"{}\"",
549 + truncate_for_log(&user_message, 100)
550 + );
551 +
552 + // ── 2. Run inference (potentially slow — mutex is NOT held) ──────
553 + let start = std::time::Instant::now();
554 + let response =
555 + model
556 + .send_chat_request(request)
557 + .await
558 + .map_err(|e| InferenceError::Inference {
559 + reason: e.to_string(),
560 + })?;
561 + let elapsed = start.elapsed();
562 +
563 + let reply = response.choices[0]
564 + .message
565 + .content
566 + .as_ref()
567 + .map(|c: &String| c.trim().to_string())
568 + .unwrap_or_else(|| "(empty response)".to_string());
569 +
570 + let finish_reason = response.choices[0].finish_reason.clone();
571 +
572 + log::info!(
573 + "ChatEngine: inference END — {} — reply: \"{}\"",
574 + format_duration(elapsed),
575 + truncate_for_log(&reply, 100)
576 + );
577 +
578 + // ── 3. Persist turns to history (brief lock re-acquisition) ──────
579 + {
580 + let mut guard = self.inner.lock().await;
581 + if let Some(loaded) = guard.as_mut() {
582 + loaded.history.push(ChatMessage::user(user_message));
583 + loaded.history.push(ChatMessage::assistant(reply.clone()));
584 + }
585 + }
586 +
587 + Ok(InferenceResult {
588 + text: reply,
589 + duration_secs: elapsed.as_secs_f64(),
590 + duration_display: format_duration(elapsed),
591 + finish_reason,
592 + })
593 + }
594 +
595 + /// Run inference on an explicit list of messages WITHOUT modifying the
596 + /// engine's internal history.
597 + ///
598 + /// This is useful for one-shot prompts (e.g. prompt enhancement) where
599 + /// you don't want side-effects on the main conversation.
600 + ///
601 + /// The system prompt set on the engine is still prepended.
602 + pub async fn generate(
603 + &self,
604 + messages: Vec<ChatMessage>,
605 + sampling: Option<SamplingConfig>,
606 + ) -> Result<InferenceResult, InferenceError> {
607 + let (model, request) = {
608 + let guard = self.inner.lock().await;
609 + let loaded = guard.as_ref().ok_or(InferenceError::NoModelLoaded)?;
610 +
611 + let sampling = sampling.as_ref().unwrap_or(&loaded.sampling);
612 + let mut req = RequestBuilder::new();
613 +
614 + // Apply sampling parameters.
615 + req = apply_sampling(req, sampling);
616 +
617 + // System prompt.
618 + if let Some(ref sp) = loaded.system_prompt {
619 + req = req.add_message(TextMessageRole::System, sp);
620 + }
621 +
622 + // Provided messages.
623 + for msg in &messages {
624 + req = req.add_message(chat_role_to_mistral(&msg.role), &msg.content);
625 + }
626 +
627 + (loaded.model.clone(), req)
628 + };
629 +
630 + let start = std::time::Instant::now();
631 + let response =
632 + model
633 + .send_chat_request(request)
634 + .await
635 + .map_err(|e| InferenceError::Inference {
636 + reason: e.to_string(),
637 + })?;
638 + let elapsed = start.elapsed();
639 +
640 + let reply = response.choices[0]
641 + .message
642 + .content
643 + .as_ref()
644 + .map(|c: &String| c.trim().to_string())
645 + .unwrap_or_else(|| "(empty response)".to_string());
646 +
647 + let finish_reason = response.choices[0].finish_reason.clone();
648 +
649 + Ok(InferenceResult {
650 + text: reply,
651 + duration_secs: elapsed.as_secs_f64(),
652 + duration_display: format_duration(elapsed),
653 + finish_reason,
654 + })
655 + }
656 +
657 + // ── Streaming inference ──────────────────────────────────────────────
658 +
659 + /// Send a user message and receive an async stream of token chunks.
660 + ///
661 + /// The user message and full assembled reply are automatically appended
662 + /// to the conversation history once the stream finishes.
663 + ///
664 + /// # Returns
665 + ///
666 + /// A `tokio::sync::mpsc::Receiver<StreamChunk>`. The caller should
667 + /// receive from it until `chunk.done == true` or the channel closes.
668 + ///
669 + /// # Errors
670 + ///
671 + /// Returns immediately with [`InferenceError::NoModelLoaded`] if no
672 + /// model is loaded. Inference errors are delivered as the final chunk
673 + /// with `done = true` and an empty delta.
674 + pub async fn stream_message(
675 + &self,
676 + user_message: impl Into<String>,
677 + ) -> Result<tokio::sync::mpsc::Receiver<StreamChunk>, InferenceError> {
678 + let user_message = user_message.into();
679 +
680 + let (model, request) = {
681 + let guard = self.inner.lock().await;
682 + let loaded = guard.as_ref().ok_or(InferenceError::NoModelLoaded)?;
683 + let request = self::build_request(loaded, &user_message);
684 + (loaded.model.clone(), request)
685 + };
686 +
687 + let (tx, rx) = tokio::sync::mpsc::channel::<StreamChunk>(64);
688 +
689 + // We need a reference to `self` inside the spawned task so we can
690 + // update history when the stream completes. Since ChatEngine is
691 + // behind a shared reference (callers hold &self or Arc<ChatEngine>),
692 + // we borrow the inner Mutex via a raw pointer. This is safe because
693 + // ChatEngine's lifetime exceeds the spawned task (it's typically in
694 + // a Lazy static or shared application state).
695 + //
696 + // Alternative: require ChatEngine to always be wrapped in Arc and
697 + // accept `self: Arc<Self>`. We avoid that to keep the API simple.
698 + let inner_ptr = &self.inner as *const Mutex<Option<LoadedModel>>;
699 + // SAFETY: ChatEngine is stored in a Lazy static or equivalent with
700 + // 'static lifetime. The spawned task cannot outlive the engine.
701 + let inner_ref: &'static Mutex<Option<LoadedModel>> = unsafe { &*inner_ptr };
702 +
703 + let user_msg_clone = user_message.clone();
704 +
705 + tokio::task::spawn(async move {
706 + // `model` is an `Arc<Model>` moved into this task, so it's owned.
707 + // `stream_chat_request` borrows `&Model` — the borrow is scoped
708 + // to this async block and does NOT need to be `'static`.
709 + let stream_result = model.stream_chat_request(request).await;
710 +
711 + match stream_result {
712 + Ok(mut stream) => {
713 + let mut assembled = String::new();
714 + let mut last_finish_reason = None;
715 +
716 + // `Stream::next()` is an inherent async method on
717 + // mistralrs::Stream that returns `Option<Response>`.
718 + // No `futures::StreamExt` import needed.
719 + while let Some(response) = stream.next().await {
720 + match response {
721 + mistralrs::Response::Chunk(chunk) => {
722 + if let Some(choice) = chunk.choices.first() {
723 + if let Some(ref text) = choice.delta.content {
724 + assembled.push_str(text);
725 + let _ = tx
726 + .send(StreamChunk {
727 + delta: text.clone(),
728 + done: false,
729 + finish_reason: None,
730 + })
731 + .await;
732 + }
733 + if let Some(ref reason) = choice.finish_reason {
734 + last_finish_reason = Some(reason.clone());
735 + }
736 + }
737 + }
738 + mistralrs::Response::Done(_) => {
739 + // Non-streaming response arrived on a streaming
740 + // channel — should not happen, but handle gracefully.
741 + break;
742 + }
743 + mistralrs::Response::InternalError(e) => {
744 + log::error!("ChatEngine stream internal error: {}", e);
745 + break;
746 + }
747 + mistralrs::Response::ValidationError(e) => {
748 + log::error!("ChatEngine stream validation error: {}", e);
749 + break;
750 + }
751 + mistralrs::Response::ModelError(msg, _) => {
752 + log::error!("ChatEngine stream model error: {}", msg);
753 + break;
754 + }
755 + _ => {
756 + // Completion / Image / Speech variants — not expected
757 + // for chat streaming.
758 + break;
759 + }
760 + }
761 + }
762 +
763 + // Persist turns to history.
764 + {
765 + let mut guard = inner_ref.lock().await;
766 + if let Some(loaded) = guard.as_mut() {
767 + loaded.history.push(ChatMessage::user(user_msg_clone));
768 + loaded
769 + .history
770 + .push(ChatMessage::assistant(assembled.trim()));
771 + }
772 + }
773 +
774 + // Send the final "done" chunk.
775 + let _ = tx
776 + .send(StreamChunk {
777 + delta: String::new(),
778 + done: true,
779 + finish_reason: last_finish_reason,
780 + })
781 + .await;
782 + }
783 + Err(e) => {
784 + log::error!("ChatEngine: stream_chat_request failed: {}", e);
785 + let _ = tx
786 + .send(StreamChunk {
787 + delta: String::new(),
788 + done: true,
789 + finish_reason: Some(format!("error: {}", e)),
790 + })
791 + .await;
792 + }
793 + }
794 + });
795 +
796 + Ok(rx)
797 + }
798 +}
799 +
800 +// ═════════════════════════════════════════════════════════════════════════════
801 +// Default impl
802 +// ═════════════════════════════════════════════════════════════════════════════
803 +
804 +#[cfg(any(
805 + target_os = "macos",
806 + target_os = "ios",
807 + target_os = "tvos",
808 + target_os = "windows",
809 + target_os = "linux",
810 + target_os = "android"
811 +))]
812 +impl Default for ChatEngine {
813 + fn default() -> Self {
814 + Self::new()
815 + }
816 +}
817 +
818 +// ═════════════════════════════════════════════════════════════════════════════
819 +// Internal helpers (platform-gated)
820 +// ═════════════════════════════════════════════════════════════════════════════
821 +
822 +/// Build a `RequestBuilder` from the current engine state and a new user message.
823 +#[cfg(any(
824 + target_os = "macos",
825 + target_os = "ios",
826 + target_os = "tvos",
827 + target_os = "windows",
828 + target_os = "linux",
829 + target_os = "android"
830 +))]
831 +fn build_request(loaded: &LoadedModel, user_message: &str) -> RequestBuilder {
832 + let mut req = RequestBuilder::new();
833 +
834 + // Apply sampling.
835 + req = apply_sampling(req, &loaded.sampling);
836 +
837 + // System prompt.
838 + if let Some(ref sp) = loaded.system_prompt {
839 + req = req.add_message(TextMessageRole::System, sp);
840 + }
841 +
842 + // Replay conversation history for multi-turn context.
843 + for turn in &loaded.history {
844 + req = req.add_message(chat_role_to_mistral(&turn.role), &turn.content);
845 + }
846 +
847 + // Append the current user message.
848 + req = req.add_message(TextMessageRole::User, user_message);
849 +
850 + req
851 +}
852 +
853 +/// Apply a [`SamplingConfig`] to a [`RequestBuilder`].
854 +#[cfg(any(
855 + target_os = "macos",
856 + target_os = "ios",
857 + target_os = "tvos",
858 + target_os = "windows",
859 + target_os = "linux",
860 + target_os = "android"
861 +))]
862 +fn apply_sampling(mut req: RequestBuilder, sampling: &SamplingConfig) -> RequestBuilder {
863 + if let Some(temp) = sampling.temperature {
864 + req = req.set_sampler_temperature(temp);
865 + }
866 + if let Some(top_p) = sampling.top_p {
867 + req = req.set_sampler_topp(top_p);
868 + }
869 + if let Some(top_k) = sampling.top_k {
870 + req = req.set_sampler_topk(top_k as usize);
871 + }
872 + if let Some(min_p) = sampling.min_p {
873 + req = req.set_sampler_minp(min_p);
874 + }
875 + if let Some(max_tokens) = sampling.max_tokens {
876 + req = req.set_sampler_max_len(max_tokens as usize);
877 + }
878 + if let Some(freq) = sampling.frequency_penalty {
879 + req = req.set_sampler_frequency_penalty(freq);
880 + }
881 + if let Some(pres) = sampling.presence_penalty {
882 + req = req.set_sampler_presence_penalty(pres);
883 + }
884 + req
885 +}
886 +
887 +/// Convert [`ChatRole`] → [`TextMessageRole`].
888 +#[cfg(any(
889 + target_os = "macos",
890 + target_os = "ios",
891 + target_os = "tvos",
892 + target_os = "windows",
893 + target_os = "linux",
894 + target_os = "android"
895 +))]
896 +fn chat_role_to_mistral(role: &ChatRole) -> TextMessageRole {
897 + match role {
898 + ChatRole::System => TextMessageRole::System,
899 + ChatRole::User => TextMessageRole::User,
900 + ChatRole::Assistant => TextMessageRole::Assistant,
901 + }
902 +}
903 +
904 +/// Truncate a string for log output, appending `"..."` if truncated.
905 +fn truncate_for_log(s: &str, max_len: usize) -> String {
906 + if s.len() > max_len {
907 + format!("{}...", &s[..max_len])
908 + } else {
909 + s.to_string()
910 + }
911 +}
912 +
913 +// ═════════════════════════════════════════════════════════════════════════════
914 +// Unsupported-platform stub
915 +// ═════════════════════════════════════════════════════════════════════════════
916 +
917 +/// Stub `ChatEngine` for platforms where mistral.rs is not available.
918 +///
919 +/// All methods return errors or empty values so that code using the engine
920 +/// can compile on any target without `#[cfg]` at every call site.
921 +#[cfg(not(any(
922 + target_os = "macos",
923 + target_os = "ios",
924 + target_os = "tvos",
925 + target_os = "windows",
926 + target_os = "linux",
927 + target_os = "android"
928 +)))]
929 +pub struct ChatEngine;
930 +
931 +#[cfg(not(any(
932 + target_os = "macos",
933 + target_os = "ios",
934 + target_os = "tvos",
935 + target_os = "windows",
936 + target_os = "linux",
937 + target_os = "android"
938 +)))]
939 +impl ChatEngine {
940 + pub fn new() -> Self {
941 + Self
942 + }
943 +
944 + pub async fn load_gguf_model(
945 + &self,
946 + _config: GgufModelConfig,
947 + _system_prompt: Option<String>,
948 + _sampling: Option<SamplingConfig>,
949 + ) -> Result<std::time::Duration, InferenceError> {
950 + Err(InferenceError::Other {
951 + reason: "LLM inference is not supported on this platform.".into(),
952 + })
953 + }
954 +
955 + pub async fn unload_model(&self) -> Option<String> {
956 + None
957 + }
958 +
959 + pub async fn is_loaded(&self) -> bool {
960 + false
961 + }
962 +
963 + pub async fn info(&self) -> EngineInfo {
964 + EngineInfo {
965 + status: EngineStatus::Unloaded,
966 + model_name: None,
967 + approx_memory: None,
968 + history_length: 0u64,
969 + }
970 + }
971 +
972 + pub async fn set_system_prompt(&self, _prompt: impl Into<String>) {}
973 +
974 + pub async fn clear_system_prompt(&self) {}
975 +
976 + pub async fn set_sampling(&self, _sampling: SamplingConfig) {}
977 +
978 + pub async fn history(&self) -> Vec<ChatMessage> {
979 + Vec::new()
980 + }
981 +
982 + pub async fn clear_history(&self) -> usize {
983 + 0
984 + }
985 +
986 + pub async fn push_history(&self, _message: ChatMessage) {}
987 +
988 + pub async fn send_message(
989 + &self,
990 + _user_message: impl Into<String>,
991 + ) -> Result<InferenceResult, InferenceError> {
992 + Err(InferenceError::Other {
993 + reason: "LLM inference is not supported on this platform.".into(),
994 + })
995 + }
996 +
997 + pub async fn generate(
998 + &self,
999 + _messages: Vec<ChatMessage>,
1000 + _sampling: Option<SamplingConfig>,
1001 + ) -> Result<InferenceResult, InferenceError> {
1002 + Err(InferenceError::Other {
1003 + reason: "LLM inference is not supported on this platform.".into(),
1004 + })
1005 + }
1006 +
1007 + pub async fn stream_message(
1008 + &self,
1009 + _user_message: impl Into<String>,
1010 + ) -> Result<tokio::sync::mpsc::Receiver<StreamChunk>, InferenceError> {
1011 + Err(InferenceError::Other {
1012 + reason: "LLM inference is not supported on this platform.".into(),
1013 + })
1014 + }
1015 +}
1016 +
1017 +#[cfg(not(any(
1018 + target_os = "macos",
1019 + target_os = "ios",
1020 + target_os = "tvos",
1021 + target_os = "windows",
1022 + target_os = "linux",
1023 + target_os = "android"
1024 +)))]
1025 +impl Default for ChatEngine {
1026 + fn default() -> Self {
1027 + Self::new()
1028 + }
1029 +}
1030 +
1031 +// ═════════════════════════════════════════════════════════════════════════════
1032 +// Prebuilt model configs (convenience constructors)
1033 +// ═════════════════════════════════════════════════════════════════════════════
1034 +
1035 +/// Convenience constructors for common GGUF model configurations.
1036 +///
1037 +/// These mirror the constants in [`super::models`] but return a ready-to-use
1038 +/// [`GgufModelConfig`].
1039 +impl GgufModelConfig {
1040 + /// Qwen 2.5 1.5B Instruct (GGUF Q4_K_M) — ~941 MB.
1041 + ///
1042 + /// Lightest option, ideal for iOS and memory-constrained Android devices.
1043 + pub fn qwen25_1_5b() -> Self {
1044 + Self {
1045 + model_id: super::models::BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF.into(),
1046 + files: vec![super::models::QWEN25_1_5B_GGUF_FILE.into()],
1047 + tok_model_id: if cfg!(target_os = "android") {
1048 + Some(super::models::QWEN25_1_5B_TOK_MODEL_ID.into())
1049 + } else {
1050 + None
1051 + },
1052 + display_name: "Qwen 2.5 1.5B".into(),
1053 + approx_memory: "~941 MB (GGUF Q4_K_M)".into(),
1054 + }
1055 + }
1056 +
1057 + /// Qwen 2.5 3B Instruct (GGUF Q4_K_M) — ~1.93 GB.
1058 + ///
1059 + /// Balanced quality/size for macOS desktops and high-RAM Android devices.
1060 + /// Not recommended for iOS (OOM on 8 GB devices).
1061 + pub fn qwen25_3b() -> Self {
1062 + Self {
1063 + model_id: super::models::BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF.into(),
1064 + files: vec![super::models::QWEN25_3B_GGUF_FILE.into()],
1065 + tok_model_id: if cfg!(target_os = "android") {
1066 + Some(super::models::QWEN25_3B_TOK_MODEL_ID.into())
1067 + } else {
1068 + None
1069 + },
1070 + display_name: "Qwen 2.5 3B".into(),
1071 + approx_memory: "~1.93 GB (GGUF Q4_K_M)".into(),
1072 + }
1073 + }
1074 +
1075 + /// Qwen 2.5 Coder 1.5B Instruct (GGUF Q4_K_M) — ~941 MB.
1076 + ///
1077 + /// Dedicated coding model fine-tuned on 5.5T tokens of code and math data.
1078 + /// Same `qwen2` GGUF architecture as the general 1.5B — loads via the
1079 + /// existing `quantized_qwen.rs` path without any mistral.rs changes.
1080 + /// Same memory footprint as the general 1.5B but dramatically better at
1081 + /// code generation, explanation, and debugging.
1082 + ///
1083 + /// Preferred default for iOS, Android, and any coding-focused deployment.
1084 + pub fn qwen25_coder_1_5b() -> Self {
1085 + Self {
1086 + model_id: super::models::BARTOWSKI_QWEN25_CODER_1_5B_INSTRUCT_GGUF.into(),
1087 + files: vec![super::models::QWEN25_CODER_1_5B_GGUF_FILE.into()],
1088 + tok_model_id: if cfg!(target_os = "android") {
1089 + Some(super::models::QWEN25_CODER_1_5B_TOK_MODEL_ID.into())
1090 + } else {
1091 + None
1092 + },
1093 + display_name: "Qwen 2.5 Coder 1.5B".into(),
1094 + approx_memory: "~941 MB (GGUF Q4_K_M)".into(),
1095 + }
1096 + }
1097 +
1098 + /// Qwen 2.5 Coder 3B Instruct (GGUF Q4_K_M) — ~1.93 GB.
1099 + ///
1100 + /// Best on-device coding quality for macOS desktop. Fine-tuned on 5.5T
1101 + /// tokens of code and math. Same `qwen2` architecture as the general 3B.
1102 + /// Not recommended for iOS due to memory constraints.
1103 + pub fn qwen25_coder_3b() -> Self {
1104 + Self {
1105 + model_id: super::models::BARTOWSKI_QWEN25_CODER_3B_INSTRUCT_GGUF.into(),
1106 + files: vec![super::models::QWEN25_CODER_3B_GGUF_FILE.into()],
1107 + tok_model_id: if cfg!(target_os = "android") {
1108 + Some(super::models::QWEN25_CODER_3B_TOK_MODEL_ID.into())
1109 + } else {
1110 + None
1111 + },
1112 + display_name: "Qwen 2.5 Coder 3B".into(),
1113 + approx_memory: "~1.93 GB (GGUF Q4_K_M)".into(),
1114 + }
1115 + }
1116 +
1117 + /// Return the platform-appropriate default **coding** model config.
1118 + ///
1119 + /// - iOS / Android → Qwen 2.5 Coder 1.5B (~941 MB, fits mobile memory budgets)
1120 + /// - macOS / Windows / Linux → Qwen 2.5 Coder 3B (~1.93 GB, best desktop quality)
1121 + ///
1122 + /// Both are dedicated coding models (trained on 5.5T code + math tokens)
1123 + /// and use the `qwen2` GGUF architecture supported by mistral.rs.
1124 + pub fn platform_default() -> Self {
1125 + if cfg!(any(
1126 + target_os = "ios",
1127 + target_os = "tvos",
1128 + target_os = "android"
1129 + )) {
1130 + Self::qwen25_coder_1_5b()
1131 + } else {
1132 + Self::qwen25_coder_3b()
1133 + }
1134 + }
1135 +}
1136 +
1137 +// ═════════════════════════════════════════════════════════════════════════════
1138 +// Tests
1139 +// ═════════════════════════════════════════════════════════════════════════════
1140 +
1141 +#[cfg(test)]
1142 +mod tests {
1143 + use super::*;
1144 +
1145 + #[test]
1146 + fn truncate_for_log_short() {
1147 + assert_eq!(truncate_for_log("hello", 10), "hello");
1148 + }
1149 +
1150 + #[test]
1151 + fn truncate_for_log_long() {
1152 + let long = "a".repeat(200);
1153 + let result = truncate_for_log(&long, 50);
1154 + assert!(result.ends_with("..."));
1155 + assert_eq!(result.len(), 53); // 50 chars + "..."
1156 + }
1157 +
1158 + #[test]
1159 + fn gguf_model_config_qwen25_1_5b() {
1160 + let cfg = GgufModelConfig::qwen25_1_5b();
1161 + assert!(cfg.model_id.contains("1.5B"));
1162 + assert_eq!(cfg.files.len(), 1);
1163 + }
1164 +
1165 + #[test]
1166 + fn gguf_model_config_qwen25_3b() {
1167 + let cfg = GgufModelConfig::qwen25_3b();
1168 + assert!(cfg.model_id.contains("3B"));
1169 + assert_eq!(cfg.files.len(), 1);
1170 + }
1171 +
1172 + #[test]
1173 + fn gguf_model_config_platform_default() {
1174 + let cfg = GgufModelConfig::platform_default();
1175 + // On the test host (macOS or Linux), this should be the 3B model.
1176 + // On iOS/Android CI it would be 1.5B. We just check it's valid.
1177 + assert!(!cfg.model_id.is_empty());
1178 + assert!(!cfg.files.is_empty());
1179 + }
1180 +
1181 + #[tokio::test]
1182 + async fn engine_new_is_unloaded() {
1183 + let engine = ChatEngine::new();
1184 + assert!(!engine.is_loaded().await);
1185 + let info = engine.info().await;
1186 + assert_eq!(info.status, EngineStatus::Unloaded);
1187 + assert_eq!(info.history_length, 0);
1188 + }
1189 +
1190 + #[tokio::test]
1191 + async fn engine_send_without_model_errors() {
1192 + let engine = ChatEngine::new();
1193 + let result = engine.send_message("hello").await;
1194 + assert!(result.is_err());
1195 + match result.unwrap_err() {
1196 + InferenceError::NoModelLoaded => {} // expected
1197 + other => panic!("Expected NoModelLoaded, got: {:?}", other),
1198 + }
1199 + }
1200 +
1201 + #[tokio::test]
1202 + async fn engine_history_empty_when_no_model() {
1203 + let engine = ChatEngine::new();
1204 + assert!(engine.history().await.is_empty());
1205 + assert_eq!(engine.clear_history().await, 0);
1206 + }
1207 +
1208 + #[tokio::test]
1209 + async fn engine_unload_when_none() {
1210 + let engine = ChatEngine::new();
1211 + assert!(engine.unload_model().await.is_none());
1212 + }
1213 +}
src/inference/ffi.rs new
+404
@@ -0,0 +1,404 @@
1 +//! UniFFI-exported wrapper around [`ChatEngine`] for Swift / Kotlin consumers.
2 +//!
3 +//! [`ChatEngine`] uses Rust idioms (generics, `impl Into<String>`,
4 +//! `tokio::sync::mpsc::Receiver`) that cannot cross the FFI boundary.
5 +//! This module provides [`OndeChatEngine`], a `#[derive(uniffi::Object)]`
6 +//! wrapper with concrete, FFI-safe method signatures.
7 +//!
8 +//! ## Swift usage
9 +//!
10 +//! ```swift
11 +//! let engine = OndeChatEngine()
12 +//!
13 +//! // Load the platform-appropriate default model.
14 +//! let elapsed = try await engine.loadDefaultModel(
15 +//! systemPrompt: "You are a helpful assistant.",
16 +//! sampling: nil
17 +//! )
18 +//! print("Model loaded in \(elapsed)s")
19 +//!
20 +//! // Multi-turn chat (history managed automatically).
21 +//! let result = try await engine.sendMessage(message: "Hello!")
22 +//! print(result.text)
23 +//!
24 +//! // Streaming (callback-based for FFI compatibility).
25 +//! try await streamChatMessage(engine: engine, message: "Tell me a story.", listener: myListener)
26 +//!
27 +//! // One-shot generation (does NOT modify conversation history).
28 +//! let enhanced = try await engine.generate(
29 +//! messages: [ChatMessage(role: .user, content: "Expand: a cat in space")],
30 +//! sampling: SamplingConfig(temperature: 0.0, topP: nil, topK: nil, minP: nil, maxTokens: 512, frequencyPenalty: nil, presencePenalty: nil)
31 +//! )
32 +//! print(enhanced.text)
33 +//!
34 +//! // Status & history.
35 +//! let info = await engine.info()
36 +//! let history = await engine.history()
37 +//!
38 +//! // Cleanup.
39 +//! await engine.unloadModel()
40 +//! ```
41 +
42 +use std::sync::Arc;
43 +
44 +use super::engine::ChatEngine;
45 +use super::types::*;
46 +
47 +// ═══════════════════════════════════════════════════════════════════════════
48 +// Callback interface for streaming (used by free function, not Object method)
49 +// ═══════════════════════════════════════════════════════════════════════════
50 +
51 +/// Callback interface for receiving streaming token chunks.
52 +///
53 +/// Implement this in Swift / Kotlin and pass it to the free function
54 +/// [`stream_chat_message`].
55 +///
56 +/// ```swift
57 +/// class MyStreamHandler: StreamChunkListener {
58 +/// func onChunk(chunk: StreamChunk) -> Bool {
59 +/// print(chunk.delta, terminator: "")
60 +/// return !chunk.done // return false to stop early
61 +/// }
62 +/// }
63 +/// ```
64 +#[uniffi::export(callback_interface)]
65 +pub trait StreamChunkListener: Send + Sync {
66 + /// Called for each token chunk during streaming inference.
67 + ///
68 + /// Return `true` to continue receiving chunks, or `false` to cancel
69 + /// the stream early (the engine will still persist partial history).
70 + fn on_chunk(&self, chunk: StreamChunk) -> bool;
71 +}
72 +
73 +// ═══════════════════════════════════════════════════════════════════════════
74 +// OndeChatEngine — UniFFI Object
75 +// ═══════════════════════════════════════════════════════════════════════════
76 +
77 +/// On-device LLM chat inference engine — UniFFI-exported wrapper.
78 +///
79 +/// This is the primary entry point for Swift / Kotlin consumers. It wraps
80 +/// [`ChatEngine`] with FFI-safe method signatures (no generics, no Rust
81 +/// channels, concrete `String` parameters).
82 +///
83 +/// Construct with [`OndeChatEngine::new()`]. The engine starts with no
84 +/// model loaded — call [`load_gguf_model`] or [`load_default_model`] first.
85 +#[derive(uniffi::Object)]
86 +pub struct OndeChatEngine {
87 + inner: ChatEngine,
88 +}
89 +
90 +#[uniffi::export]
91 +impl OndeChatEngine {
92 + // ── Construction ─────────────────────────────────────────────────────
93 +
94 + /// Create a new engine with no model loaded.
95 + #[uniffi::constructor]
96 + pub fn new() -> Arc<Self> {
97 + Arc::new(Self {
98 + inner: ChatEngine::new(),
99 + })
100 + }
101 +
102 + // ── Model lifecycle ──────────────────────────────────────────────────
103 +
104 + /// Load a GGUF model into the engine.
105 + ///
106 + /// If a model is already loaded it will be unloaded first.
107 + ///
108 + /// Returns the wall-clock loading time in seconds.
109 + pub async fn load_gguf_model(
110 + &self,
111 + config: GgufModelConfig,
112 + system_prompt: Option<String>,
113 + sampling: Option<SamplingConfig>,
114 + ) -> Result<f64, InferenceError> {
115 + let elapsed = self
116 + .inner
117 + .load_gguf_model(config, system_prompt, sampling)
118 + .await?;
119 + Ok(elapsed.as_secs_f64())
120 + }
121 +
122 + /// Load the platform-appropriate default model.
123 + ///
124 + /// - tvOS / iOS / Android → Qwen 2.5 1.5B (~941 MB)
125 + /// - macOS / Windows / Linux → Qwen 2.5 3B (~1.93 GB)
126 + ///
127 + /// Returns the wall-clock loading time in seconds.
128 + pub async fn load_default_model(
129 + &self,
130 + system_prompt: Option<String>,
131 + sampling: Option<SamplingConfig>,
132 + ) -> Result<f64, InferenceError> {
133 + let config = GgufModelConfig::platform_default();
134 + let elapsed = self
135 + .inner
136 + .load_gguf_model(config, system_prompt, sampling)
137 + .await?;
138 + Ok(elapsed.as_secs_f64())
139 + }
140 +
141 + /// Unload the current model, freeing all memory.
142 + ///
143 + /// Returns the display name of the model that was unloaded, or `nil`
144 + /// if no model was loaded.
145 + pub async fn unload_model(&self) -> Option<String> {
146 + self.inner.unload_model().await
147 + }
148 +
149 + /// Check whether a model is currently loaded.
150 + pub async fn is_loaded(&self) -> bool {
151 + self.inner.is_loaded().await
152 + }
153 +
154 + /// Get a snapshot of the engine's current state.
155 + pub async fn info(&self) -> EngineInfo {
156 + self.inner.info().await
157 + }
158 +
159 + // ── System prompt ────────────────────────────────────────────────────
160 +
161 + /// Set or replace the system prompt.
162 + pub async fn set_system_prompt(&self, prompt: String) {
163 + self.inner.set_system_prompt(prompt).await;
164 + }
165 +
166 + /// Clear the system prompt.
167 + pub async fn clear_system_prompt(&self) {
168 + self.inner.clear_system_prompt().await;
169 + }
170 +
171 + // ── Sampling configuration ───────────────────────────────────────────
172 +
173 + /// Replace the sampling configuration.
174 + pub async fn set_sampling(&self, sampling: SamplingConfig) {
175 + self.inner.set_sampling(sampling).await;
176 + }
177 +
178 + // ── Conversation history ─────────────────────────────────────────────
179 +
180 + /// Get a copy of the full conversation history.
181 + pub async fn history(&self) -> Vec<ChatMessage> {
182 + self.inner.history().await
183 + }
184 +
185 + /// Clear the conversation history but keep the model loaded.
186 + ///
187 + /// Returns the number of turns that were removed.
188 + pub async fn clear_history(&self) -> u64 {
189 + self.inner.clear_history().await as u64
190 + }
191 +
192 + /// Append a message to history without running inference.
193 + pub async fn push_history(&self, message: ChatMessage) {
194 + self.inner.push_history(message).await;
195 + }
196 +
197 + // ── Non-streaming inference ──────────────────────────────────────────
198 +
199 + /// Send a user message and receive a complete assistant reply.
200 + ///
201 + /// The user message and assistant reply are automatically appended to
202 + /// the conversation history on success.
203 + pub async fn send_message(&self, message: String) -> Result<InferenceResult, InferenceError> {
204 + self.inner.send_message(message).await
205 + }
206 +
207 + /// Run inference on an explicit list of messages WITHOUT modifying the
208 + /// engine's internal history.
209 + ///
210 + /// Useful for one-shot prompts (e.g. prompt enhancement).
211 + pub async fn generate(
212 + &self,
213 + messages: Vec<ChatMessage>,
214 + sampling: Option<SamplingConfig>,
215 + ) -> Result<InferenceResult, InferenceError> {
216 + self.inner.generate(messages, sampling).await
217 + }
218 +}
219 +
220 +// ═══════════════════════════════════════════════════════════════════════════
221 +// Free function for streaming — UniFFI callback_interface works in free fns
222 +// ═══════════════════════════════════════════════════════════════════════════
223 +
224 +/// Stream a chat message through the engine, delivering token chunks to
225 +/// the `listener` callback.
226 +///
227 +/// This is a **free function** (not an Object method) because UniFFI 0.31
228 +/// requires `callback_interface` parameters to be passed to free functions
229 +/// rather than Object methods.
230 +///
231 +/// The `listener.on_chunk()` callback is called for each token delta.
232 +/// Return `true` to continue, or `false` to cancel early.
233 +///
234 +/// The user message and assembled reply are automatically appended to the
235 +/// engine's conversation history when streaming completes.
236 +///
237 +/// ```swift
238 +/// class MyHandler: StreamChunkListener {
239 +/// func onChunk(chunk: StreamChunk) -> Bool {
240 +/// print(chunk.delta, terminator: "")
241 +/// return !chunk.done
242 +/// }
243 +/// }
244 +///
245 +/// try await streamChatMessage(
246 +/// engine: engine,
247 +/// message: "Tell me a story.",
248 +/// listener: MyHandler()
249 +/// )
250 +/// ```
251 +#[uniffi::export]
252 +pub async fn stream_chat_message(
253 + engine: Arc<OndeChatEngine>,
254 + message: String,
255 + listener: Box<dyn StreamChunkListener>,
256 +) -> Result<(), InferenceError> {
257 + let mut rx = engine.inner.stream_message(message).await?;
258 +
259 + while let Some(chunk) = rx.recv().await {
260 + let done = chunk.done;
261 + let should_continue = listener.on_chunk(chunk);
262 + if done || !should_continue {
263 + break;
264 + }
265 + }
266 +
267 + Ok(())
268 +}
269 +
270 +// ═══════════════════════════════════════════════════════════════════════════
271 +// Free functions — convenience exports for Swift / Kotlin
272 +// ═══════════════════════════════════════════════════════════════════════════
273 +
274 +/// Return the platform-appropriate default GGUF model configuration.
275 +///
276 +/// - tvOS / iOS / Android → Qwen 2.5 1.5B (~941 MB)
277 +/// - macOS / Windows / Linux → Qwen 2.5 3B (~1.93 GB)
278 +#[uniffi::export]
279 +pub fn default_model_config() -> GgufModelConfig {
280 + GgufModelConfig::platform_default()
281 +}
282 +
283 +/// Return the Qwen 2.5 1.5B GGUF model configuration (~941 MB).
284 +#[uniffi::export]
285 +pub fn qwen25_1_5b_config() -> GgufModelConfig {
286 + GgufModelConfig::qwen25_1_5b()
287 +}
288 +
289 +/// Return the Qwen 2.5 3B GGUF model configuration (~1.93 GB).
290 +#[uniffi::export]
291 +pub fn qwen25_3b_config() -> GgufModelConfig {
292 + GgufModelConfig::qwen25_3b()
293 +}
294 +
295 +/// Return default sampling parameters for creative chat.
296 +#[uniffi::export]
297 +pub fn default_sampling_config() -> SamplingConfig {
298 + SamplingConfig::default()
299 +}
300 +
301 +/// Return deterministic (greedy) sampling parameters.
302 +#[uniffi::export]
303 +pub fn deterministic_sampling_config() -> SamplingConfig {
304 + SamplingConfig::deterministic()
305 +}
306 +
307 +/// Return conservative sampling parameters for mobile devices.
308 +#[uniffi::export]
309 +pub fn mobile_sampling_config() -> SamplingConfig {
310 + SamplingConfig::mobile()
311 +}
312 +
313 +/// Create a system message.
314 +#[uniffi::export]
315 +pub fn system_message(content: String) -> ChatMessage {
316 + ChatMessage::system(content)
317 +}
318 +
319 +/// Create a user message.
320 +#[uniffi::export]
321 +pub fn user_message(content: String) -> ChatMessage {
322 + ChatMessage::user(content)
323 +}
324 +
325 +/// Create an assistant message.
326 +#[uniffi::export]
327 +pub fn assistant_message(content: String) -> ChatMessage {
328 + ChatMessage::assistant(content)
329 +}
330 +
331 +// ═══════════════════════════════════════════════════════════════════════════
332 +// Tests
333 +// ═══════════════════════════════════════════════════════════════════════════
334 +
335 +#[cfg(test)]
336 +mod tests {
337 + use super::*;
338 +
339 + #[test]
340 + fn free_functions_return_valid_configs() {
341 + let cfg = default_model_config();
342 + assert!(!cfg.model_id.is_empty());
343 +
344 + let cfg = qwen25_1_5b_config();
345 + assert!(cfg.model_id.contains("1.5B"));
346 +
347 + let cfg = qwen25_3b_config();
348 + assert!(cfg.model_id.contains("3B"));
349 + }
350 +
351 + #[test]
352 + fn free_functions_return_valid_sampling() {
353 + let s = default_sampling_config();
354 + assert_eq!(s.temperature, Some(0.7));
355 +
356 + let s = deterministic_sampling_config();
357 + assert_eq!(s.temperature, Some(0.0));
358 +
359 + let s = mobile_sampling_config();
360 + assert_eq!(s.max_tokens, Some(128));
361 + }
362 +
363 + #[test]
364 + fn message_helpers() {
365 + let m = system_message("You are helpful.".into());
366 + assert_eq!(m.role, ChatRole::System);
367 + assert_eq!(m.content, "You are helpful.");
368 +
369 + let m = user_message("Hello".into());
370 + assert_eq!(m.role, ChatRole::User);
371 +
372 + let m = assistant_message("Hi!".into());
373 + assert_eq!(m.role, ChatRole::Assistant);
374 + }
375 +
376 + #[tokio::test]
377 + async fn onde_chat_engine_new_is_unloaded() {
378 + let engine = OndeChatEngine::new();
379 + assert!(!engine.is_loaded().await);
380 + let info = engine.info().await;
381 + assert_eq!(info.status, EngineStatus::Unloaded);
382 + assert_eq!(info.history_length, 0);
383 + }
384 +
385 + #[tokio::test]
386 + async fn onde_chat_engine_send_without_model_errors() {
387 + let engine = OndeChatEngine::new();
388 + let result = engine.send_message("hello".into()).await;
389 + assert!(result.is_err());
390 + }
391 +
392 + #[tokio::test]
393 + async fn onde_chat_engine_history_empty() {
394 + let engine = OndeChatEngine::new();
395 + assert!(engine.history().await.is_empty());
396 + assert_eq!(engine.clear_history().await, 0);
397 + }
398 +
399 + #[tokio::test]
400 + async fn onde_chat_engine_unload_when_none() {
401 + let engine = OndeChatEngine::new();
402 + assert!(engine.unload_model().await.is_none());
403 + }
404 +}
src/inference/mod.rs new
+72
@@ -0,0 +1,72 @@
1 +//! On-device LLM inference powered by [mistral.rs](https://github.com/EricLBuehler/mistral.rs).
2 +//!
3 +//! This module provides a high-level, framework-agnostic API for running
4 +//! LLM chat inference on-device across macOS, iOS, Windows, Linux, and Android.
5 +//!
6 +//! # Modules
7 +//!
8 +//! - [`engine`] — The main [`ChatEngine`](engine::ChatEngine) that wraps mistral.rs
9 +//! with conversation history, sampling config, and model lifecycle management.
10 +//! - [`types`] — Shared types ([`ChatMessage`](types::ChatMessage),
11 +//! [`SamplingConfig`](types::SamplingConfig), [`InferenceResult`](types::InferenceResult), etc.)
12 +//! used by the engine and any UI layer.
13 +//! - [`models`] — Model ID constants and rich metadata for all supported models.
14 +//! - [`token`] — HuggingFace token resolution (build-time literal or on-disk cache).
15 +//!
16 +//! # Quick Start
17 +//!
18 +//! ```rust,ignore
19 +//! use onde::inference::engine::ChatEngine;
20 +//! use onde::inference::types::*;
21 +//!
22 +//! // Create engine and load the platform-appropriate default model.
23 +//! let engine = ChatEngine::new();
24 +//! engine.load_gguf_model(
25 +//! GgufModelConfig::platform_default(),
26 +//! Some("You are a helpful assistant.".into()),
27 +//! None, // platform-aware sampling defaults
28 +//! ).await?;
29 +//!
30 +//! // Multi-turn chat (history is managed automatically).
31 +//! let reply = engine.send_message("What is Rust's ownership model?").await?;
32 +//! println!("{}", reply.text);
33 +//!
34 +//! let follow_up = engine.send_message("Can you give me an example?").await?;
35 +//! println!("{}", follow_up.text);
36 +//!
37 +//! // One-shot generation (does NOT modify conversation history).
38 +//! let enhanced = engine.generate(
39 +//! vec![ChatMessage::user("Expand this into a detailed prompt: a cat in space")],
40 +//! Some(SamplingConfig::deterministic()),
41 +//! ).await?;
42 +//! println!("{}", enhanced.text);
43 +//!
44 +//! // Streaming inference.
45 +//! let mut rx = engine.stream_message("Tell me a story.").await?;
46 +//! while let Some(chunk) = rx.recv().await {
47 +//! if !chunk.delta.is_empty() {
48 +//! print!("{}", chunk.delta);
49 +//! }
50 +//! if chunk.done {
51 +//! break;
52 +//! }
53 +//! }
54 +//!
55 +//! // Cleanup.
56 +//! engine.unload_model().await;
57 +//! ```
58 +
59 +pub mod engine;
60 +pub mod ffi;
61 +pub mod models;
62 +pub mod token;
63 +pub mod types;
64 +
65 +// Re-export the most commonly used items at the `inference::` level for
66 +// ergonomic imports like `use onde::inference::{ChatEngine, ChatMessage, ...}`.
67 +pub use engine::ChatEngine;
68 +pub use ffi::{OndeChatEngine, StreamChunkListener};
69 +pub use types::{
70 + ChatMessage, ChatRole, EngineInfo, EngineStatus, GgufModelConfig, InferenceError, IsqModelConfig,
71 + InferenceResult, SamplingConfig, StreamChunk,
72 +};
src/inference/models.rs new
+192
@@ -0,0 +1,192 @@
1 +pub const BFL_FLUX_1_SCHNELL: &str = "black-forest-labs/FLUX.1-schnell";
2 +pub const GOOGLE_GEMMA_3N_E2B_IT: &str = "google/gemma-3n-E2B-it";
3 +pub const GOOGLE_GEMMA_3N_E4B_IT: &str = "google/gemma-3n-E4B-it";
4 +pub const MICROSOFT_PHI_35_MINI_INSTRUCT: &str = "microsoft/Phi-3.5-mini-instruct";
5 +
6 +/// Pre-quantized Qwen 2.5 1.5B Instruct (GGUF Q4_K_M) — lightest mobile option (~941 MB).
7 +/// Fits comfortably on both iOS (iPhone 16e, 8 GB RAM) and Android memory-constrained devices.
8 +/// Note: the 3B variant (~1.93 GB) caused OOM on iPhone 16e because iOS gives apps only ~2-3 GB;
9 +/// the 1.5B variant at ~941 MB leaves comfortable headroom for KV cache, activations, and the app.
10 +/// bartowski's GGUF embeds the full tokenizer and Qwen2.5 chat template, so on iOS/macOS no
11 +/// separate tok_model_id download is needed. On Android an explicit tok_model_id is required.
12 +pub const BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF: &str = "bartowski/Qwen2.5-1.5B-Instruct-GGUF";
13 +/// The specific GGUF filename to download from the bartowski 1.5B repo.
14 +pub const QWEN25_1_5B_GGUF_FILE: &str = "Qwen2.5-1.5B-Instruct-Q4_K_M.gguf";
15 +/// Base model repo used for the HF tokenizer on Android.
16 +/// On Android, GGUF loading requires an explicit tokenizer source; on iOS/macOS the tokenizer
17 +/// embedded in the GGUF file is used instead to avoid an extra network download.
18 +pub const QWEN25_1_5B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-1.5B-Instruct";
19 +
20 +/// Pre-quantized Qwen 2.5 Coder 1.5B Instruct (GGUF Q4_K_M) — dedicated coding model (~941 MB).
21 +///
22 +/// Uses the `qwen2` GGUF architecture, identical to Qwen2.5-1.5B-Instruct, so it loads through
23 +/// the existing `quantized_qwen.rs` path in mistral.rs without any code changes.
24 +///
25 +/// Strongly preferred over the general-purpose 1.5B for coding tasks: trained on 5.5T tokens of
26 +/// code and math data, with fill-in-the-middle (FIM) and repo-level code understanding.
27 +/// Same memory footprint as the general 1.5B (~941 MB) but dramatically better at code.
28 +///
29 +/// bartowski's GGUF embeds the full tokenizer and chat template, so on iOS/macOS no separate
30 +/// tok_model_id download is needed. On Android an explicit tok_model_id is required.
31 +pub const BARTOWSKI_QWEN25_CODER_1_5B_INSTRUCT_GGUF: &str =
32 + "bartowski/Qwen2.5-Coder-1.5B-Instruct-GGUF";
33 +/// The specific GGUF filename to download from the bartowski Coder 1.5B repo.
34 +pub const QWEN25_CODER_1_5B_GGUF_FILE: &str = "Qwen2.5-Coder-1.5B-Instruct-Q4_K_M.gguf";
35 +/// Base model repo used for the HF tokenizer on Android.
36 +pub const QWEN25_CODER_1_5B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-Coder-1.5B-Instruct";
37 +
38 +/// HuggingFace repo for the full-precision Qwen 2.5 Coder 7B Instruct model.
39 +///
40 +/// Used by ISQ pipelines (`TextModelBuilder`) which download the safetensors weights
41 +/// directly and quantise them in-situ on the device. Unlike the bartowski GGUF
42 +/// variants, this repo ships the original BF16 weights; mistral.rs handles
43 +/// quantisation to Q4K or Q8_0 at load time via the `--isq` flag.
44 +///
45 +/// Requires ~8 GB RAM during the load phase (4-bit); ~12 GB for 8-bit.
46 +/// Metal-accelerated on macOS; CPU fallback available but very slow.
47 +pub const QWEN25_CODER_7B_INSTRUCT: &str = "Qwen/Qwen2.5-Coder-7B-Instruct";
48 +
49 +/// Pre-quantized Qwen 2.5 Coder 3B Instruct (GGUF Q4_K_M) — best coding quality on macOS (~1.93 GB).
50 +///
51 +/// Same `qwen2` architecture as the 3B general model; ideal for macOS desktops where the extra
52 +/// quality headroom over the 1.5B is worthwhile. Not recommended for iOS (OOM risk).
53 +pub const BARTOWSKI_QWEN25_CODER_3B_INSTRUCT_GGUF: &str =
54 + "bartowski/Qwen2.5-Coder-3B-Instruct-GGUF";
55 +/// The specific GGUF filename to download from the bartowski Coder 3B repo.
56 +pub const QWEN25_CODER_3B_GGUF_FILE: &str = "Qwen2.5-Coder-3B-Instruct-Q4_K_M.gguf";
57 +/// Base model repo used for the HF tokenizer on Android.
58 +pub const QWEN25_CODER_3B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-Coder-3B-Instruct";
59 +
60 +/// Pre-quantized Qwen 2.5 3B Instruct (GGUF Q4_K_M) — balanced option (~1.93 GB).
61 +/// Ideal for macOS desktops and Android devices with sufficient RAM.
62 +/// Not recommended as default on iOS: the 3B variant caused OOM on iPhone 16e (8 GB RAM)
63 +/// because iOS gives apps only ~2-3 GB; use the 1.5B variant for iOS instead.
64 +/// No in-situ quantization needed; loads directly at quantized size.
65 +pub const BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF: &str = "bartowski/Qwen2.5-3B-Instruct-GGUF";
66 +/// The specific GGUF filename to download from the bartowski 3B repo.
67 +pub const QWEN25_3B_GGUF_FILE: &str = "Qwen2.5-3B-Instruct-Q4_K_M.gguf";
68 +/// Base model repo used for the HF tokenizer (tokenizer.json + tokenizer_config.json).
69 +pub const QWEN25_3B_TOK_MODEL_ID: &str = "Qwen/Qwen2.5-3B-Instruct";
70 +
71 +/// All model IDs that the Onde inference engine supports.
72 +/// Used by `list_local_hf_models` to filter the HuggingFace cache
73 +/// to only show models that can actually be used for generation.
74 +pub const SUPPORTED_MODELS: &[&str] = &[
75 + BFL_FLUX_1_SCHNELL,
76 + GOOGLE_GEMMA_3N_E2B_IT,
77 + GOOGLE_GEMMA_3N_E4B_IT,
78 + MICROSOFT_PHI_35_MINI_INSTRUCT,
79 + BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF,
80 + BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF,
81 + BARTOWSKI_QWEN25_CODER_1_5B_INSTRUCT_GGUF,
82 + BARTOWSKI_QWEN25_CODER_3B_INSTRUCT_GGUF,
83 +];
84 +
85 +/// Rich metadata for a supported model, used by the frontend to display
86 +/// unavailable models that can be downloaded.
87 +pub struct SupportedModelInfo {
88 + /// The full HuggingFace model identifier, e.g. "black-forest-labs/FLUX.1-schnell".
89 + pub id: &'static str,
90 + /// Human-friendly display name for the model.
91 + pub name: &'static str,
92 + /// Organisation or publisher display name.
93 + pub org: &'static str,
94 + /// Short description of the model's purpose / capabilities.
95 + pub description: &'static str,
96 + /// Approximate total size in bytes when fully downloaded.
97 + /// Used by the progress monitor to estimate download percentage.
98 + ///
99 + /// These values are computed by summing every file in the model's
100 + /// HuggingFace repository (via the `/api/models/{id}?blobs=true`
101 + /// endpoint's `siblings[].size` fields).
102 + pub expected_size_bytes: u64,
103 +}
104 +
105 +/// Complete list of supported models with display metadata.
106 +///
107 +/// When adding a new model, add its constant ID to [`SUPPORTED_MODELS`] **and**
108 +/// a corresponding entry here so the frontend can show it in the model list UI.
109 +pub const SUPPORTED_MODEL_INFO: &[SupportedModelInfo] = &[
110 + SupportedModelInfo {
111 + id: BFL_FLUX_1_SCHNELL,
112 + name: "FLUX.1 Schnell",
113 + org: "Black Forest Labs",
114 + description: "Fast, high-quality image generation model optimised for speed.",
115 + // Only counting flux1-schnell.safetensors (23.78 GB) — the single-file
116 + // model weight that mistral.rs actually downloads for FluxOffloaded.
117 + expected_size_bytes: 23_782_506_688,
118 + },
119 + SupportedModelInfo {
120 + id: GOOGLE_GEMMA_3N_E2B_IT,
121 + name: "Gemma 3n E2B",
122 + org: "Google",
123 + description: "Compact prompt enhancer model — lightweight and fast on macOS.",
124 + // Sum of all repo files: 3 safetensor shards (3.08 + 4.98 + 2.82 GB)
125 + // + tokenizer.json (33 MB) + tokenizer.model (4.7 MB) + configs, etc.
126 + // Total ≈ 10.92 GB
127 + expected_size_bytes: 10_922_539_343,
128 + },
129 + SupportedModelInfo {
130 + id: GOOGLE_GEMMA_3N_E4B_IT,
131 + name: "Gemma 3n E4B",
132 + org: "Google",
133 + description:
134 + "Balanced prompt enhancer model — good quality-to-size ratio for macOS desktop.",
135 + // Sum of all repo files: 4 safetensor shards (3.08 + 4.97 + 4.99 + 2.66 GB)
136 + // + tokenizer.json (33 MB) + tokenizer.model (4.7 MB) + configs, etc.
137 + // Total ≈ 15.74 GB
138 + expected_size_bytes: 15_743_647_548,
139 + },
140 + SupportedModelInfo {
141 + id: MICROSOFT_PHI_35_MINI_INSTRUCT,
142 + name: "Phi-3.5-mini",
143 + org: "Microsoft",
144 + description:
145 + "Strongest prompt enhancer quality, larger memory footprint (~2.8 GB with Q4K).",
146 + // Sum of all repo files: 2 safetensor shards (4.97 + 2.67 GB)
147 + // + tokenizer.json (1.8 MB) + tokenizer.model (500 KB) + configs, etc.
148 + // Total ≈ 7.64 GB
149 + expected_size_bytes: 7_644_702_484,
150 + },
151 + SupportedModelInfo {
152 + id: BARTOWSKI_QWEN25_CODER_1_5B_INSTRUCT_GGUF,
153 + name: "Qwen 2.5 Coder 1.5B (GGUF)",
154 + org: "Qwen / Alibaba",
155 + description:
156 + "Dedicated coding model — same size as the general 1.5B (~941 MB) but trained \
157 + on 5.5T tokens of code and math. Strongly preferred for sigit. \
158 + Ideal for iOS & Android.",
159 + // Qwen2.5-Coder-1.5B-Instruct-Q4_K_M.gguf from bartowski repo.
160 + expected_size_bytes: 986_048_768,
161 + },
162 + SupportedModelInfo {
163 + id: BARTOWSKI_QWEN25_CODER_3B_INSTRUCT_GGUF,
164 + name: "Qwen 2.5 Coder 3B (GGUF)",
165 + org: "Qwen / Alibaba",
166 + description: "Best on-device coding quality for macOS desktop (~1.93 GB). \
167 + Trained on 5.5T tokens of code and math data. Not recommended for iOS.",
168 + // Qwen2.5-Coder-3B-Instruct-Q4_K_M.gguf from bartowski repo.
169 + expected_size_bytes: 1_929_903_264,
170 + },
171 + SupportedModelInfo {
172 + id: BARTOWSKI_QWEN25_1_5B_INSTRUCT_GGUF,
173 + name: "Qwen 2.5 1.5B (GGUF)",
174 + org: "Qwen / Alibaba",
175 + description: "Lightest pre-quantized chat model — ideal for iOS & Android (~941 MB). \
176 + Fits comfortably within iOS memory limits (iPhone 16e, 8 GB RAM).",
177 + // Qwen2.5-1.5B-Instruct-Q4_K_M.gguf from bartowski repo.
178 + // Exact file size from HuggingFace API siblings[].size.
179 + expected_size_bytes: 986_048_768,
180 + },
181 + SupportedModelInfo {
182 + id: BARTOWSKI_QWEN25_3B_INSTRUCT_GGUF,
183 + name: "Qwen 2.5 3B (GGUF)",
184 + org: "Qwen / Alibaba",
185 + description:
186 + "Pre-quantized chat model for macOS & Android — balanced quality and size (~1.93 GB). \
187 + Not recommended as default on iOS due to memory constraints.",
188 + // Qwen2.5-3B-Instruct-Q4_K_M.gguf from bartowski repo.
189 + // Exact file size from HuggingFace API siblings[].size.
190 + expected_size_bytes: 1_929_903_264,
191 + },
192 +];
src/inference/token.rs new
+108
@@ -0,0 +1,108 @@
1 +//! Hugging Face token resolution for on-device model loading.
2 +//!
3 +//! On iOS there is no way to run `mistralrs login` or place a token file at
4 +//! `~/.cache/huggingface/token`, so we embed the token at **build time**.
5 +//!
6 +//! ## How it works
7 +//!
8 +//! 1. The consuming app's `build.rs` sets the `HF_TOKEN` env var (e.g. by
9 +//! loading a `.env` file with `dotenvy`, or via CI secrets).
10 +//! 2. `option_env!("HF_TOKEN")` in this module picks it up at compile time
11 +//! and bakes it into the binary.
12 +//!
13 +//! This works regardless of whether the build is triggered from a terminal
14 +//! (where shell env vars are available) or from Xcode (which strips the
15 +//! shell environment).
16 +//!
17 +//! ## Setup
18 +//!
19 +//! Set the `HF_TOKEN` environment variable before building, or add it to
20 +//! a `.env` file that your app's `build.rs` loads:
21 +//!
22 +//! ```text
23 +//! HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
24 +//! ```
25 +//!
26 +//! Then build normally — no extra env vars needed.
27 +//!
28 +//! ## Runtime behaviour
29 +//!
30 +//! [`hf_token_source`] returns:
31 +//!
32 +//! 1. `TokenSource::Literal(token)` — if `HF_TOKEN` was present at compile time.
33 +//! 2. `TokenSource::CacheToken` — otherwise (reads `~/.cache/huggingface/token`;
34 +//! works on macOS after `mistralrs login`).
35 +
36 +#[cfg(any(
37 + target_os = "macos",
38 + target_os = "ios",
39 + target_os = "tvos",
40 + target_os = "windows",
41 + target_os = "android"
42 +))]
43 +use mistralrs::TokenSource;
44 +
45 +/// Token baked in at compile time (if the `HF_TOKEN` env var was set).
46 +///
47 +/// `option_env!` is evaluated by `rustc` during compilation — the resulting
48 +/// value is a `Option<&'static str>` embedded directly in the binary.
49 +/// This means the token never needs to exist on the device's filesystem.
50 +const BUILD_TIME_HF_TOKEN: Option<&str> = option_env!("HF_TOKEN");
51 +
52 +/// Resolve the best available [`TokenSource`] for Hugging Face Hub requests.
53 +///
54 +/// Prefer the compile-time literal when available (required on iOS), otherwise
55 +/// fall back to the on-disk cache token (the default on macOS where
56 +/// `mistralrs login` has been run).
57 +#[cfg(any(
58 + target_os = "macos",
59 + target_os = "ios",
60 + target_os = "tvos",
61 + target_os = "windows",
62 + target_os = "android"
63 +))]
64 +pub fn hf_token_source() -> TokenSource {
65 + match BUILD_TIME_HF_TOKEN {
66 + Some(token) if !token.is_empty() => {
67 + log::debug!("Using build-time HF_TOKEN for Hugging Face authentication.");
68 + TokenSource::Literal(token.to_string())
69 + }
70 + _ => {
71 + log::debug!(
72 + "No build-time HF_TOKEN found; falling back to cached token \
73 + (~/.cache/huggingface/token)."
74 + );
75 + TokenSource::CacheToken
76 + }
77 + }
78 +}
79 +
80 +#[cfg(test)]
81 +mod tests {
82 + use super::*;
83 +
84 + #[test]
85 + fn build_time_token_is_option() {
86 + // This just ensures the constant compiles and is the expected type.
87 + let _: Option<&str> = BUILD_TIME_HF_TOKEN;
88 + }
89 +
90 + #[test]
91 + #[cfg(any(
92 + target_os = "macos",
93 + target_os = "ios",
94 + target_os = "tvos",
95 + target_os = "windows",
96 + target_os = "android"
97 + ))]
98 + fn token_source_returns_valid_variant() {
99 + let source = hf_token_source();
100 + // We can't know at test time whether HF_TOKEN was set, but we can
101 + // verify it returns *something* without panicking.
102 + let display = format!("{}", source);
103 + assert!(
104 + display.starts_with("literal:") || display == "cache",
105 + "Unexpected token source: {display}"
106 + );
107 + }
108 +}
src/inference/types.rs new
+477
@@ -0,0 +1,477 @@
1 +//! Shared types for the on-device LLM inference engine.
2 +//!
3 +//! These types are intentionally framework-agnostic — they do **not** depend on
4 +//! any UI framework. They carry UniFFI derive annotations so that
5 +//! UniFFI bindgen can generate Swift / Kotlin bindings automatically.
6 +//!
7 +//! ## UniFFI compatibility notes
8 +//!
9 +//! - `usize` is **not** supported by UniFFI → we use `u64` / `u32` instead.
10 +//! - Enums use `#[derive(uniffi::Enum)]`.
11 +//! - Plain data structs use `#[derive(uniffi::Record)]`.
12 +//! - Error enums use `#[derive(uniffi::Error)]`.
13 +
14 +use serde::{Deserialize, Serialize};
15 +
16 +// ── Message role ─────────────────────────────────────────────────────────────
17 +
18 +/// Role of a message in a chat conversation.
19 +///
20 +/// Mirrors the standard OpenAI / mistral.rs role taxonomy but is decoupled
21 +/// from `mistralrs::TextMessageRole` so that callers don't need a direct
22 +/// dependency on mistral.rs.
23 +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
24 +#[serde(rename_all = "lowercase")]
25 +pub enum ChatRole {
26 + System,
27 + User,
28 + Assistant,
29 +}
30 +
31 +impl std::fmt::Display for ChatRole {
32 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 + match self {
34 + ChatRole::System => write!(f, "system"),
35 + ChatRole::User => write!(f, "user"),
36 + ChatRole::Assistant => write!(f, "assistant"),
37 + }
38 + }
39 +}
40 +
41 +// ── Chat message ─────────────────────────────────────────────────────────────
42 +
43 +/// A single message in a conversation.
44 +#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
45 +pub struct ChatMessage {
46 + pub role: ChatRole,
47 + pub content: String,
48 +}
49 +
50 +impl ChatMessage {
51 + pub fn system(content: impl Into<String>) -> Self {
52 + Self {
53 + role: ChatRole::System,
54 + content: content.into(),
55 + }
56 + }
57 +
58 + pub fn user(content: impl Into<String>) -> Self {
59 + Self {
60 + role: ChatRole::User,
61 + content: content.into(),
62 + }
63 + }
64 +
65 + pub fn assistant(content: impl Into<String>) -> Self {
66 + Self {
67 + role: ChatRole::Assistant,
68 + content: content.into(),
69 + }
70 + }
71 +}
72 +
73 +// ── Sampling configuration ───────────────────────────────────────────────────
74 +
75 +/// Sampling parameters for text generation.
76 +///
77 +/// All fields are optional — `None` means "use the engine default".
78 +///
79 +/// Note: `usize` is replaced with `u64` for UniFFI compatibility.
80 +#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
81 +pub struct SamplingConfig {
82 + /// Sampling temperature (higher = more random). Typical range: 0.0–2.0.
83 + pub temperature: Option<f64>,
84 + /// Nucleus (top-p) sampling threshold. Typical value: 0.9–0.95.
85 + pub top_p: Option<f64>,
86 + /// Top-k sampling limit.
87 + pub top_k: Option<u64>,
88 + /// Min-p sampling threshold.
89 + pub min_p: Option<f64>,
90 + /// Maximum number of tokens to generate.
91 + pub max_tokens: Option<u64>,
92 + /// Frequency penalty (penalise tokens proportional to occurrence count).
93 + pub frequency_penalty: Option<f32>,
94 + /// Presence penalty (penalise tokens that appeared at all).
95 + pub presence_penalty: Option<f32>,
96 +}
97 +
98 +impl Default for SamplingConfig {
99 + /// Sensible creative-chat defaults.
100 + fn default() -> Self {
101 + Self {
102 + temperature: Some(0.7),
103 + top_p: Some(0.95),
104 + top_k: None,
105 + min_p: None,
106 + max_tokens: Some(512),
107 + frequency_penalty: None,
108 + presence_penalty: None,
109 + }
110 + }
111 +}
112 +
113 +impl SamplingConfig {
114 + /// Deterministic sampling (temperature = 0, greedy decoding).
115 + pub fn deterministic() -> Self {
116 + Self {
117 + temperature: Some(0.0),
118 + top_p: None,
119 + top_k: None,
120 + min_p: None,
121 + max_tokens: Some(512),
122 + frequency_penalty: None,
123 + presence_penalty: None,
124 + }
125 + }
126 +
127 + /// Conservative mobile defaults — lower max_tokens for faster response on
128 + /// constrained devices (CPU-only ARM SoCs doing ~1-3 tok/sec).
129 + pub fn mobile() -> Self {
130 + Self {
131 + temperature: Some(0.7),
132 + top_p: Some(0.95),
133 + top_k: None,
134 + min_p: None,
135 + max_tokens: Some(128),
136 + frequency_penalty: None,
137 + presence_penalty: None,
138 + }
139 + }
140 +
141 + /// Sampling config tuned for coding assistants.
142 + ///
143 + /// Key differences from the general-purpose default:
144 + ///
145 + /// - **`frequency_penalty = 1.15`** — the primary fix for the repeated-token
146 + /// loop you saw with small GGUF models. Penalises each token proportional
147 + /// to how many times it has already appeared in the output, making it
148 + /// progressively harder to emit the same word again. 1.15 is aggressive
149 + /// enough to kill echo loops without hurting code token repetition
150 + /// (identifiers, keywords) at typical response lengths.
151 + ///
152 + /// - **`presence_penalty = 0.1`** — a light nudge away from any token that
153 + /// has appeared at all, encouraging lexical variety across the response.
154 + ///
155 + /// - **`temperature = 0.2`** — low randomness keeps generated code
156 + /// deterministic and syntactically correct. High temperature causes
157 + /// hallucinated variable names and broken syntax in code blocks.
158 + ///
159 + /// - **`top_p = 0.95`** — nucleus sampling retained to avoid degenerate
160 + /// greedy outputs while still keeping the distribution tight.
161 + ///
162 + /// - **`max_tokens = 1024`** — doubled vs. the chat default to allow
163 + /// complete function / class explanations without truncation.
164 + pub fn coding() -> Self {
165 + Self {
166 + temperature: Some(0.2),
167 + top_p: Some(0.95),
168 + top_k: None,
169 + min_p: None,
170 + max_tokens: Some(1024),
171 + frequency_penalty: Some(1.15),
172 + presence_penalty: Some(0.1),
173 + }
174 + }
175 +
176 + /// Like [`coding`](Self::coding) but capped at 256 tokens for mobile
177 + /// devices where latency matters more than completeness.
178 + pub fn coding_mobile() -> Self {
179 + Self {
180 + max_tokens: Some(256),
181 + ..Self::coding()
182 + }
183 + }
184 +}
185 +
186 +// ── GGUF model configuration ─────────────────────────────────────────────────
187 +
188 +/// Configuration for loading a GGUF model via mistral.rs.
189 +///
190 +/// This is the primary model format for on-device mobile/desktop inference
191 +/// because GGUF files are pre-quantized and load at their compressed size,
192 +/// avoiding the large memory spike of in-situ quantization.
193 +#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
194 +pub struct GgufModelConfig {
195 + /// HuggingFace model repository ID, e.g. `"bartowski/Qwen2.5-1.5B-Instruct-GGUF"`.
196 + pub model_id: String,
197 + /// GGUF filename(s) within the repository, e.g. `["Qwen2.5-1.5B-Instruct-Q4_K_M.gguf"]`.
198 + pub files: Vec<String>,
199 + /// Optional: explicit tokenizer model ID (required on Android where GGUF
200 + /// embedded tokenizers are not supported by the candle backend).
201 + pub tok_model_id: Option<String>,
202 + /// Human-friendly display name, e.g. `"Qwen 2.5 1.5B"`.
203 + pub display_name: String,
204 + /// Approximate memory footprint description, e.g. `"~941 MB (GGUF Q4_K_M)"`.
205 + pub approx_memory: String,
206 +}
207 +
208 +// ── ISQ model configuration ──────────────────────────────────────────────────
209 +
210 +/// Configuration for loading an ISQ (in-situ quantised) model via mistral.rs
211 +/// `TextModelBuilder`.
212 +///
213 +/// Unlike GGUF models, ISQ models are loaded directly from a HuggingFace
214 +/// safetensors repo and quantised in-situ on the device. They require more
215 +/// RAM during the load phase but support a wider range of architectures
216 +/// (e.g. DeepSeek-Coder-V2-Lite, Qwen2.5-Coder-7B).
217 +///
218 +/// **macOS-only for now** — ISQ with Metal acceleration requires the `metal`
219 +/// feature on mistral.rs. The struct is still defined on all platforms so
220 +/// that types.rs compiles everywhere without `cfg` gates on the record
221 +/// (UniFFI requires all record types to be reachable without feature flags).
222 +#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
223 +pub struct IsqModelConfig {
224 + /// HuggingFace model repository ID, e.g. `"Qwen/Qwen2.5-Coder-7B-Instruct"`.
225 + pub model_id: String,
226 + /// Number of quantisation bits. `4` → Q4K (AFQ4 on Metal), `8` → Q8_0 (AFQ8 on Metal).
227 + /// Any value outside `{4, 8}` defaults to 4-bit.
228 + pub isq_bits: u8,
229 + /// Human-friendly display name, e.g. `"Qwen 2.5 Coder 7B"`.
230 + pub display_name: String,
231 + /// Approximate memory footprint description, e.g. `"~4.5 GB (Q4K, Metal)"`.
232 + pub approx_memory: String,
233 +}
234 +
235 +impl IsqModelConfig {
236 + /// Qwen 2.5 Coder 7B Instruct — ISQ 4-bit, Metal-accelerated (~4.5 GB).
237 + ///
238 + /// Best macOS desktop coding quality. Loaded from the official HF repo
239 + /// and quantised in-situ; requires ~8 GB RAM during the load phase.
240 + pub fn qwen25_coder_7b_isq4() -> Self {
241 + Self {
242 + model_id: super::models::QWEN25_CODER_7B_INSTRUCT.into(),
243 + isq_bits: 4,
244 + display_name: "Qwen 2.5 Coder 7B (ISQ 4-bit)".into(),
245 + approx_memory: "~4.5 GB (ISQ Q4K, Metal)".into(),
246 + }
247 + }
248 +
249 + /// Qwen 2.5 Coder 7B Instruct — ISQ 8-bit, Metal-accelerated (~9 GB).
250 + ///
251 + /// Higher quality than the 4-bit variant; requires ~12 GB RAM on load.
252 + /// Suitable for Macs with 16 GB+ unified memory.
253 + pub fn qwen25_coder_7b_isq8() -> Self {
254 + Self {
255 + model_id: super::models::QWEN25_CODER_7B_INSTRUCT.into(),
256 + isq_bits: 8,
257 + display_name: "Qwen 2.5 Coder 7B (ISQ 8-bit)".into(),
258 + approx_memory: "~9 GB (ISQ Q8K, Metal)".into(),
259 + }
260 + }
261 +}
262 +
263 +// ── Inference result ─────────────────────────────────────────────────────────
264 +
265 +/// The result of a chat inference request.
266 +#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
267 +pub struct InferenceResult {
268 + /// The generated assistant reply text.
269 + pub text: String,
270 + /// Wall-clock duration of the inference in seconds.
271 + pub duration_secs: f64,
272 + /// Human-readable duration string (e.g. `"2m 3.1s"` or `"4.5s"`).
273 + pub duration_display: String,
274 + /// Finish reason reported by the model (e.g. `"stop"`, `"length"`).
275 + pub finish_reason: String,
276 +}
277 +
278 +// ── Streaming chunk ──────────────────────────────────────────────────────────
279 +
280 +/// A single streaming token chunk from the inference engine.
281 +#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
282 +pub struct StreamChunk {
283 + /// The token text delta (may be empty for the final chunk).
284 + pub delta: String,
285 + /// Whether this is the final chunk in the stream.
286 + pub done: bool,
287 + /// Finish reason (only set on the final chunk).
288 + pub finish_reason: Option<String>,
289 +}
290 +
291 +// ── Engine status ────────────────────────────────────────────────────────────
292 +
293 +/// Lifecycle status of the inference engine.
294 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
295 +#[serde(rename_all = "snake_case")]
296 +pub enum EngineStatus {
297 + /// No model loaded.
298 + Unloaded,
299 + /// Model is being downloaded / loaded into memory.
300 + Loading,
301 + /// Model is loaded and ready to accept requests.
302 + Ready,
303 + /// Model is currently running inference.
304 + Generating,
305 + /// An error occurred (model may or may not still be loaded).
306 + Error,
307 +}
308 +
309 +impl std::fmt::Display for EngineStatus {
310 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
311 + match self {
312 + EngineStatus::Unloaded => write!(f, "unloaded"),
313 + EngineStatus::Loading => write!(f, "loading"),
314 + EngineStatus::Ready => write!(f, "ready"),
315 + EngineStatus::Generating => write!(f, "generating"),
316 + EngineStatus::Error => write!(f, "error"),
317 + }
318 + }
319 +}
320 +
321 +// ── Engine info snapshot ─────────────────────────────────────────────────────
322 +
323 +/// A point-in-time snapshot of the engine's state, suitable for status UIs.
324 +///
325 +/// Note: `history_length` is `u64` (not `usize`) for UniFFI compatibility.
326 +#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
327 +pub struct EngineInfo {
328 + pub status: EngineStatus,
329 + /// Display name of the currently loaded model, if any.
330 + pub model_name: Option<String>,
331 + /// Approximate memory footprint description, if a model is loaded.
332 + pub approx_memory: Option<String>,
333 + /// Number of conversation turns in the current history.
334 + pub history_length: u64,
335 +}
336 +
337 +// ── Error type ───────────────────────────────────────────────────────────────
338 +
339 +/// Errors that can occur during inference engine operations.
340 +///
341 +/// Exposed to Swift / Kotlin as a sealed class / enum via `uniffi::Error`.
342 +#[derive(Debug, thiserror::Error, uniffi::Error)]
343 +pub enum InferenceError {
344 + #[error("No model loaded — call `load_model` first")]
345 + NoModelLoaded,
346 +
347 + #[error("Model is already loaded: {model_name}")]
348 + AlreadyLoaded { model_name: String },
349 +
350 + #[error("Failed to build model: {reason}")]
351 + ModelBuild { reason: String },
352 +
353 + #[error("Inference failed: {reason}")]
354 + Inference { reason: String },
355 +
356 + #[error("Model loading was cancelled")]
357 + Cancelled,
358 +
359 + #[error("{reason}")]
360 + Other { reason: String },
361 +}
362 +
363 +// ── Duration formatting helper ───────────────────────────────────────────────
364 +
365 +/// Format a `std::time::Duration` as `Xm Ys` or just `Ys` when under a minute.
366 +pub fn format_duration(d: std::time::Duration) -> String {
367 + let total_secs = d.as_secs_f64();
368 + let mins = (total_secs / 60.0).floor() as u64;
369 + let secs = total_secs - (mins as f64 * 60.0);
370 + if mins > 0 {
371 + format!("{}m {:.1}s", mins, secs)
372 + } else {
373 + format!("{:.1}s", secs)
374 + }
375 +}
376 +
377 +#[cfg(test)]
378 +mod tests {
379 + use super::*;
380 +
381 + #[test]
382 + fn chat_message_constructors() {
383 + let sys = ChatMessage::system("You are helpful.");
384 + assert_eq!(sys.role, ChatRole::System);
385 + assert_eq!(sys.content, "You are helpful.");
386 +
387 + let user = ChatMessage::user("Hello");
388 + assert_eq!(user.role, ChatRole::User);
389 +
390 + let asst = ChatMessage::assistant("Hi there!");
391 + assert_eq!(asst.role, ChatRole::Assistant);
392 + }
393 +
394 + #[test]
395 + fn chat_role_display() {
396 + assert_eq!(ChatRole::System.to_string(), "system");
397 + assert_eq!(ChatRole::User.to_string(), "user");
398 + assert_eq!(ChatRole::Assistant.to_string(), "assistant");
399 + }
400 +
401 + #[test]
402 + fn chat_role_serde_rename() {
403 + // Verify that #[serde(rename_all = "lowercase")] is applied by
404 + // checking the Display impl matches the expected serialised form.
405 + // (Full serde_json round-trip is tested in integration tests that
406 + // already depend on serde_json.)
407 + assert_eq!(format!("{}", ChatRole::System), "system");
408 + assert_eq!(format!("{}", ChatRole::User), "user");
409 + assert_eq!(format!("{}", ChatRole::Assistant), "assistant");
410 + }
411 +
412 + #[test]
413 + fn sampling_config_defaults() {
414 + let cfg = SamplingConfig::default();
415 + assert_eq!(cfg.temperature, Some(0.7));
416 + assert_eq!(cfg.top_p, Some(0.95));
417 + assert_eq!(cfg.max_tokens, Some(512));
418 + }
419 +
420 + #[test]
421 + fn sampling_config_deterministic() {
422 + let cfg = SamplingConfig::deterministic();
423 + assert_eq!(cfg.temperature, Some(0.0));
424 + assert!(cfg.top_p.is_none());
425 + }
426 +
427 + #[test]
428 + fn sampling_config_mobile() {
429 + let cfg = SamplingConfig::mobile();
430 + assert_eq!(cfg.max_tokens, Some(128));
431 + }
432 +
433 + #[test]
434 + fn engine_status_display() {
435 + assert_eq!(EngineStatus::Ready.to_string(), "ready");
436 + assert_eq!(EngineStatus::Generating.to_string(), "generating");
437 + }
438 +
439 + #[test]
440 + fn format_duration_under_minute() {
441 + let d = std::time::Duration::from_secs_f64(4.567);
442 + assert_eq!(format_duration(d), "4.6s");
443 + }
444 +
445 + #[test]
446 + fn format_duration_over_minute() {
447 + let d = std::time::Duration::from_secs_f64(125.3);
448 + assert_eq!(format_duration(d), "2m 5.3s");
449 + }
450 +
451 + #[test]
452 + fn inference_error_display() {
453 + let err = InferenceError::NoModelLoaded;
454 + assert_eq!(err.to_string(), "No model loaded — call `load_model` first");
455 +
456 + let err = InferenceError::ModelBuild {
457 + reason: "out of memory".into(),
458 + };
459 + assert_eq!(err.to_string(), "Failed to build model: out of memory");
460 +
461 + let err = InferenceError::AlreadyLoaded {
462 + model_name: "Qwen 2.5".into(),
463 + };
464 + assert_eq!(err.to_string(), "Model is already loaded: Qwen 2.5");
465 + }
466 +
467 + #[test]
468 + fn engine_info_history_is_u64() {
469 + let info = EngineInfo {
470 + status: EngineStatus::Ready,
471 + model_name: Some("Test".into()),
472 + approx_memory: None,
473 + history_length: 42,
474 + };
475 + assert_eq!(info.history_length, 42u64);
476 + }
477 +}
src/lib.rs new
+80
@@ -0,0 +1,80 @@
1 +//! # Onde
2 +//!
3 +//! **On-device inference for cross-platform apps.**
4 +//!
5 +//! Run LLMs, diffusion models, and speech-to-text locally — no cloud,
6 +//! no latency, no data leaving the device.
7 +//!
8 +//! Onde wraps [mistral.rs](https://github.com/EricLBuehler/mistral.rs) for
9 +//! LLM and image generation, and [whisper.cpp](https://github.com/ggerganov/whisper.cpp)
10 +//! (via [transcribe-rs](https://github.com/cjpais/transcribe-rs)) for
11 +//! speech-to-text — with a unified API that handles model discovery,
12 +//! HuggingFace Hub downloads, cache management, and GPU acceleration
13 +//! across every platform.
14 +//!
15 +//! Built by [Onde Inference](https://ondeinference.com)
16 +//!
17 +//! ## Modules
18 +//!
19 +//! - [`hf_cache`] — HuggingFace Hub cache inspection, repair, and model
20 +//! download with a framework-agnostic progress-callback API.
21 +//! - [`inference::models`] — Model ID constants and rich metadata (download
22 +//! size, display name, org, description) for all supported models.
23 +//! - [`inference::token`] — HuggingFace token resolution (build-time literal
24 +//! or on-disk cache; required on iOS where the filesystem is sandboxed).
25 +//! - [`whisper`] — Whisper speech-to-text transcription with automatic model
26 +//! download (feature-gated behind `whisper`).
27 +//!
28 +//! ## Re-exports
29 +//!
30 +//! `mistralrs`, `hf_hub`, and `mistralrs_core` are re-exported so that apps
31 +//! depending on `onde` do not need their own direct dependency on those crates.
32 +//! Access them as `onde::mistralrs`, `onde::hf_hub`, and `onde::mistralrs_core`.
33 +//!
34 +//! ## Example
35 +//!
36 +//! ```rust,ignore
37 +//! use onde::whisper::{
38 +//! find_or_download_whisper_model, WhisperEngine,
39 +//! WhisperInferenceParams, TranscriptionEngine,
40 +//! };
41 +//!
42 +//! let model_path = find_or_download_whisper_model(
43 +//! &"./models/whisper".into(),
44 +//! None, // platform-smart default
45 +//! |p| println!("{}: {}", p.model_name, p.downloaded_display),
46 +//! None,
47 +//! )?;
48 +//!
49 +//! let mut engine = WhisperEngine::new();
50 +//! engine.load_model(&model_path)?;
51 +//! let result = engine.transcribe_file("audio.wav", None)?;
52 +//! println!("{}", result.text);
53 +//! ```
54 +
55 +pub mod hf_cache;
56 +pub mod inference;
57 +
58 +uniffi::setup_scaffolding!();
59 +
60 +// Whisper speech-to-text via transcribe-rs (opt-in via `whisper` feature).
61 +#[cfg(feature = "whisper")]
62 +pub mod whisper;
63 +
64 +// Re-export mistralrs for every platform that onde supports.
65 +// Apps use `onde::mistralrs::Model` etc. instead of declaring a direct dep.
66 +#[cfg(any(
67 + target_os = "macos",
68 + target_os = "ios",
69 + target_os = "tvos",
70 + target_os = "windows",
71 + target_os = "linux",
72 + target_os = "android"
73 +))]
74 +pub use mistralrs;
75 +
76 +// Android-only re-exports needed for the GLOBAL_HF_CACHE workaround.
77 +#[cfg(target_os = "android")]
78 +pub use hf_hub;
79 +#[cfg(target_os = "android")]
80 +pub use mistralrs_core;
src/whisper.rs new
+822
@@ -0,0 +1,822 @@
1 +//! Whisper speech-to-text transcription via `transcribe-rs`.
2 +//!
3 +//! This module re-exports the Whisper engine and associated types from
4 +//! `transcribe-rs` so that callers can depend on `onde` alone for all
5 +//! on-device inference — both LLM/diffusion (via mistral.rs) and
6 +//! speech-to-text (via whisper.cpp / whisper-rs).
7 +//!
8 +//! It also provides [`find_or_download_whisper_model`] which resolves a
9 +//! local Whisper GGML model file — downloading the platform-appropriate
10 +//! default from HuggingFace (`ggerganov/whisper.cpp`) if none is found.
11 +//! The download uses `hf-hub` so it shares the standard HuggingFace cache
12 +//! directory with all other model downloads in the app.
13 +//!
14 +//! # Feature gate
15 +//!
16 +//! This module is only compiled when the `whisper` Cargo feature is enabled:
17 +//!
18 +//! ```toml
19 +//! [dependencies]
20 +//! onde = { path = "…", features = ["whisper"] }
21 +//! ```
22 +//!
23 +//! # Example
24 +//!
25 +//! ```rust,ignore
26 +//! use onde::whisper::{WhisperEngine, WhisperInferenceParams};
27 +//! use onde::whisper::{TranscriptionEngine, TranscriptionSegment};
28 +//!
29 +//! let mut engine = WhisperEngine::new();
30 +//! engine.load_model(&model_path)?;
31 +//!
32 +//! let params = WhisperInferenceParams {
33 +//! language: Some("en".to_string()),
34 +//! ..Default::default()
35 +//! };
36 +//!
37 +//! let result = engine.transcribe_samples(samples, Some(params))?;
38 +//! ```
39 +//!
40 +//! # Auto-download example
41 +//!
42 +//! ```rust,ignore
43 +//! use onde::whisper::{find_or_download_whisper_model, WhisperModelDownloadProgress};
44 +//! use std::path::PathBuf;
45 +//!
46 +//! let model_dir = PathBuf::from("/path/to/models/whisper");
47 +//! let model_path = find_or_download_whisper_model(
48 +//! &model_dir,
49 +//! None, // use platform default model
50 +//! |progress| {
51 +//! println!(
52 +//! "Downloading {} — {}/{}",
53 +//! progress.model_name, progress.downloaded_display, progress.total_display
54 +//! );
55 +//! },
56 +//! )?;
57 +//! ```
58 +
59 +use {
60 + log::{debug, info, warn},
61 + serde::{Deserialize, Serialize},
62 + std::path::{Path, PathBuf},
63 + std::sync::Arc,
64 + tsync::tsync,
65 +};
66 +
67 +// ---------------------------------------------------------------------------
68 +// Re-exports from transcribe-rs
69 +// ---------------------------------------------------------------------------
70 +
71 +// Re-export the Whisper engine and its parameter types.
72 +pub use transcribe_rs::whisper_cpp::{WhisperEngine, WhisperInferenceParams, WhisperLoadParams};
73 +
74 +// Re-export the core transcription trait and result types so callers
75 +// don't need a separate `use transcribe_rs::…` import.
76 +pub use transcribe_rs::{SpeechModel, TranscribeError, TranscriptionResult, TranscriptionSegment};
77 +
78 +// Re-export the audio utility for reading raw WAV samples.
79 +pub use transcribe_rs::audio::read_wav_samples;
80 +
81 +// ---------------------------------------------------------------------------
82 +// Constants
83 +// ---------------------------------------------------------------------------
84 +
85 +/// HuggingFace repository that hosts pre-converted Whisper GGML models.
86 +const HF_WHISPER_REPO: &str = "ggerganov/whisper.cpp";
87 +
88 +/// Whisper model file names, in order of preference (best quality first).
89 +/// [`find_or_download_whisper_model`] tries each in sequence and uses the
90 +/// first one already present on disk before falling back to downloading.
91 +pub const MODEL_CANDIDATES: &[&str] = &[
92 + "ggml-large-v3-turbo.bin",
93 + "ggml-large-v3.bin",
94 + "ggml-medium.bin",
95 + "ggml-medium.en.bin",
96 + "ggml-medium-q5_0.bin",
97 + "ggml-small.bin",
98 + "ggml-small.en.bin",
99 + "ggml-base.bin",
100 + "ggml-base.en.bin",
101 + "ggml-tiny.bin",
102 + "ggml-tiny.en.bin",
103 +];
104 +
105 +// ===========================================================================
106 +// UniFFI — Error type
107 +// ===========================================================================
108 +
109 +/// Errors returned by the UniFFI-exported whisper API.
110 +#[derive(Debug, thiserror::Error, uniffi::Error)]
111 +pub enum WhisperError {
112 + #[error("Model not loaded — call load_model() first")]
113 + ModelNotLoaded,
114 + #[error("Model load failed: {reason}")]
115 + ModelLoadFailed { reason: String },
116 + #[error("Transcription failed: {reason}")]
117 + TranscriptionFailed { reason: String },
118 + #[error("Download failed: {reason}")]
119 + DownloadFailed { reason: String },
120 + #[error("IO error: {reason}")]
121 + Io { reason: String },
122 +}
123 +
124 +// ===========================================================================
125 +// UniFFI — Record types (plain data structs passed across the FFI boundary)
126 +// ===========================================================================
127 +
128 +/// Progress payload emitted during a Whisper model download.
129 +///
130 +/// Callers of [`find_or_download_whisper_model`] receive this through
131 +/// the progress callback and can forward it to the frontend without any
132 +/// framework coupling in this crate.
133 +///
134 +/// Swift/Kotlin consumers receive this as a value type (struct / data class).
135 +#[tsync]
136 +#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
137 +pub struct WhisperModelDownloadProgress {
138 + /// The GGML model file being downloaded, e.g. `"ggml-base.bin"`.
139 + pub model_name: String,
140 + /// Bytes downloaded so far.
141 + pub downloaded_bytes: u64,
142 + /// Human-readable downloaded size, e.g. `"45.2 MB"`.
143 + pub downloaded_display: String,
144 + /// Expected total size in bytes (0 if unknown).
145 + pub total_bytes: u64,
146 + /// Human-readable total size, e.g. `"141.1 MB"`.
147 + pub total_display: String,
148 + /// Download progress as a value between 0.0 and 1.0.
149 + pub progress: f64,
150 + /// Whether the download has completed.
151 + pub done: bool,
152 +}
153 +
154 +/// A single transcription segment with timing information.
155 +///
156 +/// Mirrors `transcribe_rs::TranscriptionSegment` with UniFFI-compatible
157 +/// owned types so it can cross the FFI boundary.
158 +#[derive(Debug, Clone, uniffi::Record)]
159 +pub struct WhisperSegment {
160 + /// Start time in seconds.
161 + pub start_secs: f32,
162 + /// End time in seconds.
163 + pub end_secs: f32,
164 + /// The transcribed text for this segment.
165 + pub text: String,
166 +}
167 +
168 +/// Result of a Whisper transcription.
169 +///
170 +/// Mirrors `transcribe_rs::TranscriptionResult` with UniFFI-compatible
171 +/// owned types. `segments` is always a `Vec` (empty when the engine
172 +/// returns `None`).
173 +#[derive(Debug, Clone, uniffi::Record)]
174 +pub struct WhisperResult {
175 + /// The full transcribed text.
176 + pub text: String,
177 + /// Individual timed segments (empty if the engine did not produce any).
178 + pub segments: Vec<WhisperSegment>,
179 +}
180 +
181 +// ===========================================================================
182 +// UniFFI — Callback interface (Swift/Kotlin implements this to receive progress)
183 +// ===========================================================================
184 +
185 +/// Callback interface that Swift/Kotlin implements to receive download
186 +/// progress updates.
187 +///
188 +/// ```swift
189 +/// class MyProgressListener: WhisperProgressListener {
190 +/// func onProgress(progress: WhisperModelDownloadProgress) {
191 +/// print("Downloaded: \(progress.downloadedDisplay)")
192 +/// }
193 +/// }
194 +/// ```
195 +#[uniffi::export(callback_interface)]
196 +pub trait WhisperProgressListener: Send + Sync {
197 + /// Called periodically during a model download with the current progress.
198 + fn on_progress(&self, progress: WhisperModelDownloadProgress);
199 +}
200 +
201 +// ===========================================================================
202 +// UniFFI — Object wrapper around the foreign `WhisperEngine`
203 +// ===========================================================================
204 +
205 +/// A speech-to-text engine backed by Whisper (via whisper.cpp).
206 +///
207 +/// This is a UniFFI-compatible wrapper around `transcribe_rs::WhisperEngine`.
208 +/// Construct with [`OndeWhisperEngine::new`], load a model with
209 +/// [`load_model`], then transcribe audio with [`transcribe_file`] or
210 +/// [`transcribe_samples`].
211 +///
212 +/// ```swift
213 +/// let engine = OndeWhisperEngine()
214 +/// try engine.loadModel(path: "/path/to/ggml-base.bin")
215 +/// let result = try engine.transcribeFile(path: "/path/to/audio.wav", language: "en")
216 +/// print(result.text)
217 +/// ```
218 +#[derive(uniffi::Object)]
219 +pub struct OndeWhisperEngine {
220 + inner: std::sync::Mutex<Option<WhisperEngine>>,
221 +}
222 +
223 +#[uniffi::export]
224 +impl OndeWhisperEngine {
225 + /// Create a new, unloaded Whisper engine.
226 + #[uniffi::constructor]
227 + pub fn new() -> Arc<Self> {
228 + // The inner Option<WhisperEngine> starts as None; a model must be
229 + // loaded via load_model() before transcription.
230 + Arc::new(Self {
231 + inner: std::sync::Mutex::new(None),
232 + })
233 + }
234 +
235 + /// Load a Whisper GGML model file.
236 + ///
237 + /// `path` is the absolute filesystem path to the `.bin` model file.
238 + /// This must be called before any transcription method.
239 + pub fn load_model(&self, path: String) -> Result<(), WhisperError> {
240 + let model_path = PathBuf::from(&path);
241 + let engine =
242 + WhisperEngine::load(&model_path).map_err(|e| WhisperError::ModelLoadFailed {
243 + reason: e.to_string(),
244 + })?;
245 + let mut guard = self
246 + .inner
247 + .lock()
248 + .map_err(|e| WhisperError::ModelLoadFailed {
249 + reason: format!("Lock poisoned: {e}"),
250 + })?;
251 + *guard = Some(engine);
252 + Ok(())
253 + }
254 +
255 + /// Transcribe an audio file on disk.
256 + ///
257 + /// `path` is the absolute filesystem path to a WAV file (16-bit PCM,
258 + /// 16 kHz mono recommended).
259 + ///
260 + /// `language` is an optional BCP-47 language code (e.g. `"en"`, `"id"`).
261 + /// Pass `None` / `nil` for auto-detection.
262 + pub fn transcribe_file(
263 + &self,
264 + path: String,
265 + language: Option<String>,
266 + ) -> Result<WhisperResult, WhisperError> {
267 + let mut guard = self
268 + .inner
269 + .lock()
270 + .map_err(|e| WhisperError::TranscriptionFailed {
271 + reason: format!("Lock poisoned: {e}"),
272 + })?;
273 +
274 + let engine = guard.as_mut().ok_or(WhisperError::ModelNotLoaded)?;
275 +
276 + let params = WhisperInferenceParams {
277 + language,
278 + ..Default::default()
279 + };
280 +
281 + let file_path = Path::new(&path);
282 + let samples = transcribe_rs::audio::read_wav_samples(file_path).map_err(
283 + |e: transcribe_rs::TranscribeError| WhisperError::TranscriptionFailed {
284 + reason: e.to_string(),
285 + },
286 + )?;
287 + let result = engine.transcribe_with(&samples, &params).map_err(
288 + |e: transcribe_rs::TranscribeError| WhisperError::TranscriptionFailed {
289 + reason: e.to_string(),
290 + },
291 + )?;
292 +
293 + Ok(transcription_result_to_ffi(result))
294 + }
295 +
296 + /// Transcribe raw 16-bit PCM audio samples (16 kHz, mono, f32).
297 + ///
298 + /// `language` is an optional BCP-47 language code (e.g. `"en"`, `"id"`).
299 + /// Pass `None` / `nil` for auto-detection.
300 + pub fn transcribe_samples(
301 + &self,
302 + samples: Vec<f32>,
303 + language: Option<String>,
304 + ) -> Result<WhisperResult, WhisperError> {
305 + let mut guard = self
306 + .inner
307 + .lock()
308 + .map_err(|e| WhisperError::TranscriptionFailed {
309 + reason: format!("Lock poisoned: {e}"),
310 + })?;
311 +
312 + let engine = guard.as_mut().ok_or(WhisperError::ModelNotLoaded)?;
313 +
314 + let params = WhisperInferenceParams {
315 + language,
316 + ..Default::default()
317 + };
318 +
319 + let result = engine.transcribe_with(&samples, &params).map_err(
320 + |e: transcribe_rs::TranscribeError| WhisperError::TranscriptionFailed {
321 + reason: e.to_string(),
322 + },
323 + )?;
324 +
325 + Ok(transcription_result_to_ffi(result))
326 + }
327 +}
328 +
329 +// ===========================================================================
330 +// UniFFI — Exported free functions
331 +// ===========================================================================
332 +
333 +/// Returns the default Whisper model filename for the current platform.
334 +///
335 +/// - **Android (CPU-only)**: `ggml-base.bin` (~142 MB) — best quality/speed
336 +/// trade-off for mobile ARM CPUs.
337 +/// - **macOS / iOS (Metal GPU)**: `ggml-large-v3-turbo.bin` (~1.6 GB) —
338 +/// high quality, fast with GPU acceleration.
339 +/// - **Other platforms**: `ggml-small.bin` (~466 MB) — reasonable default.
340 +#[uniffi::export]
341 +pub fn default_model_for_platform() -> String {
342 + if cfg!(target_os = "android") {
343 + "ggml-base.bin".to_string()
344 + } else if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
345 + "ggml-large-v3-turbo.bin".to_string()
346 + } else {
347 + "ggml-small.bin".to_string()
348 + }
349 +}
350 +
351 +/// Returns the list of Whisper model candidates in order of preference
352 +/// (best quality first).
353 +#[uniffi::export]
354 +pub fn whisper_model_candidates() -> Vec<String> {
355 + MODEL_CANDIDATES.iter().map(|s| s.to_string()).collect()
356 +}
357 +
358 +/// Finds a locally cached Whisper GGML model or downloads one via the
359 +/// HuggingFace hub.
360 +///
361 +/// # Arguments
362 +///
363 +/// - `model_dir` — Legacy local directory to search for manually-placed
364 +/// models. Not used for downloaded models.
365 +/// - `model_name` — Override the model filename to download. Pass `nil`
366 +/// to use the platform default.
367 +/// - `listener` — Callback invoked periodically during the download.
368 +/// Not called at all if a model is already cached.
369 +/// - `app_data_dir` — **Always pass the app's data directory.**
370 +/// The default `~/.cache` path is inaccessible on sandboxed platforms.
371 +/// Pass `nil` only in CLI / test contexts.
372 +///
373 +/// Returns the absolute path to the resolved model file.
374 +#[uniffi::export]
375 +pub fn find_or_download_whisper_model_ffi(
376 + model_dir: String,
377 + model_name: Option<String>,
378 + listener: Box<dyn WhisperProgressListener>,
379 + app_data_dir: Option<String>,
380 +) -> Result<String, WhisperError> {
381 + let model_dir_path = PathBuf::from(&model_dir);
382 + let app_data = app_data_dir.as_deref().map(Path::new);
383 + let name_ref = model_name.as_deref();
384 +
385 + let path = find_or_download_whisper_model(
386 + &model_dir_path,
387 + name_ref,
388 + move |progress| {
389 + listener.on_progress(progress);
390 + },
391 + app_data,
392 + )
393 + .map_err(|reason| WhisperError::DownloadFailed { reason })?;
394 +
395 + path.to_str()
396 + .map(|s| s.to_string())
397 + .ok_or_else(|| WhisperError::Io {
398 + reason: "Model path contains non-UTF-8 characters".to_string(),
399 + })
400 +}
401 +
402 +/// Read raw f32 samples from a WAV file (utility for feeding into
403 +/// `OndeWhisperEngine.transcribe_samples`).
404 +///
405 +/// Returns 16 kHz mono f32 samples suitable for Whisper.
406 +#[uniffi::export]
407 +pub fn read_wav_samples_ffi(path: String) -> Result<Vec<f32>, WhisperError> {
408 + read_wav_samples(Path::new(&path)).map_err(|e| WhisperError::Io {
409 + reason: e.to_string(),
410 + })
411 +}
412 +
413 +// ===========================================================================
414 +// Internal — callback-based API
415 +// ===========================================================================
416 +
417 +/// Resolve the `hf-hub` [`Cache`] instance for the current platform.
418 +///
419 +/// Callers should **always** provide `app_data_dir` (e.g.
420 +/// `app.path().app_data_dir()`). The default `~/.cache/huggingface/hub`
421 +/// is inaccessible on every sandboxed platform:
422 +///
423 +/// - **Android** — `dirs::home_dir()` panics inside the sandbox.
424 +/// - **iOS** — `~/.cache` is outside the container (`os error 1`).
425 +/// - **macOS App Store** — the app is sandboxed; `~/.cache` is
426 +/// inaccessible just like iOS.
427 +///
428 +/// Passing `app_data_dir` on non-sandboxed desktop builds (Linux,
429 +/// Windows, side-loaded macOS) is harmless — the cache simply lives
430 +/// under the app data directory instead of `~/.cache`.
431 +///
432 +/// `None` is accepted as a last-resort fallback for CLI / test contexts;
433 +/// it uses `Cache::default()`.
434 +fn resolve_hf_cache(app_data_dir: Option<&Path>) -> Result<hf_hub::Cache, String> {
435 + if let Some(data_dir) = app_data_dir {
436 + let hf_home = data_dir.join("huggingface");
437 + let hf_cache = hf_home.join("hub");
438 + std::fs::create_dir_all(&hf_cache)
439 + .map_err(|e| format!("Cannot create HF cache dir: {e}"))?;
440 +
441 + // Keep env vars in sync so hf_cache_dir() agrees.
442 + std::env::set_var("HF_HUB_CACHE", &hf_cache);
443 + std::env::set_var("HF_HOME", &hf_home);
444 +
445 + info!("HF cache resolved to app data path: {}", hf_cache.display());
446 + Ok(hf_hub::Cache::new(hf_cache))
447 + } else {
448 + warn!(
449 + "No app_data_dir provided — using Cache::default(). \
450 + This will fail on sandboxed platforms (iOS, Android, macOS App Store)."
451 + );
452 + Ok(hf_hub::Cache::default())
453 + }
454 +}
455 +
456 +/// Try to resolve a Whisper model file from the HF cache without
457 +/// downloading. Returns `Some(path)` if the file is already fully
458 +/// cached, `None` otherwise.
459 +///
460 +/// This mirrors the mistral.rs strategy: the HF cache *is* the model
461 +/// store — no separate `model_dir` copy is needed.
462 +fn resolve_from_hf_cache(model_name: &str, cache: &hf_hub::Cache) -> Option<PathBuf> {
463 + let repo = cache.repo(hf_hub::Repo::model(HF_WHISPER_REPO.to_string()));
464 + // `repo.get(name)` returns `Some(path)` when the blob is fully
465 + // downloaded and the pointer symlink exists.
466 + let path = repo.get(model_name);
467 + if let Some(ref p) = path {
468 + // Double-check: the path must exist and be a real file (following
469 + // symlinks) with a non-zero size.
470 + match std::fs::metadata(p) {
471 + Ok(meta) if meta.len() > 0 => {
472 + debug!(
473 + "HF cache hit for {}: {:?} ({} bytes)",
474 + model_name,
475 + p,
476 + meta.len()
477 + );
478 + }
479 + _ => {
480 + debug!(
481 + "HF cache entry for {} exists but is empty or broken",
482 + model_name
483 + );
484 + return None;
485 + }
486 + }
487 + }
488 + path
489 +}
490 +
491 +/// Finds a locally cached Whisper GGML model or downloads one via the
492 +/// HuggingFace hub.
493 +///
494 +/// # Resolution strategy (mirrors mistral.rs)
495 +///
496 +/// The HuggingFace hub cache is the **primary model store**. Models are
497 +/// downloaded into the cache's content-addressed blob directory and
498 +/// accessed via symlinks — no copy or hard-link into a separate
499 +/// `model_dir` is performed. This avoids "Operation not permitted"
500 +/// errors on sandboxed platforms (iOS, Android) and eliminates double
501 +/// disk usage.
502 +///
503 +/// Search order:
504 +///
505 +/// 1. Check the HF cache for an already-downloaded model (preferred
506 +/// candidate list, best quality first).
507 +/// 2. Check `model_dir` for manually-placed `.bin` files (legacy
508 +/// fallback).
509 +/// 3. Download the platform default (or explicitly requested
510 +/// `model_name`) from `ggerganov/whisper.cpp` on HuggingFace.
511 +///
512 +/// # Arguments
513 +///
514 +/// - `model_dir` — Legacy local directory to search for manually-placed
515 +/// models. Not used for downloaded models.
516 +/// - `model_name` — Override the model filename to download. Pass `None`
517 +/// to use [`default_model_for_platform`].
518 +/// - `on_progress` — Callback invoked periodically during the download.
519 +/// Receives a [`WhisperModelDownloadProgress`] payload. Not called at
520 +/// all if a model is already cached.
521 +/// - `app_data_dir` — **Always pass `Some(app.path().app_data_dir())`.**
522 +/// The default `~/.cache` path is inaccessible on every sandboxed
523 +/// platform (Android, iOS, macOS App Store). On non-sandboxed desktop
524 +/// builds it is harmless — the cache simply lives under the app data
525 +/// directory. `None` is only acceptable in CLI / test contexts.
526 +///
527 +/// # Errors
528 +///
529 +/// Returns a human-readable error string on failure (network, I/O, etc.).
530 +pub fn find_or_download_whisper_model<F>(
531 + model_dir: &Path,
532 + model_name: Option<&str>,
533 + on_progress: F,
534 + app_data_dir: Option<&Path>,
535 +) -> Result<PathBuf, String>
536 +where
537 + F: Fn(WhisperModelDownloadProgress) + Send + Sync + 'static,
538 +{
539 + // ── 1. Build the HF cache once (shared across all lookups) ────────
540 + let cache = resolve_hf_cache(app_data_dir)?;
541 +
542 + // ── 2. Check the HF cache for an already-downloaded model ─────────
543 + //
544 + // Walk the preferred candidate list (best quality first). The first
545 + // cached model wins. This is the primary lookup path — identical to
546 + // how mistral.rs resolves models from cache before triggering a
547 + // download.
548 + for candidate in MODEL_CANDIDATES {
549 + if let Some(path) = resolve_from_hf_cache(candidate, &cache) {
550 + info!("Whisper model found in HF cache: {:?}", path);
551 + return Ok(path);
552 + }
553 + }
554 +
555 + // ── 3. Legacy fallback: check model_dir for manually-placed files ─
556 + if model_dir.exists() {
557 + for candidate in MODEL_CANDIDATES {
558 + let path = model_dir.join(candidate);
559 + if path.exists() && path.is_file() {
560 + info!("Whisper model found in legacy model_dir: {:?}", path);
561 + return Ok(path);
562 + }
563 + }
564 +
565 + // Any .bin file at all.
566 + if let Ok(entries) = std::fs::read_dir(model_dir) {
567 + for entry in entries.flatten() {
568 + let path = entry.path();
569 + if path.is_file() {
570 + if let Some(ext) = path.extension() {
571 + if ext == "bin" {
572 + warn!(
573 + "No preferred Whisper model found; falling back to {:?}",
574 + path
575 + );
576 + return Ok(path);
577 + }
578 + }
579 + }
580 + }
581 + }
582 + }
583 +
584 + // ── 4. Nothing cached — download via hf-hub ───────────────────────
585 +
586 + let target_name = model_name.unwrap_or(&default_model_for_platform_internal());
587 +
588 + info!(
589 + "No Whisper model cached; downloading {} from {}",
590 + target_name, HF_WHISPER_REPO,
591 + );
592 +
593 + let hf_path = download_whisper_model(target_name, on_progress, &cache)?;
594 +
595 + // The returned path lives inside the HF cache's blob store — use it
596 + // directly. No copy / hard-link / symlink into model_dir. This is
597 + // the same strategy mistral.rs uses: the HF cache *is* the model
598 + // directory.
599 + Ok(hf_path)
600 +}
601 +
602 +// ---------------------------------------------------------------------------
603 +// Internal helpers
604 +// ---------------------------------------------------------------------------
605 +
606 +/// Internal version of `default_model_for_platform` that returns `&'static str`
607 +/// (used by the generic callback-based API where we need a string slice).
608 +fn default_model_for_platform_internal() -> &'static str {
609 + if cfg!(target_os = "android") {
610 + "ggml-base.bin"
611 + } else if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
612 + "ggml-large-v3-turbo.bin"
613 + } else {
614 + "ggml-small.bin"
615 + }
616 +}
617 +
618 +/// Convert a `transcribe_rs::TranscriptionResult` into our UniFFI-compatible
619 +/// [`WhisperResult`].
620 +fn transcription_result_to_ffi(result: TranscriptionResult) -> WhisperResult {
621 + WhisperResult {
622 + text: result.text,
623 + segments: result
624 + .segments
625 + .unwrap_or_default()
626 + .into_iter()
627 + .map(|seg| WhisperSegment {
628 + start_secs: seg.start,
629 + end_secs: seg.end,
630 + text: seg.text,
631 + })
632 + .collect(),
633 + }
634 +}
635 +
636 +/// Download a single GGML model file from `ggerganov/whisper.cpp` using the
637 +/// HuggingFace hub synchronous API.
638 +///
639 +/// Accepts a pre-built [`hf_hub::Cache`] (from [`resolve_hf_cache`]) so that
640 +/// the caller controls where files land — essential on sandboxed platforms
641 +/// (iOS, Android).
642 +///
643 +/// hf-hub handles:
644 +/// - Resumable downloads (partial `.incomplete` files are continued).
645 +/// - Content-addressed blob storage with symlinks.
646 +///
647 +/// Returns the absolute path to the downloaded file inside the HF cache.
648 +fn download_whisper_model<F>(
649 + model_name: &str,
650 + on_progress: F,
651 + cache: &hf_hub::Cache,
652 +) -> Result<PathBuf, String>
653 +where
654 + F: Fn(WhisperModelDownloadProgress) + Send + Sync + 'static,
655 +{
656 + use hf_hub::api::sync::ApiBuilder;
657 + use std::sync::{
658 + atomic::{AtomicBool, Ordering},
659 + Arc,
660 + };
661 + use std::time::Duration;
662 +
663 + let api = ApiBuilder::from_cache(cache.clone())
664 + .build()
665 + .map_err(|e| format!("Failed to create HF API: {e}"))?;
666 +
667 + let repo = api.model(HF_WHISPER_REPO.to_string());
668 +
669 + // Emit an initial "starting" progress event.
670 + let name = model_name.to_string();
671 + on_progress(WhisperModelDownloadProgress {
672 + model_name: name.clone(),
673 + downloaded_bytes: 0,
674 + downloaded_display: "0 B".into(),
675 + total_bytes: 0,
676 + total_display: "calculating…".into(),
677 + progress: 0.0,
678 + done: false,
679 + });
680 +
681 + // hf-hub's `repo.get()` is a blocking call that downloads the file.
682 + // We spin up a native monitor thread that polls the HF cache directory
683 + // for the blob size to provide progress updates — the same pattern
684 + // used in `hf_cache::download_model`.
685 + let finished = Arc::new(AtomicBool::new(false));
686 + let finished_clone = Arc::clone(&finished);
687 + let monitor_name = name.clone();
688 +
689 + // Try to figure out the model cache path for monitoring.
690 + let cache_path = crate::hf_cache::model_cache_path(HF_WHISPER_REPO);
691 +
692 + // Approximate expected sizes for common models so the progress bar
693 + // has a meaningful denominator even before the download starts.
694 + let expected_size = approximate_model_size(model_name);
695 +
696 + let monitor_handle = std::thread::spawn(move || loop {
697 + std::thread::sleep(Duration::from_secs(1));
698 +
699 + if finished_clone.load(Ordering::Relaxed) {
700 + break;
701 + }
702 +
703 + let current_bytes = cache_path
704 + .as_ref()
705 + .filter(|p| p.exists())
706 + .map(|p| dir_size_recursive(p))
707 + .unwrap_or(0);
708 +
709 + let progress = if expected_size > 0 {
710 + (current_bytes as f64 / expected_size as f64).min(0.99)
711 + } else {
712 + 0.0
713 + };
714 +
715 + on_progress(WhisperModelDownloadProgress {
716 + model_name: monitor_name.clone(),
717 + downloaded_bytes: current_bytes,
718 + downloaded_display: format_size(current_bytes),
719 + total_bytes: expected_size,
720 + total_display: format_size(expected_size),
721 + progress,
722 + done: false,
723 + });
724 + });
725 +
726 + // Blocking download — hf-hub handles resumption internally.
727 + let result = repo.get(model_name);
728 +
729 + finished.store(true, Ordering::Relaxed);
730 + let _ = monitor_handle.join();
731 +
732 + match result {
733 + Ok(path) => {
734 + info!(
735 + "Whisper model {} downloaded to HF cache: {:?}",
736 + model_name, path
737 + );
738 + // Final progress event.
739 + let file_size = std::fs::metadata(&path).map(|m| m.len()).unwrap_or(0);
740 + // We need a new closure-compatible progress emitter here.
741 + // Since the monitor thread consumed `on_progress`, we log instead.
742 + // The caller will see the file appear and can emit its own "done".
743 + info!(
744 + "Whisper model download complete: {} ({})",
745 + model_name,
746 + format_size(file_size)
747 + );
748 + Ok(path)
749 + }
750 + Err(e) => {
751 + let msg = format!(
752 + "Failed to download Whisper model {} from {}: {}",
753 + model_name, HF_WHISPER_REPO, e
754 + );
755 + warn!("{}", msg);
756 + Err(msg)
757 + }
758 + }
759 +}
760 +
761 +/// Approximate expected download size for common Whisper GGML models.
762 +/// These are rough estimates used for progress bar rendering; they don't
763 +/// need to be exact.
764 +fn approximate_model_size(model_name: &str) -> u64 {
765 + match model_name {
766 + "ggml-large-v3-turbo.bin" => 1_620_000_000,
767 + "ggml-large-v3.bin" => 3_090_000_000,
768 + "ggml-large-v2.bin" => 3_090_000_000,
769 + "ggml-large-v1.bin" => 3_090_000_000,
770 + "ggml-medium.bin" => 1_530_000_000,
771 + "ggml-medium.en.bin" => 1_530_000_000,
772 + "ggml-medium-q5_0.bin" => 539_000_000,
773 + "ggml-small.bin" => 466_000_000,
774 + "ggml-small.en.bin" => 466_000_000,
775 + "ggml-base.bin" => 142_000_000,
776 + "ggml-base.en.bin" => 142_000_000,
777 + "ggml-tiny.bin" => 75_000_000,
778 + "ggml-tiny.en.bin" => 75_000_000,
779 + _ => 0,
780 + }
781 +}
782 +
783 +/// Recursively compute the total size of a directory in bytes.
784 +/// Follows symlinks to count the real file size and also counts in-progress
785 +/// `.incomplete` staging files so progress polling works during download.
786 +fn dir_size_recursive(path: &Path) -> u64 {
787 + let mut total: u64 = 0;
788 + if let Ok(entries) = std::fs::read_dir(path) {
789 + for entry in entries.flatten() {
790 + let entry_path = entry.path();
791 + if entry_path.is_dir() {
792 + total += dir_size_recursive(&entry_path);
793 + } else if let Ok(meta) = entry_path.symlink_metadata() {
794 + if meta.is_symlink() {
795 + if let Ok(real_meta) = entry_path.metadata() {
796 + total += real_meta.len();
797 + }
798 + } else {
799 + total += meta.len();
800 + }
801 + }
802 + }
803 + }
804 + total
805 +}
806 +
807 +/// Format a byte count into a human-readable string.
808 +fn format_size(bytes: u64) -> String {
809 + const KB: u64 = 1024;
810 + const MB: u64 = KB * 1024;
811 + const GB: u64 = MB * 1024;
812 +
813 + if bytes >= GB {
814 + format!("{:.2} GB", bytes as f64 / GB as f64)
815 + } else if bytes >= MB {
816 + format!("{:.1} MB", bytes as f64 / MB as f64)
817 + } else if bytes >= KB {
818 + format!("{:.0} KB", bytes as f64 / KB as f64)
819 + } else {
820 + format!("{} B", bytes)
821 + }
822 +}
tvos_chkstk.s new
+23
@@ -0,0 +1,23 @@
1 +// tvos_chkstk.s — stub for ___chkstk_darwin on tvOS
2 +//
3 +// On macOS and iOS, ___chkstk_darwin is provided by libSystem as a stack
4 +// probing function. On arm64 Apple platforms the kernel grows the stack
5 +// automatically via guard pages, so the probe is effectively a no-op that
6 +// just returns. tvOS does NOT export this symbol, but aws-lc-sys assembly
7 +// references it unconditionally.
8 +//
9 +// This file provides the missing symbol so the linker succeeds.
10 +// It is only compiled for tvOS targets (see build.rs).
11 +//
12 +// Symbol naming:
13 +// Mach-O adds one leading underscore to C symbols automatically.
14 +// The linker error says: Undefined symbol "___chkstk_darwin"
15 +// That means the C-level name is "__chkstk_darwin" (two underscores).
16 +// In assembly we write the raw Mach-O symbol = "___chkstk_darwin" (three underscores).
17 +
18 +.text
19 +.globl ___chkstk_darwin
20 +.p2align 2
21 +
22 +___chkstk_darwin:
23 + ret
uniffi-bindgen/.gitignore new
+2
@@ -0,0 +1,2 @@
1 +target/
2 +Cargo.lock
uniffi-bindgen/Cargo.toml new
+12
@@ -0,0 +1,12 @@
1 +[package]
2 +name = "onde-uniffi-bindgen"
3 +version = "0.1.0"
4 +edition = "2021"
5 +publish = false
6 +
7 +[[bin]]
8 +name = "uniffi-bindgen"
9 +path = "uniffi-bindgen.rs"
10 +
11 +[dependencies]
12 +uniffi = { version = "=0.31.0", features = ["cli"] }
uniffi-bindgen/uniffi-bindgen.rs new
+3
@@ -0,0 +1,3 @@
1 +fn main() {
2 + uniffi::uniffi_bindgen_main()
3 +}
uniffi.toml new
+6
@@ -0,0 +1,6 @@
1 +[bindings.kotlin]
2 +package_name = "com.ondeinference.onde"
3 +cdylib_name = "onde"
4 +
5 +[bindings.python]
6 +cdylib_name = "onde"
\ No newline at end of file