Skip to content

chore(0.10.7): bump every demo to leap-sdk 0.10.7 + adopt LMD-only iOS import#48

Open
iamstuffed wants to merge 6 commits into
mainfrom
feat/desktop-examples
Open

chore(0.10.7): bump every demo to leap-sdk 0.10.7 + adopt LMD-only iOS import#48
iamstuffed wants to merge 6 commits into
mainfrom
feat/desktop-examples

Conversation

@iamstuffed
Copy link
Copy Markdown
Contributor

@iamstuffed iamstuffed commented Apr 29, 2026

Summary

Four logical commits, bundled because they ship together. Rebased onto main after the security-hardening PR #49 merged — earlier 41-commit + per-version iteration history flattened.

1. feat: add JVM/Linux/Windows desktop chat-cli demos (907e1d0)

Three new desktop chat REPL CLIs under JVM/, Linux/, Windows/ — REPL chat apps that download the default LFM2.5-350M (Q4_0) bundle on first run, cache it under ./leap_models/, and stream assistant responses to stdout. All three share the same SDK API surface — LeapDownloader().loadModel(modelName, quantizationType, progress)runner.createConversation(systemPrompt)conversation.generateResponse(line).collect { … } — so the demos illustrate the SDK's manifest-resolution flow rather than requiring users to provide a model bundle path.

  • JVM uses ai.liquid.leap:leap-sdk-jvm. The published JAR bundles JNI binaries for Linux x86_64 / aarch64 / macOS / Windows via NativeLibLoader, so one artifact runs on every desktop OS.
  • Linux uses Kotlin/Native (linuxX64) + leap-sdk-linuxx64 and the upstream ai.liquid.leap.nativelibs Gradle plugin to auto-extract the per-target .so set (umbrella + the runtime-dispatched libggml-cpu-{alderlake,…,zen4}.so backends) into build/bin/linuxX64/releaseExecutable/ so the cinterop $ORIGIN rpath finds them at runtime.
  • Windows is the mingwX64 mirror; same plugin auto-extracts the equivalent .dll set.

For Kotlin/Native (Linux + Windows): the leap-sdk's bundled Ktor CIO engine doesn't support TLS on Native, so each demo injects HttpClient(Curl) { install(ContentNegotiation) { json(...) } } into LeapDownloader. The per-target Ktor Curl artifacts statically link libcurl + openssl, so no system libraries are needed at build/run time.

Also adds:

  • .github/workflows/{jvm,linux,windows}-leap-chat-cli-test.yml — three build + smoke-test workflows. Top-level permissions: contents: read, persist-credentials: false on checkout, gradle/actions/setup-gradle@50e97c2c # v6.1.0 (SHA-pinned), and a Sonatype-snapshot regex whitelist on the cache-purge step. Concurrency group keyed by workflow + ref so a fast-following push cancels the in-flight run.
  • scripts/refresh-spm-if-needed.sh — local script for iOS/macOS demos: detects when the upstream leap-sdk SPM tag has been force-pushed (compares local Package.resolved revisions against git ls-remote) and clears the relevant SPM caches + Package.resolved files. Idempotent.
  • Root README.md adds JVM, Linux, Windows sections and Quick Start entries for each platform.

2. ci: add concurrency guard + snapshot purge to android workflow (70a3afc)

Bring android-leap-chat-test.yml up to parity with the desktop CLI workflows:

  • Concurrency group keyed by workflow + ref.
  • Snapshot-purge step that compares Sonatype's <lastUpdated> against a marker in ~/.gradle/caches/leap-snapshot-marker and only wipes the cache when a SNAPSHOT pin was force-republished. Whitelists the parsed SDK_VERSION shape before interpolating into the curl URL. No-op now that we're on stable.
  • --refresh-dependencies on the gradle invocations so Gradle's metadata TTL doesn't mask a republished snapshot.

3. chore(0.10.6): bump every existing demo to leap-sdk 0.10.6, swap to LFM2.5-350M, and adopt the LMD-only iOS import (b7492ab)

Tracks ai.liquid.leap:leap-sdk:0.10.6 on Maven Central + SPM v0.10.6 on the leap-sdk release (both live as of 2026-05-12).

Android (eight demos):

  • bump leapSdk = "0.10.6" across all gradle/libs.versions.toml
  • drop the Sonatype Central Portal Snapshots maven block from every settings.gradle.kts — stable releases live on Maven Central proper
  • switch the demo model from LFM2-350M (Q8_0) to LFM2.5-350M (Q4_0) — smaller (~250 MB vs 370 MB), faster cold start, exercises 0.10.6's CPU-dispatched llamacpp backend that picks the right libggml-cpu-<arch> for the runner's CPU. Updates the corresponding MainActivity / ViewModel model-id strings.

iOS (six demos):

  • pin SPM revision: v0.10.6 in every project.yml
  • switch the five demos that use the downloader path (LeapChat, LeapAudio, LeapSlogan, LeapVLM, RecipeGenerator) from import LeapSDK to import LeapModelDownloader. In 0.10.6 the LMD K/N framework re-exports every leap-sdk Kotlin type via its ObjC binding + SKIE-bundled Swift overlay, so one import covers both the download surface and the SDK types those demos use.
  • swap each of those demos' OTHER_LDFLAGS / LD_RUNPATH_SEARCH_PATHS / Sign nested *.dylib post-build scripts from LeapSDK.framework/Frameworks to LeapModelDownloader.framework/Frameworks and add -lie_zip for the download path.
  • LeapVoiceAssistantDemo stays on the LeapUI SPM product — LeapUI doesn't export(project(":leap-sdk")) in its K/N framework binary, so dual-importing LeapSDK + LeapUi here is unambiguous. Top-of-file comment in its project.yml documents the asymmetry.
  • adopt the renamed LeapDownloader.loadModel(modelName:, quantizationType:, …) kwargs (was model: / quantization:).
  • swap demo model to LFM2.5-350M (Q4_0), same rationale as Android.

macOS / Web:

  • macOS/LeapVoiceAssistantDemo/project.yml, macOS/LeapVLMExample/project.yml — SPM revision: v0.10.6.
  • Web/LeapVoiceAssistantDemo/gradle/libs.versions.tomlleapSdk = "0.10.6".
  • (JVM/Linux/Windows CLIs are introduced at 0.10.6 directly in commit 1.)

Local-test apparatus (new):

  • scripts/use-local-sdk.sh rewrites each iOS demo's pbxproj from the remote https://github.com/Liquid4All/leap-sdk SPM ref to an XCLocalSwiftPackageReference pointing at a leap-android-sdk worktree. Run after xcodegen generate (which would otherwise overwrite the local ref each time). Idempotent.
  • iOS/LOCAL_TESTING.md documents the workflow end-to-end (build XCFrameworks → link symlinks → run the rewrite script) for contributors iterating on unpublished SDK changes.

Docs:

  • iOS/README.md + Android/RecipeGenerator/README.md updated for the new release URL + model name.

4. chore(0.10.7): bump every demo to leap-sdk 0.10.7 (d62ba60)

Tracks ai.liquid.leap:leap-sdk:0.10.7 on Maven Central + SPM v0.10.7 on the leap-sdk release. Source: leap-android-sdk 98a7c462, PR #256.

0.10.7 is a Kotlin/JVM ergonomics + KMP target-completion release with zero Swift surface change vs 0.10.6 — the four Apple XCFrameworks (LeapSDK, LeapModelDownloader, LeapOpenAIClient, LeapUi) ship the same SKIE Swift APIs. No demo source changes required.

Upstream changes that motivate the pin (none affect demo code paths):

  • leap-openai-client now publishes jvm (Ktor CIO) + wasmJs (Ktor JS) slices on top of the prior android/apple/linux/mingw — not consumed by any of these demos, but available for future apps.
  • Repo-wide KMP target configuration centralized into root subprojects {} (jvmTarget=11 + wasmJs karma headless-Chrome). Internal cleanup.
  • Bytecode hardening. leap-sdk-jvm, leap-openai-client-jvm, leap-ui-jvm, and leap-ui-android now consistently emit Java 11 class-file major (0x37) instead of silently shipping Java 17 / 21. Strictly more compatible than 0.10.6 — demos targeting JVM 21 still consume cleanly.

Single TOML var (leapSdk) covers leap-sdk, leap-model-downloader, and leap-ui modules across all Android demos. 22 files touched (12 gradle/libs.versions.toml + 8 iOS/macOS project.yml + iOS/README.md + Android/RecipeGenerator/README.md), plus .gitignore to drop *.gguf + leap_models/ (model bundle cache created by the JVM/Linux/Windows demos at run time).

Verified locally on macOS host: compileKotlin (JVM), compileKotlinLinuxX64 (Linux K/N cross-compile), and :app:compileReleaseKotlin (Android LeapChat) all BUILD SUCCESSFUL against leap-sdk:0.10.7. JVM installDist + printf ':quit\n' | leap-chat-cli end-to-end SUCCESS — ready (model id: LFM2.5-350M-Q4_0) and exit 0.

Test plan

  • All 0.10.6 references replaced with 0.10.7 across gradle/libs.versions.toml, project.yml, and READMEs (grep -r "0\.10\.6" returns empty).
  • JVM / Linux K/N (cross from macOS) / Android Kotlin compilations all clean against leap-sdk:0.10.7.
  • JVM end-to-end smoke (installDist + :quit) prints ready (model id: LFM2.5-350M-Q4_0) and exits 0.
  • iOS/macOS pin bump applies to project.yml only (no Xcode CI in this repo); manual Xcode resolve required.
  • Manual end-to-end on a Windows host with MinGW runtime DLLs available (out of scope for the demo's redistributable bundling — JVM demo is the portable equivalent for Windows users today).

Copilot AI review requested due to automatic review settings April 29, 2026 13:02
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds three new desktop chat CLI examples (JVM, Linux, Windows) that load a local LeapSDK .bundle and stream assistant responses in a simple REPL, plus links from the root README so they’re discoverable alongside existing demos.

Changes:

  • Introduce JVM/LeapChatCli (Kotlin/JVM + Gradle Application) using LeapSDK 0.10.1.
  • Introduce Linux/LeapChatCli and Windows/LeapChatCli (Kotlin/Native linuxX64 / mingwX64) using the ai.liquid.leap.nativelibs Gradle plugin to extract native inference libs next to the produced binary.
  • Update root README.md to document the new desktop examples and quick-start commands.

Reviewed changes

Copilot reviewed 31 out of 34 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
README.md Adds JVM/Linux/Windows example sections + quick start commands and updates LeapSDK positioning to include desktop platforms.
JVM/LeapChatCli/src/main/kotlin/ai/liquid/leap/cli/Main.kt Implements JVM REPL that flushes stdout for true token streaming and prints stats.
JVM/LeapChatCli/build.gradle.kts Sets up Kotlin/JVM app packaging and main class entry.
JVM/LeapChatCli/settings.gradle.kts + wrapper/catalog files Standalone Gradle project setup for the JVM CLI.
Linux/LeapChatCli/src/linuxX64Main/kotlin/ai/liquid/leap/cli/Main.kt Implements Linux Kotlin/Native REPL (streaming + stats).
Linux/LeapChatCli/build.gradle.kts Configures Kotlin/Native linuxX64 executable and Leap native-libs plugin wiring.
Linux/LeapChatCli/README.md Documents Linux build/run steps and how native libs are provided.
Linux/LeapChatCli/settings.gradle.kts + wrapper/catalog files Standalone Gradle project setup for the Linux CLI.
Windows/LeapChatCli/src/mingwX64Main/kotlin/ai/liquid/leap/cli/Main.kt Implements Windows Kotlin/Native REPL (streaming + stats).
Windows/LeapChatCli/build.gradle.kts Configures Kotlin/Native mingwX64 executable and Leap native-libs plugin wiring.
Windows/LeapChatCli/README.md Documents Windows build/run steps and how native libs are provided.
Windows/LeapChatCli/settings.gradle.kts + wrapper/catalog files Standalone Gradle project setup for the Windows CLI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +51 to +58
conversation.generateResponse(line).collect { response ->
when (response) {
is MessageResponse.Chunk -> print(response.text)
is MessageResponse.Complete -> {
println()
response.stats?.let { stats ->
println("[${stats.completionTokens} tok, ${stats.tokenPerSecond} tok/s]")
}
Comment thread Linux/LeapChatCli/README.md Outdated
## Build

```bash
JAVA_HOME="$(/usr/libexec/java_home -v 21)" ./gradlew linkReleaseExecutableLinuxX64
Comment thread Windows/LeapChatCli/README.md Outdated
Comment on lines +9 to +17
- Windows x86_64 host (Windows 10/11 tested; or build via WSL2 / Linux host
with mingw cross-toolchain)
- JDK 21 to run Gradle (Zulu recommended)
- A LeapSDK model bundle on local disk (e.g. `LFM2-1.2B-Q4_0.bundle`)

> **Note on cross-compile**: Kotlin/Native can compile `mingwX64` Kotlin code
> from any host (verified on macOS), but cross-linking the final `.exe`
> against `inference_engine.dll` from non-Windows hosts isn't supported by
> Kotlin/Native. Build + run from Windows.
Comment on lines +51 to +58
conversation.generateResponse(line).collect { response ->
when (response) {
is MessageResponse.Chunk -> print(response.text)
is MessageResponse.Complete -> {
println()
response.stats?.let { stats ->
println("[${stats.completionTokens} tok, ${stats.tokenPerSecond} tok/s]")
}
iamstuffed added a commit that referenced this pull request Apr 29, 2026
- Linux + Windows Main.kt: flush stdout after every Chunk and after the
  prompt. Kotlin/Native print()/println() route through stdio which is
  fully buffered when stdout is not a TTY (and only line-buffered when
  it is) — without an explicit flush the streaming chunks would appear
  in one burst on Complete, defeating the REPL. Use fflush(NULL) which
  flushes all open output streams per POSIX, avoiding per-target stdout
  symbol lookup. File-level @OptIn(ExperimentalForeignApi::class)
  required for the cinterop fflush(null) call.

- Linux README: replaced /usr/libexec/java_home (a macOS-only command)
  in the build instructions with a Linux-native JAVA_HOME example
  pointing at /usr/lib/jvm/java-21-openjdk-amd64 and a SDKMAN
  alternative.

- Windows README: removed the conflicting "build via WSL2 / Linux host
  with mingw cross-toolchain" prerequisite. Kotlin/Native cross-link
  from non-Windows isn't supported (already noted in the cross-compile
  callout); WSL2 is Linux under the hood and hits the same limitation.
  Reworded the callout to make this explicit.

Both Native targets recompile cleanly with the changes.
@iamstuffed iamstuffed force-pushed the feat/desktop-examples branch from 42e4bbf to 3e17d55 Compare April 29, 2026 16:58
iamstuffed added a commit that referenced this pull request Apr 29, 2026
- Linux + Windows Main.kt: flush stdout after every Chunk and after the
  prompt. Kotlin/Native print()/println() route through stdio which is
  fully buffered when stdout is not a TTY (and only line-buffered when
  it is) — without an explicit flush the streaming chunks would appear
  in one burst on Complete, defeating the REPL. Use fflush(NULL) which
  flushes all open output streams per POSIX, avoiding per-target stdout
  symbol lookup. File-level @OptIn(ExperimentalForeignApi::class)
  required for the cinterop fflush(null) call.

- Linux README: replaced /usr/libexec/java_home (a macOS-only command)
  in the build instructions with a Linux-native JAVA_HOME example
  pointing at /usr/lib/jvm/java-21-openjdk-amd64 and a SDKMAN
  alternative.

- Windows README: removed the conflicting "build via WSL2 / Linux host
  with mingw cross-toolchain" prerequisite. Kotlin/Native cross-link
  from non-Windows isn't supported (already noted in the cross-compile
  callout); WSL2 is Linux under the hood and hits the same limitation.
  Reworded the callout to make this explicit.

Both Native targets recompile cleanly with the changes.
@iamstuffed iamstuffed changed the base branch from refactor/reorg-platform-dirs to main April 29, 2026 16:58
@iamstuffed iamstuffed changed the title feat: add JVM/Linux/Windows desktop chat CLI examples feat: JVM/Linux/Windows desktop chat CLIs + bump all examples to 0.10.4.1 May 7, 2026
@iamstuffed iamstuffed changed the title feat: JVM/Linux/Windows desktop chat CLIs + bump all examples to 0.10.4.1 feat: JVM/Linux/Windows desktop chat CLIs + KV cache + bump to 0.10.4.4 May 7, 2026
@iamstuffed iamstuffed changed the title feat: JVM/Linux/Windows desktop chat CLIs + KV cache + bump to 0.10.4.4 feat: JVM/Linux/Windows desktop chat CLIs + KV cache + bump to 0.10.4.5 May 8, 2026
iamstuffed added a commit that referenced this pull request May 8, 2026
Address PR #49 review. Copilot reviewer flagged that setup-java's
cache: 'gradle' uses the Actions cache API and the "no GitHub API
access needed" comment was imprecise. Empirically the cache works
under contents: read (cache save succeeded on the prior run), but
gradle/actions/setup-gradle is the proper modern path — matches the
desktop-examples worktree (PR #48) and cleanly separates JDK setup
from build-cache wiring.

- Drop `cache: 'gradle'` from actions/setup-java.
- Add gradle/actions@50e97c2
  (v6.1.0, SHA-pinned).
- Refine the permissions-block comment: the Actions cache is gated by
  the ACTIONS_RUNTIME_TOKEN, not GITHUB_TOKEN, so contents: read is
  sufficient.
@iamstuffed iamstuffed force-pushed the feat/desktop-examples branch from c618176 to 037ddd4 Compare May 8, 2026 20:43
@iamstuffed iamstuffed changed the title feat: JVM/Linux/Windows desktop chat CLIs + KV cache + bump to 0.10.4.5 feat: JVM/Linux/Windows desktop chat-cli demos at leap-sdk 0.10.4.5 May 8, 2026
@iamstuffed iamstuffed changed the title feat: JVM/Linux/Windows desktop chat-cli demos at leap-sdk 0.10.4.5 chore(0.10.6): bump every demo to leap-sdk 0.10.6 + adopt LMD-only iOS import May 12, 2026
Three new desktop chat REPL CLIs under `JVM/`, `Linux/`, `Windows/` — REPL chat apps that download the default `LFM2.5-350M` (Q4_0) bundle on first run, cache it under `./leap_models/`, and stream assistant responses to stdout. All three share the same SDK API surface — `LeapDownloader().loadModel(modelName, quantizationType, progress)` → `runner.createConversation(systemPrompt)` → `conversation.generateResponse(line).collect { … }` — so the demos illustrate the SDK's manifest-resolution flow rather than requiring users to provide a model bundle path.

- **JVM** uses `ai.liquid.leap:leap-sdk-jvm`. The published JAR bundles JNI binaries for Linux x86_64 / aarch64 / macOS / Windows via `NativeLibLoader`, so one artifact runs on every desktop OS.
- **Linux** uses Kotlin/Native (`linuxX64`) + `leap-sdk-linuxx64` and the upstream `ai.liquid.leap.nativelibs` Gradle plugin to auto-extract the per-target `.so` set (umbrella + the runtime-dispatched `libggml-cpu-{alderlake,…,zen4}.so` backends) into `build/bin/linuxX64/releaseExecutable/` so the cinterop `\$ORIGIN` rpath finds them at runtime.
- **Windows** is the `mingwX64` mirror; same plugin auto-extracts the equivalent `.dll` set.

For Kotlin/Native (Linux + Windows): the leap-sdk's bundled Ktor CIO engine doesn't support TLS on Native, so each demo injects `HttpClient(Curl) { install(ContentNegotiation) { json(...) } }` into `LeapDownloader`. The per-target Ktor Curl artifacts statically link libcurl + openssl, so no system libraries are needed at build/run time.

Also adds:

- `.github/workflows/{jvm,linux,windows}-leap-chat-cli-test.yml` — three build + smoke-test workflows. Top-level `permissions: contents: read`, `persist-credentials: false` on checkout, `gradle/actions/setup-gradle@50e97c2c # v6.1.0` (SHA-pinned), and a Sonatype-snapshot regex whitelist on the cache-purge step. Concurrency group keyed by `workflow + ref` so a fast-following push cancels the in-flight run.
- `scripts/refresh-spm-if-needed.sh` — local script for iOS/macOS demos: detects when the upstream `leap-sdk` SPM tag has been force-pushed (compares local `Package.resolved` revisions against `git ls-remote`) and clears the relevant SPM caches + `Package.resolved` files. Idempotent.
- Root `README.md` adds JVM, Linux, Windows sections and Quick Start entries for each platform.
Bring `android-leap-chat-test.yml` up to parity with the desktop CLI workflows:

- Concurrency group keyed by workflow + ref.
- Snapshot-purge step that compares Sonatype's `<lastUpdated>` against a marker in `~/.gradle/caches/leap-snapshot-marker` and only wipes the cache when a SNAPSHOT pin was force-republished. Whitelists the parsed `SDK_VERSION` shape before interpolating into the `curl` URL. No-op now that we're on stable.
- `--refresh-dependencies` on the `gradle` invocations so Gradle's metadata TTL doesn't mask a republished snapshot.
…FM2.5-350M, and adopt the LMD-only iOS import

Tracks `ai.liquid.leap:leap-sdk:0.10.6` on Maven Central + SPM `v0.10.6` on the leap-sdk release (both live as of 2026-05-12).

Android (eight demos):
- bump `leapSdk = "0.10.6"` across all `gradle/libs.versions.toml`
- drop the Sonatype Central Portal Snapshots maven block from every `settings.gradle.kts` — stable releases live on Maven Central proper
- switch the demo model from `LFM2-350M (Q8_0)` to `LFM2.5-350M (Q4_0)` — smaller (~250 MB vs 370 MB), faster cold start, exercises 0.10.6's CPU-dispatched llamacpp backend that picks the right `libggml-cpu-<arch>` for the runner's CPU. Updates the corresponding `MainActivity` / `ViewModel` model-id strings

iOS (six demos):
- pin SPM `revision: v0.10.6` in every `project.yml`
- switch the five demos that use the downloader path (LeapChat, LeapAudio, LeapSlogan, LeapVLM, RecipeGenerator) from `import LeapSDK` to `import LeapModelDownloader`. In 0.10.6 the LMD K/N framework re-exports every leap-sdk Kotlin type via its ObjC binding + SKIE-bundled Swift overlay, so one import covers both the download surface and the SDK types those demos use
- swap each of those demos' `OTHER_LDFLAGS` / `LD_RUNPATH_SEARCH_PATHS` / `Sign nested *.dylib` post-build scripts from `LeapSDK.framework/Frameworks` to `LeapModelDownloader.framework/Frameworks` and add `-lie_zip` for the download path
- `LeapVoiceAssistantDemo` stays on the `LeapUI` SPM product — `LeapUI` doesn't `export(project(":leap-sdk"))` in its K/N framework binary, so dual-importing `LeapSDK` + `LeapUi` here is unambiguous. Top-of-file comment in its `project.yml` documents the asymmetry
- adopt the renamed `LeapDownloader.loadModel(modelName:, quantizationType:, …)` kwargs (was `model:` / `quantization:`)
- swap demo model to `LFM2.5-350M` (Q4_0), same rationale as Android

macOS / Web / desktop CLIs:
- `macOS/LeapVoiceAssistantDemo/project.yml`, `macOS/LeapVLMExample/project.yml` — SPM `revision: v0.10.6`
- `Web/LeapVoiceAssistantDemo/gradle/libs.versions.toml` — `leapSdk = "0.10.6"`
- (JVM/Linux/Windows CLIs are introduced at 0.10.6 directly in the previous feat commit)

Local-test apparatus (new):
- `scripts/use-local-sdk.sh` rewrites each iOS demo's pbxproj from the remote `https://github.com/Liquid4All/leap-sdk` SPM ref to an `XCLocalSwiftPackageReference` pointing at a leap-android-sdk worktree. Run after `xcodegen generate` (which would otherwise overwrite the local ref each time). Idempotent
- `iOS/LOCAL_TESTING.md` documents the workflow end-to-end (build XCFrameworks → link symlinks → run the rewrite script) for contributors iterating on unpublished SDK changes

Docs:
- `iOS/README.md` + `Android/RecipeGenerator/README.md` updated for the new release URL + model name
@iamstuffed iamstuffed force-pushed the feat/desktop-examples branch from bce4b0b to b7492ab Compare May 12, 2026 23:52
0.10.7 is a Kotlin/JVM ergonomics + KMP target-completion release with
zero Swift surface change vs 0.10.6 (leap-android-sdk PR #256). All
Apple XCFrameworks ship the same SKIE Swift APIs as 0.10.6.

Changes upstream that motivate the pin (none require demo source edits):
- leap-openai-client now publishes jvm (Ktor CIO) + wasmJs (Ktor JS)
  slices on top of android/apple/linux/mingw. Not consumed here.
- Repo-wide KMP target config centralized into root subprojects {} block.
- Bytecode hardening: leap-sdk-jvm, leap-openai-client-jvm, leap-ui-jvm,
  and leap-ui-android now consistently emit Java 11 class-file major
  (0x37). Strictly more compatible than 0.10.6's silent 17/21 bytecode.

Single TOML var (leapSdk) covers leap-sdk + leap-model-downloader +
leap-ui modules across all Android demos. 22 files touched:
- 12 gradle/libs.versions.toml (Android x8 + JVM + Linux + Windows + Web)
- 8 iOS/macOS project.yml (revision pin)
- iOS/README.md (9 doc refs incl. release URL)
- Android/RecipeGenerator/README.md (1 doc ref)

Verified locally on macOS host: compileKotlin (JVM), compileKotlinLinuxX64
(Linux K/N cross), and :app:compileReleaseKotlin (Android LeapChat) all
BUILD SUCCESSFUL against leap-sdk:0.10.7. JVM end-to-end smoke prints
"ready (model id: LFM2.5-350M-Q4_0)" and exits 0 on ':quit'.
@iamstuffed iamstuffed changed the title chore(0.10.6): bump every demo to leap-sdk 0.10.6 + adopt LMD-only iOS import chore(0.10.7): bump every demo to leap-sdk 0.10.7 + adopt LMD-only iOS import May 18, 2026
…eep critical-review fixes

Bumps every demo SDK pin from 0.10.7 → 0.10.8 (12 gradle/libs.versions.toml,
8 iOS/macOS project.yml) and Kotlin 2.3.20 → 2.3.21. 0.10.8 ships the SKIE
coverage fix from leap-android-sdk PR #258: SKIE applied to leap-sdk-openai-client
and a new in-band MessageResponse.Error sealed case emitted before the flow
closes — required because SKIE's FlowInterop bridges Flow<T> as
SkieSwiftFlow<T> with Failure = Never, so Swift for-await otherwise loses the
close-throwable silently.

Critical-review fix sweep across the 119-file change set:

Correctness:
- Handle MessageResponse.Error in every Kotlin collector (8 Android + 3 desktop
  CLIs + Web). Existing-handler demos rethrow to route through .catch{}/try/
  catch/runCatching{}.onFailure{}; CLIs add .catch{} that prints and continues
  the REPL; VLMExample/LeapChat add user-visible error UI.
- Handle .error case in every Swift collector (5 iOS + 1 macOS Store + 2
  AppleVoiceConversation). RecipeGenerator/SloganExample accumulate into
  streamError and throw NSError post-loop; cast-style sites throw NSError
  inline. Dead handleGenerationError(_:) removed from AudioDemoStore.
- LeapKoogAgent: replaced const val modelsPath = "/tmp/models" (unwritable on
  Android, runtime crash) with App.context.filesDir.resolve("models").

CI:
- .github/workflows/ios-demos-test.yml + macos-demos-test.yml: runs-on macos-15
  → macos-26 (the if -d /Applications/Xcode_26.app fallback was silently
  no-op'ing on macos-15). Dropped EXCLUDED_ARCHS=x86_64; pinned iOS destination
  to platform=iOS Simulator,name=iPhone 16 (matches make build).
- Added 4 new workflows: android-demos-test.yml, ios-demos-test.yml,
  macos-demos-test.yml, web-demo-test.yml — matrix-build every demo on the
  right runner, gated by per-path triggers, with concurrency guards.

Bugs:
- Float.toFixed1() in Linux/Windows/Web Main.kt truncated instead of rounding
  (9.95f → "9.9"). Replaced with kotlin.math.round(this * 10).toLong().
- Android LeapVoiceAssistantDemo: onCleared used viewModelScope which is
  cancelled by the time onCleared runs; added @volatile modelRunner captured
  at load time + fresh CoroutineScope(Dispatchers.IO) unload. Manifest had
  POST_NOTIFICATIONS but no runtime request; added Compose runtime ask gated
  by SDK 33+.
- iOS LeapVLMExample VLMStore: dropped self-defeating
  `await generationTask?.value` that serialized the function with the task it
  just spawned.
- macOS LeapVLMExample VLMStore: added generationTask field + stop() + deinit
  cancel for parity with iOS.

Modernization:
- iOS LeapVoiceAssistantDemo DemoViewModel: ObservableObject + @published@observable + @State (last iOS demo not migrated).
- JVM/Linux/Windows CLIs: added com.ncorti.ktfmt.gradle plugin with
  googleStyle() (every other module already had it).

Polish:
- Standardized QUANTIZATION_TYPE constant naming across all 12 demos (was a
  mix of QUANTIZATION_SLUG / QUANTIZATION / local quantType).
- ShareAI: moved hardcoded notification titles into strings.xml.
- SloganApp / VLMExample: promoted modelName/quantType locals to companion
  constants for consistency with the other Android demos.
- Web demo: explicitly pinned coroutines = "1.10.2" (was relying on transitive
  resolution).
- Root README: Xcode 15+ → Xcode 16+ (Xcode 26 recommended), matches CI.
- JVM CLI --help: stderr → stdout (matches Linux/Windows + convention).
- iOS/RecipeGenerator/README.md: fixed stale `rawFlow as! SkieSwiftFlow<...>`
  snippet to match the actual code (0.10.8 returns SkieSwiftFlow directly).
- 3 new iOS Makefiles (VLMExample, VoiceAssistantDemo, RecipeGenerator) +
  3 new READMEs (Android LeapVoiceAssistantDemo, iOS LeapVLMExample,
  macOS LeapVLMExample) for parity with the rest of the suite.

Verified locally: all 7 modified Android demos pass :app:compileDebugKotlin +
:app:ktfmtCheckMain. All 3 desktop CLIs pass compileKotlin* + ktfmtCheck. Web
passes compileKotlinWasmJs + ktfmtCheck. LeapKoogAgent's pre-existing missing
koog-edge-0.0.1.aar is unchanged and still blocks its build (separate cleanup
item).
…imulator

Two CI failures on commit 21f7eff:

(1) macOS Demos Build (LeapVLMExample): Swift compile error
    `type 'Skie.LeapSdk.MessageResponse.__Sealed' has no member 'error'`.
    SKIE excludes the Error sealed-subtype from its __Sealed Swift-friendly
    enum codegen because the name collides with Swift's built-in Error
    protocol (the SDK's SKIE config sets SuppressSkieWarning.NameCollision
    precisely for this reason). The runtime class MessageResponseError still
    exists; it just isn't in the synthesized enum. Switched all 7 Swift
    collectors from `case .error(let err)` arms to a pre-switch
    `if let err = resp as? MessageResponseError { ...; continue }` guard,
    matching the pattern AppleVoiceConversation.swift was already using.

(2) iOS Demos Build: "Unable to find a device matching the provided
    destination specifier". My critical-review fix pinned `name=iPhone 16`,
    but Xcode 26.2 on macos-26 ships iPhone 16e / 17 / 17 Pro / 17 Pro Max /
    Air — the plain "iPhone 16" simulator was dropped at the 17-line cut.
    Bumped to `iPhone 17` across the iOS workflow and 6 demo Makefiles.
    Matches the root README's "Xcode 26 recommended" guidance.

Other 6 jobs from 21f7eff were green (JVM, Linux, Windows, Web, Android
Demos, Android LeapChat) — the Kotlin sweep landed cleanly; only the
Swift-side bridge details and CI simulator name needed the follow-up.
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.

2 participants