Skip to main content
If you’ve used a cloud chat-completion API (OpenAI, Anthropic, etc.), most of LEAP’s shape will be familiar — async streaming, role-tagged messages, JSON-serializable history. The biggest difference: you load the model explicitly, locally, before generation, instead of pointing a client at a remote endpoint. This page maps the OpenAI Python client’s flow onto the LEAP SDK across Swift, Kotlin (Android), and Kotlin (JVM / native). For OpenAI compatibility on the client side, also see OpenAI-Compatible Client.

Reference: an OpenAI streaming call

1. Load the model (vs. construct a client)

Cloud APIs create a thin client that points at a remote endpoint. LEAP downloads the model the first time and loads it into a ModelRunner — typically a few seconds depending on model size and device.
The returned ModelRunner plays the same role as the cloud API’s client object — except it carries the model weights. Release it and you’ll have to load again before generating.

2. Request generation

The cloud API takes a messages array and returns a stream. LEAP attaches messages to a Conversation (so history is tracked automatically) and returns an async stream from generateResponse(...).
You don’t pass the model name on each call — the Conversation is already bound to the runner that loaded it.

3. Consume the stream

Cloud APIs deliver deltas; you concatenate them. LEAP delivers MessageResponse values; each variant maps to a UI update, audio frame, tool call, or completion marker.

4. Async context

Both LEAP and the OpenAI Python streaming client run inside an async context. The SDK’s call shape mirrors the language’s idiomatic concurrency primitives.
Wrap calls in a Task. SwiftUI’s .task modifier on a view is the most common entry. @MainActor view models keep model state on the main thread; the for try await loop suspends the task until the next chunk arrives.

What’s the same

What’s different

  • No remote endpoint. You ship the model with the app (or download it the first time it runs). Latency is bounded by device CPU/GPU, not network round-trips.
  • Explicit lifecycle. Hold a ModelRunner reference; unload() when done. Cloud clients never load anything explicitly.
  • Multimodal inputs go in content array, same as OpenAI. Image and audio parts use the same OpenAI image_url / input_audio wire format.
  • Companion files for multimodal models. Vision and audio-capable models need an mmproj (vision) and/or audio decoder/tokenizer co-located on disk. Manifest-based loading handles this automatically; loadSimpleModel accepts explicit mmprojPath / audioDecoderPath / audioTokenizerPath.

Next steps