Skip to content

feat: add iOS TTS support using ONNX Runtime - #378

Closed
AnthonyRonning wants to merge 22 commits into
masterfrom
ios-tts
Closed

AnthonyRonning wants to merge 22 commits into
masterfrom
ios-tts

Conversation

@AnthonyRonning

@AnthonyRonning AnthonyRonning commented Jan 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Add Text-to-Speech (TTS) support for iOS using ONNX Runtime, enabling the Supertonic TTS model to run on-device on iPhones and iPads.

Changes

  • Cargo.toml: Add iOS-specific dependencies for ort and other TTS libraries
  • build.rs: Add iOS-specific linker configuration for ONNX Runtime xcframework
  • lib.rs: Enable TTS module for iOS (was desktop-only), add TTS commands to iOS invoke handler
  • tts.rs: Add iOS-specific path handling for TTS model storage (~/Documents/tts_models)
  • TTSContext.tsx: Update frontend to enable TTS on iOS
  • GitHub Actions: Add steps to download ONNX Runtime xcframework before iOS builds
  • setup-ios-onnxruntime.sh: New script to download pre-built ONNX Runtime 1.20.1 xcframework

Technical Details

  • Uses pre-built ONNX Runtime 1.20.1 xcframework from csukuangfj/ios-onnxruntime on HuggingFace
  • Static libraries are cached in GitHub Actions to speed up builds
  • TTS models (~264MB) are downloaded on-demand, same as desktop
  • Memory usage ~500MB RAM, suitable for modern iOS devices

Testing

  • Test on iOS simulator
  • Test on physical iOS device
  • Verify model download works on iOS
  • Verify TTS playback works on iOS

Notes

This is the first step toward iOS TTS. The implementation mirrors the desktop version - users will need to download the TTS models (~264MB) before use.

Summary by CodeRabbit

  • New Features

    • TTS now available on iOS with dedicated app initialization, deep-link handling, updater integration, and iOS-specific model/engine management.
    • UI surfaces TTS playback errors via notifications; TTS context exposes lastPlaybackError for apps to consume.
  • Chores

    • Enhanced iOS build and deployment pipeline: caching with build-from-source fallback, artifact verification, generated link configuration, runtime library propagation, and TestFlight trigger adjustments.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 9, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds iOS on-device TTS support via ONNX Runtime: CI caches or builds an xcframework, verifies artifacts, generates an absolute Cargo config, exposes ORT_LIB_LOCATION to the Tauri iOS build, adds scripts to download/build XCFrameworks, and wires iOS TTS runtime and UI error reporting in frontend code.

Changes

Cohort / File(s) Summary
CI: mobile build & TestFlight gating
/.github/workflows/mobile-build.yml, /.github/workflows/testflight-on-comment.yml
Add cache/restore for ONNX Runtime iOS xcframework, conditional build-from-source step (90m), verification steps, generate .cargo/config.toml, propagate ORT_LIB_LOCATION into iOS build env, and tighten TestFlight push/PR gating.
iOS ONNX Runtime scripts
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh, frontend/src-tauri/scripts/build-ios-onnxruntime.sh
Add download script for prebuilt xcframework and a from-source build script that clones/patches/builds device+simulator libs, assembles an xcframework, and emits verification outputs.
Tauri iOS build config & ignores
frontend/src-tauri/build.rs, frontend/src-tauri/Cargo.toml, frontend/src-tauri/.gitignore
Add iOS-specific build.rs to locate xcframework and set cargo link-search/link-lib (onnxruntime static, Foundation, Accelerate), set ORT_LIB_LOCATION; add iOS target dependencies for TTS crates; ignore onnxruntime build artifacts and .cargo.
Frontend TTS wiring & platform gating
frontend/src-tauri/src/lib.rs, frontend/src-tauri/src/tts.rs, frontend/src/services/tts/TTSContext.tsx, frontend/src/components/UnifiedChat.tsx
Enable TTS modules & invoke handlers on iOS, change models directory to HOME/Documents/tts_models on iOS, add iOS app initializer/updater/deeplink wiring, switch playback to HTMLAudioElement with lastPlaybackError surfaced and show UI notifications for playback failures.

Sequence Diagram(s)

sequenceDiagram
  participant CI as GitHub Actions
  participant Cache as Actions Cache
  participant HF as HuggingFace
  participant Script as setup/build script
  participant FS as Runner FS
  participant CargoCfg as .cargo/config.toml
  participant Tauri as Tauri iOS Build
  participant App as iOS App Runtime

  CI->>Cache: check for ONNX xcframework cache
  alt cache hit
    Cache-->>CI: restore xcframework into FS
  else cache miss
    CI->>Script: run setup-ios-onnxruntime.sh or build-ios-onnxruntime.sh
    Script->>HF: download assets or clone & build source
    Script-->>FS: produce xcframework at path
    CI->>Cache: save xcframework to cache
  end
  CI->>CargoCfg: write absolute linker paths (ORT_LIB_LOCATION)
  CI->>Tauri: run iOS build with ORT_LIB_LOCATION env
  Tauri->>CargoCfg: compile and link static onnxruntime
  Tauri-->>App: produce iOS artifact with linked ONNX Runtime
  App->>App: runtime TTS handlers call into ONNX Runtime
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped and fetched an xcframework bright,

Built by scripts beneath CI's starlit night,
Cargo paths set so runtimes find home,
Tiny voices bloom on iOS foam,
I nibble a carrot and give a small bite.

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add iOS TTS support using ONNX Runtime' directly and clearly describes the main change: adding Text-to-Speech functionality to iOS using ONNX Runtime, which is the core objective of this PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jan 9, 2026 •

Copy link
Copy Markdown

Deploying maple with  Cloudflare Pages  Cloudflare Pages

Latest commit: d146705
Status: ✅  Deploy successful!
Preview URL: https://478d8a0b.maple-ca8.pages.dev
Branch Preview URL: https://ios-tts-working-ci.maple-ca8.pages.dev

View logs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @frontend/src-tauri/scripts/setup-ios-onnxruntime.sh:
- Around line 51-53: The curl invocation that downloads Info.plist (the line
starting with curl -L -o "$XCFRAMEWORK_DIR/Info.plist"
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist") should include
the --fail flag so HTTP errors cause curl to exit non‑zero; update this curl
command and all other curl invocations in the script (the other download lines)
to use --fail (e.g., curl --fail -L -o ...) so the script’s set -e error
handling catches HTTP failures.
🧹 Nitpick comments (3)
frontend/src-tauri/src/lib.rs (1)

269-317: Consider consolidating duplicated setup logic.

The Android (lines 275-288) and iOS (lines 303-316) setup blocks have identical deep link handler code. While functional, this duplication could be reduced.

♻️ Optional: Extract shared mobile setup into a helper

You could extract the common deep link setup into a helper function to reduce duplication:

#[cfg(not(desktop))]
fn setup_mobile_deep_links(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
    let app_handle = app.handle().clone();
    app.deep_link().on_open_url(move |event| {
        if let Some(url) = event.urls().first() {
            handle_deep_link_event(url.as_ref(), &app_handle);
        }
    });
    Ok(())
}

Then call it from both Android and iOS setup blocks.

.github/workflows/mobile-build.yml (1)

56-64: Consider removing the restore-keys to prevent incompatible version restoration.

The restore-keys pattern could restore a cached older version of ONNX Runtime when the version changes from 1.20.1 to 1.20.2+. This could lead to build failures or runtime issues if the API or binary format is incompatible.

Since the setup script is idempotent and relatively fast (~100-200MB download), it's safer to only use an exact version match.

♻️ Proposed fix to remove restore-keys
      - name: Cache ONNX Runtime iOS xcframework
        uses: actions/cache@v4
        id: cache-onnxruntime
        with:
          path: frontend/src-tauri/onnxruntime-ios
          key: onnxruntime-ios-1.20.1
-         restore-keys: |
-           onnxruntime-ios-
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh (1)

1-16: Consider adding stricter error handling flags.

The script uses set -e which is good, but adding -u (exit on undefined variables) and -o pipefail (exit on pipe failures) would make the script more robust. This is especially important for build scripts that download external dependencies.

♻️ Proposed enhancement for error handling
-set -e
+set -euo pipefail

This ensures:

  • -e: Exit on any command failure
  • -u: Exit on undefined variable usage
  • -o pipefail: Exit if any command in a pipe fails (not just the last one)
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 925c1b5 and bbefadf.

⛔ Files ignored due to path filters (1)
  • frontend/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • .github/workflows/mobile-build.yml
  • .github/workflows/testflight-on-comment.yml
  • frontend/src-tauri/.gitignore
  • frontend/src-tauri/Cargo.toml
  • frontend/src-tauri/build.rs
  • frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
  • frontend/src-tauri/src/lib.rs
  • frontend/src-tauri/src/tts.rs
  • frontend/src/services/tts/TTSContext.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use path aliases (@/* maps to ./src/*) for imports in TypeScript/React files
Use 2-space indentation, double quotes, and enforce 100-character line limit in TypeScript/React code
Maintain strict TypeScript and avoid using any type
Use PascalCase for component names and camelCase for variables and function names
Use functional components with React hooks instead of class components
Use React context for global state management and TanStack Query for server state management
Run just format, just lint, and just build after making TypeScript/React changes to ensure code quality and compilation

Files:

  • frontend/src/services/tts/TTSContext.tsx
🧠 Learnings (3)
📚 Learning: 2026-01-08T17:09:40.432Z
Learnt from: AnthonyRonning
Repo: OpenSecretCloud/Maple PR: 372
File: frontend/src-tauri/Cargo.toml:9-9
Timestamp: 2026-01-08T17:09:40.432Z
Learning: The OpenSecretCloud/Maple repository has comprehensive GitHub Actions workflows (e.g., desktop-build.yml) that automatically validate compilation and testing, so manual compilation verification reminders are unnecessary when reviewing version bumps or dependency updates.

Applied to files:

  • .github/workflows/testflight-on-comment.yml
📚 Learning: 2025-03-25T19:50:07.925Z
Learnt from: AnthonyRonning
Repo: OpenSecretCloud/Maple PR: 23
File: frontend/src-tauri/src/lib.rs:14-16
Timestamp: 2025-03-25T19:50:07.925Z
Learning: In Tauri applications, updater security configurations (including endpoints, public key for verification, and dialog settings) should be defined in the tauri.conf.json file rather than duplicated in the code. When initialized with tauri_plugin_updater::Builder::new().build(), the plugin automatically reads and uses these settings from the configuration file.

Applied to files:

  • frontend/src-tauri/src/lib.rs
📚 Learning: 2025-03-25T19:50:07.925Z
Learnt from: AnthonyRonning
Repo: OpenSecretCloud/Maple PR: 23
File: frontend/src-tauri/src/lib.rs:14-16
Timestamp: 2025-03-25T19:50:07.925Z
Learning: In Tauri applications, the updater configuration (including security settings like server URL and public key) should be defined in tauri.conf.json rather than hardcoded in the application code. The code only needs to initialize the updater plugin with tauri_plugin_updater::Builder::new().build(), which will automatically use the settings from the configuration file.

Applied to files:

  • frontend/src-tauri/src/lib.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-linux
  • GitHub Check: build-macos (universal-apple-darwin)
  • GitHub Check: build-android
  • GitHub Check: build-ios
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (13)
frontend/src-tauri/.gitignore (1)

5-7: LGTM!

Correctly ignores the downloaded ONNX Runtime iOS xcframework directory, which aligns with the setup script and CI caching strategy.

frontend/src/services/tts/TTSContext.tsx (2)

10-10: LGTM!

Import correctly uses the @/* path alias as per coding guidelines.


63-64: LGTM!

The environment detection logic correctly extends TTS availability to iOS while excluding Android. Both isIOS and isTauri functions are properly exported from frontend/src/utils/platform.ts and correctly imported using the path alias in TTSContext.tsx. The comment clearly documents the intent.

frontend/src-tauri/build.rs (2)

2-30: LGTM!

The iOS build configuration correctly sets up static linking for ONNX Runtime, links required iOS frameworks (Foundation, Accelerate), and sets the ORT_LIB_LOCATION environment variable for the ort crate.


10-15: Directory structure and target detection are correct.

The xcframework directory names in build.rs (ios-arm64_x86_64-simulator and ios-arm64) match the structure created by the setup script. The target detection logic correctly routes simulator targets (containing "sim" or "x86_64") to the simulator xcframework and device targets to the device variant.

frontend/src-tauri/src/lib.rs (2)

6-8: LGTM!

The conditional compilation correctly enables the TTS module for both desktop and iOS platforms.


263-267: LGTM!

TTS state management is correctly added for iOS, mirroring the desktop configuration.

frontend/src-tauri/src/tts.rs (1)

614-633: LGTM!

The iOS-specific path handling correctly uses the app's Documents directory, which is appropriate for user-downloadable content that should persist across app updates. The HOME environment variable approach is standard for iOS apps. The early return for iOS ensures the dirs crate is never called on that platform, so including it in iOS dependencies poses no issues.

.github/workflows/testflight-on-comment.yml (1)

114-128: LGTM!

The ONNX Runtime caching configuration is well-structured:

  • Version-specific cache key (1.20.1) matches the script default, enabling proper cache invalidation on updates
  • Conditional download avoids redundant work on cache hits
  • Script at frontend/src-tauri/scripts/setup-ios-onnxruntime.sh exists and is properly structured
  • Cache path and working directory are correctly aligned with the setup script expectations
frontend/src-tauri/Cargo.toml (1)

56-69: LGTM!

The iOS dependency configuration appropriately differs from desktop:

  • ort with default-features = false for static linking compatibility with the pre-built xcframework
  • ndarray without the rayon feature, which is sensible for iOS

The dirs crate is included in the iOS dependencies but won't be used since get_tts_models_dir() returns early with the HOME-based path on iOS.

.github/workflows/mobile-build.yml (1)

65-71: LGTM!

The conditional download step is well-implemented:

  • Only runs on cache miss to avoid redundant downloads
  • Sets executable permissions before running the script
  • Working directory aligns with the script's expectations
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh (2)

17-22: LGTM!

The idempotency check is well-implemented:

  • Prevents redundant downloads when the xcframework already exists
  • Exits successfully (status 0) to allow the workflow to continue
  • Provides clear guidance for manual re-download if needed

61-78: Good user feedback and verification output.

The script provides:

  • Clear progress messages with time expectations for large downloads
  • Verification output showing downloaded contents and file sizes
  • Helpful debugging information with ls commands

This makes troubleshooting download issues much easier.

Comment on lines +24 to +50
# Create directory
mkdir -p "$ORT_DIR"

# Download pre-built xcframework from HuggingFace
# Repository: https://huggingface.co/csukuangfj/ios-onnxruntime
HF_BASE_URL="https://huggingface.co/csukuangfj/ios-onnxruntime/resolve/main"

echo "Downloading ONNX Runtime $ORT_VERSION xcframework from HuggingFace..."

# Download the xcframework directory structure
# The structure is:
# onnxruntime.xcframework/
# Info.plist
# Headers/
# cpu_provider_factory.h
# onnxruntime_c_api.h
# onnxruntime_cxx_api.h
# onnxruntime_cxx_inline.h
# ios-arm64/
# onnxruntime.a
# ios-arm64_x86_64-simulator/
# onnxruntime.a

mkdir -p "$XCFRAMEWORK_DIR/Headers"
mkdir -p "$XCFRAMEWORK_DIR/ios-arm64"
mkdir -p "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Document the third-party dependency and consider verification steps.

The script downloads pre-built binaries from a third-party HuggingFace repository (csukuangfj/ios-onnxruntime). While convenient, this introduces supply chain security considerations:

  • No checksum or signature verification of downloaded files
  • Dependency on a third-party maintainer's infrastructure
  • Potential for compromise or unavailability

Consider adding:

  1. SHA256 checksum verification for downloaded files
  2. Documentation about the trust model and why this source is acceptable
  3. A fallback mechanism or alternative source

Example checksum verification approach:

# After downloading, verify checksums
EXPECTED_ARM64_SHA256="<hash_here>"
ACTUAL_SHA256=$(shasum -a 256 "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" | cut -d' ' -f1)
if [ "$ACTUAL_SHA256" != "$EXPECTED_ARM64_SHA256" ]; then
    echo "ERROR: Checksum verification failed for ios-arm64 library"
    exit 1
fi

Comment on lines +51 to +53
echo "Downloading Info.plist..."
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add --fail flag to curl commands to catch HTTP errors.

Without --fail, curl will silently write error HTML pages (like 404 responses) to the output files, which could lead to cryptic build failures later. The --fail flag ensures curl exits with a non-zero status on HTTP errors, leveraging the set -e error handling.

♻️ Proposed fix to add --fail to all curl commands

This issue applies to all curl commands in the script (lines 52, 57-58, 62-63, 66-67). Here's the fix for this specific download:

 echo "Downloading Info.plist..."
-curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
+curl -L --fail -o "$XCFRAMEWORK_DIR/Info.plist" \
     "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"

Apply the same change to all other curl commands in the script.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
echo "Downloading Info.plist..."
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"
echo "Downloading Info.plist..."
curl -L --fail -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"
🤖 Prompt for AI Agents
In @frontend/src-tauri/scripts/setup-ios-onnxruntime.sh around lines 51 - 53,
The curl invocation that downloads Info.plist (the line starting with curl -L -o
"$XCFRAMEWORK_DIR/Info.plist"
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist") should include
the --fail flag so HTTP errors cause curl to exit non‑zero; update this curl
command and all other curl invocations in the script (the other download lines)
to use --fail (e.g., curl --fail -L -o ...) so the script’s set -e error
handling catches HTTP failures.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR extends Text-to-Speech (TTS) functionality from desktop-only to include iOS support using ONNX Runtime. The implementation follows the existing desktop architecture, downloading TTS models (~264MB) on-demand and storing them in the iOS Documents directory.

Key Changes

Build System: New setup-ios-onnxruntime.sh script downloads pre-built ONNX Runtime 1.20.1 xcframework from HuggingFace. The build configuration (build.rs) adds iOS-specific linker flags for the static ONNX Runtime library and required iOS frameworks (Foundation, Accelerate).

Dependencies: iOS-specific dependencies mirror desktop TTS dependencies with one key difference—ndarray omits the rayon feature on iOS (appropriate since rayon's threading may not work reliably on mobile).

Platform Detection: The frontend correctly updates TTS availability from desktop-only to include iOS using the existing platform detection utilities (isTauriDesktop() || (isTauri() && isIOS())).

Configuration Split: The lib.rs mobile configuration has been properly split into separate iOS and Android blocks. iOS gets TTS state management and TTS-specific commands, while Android continues with the minimal configuration (PDF extraction only).

Architecture Integration

The iOS implementation reuses the entire desktop TTS codebase without modification, except for the model storage path. On iOS, models are stored at ~/Documents/tts_models instead of using the system's data directory. The ONNX inference pipeline, text preprocessing, and audio generation remain identical across platforms.

Issues Found

  1. Path Handling Risk: The iOS path resolution uses std::env::var("HOME") which may be unreliable in sandboxed iOS apps. This could cause TTS initialization to fail even when the Documents directory is accessible.

  2. Download Security: The xcframework download script lacks checksum validation and proper HTTP error handling (no --fail flag on curl). This creates supply chain security risks—corrupted or tampered downloads could cause cryptic build failures or compromise the build.

  3. Minor Code Quality: Build script uses .unwrap() which provides poor error messages on failure.

Testing Gaps

The PR description shows the testing checklist is incomplete—no tests have been run yet on simulator or physical devices, and model download/playback verification is pending.

Confidence Score: 3/5

  • This PR has solid architectural decisions but contains reliability and security issues that should be addressed before merging
  • The score reflects well-structured platform-specific configuration and correct dependency management, but is lowered due to: (1) unreliable iOS path resolution that could cause runtime failures, (2) supply chain security concerns from unvalidated xcframework downloads, and (3) lack of testing verification. The core TTS logic is proven from desktop, but the iOS-specific integration points need hardening.
  • Pay special attention to frontend/src-tauri/src/tts.rs (iOS path handling) and frontend/src-tauri/scripts/setup-ios-onnxruntime.sh (download validation)

Important Files Changed

File Analysis

Filename Score Overview
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 3/5 Downloads ONNX Runtime xcframework from HuggingFace without checksum validation or proper error handling, creating potential supply chain security risks
frontend/src-tauri/src/tts.rs 3/5 Adds iOS path handling using unreliable HOME environment variable instead of proper iOS APIs, may fail in sandboxed environments
frontend/src-tauri/build.rs 4/5 Adds iOS-specific ONNX Runtime linker configuration, uses unwrap() which could provide better error messages
frontend/src-tauri/src/lib.rs 4/5 Properly splits mobile configuration into separate iOS and Android blocks, adds TTS commands for iOS

Sequence Diagram

sequenceDiagram
    participant User
    participant TTSContext as TTSContext.tsx
    participant Tauri as Tauri Bridge
    participant TTS as tts.rs
    participant ONNX as ONNX Runtime
    participant HF as HuggingFace

    Note over User,HF: TTS Initialization Flow (iOS)
    
    User->>TTSContext: App loads on iOS
    TTSContext->>Tauri: invoke("tts_get_status")
    Tauri->>TTS: tts_get_status()
    TTS->>TTS: Check ~/Documents/tts_models
    TTS-->>Tauri: {models_downloaded: false, models_loaded: false}
    Tauri-->>TTSContext: Status response
    TTSContext->>TTSContext: Set status: "not_downloaded"
    
    Note over User,HF: Model Download Flow
    
    User->>TTSContext: Click download models
    TTSContext->>Tauri: invoke("tts_download_models")
    Tauri->>TTS: tts_download_models()
    
    loop For each model file
        TTS->>HF: Download model file (~264MB total)
        HF-->>TTS: Model file chunks
        TTS->>TTS: Verify SHA256 checksum
        TTS->>Tauri: Emit download progress
        Tauri-->>TTSContext: "tts-download-progress" event
        TTSContext->>TTSContext: Update progress UI
    end
    
    TTS-->>Tauri: Download complete
    Tauri-->>TTSContext: Success
    TTSContext->>Tauri: invoke("tts_load_models")
    Tauri->>TTS: tts_load_models()
    TTS->>ONNX: Load ONNX sessions
    ONNX-->>TTS: Sessions loaded (~500MB RAM)
    TTS-->>Tauri: Success
    Tauri-->>TTSContext: Models loaded
    TTSContext->>TTSContext: Set status: "ready"
    
    Note over User,HF: Speech Synthesis Flow
    
    User->>TTSContext: Request TTS for message
    TTSContext->>TTSContext: Preprocess text (remove code/thinking)
    TTSContext->>Tauri: invoke("tts_synthesize", {text})
    Tauri->>TTS: tts_synthesize(text)
    TTS->>TTS: Chunk text (~300 chars)
    TTS->>TTS: Preprocess chunks
    
    loop For each chunk
        TTS->>ONNX: Predict duration
        TTS->>ONNX: Encode text
        TTS->>ONNX: Denoise latent (10 steps)
        TTS->>ONNX: Generate waveform
    end
    
    TTS->>TTS: Concatenate audio chunks
    TTS->>TTS: Encode to WAV base64
    TTS-->>Tauri: {audio_base64, sample_rate, duration}
    Tauri-->>TTSContext: Synthesis result
    TTSContext->>TTSContext: Decode base64 to audio
    TTSContext->>TTSContext: Play via Web Audio API
    TTSContext->>User: Audio playback
Loading

Comment on lines +62 to +67
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/onnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The curl commands download large binary files without any validation or error handling. Several issues:

  1. Missing --fail flag: If the HuggingFace URL returns a 404 or other HTTP error, curl will save the error page as a valid file, causing cryptic build failures later
  2. No checksum validation: Unlike the TTS model downloads in tts.rs which verify SHA256 checksums, these xcframework files are not validated
  3. No retry logic: Network failures will cause the entire download to fail without retry

This could lead to corrupted builds or supply chain security issues if the downloaded files are tampered with.

Recommendation: Add --fail flag to all curl commands and consider adding checksum validation similar to the TTS model downloads.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 62:67

Comment:
The curl commands download large binary files without any validation or error handling. Several issues:

1. **Missing `--fail` flag**: If the HuggingFace URL returns a 404 or other HTTP error, curl will save the error page as a valid file, causing cryptic build failures later
2. **No checksum validation**: Unlike the TTS model downloads in `tts.rs` which verify SHA256 checksums, these xcframework files are not validated
3. **No retry logic**: Network failures will cause the entire download to fail without retry

This could lead to corrupted builds or supply chain security issues if the downloaded files are tampered with.

**Recommendation**: Add `--fail` flag to all curl commands and consider adding checksum validation similar to the TTS model downloads.

How can I resolve this? If you propose a fix, please make it concise.

{
// On iOS, use the app's Documents directory which is accessible and persists
// NSHomeDirectory() + /Documents/tts_models
let home = std::env::var("HOME").context("Failed to get HOME directory on iOS")?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using std::env::var("HOME") is unreliable on iOS. The HOME environment variable may not be set or may not point to the expected location in sandboxed iOS apps.

Issue: If HOME is not set, this will return an error and TTS will fail to initialize, even though the app directory is accessible through proper iOS APIs.

Recommendation: Consider using Tauri's path resolution APIs (e.g., app_handle.path().app_data_dir() or similar) instead of relying on environment variables. This would be more robust and consistent with how Tauri handles paths across platforms.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/src/tts.rs
Line: 620:620

Comment:
Using `std::env::var("HOME")` is unreliable on iOS. The HOME environment variable may not be set or may not point to the expected location in sandboxed iOS apps.

**Issue**: If HOME is not set, this will return an error and TTS will fail to initialize, even though the app directory is accessible through proper iOS APIs.

**Recommendation**: Consider using Tauri's path resolution APIs (e.g., `app_handle.path().app_data_dir()` or similar) instead of relying on environment variables. This would be more robust and consistent with how Tauri handles paths across platforms.

How can I resolve this? If you propose a fix, please make it concise.

#[cfg(target_os = "ios")]
{
// Get the path to the ONNX Runtime xcframework
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using .unwrap() in build scripts provides poor error messages when failures occur. While CARGO_MANIFEST_DIR should always be set during builds, if it's not set for any reason, the build will panic with an unhelpful error message.

Recommendation: Use .expect("CARGO_MANIFEST_DIR not set") to provide a more descriptive error message, or use .context() from anyhow if error handling is needed.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 6:6

Comment:
Using `.unwrap()` in build scripts provides poor error messages when failures occur. While `CARGO_MANIFEST_DIR` should always be set during builds, if it's not set for any reason, the build will panic with an unhelpful error message.

**Recommendation**: Use `.expect("CARGO_MANIFEST_DIR not set")` to provide a more descriptive error message, or use `.context()` from anyhow if error handling is needed.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds Text-to-Speech (TTS) support for iOS using ONNX Runtime, enabling the Supertonic TTS model to run on-device on iPhones and iPads. The implementation mirrors the existing desktop TTS functionality and makes the following key changes:

Core Changes:

  • iOS Build Configuration: Downloads pre-built ONNX Runtime 1.20.1 xcframework from HuggingFace during CI/CD builds, with caching to optimize build times
  • Linker Setup: Configures iOS-specific static library linking in build.rs, detecting simulator vs device targets and linking appropriate ONNX Runtime binaries along with Foundation and Accelerate frameworks
  • Module Enablement: Extends TTS module compilation from desktop-only to include iOS via #[cfg(any(desktop, target_os = "ios"))]
  • iOS-Specific Storage: Uses ~/Documents/tts_models for iOS model storage (vs platform-specific data directories on desktop) since dirs::data_local_dir() may not work reliably on iOS
  • Frontend Detection: Updates TTSContext.tsx to recognize iOS as a TTS-capable platform alongside desktop
  • Split Mobile Configuration: Separates Android and iOS invoke handlers in lib.rs to add TTS commands only to iOS

Architecture:
The implementation uses pre-built static ONNX Runtime libraries (avoiding runtime binary downloads) and follows iOS sandboxing requirements. Models (~264MB) are downloaded on-demand at runtime and stored in the app's Documents directory. The TTS pipeline runs entirely on-device using iOS's Accelerate framework for neural network acceleration.

Integration Quality:
The changes are well-structured and maintain clean separation between platforms. The iOS implementation reuses the existing desktop TTS codebase with minimal platform-specific modifications (primarily path handling). GitHub Actions workflows properly cache the ONNX Runtime xcframework to avoid repeated downloads.

Confidence Score: 5/5

  • This PR is safe to merge. The implementation is well-structured, platform-specific changes are properly isolated with cfg attributes, and the code follows established patterns from the desktop TTS implementation.
  • All changes are isolated to iOS-specific code paths with proper conditional compilation. The build configuration correctly handles simulator and device targets. The iOS-specific storage path using ~/Documents is appropriate for the iOS sandbox. The GitHub Actions workflows properly cache dependencies. No breaking changes to existing desktop or Android functionality.
  • No files require special attention. All implementations are correct and follow iOS development best practices.

Important Files Changed

File Analysis

Filename Score Overview
.github/workflows/mobile-build.yml 5/5 Adds ONNX Runtime xcframework download and caching before iOS build. Implementation is correct with proper cache keys.
.github/workflows/testflight-on-comment.yml 5/5 Adds identical ONNX Runtime setup as mobile-build.yml. Correctly placed before Xcode setup.
frontend/src-tauri/.gitignore 5/5 Adds /onnxruntime-ios/ to gitignore. Correctly excludes build-time downloaded dependencies.
frontend/src-tauri/Cargo.toml 5/5 Adds iOS-specific TTS dependencies with disabled default features for ort. Correctly mirrors desktop dependencies except for ndarray features.
frontend/src-tauri/build.rs 5/5 Adds iOS linker configuration for ONNX Runtime xcframework. Correctly detects simulator vs device targets and links appropriate static libraries.
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 5/5 New script to download ONNX Runtime 1.20.1 xcframework from HuggingFace. Downloads Info.plist, headers, and static libraries for both device and simulator.
frontend/src-tauri/src/lib.rs 5/5 Enables TTS module for iOS and adds TTS commands to iOS invoke handler. Splits mobile configuration into separate Android and iOS blocks with appropriate handlers.
frontend/src-tauri/src/tts.rs 5/5 Adds iOS-specific path handling using ~/Documents/tts_models for model storage. Correctly uses HOME env var fallback for iOS.
frontend/src/services/tts/TTSContext.tsx 5/5 Updates isTauriEnv check to enable TTS on iOS alongside desktop. Correctly excludes Android.
frontend/bun.lock 5/5 Lockfile changes. No issues detected.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant UI as Frontend (TTSContext.tsx)
    participant Tauri as Tauri IPC Bridge
    participant Rust as Rust Backend (tts.rs)
    participant ORT as ONNX Runtime
    participant FS as File System

    Note over User,FS: App Initialization (iOS)
    UI->>UI: Check platform: isTauri() && isIOS()
    UI->>Tauri: invoke("tts_get_status")
    Tauri->>Rust: tts_get_status()
    Rust->>FS: Check ~/Documents/tts_models/
    FS-->>Rust: Directory status
    Rust-->>Tauri: {models_downloaded, models_loaded, total_size_mb}
    Tauri-->>UI: Status response
    
    alt Models not downloaded
        UI->>UI: Set status "not_downloaded"
        User->>UI: Click download button
        UI->>Tauri: invoke("tts_download_models")
        Tauri->>Rust: tts_download_models()
        loop For each model file
            Rust->>Rust: Download from HuggingFace
            Rust->>Tauri: emit("tts-download-progress")
            Tauri->>UI: Progress event
            UI->>UI: Update progress bar
        end
        Rust->>FS: Save models to ~/Documents/tts_models/
        Rust-->>Tauri: Download complete
        UI->>Tauri: invoke("tts_load_models")
    end
    
    Note over User,FS: Model Loading
    Tauri->>Rust: tts_load_models()
    Rust->>FS: Read model files from ~/Documents/tts_models/
    FS-->>Rust: Model data
    Rust->>ORT: Create ONNX sessions
    ORT->>ORT: Load to iOS Accelerate framework
    ORT-->>Rust: Sessions ready
    Rust-->>Tauri: Models loaded
    Tauri-->>UI: Success
    UI->>UI: Set status "ready"
    
    Note over User,FS: Text-to-Speech Synthesis
    User->>UI: Click speak button
    UI->>UI: Preprocess text (remove code blocks)
    UI->>Tauri: invoke("tts_synthesize", {text})
    Tauri->>Rust: tts_synthesize(text)
    Rust->>Rust: Text preprocessing & normalization
    Rust->>ORT: Run text_encoder session
    ORT-->>Rust: Text embeddings
    Rust->>ORT: Run duration_predictor session
    ORT-->>Rust: Duration values
    Rust->>ORT: Run vector_estimator session
    ORT-->>Rust: Latent vectors
    Rust->>ORT: Run vocoder session
    ORT-->>Rust: WAV audio data
    Rust->>Rust: Encode to base64
    Rust-->>Tauri: {audio_base64, sample_rate, duration_seconds}
    Tauri-->>UI: Audio response
    UI->>UI: Decode base64 to Blob
    UI->>UI: Create AudioContext
    UI->>UI: Play audio via Web Audio API
Loading

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR successfully enables on-device Text-to-Speech for iOS using ONNX Runtime and the Supertonic model. The implementation mirrors the existing desktop TTS functionality with iOS-specific adaptations for static library linking and storage paths.

Major Changes:

  • Downloads pre-built ONNX Runtime 1.20.1 xcframework from HuggingFace during CI builds
  • Configures iOS linker to use static ONNX Runtime libraries for simulator and device targets
  • Stores TTS models in ~/Documents/tts_models on iOS (sandboxed app directory)
  • Updates frontend platform detection to enable TTS on iOS (but not Android)
  • Adds caching to CI workflows to speed up builds

Issues Found:

  • Security concern: Download script lacks checksum verification (unlike the Rust download code which validates SHA256)
  • CI reliability: No validation of cached xcframework files - broken cache could cause build failures
  • Build validation: build.rs doesn't verify xcframework exists before setting linker flags, leading to cryptic errors if download fails

The implementation is architecturally sound with proper conditional compilation, correct platform detection, and appropriate error handling in the Rust code. The main concerns are around the CI/build pipeline's robustness and the security of the binary download process.

Confidence Score: 3/5

  • Safe to merge with moderate risk - the runtime code is solid, but build/CI pipeline has reliability and security gaps
  • Score reflects well-structured runtime implementation with proper error handling, but notable issues in the build pipeline: missing checksum verification for binary downloads creates a security vulnerability, and lack of cache validation could cause CI failures. The core iOS TTS functionality mirrors the proven desktop implementation and should work correctly once built.
  • Pay close attention to setup-ios-onnxruntime.sh (security), build.rs (validation), and both workflow files (cache reliability)

Important Files Changed

File Analysis

Filename Score Overview
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 3/5 Downloads ONNX Runtime xcframework from HuggingFace but lacks checksum verification, posing a security risk
frontend/src-tauri/build.rs 4/5 iOS linker configuration for ONNX Runtime. Target detection logic is correct, but missing validation that xcframework exists before build
frontend/src-tauri/src/tts.rs 4/5 Adds iOS-specific path handling using HOME/Documents directory. Implementation is functional but could benefit from using Tauri's filesystem APIs
.github/workflows/mobile-build.yml 4/5 Adds ONNX Runtime download and caching for iOS builds. Missing validation step for cached files could lead to broken builds
.github/workflows/testflight-on-comment.yml 4/5 Adds ONNX Runtime download and caching for TestFlight builds. Same cache validation issue as mobile-build.yml

Sequence Diagram

sequenceDiagram
    participant User
    participant TTSContext as TTSContext.tsx
    participant Backend as Rust Backend
    participant Models as Model Storage
    participant ONNX as ONNX Runtime

    Note over User,ONNX: iOS TTS Initialization Flow
    
    User->>TTSContext: App starts on iOS
    TTSContext->>TTSContext: Detect platform (isTauri() && isIOS())
    TTSContext->>Backend: invoke('tts_get_status')
    Backend->>Models: Check if models exist in ~/Documents/tts_models
    Models-->>Backend: models_downloaded: false
    Backend-->>TTSContext: Status: not_downloaded
    
    Note over User,ONNX: Model Download Flow
    
    User->>TTSContext: Trigger download
    TTSContext->>Backend: invoke('tts_download_models')
    Backend->>Models: Download from HuggingFace (with SHA256 verification)
    Models-->>Backend: Models saved to ~/Documents/tts_models
    Backend-->>TTSContext: emit('tts-download-progress')
    TTSContext->>Backend: invoke('tts_load_models')
    Backend->>Models: Load ONNX models
    Backend->>ONNX: Initialize sessions (duration_predictor, text_encoder, etc.)
    ONNX-->>Backend: Sessions ready
    Backend-->>TTSContext: Status: ready
    
    Note over User,ONNX: TTS Synthesis Flow
    
    User->>TTSContext: speak(text, messageId)
    TTSContext->>TTSContext: preprocess text (remove code blocks, think tags)
    TTSContext->>Backend: invoke('tts_synthesize', {text})
    Backend->>Backend: Chunk text (max 300 chars)
    Backend->>ONNX: Run inference pipeline
    ONNX->>ONNX: Text encoding → Duration prediction → Denoising → Vocoder
    ONNX-->>Backend: Audio samples (f32[])
    Backend->>Backend: Convert to WAV and Base64 encode
    Backend-->>TTSContext: {audio_base64, sample_rate}
    TTSContext->>TTSContext: Decode Base64 → AudioContext → Play
    TTSContext-->>User: Audio playback

Loading

Comment on lines +52 to +67
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"

echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done

echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/onnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security: Downloads from HuggingFace lack integrity verification. Unlike the Rust tts_download_models function (tts.rs lines 832-889) which verifies SHA256 checksums, this script downloads and trusts binary files without any verification. Consider adding checksum validation to prevent supply chain attacks.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 52:67

Comment:
Security: Downloads from HuggingFace lack integrity verification. Unlike the Rust `tts_download_models` function (tts.rs lines 832-889) which verifies SHA256 checksums, this script downloads and trusts binary files without any verification. Consider adding checksum validation to prevent supply chain attacks.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread .github/workflows/mobile-build.yml Outdated
Comment on lines +56 to +70
- name: Cache ONNX Runtime iOS xcframework
uses: actions/cache@v4
id: cache-onnxruntime
with:
path: frontend/src-tauri/onnxruntime-ios
key: onnxruntime-ios-1.20.1
restore-keys: |
onnxruntime-ios-

- name: Download ONNX Runtime for iOS
if: steps.cache-onnxruntime.outputs.cache-hit != 'true'
working-directory: ./frontend/src-tauri
run: |
chmod +x scripts/setup-ios-onnxruntime.sh
./scripts/setup-ios-onnxruntime.sh

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cache validation: No verification that cached xcframework is complete/valid. If a previous build cached a partial download, subsequent builds will use the broken cache without detection. Consider adding a validation step after cache restore (e.g., check file sizes or presence of key files).

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 56:70

Comment:
Cache validation: No verification that cached xcframework is complete/valid. If a previous build cached a partial download, subsequent builds will use the broken cache without detection. Consider adding a validation step after cache restore (e.g., check file sizes or presence of key files).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +6 to +15
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let ort_dir = format!("{}/onnxruntime-ios", manifest_dir);

// Check if building for simulator or device
let target = std::env::var("TARGET").unwrap_or_default();
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
} else {
format!("{}/onnxruntime.xcframework/ios-arm64", ort_dir)
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing validation: No check if xcframework exists before setting linker flags. If download step fails silently or is skipped, the build fails with cryptic linker errors. Consider adding a check with a helpful error message:

let ort_dir = format!("{}/onnxruntime-ios", manifest_dir);
let xcframework_path = format!("{}/onnxruntime.xcframework", ort_dir);
if !std::path::Path::new(&xcframework_path).exists() {
    panic!("ONNX Runtime xcframework not found at {}. Run scripts/setup-ios-onnxruntime.sh first.", xcframework_path);
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 6:15

Comment:
Missing validation: No check if xcframework exists before setting linker flags. If download step fails silently or is skipped, the build fails with cryptic linker errors. Consider adding a check with a helpful error message:

```rust
let ort_dir = format!("{}/onnxruntime-ios", manifest_dir);
let xcframework_path = format!("{}/onnxruntime.xcframework", ort_dir);
if !std::path::Path::new(&xcframework_path).exists() {
    panic!("ONNX Runtime xcframework not found at {}. Run scripts/setup-ios-onnxruntime.sh first.", xcframework_path);
}
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 614 to +623
fn get_tts_models_dir() -> Result<PathBuf> {
let data_dir = dirs::data_local_dir()
.context("Failed to get local data directory")?
.join("cloud.opensecret.maple")
.join("tts_models");
Ok(data_dir)
// On iOS, we need to use a different approach since dirs::data_local_dir() may not work
#[cfg(target_os = "ios")]
{
// On iOS, use the app's Documents directory which is accessible and persists
// NSHomeDirectory() + /Documents/tts_models
let home = std::env::var("HOME").context("Failed to get HOME directory on iOS")?;
let data_dir = PathBuf::from(home).join("Documents").join("tts_models");
return Ok(data_dir);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using tauri-plugin-fs for cross-platform path handling. While $HOME/Documents works for iOS sandboxed apps, using Tauri's filesystem plugin would be more consistent with the rest of the app and provide better error messages if the directory is inaccessible.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/src/tts.rs
Line: 614:623

Comment:
Consider using `tauri-plugin-fs` for cross-platform path handling. While `$HOME/Documents` works for iOS sandboxed apps, using Tauri's filesystem plugin would be more consistent with the rest of the app and provide better error messages if the directory is inaccessible.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +114 to +128
- name: Cache ONNX Runtime iOS xcframework
uses: actions/cache@v4
id: cache-onnxruntime
with:
path: frontend/src-tauri/onnxruntime-ios
key: onnxruntime-ios-1.20.1
restore-keys: |
onnxruntime-ios-

- name: Download ONNX Runtime for iOS
if: steps.cache-onnxruntime.outputs.cache-hit != 'true'
working-directory: ./frontend/src-tauri
run: |
chmod +x scripts/setup-ios-onnxruntime.sh
./scripts/setup-ios-onnxruntime.sh

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cache validation: No verification that cached xcframework is complete/valid. If a previous build cached a partial download, subsequent builds will use the broken cache without detection. Consider adding a validation step after cache restore (e.g., check file sizes or presence of key files).

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 114:128

Comment:
Cache validation: No verification that cached xcframework is complete/valid. If a previous build cached a partial download, subsequent builds will use the broken cache without detection. Consider adding a validation step after cache restore (e.g., check file sizes or presence of key files).

How can I resolve this? If you propose a fix, please make it concise.

AnthonyRonning and others added 4 commits January 9, 2026 12:46
- Add iOS-specific ort dependencies in Cargo.toml
- Update build.rs to link ONNX Runtime xcframework for iOS
- Enable TTS module for iOS in lib.rs (was desktop-only)
- Add iOS-specific path handling in tts.rs for model storage
- Update TTSContext.tsx to enable TTS on iOS
- Add setup-ios-onnxruntime.sh script to download pre-built xcframework
- Update GitHub Actions workflows to download ONNX Runtime before iOS builds
- Add onnxruntime-ios/ to .gitignore

Uses pre-built ONNX Runtime 1.20.1 xcframework from HuggingFace
(csukuangfj/ios-onnxruntime) for static linking on iOS.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
The ort crate requires the ndarray feature to be explicitly enabled
when default-features = false. This fixes the iOS build by enabling
the ndarray feature which provides OwnedTensorArrayData trait
implementations for ndarray types.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
The ort crate requires the 'std' feature for:
1. ort::Error to implement std::error::Error (StdError trait)
2. commit_from_file method for loading ONNX models from filesystem

Without 'std', the ? operator cannot convert ort::Error to anyhow::Error
and file-based session loading is unavailable.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
The ort-sys crate needs ORT_LIB_LOCATION environment variable set
before cargo build starts to locate the ONNX Runtime static library.
Setting it in build.rs doesn't work because ort-sys checks for the
library during its own build process.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds Text-to-Speech (TTS) support for iOS using ONNX Runtime, enabling the Supertonic TTS model to run on-device. The implementation mirrors the existing desktop TTS functionality and involves changes across build configuration, runtime initialization, and frontend platform detection.

Key Changes

Build Infrastructure:

  • Adds a download script (setup-ios-onnxruntime.sh) to fetch pre-built ONNX Runtime 1.20.1 xcframework from HuggingFace
  • Configures GitHub Actions workflows to cache and setup ONNX Runtime before iOS builds
  • Adds iOS-specific linker configuration in build.rs to link the static ONNX Runtime library

Runtime Configuration:

  • Enables the TTS module for iOS (previously desktop-only) with conditional compilation
  • Adds TTS state management and command handlers to the iOS-specific app configuration
  • Updates iOS storage path to use ~/Documents/tts_models instead of standard app data directory

Frontend Integration:

  • Updates TTSContext.tsx to enable TTS on iOS by checking isTauri() && isIOS()
  • Maintains the same user-facing behavior: users download models on-demand (~264MB)

Architecture

The implementation follows the existing desktop TTS pattern:

  1. ONNX Runtime xcframework is downloaded at build time and cached
  2. TTS models are downloaded by users at runtime on first use
  3. Models are loaded into memory and used for on-device synthesis
  4. Same Supertonic model used across desktop and iOS for consistency

Issues Identified

The implementation has several issues that need to be addressed:

  1. Critical: Incorrect ORT_LIB_LOCATION path - Both GitHub Actions workflows set the environment variable to point to a subdirectory instead of the base directory, which conflicts with how build.rs expects it

  2. Security: Missing checksum verification - The setup script downloads large binary files without verifying their integrity, unlike the TTS model downloads which include SHA256 verification

  3. Robustness: No directory existence check - The build script doesn't verify the ONNX Runtime directory exists, leading to cryptic linker errors if setup fails

  4. Reliability: HOME environment variable usage - iOS path handling relies on the HOME env var which may not be reliable in all iOS contexts (sandboxed apps, extensions)

Confidence Score: 2/5

  • This PR has critical configuration issues that will likely cause build failures and security concerns
  • Score reflects two critical issues: (1) ORT_LIB_LOCATION path mismatch will cause builds to fail or link incorrectly, and (2) missing checksum verification for downloaded binaries creates security risk. The setup script downloads ~100MB+ of unverified binary code from HuggingFace. Additional robustness issues include lack of build-time directory checks and questionable iOS path handling.
  • Pay close attention to .github/workflows/mobile-build.yml and testflight-on-comment.yml (ORT_LIB_LOCATION paths must be fixed), frontend/src-tauri/scripts/setup-ios-onnxruntime.sh (needs checksum verification), and frontend/src-tauri/build.rs (needs existence check)

Important Files Changed

File Analysis

Filename Score Overview
.github/workflows/mobile-build.yml 3/5 Adds ONNX Runtime caching and setup for iOS builds, but ORT_LIB_LOCATION path is incorrect
.github/workflows/testflight-on-comment.yml 3/5 Adds ONNX Runtime caching and setup for TestFlight builds, same ORT_LIB_LOCATION path issue
frontend/src-tauri/build.rs 3/5 Adds iOS linker configuration for ONNX Runtime, but lacks directory existence check
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 2/5 Downloads ONNX Runtime xcframework for iOS, but missing checksum verification for downloaded files
frontend/src-tauri/src/lib.rs 4/5 Enables TTS module for iOS, adds TTS commands to iOS invoke handler and state management
frontend/src-tauri/src/tts.rs 3/5 Adds iOS-specific path handling using HOME env var, which may not be reliable in all contexts

Sequence Diagram

sequenceDiagram
    participant User
    participant Frontend as TTSContext (Frontend)
    participant Tauri as Tauri Runtime
    participant TTS as TTS Module (Rust)
    participant FS as File System
    participant ONNX as ONNX Runtime
    participant HF as HuggingFace

    Note over User,HF: Build Time Setup
    User->>Tauri: Trigger iOS Build
    Tauri->>FS: Check onnxruntime-ios cache
    alt Cache Miss
        Tauri->>HF: Download xcframework (setup-ios-onnxruntime.sh)
        HF-->>FS: ONNX Runtime binaries (~100MB)
        Note over FS: No checksum verification ⚠️
    end
    Tauri->>ONNX: Link static library (build.rs)
    Note over ONNX: ORT_LIB_LOCATION path issue ⚠️
    
    Note over User,HF: Runtime - First Use
    User->>Frontend: Enable TTS
    Frontend->>Tauri: tts_get_status()
    Tauri->>TTS: Check models
    TTS->>FS: Check ~/Documents/tts_models
    Note over FS: HOME env var usage ⚠️
    TTS-->>Frontend: models_downloaded=false
    
    User->>Frontend: Download Models
    Frontend->>Tauri: tts_download_models()
    Tauri->>TTS: Download from HuggingFace
    loop For each model file
        TTS->>HF: Download model
        HF-->>TTS: Model data
        TTS->>TTS: Verify SHA256 checksum
        TTS->>FS: Save to ~/Documents/tts_models
        TTS-->>Frontend: Progress event
    end
    
    Frontend->>Tauri: tts_load_models()
    Tauri->>TTS: Load models
    TTS->>FS: Read model files
    TTS->>ONNX: Create ONNX sessions
    ONNX-->>TTS: Sessions ready
    TTS-->>Frontend: Models loaded
    
    Note over User,HF: Runtime - Synthesis
    User->>Frontend: Click speak button
    Frontend->>Tauri: tts_synthesize(text)
    Tauri->>TTS: Synthesize
    TTS->>TTS: Preprocess text
    TTS->>ONNX: Run inference (4 models)
    ONNX-->>TTS: Audio samples
    TTS->>TTS: Encode to WAV + base64
    TTS-->>Frontend: audio_base64
    Frontend->>Frontend: Decode & play via Web Audio API
Loading

VITE_MAPLE_BILLING_API_URL: https://billing.opensecret.cloud
VITE_CLIENT_ID: ba5a14b5-d915-47b1-b7b1-afda52bc5fc6
# ONNX Runtime location for ort-sys crate
ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ORT_LIB_LOCATION path is incorrect. According to the build.rs file (line 26), ORT_LIB_LOCATION should point to the onnxruntime-ios directory, not to the ios-arm64 subdirectory within the xcframework.

The build.rs sets ORT_LIB_LOCATION={ort_dir} where ort_dir = "{manifest_dir}/onnxruntime-ios", and then constructs the lib_path by appending the appropriate xcframework subdirectory based on the target.

Suggested change
ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64
ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 109:109

Comment:
The `ORT_LIB_LOCATION` path is incorrect. According to the build.rs file (line 26), `ORT_LIB_LOCATION` should point to the `onnxruntime-ios` directory, not to the `ios-arm64` subdirectory within the xcframework.

The build.rs sets `ORT_LIB_LOCATION={ort_dir}` where `ort_dir = "{manifest_dir}/onnxruntime-ios"`, and then constructs the lib_path by appending the appropriate xcframework subdirectory based on the target.

```suggestion
          ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios
```

How can I resolve this? If you propose a fix, please make it concise.

VITE_MAPLE_BILLING_API_URL: https://billing.opensecret.cloud
VITE_CLIENT_ID: ba5a14b5-d915-47b1-b7b1-afda52bc5fc6
# ONNX Runtime location for ort-sys crate
ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ORT_LIB_LOCATION path is incorrect - same issue as in mobile-build.yml. According to the build.rs file (line 26), ORT_LIB_LOCATION should point to the onnxruntime-ios directory, not to the ios-arm64 subdirectory within the xcframework.

Suggested change
ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64
ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 167:167

Comment:
The `ORT_LIB_LOCATION` path is incorrect - same issue as in mobile-build.yml. According to the build.rs file (line 26), `ORT_LIB_LOCATION` should point to the `onnxruntime-ios` directory, not to the `ios-arm64` subdirectory within the xcframework.

```suggestion
          ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +51 to +67
echo "Downloading Info.plist..."
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"

echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done

echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/onnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The downloaded ONNX Runtime files are not verified with checksums before use. This creates a security risk as corrupted or tampered files could be used without detection. The TTS model downloads (in tts.rs) include SHA256 verification - the same approach should be used here.

Consider adding checksum verification similar to the TTS model downloads:

echo "Downloading iOS arm64 static library..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

# Verify checksum
EXPECTED_SHA256="<expected_hash_here>"
ACTUAL_SHA256=$(shasum -a 256 "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" | awk '{print $1}')
if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then
    echo "Error: Checksum mismatch for ios-arm64/onnxruntime.a"
    exit 1
fi
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 51:67

Comment:
The downloaded ONNX Runtime files are not verified with checksums before use. This creates a security risk as corrupted or tampered files could be used without detection. The TTS model downloads (in tts.rs) include SHA256 verification - the same approach should be used here.

Consider adding checksum verification similar to the TTS model downloads:
```bash
echo "Downloading iOS arm64 static library..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

# Verify checksum
EXPECTED_SHA256="<expected_hash_here>"
ACTUAL_SHA256=$(shasum -a 256 "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" | awk '{print $1}')
if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then
    echo "Error: Checksum mismatch for ios-arm64/onnxruntime.a"
    exit 1
fi
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +3 to +15
#[cfg(target_os = "ios")]
{
// Get the path to the ONNX Runtime xcframework
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let ort_dir = format!("{}/onnxruntime-ios", manifest_dir);

// Check if building for simulator or device
let target = std::env::var("TARGET").unwrap_or_default();
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
} else {
format!("{}/onnxruntime.xcframework/ios-arm64", ort_dir)
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build script doesn't verify that the ONNX Runtime directory exists before attempting to use it. If the setup script fails or hasn't been run, this will cause cryptic linker errors that are difficult to debug.

Consider adding a check with a helpful error message:

Suggested change
#[cfg(target_os = "ios")]
{
// Get the path to the ONNX Runtime xcframework
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let ort_dir = format!("{}/onnxruntime-ios", manifest_dir);
// Check if building for simulator or device
let target = std::env::var("TARGET").unwrap_or_default();
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
} else {
format!("{}/onnxruntime.xcframework/ios-arm64", ort_dir)
};
#[cfg(target_os = "ios")]
{
// Get the path to the ONNX Runtime xcframework
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let ort_dir = format!("{}/onnxruntime-ios", manifest_dir);
// Verify the xcframework exists before proceeding
let xcframework_path = format!("{}/onnxruntime.xcframework", ort_dir);
if !std::path::Path::new(&xcframework_path).exists() {
panic!(
"ONNX Runtime xcframework not found at: {}\n\
Please run: ./scripts/setup-ios-onnxruntime.sh",
xcframework_path
);
}
// Check if building for simulator or device
let target = std::env::var("TARGET").unwrap_or_default();
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
} else {
format!("{}/onnxruntime.xcframework/ios-arm64", ort_dir)
};
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 3:15

Comment:
The build script doesn't verify that the ONNX Runtime directory exists before attempting to use it. If the setup script fails or hasn't been run, this will cause cryptic linker errors that are difficult to debug.

Consider adding a check with a helpful error message:

```suggestion
    #[cfg(target_os = "ios")]
    {
        // Get the path to the ONNX Runtime xcframework
        let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
        let ort_dir = format!("{}/onnxruntime-ios", manifest_dir);
        
        // Verify the xcframework exists before proceeding
        let xcframework_path = format!("{}/onnxruntime.xcframework", ort_dir);
        if !std::path::Path::new(&xcframework_path).exists() {
            panic!(
                "ONNX Runtime xcframework not found at: {}\n\
                Please run: ./scripts/setup-ios-onnxruntime.sh",
                xcframework_path
            );
        }
        
        // Check if building for simulator or device
        let target = std::env::var("TARGET").unwrap_or_default();
        let lib_path = if target.contains("sim") || target.contains("x86_64") {
            format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
        } else {
            format!("{}/onnxruntime.xcframework/ios-arm64", ort_dir)
        };
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +616 to +623
#[cfg(target_os = "ios")]
{
// On iOS, use the app's Documents directory which is accessible and persists
// NSHomeDirectory() + /Documents/tts_models
let home = std::env::var("HOME").context("Failed to get HOME directory on iOS")?;
let data_dir = PathBuf::from(home).join("Documents").join("tts_models");
return Ok(data_dir);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using std::env::var("HOME") on iOS may not be reliable in all contexts (sandboxed apps, different iOS versions, app extensions). Consider using Tauri's path APIs or iOS-specific APIs to get the documents directory more reliably.

For example, you could use Tauri's app_data_dir() or app_document_dir() functions which properly handle iOS sandboxing and provide the correct paths for the application's data storage.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/src/tts.rs
Line: 616:623

Comment:
Using `std::env::var("HOME")` on iOS may not be reliable in all contexts (sandboxed apps, different iOS versions, app extensions). Consider using Tauri's path APIs or iOS-specific APIs to get the documents directory more reliably.

For example, you could use Tauri's `app_data_dir()` or `app_document_dir()` functions which properly handle iOS sandboxing and provide the correct paths for the application's data storage.

How can I resolve this? If you propose a fix, please make it concise.

The ort-sys crate expects the static library to be named 'libonnxruntime.a'
(with the 'lib' prefix), not 'onnxruntime.a'. Also adds verification step
to debug library location and invalidates cache to force re-download.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @frontend/src-tauri/Cargo.toml:
- Around line 56-71: The Cargo.toml currently pins the ONNX Runtime crate as ort
= "2.0.0-rc.10" (pre-release); replace this with a stable ort version (e.g., the
latest 1.x stable) or, if 2.0.0-rc.10 is required for iOS support, add a comment
documenting the exact compatibility reason and link to the upstream release
notes; update the ort entry in the target.'cfg(target_os = "ios")'.dependencies
block accordingly and ensure feature flags (["std","ndarray"]) remain correct
for the chosen stable version.
🧹 Nitpick comments (2)
frontend/src/services/tts/TTSContext.tsx (1)

63-64: Consider simplifying the iOS detection logic.

The logic correctly extends TTS availability to iOS, but the condition could be slightly cleaner. Since isTauriDesktop() likely already checks isTauri(), the explicit isTauri() check in the iOS condition may be redundant depending on the implementation of these utility functions.

♻️ Optional simplification

If isTauriDesktop() already ensures it's a Tauri environment, you could simplify to:

-  // Check Tauri environment - TTS is available on desktop and iOS (not Android)
-  const isTauriEnv = isTauriDesktop() || (isTauri() && isIOS());
+  // Check Tauri environment - TTS is available on desktop and iOS (not Android)
+  const isTauriEnv = isTauriDesktop() || isIOS();

However, only apply this if isIOS() is guaranteed to be used within a Tauri context. The current implementation is safe and explicit, so this is purely optional.

frontend/src-tauri/src/lib.rs (1)

269-317: Consider reducing code duplication between iOS and Android setup blocks.

The iOS and Android configuration blocks contain significant duplication, particularly in the setup closures (lines 275-288 vs 303-316). The deep link handler registration is identical in both blocks.

♻️ Suggested refactor to reduce duplication

Consider extracting the common setup logic into a shared function:

// Add before the cfg blocks
#[cfg(not(desktop))]
fn setup_mobile_deep_link_handler(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
    let app_handle = app.handle().clone();
    
    // Register deep link handler - note that iOS does not support runtime registration
    // but the handler for incoming URLs still works
    app.deep_link().on_open_url(move |event| {
        if let Some(url) = event.urls().first() {
            handle_deep_link_event(url.as_ref(), &app_handle);
        }
    });
    
    Ok(())
}

Then simplify both blocks:

// Android-specific configuration (no TTS)
#[cfg(all(not(desktop), target_os = "android"))]
let app = builder
    .invoke_handler(tauri::generate_handler![
        pdf_extractor::extract_document_content,
    ])
    .setup(|app| setup_mobile_deep_link_handler(app))
    .plugin(tauri_plugin_updater::Builder::new().build());

// iOS-specific configuration (with TTS)
#[cfg(all(not(desktop), target_os = "ios"))]
let app = builder
    .invoke_handler(tauri::generate_handler![
        pdf_extractor::extract_document_content,
        tts::tts_get_status,
        tts::tts_download_models,
        tts::tts_load_models,
        tts::tts_synthesize,
        tts::tts_unload_models,
        tts::tts_delete_models,
    ])
    .setup(|app| setup_mobile_deep_link_handler(app))
    .plugin(tauri_plugin_updater::Builder::new().build());

This reduces duplication and makes the code easier to maintain.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cfa212 and a617282.

⛔ Files ignored due to path filters (1)
  • frontend/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • .github/workflows/mobile-build.yml
  • .github/workflows/testflight-on-comment.yml
  • frontend/src-tauri/.gitignore
  • frontend/src-tauri/Cargo.toml
  • frontend/src-tauri/build.rs
  • frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
  • frontend/src-tauri/src/lib.rs
  • frontend/src-tauri/src/tts.rs
  • frontend/src/services/tts/TTSContext.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • frontend/src-tauri/src/tts.rs
  • frontend/src-tauri/.gitignore
  • frontend/src-tauri/build.rs
  • frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
  • .github/workflows/mobile-build.yml
  • .github/workflows/testflight-on-comment.yml
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use path aliases (@/* maps to ./src/*) for imports in TypeScript/React files
Use 2-space indentation, double quotes, and enforce 100-character line limit in TypeScript/React code
Maintain strict TypeScript and avoid using any type
Use PascalCase for component names and camelCase for variables and function names
Use functional components with React hooks instead of class components
Use React context for global state management and TanStack Query for server state management
Run just format, just lint, and just build after making TypeScript/React changes to ensure code quality and compilation

Files:

  • frontend/src/services/tts/TTSContext.tsx
🧠 Learnings (2)
📚 Learning: 2025-03-25T19:50:07.925Z
Learnt from: AnthonyRonning
Repo: OpenSecretCloud/Maple PR: 23
File: frontend/src-tauri/src/lib.rs:14-16
Timestamp: 2025-03-25T19:50:07.925Z
Learning: In Tauri applications, updater security configurations (including endpoints, public key for verification, and dialog settings) should be defined in the tauri.conf.json file rather than duplicated in the code. When initialized with tauri_plugin_updater::Builder::new().build(), the plugin automatically reads and uses these settings from the configuration file.

Applied to files:

  • frontend/src-tauri/src/lib.rs
📚 Learning: 2025-03-25T19:50:07.925Z
Learnt from: AnthonyRonning
Repo: OpenSecretCloud/Maple PR: 23
File: frontend/src-tauri/src/lib.rs:14-16
Timestamp: 2025-03-25T19:50:07.925Z
Learning: In Tauri applications, the updater configuration (including security settings like server URL and public key) should be defined in tauri.conf.json rather than hardcoded in the application code. The code only needs to initialize the updater plugin with tauri_plugin_updater::Builder::new().build(), which will automatically use the settings from the configuration file.

Applied to files:

  • frontend/src-tauri/src/lib.rs
🧬 Code graph analysis (1)
frontend/src-tauri/src/lib.rs (1)
frontend/src-tauri/src/tts.rs (8)
  • new (174-176)
  • new (451-456)
  • tts_get_status (735-757)
  • tts_download_models (768-899)
  • tts_load_models (902-920)
  • tts_synthesize (930-972)
  • tts_unload_models (975-981)
  • tts_delete_models (984-1000)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-linux
  • GitHub Check: build-ios
  • GitHub Check: build-macos (universal-apple-darwin)
  • GitHub Check: build-android
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (4)
frontend/src/services/tts/TTSContext.tsx (1)

10-10: LGTM: Clean import additions for iOS support.

The added imports (isIOS, isTauri) are necessary for the iOS platform detection logic below and follow the established path alias pattern.

frontend/src-tauri/src/lib.rs (3)

6-8: LGTM: TTS module correctly extended to iOS.

The conditional compilation correctly enables the TTS module for both desktop and iOS platforms, with a clear comment explaining the availability.


244-255: LGTM: Clean mobile configuration setup.

The base mobile builder configuration is properly shared between iOS and Android platforms, with appropriate plugin initialization.


263-267: LGTM: iOS TTS state management correctly initialized.

The TTS state is properly initialized for iOS builds using the same pattern as desktop, with appropriate conditional compilation.

Comment on lines +56 to +71
[target.'cfg(target_os = "ios")'.dependencies]
# TTS dependencies (Supertonic) - iOS
# Uses pre-built ONNX Runtime xcframework from HuggingFace
# We disable download-binaries and copy-dylibs since we link our own xcframework
# Need "std" for Error trait impl and file operations, "ndarray" for tensor creation
ort = { version = "2.0.0-rc.10", default-features = false, features = ["std", "ndarray"] }
ndarray = { version = "0.16" }
rand = "0.8"
rand_distr = "0.4"
hound = "3.5"
unicode-normalization = "0.1"
regex = "1.10"
reqwest = { version = "0.12", features = ["stream"] }
futures-util = "0.3"
dirs = "5.0"
sha2 = "0.10"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

ONNX Runtime 2.0.0-rc.10 release status production iOS

💡 Result:

Short answer: 2.0.0-rc.10 is a release-candidate (pre-release), not a GA release—so it’s not recommended as a drop-in production build for iOS without your own validation and testing. The ort 2.0.0-rc.10 Rust wrapper exists, and ONNX Runtime provides iOS build instructions and supported iOS platforms, but RCs can contain breaking changes or unresolved bugs and should be treated as test/pre‑production. [1][2]

References

  • ort 2.0.0-rc.10 (crate documentation). [1]
  • ONNX Runtime iOS build & platform support (instructions and supported iOS architectures). [2]

🌐 Web query:

ONNX Runtime latest stable version iOS support

💡 Result:

As of Jan 9, 2026 the latest stable ONNX Runtime release is 1.23.2 (released Oct 2025). It supports iOS (arm64 devices and x86_64 simulator); the docs list iOS 12 as the tested minimum and note tvOS/watchOS and 32-bit architectures are not supported. [1][2]

Sources:

  • ONNX Runtime roadmap / release announcement. [1]
  • ONNX Runtime iOS build documentation (platforms, architectures, minimum tested iOS). [2]

🌐 Web query:

ONNX Runtime 2.0.0 final release iOS xcframework

💡 Result:

Short answer: There is no ONNX Runtime "2.0.0 final" release or official iOS xcframework available (ONNX Runtime releases are still in the 1.x series). See the official releases page and the iOS build docs. [1][2]

If you need an iOS xcframework now, you can either:

  • build an iOS xcframework from the ONNX Runtime repo using the iOS build scripts (instructions here). [1]
  • or use the latest official release assets from the ONNX Runtime GitHub Releases page (download binaries or source and build an xcframework). [2]

References

  • Build ONNX Runtime for iOS (instructions). [1]
  • ONNX Runtime releases / GitHub (official releases page). [2]

Would you like step-by-step commands to build an iOS xcframework from the current ONNX Runtime release?


Replace ONNX Runtime release candidate with a stable version.

Using ort = "2.0.0-rc.10" (a pre-release) in production is not recommended. ONNX Runtime 2.0.0 has not reached a stable release—the latest stable version is 1.23.2 (Oct 2025), which supports iOS with arm64 devices and x86_64 simulator. Release candidates can contain breaking changes or unresolved bugs.

Either upgrade to the latest stable release or document the specific reason this RC version is necessary for iOS compatibility.

🤖 Prompt for AI Agents
In @frontend/src-tauri/Cargo.toml around lines 56 - 71, The Cargo.toml currently
pins the ONNX Runtime crate as ort = "2.0.0-rc.10" (pre-release); replace this
with a stable ort version (e.g., the latest 1.x stable) or, if 2.0.0-rc.10 is
required for iOS support, add a comment documenting the exact compatibility
reason and link to the upstream release notes; update the ort entry in the
target.'cfg(target_os = "ios")'.dependencies block accordingly and ensure
feature flags (["std","ndarray"]) remain correct for the chosen stable version.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

iOS TTS Support Implementation

This PR adds Text-to-Speech functionality to iOS by integrating ONNX Runtime 1.20.1 through a pre-built xcframework from HuggingFace. The implementation mirrors the existing desktop TTS architecture and enables on-device TTS synthesis using the Supertonic model.

What Changed

  • Build System: Added iOS-specific build configuration in build.rs to link ONNX Runtime static libraries and iOS frameworks
  • Dependencies: Added iOS-specific Cargo.toml targets with properly configured ort crate (disabling default features, enabling std/ndarray only)
  • Runtime Code: Modified lib.rs to enable TTS module on iOS, added conditional iOS invoke handlers for TTS commands
  • Model Storage: Updated tts.rs to use ~/Documents/tts_models path on iOS (sandboxed app directory) instead of desktop paths
  • Frontend: Updated TTSContext.tsx platform detection to enable TTS on both desktop and iOS
  • CI/CD: Added cache and download steps in both mobile-build and testflight workflows, with ORT_LIB_LOCATION environment variable

Architecture

The implementation properly separates platform-specific code:

  • Desktop (macos/linux/windows): Uses full-featured ort with rayon parallelization
  • iOS: Uses stripped-down ort (std, ndarray only) with pre-linked xcframework
  • Android: TTS explicitly disabled (no changes to existing Android support)

Issues Found

Critical (Blocks Merge):

  1. build.rs: Unprotected unwrap() on CARGO_MANIFEST_DIR and missing library file existence check
  2. setup-ios-onnxruntime.sh: No SHA256 checksum verification for downloaded binaries - security vulnerability
  3. setup-ios-onnxruntime.sh: curl commands don't validate HTTP status codes, allowing silent download failures
  4. setup-ios-onnxruntime.sh: Large binary downloads lack timeout settings, risk of indefinite build hangs

Important (Should Fix):

  1. build.rs: No verification that onnxruntime directory exists during build
  2. Workflows: Verification step silently fails, masking missing ONNX Runtime files with unclear downstream errors
  3. setup-ios-onnxruntime.sh: No timeout protection on curl requests for ~100MB downloads

Minor (Nice to Have):

  1. Documentation on how to manually set up iOS builds when GitHub cache is unavailable

Risk Assessment

  • Build Reliability: Currently fragile - silent failures in setup script will cause confusing linker errors
  • Security: Binary downloads lack integrity verification, vulnerable to supply chain attacks
  • Maintainability: Hard-coded paths and versions make future updates difficult

The core TTS implementation is sound, but the build infrastructure needs hardening before production use.

Confidence Score: 2/5

  • This PR should not be merged in current form - it has critical build reliability and security issues that must be fixed.
  • Score of 2 reflects serious blockers: (1) build.rs uses unwrap() without proper error handling, (2) setup script downloads binaries without checksum verification (security vulnerability), (3) missing HTTP error checks on curl (silent failures), (4) no existence verification before linking. These issues will cause difficult-to-debug build failures and security risks. The TTS implementation itself is solid (4-5 confidence), but infrastructure issues prevent safe deployment.
  • Critical attention needed: frontend/src-tauri/build.rs, frontend/src-tauri/scripts/setup-ios-onnxruntime.sh. High attention: .github/workflows/mobile-build.yml, .github/workflows/testflight-on-comment.yml

Important Files Changed

File Analysis

Filename Score Overview
frontend/src-tauri/build.rs 2/5 iOS build configuration has critical issues: uses unwrap() without error handling, doesn't verify required library files exist before linking, leading to unclear build failure messages if setup fails.
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 2/5 Critical security and reliability issues: downloads binary files without checksum verification, no HTTP error checking on curl, no timeout settings for large downloads, vulnerable to MITM attacks and silent failures.
.github/workflows/mobile-build.yml 3/5 Workflow verification step runs even after download failures, silently ignoring missing critical files and leading to confusing downstream build errors.
frontend/src-tauri/src/tts.rs 4/5 Good implementation with proper iOS path handling. Model download and TTS synthesis logic is sound with appropriate error handling.
frontend/src-tauri/src/lib.rs 4/5 iOS and Android configurations properly separated with correct conditional compilation. TTS commands correctly registered for iOS only.

Sequence Diagram

sequenceDiagram
    participant Build as GitHub Actions
    participant Script as setup-ios-onnxruntime.sh
    participant HF as HuggingFace
    participant BuildRs as build.rs
    participant Cargo as Cargo Build
    participant App as iOS App
    
    Note over Build,App: Build Phase
    Build->>Script: Run setup script
    Script->>HF: Download onnxruntime.xcframework
    HF-->>Script: Binary files
    Script->>Script: Extract and organize
    
    Note over Build,App: Compilation Phase
    Build->>BuildRs: Execute build.rs
    BuildRs->>BuildRs: Check TARGET (device/sim)
    BuildRs->>BuildRs: Set link paths
    BuildRs->>Cargo: Provide ORT_LIB_LOCATION
    
    Note over Build,App: Linking Phase
    Cargo->>Cargo: Link onnxruntime static lib
    Cargo->>Cargo: Link iOS frameworks
    Cargo-->>Build: iOS app binary
    
    Note over Build,App: Runtime Phase
    App->>App: Initialize TTS module on iOS
    App->>App: Get models dir (~/Documents/tts_models)
    App->>App: Download models from HuggingFace (if needed)
    App->>App: Load ONNX Runtime session
    App->>App: Ready for TTS synthesis

Loading

#[cfg(target_os = "ios")]
{
// Get the path to the ONNX Runtime xcframework
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unwrap() call on line 6 will panic if CARGO_MANIFEST_DIR is not set. This is a build-time failure that will cause confusing error messages. Should use expect() with a descriptive message or handle the error gracefully.

Suggested change
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set - this is required by Cargo");
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 6:6

Comment:
The `unwrap()` call on line 6 will panic if `CARGO_MANIFEST_DIR` is not set. This is a build-time failure that will cause confusing error messages. Should use `expect()` with a descriptive message or handle the error gracefully.

```suggestion
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set - this is required by Cargo");
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +52 to +68
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"

echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done

echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script downloads binary files (libonnxruntime.a) from HuggingFace without any integrity verification (checksums, signatures, or GPG verification). This is a security vulnerability - downloaded binaries could be compromised or tampered with. The PR description mentions pinning to a specific revision for "integrity and reproducibility" in tts.rs but this is NOT implemented here.

Additionally, the script uses curl -L (follow redirects) without validating the final URL, which could expose the build to MITM attacks.

Recommendation: Add SHA256 checksums for all downloaded files and verify them after download:

Suggested change
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"
echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done
echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"
echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"
echo "Downloading Info.plist..."
PLIST_SHA256="expected_hash_here"
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"
echo "$PLIST_SHA256 $XCFRAMEWORK_DIR/Info.plist" | sha256sum -c - || { echo "Checksum mismatch"; exit 1; }

Do this for all downloaded files, especially the large binary libraries.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 52:68

Comment:
The script downloads binary files (libonnxruntime.a) from HuggingFace without any integrity verification (checksums, signatures, or GPG verification). This is a security vulnerability - downloaded binaries could be compromised or tampered with. The PR description mentions pinning to a specific revision for "integrity and reproducibility" in tts.rs but this is NOT implemented here.

Additionally, the script uses `curl -L` (follow redirects) without validating the final URL, which could expose the build to MITM attacks.

Recommendation: Add SHA256 checksums for all downloaded files and verify them after download:

```suggestion
echo "Downloading Info.plist..."
PLIST_SHA256="expected_hash_here"
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"
echo "$PLIST_SHA256  $XCFRAMEWORK_DIR/Info.plist" | sha256sum -c - || { echo "Checksum mismatch"; exit 1; }
```

Do this for all downloaded files, especially the large binary libraries.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 269 to 289
@@ -279,6 +288,34 @@ pub fn run() {
})
.plugin(tauri_plugin_updater::Builder::new().build());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a critical control flow issue: the Android configuration block (lines 269-289) creates the app binding with let app = builder..., but the iOS configuration block (lines 291-317) also tries to create let app = builder... using the SAME builder variable that was already consumed. In Rust, the first branch consumes builder, so the second let app assignment will fail to compile because builder no longer exists.

This appears to be a logic error in the conditional compilation. The code structure should ensure that ONLY ONE of these branches executes (they have mutually exclusive conditions), but both branches are trying to create an app from the same builder. This will cause a compilation error.

Expected fix: Verify that these cfg conditions are truly mutually exclusive and that only one branch will ever execute. If both branches need builder, there's a design issue that needs refactoring.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/src/lib.rs
Line: 269:289

Comment:
There is a critical control flow issue: the Android configuration block (lines 269-289) creates the `app` binding with `let app = builder...`, but the iOS configuration block (lines 291-317) also tries to create `let app = builder...` using the SAME builder variable that was already consumed. In Rust, the first branch consumes `builder`, so the second `let app` assignment will fail to compile because `builder` no longer exists.

This appears to be a logic error in the conditional compilation. The code structure should ensure that ONLY ONE of these branches executes (they have mutually exclusive conditions), but both branches are trying to create an `app` from the same `builder`. This will cause a compilation error.

Expected fix: Verify that these cfg conditions are truly mutually exclusive and that only one branch will ever execute. If both branches need `builder`, there's a design issue that needs refactoring.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +52 to +67
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"

echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done

echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The curl commands downloading large binary files (libonnxruntime.a files are ~100MB each) don't have connection or timeout settings. This could cause the build to hang indefinitely if the network is slow or the remote server is unresponsive. Add explicit timeout values to prevent build hangs.

Suggested change
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"
echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done
echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"
echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"
echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L --connect-timeout 30 --max-time 3600 -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"
echo "Downloading iOS simulator static library (this may take a while)..."
curl -L --connect-timeout 30 --max-time 3600 -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"

Apply similar timeout settings to all curl commands in the script.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 52:67

Comment:
The curl commands downloading large binary files (libonnxruntime.a files are ~100MB each) don't have connection or timeout settings. This could cause the build to hang indefinitely if the network is slow or the remote server is unresponsive. Add explicit timeout values to prevent build hangs.

```suggestion
echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L --connect-timeout 30 --max-time 3600 -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

echo "Downloading iOS simulator static library (this may take a while)..."
curl -L --connect-timeout 30 --max-time 3600 -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"
```

Apply similar timeout settings to all curl commands in the script.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +17 to +19
// Tell cargo where to find the ONNX Runtime static library
println!("cargo:rustc-link-search=native={}", lib_path);
println!("cargo:rustc-link-lib=static=onnxruntime");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build script tells cargo to link against the ONNX Runtime library without verifying that the path actually exists. If the onnxruntime-ios directory was not downloaded (e.g., the setup script failed silently or was skipped), the build will fail with an obscure linker error rather than a clear error message about the missing file.

Add a check to verify the library exists before proceeding:

Suggested change
// Tell cargo where to find the ONNX Runtime static library
println!("cargo:rustc-link-search=native={}", lib_path);
println!("cargo:rustc-link-lib=static=onnxruntime");
// Tell cargo where to find the ONNX Runtime static library
if !std::path::Path::new(&lib_path).exists() {
panic!("ONNX Runtime library not found at {}. Did you run setup-ios-onnxruntime.sh?", lib_path);
}
println!("cargo:rustc-link-search=native={}", lib_path);
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 17:19

Comment:
The build script tells cargo to link against the ONNX Runtime library without verifying that the path actually exists. If the `onnxruntime-ios` directory was not downloaded (e.g., the setup script failed silently or was skipped), the build will fail with an obscure linker error rather than a clear error message about the missing file.

Add a check to verify the library exists before proceeding:

```suggestion
// Tell cargo where to find the ONNX Runtime static library
if !std::path::Path::new(&lib_path).exists() {
    panic!("ONNX Runtime library not found at {}. Did you run setup-ios-onnxruntime.sh?", lib_path);
}
println!("cargo:rustc-link-search=native={}", lib_path);
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread .github/workflows/mobile-build.yml Outdated
Comment on lines +72 to +76
- name: Verify ONNX Runtime files
run: |
echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a || echo "File not found or not a valid archive"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Verify ONNX Runtime files" step runs unconditionally, but if the download step failed, this verification will also fail silently (due to the || echo fallback). The build will continue even though critical files are missing, leading to build failure downstream with confusing error messages.

The verification step should explicitly check if the required directory exists and fail the workflow if it doesn't:

Suggested change
- name: Verify ONNX Runtime files
run: |
echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a || echo "File not found or not a valid archive"
- name: Verify ONNX Runtime files
run: |
ORT_PATH="${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
if [ ! -f "$ORT_PATH/libonnxruntime.a" ]; then
echo "ERROR: ONNX Runtime library not found at $ORT_PATH/libonnxruntime.a"
exit 1
fi
echo "ONNX Runtime files verified successfully"
ls -lh "$ORT_PATH/libonnxruntime.a"

This makes build failures explicit and immediate rather than downstream.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 72:76

Comment:
The "Verify ONNX Runtime files" step runs unconditionally, but if the download step failed, this verification will also fail silently (due to the `|| echo` fallback). The build will continue even though critical files are missing, leading to build failure downstream with confusing error messages.

The verification step should explicitly check if the required directory exists and fail the workflow if it doesn't:

```suggestion
      - name: Verify ONNX Runtime files
        run: |
          ORT_PATH="${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
          if [ ! -f "$ORT_PATH/libonnxruntime.a" ]; then
            echo "ERROR: ONNX Runtime library not found at $ORT_PATH/libonnxruntime.a"
            exit 1
          fi
          echo "ONNX Runtime files verified successfully"
          ls -lh "$ORT_PATH/libonnxruntime.a"
```

This makes build failures explicit and immediate rather than downstream.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +52 to +59
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"

echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The curl commands don't check HTTP status codes or validate download success. If HuggingFace returns a 404, authentication error (403), or server error (5xx), the download will fail silently, creating empty or corrupt files. The script will then report success when actually it failed to download the required files.

Add error checking after each download:

Suggested change
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"
echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done
echo "Downloading Info.plist..."
if ! curl -L --fail -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"; then
echo "ERROR: Failed to download Info.plist"
rm -rf "$ORT_DIR"
exit 1
fi

The --fail flag makes curl exit with an error on HTTP failures (4xx/5xx status codes). Apply this to all curl downloads.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 52:59

Comment:
The curl commands don't check HTTP status codes or validate download success. If HuggingFace returns a 404, authentication error (403), or server error (5xx), the download will fail silently, creating empty or corrupt files. The script will then report success when actually it failed to download the required files.

Add error checking after each download:

```suggestion
echo "Downloading Info.plist..."
if ! curl -L --fail -o "$XCFRAMEWORK_DIR/Info.plist" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"; then
    echo "ERROR: Failed to download Info.plist"
    rm -rf "$ORT_DIR"
    exit 1
fi
```

The `--fail` flag makes curl exit with an error on HTTP failures (4xx/5xx status codes). Apply this to all curl downloads.

How can I resolve this? If you propose a fix, please make it concise.

AnthonyRonning and others added 2 commits January 9, 2026 13:02
The xcodebuild process runs cargo in a subprocess that doesn't inherit
GitHub Actions environment variables. This config file uses Cargo's [env]
section to set ORT_LIB_LOCATION, which will be read by ort-sys when cargo
builds the iOS target.

Also adds target-specific rustflags to ensure the linker can find the
ONNX Runtime static library for each iOS target.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
The previous approach broke both desktop and iOS builds:
- [env] section applied ORT_LIB_LOCATION to ALL targets, breaking desktop
- rustflags with -l applied to ALL crate compilations, including libc

This fix uses Cargo's [target.<triple>.<links>] feature to override
ort-sys's build script output ONLY for iOS targets. The 'onnxruntime'
key matches ort-sys's 'links = "onnxruntime"' declaration.

This is the correct way to provide library paths for specific targets
without affecting other targets or crate compilations.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Adds iOS support for on-device TTS using ONNX Runtime 1.20.1 and the Supertonic model. The implementation mirrors the existing desktop TTS, downloading pre-built xcframework binaries from HuggingFace and storing TTS models in ~/Documents/tts_models.

Key Changes:

  • Added iOS-specific ONNX Runtime dependencies to Cargo.toml with ort configured for static linking
  • Created build infrastructure (build.rs, .cargo/config.toml) to link xcframework libraries for both device and simulator targets
  • Extended TTS module availability from desktop-only to desktop + iOS
  • Added GitHub Actions steps to cache and download ONNX Runtime binaries
  • Frontend platform detection updated to enable TTS on iOS

Issues Found:

  • Configuration inconsistency: ORT_LIB_LOCATION is set in three places (build.rs, .cargo/config.toml, GitHub Actions) with conflicting values (base directory vs subdirectory vs absolute path)
  • Performance gap: iOS build missing rayon feature for ndarray, which will result in 5-10x slower tensor operations compared to desktop
  • Security concern: Download script doesn't verify integrity of ~200MB binary libraries from HuggingFace
  • Maintainability: Hardcoded device-only paths in workflows and config will cause issues if simulator builds are needed

The core implementation is solid with proper error handling in Rust and correct platform detection in TypeScript. However, the build configuration has redundancy and inconsistencies that should be cleaned up to avoid future build failures.

Confidence Score: 3/5

  • This PR has multiple configuration inconsistencies that need attention before merge
  • Core logic is sound with proper error handling and platform detection. However, critical build configuration issues exist: ORT_LIB_LOCATION is inconsistently defined across three locations causing potential build failures, missing performance optimization (rayon), and lack of binary integrity verification. These are style/best-practice issues rather than breaking bugs, but they impact reliability and should be addressed.
  • Pay close attention to build.rs, .cargo/config.toml, and setup-ios-onnxruntime.sh - configuration conflicts and missing security checks

Important Files Changed

File Analysis

Filename Score Overview
frontend/src-tauri/Cargo.toml 4/5 Added iOS TTS dependencies mirroring desktop config. Missing rayon feature for ndarray which will impact performance.
frontend/src-tauri/build.rs 3/5 iOS-specific ONNX Runtime linking configuration added. ORT_LIB_LOCATION setting conflicts with .cargo/config.toml.
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 3/5 Downloads ONNX Runtime xcframework from HuggingFace. Missing integrity verification for downloaded binaries (~200MB).
.github/workflows/mobile-build.yml 4/5 Added ONNX Runtime caching and download steps. ORT_LIB_LOCATION hardcoded to device path, may conflict with build.rs.
frontend/src-tauri/.cargo/config.toml 3/5 iOS linking configuration for ONNX Runtime. ORT_LIB_LOCATION hardcoded to device path but applies to all targets.

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Script as setup-ios-onnxruntime.sh
    participant HF as HuggingFace
    participant Cargo as Cargo Build
    participant ORT as ONNX Runtime
    participant App as iOS App

    Note over GHA: iOS Build Triggered
    GHA->>GHA: Check cache for onnxruntime-ios
    alt Cache Miss
        GHA->>Script: Execute setup script
        Script->>HF: Download xcframework files
        HF-->>Script: Info.plist, headers, .a libraries
        Script->>Script: Save to onnxruntime-ios/
    else Cache Hit
        GHA->>GHA: Restore cached files
    end
    
    GHA->>GHA: Set ORT_LIB_LOCATION env var
    GHA->>Cargo: Start build (bun tauri ios build)
    
    Note over Cargo: Build Process
    Cargo->>Cargo: Read .cargo/config.toml
    Cargo->>Cargo: Execute build.rs
    Note over Cargo: Sets ORT_LIB_LOCATION (conflicts with config.toml)
    Cargo->>Cargo: Detect target (device/simulator)
    Cargo->>Cargo: Set rustflags for linking
    
    Cargo->>ORT: Link static libraries
    ORT->>ORT: Load libonnxruntime.a
    Cargo->>Cargo: Compile TTS module
    Cargo->>Cargo: Build iOS binary
    
    Cargo-->>App: Generate .ipa file
    
    Note over App: Runtime
    App->>App: User requests TTS
    App->>App: Download TTS models (~264MB)
    App->>ORT: Load models & synthesize
    ORT-->>App: Return audio data

Loading

# We disable download-binaries and copy-dylibs since we link our own xcframework
# Need "std" for Error trait impl and file operations, "ndarray" for tensor creation
ort = { version = "2.0.0-rc.10", default-features = false, features = ["std", "ndarray"] }
ndarray = { version = "0.16" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iOS build missing rayon feature for ndarray - desktop has it on line 45. Without parallel processing, TTS inference will be significantly slower on iOS (5-10x slower for tensor operations). Consider adding features = ["rayon"] unless there's a specific reason to exclude it.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/Cargo.toml
Line: 62:62

Comment:
iOS build missing `rayon` feature for `ndarray` - desktop has it on line 45. Without parallel processing, TTS inference will be significantly slower on iOS (5-10x slower for tensor operations). Consider adding `features = ["rayon"]` unless there's a specific reason to exclude it.

How can I resolve this? If you propose a fix, please make it concise.

println!("cargo:rustc-link-lib=framework=Accelerate");

// Set ORT_LIB_LOCATION for the ort crate
println!("cargo:rustc-env=ORT_LIB_LOCATION={}", ort_dir);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent ORT_LIB_LOCATION configuration. This sets it to {manifest_dir}/onnxruntime-ios (base directory), but .cargo/config.toml line 11 sets it to onnxruntime-ios/onnxruntime.xcframework/ios-arm64 (subdirectory), and GitHub Actions sets it to the full absolute path with subdirectory. The .cargo/config.toml value will override this, making this line ineffective. Either remove this line or ensure all three locations use consistent paths.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 26:26

Comment:
Inconsistent `ORT_LIB_LOCATION` configuration. This sets it to `{manifest_dir}/onnxruntime-ios` (base directory), but `.cargo/config.toml` line 11 sets it to `onnxruntime-ios/onnxruntime.xcframework/ios-arm64` (subdirectory), and GitHub Actions sets it to the full absolute path with subdirectory. The `.cargo/config.toml` value will override this, making this line ineffective. Either remove this line or ensure all three locations use consistent paths.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +62 to +67
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing checksum/signature verification for downloaded files. The script downloads ~200MB of binary libraries from HuggingFace but doesn't verify their integrity. If the remote files are compromised or corrupted, this could fail silently or worse, include malicious code. Consider adding SHA256 verification for the downloaded .a files, similar to how tts.rs verifies model file integrity (lines 876-883).

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 62:67

Comment:
Missing checksum/signature verification for downloaded files. The script downloads ~200MB of binary libraries from HuggingFace but doesn't verify their integrity. If the remote files are compromised or corrupted, this could fail silently or worse, include malicious code. Consider adding SHA256 verification for the downloaded `.a` files, similar to how `tts.rs` verifies model file integrity (lines 876-883).

How can I resolve this? If you propose a fix, please make it concise.

VITE_MAPLE_BILLING_API_URL: https://billing.opensecret.cloud
VITE_CLIENT_ID: ba5a14b5-d915-47b1-b7b1-afda52bc5fc6
# ONNX Runtime location for ort-sys crate
ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ORT_LIB_LOCATION points to device-specific path (ios-arm64) but the workflow only builds for device, not simulator. If simulator builds are needed in the future, this will cause linker errors. The path should be consistent with what build.rs selects based on target (device vs simulator). Consider whether this env var is even needed since build.rs and .cargo/config.toml already handle this.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 115:115

Comment:
`ORT_LIB_LOCATION` points to device-specific path (`ios-arm64`) but the workflow only builds for device, not simulator. If simulator builds are needed in the future, this will cause linker errors. The path should be consistent with what `build.rs` selects based on target (device vs simulator). Consider whether this env var is even needed since `build.rs` and `.cargo/config.toml` already handle this.

How can I resolve this? If you propose a fix, please make it concise.

VITE_MAPLE_BILLING_API_URL: https://billing.opensecret.cloud
VITE_CLIENT_ID: ba5a14b5-d915-47b1-b7b1-afda52bc5fc6
# ONNX Runtime location for ort-sys crate
ORT_LIB_LOCATION: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same ORT_LIB_LOCATION issue as in mobile-build.yml - hardcoded to device path but doesn't match the dynamic selection in build.rs. This creates maintenance issues and potential build failures if simulator builds are ever needed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 173:173

Comment:
Same `ORT_LIB_LOCATION` issue as in `mobile-build.yml` - hardcoded to device path but doesn't match the dynamic selection in `build.rs`. This creates maintenance issues and potential build failures if simulator builds are ever needed.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread frontend/src-tauri/.cargo/config.toml Outdated
# The `onnxruntime` key matches ort-sys's `links = "onnxruntime"` declaration.

# iOS arm64 device target - override ort-sys build script
[target.aarch64-apple-ios.onnxruntime]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded to ios-arm64 device path. This value is used for ALL targets (device + simulators) per line 9 comment, but device and simulator need different paths. The target-specific rustflags on lines 14-32 correctly point to different directories, but this env var doesn't. If ort-sys uses this env var, simulator builds may fail. Verify whether this env var is needed at all since build.rs already sets it dynamically.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/.cargo/config.toml
Line: 11:11

Comment:
Hardcoded to `ios-arm64` device path. This value is used for ALL targets (device + simulators) per line 9 comment, but device and simulator need different paths. The target-specific `rustflags` on lines 14-32 correctly point to different directories, but this env var doesn't. If `ort-sys` uses this env var, simulator builds may fail. Verify whether this env var is needed at all since `build.rs` already sets it dynamically.

How can I resolve this? If you propose a fix, please make it concise.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
frontend/src-tauri/.cargo/config.toml (1)

14-32: Verify you’re not double-linking libonnxruntime.a (ort-sys vs rustflags).

You’re passing -l static=onnxruntime via rustflags for all iOS targets. If ort-sys already emits cargo:rustc-link-lib=static=onnxruntime, this can become redundant at best (bigger/messier link lines) or cause duplicate/ordering issues depending on how the final link is composed.

If ort-sys already links the library, consider keeping only the per-target -L native=... here and letting ort-sys own the -l directive.

Proposed change (only if ort-sys already emits the `-l`)
 [target.aarch64-apple-ios]
 rustflags = [
     "-L", "native=onnxruntime-ios/onnxruntime.xcframework/ios-arm64",
-    "-l", "static=onnxruntime",
 ]

 [target.aarch64-apple-ios-sim]
 rustflags = [
     "-L", "native=onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator",
-    "-l", "static=onnxruntime",
 ]

 [target.x86_64-apple-ios]
 rustflags = [
     "-L", "native=onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator",
-    "-l", "static=onnxruntime",
 ]
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a617282 and ff027db.

📒 Files selected for processing (1)
  • frontend/src-tauri/.cargo/config.toml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-08T19:55:33.330Z
Learnt from: CR
Repo: OpenSecretCloud/Maple PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T19:55:33.330Z
Learning: Applies to src-tauri/**/*.rs : Follow standard Rust conventions and rustfmt defaults for code formatting

Applied to files:

  • frontend/src-tauri/.cargo/config.toml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build-linux
  • GitHub Check: build-android
  • GitHub Check: build-macos (universal-apple-darwin)
🔇 Additional comments (1)
frontend/src-tauri/.cargo/config.toml (1)

5-12: This review comment is based on an incorrect or outdated view of the file. The actual .cargo/config.toml does not contain a global [env] section—it correctly uses target-specific Cargo config overrides instead.

Actual structure (lines 1–23):

  • [target.aarch64-apple-ios.onnxruntime] → ios-arm64 (device)
  • [target.aarch64-apple-ios-sim.onnxruntime] → ios-arm64_x86_64-simulator (simulator)
  • [target.x86_64-apple-ios.onnxruntime] → ios-arm64_x86_64-simulator (simulator x86_64)

This target-specific approach avoids the global environment leakage concern. The build.rs also correctly selects per-target paths (lines 12–14 show conditional logic for simulator vs. device). Workflows set ORT_LIB_LOCATION in the CI environment context only, which is appropriate.

The implementation is correct and does not have the issue described in the review comment.

Likely an incorrect or invalid review comment.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds iOS support for on-device Text-to-Speech (TTS) using the Supertonic model via ONNX Runtime. The implementation mirrors the existing desktop TTS functionality with iOS-specific adaptations.

Key Changes

Infrastructure:

  • Downloads pre-built ONNX Runtime 1.20.1 xcframework from HuggingFace during build
  • Adds GitHub Actions caching to speed up builds (xcframework is ~100MB)
  • Uses Cargo build script override (.cargo/config.toml) to link ONNX Runtime statically for iOS targets

iOS-Specific Adaptations:

  • TTS models (~264MB) stored in ~/Documents/tts_models on iOS (vs app data dir on desktop)
  • Uses iOS Documents directory for persistence, which has iCloud sync implications
  • Omits rayon parallel processing feature from ndarray dependency on iOS

Code Architecture:

  • Enables tts module for iOS using #[cfg(any(desktop, target_os = "ios"))]
  • Adds iOS-specific configuration block in lib.rs with TTS command handlers
  • Frontend detects iOS via platform utils and enables TTS UI accordingly

Issues Found

Critical (Logic):

  1. ✅ Shell script curl commands don't use --fail flag, could download error pages instead of binaries
  2. ✅ Workflow verification steps use || echo which prevents build failures on missing libraries

Important (Style):
3. ✅ iOS models stored in ~/Documents will sync to iCloud (264MB), better to use Application Support
4. ✅ ONNX Runtime downloads from HuggingFace main branch (not pinned to commit hash like TTS models)

Architecture Integration

The implementation integrates cleanly with existing TTS infrastructure. The Rust backend handles all inference work, while the frontend simply invokes Tauri commands and plays returned audio. Models are downloaded on-demand, same as desktop. Memory usage (~500MB) is acceptable for modern iOS devices (iPhone 12+).

The conditional compilation strategy properly separates iOS, Android, and desktop paths, though the control flow in lib.rs is somewhat complex with multiple cfg blocks.

Confidence Score: 4/5

  • This PR is generally safe to merge with some minor improvements recommended
  • Score reflects solid implementation with well-structured code, but has a few issues that should be addressed: (1) download script lacks robust error handling for HTTP failures, (2) workflow verification steps don't fail builds properly, (3) iOS storage location may cause iCloud sync overhead, and (4) ONNX Runtime downloads from unpinned branch. The core TTS logic is proven (already works on desktop), and the iOS adaptations are straightforward. The issues found are operational/configuration concerns rather than logic bugs. All critical paths have proper error handling with Result types.
  • Pay close attention to setup-ios-onnxruntime.sh (download reliability), mobile-build.yml and testflight-on-comment.yml (verification steps), and tts.rs (iOS storage location)

Important Files Changed

File Analysis

Filename Score Overview
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 3/5 Download script for ONNX Runtime lacks explicit HTTP status checks and final verification
.github/workflows/mobile-build.yml 4/5 iOS build workflow with ONNX Runtime caching and verification, but verification doesn't fail on error
.github/workflows/testflight-on-comment.yml 4/5 TestFlight deployment workflow with same ONNX Runtime setup as mobile-build, verification doesn't fail on error
frontend/src-tauri/Cargo.toml 4/5 Adds iOS-specific TTS dependencies, omits rayon feature for ndarray (will reduce parallel processing performance)
frontend/src-tauri/build.rs 4/5 Adds iOS-specific ONNX Runtime linking configuration, correctly handles simulator vs device targets
frontend/src-tauri/src/lib.rs 4/5 Enables TTS module and commands for iOS with proper conditional compilation, complex but correct control flow
frontend/src-tauri/src/tts.rs 3/5 Adds iOS-specific path handling using ~/Documents which may cause iCloud sync and storage issues

Sequence Diagram

sequenceDiagram
    participant User
    participant Frontend as Frontend (React)
    participant Tauri as Tauri Backend (Rust)
    participant FS as File System
    participant HF as HuggingFace
    participant ONNX as ONNX Runtime

    Note over User,ONNX: iOS TTS Initialization Flow
    
    User->>Frontend: Open app on iOS
    Frontend->>Tauri: tts_get_status()
    Tauri->>FS: Check ~/Documents/tts_models/
    FS-->>Tauri: Models not found
    Tauri-->>Frontend: models_downloaded: false
    
    Note over User,ONNX: Model Download Flow
    
    User->>Frontend: Click "Download TTS Models"
    Frontend->>Tauri: tts_download_models()
    
    loop For each model file (10 files, 264MB total)
        Tauri->>HF: Download model file with SHA256
        HF-->>Tauri: Model file chunk
        Tauri->>Tauri: Verify checksum
        Tauri->>FS: Save to ~/Documents/tts_models/
        Tauri->>Frontend: Emit download progress event
        Frontend->>User: Update progress bar
    end
    
    Tauri-->>Frontend: Download complete
    Frontend->>Tauri: tts_load_models()
    Tauri->>FS: Read model files
    Tauri->>ONNX: Load ONNX sessions (4 models)
    ONNX-->>Tauri: Sessions ready (~500MB RAM)
    Tauri-->>Frontend: Models loaded
    
    Note over User,ONNX: TTS Synthesis Flow
    
    User->>Frontend: Click TTS button on message
    Frontend->>Tauri: tts_synthesize(text)
    Tauri->>Tauri: Preprocess text (remove markdown, etc.)
    Tauri->>Tauri: Chunk text into 300-char segments
    
    loop For each text chunk
        Tauri->>ONNX: Run text_encoder
        Tauri->>ONNX: Run duration_predictor
        Tauri->>ONNX: Run vector_estimator (10 steps)
        Tauri->>ONNX: Run vocoder
        ONNX-->>Tauri: Audio samples (float32)
    end
    
    Tauri->>Tauri: Concatenate audio chunks
    Tauri->>Tauri: Encode to WAV + base64
    Tauri-->>Frontend: audio_base64, sample_rate
    Frontend->>Frontend: Decode base64 to Blob
    Frontend->>Frontend: Play via Web Audio API
    Frontend-->>User: Play audio
Loading

Comment on lines +52 to +67
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"

echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done

echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The curl commands don't use the --fail flag, which means they will succeed even if the server returns a 404 or other error status. This could result in downloading HTML error pages instead of the actual files.

Consider adding --fail to all curl commands to ensure they fail on HTTP errors:

Suggested change
curl -L -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"
echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done
echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"
echo "Downloading iOS simulator static library (this may take a while)..."
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"
echo "Downloading Info.plist..."
curl -L --fail -o "$XCFRAMEWORK_DIR/Info.plist" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"
echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
curl -L --fail -o "$XCFRAMEWORK_DIR/Headers/$header" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done
echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L --fail -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"
echo "Downloading iOS simulator static library (this may take a while)..."
curl -L --fail -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 52:67

Comment:
The curl commands don't use the `--fail` flag, which means they will succeed even if the server returns a 404 or other error status. This could result in downloading HTML error pages instead of the actual files.

Consider adding `--fail` to all curl commands to ensure they fail on HTTP errors:

```suggestion
echo "Downloading Info.plist..."
curl -L --fail -o "$XCFRAMEWORK_DIR/Info.plist" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Info.plist"

echo "Downloading headers..."
for header in cpu_provider_factory.h onnxruntime_c_api.h onnxruntime_cxx_api.h onnxruntime_cxx_inline.h; do
    curl -L --fail -o "$XCFRAMEWORK_DIR/Headers/$header" \
        "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/Headers/$header"
done

echo "Downloading iOS arm64 static library (this may take a while)..."
curl -L --fail -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

echo "Downloading iOS simulator static library (this may take a while)..."
curl -L --fail -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread .github/workflows/mobile-build.yml Outdated
Comment on lines +72 to +76
- name: Verify ONNX Runtime files
run: |
echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a || echo "File not found or not a valid archive"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The verification step uses || echo which means it will never fail the build even if the ONNX Runtime library is missing or invalid. This could lead to cryptic build failures in the next step.

The verification should fail the build if the file is missing:

Suggested change
- name: Verify ONNX Runtime files
run: |
echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a || echo "File not found or not a valid archive"
- name: Verify ONNX Runtime files
run: |
echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a
# Verify it's actually a static library
if ! file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a | grep -q "ar archive"; then
echo "ERROR: libonnxruntime.a is not a valid static library"
exit 1
fi
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 72:76

Comment:
The verification step uses `|| echo` which means it will never fail the build even if the ONNX Runtime library is missing or invalid. This could lead to cryptic build failures in the next step.

The verification should fail the build if the file is missing:

```suggestion
      - name: Verify ONNX Runtime files
        run: |
          echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
          ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
          file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a
          # Verify it's actually a static library
          if ! file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a | grep -q "ar archive"; then
            echo "ERROR: libonnxruntime.a is not a valid static library"
            exit 1
          fi
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +130 to +134
- name: Verify ONNX Runtime files
run: |
echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a || echo "File not found or not a valid archive"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as in mobile-build.yml - the verification step uses || echo which means it will never fail the build even if the ONNX Runtime library is missing or invalid.

Suggested change
- name: Verify ONNX Runtime files
run: |
echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a || echo "File not found or not a valid archive"
- name: Verify ONNX Runtime files
run: |
echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a
# Verify it's actually a static library
if ! file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a | grep -q "ar archive"; then
echo "ERROR: libonnxruntime.a is not a valid static library"
exit 1
fi
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 130:134

Comment:
Same issue as in mobile-build.yml - the verification step uses `|| echo` which means it will never fail the build even if the ONNX Runtime library is missing or invalid.

```suggestion
      - name: Verify ONNX Runtime files
        run: |
          echo "ORT_LIB_LOCATION will be: ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"
          ls -la ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/
          file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a
          # Verify it's actually a static library
          if ! file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a | grep -q "ar archive"; then
            echo "ERROR: libonnxruntime.a is not a valid static library"
            exit 1
          fi
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 614 to +623
fn get_tts_models_dir() -> Result<PathBuf> {
let data_dir = dirs::data_local_dir()
.context("Failed to get local data directory")?
.join("cloud.opensecret.maple")
.join("tts_models");
Ok(data_dir)
// On iOS, we need to use a different approach since dirs::data_local_dir() may not work
#[cfg(target_os = "ios")]
{
// On iOS, use the app's Documents directory which is accessible and persists
// NSHomeDirectory() + /Documents/tts_models
let home = std::env::var("HOME").context("Failed to get HOME directory on iOS")?;
let data_dir = PathBuf::from(home).join("Documents").join("tts_models");
return Ok(data_dir);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On iOS, storing TTS models (~264MB) in ~/Documents/tts_models has several implications:

  1. iCloud sync: The Documents directory is backed up to iCloud by default, which will use significant iCloud storage and bandwidth
  2. User visibility: Users can see this folder in the Files app, which may be confusing
  3. Storage: Users may delete it thinking it's unnecessary

iOS best practice is to use the Application Support directory for app-specific data that users don't need to access. Consider using a directory like:

  • ~/Library/Application Support/cloud.opensecret.maple/tts_models (not backed up to iCloud)
  • Or mark the Documents subdirectory as excluded from backup using file attributes

This is particularly important given the 264MB size of the models.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/src/tts.rs
Line: 614:623

Comment:
On iOS, storing TTS models (~264MB) in `~/Documents/tts_models` has several implications:

1. **iCloud sync**: The Documents directory is backed up to iCloud by default, which will use significant iCloud storage and bandwidth
2. **User visibility**: Users can see this folder in the Files app, which may be confusing
3. **Storage**: Users may delete it thinking it's unnecessary

iOS best practice is to use the Application Support directory for app-specific data that users don't need to access. Consider using a directory like:
- `~/Library/Application Support/cloud.opensecret.maple/tts_models` (not backed up to iCloud)
- Or mark the Documents subdirectory as excluded from backup using file attributes

This is particularly important given the 264MB size of the models.

How can I resolve this? If you propose a fix, please make it concise.


# Download pre-built xcframework from HuggingFace
# Repository: https://huggingface.co/csukuangfj/ios-onnxruntime
HF_BASE_URL="https://huggingface.co/csukuangfj/ios-onnxruntime/resolve/main"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script downloads from the main branch of the HuggingFace repository, which means the files could change over time without notice. This differs from the TTS model downloads in tts.rs which pin to a specific commit hash (b6856d033f622c63ea29441795be266a1133e227) for security and reproducibility.

Consider pinning to a specific commit hash instead of using main:

Suggested change
HF_BASE_URL="https://huggingface.co/csukuangfj/ios-onnxruntime/resolve/main"
HF_BASE_URL="https://huggingface.co/csukuangfj/ios-onnxruntime/resolve/<commit-hash>"

This ensures builds are reproducible and protects against potential supply chain attacks if the repository is compromised.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 29:29

Comment:
The script downloads from the `main` branch of the HuggingFace repository, which means the files could change over time without notice. This differs from the TTS model downloads in `tts.rs` which pin to a specific commit hash (`b6856d033f622c63ea29441795be266a1133e227`) for security and reproducibility.

Consider pinning to a specific commit hash instead of using `main`:

```suggestion
HF_BASE_URL="https://huggingface.co/csukuangfj/ios-onnxruntime/resolve/<commit-hash>"
```

This ensures builds are reproducible and protects against potential supply chain attacks if the repository is compromised.

How can I resolve this? If you propose a fix, please make it concise.

The static .cargo/config.toml with relative paths wasn't working because:
1. xcodebuild may run cargo from different working directories
2. Relative paths in config files are relative to the config file location,
   which may not match the actual library location in CI

This fix generates the config file dynamically in GitHub Actions with
absolute paths to the ONNX Runtime library location, ensuring the
build script override works regardless of the working directory.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @.github/workflows/mobile-build.yml:
- Around line 72-77: The "Verify ONNX Runtime files" workflow step currently
swallows failures by using `file ... || echo ...`; change it to fail-fast so
missing or invalid ORT artifacts stop the run: replace the `file ${{
github.workspace
}}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/libonnxruntime.a
|| echo "File not found or not a valid archive"` pattern with a strict check
that exits non-zero on failure (e.g., run `file` and if it indicates an error or
the archive is absent, call `exit 1` or use a conditional that fails), and
ensure the `ls`/`file` invocations in the "Verify ONNX Runtime files" step
reference the same path shown in the diff so the workflow fails when
libonnxruntime.a is missing or corrupt.
🧹 Nitpick comments (1)
.github/workflows/mobile-build.yml (1)

56-64: Cache key/restore-keys are too static; risk of stale/poisoned ORT artifacts.
Right now the key won’t change if the download script/URL changes, and restore-keys duplicates the full key (no fallback behavior).

Proposed tweak
       - name: Cache ONNX Runtime iOS xcframework
         uses: actions/cache@v4
         id: cache-onnxruntime
         with:
           path: frontend/src-tauri/onnxruntime-ios
-          key: onnxruntime-ios-1.20.1-v2
+          key: onnxruntime-ios-1.20.1-${{ hashFiles('frontend/src-tauri/scripts/setup-ios-onnxruntime.sh') }}
           restore-keys: |
-            onnxruntime-ios-1.20.1-v2
+            onnxruntime-ios-1.20.1-
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff027db and d95a2df.

📒 Files selected for processing (2)
  • .github/workflows/mobile-build.yml
  • .github/workflows/testflight-on-comment.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/testflight-on-comment.yml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-08T17:09:40.432Z
Learnt from: AnthonyRonning
Repo: OpenSecretCloud/Maple PR: 372
File: frontend/src-tauri/Cargo.toml:9-9
Timestamp: 2026-01-08T17:09:40.432Z
Learning: The OpenSecretCloud/Maple repository has comprehensive GitHub Actions workflows (e.g., desktop-build.yml) that automatically validate compilation and testing, so manual compilation verification reminders are unnecessary when reviewing version bumps or dependency updates.

Applied to files:

  • .github/workflows/mobile-build.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-macos (universal-apple-darwin)
  • GitHub Check: build-linux
  • GitHub Check: build-android
  • GitHub Check: build-ios
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (2)
.github/workflows/mobile-build.yml (2)

140-141: [Rewritten review comment]
[Exactly ONE classification tag]


65-71: Supply-chain hardening: downloaded prebuilt xcframework needs integrity verification.
This pulls a large prebuilt binary from an external source but doesn't pin/verify a checksum/signature in CI.

Actionable ask: have scripts/setup-ios-onnxruntime.sh (or this workflow) verify a known SHA-256 (and fail if mismatched).

Comment thread .github/workflows/mobile-build.yml
Comment on lines +78 to +103
- name: Configure Cargo for iOS ONNX Runtime
run: |
# Create cargo config with absolute paths for iOS builds
# This overrides ort-sys's build script to use our pre-built library
WORKSPACE="${{ github.workspace }}"
mkdir -p "${WORKSPACE}/frontend/src-tauri/.cargo"
cat > "${WORKSPACE}/frontend/src-tauri/.cargo/config.toml" << EOF
# Auto-generated cargo config for iOS ONNX Runtime linking
# Uses absolute paths because xcodebuild may run cargo from different directories

[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
EOF

echo "Generated cargo config:"
cat "${WORKSPACE}/frontend/src-tauri/.cargo/config.toml"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Don’t blindly overwrite .cargo/config.toml; also ensure simulator targets are actually installed if needed.
This unconditionally writes frontend/src-tauri/.cargo/config.toml, which can clobber repo config if it exists (now or later). Also, you configure aarch64-apple-ios-sim / x86_64-apple-ios, but only install aarch64-apple-ios (Line 23).

Suggested adjustments:

  • Write to a separate file (or back up/restore an existing config).
  • If the build can hit simulator targets, add Rust targets: aarch64-apple-ios-sim,x86_64-apple-ios (or explicitly ensure the workflow only builds device).

AnthonyRonning and others added 2 commits January 9, 2026 13:30
Replace pre-built HuggingFace library with building ONNX Runtime from
source. The pre-built library lacked statically-linked Abseil dependencies
required for Rust static linking.

Changes:
- Add build-ios-onnxruntime.sh script that builds ONNX Runtime 1.20.1
  from Microsoft's official repo for iOS device and simulator
- Update GitHub Actions workflows to use build-from-source approach
- Cache both build directory and output xcframework for CI efficiency
- Add 90-minute timeout for initial builds (subsequent builds are cached)
- Update .gitignore for build artifacts

The built-from-source library includes all dependencies (Abseil, etc.)
statically linked, resolving the undefined symbols errors.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
The google_nsync dependency requires an older CMake minimum version
that's no longer supported by newer CMake versions. Adding
CMAKE_POLICY_VERSION_MINIMUM=3.5 works around this compatibility issue.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds Text-to-Speech (TTS) support for iOS using ONNX Runtime, enabling the Supertonic TTS model to run on-device. The implementation builds ONNX Runtime 1.20.1 from source during CI builds (despite PR description mentioning pre-built binaries), caches the compiled xcframework, and integrates it with the iOS Tauri app.

Key Changes:

  • Build Infrastructure: Adds GitHub Actions steps to build ONNX Runtime from source for iOS device and simulator architectures, with aggressive caching to speed up subsequent builds
  • Rust Integration: Enables TTS module for iOS (previously desktop-only), adds iOS-specific ONNX Runtime linking in build.rs, and includes iOS TTS commands in the invoke handler
  • iOS Storage: Uses ~/Documents/tts_models for model storage on iOS instead of the standard app data directory
  • Frontend: Updates TTS context to recognize iOS as a supported platform alongside desktop

Implementation Approach:
The implementation mirrors the desktop TTS functionality - models (~264MB) are downloaded on-demand from HuggingFace, ONNX Runtime runs inference on-device, and audio is synthesized locally. Memory usage is approximately 500MB RAM.

Technical Notes:

  • The PR includes an unused setup-ios-onnxruntime.sh script for downloading pre-built binaries, but workflows actually use build-ios-onnxruntime.sh to compile from source
  • Build configuration uses multiple mechanisms (build.rs, .cargo/config.toml generation, environment variables) which may have some redundancy
  • The Cargo config generation uses non-standard table syntax that may not be recognized by Cargo

Confidence Score: 4/5

  • Safe to merge with minor configuration issues that may need follow-up testing
  • The core implementation is sound - TTS module integration, iOS-specific paths, and dependency configuration are correct. However, there are configuration inconsistencies: (1) the Cargo config generation uses non-standard syntax that may be ignored, (2) ORT_LIB_LOCATION paths differ between build.rs and workflow, and (3) an unused setup script suggests incomplete cleanup. These are style/configuration issues that won't break the build since build.rs provides fallback configuration, but they should be verified in testing.
  • The GitHub Actions workflow files (.github/workflows/mobile-build.yml and testflight-on-comment.yml) should be tested to verify the Cargo config syntax works as intended, and build.rs should be aligned with the workflow's ORT_LIB_LOCATION path for consistency.

Important Files Changed

File Analysis

Filename Score Overview
.github/workflows/mobile-build.yml 4/5 Adds ONNX Runtime iOS build steps with caching, library verification, and Cargo configuration generation
.github/workflows/testflight-on-comment.yml 4/5 Duplicates ONNX Runtime build configuration from mobile-build.yml for TestFlight deployments
frontend/src-tauri/Cargo.toml 5/5 Adds iOS-specific TTS dependencies with custom ort features (std, ndarray, no download-binaries)
frontend/src-tauri/build.rs 3/5 Adds iOS-specific ONNX Runtime linking configuration, but has path inconsistency with workflow env var
frontend/src-tauri/src/lib.rs 4/5 Enables TTS module for iOS, adds TTS commands to iOS invoke handler, manages TTS state
frontend/src-tauri/src/tts.rs 5/5 Adds iOS-specific path handling for TTS models using HOME/Documents/tts_models directory
frontend/src/services/tts/TTSContext.tsx 5/5 Updates TTS availability check to include iOS alongside desktop platforms
frontend/src-tauri/scripts/build-ios-onnxruntime.sh 4/5 New script to build ONNX Runtime from source for iOS device and simulator architectures

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Build as build-ios-onnxruntime.sh
    participant Cargo as Cargo Build System
    participant BuildRS as build.rs
    participant App as Tauri iOS App
    participant TTS as TTS Module
    participant ONNX as ONNX Runtime

    Note over GHA,Build: Build Phase
    GHA->>GHA: Cache check for ONNX Runtime
    alt Cache miss
        GHA->>Build: Execute build-ios-onnxruntime.sh
        Build->>Build: Clone ONNX Runtime v1.20.1
        Build->>Build: Build for iOS device (arm64)
        Build->>Build: Build for iOS simulator (arm64 + x86_64)
        Build->>Build: Create xcframework structure
        Build->>GHA: Return built libraries
    end
    GHA->>GHA: Verify ONNX Runtime libraries
    GHA->>GHA: Generate .cargo/config.toml with paths
    GHA->>GHA: Set ORT_LIB_LOCATION env var
    
    Note over GHA,Cargo: Compilation Phase
    GHA->>Cargo: Start iOS build
    Cargo->>BuildRS: Execute build.rs
    BuildRS->>BuildRS: Detect iOS target
    BuildRS->>BuildRS: Set library search paths
    BuildRS->>BuildRS: Set ORT_LIB_LOCATION (overridden by env)
    BuildRS->>Cargo: Return link flags
    Cargo->>Cargo: Compile Rust code with ONNX Runtime
    Cargo->>GHA: iOS app binary
    
    Note over App,ONNX: Runtime Phase
    App->>App: Launch on iOS device
    App->>TTS: User requests TTS
    TTS->>TTS: Check models in ~/Documents/tts_models
    alt Models not present
        TTS->>TTS: Download models from HuggingFace
    end
    TTS->>ONNX: Load ONNX models
    ONNX->>ONNX: Initialize inference sessions
    TTS->>TTS: Process text input
    TTS->>ONNX: Run inference
    ONNX->>TTS: Return audio samples
    TTS->>App: Play synthesized audio
Loading

println!("cargo:rustc-link-lib=framework=Accelerate");

// Set ORT_LIB_LOCATION for the ort crate
println!("cargo:rustc-env=ORT_LIB_LOCATION={}", ort_dir);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] The ORT_LIB_LOCATION set here points to onnxruntime-ios directory, but the GitHub Actions workflow sets it to onnxruntime-ios/onnxruntime.xcframework/ios-arm64. The workflow environment variable will override this build.rs setting, which creates inconsistency between local and CI builds. Consider either removing this line or aligning the paths.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 26:26

Comment:
[P2] The `ORT_LIB_LOCATION` set here points to `onnxruntime-ios` directory, but the GitHub Actions workflow sets it to `onnxruntime-ios/onnxruntime.xcframework/ios-arm64`. The workflow environment variable will override this build.rs setting, which creates inconsistency between local and CI builds. Consider either removing this line or aligning the paths.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +88 to +107
run: |
# Create cargo config with absolute paths for iOS builds
# This overrides ort-sys's build script to use our pre-built library
WORKSPACE="${{ github.workspace }}"
mkdir -p "${WORKSPACE}/frontend/src-tauri/.cargo"
cat > "${WORKSPACE}/frontend/src-tauri/.cargo/config.toml" << EOF
# Auto-generated cargo config for iOS ONNX Runtime linking
# Uses absolute paths because xcodebuild may run cargo from different directories

[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] This dynamically generated .cargo/config.toml uses [target.*.onnxruntime] table names, but standard Cargo config uses section names without dots after the target triple. The correct format should be [target.aarch64-apple-ios] with rustc-link-search directly under it, not nested under onnxruntime. This non-standard syntax may be ignored by Cargo, making the configuration ineffective.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 88:107

Comment:
[P2] This dynamically generated `.cargo/config.toml` uses `[target.*.onnxruntime]` table names, but standard Cargo config uses section names without dots after the target triple. The correct format should be `[target.aarch64-apple-ios]` with `rustc-link-search` directly under it, not nested under `onnxruntime`. This non-standard syntax may be ignored by Cargo, making the configuration ineffective.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +145 to +164
- name: Configure Cargo for iOS ONNX Runtime
run: |
# Create cargo config with absolute paths for iOS builds
# This overrides ort-sys's build script to use our pre-built library
WORKSPACE="${{ github.workspace }}"
mkdir -p "${WORKSPACE}/frontend/src-tauri/.cargo"
cat > "${WORKSPACE}/frontend/src-tauri/.cargo/config.toml" << EOF
# Auto-generated cargo config for iOS ONNX Runtime linking
# Uses absolute paths because xcodebuild may run cargo from different directories

[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Same Cargo config syntax issue as mobile-build.yml. The [target.*.onnxruntime] table syntax is non-standard and likely ignored by Cargo. Should use [target.aarch64-apple-ios] format instead.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 145:164

Comment:
[P2] Same Cargo config syntax issue as mobile-build.yml. The `[target.*.onnxruntime]` table syntax is non-standard and likely ignored by Cargo. Should use `[target.aarch64-apple-ios]` format instead.

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds iOS TTS support using ONNX Runtime, enabling the Supertonic TTS model to run on-device on iPhones and iPads. The implementation mirrors the existing desktop TTS functionality and downloads a pre-built ONNX Runtime 1.20.1 xcframework from HuggingFace.

Key Changes

Build Infrastructure:

  • New setup-ios-onnxruntime.sh script downloads pre-built ONNX Runtime xcframework from HuggingFace
  • GitHub Actions workflows updated with caching and setup steps for ONNX Runtime
  • build.rs updated with iOS-specific linker configuration for ONNX Runtime static library
  • iOS TTS dependencies added to Cargo.toml with appropriate feature flags

Rust Backend:

  • lib.rs updated to enable TTS module for iOS (previously desktop-only) with proper conditional compilation
  • tts.rs updated with iOS-specific path handling using ~/Documents/tts_models directory
  • TTS commands added to iOS invoke handler (download, load, synthesize, unload, delete)

Frontend:

  • TTSContext.tsx updated to enable TTS on iOS using platform detection utilities

Critical Issues Found

Build-Breaking Issues:

  1. Filename mismatch in download script - The script downloads onnxruntime.a from HuggingFace but saves it as libonnxruntime.a, which will cause downloads to fail
  2. Invalid Cargo config tables - The GitHub Actions workflows generate Cargo config with invalid table names like [target.aarch64-apple-ios.onnxruntime] which Cargo will ignore
  3. Inconsistent verification - The workflows verify libonnxruntime.a exists but the script saves onnxruntime.a

These issues will prevent the iOS build from succeeding until fixed.

Architecture

The implementation follows a solid architecture:

  • TTS models (~264MB) are downloaded on-demand at runtime, stored in iOS Documents directory
  • ONNX Runtime static library (~100MB+) is downloaded at build time and cached in GitHub Actions
  • The same TTS engine code is reused for both desktop and iOS via conditional compilation
  • Platform detection properly identifies iOS to enable TTS functionality

Confidence Score: 1/5

  • This PR has critical build-breaking issues that will prevent iOS builds from succeeding
  • Multiple critical logical errors were found that will cause build failures: (1) filename mismatch in the download script where it downloads onnxruntime.a but saves as libonnxruntime.a, (2) invalid Cargo configuration table names that will be ignored, (3) inconsistent file verification. These issues demonstrate the code was not tested on a real iOS build. While the overall architecture is sound and the implementation approach is good, these errors must be fixed before the PR can work.
  • Pay close attention to frontend/src-tauri/scripts/setup-ios-onnxruntime.sh (critical filename bugs), .github/workflows/mobile-build.yml and .github/workflows/testflight-on-comment.yml (invalid Cargo config)

Important Files Changed

File Analysis

Filename Score Overview
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 1/5 Critical filename mismatch - downloads onnxruntime.a but saves as libonnxruntime.a, causing download failures
.github/workflows/mobile-build.yml 2/5 Invalid Cargo config table names and filename mismatches that will prevent builds from working
.github/workflows/testflight-on-comment.yml 2/5 Same issues as mobile-build.yml - invalid Cargo config and filename mismatches
frontend/src-tauri/build.rs 3/5 iOS build configuration added with minor inconsistency in ORT_LIB_LOCATION path between build.rs and workflows
frontend/src-tauri/Cargo.toml 4/5 iOS TTS dependencies added correctly with appropriate feature flags for ort crate
frontend/src-tauri/src/lib.rs 4/5 iOS TTS support properly integrated with conditional compilation, TTS state management, and invoke handlers

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Script as setup-ios-onnxruntime.sh
    participant HF as HuggingFace
    participant Build as build.rs
    participant Cargo as Cargo Build
    participant ORT as ONNX Runtime
    participant TTS as TTS Engine
    participant iOS as iOS Device
    
    Note over GHA,HF: Build-time Setup
    GHA->>GHA: Cache check for onnxruntime-ios
    alt Cache miss
        GHA->>Script: Execute setup script
        Script->>HF: Download xcframework (Info.plist, headers)
        Script->>HF: Download ios-arm64/onnxruntime.a
        Script->>HF: Download ios-arm64_x86_64-simulator/onnxruntime.a
        Script->>GHA: Save to onnxruntime-ios/
        GHA->>GHA: Cache onnxruntime-ios directory
    end
    
    GHA->>GHA: Generate .cargo/config.toml with paths
    GHA->>GHA: Set ORT_LIB_LOCATION env var
    
    GHA->>Build: Invoke Tauri iOS build
    Build->>Build: Detect target_os = ios
    Build->>Build: Set rustc-link-search to arch-specific path
    Build->>Build: Set rustc-link-lib=static=onnxruntime
    Build->>Build: Link iOS frameworks (Foundation, Accelerate)
    Build->>Cargo: Build with iOS target
    Cargo->>ORT: Link pre-built ONNX Runtime static lib
    Cargo->>GHA: Produce iOS .ipa
    
    Note over TTS,iOS: Runtime Usage
    iOS->>TTS: User requests TTS
    TTS->>TTS: Check status (models_downloaded?)
    alt Models not downloaded
        TTS->>HF: Download TTS models (~264MB)
        TTS->>iOS: Save to ~/Documents/tts_models/
    end
    TTS->>ORT: Load ONNX models (duration, encoder, estimator, vocoder)
    TTS->>TTS: Load voice style (F2.json)
    iOS->>TTS: Synthesize text
    TTS->>TTS: Preprocess text (remove markdown, normalize)
    TTS->>ORT: Run duration predictor
    TTS->>ORT: Run text encoder
    TTS->>ORT: Run vector estimator (denoising loop)
    TTS->>ORT: Run vocoder
    TTS->>iOS: Return audio as base64 WAV
    iOS->>iOS: Play audio via Web Audio API
Loading

Comment on lines +62 to +63
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script downloads onnxruntime.a from HuggingFace but saves it as libonnxruntime.a. The remote file is named onnxruntime.a (without the lib prefix), but the script saves it with the lib prefix. This will cause the download to fail because the URL points to a file named onnxruntime.a, not libonnxruntime.a.

Suggested change
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 62:63

Comment:
The script downloads `onnxruntime.a` from HuggingFace but saves it as `libonnxruntime.a`. The remote file is named `onnxruntime.a` (without the `lib` prefix), but the script saves it with the `lib` prefix. This will cause the download to fail because the URL points to a file named `onnxruntime.a`, not `libonnxruntime.a`.

```suggestion
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64/onnxruntime.a"
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +66 to +67
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here - the script downloads onnxruntime.a from HuggingFace but saves it as libonnxruntime.a. This will cause the download to fail.

Suggested change
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/onnxruntime.a" \
"$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 66:67

Comment:
Same issue here - the script downloads `onnxruntime.a` from HuggingFace but saves it as `libonnxruntime.a`. This will cause the download to fail.

```suggestion
curl -L -o "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/onnxruntime.a" \
    "$HF_BASE_URL/$ORT_VERSION/onnxruntime.xcframework/ios-arm64_x86_64-simulator/onnxruntime.a"
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +77 to +78
ls -lh "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a"
ls -lh "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These ls commands reference libonnxruntime.a but after fixing the download issue above, the files will be named onnxruntime.a (without the lib prefix).

Suggested change
ls -lh "$XCFRAMEWORK_DIR/ios-arm64/libonnxruntime.a"
ls -lh "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/libonnxruntime.a"
ls -lh "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a"
ls -lh "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/onnxruntime.a"
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 77:78

Comment:
These ls commands reference `libonnxruntime.a` but after fixing the download issue above, the files will be named `onnxruntime.a` (without the `lib` prefix).

```suggestion
ls -lh "$XCFRAMEWORK_DIR/ios-arm64/onnxruntime.a"
ls -lh "$XCFRAMEWORK_DIR/ios-arm64_x86_64-simulator/onnxruntime.a"
```

How can I resolve this? If you propose a fix, please make it concise.

timeout-minutes: 90

- name: Verify ONNX Runtime files
run: |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This verification step expects libonnxruntime.a, but the download script saves files as onnxruntime.a (without the lib prefix). After fixing the script, update this to match:

Suggested change
run: |
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/onnxruntime.a || echo "File not found or not a valid archive"
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 76:76

Comment:
This verification step expects `libonnxruntime.a`, but the download script saves files as `onnxruntime.a` (without the `lib` prefix). After fixing the script, update this to match:

```suggestion
          file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/onnxruntime.a || echo "File not found or not a valid archive"
```

How can I resolve this? If you propose a fix, please make it concise.

timeout-minutes: 90

- name: Verify ONNX Runtime files
run: |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as in mobile-build.yml - this expects libonnxruntime.a but the script saves onnxruntime.a:

Suggested change
run: |
file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/onnxruntime.a || echo "File not found or not a valid archive"
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 134:134

Comment:
Same issue as in mobile-build.yml - this expects `libonnxruntime.a` but the script saves `onnxruntime.a`:

```suggestion
          file ${{ github.workspace }}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64/onnxruntime.a || echo "File not found or not a valid archive"
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +88 to +98
run: |
# Create cargo config with absolute paths for iOS builds
# This overrides ort-sys's build script to use our pre-built library
WORKSPACE="${{ github.workspace }}"
mkdir -p "${WORKSPACE}/frontend/src-tauri/.cargo"
cat > "${WORKSPACE}/frontend/src-tauri/.cargo/config.toml" << EOF
# Auto-generated cargo config for iOS ONNX Runtime linking
# Uses absolute paths because xcodebuild may run cargo from different directories

[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Cargo config table names [target.aarch64-apple-ios.onnxruntime], [target.aarch64-apple-ios-sim.onnxruntime], and [target.x86_64-apple-ios.onnxruntime] are not valid Cargo configuration syntax.

Cargo config only supports specific known table names under [target.<triple>]. The .onnxruntime suffix is not a recognized table and will be ignored by Cargo, meaning these linker settings will have no effect.

If the intent is to configure linking for the ort crate, this approach won't work. The linker flags in build.rs (which uses cargo:rustc-link-search and cargo:rustc-link-lib) are the correct approach and should be sufficient. This entire config generation step may be unnecessary.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 88:98

Comment:
The Cargo config table names `[target.aarch64-apple-ios.onnxruntime]`, `[target.aarch64-apple-ios-sim.onnxruntime]`, and `[target.x86_64-apple-ios.onnxruntime]` are not valid Cargo configuration syntax. 

Cargo config only supports specific known table names under `[target.<triple>]`. The `.onnxruntime` suffix is not a recognized table and will be ignored by Cargo, meaning these linker settings will have no effect. 

If the intent is to configure linking for the `ort` crate, this approach won't work. The linker flags in `build.rs` (which uses `cargo:rustc-link-search` and `cargo:rustc-link-lib`) are the correct approach and should be sufficient. This entire config generation step may be unnecessary.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +146 to +156
run: |
# Create cargo config with absolute paths for iOS builds
# This overrides ort-sys's build script to use our pre-built library
WORKSPACE="${{ github.workspace }}"
mkdir -p "${WORKSPACE}/frontend/src-tauri/.cargo"
cat > "${WORKSPACE}/frontend/src-tauri/.cargo/config.toml" << EOF
# Auto-generated cargo config for iOS ONNX Runtime linking
# Uses absolute paths because xcodebuild may run cargo from different directories

[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as mobile-build.yml - these Cargo config table names with .onnxruntime suffix are not valid and will be ignored by Cargo. The linker configuration in build.rs should be sufficient.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 146:156

Comment:
Same issue as mobile-build.yml - these Cargo config table names with `.onnxruntime` suffix are not valid and will be ignored by Cargo. The linker configuration in `build.rs` should be sufficient.

How can I resolve this? If you propose a fix, please make it concise.

println!("cargo:rustc-link-lib=framework=Accelerate");

// Set ORT_LIB_LOCATION for the ort crate
println!("cargo:rustc-env=ORT_LIB_LOCATION={}", ort_dir);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ORT_LIB_LOCATION is set to ort_dir (the base onnxruntime-ios directory), but the GitHub Actions workflow sets it to the architecture-specific path (ios-arm64). This inconsistency could cause issues depending on what the ort crate expects.

The workflow's environment variable will override this build script value, but during local development builds this could cause confusion. Consider whether ORT_LIB_LOCATION should point to the base directory or the architecture-specific directory, and make it consistent across build.rs and the workflows.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 26:26

Comment:
The `ORT_LIB_LOCATION` is set to `ort_dir` (the base `onnxruntime-ios` directory), but the GitHub Actions workflow sets it to the architecture-specific path (`ios-arm64`). This inconsistency could cause issues depending on what the `ort` crate expects. 

The workflow's environment variable will override this build script value, but during local development builds this could cause confusion. Consider whether `ORT_LIB_LOCATION` should point to the base directory or the architecture-specific directory, and make it consistent across build.rs and the workflows.

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds Text-to-Speech (TTS) support for iOS using ONNX Runtime, enabling the Supertonic TTS model to run on-device. The implementation mirrors the existing desktop TTS functionality.

Key Changes:

  • Rust Backend: Enables TTS module compilation for iOS, adds iOS-specific dependencies (ort with std/ndarray features), and uses ~/Documents/tts_models for model storage on iOS
  • Build System: Adds build.rs configuration for linking ONNX Runtime xcframework, with separate paths for simulator vs device builds
  • CI/CD: GitHub Actions workflows now build ONNX Runtime 1.20.1 from source (cached), generate cargo config with absolute paths, and set environment variables for linking
  • Frontend: Updates TTSContext to enable TTS on iOS platforms

Critical Issue Found:
The lib.rs file contains a blocking bug where Android and iOS app configurations both create a variable named app, causing the Android configuration (lines 271-289) to be completely shadowed by the iOS configuration (lines 293-317). This will break Android builds.

Technical Approach:

  • ONNX Runtime is built from source via build-ios-onnxruntime.sh during CI, creating a universal xcframework
  • Static linking is configured through both build.rs and a generated .cargo/config.toml
  • TTS models (~264MB) are downloaded on-demand to iOS Documents directory

Confidence Score: 0/5

  • NOT SAFE to merge - contains critical bug that breaks Android builds
  • The PR contains a P0 blocking issue in lib.rs where the Android app configuration is shadowed by the iOS configuration, causing both blocks to try to create the same app variable. This will cause Android builds to fail because iOS TTS commands won't exist on Android. The shadowing bug must be fixed before merge.
  • frontend/src-tauri/src/lib.rs (critical cfg block shadowing bug)

Important Files Changed

File Analysis

Filename Score Overview
frontend/src-tauri/src/lib.rs 0/5 Adds iOS TTS support by enabling TTS module and commands. CRITICAL BUG: Android and iOS app configurations shadow each other, breaking Android builds.
frontend/src-tauri/src/tts.rs 5/5 Adds iOS-specific path handling for TTS models using ~/Documents directory, appropriate for iOS file system.
frontend/src-tauri/build.rs 4/5 Adds iOS ONNX Runtime linking configuration. ORT_LIB_LOCATION value differs from workflows, may cause confusion but likely functional.
frontend/src-tauri/Cargo.toml 5/5 Adds iOS-specific TTS dependencies with appropriate ort features (std, ndarray) and disabled default features.
frontend/src/services/tts/TTSContext.tsx 5/5 Updates TTS availability check to include iOS platforms alongside desktop.
.github/workflows/mobile-build.yml 4/5 Adds ONNX Runtime build from source with caching, cargo config generation, and ORT_LIB_LOCATION env var. Comprehensive build setup.
.github/workflows/testflight-on-comment.yml 4/5 Mirrors mobile-build.yml changes for TestFlight builds. Identical ONNX Runtime setup for consistency.
frontend/src-tauri/scripts/build-ios-onnxruntime.sh 5/5 New script to build ONNX Runtime from source for iOS, creating xcframework with device and simulator libraries.

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Build as build-ios-onnxruntime.sh
    participant ONNX as ONNX Runtime Repo
    participant Cargo as Cargo Build
    participant iOS as iOS App
    participant TTS as TTS Module
    participant Models as HuggingFace

    Note over GHA,ONNX: Build Phase (CI)
    GHA->>GHA: Check cache for ONNX Runtime
    alt Cache miss
        GHA->>Build: Execute build-ios-onnxruntime.sh
        Build->>ONNX: Clone v1.20.1
        Build->>Build: Build for ios-arm64
        Build->>Build: Build for ios-arm64_x86_64-simulator
        Build->>Build: Create xcframework
        Build-->>GHA: xcframework ready
    end
    
    GHA->>GHA: Generate .cargo/config.toml
    GHA->>GHA: Set ORT_LIB_LOCATION env
    GHA->>Cargo: cargo build (via tauri ios build)
    
    Note over Cargo,TTS: Compile Time
    Cargo->>Cargo: Read build.rs
    Cargo->>Cargo: Link static libonnxruntime.a
    Cargo->>Cargo: Compile with iOS TTS support
    Cargo-->>GHA: iOS IPA created

    Note over iOS,Models: Runtime
    iOS->>TTS: User initiates TTS
    TTS->>TTS: Check ~/Documents/tts_models
    alt Models not present
        TTS->>Models: Download Supertonic models (~264MB)
        Models-->>TTS: Models downloaded
        TTS->>TTS: Save to ~/Documents/tts_models
    end
    TTS->>TTS: Load ONNX models via ort crate
    TTS->>TTS: Synthesize speech
    TTS-->>iOS: Audio playback
Loading

Comment on lines 269 to +318
@@ -279,6 +288,34 @@ pub fn run() {
})
.plugin(tauri_plugin_updater::Builder::new().build());

// iOS-specific configuration (with TTS)
#[cfg(all(not(desktop), target_os = "ios"))]
let app = builder
.invoke_handler(tauri::generate_handler![
pdf_extractor::extract_document_content,
tts::tts_get_status,
tts::tts_download_models,
tts::tts_load_models,
tts::tts_synthesize,
tts::tts_unload_models,
tts::tts_delete_models,
])
.setup(|app| {
// Set up the deep link handler for mobile
let app_handle = app.handle().clone();

// Register deep link handler - note that iOS does not support runtime registration
// but the handler for incoming URLs still works
app.deep_link().on_open_url(move |event| {
if let Some(url) = event.urls().first() {
handle_deep_link_event(url.as_ref(), &app_handle);
}
});

Ok(())
})
.plugin(tauri_plugin_updater::Builder::new().build());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Android app configuration is shadowed and never runs. Both Android (line 271) and iOS (line 293) configurations create a variable named app, causing the Android configuration to be completely overwritten. On Android builds, this will cause compilation failure because iOS-specific TTS commands won't exist.

The iOS block at line 292 should use #[cfg(target_os = "ios")] instead of #[cfg(all(not(desktop), target_os = "ios"))] since the outer #[cfg(not(desktop))] already excludes desktop. This would prevent both blocks from trying to create app.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/src/lib.rs
Line: 269:318

Comment:
[P0] Android app configuration is shadowed and never runs. Both Android (line 271) and iOS (line 293) configurations create a variable named `app`, causing the Android configuration to be completely overwritten. On Android builds, this will cause compilation failure because iOS-specific TTS commands won't exist.

The iOS block at line 292 should use `#[cfg(target_os = "ios")]` instead of `#[cfg(all(not(desktop), target_os = "ios"))]` since the outer `#[cfg(not(desktop))]` already excludes desktop. This would prevent both blocks from trying to create `app`.

How can I resolve this? If you propose a fix, please make it concise.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @frontend/src-tauri/scripts/build-ios-onnxruntime.sh:
- Around line 220-232: The Info.plist generation currently unconditionally lists
x86_64 under SupportedArchitectures even if the x86_64 simulator build fails;
modify the build-ios-onnxruntime.sh flow so that the simulator build step sets a
boolean flag on failure (the code path that currently only logs a warning for
the x86_64 simulator build) and then use that flag when emitting the <array> for
SupportedArchitectures: omit the <string>x86_64</string> entry if the x86_64
build failed, or alternatively append a clear summary warning to the build
output indicating the Info.plist contains only arm64; ensure the flag is
referenced where the Info.plist snippet with SupportedArchitectures is written
so the plist accurately reflects the actual built libs.
- Around line 124-130: The simulator arm64 lookup assigns IOS_SIM_ARM64_LIB but
lacks the error check; mirror the device block's behavior by validating
IOS_SIM_ARM64_LIB after the find (and fallback) and, if empty, log a clear error
(e.g., "Could not find iOS simulator arm64 lib: libonnxruntime.a") and exit
non‑zero so the script fails fast before lipo/cp; update the echo to only run
when IOS_SIM_ARM64_LIB is set.
🧹 Nitpick comments (2)
frontend/src-tauri/scripts/build-ios-onnxruntime.sh (2)

14-14: Consider stricter error handling with set -euo pipefail.

Using set -e alone may miss failures in pipelines and unbound variable references. Adding -u catches typos and -o pipefail ensures pipeline failures propagate.

Suggested improvement
-set -e
+set -euo pipefail

184-192: Header copy may silently fail with confusing downstream errors.

Line 184's find ... | head -n 1 | xargs dirname will produce . if no file is found (empty input to xargs), potentially causing the header copy to silently do nothing. Consider adding a check.

Suggested improvement
 # Copy headers
-HEADER_DIR=$(find build -name "onnxruntime_c_api.h" -type f | head -n 1 | xargs dirname)
-if [ -n "$HEADER_DIR" ]; then
+HEADER_FILE=$(find build -name "onnxruntime_c_api.h" -type f | head -n 1)
+if [ -n "$HEADER_FILE" ]; then
+    HEADER_DIR=$(dirname "$HEADER_FILE")
     cp "${HEADER_DIR}"/*.h "${XCFRAMEWORK_DIR}/Headers/" 2>/dev/null || true
 fi
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d95a2df and 518a04b.

📒 Files selected for processing (4)
  • .github/workflows/mobile-build.yml
  • .github/workflows/testflight-on-comment.yml
  • frontend/src-tauri/.gitignore
  • frontend/src-tauri/scripts/build-ios-onnxruntime.sh
✅ Files skipped from review due to trivial changes (1)
  • frontend/src-tauri/.gitignore
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/mobile-build.yml
  • .github/workflows/testflight-on-comment.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build-linux
  • GitHub Check: build-macos (universal-apple-darwin)
  • GitHub Check: build-android
🔇 Additional comments (4)
frontend/src-tauri/scripts/build-ios-onnxruntime.sh (4)

47-62: LGTM!

The clone and checkout logic correctly handles both fresh clones and updates to existing repositories. The --depth 1 --recursive clone is appropriate for CI builds to minimize download size.


92-105: LGTM!

Good defensive fallback logic to find the library in alternate locations, with helpful debug output if the build fails.


132-158: LGTM!

The x86_64 simulator build correctly treats a missing library as a warning rather than an error, since arm64-only simulator support is acceptable for Apple Silicon workflows. The downstream logic at lines 174-181 properly handles both cases.


242-258: LGTM!

Clear build summary with helpful debugging information including library sizes and a symbol verification command.

Comment thread frontend/src-tauri/scripts/build-ios-onnxruntime.sh Outdated
Comment thread frontend/src-tauri/scripts/build-ios-onnxruntime.sh Outdated
AnthonyRonning and others added 2 commits January 9, 2026 13:41
ONNX Runtime 1.20.1 has a stale Eigen dependency hash that no longer
matches GitLab's regenerated archive. Upgrading to 1.22.0 which has
updated dependency hashes.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
GitLab archives are regenerated periodically, causing hash mismatches
with older ONNX Runtime versions. Using the latest release (1.22.2)
which should have the most current dependency hashes.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
AnthonyRonning and others added 2 commits January 9, 2026 14:06
ONNX Runtime builds multiple component static libraries instead of a
single libonnxruntime.a. We now use libtool to combine them all into
one archive for easier linking.

Also simplified to only build arm64 simulator (skipping x86_64) since
GitHub Actions runners use Apple Silicon.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Transient network errors (DNS resolution failures) can cause the
ONNX Runtime clone to fail. Added retry logic with 3 attempts and
10 second delays between retries.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds iOS TTS support by integrating ONNX Runtime 1.22.2, enabling the Supertonic TTS model to run on-device.

Key Changes:

  • Build System: Adds build-ios-onnxruntime.sh to build ONNX Runtime from source with all dependencies statically linked. GitHub Actions caches the ~90min build for reuse.
  • Linker Configuration: build.rs configures iOS-specific linker paths for the ONNX Runtime xcframework, linking Foundation and Accelerate frameworks.
  • Rust Backend: Enables the tts module for iOS with platform-specific model storage in ~/Documents/tts_models (iOS sandboxing requirement).
  • Frontend: Updates TTSContext.tsx to detect iOS platform and enable TTS UI/functionality.
  • Cargo Dependencies: Adds iOS-specific ort dependency with default-features = false to prevent automatic binary downloads.

Architecture:
The implementation mirrors the desktop TTS approach: users download ~264MB of models on-demand, which are then loaded into memory for synthesis. The ONNX Runtime library is built from source to ensure all dependencies (Abseil, protobuf, etc.) are statically linked into a single .a file per architecture.

iOS-Specific Adaptations:

  1. Model storage uses ~/Documents/tts_models instead of system data directories
  2. Static library linking via xcframework structure (device + simulator)
  3. Build process integrated into CI/CD with caching

Confidence Score: 3/5

  • Generally safe but has a path mismatch bug that will cause simulator build failures
  • The implementation is well-structured and follows proper iOS patterns, but contains a critical path inconsistency between build.rs and the build script that will cause linker failures for simulator builds. The Cargo config sections in workflows also use non-standard syntax that Cargo will ignore (though this may not break builds if build.rs handles linking correctly).
  • frontend/src-tauri/build.rs (simulator path mismatch), .github/workflows/*.yml (non-standard Cargo config syntax)

Important Files Changed

File Analysis

Filename Score Overview
.github/workflows/mobile-build.yml 3/5 Adds ONNX Runtime build/cache steps and Cargo config generation with non-standard target sections that Cargo will ignore
.github/workflows/testflight-on-comment.yml 3/5 Mirrors mobile-build.yml with same ONNX Runtime setup and Cargo config issues
frontend/src-tauri/.gitignore 5/5 Adds ignore patterns for ONNX Runtime iOS build artifacts and generated cargo config
frontend/src-tauri/Cargo.toml 5/5 Adds iOS-specific TTS dependencies with proper feature flags to disable download-binaries
frontend/src-tauri/build.rs 4/5 Adds iOS linker configuration for ONNX Runtime with simulator path inconsistency
frontend/src-tauri/scripts/build-ios-onnxruntime.sh 5/5 New script to build ONNX Runtime 1.22.2 from source for iOS, creates xcframework with combined static libraries
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 5/5 New script to download pre-built ONNX Runtime 1.20.1 from HuggingFace (not used by workflows)
frontend/src-tauri/src/lib.rs 5/5 Enables TTS module for iOS, adds iOS-specific app initialization with TTS state management and invoke handlers
frontend/src-tauri/src/tts.rs 5/5 Adds iOS-specific path handling using ~/Documents/tts_models for model storage
frontend/src/services/tts/TTSContext.tsx 5/5 Updates platform detection to enable TTS on iOS in addition to desktop
frontend/bun.lock 5/5 Lock file update, likely from dependency changes

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Build as build-ios-onnxruntime.sh
    participant Cargo as Cargo Build
    participant BuildRS as build.rs
    participant ORT as ONNX Runtime
    participant App as iOS App

    Note over GHA: iOS Build Pipeline
    GHA->>GHA: Cache check (1.22.2-v1)
    alt Cache Miss
        GHA->>Build: Run build script
        Build->>Build: Clone ONNX Runtime 1.22.2
        Build->>Build: Build ios-arm64 static lib
        Build->>Build: Build ios-arm64-simulator lib
        Build->>Build: Create xcframework structure
        Build-->>GHA: xcframework ready
    end
    
    GHA->>GHA: Configure Cargo config.toml
    Note over GHA: Sets [target.*.onnxruntime]<br/>(non-standard, ignored by Cargo)
    
    GHA->>Cargo: bun tauri ios build
    Cargo->>BuildRS: Execute build.rs
    BuildRS->>BuildRS: Detect iOS target
    BuildRS->>BuildRS: Set rustc-link-search
    BuildRS->>BuildRS: Set ORT_LIB_LOCATION
    BuildRS-->>Cargo: Link configuration
    
    Cargo->>ORT: Link static library
    Note over ORT: Uses ios-arm64 or<br/>ios-arm64-simulator
    ORT-->>Cargo: Linked binary
    
    Cargo->>App: Build iOS app
    App->>App: TTS module available
    Note over App: Models stored in<br/>~/Documents/tts_models
Loading

Comment on lines +11 to +14
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
} else {
format!("{}/onnxruntime.xcframework/ios-arm64", ort_dir)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Simulator path inconsistency: build.rs uses ios-arm64_x86_64-simulator for sim/x86_64 targets, but build-ios-onnxruntime.sh creates only ios-arm64-simulator. This mismatch will cause linker failures when building for x86_64 simulator. Either update build.rs to use ios-arm64-simulator or update the build script to create the ios-arm64_x86_64-simulator directory.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 11:14

Comment:
[P2] Simulator path inconsistency: `build.rs` uses `ios-arm64_x86_64-simulator` for sim/x86_64 targets, but `build-ios-onnxruntime.sh` creates only `ios-arm64-simulator`. This mismatch will cause linker failures when building for x86_64 simulator. Either update `build.rs` to use `ios-arm64-simulator` or update the build script to create the `ios-arm64_x86_64-simulator` directory.

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds iOS TTS support using ONNX Runtime, building from source (v1.22.2) and enabling the Supertonic TTS model to run on-device on iOS. The implementation mirrors the existing desktop TTS functionality with iOS-specific adjustments for file paths and dependencies.

What Changed

Core Implementation:

  • Added iOS-specific TTS dependencies to Cargo.toml (ort, ndarray, etc.)
  • Modified build.rs to link ONNX Runtime xcframework for iOS builds
  • Updated lib.rs to enable TTS module for iOS (was desktop-only)
  • Modified tts.rs to use iOS Documents directory for model storage
  • Updated frontend TTSContext.tsx to enable TTS on iOS devices

Build Infrastructure:

  • Added build-ios-onnxruntime.sh to build ONNX Runtime 1.22.2 from source
  • Added setup-ios-onnxruntime.sh (downloads pre-built 1.20.1, appears unused in CI)
  • Modified GitHub Actions workflows to build/cache ONNX Runtime and configure Cargo
  • Added .gitignore entries for ONNX Runtime build artifacts

Critical Issues Found

🔴 Path Mismatch Bug (Will Break Simulator Builds):
The build-ios-onnxruntime.sh script creates the xcframework with path ios-arm64-simulator, but build.rs looks for ios-arm64_x86_64-simulator. This inconsistency will cause iOS simulator builds to fail with linker errors. Device builds will work, but developers cannot test in the iOS simulator.

🔴 Invalid Cargo Configuration Syntax:
Both workflow files generate Cargo config with [target.aarch64-apple-ios.onnxruntime] sections. The .onnxruntime suffix is not valid Cargo syntax and will be ignored. This means the custom linker paths won't be applied, potentially causing build failures.

Other Issues

  • Performance: iOS ndarray missing rayon feature (present in desktop version) may cause slower TTS synthesis
  • Version Confusion: setup-ios-onnxruntime.sh defaults to 1.20.1 while everything else uses 1.22.2
  • Documentation: PR description mentions 1.20.1 but actual builds use 1.22.2

Architecture Assessment

The overall approach is sound: using platform-specific conditional compilation, proper iOS sandboxing (Documents directory), and building ONNX Runtime from source to ensure compatibility. The TTS implementation correctly reuses the existing desktop code. However, the critical path mismatch bug must be fixed before this can work on iOS simulator.

Confidence Score: 1/5

  • This PR has critical bugs that will break iOS simulator builds and potentially all iOS builds due to invalid Cargo configuration
  • Score of 1 (critical issues) reflects two blocking bugs: (1) xcframework path mismatch between build script output and build.rs expectations will cause linker failures for iOS simulator, and (2) invalid Cargo config syntax in workflows means linker paths won't be applied correctly. These are not "potential" issues - they will definitely cause build failures. Device builds might work by accident if the build.rs paths are found, but simulator builds will fail 100% of the time.
  • Critical fixes needed in: frontend/src-tauri/build.rs (line 12), .github/workflows/mobile-build.yml (lines 97-107), .github/workflows/testflight-on-comment.yml (lines 155-165). Also review frontend/src-tauri/Cargo.toml for iOS ndarray rayon feature.

Important Files Changed

File Analysis

Filename Score Overview
frontend/src-tauri/build.rs 1/5 Critical path mismatch bug: simulator library path points to ios-arm64_x86_64-simulator instead of ios-arm64-simulator, causing iOS simulator builds to fail
.github/workflows/mobile-build.yml 1/5 Invalid Cargo config syntax with .onnxruntime suffix will be ignored; simulator path inconsistency will cause linker failures
.github/workflows/testflight-on-comment.yml 1/5 Same issues as mobile-build.yml: invalid Cargo config syntax and simulator path mismatch
frontend/src-tauri/Cargo.toml 3/5 iOS ndarray missing rayon feature may cause performance degradation compared to desktop; TTS dependencies properly added for iOS
frontend/src-tauri/scripts/build-ios-onnxruntime.sh 4/5 Build script creates ios-arm64-simulator directory (not ios-arm64_x86_64-simulator), causing path mismatch with other files; otherwise well-structured with retry logic

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Build as build-ios-onnxruntime.sh
    participant Cache as Actions Cache
    participant BuildRS as build.rs
    participant Cargo as Cargo Build
    participant XCF as xcframework

    Note over GHA,XCF: iOS TTS Build Flow

    GHA->>Cache: Check cache for onnxruntime-ios-built-1.22.2-v1
    alt Cache Hit
        Cache-->>GHA: Restore cached xcframework
    else Cache Miss
        GHA->>Build: Execute build-ios-onnxruntime.sh 1.22.2
        Build->>Build: Clone ONNX Runtime v1.22.2
        Build->>Build: Build for ios-arm64 (device)
        Build->>Build: Build for ios-arm64-simulator
        Build->>XCF: Create xcframework at ios-arm64-simulator/
        XCF-->>Build: xcframework created
        Build-->>GHA: Build complete
        GHA->>Cache: Cache xcframework for future builds
    end

    GHA->>GHA: Generate .cargo/config.toml
    Note over GHA: ⚠️ BUG: Uses invalid [target.*.onnxruntime] syntax
    Note over GHA: ⚠️ BUG: Points to ios-arm64-simulator (correct path from build script)

    GHA->>BuildRS: Invoke build.rs during cargo build
    BuildRS->>BuildRS: Check TARGET env var
    alt Simulator Build
        Note over BuildRS: ⚠️ BUG: Looks for ios-arm64_x86_64-simulator
        BuildRS->>XCF: Search for ios-arm64_x86_64-simulator/libonnxruntime.a
        XCF-->>BuildRS: ❌ File not found (actual path is ios-arm64-simulator)
        BuildRS-->>Cargo: ❌ Linker error - library not found
    else Device Build
        BuildRS->>XCF: Search for ios-arm64/libonnxruntime.a
        XCF-->>BuildRS: ✅ File found
        BuildRS->>Cargo: Link libonnxruntime.a + Accelerate + Foundation
        Cargo->>Cargo: Compile Rust code with TTS
        Cargo-->>GHA: ✅ Build succeeds for device
    end

    Note over GHA,Cargo: Result: Device builds work, simulator builds fail
Loading

// Check if building for simulator or device
let target = std::env::var("TARGET").unwrap_or_default();
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The simulator xcframework path ios-arm64_x86_64-simulator in build.rs does not match the actual path created by build-ios-onnxruntime.sh which creates ios-arm64-simulator. This will cause build failures when building for iOS simulator.

Impact: iOS simulator builds will fail with a linker error because the library cannot be found at this path.

Root cause: The build-ios-onnxruntime.sh script (line 205) creates the directory as ios-arm64-simulator, but this build.rs expects ios-arm64_x86_64-simulator (matching the setup script but not the build script).

Fix needed: Change this line to:

Suggested change
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
format!("{}/onnxruntime.xcframework/ios-arm64-simulator", ort_dir)

Also update the GitHub workflows (mobile-build.yml lines 102, 106 and testflight-on-comment.yml lines 160, 164) to use ios-arm64-simulator instead of ios-arm64-simulator in the cargo config generation.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 12:12

Comment:
The simulator xcframework path `ios-arm64_x86_64-simulator` in build.rs does not match the actual path created by `build-ios-onnxruntime.sh` which creates `ios-arm64-simulator`. This will cause build failures when building for iOS simulator.

**Impact**: iOS simulator builds will fail with a linker error because the library cannot be found at this path.

**Root cause**: The `build-ios-onnxruntime.sh` script (line 205) creates the directory as `ios-arm64-simulator`, but this build.rs expects `ios-arm64_x86_64-simulator` (matching the setup script but not the build script).

**Fix needed**: Change this line to:
```suggestion
            format!("{}/onnxruntime.xcframework/ios-arm64-simulator", ort_dir)
```

Also update the GitHub workflows (mobile-build.yml lines 102, 106 and testflight-on-comment.yml lines 160, 164) to use `ios-arm64-simulator` instead of `ios-arm64-simulator` in the cargo config generation.

How can I resolve this? If you propose a fix, please make it concise.

# We disable download-binaries and copy-dylibs since we link our own xcframework
# Need "std" for Error trait impl and file operations, "ndarray" for tensor creation
ort = { version = "2.0.0-rc.10", default-features = false, features = ["std", "ndarray"] }
ndarray = { version = "0.16" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The iOS version of ndarray is missing the "rayon" feature that is included in the desktop version (line 46). This inconsistency could cause performance degradation on iOS since parallel operations won't be available.

The desktop version has:

ndarray = { version = "0.16", features = ["rayon"] }

But the iOS version only has:

ndarray = { version = "0.16" }

Impact: TTS synthesis on iOS may be significantly slower than on desktop due to lack of parallel processing via rayon.

Suggested change
ndarray = { version = "0.16" }
ndarray = { version = "0.16", features = ["rayon"] }
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/Cargo.toml
Line: 62:62

Comment:
The iOS version of ndarray is missing the "rayon" feature that is included in the desktop version (line 46). This inconsistency could cause performance degradation on iOS since parallel operations won't be available.

The desktop version has:
```toml
ndarray = { version = "0.16", features = ["rayon"] }
```

But the iOS version only has:
```toml
ndarray = { version = "0.16" }
```

**Impact**: TTS synthesis on iOS may be significantly slower than on desktop due to lack of parallel processing via rayon.

```suggestion
ndarray = { version = "0.16", features = ["rayon"] }
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +97 to +107
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cargo config sections use an invalid format: [target.aarch64-apple-ios.onnxruntime]. This was already noted in previous review threads. The .onnxruntime suffix is not a valid Cargo config section and will be ignored by Cargo.

Standard Cargo only supports [target.<triple>] sections. The correct format should be:

Suggested change
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

Additionally, line 106 has the wrong path - it should point to ios-arm64-simulator not ios-arm64-simulator (matching the build-ios-onnxruntime.sh script output).

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 97:107

Comment:
The cargo config sections use an invalid format: `[target.aarch64-apple-ios.onnxruntime]`. This was already noted in previous review threads. The `.onnxruntime` suffix is not a valid Cargo config section and will be ignored by Cargo.

Standard Cargo only supports `[target.<triple>]` sections. The correct format should be:

```suggestion
          [target.aarch64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.aarch64-apple-ios-sim]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.x86_64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
```

Additionally, line 106 has the wrong path - it should point to `ios-arm64-simulator` not `ios-arm64-simulator` (matching the build-ios-onnxruntime.sh script output).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +155 to +165
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as in mobile-build.yml: The cargo config sections use an invalid format with .onnxruntime suffix which will be ignored by Cargo.

The correct format should be:

Suggested change
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

Additionally, line 164 has the wrong path - it should point to ios-arm64-simulator (matching the build-ios-onnxruntime.sh script output).

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 155:165

Comment:
Same issue as in mobile-build.yml: The cargo config sections use an invalid format with `.onnxruntime` suffix which will be ignored by Cargo. 

The correct format should be:

```suggestion
          [target.aarch64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.aarch64-apple-ios-sim]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.x86_64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
```

Additionally, line 164 has the wrong path - it should point to `ios-arm64-simulator` (matching the build-ios-onnxruntime.sh script output).

How can I resolve this? If you propose a fix, please make it concise.


SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TAURI_DIR="$(dirname "$SCRIPT_DIR")"
ORT_VERSION="${ORT_VERSION:-1.20.1}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version mismatch: This script defaults to ONNX Runtime 1.20.1, but:

  • The PR description states version 1.20.1 is being used
  • The build-ios-onnxruntime.sh script defaults to 1.22.2 (which is what's actually being built in CI)
  • Cargo.toml comments say 1.22.2
  • The CI cache key is for 1.22.2

Since the CI workflows use the build-from-source script (build-ios-onnxruntime.sh) and cache version 1.22.2, this setup script is essentially unused but creates confusion about which version is intended.

Recommendation: Either update this to match 1.22.2, or document clearly that this script is for local development only and CI uses the build script.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 10:10

Comment:
Version mismatch: This script defaults to ONNX Runtime 1.20.1, but:
- The PR description states version 1.20.1 is being used
- The build-ios-onnxruntime.sh script defaults to 1.22.2 (which is what's actually being built in CI)
- Cargo.toml comments say 1.22.2
- The CI cache key is for 1.22.2

Since the CI workflows use the build-from-source script (build-ios-onnxruntime.sh) and cache version 1.22.2, this setup script is essentially unused but creates confusion about which version is intended. 

**Recommendation**: Either update this to match 1.22.2, or document clearly that this script is for local development only and CI uses the build script.

How can I resolve this? If you propose a fix, please make it concise.

The simulator build fails with a linker error:
'building for iOS-simulator, but linking in dylib built for iOS'

This is a bug in ONNX Runtime's CMake configuration for iOS simulator
where it incorrectly uses the iPhoneOS SDK's libiconv instead of
the iPhoneSimulator SDK's libiconv.

For TestFlight/App Store deployment, only the device (arm64) build is
needed anyway. Local development can use desktop or physical devices.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds Text-to-Speech support for iOS using ONNX Runtime 1.22.2, enabling the Supertonic TTS model to run on-device. The implementation mirrors the desktop version with appropriate iOS-specific adaptations.

Key Changes:

  • Builds ONNX Runtime 1.22.2 from source for iOS (device only, simulator build skipped due to known CMake bug)
  • Adds iOS-specific dependencies in Cargo.toml matching desktop TTS configuration
  • Implements iOS path handling using ~/Documents/tts_models for model storage
  • Updates frontend to enable TTS on iOS platforms
  • Configures GitHub Actions to cache built ONNX Runtime libraries

Critical Issues Found:
The implementation has path inconsistencies between build scripts, build.rs, and GitHub Actions workflows. The build-ios-onnxruntime.sh script creates a directory named ios-arm64-simulator, while build.rs and the setup-ios-onnxruntime.sh script expect ios-arm64_x86_64-simulator. This mismatch will cause linker failures when building for simulator targets, as the linker won't find the library in the expected location.

Impact:

  • Device builds may work (ios-arm64 path is consistent)
  • Simulator builds will fail with "library not found" linker errors
  • TestFlight/App Store deployment blocked until simulator path issues resolved

The overall architecture is sound - TTS module properly gated for iOS, state management correctly configured, and iOS sandboxing constraints appropriately handled. Once path consistency issues are resolved, this should function as intended.

Confidence Score: 2/5

  • Not safe to merge - contains blocking path mismatches that will cause build failures
  • Multiple P0 path inconsistencies between build script output (ios-arm64-simulator) and expected paths in build.rs/workflows (ios-arm64_x86_64-simulator) will cause linker failures. While device builds may succeed, simulator builds will definitely fail, blocking local development and potentially CI/CD depending on build configuration.
  • frontend/src-tauri/scripts/build-ios-onnxruntime.sh (fix directory names), .github/workflows/mobile-build.yml (fix cargo config paths), .github/workflows/testflight-on-comment.yml (fix cargo config paths)

Important Files Changed

File Analysis

Filename Score Overview
.github/workflows/mobile-build.yml 3/5 Adds ONNX Runtime build steps for iOS TTS. Contains path inconsistencies between build script output and cargo config that will cause linker failures for simulator builds.
.github/workflows/testflight-on-comment.yml 3/5 Mirrors mobile-build.yml changes. Same path inconsistency issues will cause simulator build failures.
frontend/bun.lock 5/5 Minor lockfile metadata update (adds configVersion field). No functional changes.
frontend/src-tauri/.gitignore 5/5 Adds ignore patterns for ONNX Runtime build artifacts and generated cargo config.
frontend/src-tauri/Cargo.toml 5/5 Adds iOS-specific TTS dependencies matching desktop configuration. Properly configured with correct ort flags.
frontend/src-tauri/build.rs 3/5 Adds iOS build configuration for ONNX Runtime linking. Simulator path uses ios-arm64_x86_64-simulator but build-ios-onnxruntime.sh creates ios-arm64-simulator, causing mismatch.
frontend/src-tauri/scripts/build-ios-onnxruntime.sh 4/5 Builds ONNX Runtime 1.22.2 from source, creating ios-arm64 and ios-arm64-simulator directories. Path naming doesn't match what build.rs expects.
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 4/5 Downloads pre-built ONNX Runtime from HuggingFace. Creates ios-arm64_x86_64-simulator directory (different naming than build script). Currently unused as workflow uses build script instead.
frontend/src-tauri/src/lib.rs 5/5 Enables TTS module and commands for iOS, adds iOS-specific app setup with TTS state management. Logic correctly separated between iOS and Android.
frontend/src-tauri/src/tts.rs 5/5 Adds iOS-specific path handling for TTS models using ~/Documents/tts_models. Implementation is appropriate for iOS sandboxing.
frontend/src/services/tts/TTSContext.tsx 5/5 Updates TTS availability check to include iOS platforms. Correctly uses platform detection utilities.

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Build as build-ios-onnxruntime.sh
    participant Cache as Actions Cache
    participant Cargo as Cargo Build
    participant BuildRS as build.rs
    participant ORT as ONNX Runtime

    GHA->>Cache: Check for onnxruntime-ios cache
    alt Cache Miss
        GHA->>Build: Execute build script (1.22.2)
        Build->>Build: Clone ONNX Runtime repo
        Build->>Build: Build for ios-arm64 (device)
        Build->>Build: Skip ios-arm64-simulator (CMake bug)
        Build->>Build: Create xcframework with<br/>ios-arm64/<br/>ios-arm64-simulator/
        Build->>Cache: Store in cache
    else Cache Hit
        Cache->>GHA: Restore onnxruntime-ios
    end
    
    GHA->>GHA: Generate .cargo/config.toml<br/>with ios-arm64-simulator paths
    
    Note over GHA,BuildRS: PATH MISMATCH OCCURS HERE
    
    GHA->>Cargo: cargo-tauri ios build
    Cargo->>BuildRS: Execute build.rs
    BuildRS->>BuildRS: Set rustc-link-search for<br/>ios-arm64_x86_64-simulator
    BuildRS->>Cargo: Return linker flags
    
    alt Device Build (aarch64-apple-ios)
        Cargo->>ORT: Link ios-arm64/libonnxruntime.a ✓
        Cargo->>GHA: Build succeeds
    else Simulator Build (aarch64-apple-ios-sim)
        Cargo->>ORT: Search ios-arm64_x86_64-simulator/ ✗
        Note over Cargo,ORT: Directory not found!<br/>Actual: ios-arm64-simulator
        Cargo->>GHA: Linker error: library not found
    end
Loading


mkdir -p "${OUTPUT_DIR}"
mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64"
mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64-simulator"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Simulator directory name mismatch will cause linker failures. This creates ios-arm64-simulator but build.rs expects ios-arm64_x86_64-simulator. Change line 172 to: mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64_x86_64-simulator"

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/build-ios-onnxruntime.sh
Line: 172:172

Comment:
[P0] Simulator directory name mismatch will cause linker failures. This creates `ios-arm64-simulator` but `build.rs` expects `ios-arm64_x86_64-simulator`. Change line 172 to: `mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64_x86_64-simulator"`

How can I resolve this? If you propose a fix, please make it concise.


# Copy the simulator library (arm64 only for now)
if [ -n "$IOS_SIM_ARM64_LIB" ] && [ -f "$IOS_SIM_ARM64_LIB" ]; then
cp "$IOS_SIM_ARM64_LIB" "${XCFRAMEWORK_DIR}/ios-arm64-simulator/libonnxruntime.a"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Simulator path mismatch. Change to match expected directory: cp "$IOS_SIM_ARM64_LIB" "${XCFRAMEWORK_DIR}/ios-arm64_x86_64-simulator/libonnxruntime.a"

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/build-ios-onnxruntime.sh
Line: 180:180

Comment:
[P0] Simulator path mismatch. Change to match expected directory: `cp "$IOS_SIM_ARM64_LIB" "${XCFRAMEWORK_DIR}/ios-arm64_x86_64-simulator/libonnxruntime.a"`

How can I resolve this? If you propose a fix, please make it concise.

<key>HeadersPath</key>
<string>Headers</string>
<key>LibraryIdentifier</key>
<string>ios-arm64-simulator</string>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Plist metadata mismatch. Change LibraryIdentifier to: <string>ios-arm64_x86_64-simulator</string> to match actual directory structure.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/build-ios-onnxruntime.sh
Line: 222:222

Comment:
[P0] Plist metadata mismatch. Change LibraryIdentifier to: `<string>ios-arm64_x86_64-simulator</string>` to match actual directory structure.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +225 to +228
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Plist declares both arm64 and x86_64 architectures but script only builds arm64 simulator (line 162 skips simulator). Either build both architectures or update to only list <string>arm64</string>.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/build-ios-onnxruntime.sh
Line: 225:228

Comment:
[P1] Plist declares both arm64 and x86_64 architectures but script only builds arm64 simulator (line 162 skips simulator). Either build both architectures or update to only list `<string>arm64</string>`.

How can I resolve this? If you propose a fix, please make it concise.

echo ""
echo "Static library sizes:"
ls -lh "${XCFRAMEWORK_DIR}/ios-arm64/libonnxruntime.a"
ls -lh "${XCFRAMEWORK_DIR}/ios-arm64-simulator/libonnxruntime.a" 2>/dev/null || echo "No simulator library"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Path mismatch in verification. Update to: ls -lh "${XCFRAMEWORK_DIR}/ios-arm64_x86_64-simulator/libonnxruntime.a"

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/build-ios-onnxruntime.sh
Line: 256:256

Comment:
[P0] Path mismatch in verification. Update to: `ls -lh "${XCFRAMEWORK_DIR}/ios-arm64_x86_64-simulator/libonnxruntime.a"`

How can I resolve this? If you propose a fix, please make it concise.

rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Path mismatch with build script output. The build-ios-onnxruntime.sh creates ios-arm64-simulator but this expects ios-arm64-simulator. If using build script, this should be ios-arm64-simulator (which still needs fixing in build script), or if using setup script, keep as ios-arm64_x86_64-simulator.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 102:102

Comment:
[P0] Path mismatch with build script output. The build-ios-onnxruntime.sh creates `ios-arm64-simulator` but this expects `ios-arm64-simulator`. If using build script, this should be `ios-arm64-simulator` (which still needs fixing in build script), or if using setup script, keep as `ios-arm64_x86_64-simulator`.

How can I resolve this? If you propose a fix, please make it concise.

rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Path mismatch. Same issue as line 102 - verify simulator directory name matches actual build output.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 106:106

Comment:
[P0] Path mismatch. Same issue as line 102 - verify simulator directory name matches actual build output.

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps

greptile-apps Bot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
Additional Comments (2)

.github/workflows/testflight-on-comment.yml
[P0] Path mismatch with build script output. Same issue as mobile-build.yml - simulator directory name inconsistency.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 102:102

Comment:
[P0] Path mismatch with build script output. Same issue as mobile-build.yml - simulator directory name inconsistency.

How can I resolve this? If you propose a fix, please make it concise.

.github/workflows/testflight-on-comment.yml
[P0] Path mismatch. Same issue as line 102.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 106:106

Comment:
[P0] Path mismatch. Same issue as line 102.

How can I resolve this? If you propose a fix, please make it concise.

@AnthonyRonning

Copy link
Copy Markdown
Contributor Author

@TestFlight build

@github-actions

github-actions Bot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor

🚀 TestFlight deployment triggered! Check the Actions tab for progress.

@github-actions

github-actions Bot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor

❌ TestFlight deployment failed. Check the workflow logs for details.

TODO: Remove the push trigger after PR #378 is merged.

This is a workaround because issue_comment workflows run from master,
so they don't pick up workflow changes from the PR branch. We need to
test the full TestFlight flow with the ONNX Runtime changes.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds iOS TTS support by building ONNX Runtime 1.22.2 from source and enabling the TTS module on iOS devices. The implementation mirrors the desktop version with iOS-specific paths (~/Documents/tts_models).

Key Changes:

  • Builds ONNX Runtime from source via build-ios-onnxruntime.sh with caching (90min build)
  • Adds iOS target dependencies in Cargo.toml with correct feature flags (std, ndarray)
  • Enables TTS module compilation and invoke handlers for iOS in lib.rs
  • Frontend updated to enable TTS on iOS platform
  • GitHub Actions workflows extended with ONNX build steps

Critical Issue Found:
The build script creates directory ios-arm64-simulator but build.rs expects ios-arm64_x86_64-simulator, causing simulator builds to fail with missing library errors.

Architecture:
The implementation uses conditional compilation (#[cfg(target_os = "ios")]) throughout to enable TTS on iOS while maintaining desktop functionality. ONNX Runtime is statically linked with all dependencies bundled to avoid runtime linking issues.

Confidence Score: 1/5

  • Not safe to merge - critical path mismatch will cause simulator builds to fail
  • There is a critical directory name mismatch between build.rs (expects ios-arm64_x86_64-simulator) and the build script that creates ios-arm64-simulator. This will cause the linker to fail when building for iOS simulator, as it won't find the ONNX Runtime library at the expected path. Device builds may work, but any simulator testing will fail.
  • frontend/src-tauri/build.rs - Fix simulator directory path mismatch

Important Files Changed

File Analysis

Filename Score Overview
.github/workflows/mobile-build.yml 3/5 Adds ONNX Runtime caching and build-from-source support for iOS TTS. Contains cargo config syntax issue with .onnxruntime suffix that Cargo will ignore.
.github/workflows/testflight-on-comment.yml 3/5 Adds testflight-on-comment workflow with ONNX Runtime build support. Same cargo config syntax issue as mobile-build.yml.
frontend/src-tauri/Cargo.toml 5/5 Adds iOS-specific TTS dependencies with correct feature flags. Clean implementation matching desktop dependencies.
frontend/src-tauri/build.rs 0/5 Adds iOS ONNX Runtime linking configuration. Critical bug: expects ios-arm64_x86_64-simulator directory but build script creates ios-arm64-simulator.
frontend/src-tauri/scripts/build-ios-onnxruntime.sh 4/5 Builds ONNX Runtime from source for iOS with retry logic and dependency bundling. Creates ios-arm64-simulator directory (mismatches build.rs expectations).
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 5/5 Downloads pre-built ONNX Runtime xcframework from HuggingFace (not used in current workflows). Clean implementation.
frontend/src-tauri/src/lib.rs 5/5 Enables TTS module for iOS and adds iOS-specific invoke handlers. Clean conditional compilation with proper setup handlers.
frontend/src-tauri/src/tts.rs 5/5 Adds iOS-specific path handling for TTS models using ~/Documents/tts_models. Clean implementation with proper platform conditionals.
frontend/src/services/tts/TTSContext.tsx 5/5 Enables TTS support for iOS in frontend by updating platform check. Simple, correct change.
frontend/src-tauri/.gitignore 5/5 Adds gitignore entries for ONNX Runtime build artifacts and generated cargo config. Appropriate additions.

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Cache as Cache Storage
    participant Build as Build Script
    participant Cargo as Cargo Build
    participant Tauri as Tauri iOS Build
    participant TF as TestFlight

    Note over GHA,Cache: iOS Build Workflow
    GHA->>Cache: Check ONNX Runtime cache
    alt Cache Hit
        Cache-->>GHA: Restore cached xcframework
    else Cache Miss
        GHA->>Build: Execute build-ios-onnxruntime.sh
        Build->>Build: Clone ONNX Runtime 1.22.2
        Build->>Build: Build for iOS arm64
        Build->>Build: Combine static libraries
        Build->>Build: Create xcframework structure
        Build-->>GHA: ios-arm64-simulator directory
        GHA->>Cache: Save to cache
    end
    
    GHA->>GHA: Configure Cargo with absolute paths
    GHA->>Cargo: Set ORT_LIB_LOCATION env var
    
    Note over Cargo,Tauri: Rust Build Phase
    Tauri->>Cargo: Build Rust code
    Cargo->>Cargo: Process build.rs (iOS config)
    Cargo->>Cargo: Look for ios-arm64_x86_64-simulator
    Cargo->>Cargo: ❌ Directory not found (mismatch)
    
    Note over GHA,TF: Deployment Phase
    Tauri->>Tauri: Build iOS app (if linking succeeds)
    Tauri->>GHA: Generate IPA
    GHA->>TF: Upload to TestFlight
Loading

// Check if building for simulator or device
let target = std::env::var("TARGET").unwrap_or_default();
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Directory name mismatch will cause simulator builds to fail. The build script at line 172 creates ios-arm64-simulator but this code expects ios-arm64_x86_64-simulator. Change to:

Suggested change
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
format!("{}/onnxruntime.xcframework/ios-arm64-simulator", ort_dir)
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 12:12

Comment:
[P0] Directory name mismatch will cause simulator builds to fail. The build script at line 172 creates `ios-arm64-simulator` but this code expects `ios-arm64_x86_64-simulator`. Change to:
```suggestion
            format!("{}/onnxruntime.xcframework/ios-arm64-simulator", ort_dir)
```

How can I resolve this? If you propose a fix, please make it concise.

TODO: Remove the ios-tts condition after PR #378 is merged.

This allows us to test the full TestFlight flow on every PR build
during iOS TTS development.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/testflight-on-comment.yml (1)

230-252: Guard “comment back on PR” steps for push runs (no PR number).
On push, needs.check-comment.outputs.pr-number will be empty, so these steps can fail and turn a successful build into a failed workflow.

Proposed fix
       - name: Comment on PR with success
-        if: success()
+        if: github.event_name == 'issue_comment' && success()
         uses: actions/github-script@v7
@@
       - name: Comment on PR with failure
-        if: failure()
+        if: github.event_name == 'issue_comment' && failure()
         uses: actions/github-script@v7
🤖 Fix all issues with AI agents
In @.github/workflows/testflight-on-comment.yml:
- Around line 19-21: The workflow currently makes the deploy-testflight job
depend on the check-comment job (job id check-comment), so when a push event
skips check-comment the deploy-testflight job will be skipped too; remove the
needs: check-comment dependency or split the workflow into two paths so
deploy-testflight runs on push independently and only the comment-related steps
are gated by check-comment; specifically, ensure deploy-testflight (the job
named deploy-testflight) does not require check-comment, compute
PR_REF/PR_NUMBER inside a step (detecting github.event_name == 'push' vs
'issue_comment'), and conditionally run the comment-posting steps only when the
event is issue_comment (use the check-comment job or an if that references
github.event_name and the presence of the comment).
- Around line 154-175: Remove the "Configure Cargo for iOS ONNX Runtime" step
that generates a .cargo/config.toml with non-standard `[target.*.onnxruntime]`
tables; they are ignored by Cargo. Instead, delete that generation block (or
replace it with a short explanatory comment) and rely on the existing build.rs
logic that emits the `cargo:rustc-link-search` / `cargo:rustc-link-lib`
directives and the ORT_LIB_LOCATION environment variable consumed by the ort
crate to handle linking.

In @frontend/src-tauri/scripts/build-ios-onnxruntime.sh:
- Around line 154-183: The XCFramework currently declares a simulator slice but
never provides a simulator library, causing an invalid xcframework; change the
script to produce a device-only XCFramework by removing creation/usage of the
ios-arm64-simulator slice and related Info.plist entries when IOS_SIM_ARM64_LIB
is empty: stop creating the "${XCFRAMEWORK_DIR}/ios-arm64-simulator" directory,
skip copying or referencing the simulator lib when IOS_SIM_ARM64_LIB is unset,
and ensure the generated Info.plist (the block that mentions
ios-arm64-simulator) only includes the ios-arm64 slice or is conditionally built
when IOS_SIM_ARM64_LIB exists; alternatively, keep the existing conditional copy
but also conditionally build the Info.plist and directory based on
IOS_SIM_ARM64_LIB so the simulator slice is never declared unless a valid
simulator lib is present.
🧹 Nitpick comments (3)
.github/workflows/testflight-on-comment.yml (1)

21-21: Tighten the trigger phrase matching.
contains(..., 'testflight build') will also match unrelated text (“don’t testflight build yet”). Consider exact/anchored matching (trim + startsWith) or a small regex.

frontend/src-tauri/scripts/build-ios-onnxruntime.sh (2)

14-40: Harden bash safety and make header discovery non-fragile.
set -e alone (Line 14) + the find | head | xargs dirname pipeline (Line 186) is brittle when no header is found.

Proposed fix
-set -e
+set -euo pipefail
@@
-HEADER_DIR=$(find build -name "onnxruntime_c_api.h" -type f | head -n 1 | xargs dirname)
-if [ -n "$HEADER_DIR" ]; then
-    cp "${HEADER_DIR}"/*.h "${XCFRAMEWORK_DIR}/Headers/" 2>/dev/null || true
-fi
+HEADER_FILE="$(find build -name "onnxruntime_c_api.h" -type f | head -n 1 || true)"
+if [ -n "${HEADER_FILE}" ]; then
+    HEADER_DIR="$(dirname "${HEADER_FILE}")"
+    cp "${HEADER_DIR}"/*.h "${XCFRAMEWORK_DIR}/Headers/" 2>/dev/null || true
+fi

Also applies to: 186-190


129-144: libtool invocation may hit arg-length limits; also prefer portable grep.
You pass a potentially huge list of .a files directly to libtool (Line 143), and the grep -v "gtest\|gmock" regex is less portable than grep -E on macOS/BSD grep.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7268eb7 and f06513c.

📒 Files selected for processing (3)
  • .github/workflows/mobile-build.yml
  • .github/workflows/testflight-on-comment.yml
  • frontend/src-tauri/scripts/build-ios-onnxruntime.sh
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2026-01-08T17:09:40.432Z
Learnt from: AnthonyRonning
Repo: OpenSecretCloud/Maple PR: 372
File: frontend/src-tauri/Cargo.toml:9-9
Timestamp: 2026-01-08T17:09:40.432Z
Learning: The OpenSecretCloud/Maple repository has comprehensive GitHub Actions workflows (e.g., desktop-build.yml) that automatically validate compilation and testing, so manual compilation verification reminders are unnecessary when reviewing version bumps or dependency updates.

Applied to files:

  • .github/workflows/mobile-build.yml
  • .github/workflows/testflight-on-comment.yml
📚 Learning: 2025-12-08T19:55:33.330Z
Learnt from: CR
Repo: OpenSecretCloud/Maple PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T19:55:33.330Z
Learning: Applies to src-tauri/**/*.rs : Run `just rust-lint` after modifying Rust code to ensure proper formatting, compilation, and linting (runs fmt + clippy strict)

Applied to files:

  • .github/workflows/mobile-build.yml
📚 Learning: 2025-12-08T19:55:33.330Z
Learnt from: CR
Repo: OpenSecretCloud/Maple PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T19:55:33.330Z
Learning: Applies to src-tauri/**/*.rs : Follow standard Rust conventions and rustfmt defaults for code formatting

Applied to files:

  • .github/workflows/mobile-build.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-macos (universal-apple-darwin)
  • GitHub Check: build-linux
  • GitHub Check: build-ios
  • GitHub Check: build-android
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (4)
.github/workflows/mobile-build.yml (2)

149-150: ORT_LIB_LOCATION device-only is consistent with device CI—just ensure no simulator build is attempted.
If any step ever builds a simulator target, it’ll need a real simulator slice (or conditional env/config).


56-112: Remove redundant and ineffective .cargo/config.toml generation—linking is already handled by build.rs.

The workflow generates a .cargo/config.toml with [target.aarch64-apple-ios.onnxruntime] sections, but this approach does not work. Cargo only parses these target-specific package tables when the named crate declares links = "onnxruntime" in its manifest. The ort crate does not; it handles linking via its own build.rs script. The generated config sections are silently ignored by Cargo and have no effect.

The actual linking is already correctly handled by frontend/src-tauri/build.rs, which:

  • Detects the target triple and selects the correct xcframework subdirectory
  • Outputs proper cargo:rustc-link-search and cargo:rustc-link-lib directives
  • Sets ORT_LIB_LOCATION environment variable for the ort crate

Delete the "Configure Cargo for iOS ONNX Runtime" step and rely on the build script instead. If additional per-target overrides are later needed, they should be handled via [target.<triple>] rustflags or by modifying the build script logic, not via unused config sections.

⛔ Skipped due to learnings
Learnt from: AnthonyRonning
Repo: OpenSecretCloud/Maple PR: 372
File: frontend/src-tauri/Cargo.toml:9-9
Timestamp: 2026-01-08T17:09:40.432Z
Learning: The OpenSecretCloud/Maple repository has comprehensive GitHub Actions workflows (e.g., desktop-build.yml) that automatically validate compilation and testing, so manual compilation verification reminders are unnecessary when reviewing version bumps or dependency updates.
.github/workflows/testflight-on-comment.yml (1)

219-229: xcrun altool is still supported in Xcode 16.4 for TestFlight uploads—not removed.

altool deprecation applies to macOS notarization only (use xcrun notarytool for that). For iOS IPA uploads to App Store Connect/TestFlight, xcrun altool --upload-app with API key authentication (as shown) remains functional. Apple recommends alternatives like Transporter or App Store Connect API for new workflows, but the current code will not fail on Xcode 16.4 runners.

frontend/src-tauri/scripts/build-ios-onnxruntime.sh (1)

109-120: Build flags for ONNX Runtime v1.22.2 are supported and documented.
The flags --use_xcode, --ios, --apple_sysroot, --osx_arch, and --cmake_extra_defines are all valid in v1.22.2. The iOS build approach in this script aligns with the official ONNX Runtime documentation. Note: ONNX Runtime v1.22.2 requires iOS SDK >= 15.1.

Comment on lines 19 to +21
check-comment:
if: github.event.issue.pull_request && contains(github.event.comment.body, 'testflight build')
# Only run on issue_comment events, not on push
if: github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, 'testflight build')

ghost Jan 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

deploy-testflight likely won’t run on push due to needs: check-comment being skipped.
On push, check-comment won’t execute (Line 20-21). Jobs that needs a skipped job typically get skipped too, so the temporary push trigger (Line 6-11) may be a no-op.

Proposed fix (split push vs comment paths)
 jobs:
   check-comment:
     # Only run on issue_comment events, not on push
     if: github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, 'testflight build')
     runs-on: ubuntu-latest
@@
   deploy-testflight:
-    needs: check-comment
-    # Run on push to ios-tts branch OR when triggered by comment with approval
-    if: github.event_name == 'push' || needs.check-comment.outputs.should-deploy == 'true'
+    # Run on push to ios-tts branch OR when triggered by comment with approval
+    if: github.event_name == 'push' || needs.check-comment.outputs.should-deploy == 'true'
+    needs: check-comment
     runs-on: macos-latest-xlarge

If this still skips on push in practice, the robust pattern is:

  • keep deploy-testflight without needs
  • compute PR_REF / PR_NUMBER in-step based on event type
  • gate comment-posting steps on issue_comment

Also applies to: 72-75

🤖 Prompt for AI Agents
In @.github/workflows/testflight-on-comment.yml around lines 19 - 21, The
workflow currently makes the deploy-testflight job depend on the check-comment
job (job id check-comment), so when a push event skips check-comment the
deploy-testflight job will be skipped too; remove the needs: check-comment
dependency or split the workflow into two paths so deploy-testflight runs on
push independently and only the comment-related steps are gated by
check-comment; specifically, ensure deploy-testflight (the job named
deploy-testflight) does not require check-comment, compute PR_REF/PR_NUMBER
inside a step (detecting github.event_name == 'push' vs 'issue_comment'), and
conditionally run the comment-posting steps only when the event is issue_comment
(use the check-comment job or an if that references github.event_name and the
presence of the comment).

Comment on lines +154 to +175
- name: Configure Cargo for iOS ONNX Runtime
run: |
# Create cargo config with absolute paths for iOS builds
# This overrides ort-sys's build script to use our built-from-source library
WORKSPACE="${{ github.workspace }}"
mkdir -p "${WORKSPACE}/frontend/src-tauri/.cargo"
cat > "${WORKSPACE}/frontend/src-tauri/.cargo/config.toml" << EOF
# Auto-generated cargo config for iOS ONNX Runtime linking
# Uses absolute paths because xcodebuild may run cargo from different directories

[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
EOF

ghost Jan 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the workflow file and check all similar sections
fd -n "testflight-on-comment.yml" .
wc -l .github/workflows/testflight-on-comment.yml

Repository: OpenSecretCloud/Maple

Length of output: 360


🏁 Script executed:

# Verify whether any repo code parses the custom .cargo/config.toml tables
rg -n "target\.[a-zA-Z0-9_\-]+\.onnxruntime" --hidden
rg -n "rustc-link-search|rustc-link-lib" --hidden
rg -n "ORT_LIB_LOCATION" --hidden

Repository: OpenSecretCloud/Maple

Length of output: 3630


🏁 Script executed:

# Check for any build.rs files that might read cargo config
fd -n "build\.rs" .
# Check for references to .cargo/config or CARGO_HOME
rg -n "\.cargo/config|CARGO_HOME" --hidden -t toml -t rs -t yaml

Repository: OpenSecretCloud/Maple

Length of output: 322


🏁 Script executed:

# Look at lines 216-218 in the workflow to see if similar code exists
sed -n '210,225p' .github/workflows/testflight-on-comment.yml

Repository: OpenSecretCloud/Maple

Length of output: 901


🏁 Script executed:

# Get the full build.rs file to understand the complete linking strategy
cat -n frontend/src-tauri/build.rs

Repository: OpenSecretCloud/Maple

Length of output: 1647


🏁 Script executed:

# Check if there's any documentation about this setup
rg -n "cargo.*config|\.cargo.*config" --hidden -t md

Repository: OpenSecretCloud/Maple

Length of output: 47


🌐 Web query:

Cargo config.toml custom target subtables syntax support

💡 Result:

Short answer: Yes — Cargo's config.toml supports target-specific subtables of the form [target.] (and custom target-spec paths are normalized to a triple name), but the config's conditional [target.'cfg(...)'] form has limits (notably it does not observe crate-level --features when evaluated). References:

  • Official Cargo config docs: target. keys (linker, runner, rustflags, rustdocflags, etc.). [1]
  • cargo-config2 note: custom target-spec files are converted to a triple name so they work with target.. [2]
  • Community discussion showing [target.'cfg(...)'] exists but that user-supplied features (cargo --features) are not available to config-level cfg predicates. [3]

If you want, tell me the exact triple or cfg expression you want to use and I’ll show the exact config.toml snippet.


Remove or replace the non-standard .cargo/config.toml generation—the custom [target.*.onnxruntime] tables are ignored by Cargo.

The generated config file uses non-standard Cargo syntax: custom subtables like [target.aarch64-apple-ios.onnxruntime] with rustc-link-search and rustc-link-lib keys are not recognized by Cargo. (Cargo's config.toml only accepts [target.<triple>] with linker, runner, rustflags, etc.) The actual linking is already handled correctly by build.rs, which emits the proper cargo:rustc-link-search and cargo:rustc-link-lib directives at lines 18–19, and the ORT_LIB_LOCATION environment variable at line 26 is read by the ort crate. The config generation is dead code that should be removed to avoid misleading future maintainers.

Note: The x86_64 simulator path is correct—build.rs line 11 intentionally treats x86_64 as a simulator target, consistent with the config at lines 172–174.

🤖 Prompt for AI Agents
In @.github/workflows/testflight-on-comment.yml around lines 154 - 175, Remove
the "Configure Cargo for iOS ONNX Runtime" step that generates a
.cargo/config.toml with non-standard `[target.*.onnxruntime]` tables; they are
ignored by Cargo. Instead, delete that generation block (or replace it with a
short explanatory comment) and rely on the existing build.rs logic that emits
the `cargo:rustc-link-search` / `cargo:rustc-link-lib` directives and the
ORT_LIB_LOCATION environment variable consumed by the ort crate to handle
linking.

Comment on lines +154 to +183
# SKIP SIMULATOR BUILD for now
# The simulator build has a bug where it tries to link against the wrong iconv library:
# "ld: building for 'iOS-simulator', but linking in dylib built for 'iOS'"
# For TestFlight/App Store deployment, we only need the device build anyway.
# Local development can use the desktop version or a physical device.
echo ""
echo "Skipping iOS simulator build (known ONNX Runtime CMake bug with libiconv)"
echo "Device build is sufficient for TestFlight deployment"
IOS_SIM_ARM64_LIB=""

# Create output directories
echo ""
echo "========================================"
echo "Creating xcframework..."
echo "========================================"

mkdir -p "${OUTPUT_DIR}"
mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64"
mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64-simulator"
mkdir -p "${XCFRAMEWORK_DIR}/Headers"

# Copy the device library
cp "$IOS_ARM64_LIB" "${XCFRAMEWORK_DIR}/ios-arm64/libonnxruntime.a"

# Copy the simulator library (arm64 only for now)
if [ -n "$IOS_SIM_ARM64_LIB" ] && [ -f "$IOS_SIM_ARM64_LIB" ]; then
cp "$IOS_SIM_ARM64_LIB" "${XCFRAMEWORK_DIR}/ios-arm64-simulator/libonnxruntime.a"
else
echo "Warning: No simulator library available"
fi

ghost Jan 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

XCFramework is likely invalid: simulator slice is declared but no simulator library is copied.
You create ios-arm64-simulator and include it in Info.plist (Line 218-233), but you intentionally don’t build/copy a simulator libonnxruntime.a (Line 154-183). This will break any simulator build (and may break some tooling even for device-only workflows).

Proposed fix (device-only xcframework: omit simulator slice entirely)
- mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64-simulator"
  mkdir -p "${XCFRAMEWORK_DIR}/Headers"
@@
- # Copy the simulator library (arm64 only for now)
- if [ -n "$IOS_SIM_ARM64_LIB" ] && [ -f "$IOS_SIM_ARM64_LIB" ]; then
-     cp "$IOS_SIM_ARM64_LIB" "${XCFRAMEWORK_DIR}/ios-arm64-simulator/libonnxruntime.a"
- else
-     echo "Warning: No simulator library available"
- fi
+ echo "No simulator library (device-only build)"
@@
-        <dict>
-            <key>HeadersPath</key>
-            <string>Headers</string>
-            <key>LibraryIdentifier</key>
-            <string>ios-arm64-simulator</string>
-            <key>LibraryPath</key>
-            <string>libonnxruntime.a</string>
-            <key>SupportedArchitectures</key>
-            <array>
-                <string>arm64</string>
-            </array>
-            <key>SupportedPlatform</key>
-            <string>ios</string>
-            <key>SupportedPlatformVariant</key>
-            <string>simulator</string>
-        </dict>

Also applies to: 196-234

🤖 Prompt for AI Agents
In @frontend/src-tauri/scripts/build-ios-onnxruntime.sh around lines 154 - 183,
The XCFramework currently declares a simulator slice but never provides a
simulator library, causing an invalid xcframework; change the script to produce
a device-only XCFramework by removing creation/usage of the ios-arm64-simulator
slice and related Info.plist entries when IOS_SIM_ARM64_LIB is empty: stop
creating the "${XCFRAMEWORK_DIR}/ios-arm64-simulator" directory, skip copying or
referencing the simulator lib when IOS_SIM_ARM64_LIB is unset, and ensure the
generated Info.plist (the block that mentions ios-arm64-simulator) only includes
the ios-arm64 slice or is conditionally built when IOS_SIM_ARM64_LIB exists;
alternatively, keep the existing conditional copy but also conditionally build
the Info.plist and directory based on IOS_SIM_ARM64_LIB so the simulator slice
is never declared unless a valid simulator lib is present.

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds Text-to-Speech support for iOS by building ONNX Runtime 1.22.2 from source and integrating it with the existing Supertonic TTS implementation. The changes enable on-device TTS for iPhones and iPads.

Major Changes:

  • Added CI/CD pipeline to build ONNX Runtime from source with caching (90min build cached for reuse)
  • Extended Rust TTS module to support iOS alongside desktop platforms
  • Updated frontend to detect and enable TTS on iOS devices
  • Added iOS-specific path handling for model storage (~/Documents/tts_models)

Critical Issues Found:

  • Cargo config syntax errors: Invalid [target.<triple>.onnxruntime] sections in both workflows will be ignored by Cargo, potentially causing linking failures
  • Directory name mismatches: build.rs expects ios-arm64_x86_64-simulator but build script creates ios-arm64-simulator, causing simulator builds to fail
  • Workflow logic bug: PR comment steps in testflight-on-comment.yml will fail when triggered by push events (missing pr-number)
  • Unused script: setup-ios-onnxruntime.sh downloads pre-built binaries but is never used

Positive Aspects:

  • Rust code changes are clean and follow existing patterns
  • Proper platform-specific conditionals throughout
  • Good error handling in model download/loading
  • Appropriate dependency configuration (disabled rayon, download-binaries for iOS)

Confidence Score: 2/5

  • This PR has multiple critical bugs that will cause build and deployment failures
  • Score of 2 reflects critical issues in CI/CD configuration: invalid Cargo config syntax will prevent proper linking, directory name mismatches will break simulator builds, and workflow logic errors will cause PR comment failures. These are not edge cases but fundamental bugs that will manifest on every build attempt. The Rust implementation itself is solid (would be 4-5 alone), but the build infrastructure has severe issues.
  • Critical attention needed for .github/workflows/mobile-build.yml, .github/workflows/testflight-on-comment.yml, and frontend/src-tauri/build.rs - all three have bugs that will cause build failures

Important Files Changed

File Analysis

Filename Score Overview
.github/workflows/mobile-build.yml 2/5 Added ONNX Runtime iOS build pipeline with caching, but has critical Cargo config syntax errors and directory name mismatches that will cause build failures
.github/workflows/testflight-on-comment.yml 2/5 Added ONNX Runtime build steps and push trigger for testing, but has same Cargo config errors as mobile-build.yml plus PR comment failures when triggered by push
frontend/src-tauri/Cargo.toml 4/5 Added iOS-specific TTS dependencies with correct feature flags (disabled rayon, download-binaries, copy-dylibs). Clean addition mirroring desktop deps.
frontend/src-tauri/build.rs 2/5 Added iOS ONNX Runtime linking configuration, but simulator directory name (ios-arm64_x86_64-simulator) doesn't match what build script creates (ios-arm64-simulator)
frontend/src-tauri/src/lib.rs 5/5 Added iOS TTS support by extending platform conditionals and adding TTS commands to iOS invoke handler. Clean integration following existing patterns.
frontend/src-tauri/scripts/build-ios-onnxruntime.sh 4/5 Comprehensive script to build ONNX Runtime 1.22.2 from source with retry logic and proper error handling. Skips simulator build due to known CMake bug.

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Build as build-ios-onnxruntime.sh
    participant Cache as Cache Storage
    participant Cargo as Cargo Build
    participant Xcode as Xcode Build
    participant TF as TestFlight

    Note over GHA,TF: iOS TTS Build & Deploy Flow

    GHA->>Cache: Check ONNX Runtime cache
    alt Cache miss
        GHA->>Build: Execute build script
        Build->>Build: Clone ONNX Runtime 1.22.2
        Build->>Build: Build for iOS arm64
        Build->>Build: Combine static libraries
        Build->>Build: Create xcframework structure
        Build->>GHA: Return xcframework
        GHA->>Cache: Store in cache
    else Cache hit
        Cache->>GHA: Restore xcframework
    end

    GHA->>GHA: Generate Cargo config.toml
    Note over GHA: Sets rustc-link-search paths

    GHA->>Cargo: Build Rust library
    Cargo->>Cargo: Link ONNX Runtime static lib
    Cargo->>Cargo: Compile TTS module (iOS enabled)
    Cargo->>Xcode: Provide static library

    GHA->>Xcode: Build iOS app
    Xcode->>Xcode: Link Rust + ONNX Runtime
    Xcode->>Xcode: Create IPA package
    Xcode->>GHA: Return IPA

    alt Deploy condition met
        GHA->>TF: Upload IPA via altool
        TF->>TF: Process for TestFlight
    end
Loading

// Check if building for simulator or device
let target = std::env::var("TARGET").unwrap_or_default();
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directory name mismatch: build-ios-onnxruntime.sh creates ios-arm64-simulator but build.rs expects ios-arm64_x86_64-simulator.

Suggested change
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
format!("{}/onnxruntime.xcframework/ios-arm64-simulator", ort_dir)
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 12:12

Comment:
Directory name mismatch: `build-ios-onnxruntime.sh` creates `ios-arm64-simulator` but `build.rs` expects `ios-arm64_x86_64-simulator`.

```suggestion
            format!("{}/onnxruntime.xcframework/ios-arm64-simulator", ort_dir)
```

How can I resolve this? If you propose a fix, please make it concise.

# Auto-generated cargo config for iOS ONNX Runtime linking
# Uses absolute paths because xcodebuild may run cargo from different directories

[target.aarch64-apple-ios.onnxruntime]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid Cargo config syntax: [target.aarch64-apple-ios.onnxruntime] is not a standard Cargo config section. Cargo only supports [target.<triple>] sections with keys like rustc-link-search and rustc-link-lib. The .onnxruntime suffix will be ignored by Cargo.

Remove .onnxruntime from all three target sections (lines 97, 101, 105).

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 97:97

Comment:
Invalid Cargo config syntax: `[target.aarch64-apple-ios.onnxruntime]` is not a standard Cargo config section. Cargo only supports `[target.<triple>]` sections with keys like `rustc-link-search` and `rustc-link-lib`. The `.onnxruntime` suffix will be ignored by Cargo.

Remove `.onnxruntime` from all three target sections (lines 97, 101, 105).

How can I resolve this? If you propose a fix, please make it concise.

rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directory name mismatch: build-ios-onnxruntime.sh creates ios-arm64-simulator but workflow references ios-arm64-simulator.

Suggested change
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 102:102

Comment:
Directory name mismatch: `build-ios-onnxruntime.sh` creates `ios-arm64-simulator` but workflow references `ios-arm64-simulator`.

```suggestion
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
```

How can I resolve this? If you propose a fix, please make it concise.

rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same directory mismatch as line 102 - should be ios-arm64-simulator not ios-arm64-simulator.

Suggested change
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 106:106

Comment:
Same directory mismatch as line 102 - should be `ios-arm64-simulator` not `ios-arm64-simulator`.

```suggestion
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
```

How can I resolve this? If you propose a fix, please make it concise.

# Auto-generated cargo config for iOS ONNX Runtime linking
# Uses absolute paths because xcodebuild may run cargo from different directories

[target.aarch64-apple-ios.onnxruntime]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same invalid Cargo config syntax as mobile-build.yml - remove .onnxruntime suffix.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 164:164

Comment:
Same invalid Cargo config syntax as mobile-build.yml - remove `.onnxruntime` suffix.

How can I resolve this? If you propose a fix, please make it concise.

rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directory mismatch - should be ios-arm64-simulator.

Suggested change
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 169:169

Comment:
Directory mismatch - should be `ios-arm64-simulator`.

```suggestion
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
```

How can I resolve this? If you propose a fix, please make it concise.

rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directory mismatch - should be ios-arm64-simulator.

Suggested change
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 173:173

Comment:
Directory mismatch - should be `ios-arm64-simulator`.

```suggestion
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
```

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps

ghost commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
Additional Comments (3)

.github/workflows/testflight-on-comment.yml
When workflow runs via push trigger (not comment), needs.check-comment.outputs.pr-number will be empty/undefined, causing this step to fail or create an invalid comment.

Add condition: if: success() && github.event_name == 'issue_comment'

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 230:239

Comment:
When workflow runs via push trigger (not comment), `needs.check-comment.outputs.pr-number` will be empty/undefined, causing this step to fail or create an invalid comment.

Add condition: `if: success() && github.event_name == 'issue_comment'`

How can I resolve this? If you propose a fix, please make it concise.

.github/workflows/testflight-on-comment.yml
Same issue as success case - pr-number will be undefined when running via push trigger.

Add condition: if: failure() && github.event_name == 'issue_comment'

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 242:252

Comment:
Same issue as success case - `pr-number` will be undefined when running via push trigger.

Add condition: `if: failure() && github.event_name == 'issue_comment'`

How can I resolve this? If you propose a fix, please make it concise.

frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
This script is never referenced in the workflows or build process. The workflows use build-ios-onnxruntime.sh instead. Consider removing this dead code or documenting when/why it should be used.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 1:79

Comment:
This script is never referenced in the workflows or build process. The workflows use `build-ios-onnxruntime.sh` instead. Consider removing this dead code or documenting when/why it should be used.

How can I resolve this? If you propose a fix, please make it concise.

iOS WKWebView requires explicit audioContext.resume() call even when
created during a user gesture, as the context may start in suspended state.
This is a no-op on macOS/Linux where the context is already running.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds iOS TTS support using ONNX Runtime. The core implementation is solid—the Rust TTS code, iOS-specific path handling, and frontend integration are well-designed. However, there are critical build configuration issues that will prevent successful compilation:

Critical Issues Found

1. Invalid Cargo Config Syntax (Both Workflows)

The generated .cargo/config.toml uses invalid section names like [target.aarch64-apple-ios.onnxruntime]. Standard Cargo only recognizes [target.<triple>] without custom suffixes. The .onnxruntime suffix will be silently ignored, causing linker flags to not be applied.

2. Directory Name Mismatch

There's a critical inconsistency in simulator directory naming:

  • build-ios-onnxruntime.sh creates: ios-arm64-simulator
  • setup-ios-onnxruntime.sh creates: ios-arm64_x86_64-simulator
  • build.rs expects: ios-arm64_x86_64-simulator
  • Workflows reference: ios-arm64-simulator

This mismatch means builds will fail with "library not found" errors when the cache misses and the build script runs.

3. Missing Conditionals in testflight-on-comment.yml

The PR comment steps (lines 230-252) will fail when the workflow runs via the push trigger because pr-number will be undefined.

What Works Well

  • iOS TTS module integration with proper conditional compilation
  • iOS-specific model storage path using Documents directory
  • Frontend AudioContext.resume() for iOS compatibility
  • Dependency configuration in Cargo.toml
  • Build script retry logic and error handling

Recommendation

These configuration issues must be fixed before merge—they will cause 100% build failure rate when building from source (cache miss).

Confidence Score: 0/5

  • This PR has critical build configuration bugs that will cause guaranteed build failures
  • Score reflects three critical issues that will prevent successful builds: (1) Invalid Cargo config syntax that will be silently ignored causing linker failures, (2) Directory path mismatches between build script output and expected locations, (3) Missing conditionals causing workflow failures. While the core TTS implementation code is solid, the build infrastructure has fundamental issues that must be fixed before this can work.
  • Critical attention needed: .github/workflows/mobile-build.yml, .github/workflows/testflight-on-comment.yml, frontend/src-tauri/build.rs, and frontend/src-tauri/scripts/build-ios-onnxruntime.sh must be fixed to resolve path mismatches and invalid Cargo config syntax

Important Files Changed

File Analysis

Filename Score Overview
.github/workflows/mobile-build.yml 1/5 Critical issues: Invalid Cargo config syntax (.onnxruntime suffix) and simulator path mismatch (ios-arm64-simulator vs ios-arm64_x86_64-simulator) will cause build failures
.github/workflows/testflight-on-comment.yml 1/5 Critical issues: Invalid Cargo config syntax, path mismatch with build script, and missing conditionals for PR comment steps when triggered via push
frontend/src-tauri/build.rs 1/5 Critical path mismatch: expects ios-arm64_x86_64-simulator but build script creates ios-arm64-simulator, will cause linker failures
frontend/src-tauri/scripts/build-ios-onnxruntime.sh 2/5 Creates ios-arm64-simulator directory but other files expect ios-arm64_x86_64-simulator, causing path inconsistency

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant BuildScript as build-ios-onnxruntime.sh
    participant Cache as Actions Cache
    participant CargoConfig as .cargo/config.toml
    participant BuildRS as build.rs
    participant Cargo as Cargo Build
    participant XCode as Xcode Build

    GHA->>Cache: Check for onnxruntime-ios cache
    alt Cache Hit
        Cache-->>GHA: Restore cached xcframework
    else Cache Miss
        GHA->>BuildScript: Execute build script
        BuildScript->>BuildScript: Clone ONNX Runtime repo
        BuildScript->>BuildScript: Build for ios-arm64
        BuildScript->>BuildScript: Create xcframework/ios-arm64-simulator/
        BuildScript-->>GHA: Built xcframework
    end
    
    GHA->>CargoConfig: Generate .cargo/config.toml
    Note over CargoConfig: ❌ Invalid syntax: [target.*.onnxruntime]
    Note over CargoConfig: ❌ Path: ios-arm64-simulator
    
    GHA->>Cargo: Start iOS build
    Cargo->>BuildRS: Execute build.rs
    BuildRS->>BuildRS: Check target (simulator/device)
    Note over BuildRS: ❌ Expects: ios-arm64_x86_64-simulator
    Note over BuildRS: ⚠️ Gets: ios-arm64-simulator
    BuildRS->>Cargo: Set linker paths
    
    Cargo->>XCode: Compile Rust for iOS
    XCode-->>Cargo: ❌ Linker Error: libonnxruntime.a not found
    Cargo-->>GHA: ❌ Build Failed
Loading

// Check if building for simulator or device
let target = std::env::var("TARGET").unwrap_or_default();
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical path mismatch: This code expects ios-arm64_x86_64-simulator but the build script (build-ios-onnxruntime.sh) creates ios-arm64-simulator (line 172). The setup script downloads to ios-arm64_x86_64-simulator which matches this code, but the build script uses a different directory name.

This will cause linker failures when building from source (cache miss) because the library won't be found at the expected path.

Suggested change
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
format!("{}/onnxruntime.xcframework/ios-arm64-simulator", ort_dir)
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 12:12

Comment:
Critical path mismatch: This code expects `ios-arm64_x86_64-simulator` but the build script (`build-ios-onnxruntime.sh`) creates `ios-arm64-simulator` (line 172). The setup script downloads to `ios-arm64_x86_64-simulator` which matches this code, but the build script uses a different directory name.

This will cause linker failures when building from source (cache miss) because the library won't be found at the expected path.

```suggestion
            format!("{}/onnxruntime.xcframework/ios-arm64-simulator", ort_dir)
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +97 to +107
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid Cargo config format: The custom section suffix .onnxruntime (e.g., [target.aarch64-apple-ios.onnxruntime]) is not valid in Cargo's config format. Standard Cargo only recognizes [target.<triple>] sections with keys like rustc-link-search and rustc-link-lib.

The .onnxruntime suffix will be silently ignored by Cargo, meaning these linker flags won't be applied, causing build failures.

Suggested change
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 97:107

Comment:
Invalid Cargo config format: The custom section suffix `.onnxruntime` (e.g., `[target.aarch64-apple-ios.onnxruntime]`) is not valid in Cargo's config format. Standard Cargo only recognizes `[target.<triple>]` sections with keys like `rustc-link-search` and `rustc-link-lib`. 

The `.onnxruntime` suffix will be silently ignored by Cargo, meaning these linker flags won't be applied, causing build failures.

```suggestion
          [target.aarch64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.aarch64-apple-ios-sim]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.x86_64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +101 to +106
[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path mismatch with build script output: These paths reference ios-arm64-simulator, but the build-ios-onnxruntime.sh script creates this directory (line 172), while setup-ios-onnxruntime.sh creates ios-arm64_x86_64-simulator. The build.rs file expects ios-arm64_x86_64-simulator (line 12).

There's an inconsistency:

  • setup script → ios-arm64_x86_64-simulator
  • build script → ios-arm64-simulator
  • build.rs → ios-arm64_x86_64-simulator
  • workflows → ios-arm64-simulator

This will cause build failures depending on which path is used (download vs build from source).

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 101:106

Comment:
Path mismatch with build script output: These paths reference `ios-arm64-simulator`, but the `build-ios-onnxruntime.sh` script creates this directory (line 172), while `setup-ios-onnxruntime.sh` creates `ios-arm64_x86_64-simulator`. The build.rs file expects `ios-arm64_x86_64-simulator` (line 12).

There's an inconsistency:
- setup script → `ios-arm64_x86_64-simulator` 
- build script → `ios-arm64-simulator`
- build.rs → `ios-arm64_x86_64-simulator`
- workflows → `ios-arm64-simulator`

This will cause build failures depending on which path is used (download vs build from source).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +164 to +174
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid Cargo config format: Same issue as mobile-build.yml - the .onnxruntime suffix in section names like [target.aarch64-apple-ios.onnxruntime] is not valid Cargo syntax and will be ignored.

Suggested change
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 164:174

Comment:
Invalid Cargo config format: Same issue as mobile-build.yml - the `.onnxruntime` suffix in section names like `[target.aarch64-apple-ios.onnxruntime]` is not valid Cargo syntax and will be ignored.

```suggestion
          [target.aarch64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.aarch64-apple-ios-sim]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.x86_64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +168 to +173
[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path mismatch with build script: Same directory name inconsistency as in mobile-build.yml. The workflows reference ios-arm64-simulator but build.rs expects ios-arm64_x86_64-simulator.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 168:173

Comment:
Path mismatch with build script: Same directory name inconsistency as in mobile-build.yml. The workflows reference `ios-arm64-simulator` but build.rs expects `ios-arm64_x86_64-simulator`.

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps

ghost commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
Additional Comments (2)

.github/workflows/testflight-on-comment.yml
Missing conditional check: When this workflow runs via the push trigger (line 10-11), needs.check-comment.outputs.pr-number will be undefined/empty, causing this GitHub API call to fail or post to an invalid issue number.

The step should only run when triggered by a comment:

      - name: Comment on PR with success
        if: success() && github.event_name == 'issue_comment'
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: ${{ needs.check-comment.outputs.pr-number }},
              body: '✅ TestFlight deployment completed successfully!'
            });
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 230:240

Comment:
Missing conditional check: When this workflow runs via the `push` trigger (line 10-11), `needs.check-comment.outputs.pr-number` will be undefined/empty, causing this GitHub API call to fail or post to an invalid issue number.

The step should only run when triggered by a comment:

```suggestion
      - name: Comment on PR with success
        if: success() && github.event_name == 'issue_comment'
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: ${{ needs.check-comment.outputs.pr-number }},
              body: '✅ TestFlight deployment completed successfully!'
            });
```

How can I resolve this? If you propose a fix, please make it concise.

.github/workflows/testflight-on-comment.yml
Missing conditional check: Same issue as the success comment - when running via push trigger, pr-number will be undefined.

      - name: Comment on PR with failure
        if: failure() && github.event_name == 'issue_comment'
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: ${{ needs.check-comment.outputs.pr-number }},
              body: '❌ TestFlight deployment failed. Check the [workflow logs](https://github.com/' + context.repo.owner + '/' + context.repo.repo + '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/actions/runs/' + context.runId + ') for details.'
            });
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 242:252

Comment:
Missing conditional check: Same issue as the success comment - when running via push trigger, `pr-number` will be undefined.

```suggestion
      - name: Comment on PR with failure
        if: failure() && github.event_name == 'issue_comment'
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: ${{ needs.check-comment.outputs.pr-number }},
              body: '❌ TestFlight deployment failed. Check the [workflow logs](https://github.com/' + context.repo.owner + '/' + context.repo.repo + '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/actions/runs/' + context.runId + ') for details.'
            });
```

How can I resolve this? If you propose a fix, please make it concise.

The old TTS implementation (PR #235) had UIBackgroundModes with audio
capability which was later removed. iOS requires this capability to
play audio properly in WKWebView.

Also added debug logging and error notifications for TTS playback
to help diagnose issues.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Adds iOS TTS support using ONNX Runtime 1.22.2 built from source, enabling the Supertonic model to run on-device. Introduces GitHub Actions steps to build and cache the xcframework (~90min first build), then links it statically into the iOS app. The frontend enables TTS for iOS with explicit AudioContext.resume() to handle iOS audio restrictions.

Confidence Score: 2/5

  • Moderate risk due to workflow logic errors that will cause failures when triggered via push events
  • The testflight-on-comment workflow has logic errors in PR comment steps that reference undefined outputs when triggered via push (lines 230-252), causing runtime failures. Additionally, both workflows generate invalid Cargo config with .onnxruntime suffixes that Cargo ignores. There's also a potential path mismatch between build.rs expecting ios-arm64_x86_64-simulator while build-ios-onnxruntime.sh creates ios-arm64-simulator.
  • .github/workflows/testflight-on-comment.yml (PR comment steps will fail on push trigger), frontend/src-tauri/build.rs (simulator directory path mismatch)

Important Files Changed

File Analysis

Filename Score Overview
.github/workflows/mobile-build.yml 2/5 Adds ONNX Runtime iOS build with caching; cargo config uses invalid .onnxruntime suffix which Cargo ignores
.github/workflows/testflight-on-comment.yml 2/5 Adds TestFlight deployment with ONNX Runtime support; PR comment steps will fail when triggered via push event
frontend/src-tauri/build.rs 3/5 Adds iOS-specific ONNX Runtime linking configuration; correctly handles device vs simulator paths

Sequence Diagram

sequenceDiagram
    participant GHA as GitHub Actions
    participant Cache as Cache Storage
    participant Build as ONNX Build Script
    participant Cargo as Cargo/Tauri
    participant iOS as iOS App
    participant TTS as TTS Engine

    GHA->>Cache: Check for onnxruntime-ios cache
    alt Cache Hit
        Cache-->>GHA: Return cached xcframework
    else Cache Miss
        GHA->>Build: Run build-ios-onnxruntime.sh
        Build->>Build: Clone ONNX Runtime 1.22.2
        Build->>Build: Build for iOS arm64 (90 min)
        Build->>Build: Combine static libraries
        Build-->>GHA: Create xcframework
        GHA->>Cache: Store xcframework
    end
    
    GHA->>GHA: Generate .cargo/config.toml
    GHA->>Cargo: Set ORT_LIB_LOCATION env var
    Cargo->>Cargo: build.rs links xcframework
    Cargo->>iOS: Build iOS app with TTS
    
    iOS->>TTS: User requests TTS
    TTS->>TTS: Download models (~264MB)
    TTS->>TTS: Load ONNX sessions
    TTS->>TTS: Synthesize audio
    TTS-->>iOS: Return base64 WAV
    iOS->>iOS: AudioContext.resume() for iOS
    iOS->>iOS: Play audio
Loading

Comment on lines +97 to +107
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cargo config sections use invalid custom suffix .onnxruntime which Cargo ignores. The standard format is [target.<triple>] with keys like rustc-link-search and rustc-link-lib. This configuration won't affect the build—the actual linking is handled by build.rs (line 18-19) and the ORT_LIB_LOCATION environment variable (line 150). Consider removing these non-functional config sections or restructuring them to valid Cargo target configuration if they're intended to override ort-sys behavior.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 97:107

Comment:
Cargo config sections use invalid custom suffix `.onnxruntime` which Cargo ignores. The standard format is `[target.<triple>]` with keys like `rustc-link-search` and `rustc-link-lib`. This configuration won't affect the build—the actual linking is handled by `build.rs` (line 18-19) and the `ORT_LIB_LOCATION` environment variable (line 150). Consider removing these non-functional config sections or restructuring them to valid Cargo target configuration if they're intended to override ort-sys behavior.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +164 to +174
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as mobile-build.yml—these cargo config sections with .onnxruntime suffix are non-standard and will be ignored by Cargo.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 164:174

Comment:
Same issue as mobile-build.yml—these cargo config sections with `.onnxruntime` suffix are non-standard and will be ignored by Cargo.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +10 to +15
let target = std::env::var("TARGET").unwrap_or_default();
let lib_path = if target.contains("sim") || target.contains("x86_64") {
format!("{}/onnxruntime.xcframework/ios-arm64_x86_64-simulator", ort_dir)
} else {
format!("{}/onnxruntime.xcframework/ios-arm64", ort_dir)
};

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path logic checks for "sim" or "x86_64" but maps to ios-arm64_x86_64-simulator directory. However, the build script creates ios-arm64-simulator directory (build-ios-onnxruntime.sh:172), causing a mismatch. The setup script (setup-ios-onnxruntime.sh:49) creates ios-arm64_x86_64-simulator matching this code, but the build script differs. Which directory structure is correct—build script creates ios-arm64-simulator while this expects ios-arm64_x86_64-simulator?

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/build.rs
Line: 10:15

Comment:
Path logic checks for "sim" or "x86_64" but maps to `ios-arm64_x86_64-simulator` directory. However, the build script creates `ios-arm64-simulator` directory (build-ios-onnxruntime.sh:172), causing a mismatch. The setup script (setup-ios-onnxruntime.sh:49) creates `ios-arm64_x86_64-simulator` matching this code, but the build script differs. Which directory structure is correct—build script creates ios-arm64-simulator while this expects ios-arm64_x86_64-simulator?

How can I resolve this? If you propose a fix, please make it concise.

ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @frontend/src/components/UnifiedChat.tsx:
- Around line 212-227: The ref update for prevPlaybackError.current is currently
unconditional and can swallow errors; modify the useEffect that watches
lastPlaybackError/currentPlayingId/messageId so that prevPlaybackError.current
is updated only when you actually call showNotification (i.e., move the
assignment inside the if block that checks lastPlaybackError !==
prevPlaybackError.current && currentPlayingId === messageId) so
non-playing-message errors do not override the ref and later identical errors on
the playing message will still trigger the notification; ensure you still
reference showNotification, lastPlaybackError, currentPlayingId and messageId in
the dependency array.
🧹 Nitpick comments (2)
frontend/src/services/tts/TTSContext.tsx (2)

228-287: Consider clearing playback error on successful completion.

The lastPlaybackError state is cleared when starting new playback (line 226) but not when playback completes successfully. This could cause stale errors to be displayed if a component remounts after an error.

♻️ Recommended enhancement

Clear the error in the onended handler:

  source.onended = () => {
    console.log("[TTS] Playback ended");
    if (sourceNodeRef.current !== source) {
      return;
    }
    setIsPlaying(false);
    setCurrentPlayingId(null);
+   setLastPlaybackError(null);

    if (audioUrlRef.current === audioUrl) {
      URL.revokeObjectURL(audioUrlRef.current);
      audioUrlRef.current = null;
    }
    void audioContext.close().catch(() => {
      // Ignore
    });
    audioContextRef.current = null;
    sourceNodeRef.current = null;
  };

228-287: Consider refining debug logging for production.

Extensive console logging has been added throughout the TTS playback flow, which is helpful for debugging iOS issues. For production, consider using a conditional logging framework or making these logs removable in production builds.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2faebdd and 23d36a6.

⛔ Files ignored due to path filters (1)
  • frontend/src-tauri/gen/apple/maple_iOS/Info.plist is excluded by !**/gen/**
📒 Files selected for processing (2)
  • frontend/src/components/UnifiedChat.tsx
  • frontend/src/services/tts/TTSContext.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use path aliases (@/* maps to ./src/*) for imports in TypeScript/React files
Use 2-space indentation, double quotes, and enforce 100-character line limit in TypeScript/React code
Maintain strict TypeScript and avoid using any type
Use PascalCase for component names and camelCase for variables and function names
Use functional components with React hooks instead of class components
Use React context for global state management and TanStack Query for server state management
Run just format, just lint, and just build after making TypeScript/React changes to ensure code quality and compilation

Files:

  • frontend/src/services/tts/TTSContext.tsx
  • frontend/src/components/UnifiedChat.tsx
🧬 Code graph analysis (1)
frontend/src/components/UnifiedChat.tsx (2)
frontend/src/services/tts/TTSContext.tsx (1)
  • useTTS (347-353)
frontend/src/contexts/NotificationContext.tsx (1)
  • useNotification (35-41)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-linux
  • GitHub Check: build-macos (universal-apple-darwin)
  • GitHub Check: build-ios
  • GitHub Check: build-android
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (2)
frontend/src/services/tts/TTSContext.tsx (2)

244-247: LGTM: iOS AudioContext fix is correct.

The explicit await audioContext.resume() is necessary for iOS, where the AudioContext may start in a suspended state even after a user gesture. This is a known iOS Web Audio API issue, and calling resume() is safe on all platforms (no-op if already running).


64-65: The platform detection logic is correct and not redundant. isTauriDesktop() returns true only for desktop platforms (macOS, Windows, Linux), explicitly excluding mobile. The additional (isTauri() && isIOS()) check is necessary to include iOS support in the TTS environment detection.

Comment on lines +212 to +227
// Show notification when playback error occurs for this message
useEffect(() => {
if (
lastPlaybackError &&
lastPlaybackError !== prevPlaybackError.current &&
currentPlayingId === messageId
) {
showNotification({
type: "error",
title: "TTS Playback Failed",
message: lastPlaybackError,
duration: 8000
});
}
prevPlaybackError.current = lastPlaybackError;
}, [lastPlaybackError, currentPlayingId, messageId, showNotification]);

ghost Jan 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix the error notification logic to prevent swallowed errors.

The prevPlaybackError.current is updated unconditionally outside the notification condition. This can cause errors to be silently dropped:

  1. If an error occurs for a non-playing message, the ref updates but no notification shows
  2. If the same error then occurs for the currently playing message, it won't show (not considered "new")
🐛 Proposed fix

Move the ref update inside the conditional block:

  // Show notification when playback error occurs for this message
  useEffect(() => {
    if (
      lastPlaybackError &&
      lastPlaybackError !== prevPlaybackError.current &&
      currentPlayingId === messageId
    ) {
      showNotification({
        type: "error",
        title: "TTS Playback Failed",
        message: lastPlaybackError,
        duration: 8000
      });
+     prevPlaybackError.current = lastPlaybackError;
    }
-   prevPlaybackError.current = lastPlaybackError;
  }, [lastPlaybackError, currentPlayingId, messageId, showNotification]);
🤖 Prompt for AI Agents
In @frontend/src/components/UnifiedChat.tsx around lines 212 - 227, The ref
update for prevPlaybackError.current is currently unconditional and can swallow
errors; modify the useEffect that watches
lastPlaybackError/currentPlayingId/messageId so that prevPlaybackError.current
is updated only when you actually call showNotification (i.e., move the
assignment inside the if block that checks lastPlaybackError !==
prevPlaybackError.current && currentPlayingId === messageId) so
non-playing-message errors do not override the ref and later identical errors on
the playing message will still trigger the notification; ensure you still
reference showNotification, lastPlaybackError, currentPlayingId and messageId in
the dependency array.

@greptile-apps

ghost commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
Additional Comments (2)

.github/workflows/testflight-on-comment.yml
When workflow runs via push trigger (lines 9-11), needs.check-comment.outputs.pr-number will be undefined, causing this API call to fail or post to an invalid issue. The step should only run for comment-triggered events.

      - name: Comment on PR with success
        if: success() && github.event_name == 'issue_comment'
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: ${{ needs.check-comment.outputs.pr-number }},
              body: '✅ TestFlight deployment completed successfully!'
            });
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 230:240

Comment:
When workflow runs via `push` trigger (lines 9-11), `needs.check-comment.outputs.pr-number` will be undefined, causing this API call to fail or post to an invalid issue. The step should only run for comment-triggered events.

```suggestion
      - name: Comment on PR with success
        if: success() && github.event_name == 'issue_comment'
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: ${{ needs.check-comment.outputs.pr-number }},
              body: '✅ TestFlight deployment completed successfully!'
            });
```

How can I resolve this? If you propose a fix, please make it concise.

.github/workflows/testflight-on-comment.yml
Same issue as the success comment step—pr-number will be undefined when triggered via push event, causing this step to fail.

      - name: Comment on PR with failure
        if: failure() && github.event_name == 'issue_comment'
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: ${{ needs.check-comment.outputs.pr-number }},
              body: '❌ TestFlight deployment failed. Check the [workflow logs](https://github.com/' + context.repo.owner + '/' + context.repo.repo + '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/actions/runs/' + context.runId + ') for details.'
            });
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 242:252

Comment:
Same issue as the success comment step—`pr-number` will be undefined when triggered via push event, causing this step to fail.

```suggestion
      - name: Comment on PR with failure
        if: failure() && github.event_name == 'issue_comment'
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: ${{ needs.check-comment.outputs.pr-number }},
              body: '❌ TestFlight deployment failed. Check the [workflow logs](https://github.com/' + context.repo.owner + '/' + context.repo.repo + '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/actions/runs/' + context.runId + ') for details.'
            });
```

How can I resolve this? If you propose a fix, please make it concise.

The old TTS implementation (PR #235) that worked on iOS used HTMLAudioElement
(new Audio()), not Web Audio API. Switching back to this approach as Web Audio
API has known issues with iOS WKWebView.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @frontend/src/services/tts/TTSContext.tsx:
- Around line 168-171: stop() clears audioElementRef.current but doesn't detach
the old audio element's event handlers, so an old element's onended/onerror can
later run and set audioElementRef.current = null, breaking new playback; update
stop() to first capture the current element into a local variable (e.g., const
old = audioElementRef.current), if old exists remove its handlers (old.onended =
null; old.onerror = null), call old.pause(), then set audioElementRef.current =
null; mirror this same detach pattern used in the cleanup effect and ensure
speak() continues to set handlers only on the newly created element.
🧹 Nitpick comments (1)
frontend/src/services/tts/TTSContext.tsx (1)

217-217: Consider reducing console logging in production.

The playback lifecycle has extensive console logging (~8 statements). While helpful for debugging this new iOS TTS feature, consider reducing verbosity or making logs conditional for production builds.

Also applies to: 221-221, 225-225, 235-235, 247-247, 258-260, 263-263

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 23d36a6 and 645d869.

📒 Files selected for processing (1)
  • frontend/src/services/tts/TTSContext.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use path aliases (@/* maps to ./src/*) for imports in TypeScript/React files
Use 2-space indentation, double quotes, and enforce 100-character line limit in TypeScript/React code
Maintain strict TypeScript and avoid using any type
Use PascalCase for component names and camelCase for variables and function names
Use functional components with React hooks instead of class components
Use React context for global state management and TanStack Query for server state management
Run just format, just lint, and just build after making TypeScript/React changes to ensure code quality and compilation

Files:

  • frontend/src/services/tts/TTSContext.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-ios
  • GitHub Check: build-linux
  • GitHub Check: build-macos (universal-apple-darwin)
  • GitHub Check: build-android
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (4)
frontend/src/services/tts/TTSContext.tsx (4)

64-65: LGTM!

The platform detection logic correctly enables TTS on both desktop and iOS platforms, aligning with the PR objectives.


229-233: LGTM!

Switching to HTMLAudioElement is the correct approach for iOS WKWebView compatibility. The comment clearly documents the rationale and references the prior implementation.


52-52: LGTM!

The lastPlaybackError state is properly typed, follows naming conventions, and is correctly integrated into the context.

Also applies to: 75-75, 299-299


10-10: All platform utilities (isTauriDesktop, isIOS, isTauri) are properly exported from @/utils/platform.

Comment on lines +168 to +171
if (audioElementRef.current) {
audioElementRef.current.pause();
audioElementRef.current = null;
}

ghost Jan 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Event handlers from previous playback can interfere with new playback.

When stop() is called, it clears audioElementRef.current but doesn't remove the onended and onerror handlers from the old audio element. If speak() is called again immediately:

  1. stop() clears the ref
  2. A new audio element is created and ref is set to the new element (line 232)
  3. The old audio element's onended handler may fire (lines 234-243)
  4. The handler unconditionally sets audioElementRef.current = null (line 242), breaking the new playback
🔒 Recommended fix: Clear event handlers in stop()
 const stop = useCallback(() => {
   if (audioElementRef.current) {
     audioElementRef.current.pause();
+    audioElementRef.current.onended = null;
+    audioElementRef.current.onerror = null;
     audioElementRef.current = null;
   }
   if (audioUrlRef.current) {
     URL.revokeObjectURL(audioUrlRef.current);
     audioUrlRef.current = null;
   }
   setIsPlaying(false);
   setCurrentPlayingId(null);
 }, []);

Apply the same pattern in the cleanup effect:

   return () => {
     if (unlistenRef.current) {
       unlistenRef.current();
     }
     if (audioElementRef.current) {
       audioElementRef.current.pause();
+      audioElementRef.current.onended = null;
+      audioElementRef.current.onerror = null;
       audioElementRef.current = null;
     }
     if (audioUrlRef.current) {
       URL.revokeObjectURL(audioUrlRef.current);
       audioUrlRef.current = null;
     }
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (audioElementRef.current) {
audioElementRef.current.pause();
audioElementRef.current = null;
}
if (audioElementRef.current) {
audioElementRef.current.pause();
audioElementRef.current.onended = null;
audioElementRef.current.onerror = null;
audioElementRef.current = null;
}
🤖 Prompt for AI Agents
In @frontend/src/services/tts/TTSContext.tsx around lines 168 - 171, stop()
clears audioElementRef.current but doesn't detach the old audio element's event
handlers, so an old element's onended/onerror can later run and set
audioElementRef.current = null, breaking new playback; update stop() to first
capture the current element into a local variable (e.g., const old =
audioElementRef.current), if old exists remove its handlers (old.onended = null;
old.onerror = null), call old.pause(), then set audioElementRef.current = null;
mirror this same detach pattern used in the cleanup effect and ensure speak()
continues to set handlers only on the newly created element.

@greptile-apps

ghost commented Jan 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Overview

Greptile Summary

This PR adds iOS TTS support using ONNX Runtime 1.22.2, building on the existing desktop TTS implementation. The changes enable on-device text-to-speech for iOS using the Supertonic model.

Key Changes

  • Rust Backend: iOS-specific TTS module compilation, path handling for ~/Documents/tts_models, and ONNX Runtime static linking via build.rs
  • Build Infrastructure: Two scripts for ONNX Runtime - build-ios-onnxruntime.sh (builds from source) and setup-ios-onnxruntime.sh (downloads pre-built from HuggingFace)
  • GitHub Actions: Enhanced workflows with ONNX Runtime caching, build-from-source fallback, and generated Cargo config for linking
  • Frontend: iOS platform detection in TTSContext, error notification integration, and HTMLAudioElement playback

Critical Issues Found

1. Directory Name Mismatch (P0 - Build Blocker)

The build script creates ios-arm64-simulator but other components expect ios-arm64_x86_64-simulator:

  • build-ios-onnxruntime.sh line 172 creates wrong directory
  • build.rs expects ios-arm64_x86_64-simulator
  • Workflows generate cargo config with ios-arm64-simulator
    Impact: Simulator builds will fail with linker errors

2. Invalid Cargo Configuration (P0 - Build Blocker)

Both workflows generate Cargo config with invalid syntax:

  • [target.aarch64-apple-ios.onnxruntime] - the .onnxruntime suffix is not valid
  • Cargo will ignore these sections entirely
  • ONNX Runtime linking will fail
    Impact: Builds will fail or fall back to downloading ONNX Runtime

3. Version Mismatch (P1 - Consistency Issue)

setup-ios-onnxruntime.sh defaults to 1.20.1 while everything else uses 1.22.2
Impact: Local development may use wrong version with compatibility issues

Positive Aspects

  • Clean iOS integration following desktop patterns
  • Proper conditional compilation with #[cfg(target_os = "ios")]
  • Good error handling and progress reporting
  • Appropriate use of iOS Documents directory for model storage
  • Background audio capability correctly added to Info.plist

Confidence Score: 1/5

  • This PR has critical build-blocking issues that will prevent iOS builds from succeeding
  • Score of 1 reflects three P0/P1 issues: (1) directory naming mismatch between build script and consumers will cause simulator build failures, (2) invalid Cargo config syntax will break ONNX Runtime linking for all iOS builds, (3) version inconsistency risks compatibility problems. These are not code quality issues but fundamental configuration errors that will prevent successful compilation. The Rust and TypeScript code is well-structured, but the build infrastructure has critical bugs.
  • Critical: frontend/src-tauri/scripts/build-ios-onnxruntime.sh (directory naming), .github/workflows/mobile-build.yml and .github/workflows/testflight-on-comment.yml (invalid Cargo config syntax), frontend/src-tauri/scripts/setup-ios-onnxruntime.sh (version mismatch)

Important Files Changed

File Analysis

Filename Score Overview
frontend/src-tauri/scripts/build-ios-onnxruntime.sh 2/5 Critical directory naming bug: creates ios-arm64-simulator but other components expect ios-arm64_x86_64-simulator, causing build failures
frontend/src-tauri/scripts/setup-ios-onnxruntime.sh 3/5 Version mismatch: defaults to 1.20.1 instead of 1.22.2, could cause compatibility issues
.github/workflows/mobile-build.yml 2/5 Invalid Cargo config syntax (.onnxruntime suffix) and directory naming inconsistency will prevent proper linking
.github/workflows/testflight-on-comment.yml 2/5 Same Cargo config and directory naming issues as mobile-build.yml; also has pr-number undefined issue for push triggers (already noted in previous threads)
frontend/src-tauri/build.rs 4/5 iOS ONNX Runtime linking configuration added; expects ios-arm64_x86_64-simulator directory which conflicts with build script output

Sequence Diagram

sequenceDiagram
    participant User
    participant TTSContext
    participant TauriBackend
    participant ONNX
    participant iOS

    Note over User,iOS: TTS Initialization Flow
    User->>TTSContext: App starts on iOS
    TTSContext->>TauriBackend: checkStatus()
    TauriBackend->>iOS: Check ~/Documents/tts_models
    iOS-->>TauriBackend: Models not found
    TauriBackend-->>TTSContext: status: not_downloaded
    
    User->>TTSContext: Click download TTS models
    TTSContext->>TauriBackend: startDownload()
    TauriBackend->>TauriBackend: Download from HuggingFace
    Note over TauriBackend: Downloads 264MB models
    TauriBackend-->>TTSContext: Progress events
    TauriBackend->>iOS: Save to ~/Documents/tts_models
    TauriBackend->>TauriBackend: tts_load_models()
    TauriBackend->>ONNX: Load ONNX models
    ONNX-->>TauriBackend: Models loaded
    TauriBackend-->>TTSContext: status: ready
    
    Note over User,iOS: TTS Synthesis Flow
    User->>TTSContext: Click speak button
    TTSContext->>TTSContext: Preprocess text (remove code blocks)
    TTSContext->>TauriBackend: tts_synthesize(text)
    TauriBackend->>ONNX: Run inference
    Note over ONNX: duration_predictor → text_encoder<br/>→ vector_estimator → vocoder
    ONNX-->>TauriBackend: Audio waveform
    TauriBackend-->>TTSContext: Base64 WAV audio
    TTSContext->>TTSContext: Create Audio element
    TTSContext->>iOS: Play audio via HTMLAudioElement
    iOS-->>User: Audio playback
Loading

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile


mkdir -p "${OUTPUT_DIR}"
mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64"
mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64-simulator"

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directory name mismatch causing build failure: This script creates ios-arm64-simulator but other components expect ios-arm64_x86_64-simulator.

Impact: When the build script is used (on cache miss), it creates a directory structure incompatible with:

  1. build.rs line 12 which looks for ios-arm64_x86_64-simulator
  2. setup-ios-onnxruntime.sh which creates ios-arm64_x86_64-simulator
  3. The GitHub Actions workflows which reference ios-arm64-simulator in the generated cargo config

This will cause linker errors when building for iOS simulator.

Suggested change
mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64-simulator"
mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64_x86_64-simulator"

Also update line 180, 222, and 256 to use ios-arm64_x86_64-simulator consistently.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/build-ios-onnxruntime.sh
Line: 172:172

Comment:
Directory name mismatch causing build failure: This script creates `ios-arm64-simulator` but other components expect `ios-arm64_x86_64-simulator`.

**Impact**: When the build script is used (on cache miss), it creates a directory structure incompatible with:
1. `build.rs` line 12 which looks for `ios-arm64_x86_64-simulator`
2. `setup-ios-onnxruntime.sh` which creates `ios-arm64_x86_64-simulator`
3. The GitHub Actions workflows which reference `ios-arm64-simulator` in the generated cargo config

This will cause linker errors when building for iOS simulator.

```suggestion
mkdir -p "${XCFRAMEWORK_DIR}/ios-arm64_x86_64-simulator"
```

Also update line 180, 222, and 256 to use `ios-arm64_x86_64-simulator` consistently.

How can I resolve this? If you propose a fix, please make it concise.


SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TAURI_DIR="$(dirname "$SCRIPT_DIR")"
ORT_VERSION="${ORT_VERSION:-1.20.1}"

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version mismatch: This script defaults to ONNX Runtime 1.20.1, but build-ios-onnxruntime.sh defaults to 1.22.2 and the GitHub Actions workflows explicitly use 1.22.2.

Impact: If this script is run locally without specifying a version, it will download 1.20.1 which may be incompatible with the codebase expectations. The build script comment mentions "older versions have Eigen hash mismatch issues with GitLab".

Suggested change
ORT_VERSION="${ORT_VERSION:-1.20.1}"
ORT_VERSION="${ORT_VERSION:-1.22.2}"
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src-tauri/scripts/setup-ios-onnxruntime.sh
Line: 10:10

Comment:
Version mismatch: This script defaults to ONNX Runtime 1.20.1, but `build-ios-onnxruntime.sh` defaults to 1.22.2 and the GitHub Actions workflows explicitly use 1.22.2.

**Impact**: If this script is run locally without specifying a version, it will download 1.20.1 which may be incompatible with the codebase expectations. The build script comment mentions "older versions have Eigen hash mismatch issues with GitLab".

```suggestion
ORT_VERSION="${ORT_VERSION:-1.22.2}"
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +97 to +107
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid Cargo configuration: The .onnxruntime suffix in section names like [target.aarch64-apple-ios.onnxruntime] is not valid Cargo TOML syntax.

Issue: Cargo only recognizes [target.<triple>] sections with keys like rustc-link-search and rustc-link-lib. The .onnxruntime suffix will be ignored, causing the generated config to be ineffective.

Impact: The linking configuration won't be applied, which may cause:

  • Build failures due to missing ONNX Runtime library
  • Falls back to ort-sys attempting to download/build ONNX Runtime itself
Suggested change
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

Note: Also fixed directory name to ios-arm64_x86_64-simulator to match build.rs.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/mobile-build.yml
Line: 97:107

Comment:
Invalid Cargo configuration: The `.onnxruntime` suffix in section names like `[target.aarch64-apple-ios.onnxruntime]` is not valid Cargo TOML syntax.

**Issue**: Cargo only recognizes `[target.<triple>]` sections with keys like `rustc-link-search` and `rustc-link-lib`. The `.onnxruntime` suffix will be ignored, causing the generated config to be ineffective.

**Impact**: The linking configuration won't be applied, which may cause:
- Build failures due to missing ONNX Runtime library
- Falls back to `ort-sys` attempting to download/build ONNX Runtime itself

```suggestion
          [target.aarch64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.aarch64-apple-ios-sim]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.x86_64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
```

Note: Also fixed directory name to `ios-arm64_x86_64-simulator` to match `build.rs`.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +164 to +174
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]

[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]

ghost Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid Cargo configuration: Same .onnxruntime suffix issue as in mobile-build.yml. The section names are invalid and will be ignored by Cargo.

Additionally, the simulator directory path should be ios-arm64_x86_64-simulator to match build.rs expectations.

Suggested change
[target.aarch64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios.onnxruntime]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
rustc-link-lib = ["static=onnxruntime"]
[target.aarch64-apple-ios-sim]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
[target.x86_64-apple-ios]
rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
rustc-link-lib = ["static=onnxruntime"]
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/testflight-on-comment.yml
Line: 164:174

Comment:
Invalid Cargo configuration: Same `.onnxruntime` suffix issue as in mobile-build.yml. The section names are invalid and will be ignored by Cargo.

Additionally, the simulator directory path should be `ios-arm64_x86_64-simulator` to match `build.rs` expectations.

```suggestion
          [target.aarch64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.aarch64-apple-ios-sim]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
          
          [target.x86_64-apple-ios]
          rustc-link-search = ["${WORKSPACE}/frontend/src-tauri/onnxruntime-ios/onnxruntime.xcframework/ios-arm64_x86_64-simulator"]
          rustc-link-lib = ["static=onnxruntime"]
```

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant