ChatMessage and ChatMessageContent mirror the OpenAI chat-completions message schema. Both are declared once in commonMain (data class ChatMessage, sealed class ChatMessageContent) and Kotlin/Native + SKIE bridge the Kotlin types into Swift β there are no separate βnativeβ Swift declarations.
ChatMessage
- Swift (iOS / macOS)
- Kotlin (all platforms)
The Swift class is generated from the Kotlin
data class. Kotlin parameter defaults donβt propagate, so the primary init requires all four arguments explicitly:Fields
roleβ the speaker (user,system,assistant, ortool). Usetoolwhen appending function-call results back into the history.contentβ ordered fragments. Supported part types:Text,Image(JPEG bytes wrapped in a data URL),Audio(WAV bytes orinput_audiopayload), and on KotlinAudioPcmF32for raw float samples.reasoningContentβ text emitted by reasoning models inside<think>/</think>tags.nullfor non-reasoning responses.functionCallsβ calls returned byMessageResponse.FunctionCallson the previous turn, included when appending tool-call results to history.
Serialization
Round-trip the message throughkotlinx.serialization β there is no separate βfrom [String: Any]β initializer on either platform.
- Swift (iOS / macOS)
- Kotlin (all platforms)
Encode with
LeapJson.encodeToString (or your own JSONEncoder against the OpenAI shape) and decode with the matching Kotlin serializer. See Utilities β Serialization for examples that route through LeapJson.ChatMessageContent
- Swift (iOS / macOS)
- Kotlin (all platforms)
ChatMessageContent is the Kotlin sealed class bridged to Swift β switch on its subclasses with SKIEβs onEnum(of:) helper. There is no native Swift enum, no positional .image(_:) / .audio(_:) factory, and no init(from json:). Use the static factories on the Swift overlay:fromUIImage is iOS-only and takes only the image β JPEG compression quality is hard-coded to 0.85 in the overlay (leap-sdk/src/iosMain/.../ChatMessageContentExtensionsIos.kt). There is no fromNSImage factory; on macOS, convert your NSImage to JPEG Data yourself and pass it through fromJPEGData(_:).On the wire, image parts are encoded as OpenAI-style image_url payloads (with a data:image/jpeg;base64,... URL) and audio parts as input_audio arrays with Base64 data.Textβ plain text fragment.Imageβ JPEG-encoded image bytes. Only vision-capable models can interpret image parts.Audioβ WAV-encoded audio bytes (see audio format requirements below).AudioPcmF32(Kotlin) β raw float32 mono PCM in memory. Avoids the WAV encoding step when you already have samples; the engine handles framing internally. Kotlin-only.fromFloatSamples(...)(Swift) β convenience that wraps[Float]samples into aChatMessageContent.AudioWAV blob (viaFloatAudioBuffer.makeAudioContent()). Different from KotlinβsAudioPcmF32: this one DOES re-encode through WAV. There is no Swift surface for rawAudioPcmF32today.
Audio format requirements
The LEAP inference engine expects WAV-encoded audio with these specifications:
Supported PCM encodings
- Float32 β 32-bit floating point, normalized to [-1.0, 1.0]
- Int16 β 16-bit signed integer (recommended)
- Int24 β 24-bit signed integer
- Int32 β 32-bit signed integer
Automatic resampling. The engine resamples to 16 kHz when needed, but providing 16 kHz audio directly avoids the resampling overhead. For best quality, record at 16 kHz mono.
Creating audio content
From a WAV file
- Swift (iOS / macOS)
- Kotlin (all platforms)
From raw PCM samples
- Swift (iOS / macOS)
- Kotlin (all platforms)
Recording from the microphone
- Swift (iOS / macOS)
- Kotlin (Android)
- Kotlin (JVM)
Configure
AVAudioRecorder with WAV-compatible settings:Audio duration
- Minimum β at least 1 second of audio for reliable speech recognition.
- Maximum β bounded by the modelβs context window (typically several minutes).
- Silence β trim excessive silence from the start and end for better results.
Audio output from models
Audio-capable models likeLFM2.5-Audio-1.5B emit float32 PCM frames via MessageResponse.AudioSample. Output sample rate is typically 24 kHz (vs. 16 kHz for input).
- Swift (iOS / macOS)
- Kotlin (all platforms)
Audio input should be 16 kHz; audio output from generation models is typically 24 kHz. Configure your playback pipeline accordingly.