docs(leap-sdk): refresh through v0.10.9 (SKIE on openai-client + MessageResponse.Error + LeapDownloaderConfig.with fix)#100
docs(leap-sdk): refresh through v0.10.9 (SKIE on openai-client + MessageResponse.Error + LeapDownloaderConfig.with fix)#100iamstuffed wants to merge 7 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Refreshes the on-device LEAP SDK documentation set to match leap-sdk v0.10.8, primarily reflecting (1) SKIE being applied to leap-sdk-openai-client (new Swift AsyncSequence + onEnum(of:) surface and preserved nested type names) and (2) the new in-band MessageResponse.Error case to make generation failures observable to Swift stream consumers.
Changes:
- Bumps all dependency/version pins from 0.10.7 → 0.10.8 across SDK pages and Android examples.
- Updates Swift OpenAI-client docs to the new SKIE-bridged surface (
OpenAiClient(config:),for … await,onEnum(of:)). - Documents and propagates the new
MessageResponse.Errorcase throughout streaming examples (Swift + Kotlin), making switches/whenblocks exhaustive.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| link-snapshot.yaml | Adds the SDK overview route to the link snapshot allowlist. |
| examples/android/web-content-summarizer.mdx | Updates Gradle dependency pins to v0.10.8. |
| examples/android/vision-language-model-example.mdx | Updates Gradle dependency pins to v0.10.8. |
| examples/android/slogan-generator.mdx | Updates Gradle dependency pins to v0.10.8. |
| examples/android/recipe-generator-constrained-output.mdx | Updates dependency pins and referenced version text to v0.10.8. |
| examples/android/leap-koog-agent.mdx | Updates Gradle dependency pins to v0.10.8. |
| deployment/on-device/sdk/voice-assistant.mdx | Bumps version pins and adds explicit handling for MessageResponse.Error in examples. |
| deployment/on-device/sdk/quick-start.mdx | Bumps “latest version” + dependency pins; adds .error handling to streaming example; updates XCFramework URLs to v0.10.8. |
| deployment/on-device/sdk/openai-client.mdx | Rewrites Swift examples to the SKIE-bridged v0.10.8 API and updates error semantics text/table. |
| deployment/on-device/sdk/model-loading.mdx | Updates version-scoped note from v0.10.7 → v0.10.8. |
| deployment/on-device/sdk/function-calling.mdx | Adds explicit .error / MessageResponse.Error handling and removes catch-all branches. |
| deployment/on-device/sdk/desktop-platforms.mdx | Bumps dependency pins; updates native ZIP coordinates and adds explicit error handling in samples. |
| deployment/on-device/sdk/conversation-generation.mdx | Documents the new MessageResponse.Error case and updates examples/warnings accordingly. |
| deployment/on-device/sdk/cloud-ai-comparison.mdx | Adds explicit handling for the new .error / MessageResponse.Error case. |
| deployment/on-device/sdk/ai-agent-usage-guide.mdx | Makes response handling exhaustive and adds error propagation/handling. |
| deployment/on-device/leap-sdk-changelog.mdx | Adds the v0.10.8 changelog entry describing SKIE-on-openai-client + in-band generation errors. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ```swift | ||
| .binaryTarget( | ||
| name: "LeapSDK", | ||
| url: "https://github.com/Liquid4All/leap-sdk/releases/download/v0.10.7/LeapSDK.xcframework.zip", | ||
| checksum: "6f2721aa45d7555646f78cbcaedb57aba3d869f56b24d681ad332846e131ae3d" | ||
| url: "https://github.com/Liquid4All/leap-sdk/releases/download/v0.10.8/LeapSDK.xcframework.zip", | ||
| checksum: "<copy from the v0.10.8 release page>" | ||
| ), |
| @@ -222,11 +222,11 @@ The Leap SDK is a Kotlin Multiplatform library: the same `ModelRunner` / `Conver | |||
| // build.gradle.kts | |||
| plugins { | |||
| kotlin("multiplatform") version "2.3.20" | |||
| case .error(let err): | ||
| // In-band failure (v0.10.8+) — SKIE bridges `Flow` with `Failure = Never`, | ||
| // so generation failures arrive here instead of on the `catch` block above. | ||
| print("Generation failed:", err.message) |
| @@ -194,11 +197,11 @@ dependencyResolutionManagement { | |||
| // build.gradle.kts | |||
| plugins { | |||
| kotlin("multiplatform") version "2.3.20" | |||
|
|
||
| dependencies { | ||
| implementation("ai.liquid.leap:leap-sdk:0.10.7") | ||
| implementation("ai.liquid.leap:leap-sdk:0.10.8") |
| @@ -269,11 +272,11 @@ The same Kotlin/Native flow works for Windows x86_64 via the MinGW-w64 toolchain | |||
| ```kotlin | |||
| plugins { | |||
| kotlin("multiplatform") version "2.3.20" | |||
| name: "LeapSDK", | ||
| url: "https://github.com/Liquid4All/leap-sdk/releases/download/v0.10.7/LeapSDK.xcframework.zip", | ||
| url: "https://github.com/Liquid4All/leap-sdk/releases/download/v0.10.8/LeapSDK.xcframework.zip", | ||
| checksum: "6f2721aa45d7555646f78cbcaedb57aba3d869f56b24d681ad332846e131ae3d" |
| <Note> | ||
| SKIE bridges Kotlin `Flow` to a Swift `AsyncSequence` with `Failure = Never`, so transport-level failures (network drop, TLS error, etc.) silently terminate the stream rather than throwing. Only HTTP-level errors (non-2xx response) arrive as in-band `.error` events; malformed SSE chunks are logged and skipped. If you need to react to silent termination, track whether `.done` was observed and treat a stream that ended without it as a transport failure. | ||
| </Note> |
| case .error(let err): | ||
| // SKIE bridges `Flow` as an `AsyncSequence` with `Failure = Never`, so the | ||
| // surrounding `for try await` cannot observe a thrown error from the Kotlin | ||
| // side. Generation failures surface as this in-band `.error` case (added in | ||
| // v0.10.8) — handle it here and present `err.message` to the user. |
|
|
||
| **In-band `MessageResponse.Error` (Kotlin) / `LiquidMessageResponse.Error` (Swift compat layer)** ([PR #258](https://github.com/Liquid4All/leap-android-sdk/pull/258)): | ||
|
|
||
| `Conversation.generateResponse(...)` now emits a terminal `MessageResponse.Error(throwable, message)` value **before** closing the underlying channel with the same throwable. This closes a Swift gap: SKIE bridges Kotlin `Flow` to a Swift `AsyncSequence` with `Failure = Never`, so a thrown `LeapGenerationException` could not be observed from Swift — `for await response in conversation.generateResponse(...)` simply terminated silently. With the new in-band case, Swift consumers `switch onEnum(of: response)` over the `.error` arm and surface the failure to the user; Kotlin consumers using `Flow.catch { }` / `try/catch` keep working unchanged because the exceptional close is still emitted. |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
Mechanical version bump across the five Android example tutorials — `ai.liquid.leap:leap-sdk` and `ai.liquid.leap:leap-model-downloader` Gradle pins from `0.10.7` → `0.10.8`. No prose changes; the example snippets continue to demonstrate the same APIs.
Add the v0.10.8 release entry to the SDK changelog and the corresponding
reference-doc updates for the new in-band failure event.
Changelog (`leap-sdk-changelog.mdx`):
- Bump headline "Latest release" v0.10.7 → v0.10.8.
- Convert the v0.10.7 "next release will enable SKIE..." teaser into a
past-tense pointer at the new v0.10.8 section so the v0.10.7 entry
stays internally consistent.
- New `### v0.10.8 — 2026-05-21` section covering:
- SKIE applied to `leap-sdk-openai-client` — `client.streamChatCompletion`
is now a Swift `AsyncSequence`, `onEnum(of:)` switches exhaustively
over `ChatCompletionEvent`, nested Kotlin class names are preserved
(`ChatCompletionEvent.Delta` instead of K/N-flattened
`ChatCompletionEventDelta`), and the top-level
`fun OpenAiClient(config:)` factory exports as a real Swift
convenience init (no more `OpenAiClientKt.` prefix). The framework is
now distributable so a plain `import LeapOpenAIClient` is enough.
- New in-band `MessageResponse.Error(throwable, message)` /
`LiquidMessageResponse.Error` — closes the Swift `Failure = Never`
gap on `Conversation.generateResponse(...)`. Kotlin consumers keep
working unchanged because the channel still closes with the
underlying throwable.
- Exhaustive-`when` / `switch` migration notes for both Kotlin and
Swift call sites.
- Terminal-operator caveat warning — `first()` / `first { ... }` /
`take(1)` may now consume the in-band `Error` value and complete
*normally*, where they previously propagated exceptionally.
- The `Flow` is now backed by `buffer(Channel.UNLIMITED)` so the
terminal `Error` emission can never be silently dropped under
collector backpressure.
- Toolchain: Kotlin 2.3.20 → 2.3.21, SKIE 0.10.11 → 0.10.12. No Xcode
or Swift baseline change.
`MessageResponse` reference (`conversation-generation.mdx`):
- Add the new sealed-class case to the Swift and Kotlin reference
blocks: Swift `case error(Error)`; Kotlin
`data class Error(throwable, message)` with the documented `message`
default of `throwable.message ?: throwable::class.simpleName ?: throwable.toString()`.
- Add a bulleted entry documenting the new case alongside the existing
ones, including the reference-equality-on-throwable caveat (since
`Throwable` does not override `equals` / `hashCode`, the synthesised
`data class` equality is reference-based).
- Update the streaming-generation Swift example's `switch onEnum(of:
response)` with a `case .error(let err)` arm that explains the SKIE
`Failure = Never` rationale inline.
- Update the streaming-generation Kotlin example's `when (response)`
with an `is MessageResponse.Error -> Log.e(...)` arm.
- Rewrite the trailing "Errors propagate as `LeapGenerationException`"
note into a two-paragraph explanation covering the dual error path
(in-band `Error` value + exceptional flow close) and adding a
`<Warning>` callout for the terminal-operator caveat.
v0.10.8 applies SKIE to `leap-sdk-openai-client`, so the entire Swift
side of the OpenAI-compatible client page needed to be rewritten — the
v0.10.7 docs described the manual `Flow.collect(collector: FlowCollector
{ ... })` shape with K/N-flattened type names. Two source-accuracy gaps
in the prior version also fixed in this pass.
SKIE surface rewrites:
- Replaced the v0.10.7 "no SKIE / manual collector" `<Warning>` with a
v0.10.8 `<Info>` flip explaining the new surface and pointing readers
who want the old behavior frozen to a `0.10.7` pin.
- Rewrote every Swift code block to use the new ergonomic surface:
`OpenAiClient(config: ...)` instead of
`OpenAiClientKt.OpenAiClient(config: ...)`; `for try await event in
client.streamChatCompletion(request: ...)` with `switch onEnum(of:
event) { case .delta / .done / .error }` instead of the manual
`FlowCollector`. Affected blocks: Basic usage, OpenRouter
configuration, self-hosted vLLM / llama-server, hybrid on-device +
cloud routing.
- Switched all `ChatMessage` constructions from K/N-flattened
`ChatMessageUser(content:)` / `ChatMessageSystem(content:)` to the
SKIE-preserved nested form `ChatMessage.User(content:)` /
`ChatMessage.System(content:)` — confirmed against the source
`sealed interface ChatMessage { data class System, User, Assistant }`.
- Updated the Response-shape prose paragraph to drop the no-SKIE-bridge
caveat — Swift consumers see a `AsyncSequence` now.
- Lifecycle section's Swift block dropped the `OpenAiClientKt.` prefix
references; the SKIE-bundled `OpenAiClient(config:)` is the Swift
entry point.
Bumped every dependency pin in the install-the-SDK Tabs from 0.10.7 →
0.10.8 (SPM `from:`, Android Gradle, JVM Gradle, Kotlin/Native Gradle).
Source-accuracy gaps caught while rewriting:
1. The Basic-usage Swift sample previously wrapped the `for try await`
in a `do/catch` with a comment claiming that "transport-level
failures (network drop, bad TLS, etc.) surface as a thrown error on
the AsyncSequence." That claim is **wrong under SKIE FlowInterop with
`Failure = Never`** — transport errors silently terminate the
`AsyncSequence` rather than throwing. Dropped the misleading
`do/catch` and added a `<Note>` explaining the silent-termination
behavior, plus the "track whether `.done` was observed" workaround
for detecting it.
2. The Response-shape table's `Error(message:)` row claimed it covers
"HTTP error or stream parsing failure." Source contradicts the
second half: `OpenAiClient.processChunk(...)` catches `Exception`
from `json.decodeFromString` and `log.w { "Skipping malformed SSE
chunk: ${e.message}" }; null` — malformed chunks are silently
skipped, not surfaced. Updated the row to "Non-2xx HTTP response.
Malformed SSE chunks are logged and skipped — they do not emit an
`Error` event."
…se switches
Two related changes across the remaining SDK pages:
1. Version pins bumped 0.10.7 → 0.10.8 — every `ai.liquid.leap:*` Gradle
coordinate, SPM `from: "0.10.7"`, `nativelibs` plugin version, the
`gradle/libs.versions.toml` snippet, Maven `<version>` block,
XCFramework binary-target URLs, and `*-natives@zip` classifier
coordinates. Quick-start's XCFramework SHA-256 values were replaced
with `<copy from the v0.10.8 release page>` placeholders since the
v0.10.8 GitHub release wasn't live when these were drafted; a
follow-up pass needs to drop in the real checksums.
2. Every Kotlin `when (response)` over `MessageResponse` and every Swift
`switch onEnum(of: response)` that previously used an `else -> {}` /
`else -> Unit` / `default: break` fallback was expanded into explicit
arms covering all six `MessageResponse` subtypes (`Chunk`,
`ReasoningChunk`, `FunctionCalls`, `AudioSample`, `Complete`, and the
new `Error` case from v0.10.8). Rationale: the example code is what
readers copy into their apps; under v0.10.8 a fallback-based pattern
silently swallows the new `Error` arm on Kotlin (statement-`when`
compiles with a warning, expression-`when` won't) and on Swift the
compiler enforces exhaustiveness, so call sites stop compiling.
Showing the explicit `.error` arm in every example puts the
migration path right next to the surrounding code.
Per-file detail:
- `quick-start.mdx` — bump every dependency pin; XCFramework
binary-target SHA-256s replaced with placeholders; iOS Swift
streaming example gains `case .error(let err)` arm; Android Kotlin
`when` gains `is MessageResponse.Error -> _errorMessage.value = ...`
arm; Kotlin/Native quick-start `when` expanded from 2-arm + `else`
to 6 explicit arms with `Error → System.err.println(...)`.
- `ai-agent-usage-guide.mdx` — first handler example: Swift `switch
onEnum(of:)` gains `case .error(let err): log(...)`; Kotlin `when`
gains `is MessageResponse.Error -> Log.e(...)`. ChatViewModel example:
same treatment, Kotlin path writes to `_errorMessage` so SwiftUI /
Compose can surface it. Agent-loop example: Swift `default: break`
replaced with `case .reasoningChunk, .audioSample: break` +
`case .error(let err): throw NSError(...)`; Kotlin `else -> {}`
replaced with explicit no-op arms plus
`is MessageResponse.Error -> throw response.throwable`.
- `function-calling.mdx` — Swift exhaustive case-list gains `.error`
arm; Kotlin `when` expanded with explicit `ReasoningChunk` /
`AudioSample` no-ops plus `Error → Log.e(...)`.
- `cloud-ai-comparison.mdx` — Swift case-list gains `.error` arm
surfacing via `print(...)`; Kotlin `when` expanded to 6 arms.
- `voice-assistant.mdx` — bump SPM `from:` and Gradle pins; bump
"stable release notes through v0.10.7" → "through v0.10.8"; Swift
audio-streaming `switch` gains `case .error(let err): throw
NSError(...)` so the surrounding `VoiceConversation` machinery
surfaces the failure; Kotlin `when` expanded with explicit no-op
arms plus `Error → throw response.throwable` matching the Swift
shape.
- `desktop-platforms.mdx` — bump every dependency pin, plugin
version, Maven `<version>`, natives-zip coords, and the XCFramework
binary-target URL; Kotlin K/N quick-start `when` expanded to 6
arms.
- `model-loading.mdx` — rewrite the "Sideloaded
`LiquidInferenceEngineOptions` (URL-based load)" callout from "does
NOT ship a Swift convenience init in v0.10.7" to "...through v0.10.8"
so the version stays accurate — v0.10.8's SKIE-on-openai-client
change didn't touch `LiquidInferenceEngineOptions`, so the all-12-
fields situation is unchanged.
336aba4 to
b9c1a82
Compare
| name: "LeapSDK", | ||
| url: "https://github.com/Liquid4All/leap-sdk/releases/download/v0.10.7/LeapSDK.xcframework.zip", | ||
| url: "https://github.com/Liquid4All/leap-sdk/releases/download/v0.10.8/LeapSDK.xcframework.zip", | ||
| checksum: "6f2721aa45d7555646f78cbcaedb57aba3d869f56b24d681ad332846e131ae3d" |
| @@ -194,11 +197,11 @@ | |||
| // build.gradle.kts | |||
| plugins { | |||
| kotlin("multiplatform") version "2.3.20" | |||
| ```kotlin | ||
| plugins { | ||
| kotlin("multiplatform") version "2.3.20" | ||
| } | ||
|
|
||
| dependencies { | ||
| implementation("ai.liquid.leap:leap-sdk:0.10.7") | ||
| implementation("ai.liquid.leap:leap-sdk:0.10.8") | ||
| } |
| @@ -269,11 +272,11 @@ | |||
| ```kotlin | |||
| plugins { | |||
| kotlin("multiplatform") version "2.3.20" | |||
| @@ -222,11 +222,11 @@ The Leap SDK is a Kotlin Multiplatform library: the same `ModelRunner` / `Conver | |||
| // build.gradle.kts | |||
| plugins { | |||
| kotlin("multiplatform") version "2.3.20" | |||
| ```swift | ||
| .binaryTarget( | ||
| name: "LeapSDK", | ||
| url: "https://github.com/Liquid4All/leap-sdk/releases/download/v0.10.7/LeapSDK.xcframework.zip", | ||
| checksum: "6f2721aa45d7555646f78cbcaedb57aba3d869f56b24d681ad332846e131ae3d" | ||
| url: "https://github.com/Liquid4All/leap-sdk/releases/download/v0.10.8/LeapSDK.xcframework.zip", | ||
| checksum: "<copy from the v0.10.8 release page>" | ||
| ), |
| --- | ||
|
|
||
| Latest version: `v0.10.7` | ||
| Latest version: `v0.10.8` |
| --- | ||
|
|
||
| Latest release: **v0.10.7** ([GitHub](https://github.com/Liquid4All/leap-sdk/releases/tag/v0.10.7)). | ||
| Latest release: **v0.10.8** ([GitHub](https://github.com/Liquid4All/leap-sdk/releases/tag/v0.10.8)). |
… fix - Add a v0.10.9 changelog entry covering the Swift-only LeapDownloaderConfig / ModelDownloader construction hang and its fix via the LeapDownloaderConfig.with(...) static factory, with the Swift call-site change and the Kotlin no-op note - Switch Swift examples from LeapDownloaderConfig(saveDir:) to LeapDownloaderConfig.with(saveDir:) across quick-start, model-loading, cloud-ai-comparison, utilities, voice-assistant, and ai-agent-usage-guide; Kotlin LeapDownloaderConfig(saveDir = ...) examples unchanged - Bump "Latest release" to v0.10.9
The v0.10.9 entry migrated Swift examples to `LeapDownloaderConfig.with(...)`
but left every install pin at 0.10.8. `.with(...)` only exists in v0.10.9
(introduced in leap-android-sdk#262 / 3474b16), so the examples could not
compile against the pinned version — and `LeapDownloaderConfig(saveDir:)` on
0.10.8 is the exact call that hangs. Make the install version match the code.
- Bump all SPM `from:` / `.binaryTarget` URLs, Maven + Gradle coordinates,
the `-jvm` classifier, the `nativelibs` plugin pins, the `:natives@zip`
coordinates, the Maven `<version>`, and the `leapSdk` catalog entry
0.10.8 -> 0.10.9 across the SDK pages and the five Android examples.
Verified every artifact is published at 0.10.9 (Maven Central `<release>`;
SPM via the leap-sdk v0.10.9 tag).
- Replace the four placeholder `<copy from...>` checksums in quick-start.mdx
and the fabricated checksum in desktop-platforms.mdx (6f2721aa..., matching
no real release) with the real v0.10.9 SHA-256s from leap-sdk/Package.swift.
- Correct the v0.10.9 changelog heading date 2026-05-27 -> 2026-05-29 to match
the published release.
- Leave historical prose ("New in v0.10.8", "since v0.10.8", "v0.10.8+")
unchanged.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
deployment/on-device/sdk/conversation-generation.mdx:212
- The Kotlin example handles generation failures twice: it logs
MessageResponse.Errorin thewhenand then logs again in.catch { ... }when the flow closes exceptionally with the same throwable. This will double-log (and it contradicts the text below saying to pick one path).
is MessageResponse.Error -> Log.e(TAG, "Generation failed: ${response.message}", response.throwable)
}
}
?.catch { e -> Log.e(TAG, "Generation failed", e) }
?.collect()
| } else { | ||
| // On-device path: leap-sdk has SKIE — `for try await` + `onEnum(of:)` | ||
| // work as written. | ||
| let userMessage = ChatMessage(role: .user, textContent: text) | ||
| // On-device path. | ||
| let userMessage = LeapSDK.ChatMessage(role: .user, textContent: text) | ||
| for try await response in onDevice.generateResponse(message: userMessage) { | ||
| if case let .chunk(c) = onEnum(of: response) { appendChunk(c.text) } |
| ``` | ||
|
|
||
| **Sideloaded `LiquidInferenceEngineOptions` (URL-based load).** The non-manifest variant does NOT ship a Swift convenience init in v0.10.7 — the K/N-generated designated init takes all 12 fields. Either build it fully (verbose) or use `loadSimpleModel(model: ModelSource(...))` on `ModelDownloader` (preferred for new code; see the Sideloaded files section). The builder `.with(...)` overloads exist but they create a new instance internally via the same 12-arg init, so you still need a fully-built starting instance — there is no `LiquidInferenceEngineOptions(bundlePath: …)` 1-arg form today. | ||
| **Sideloaded `LiquidInferenceEngineOptions` (URL-based load).** The non-manifest variant does NOT ship a Swift convenience init through v0.10.8 — the K/N-generated designated init takes all 12 fields. Either build it fully (verbose) or use `loadSimpleModel(model: ModelSource(...))` on `ModelDownloader` (preferred for new code; see the Sideloaded files section). The builder `.with(...)` overloads exist but they create a new instance internally via the same 12-arg init, so you still need a fully-built starting instance — there is no `LiquidInferenceEngineOptions(bundlePath: …)` 1-arg form today. |
- Align Kotlin plugin pins 2.3.20 -> 2.3.21 across the SDK pages and the
constrained-output example, matching the SDK's build toolchain
(libs.versions.toml kotlin = 2.3.21) and its own KOTLIN_NATIVE_SETUP.md.
- Fix the error-model notes that claimed the SKIE bridge is "Failure = Never"
and that transport failures "silently terminate the stream" with a "track
whether .done was observed" workaround. Verified against SKIE 0.10.12
generated output and OpenAiClient.kt: the bridged AsyncSequence does not
rethrow Kotlin exceptions; recoverable errors arrive in-band (.error only on
non-2xx HTTP, malformed SSE chunks logged+skipped); transport failures are
not delivered to the stream. Notes reworded to say exactly that, dropping the
misleading "Failure" terminology while keeping the existing for-try-await
convention.
- Fix the Kotlin double-log in conversation-generation: handle the failure once
in the in-band MessageResponse.Error arm; the terminal .catch {} now swallows
the redundant exceptional close.
- Hybrid routing example: the on-device message used LeapSDK.ChatMessage, but
the example imports only LeapModelDownloader + LeapOpenAIClient. The leap-sdk
types are emitted into the LeapModelDownloader module (export(project)), so
LeapSDK.ChatMessage would not resolve. Use LeapModelDownloader.ChatMessage and
qualify the cloud message as LeapOpenAIClient.ChatMessage.User.
- model-loading: bump the LiquidInferenceEngineOptions callout version label
"through v0.10.8" -> "through v0.10.9" (the claim still holds at v0.10.9).
Summary
Refreshes the Leap SDK docs through v0.10.9. Two source releases drive the edits:
v0.10.9 (source PR
leap-android-sdk#262)LeapDownloaderConfig/ModelDownloaderSwift construction no longer hangs. In v0.10.6–v0.10.8, constructingLeapDownloaderConfig(...)/LeapDownloader(...)/ModelDownloader()from Swift spun the calling thread at 100% CPU forever — the v0.10.6 defaultedconvenience initshared the exact ObjC selector of the imported Kotlin/Native designated init it delegated to, soself.init(...)resolved back to itself (infinite recursion, optimized into a busy loop in Release builds). The fix replaces the defaulted convenience init with aLeapDownloaderConfig.with(...)static factory carrying the same Kotlin defaults.LeapDownloaderConfig(saveDir:)toLeapDownloaderConfig.with(saveDir:)(quick-start, model-loading, cloud-ai-comparison, utilities, voice-assistant, ai-agent-usage-guide). Kotlin / Android / JVM callers are unaffected — the KotlinLeapDownloaderConfig(saveDir = ...)data-class constructor never had this issue, so Kotlin examples are unchanged. Binary-compatible with v0.10.8 apart from the Swift construction shape.v0.10.8 (source PR
leap-android-sdk#258, commit17f5fe1)leap-sdk-openai-client— Swift consumers now get anAsyncSequence,onEnum(of:)exhaustive switching overChatCompletionEvent, nested Kotlin type names preserved (ChatCompletionEvent.Deltainstead of K/N-flattenedChatCompletionEventDelta, same forChatMessage.System/.User/.Assistant), and a realOpenAiClient(config:)Swift convenience init from the SKIE-bundled top-level factory. Framework is now distributable soimport LeapOpenAIClientis enough.MessageResponse.Error(throwable, message)sealed-class case (mirrored asLiquidMessageResponse.Erroron the iOS compat layer). SKIE bridges KotlinFlowwithFailure = Never, so Swiftfor awaitcould not previously observe aclose(error)— generation failures silently terminated the stream. The new in-bandErrorvalue closes that gap; Kotlin behavior is unchanged (the channel still closes with the same throwable, soFlow.catch { }keeps working). The flow is also backed bybuffer(Channel.UNLIMITED)so the terminalErroremission cannot be silently dropped under collector backpressure.Commits
docs(leap-sdk): bump example dependency pins to 0.10.8— mechanical version bumps in the five Android example tutorials.docs(leap-sdk): add v0.10.8 changelog + document MessageResponse.Error— new### v0.10.8 — 2026-05-21changelog entry, updatedMessageResponsereference block with the newErrorcase (Swift + Kotlin), and the streaming-generation examples gain explicit.error/is MessageResponse.Errorarms.docs(openai-client): rewrite Swift surface for v0.10.8 SKIE bridge— every Swift code block onopenai-client.mdxrewritten to useOpenAiClient(config:)+for try await event in client.streamChatCompletion(...)+switch onEnum(of: event). Also fixes two source-vs-doc accuracy gaps from the v0.10.7 docs (the misleadingdo/catchtransport-failure claim and the inaccurate "stream parsing failure" half of theErrorrow).docs(leap-sdk): bump SDK page version pins + exhaustive MessageResponse switches— version bumps across the rest of the SDK pages + everywhen (response)/switch onEnum(of: response)overMessageResponseconverted fromelse -> {}/default: breakfallback to an explicit listing of all six sealed-class arms (Chunk,ReasoningChunk,FunctionCalls,AudioSample,Complete,Error). Reader-facing rationale: under v0.10.8 the Swift compiler enforces exhaustiveness (call sites stop compiling against v0.10.8 until.erroris added) and Kotlin statement-whencompiles only with a warning — showing the explicit.errorarm in every example puts the migration path right next to the surrounding code.docs(leap-sdk): document v0.10.9 LeapDownloaderConfig.with(...) Swift fix— new### v0.10.9changelog entry covering the Swift construction hang and its fix, "Latest release" bumped to v0.10.9, and every SwiftLeapDownloaderConfig(saveDir:)call site migrated toLeapDownloaderConfig.with(saveDir:)across six SDK pages. Kotlin examples untouched.fix(leap-sdk): pin docs to v0.10.9 + real XCFramework checksums— the v0.10.9 commit migrated Swift examples toLeapDownloaderConfig.with(...), which only exists in v0.10.9, but left every install pin at0.10.8(the examples could not compile against the pinned version, andLeapDownloaderConfig(saveDir:)on 0.10.8 is the call that hangs). Bumps all SPMfrom:/.binaryTargetURLs, Maven + Gradle coordinates,-jvmclassifier,nativelibsplugin pins,:natives@zipcoords, Maven<version>, and theleapSdkcatalog entry0.10.8 → 0.10.9across the SDK pages and the five Android examples — after confirming every artifact is published at 0.10.9 (Maven Central<release>; SPM via theleap-sdkv0.10.9tag). Replaces the four placeholder checksums inquick-start.mdxand the fabricated checksum indesktop-platforms.mdx(6f2721aa…, matching no real release) with the real v0.10.9 SHA-256s fromleap-sdk/Package.swift, and corrects the v0.10.9 changelog date to2026-05-29(the published release date). Historical prose ("New in v0.10.8", "since v0.10.8") left unchanged.Verification against SDK source
Every code example and SDK/API claim in this PR was cross-checked against the actual v0.10.9 source (
leap-android-sdk@artifactVersion = 0.10.9, fix commit3474b16;leap-sdk@v0.10.9tag +Package.swift). The openai-client SKIE rewrite (OpenAiClient(config:),streamChatCompletion(request:),ChatCompletionEvent.Delta/.Done/.Error,ChatMessage.System/.User/.Assistant, the "Error only on non-2xx HTTP" +Failure = Nevertransport-failure claims), theMessageResponsesix-subtype list +Error(throwable, message)shape + exhaustive switches, and theLeapDownloaderConfig.with(...)factory + defaults + recursion root-cause all verified correct against source.Test plan
npx mintlify dev --port 3010boots clean.200(/deployment/on-device/leap-sdk-changelog,/sdk/openai-client,/sdk/conversation-generation,/sdk/quick-start,/sdk/ai-agent-usage-guide,/sdk/function-calling,/sdk/cloud-ai-comparison,/sdk/voice-assistant,/sdk/desktop-platforms,/sdk/model-loading,/sdk/utilities, plus the 5 example pages).scripts/generateLinkSnapshot.ts --checkpasses (pre-commit hook ran each commit;link-snapshot.yamlclean). Re-verified after the v0.10.9 pin bump: 162 active URLs, all 16 changed pages probe200.leap-sdk/Package.swift.leap-sdk,leap-model-downloader,leap-ui,leap-openai-client(-jvm), the threeleap-sdk-{linuxx64,linuxarm64,mingwx64}native zips,nativelibsplugin) and SPM (v0.10.9tag).OpenAiClient(config:)+for try await event in client.streamChatCompletion(...)+onEnum(of: event)resolves and compiles againstleap-sdk:0.10.9.LeapDownloaderConfig.with(saveDir:)resolves and thatModelDownloader(config:)construction no longer hangs againstleap-sdk:0.10.9.is MessageResponse.Error -> ...arms compile againstai.liquid.leap:leap-sdk:0.10.9.Notes for reviewers
conversation.generateResponseSwift example inconversation-generation.mdxis intentionally left in place — thecatchstill catches Swift-side throws inside the loop body (e.g. fromhandleFunctionCalls), even though Kotlin-thrown errors now route through the in-band.errorarm. The inline comment on.errormakes the SKIEFailure = Neverrationale explicit.openai-client.mdx(transport-failure<Note>+Errorvariant row) were latent bugs from the v0.10.7 docs that became more visible once SKIE was applied — they're scoped to this PR since they sit in the same Swift sample I was rewriting anyway.LeapDownloaderConfig(saveDir:validateSha256:disableSslValidation:baseUrl:connectTimeoutMillis:socketTimeoutMillis:requestTimeoutMillis:)designated initializer also works directly if a reader prefers passing every field — the changelog entry notes this.