docs(leap-sdk): refresh through v0.10.8 (SKIE on openai-client + MessageResponse.Error)#100
Open
iamstuffed wants to merge 4 commits into
Open
docs(leap-sdk): refresh through v0.10.8 (SKIE on openai-client + MessageResponse.Error)#100iamstuffed wants to merge 4 commits into
iamstuffed wants to merge 4 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.
Comment on lines
103
to
108
| ```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" | |||
Comment on lines
+479
to
+482
| 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 @@ | |||
| // build.gradle.kts | |||
| plugins { | |||
| kotlin("multiplatform") version "2.3.20" | |||
Comment on lines
227
to
+233
| ```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" | |||
| 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" |
Comment on lines
+112
to
+114
| <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> |
Comment on lines
+171
to
+175
| 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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
17f5fe1).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-21` changelog entry, updated `MessageResponse` reference block with the new `Error` case (Swift + Kotlin), and the streaming-generation examples gain explicit `.error` / `is MessageResponse.Error` arms.docs(openai-client): rewrite Swift surface for v0.10.8 SKIE bridge— every Swift code block on `openai-client.mdx` rewritten to use `OpenAiClient(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 misleading `do/catch` transport-failure claim and the inaccurate "stream parsing failure" half of the `Error` row).docs(leap-sdk): bump SDK page version pins + exhaustive MessageResponse switches— version bumps across the rest of the SDK pages + every `when (response)` / `switch onEnum(of: response)` over `MessageResponse` converted from `else -> {}` / `default: break` fallback 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 `.error` is added) and Kotlin statement-`when` compiles only with a warning — showing the explicit `.error` arm in every example puts the migration path right next to the surrounding code.Outstanding (does not block review)
Test plan
Notes for reviewers