> ## Documentation Index
> Fetch the complete documentation index at: https://liquidai-alay2shah-sync-notebook-snippets.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Utilities

> API reference for error handling, serialization, and utilities in the LEAP Android SDK

## Error Handling

All errors are thrown as `LeapException`, which has following subclasses:

* `LeapModelLoadingException` : error in loading the model
* `LeapGenerationException` : error in generating content
* `LeapGenerationPromptExceedContextLengthException`: the prompt text exceeds the maximum context length so no content will be generated
* `LeapSerializationException` : error in serializing / deserializing data.

## Serialization Support

The LEAP SDK uses [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) for JSON serialization and deserialization. This is built into the core SDK and requires no additional dependencies.

The following types are `@Serializable`:

* [`ChatMessage`](./messages-content#chatmessage)
* [`ChatMessageContent`](./messages-content#chatmessagecontent)
* [`LeapFunctionCall`](./function-calling)
* [`Manifest`](./model-loading#manifest)

### Serializing and Deserializing Conversation History

**Add kotlinx.serialization to your project:**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
// app/build.gradle.kts
plugins {
    id("org.jetbrains.kotlin.plugin.serialization") version "2.3.10"
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
}
```

**Save conversation history:**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString

val json = Json { ignoreUnknownKeys = true }

// Serialize to JSON string
val jsonString = json.encodeToString(conversation.history)

// Save to SharedPreferences, file, database, etc.
sharedPreferences.edit().putString("conversation_history", jsonString).apply()
```

**Restore conversation history:**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
import kotlinx.serialization.decodeFromString

// Load from storage
val jsonString = sharedPreferences.getString("conversation_history", null)

if (jsonString != null) {
    val history = json.decodeFromString<List<ChatMessage>>(jsonString)
    val restoredConversation = modelRunner.createConversationFromHistory(history)
}
```

**Serialize single message:**

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
val message = ChatMessage(
    role = ChatMessage.Role.USER,
    content = listOf(ChatMessageContent.Text("Hello"))
)

val messageJson = json.encodeToString(message)
```

## LeapModelDownloader (Android)

<Info>
  `LeapModelDownloader` is the **recommended** option for Android applications. It provides background downloads with WorkManager, foreground service notifications, and robust handling of network interruptions.
</Info>

The LeapSDK Android Model Downloader module is a production-ready helper for downloading models from the LEAP Model Library on Android. It runs as a [foreground service](https://developer.android.com/develop/background-work/services/fgs) and displays notifications to users during downloads.

### Permission Setup

The model downloader requires notification permissions to display download progress. You need to:

1. **Add permissions to AndroidManifest.xml**:

```xml theme={"theme":{"light":"github-light","dark":"github-dark"}}
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
```

2. **Request notification permission at runtime** (Android 13+):

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
// In your Activity
private val requestPermissionLauncher = registerForActivityResult(
    ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
    if (isGranted) {
        Log.d(TAG, "Notification permission granted")
        // Proceed with download
    } else {
        Log.w(TAG, "Notification permission denied")
        // Handle permission denial
    }
}

// Before downloading
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    if (ContextCompat.checkSelfPermission(
            this,
            android.Manifest.permission.POST_NOTIFICATIONS
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        requestPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)
    }
}
```

### Installation

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
// In build.gradle.kts
dependencies {
  implementation("ai.liquid.leap:leap-sdk:0.9.7")
  implementation("ai.liquid.leap:leap-model-downloader:0.9.7")
}
```

### Basic Usage

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
import ai.liquid.leap.model_downloader.LeapModelDownloader
import ai.liquid.leap.model_downloader.LeapModelDownloaderNotificationConfig

// Initialize (in onCreate or similar)
val modelDownloader = LeapModelDownloader(
    context,
    notificationConfig = LeapModelDownloaderNotificationConfig.build {
        notificationTitleDownloading = "Downloading AI model..."
        notificationTitleDownloaded = "Model ready!"
        notificationContentDownloading = "Please wait..."
    }
)

// Download and load model
lifecycleScope.launch {
    try {
        val modelRunner = modelDownloader.loadModel(
            modelSlug = "LFM2-1.2B",
            quantizationSlug = "Q5_K_M",
            progress = { progressData ->
                Log.d(TAG, "Progress: ${progressData.progress * 100}%")
            }
        )
        // Model is ready to use
    } catch (e: Exception) {
        Log.e(TAG, "Failed to load model: ${e.message}")
    }
}
```

### API Reference

### LeapModelDownloader

`LeapModelDownloader` is the instance to make request of downloading models and to query the status of a model download request.

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
class LeapModelDownloader(
    private val context: Context,
    modelFileDir: File? = null,
    private val extraHTTPRequestHeaders: Map<String, String> = mapOf(),
    private val notificationConfig: LeapModelDownloaderNotificationConfig = LeapModelDownloaderNotificationConfig(),
) {
  fun getModelFile(model: DownloadableModel): File
  fun requestDownloadModel(model: DownloadableModel, forceDownload: Boolean = false)
  fun requestStopDownload(model: DownloadableModel)
  suspend fun queryStatus(model: DownloadableModel): ModelDownloadStatus
  fun requestStopService()
}
```

#### Constructor parameters

* `context`: The Android context to retrieve cache directory and launch services. The activity context works for this purpose.
* `modelFileDir`: The path to store model files. If it is not set, a path in the app's external file dir will be used.
* `extraHTTPRequestHeaders`: Any extra HTTP request headers to send when downloading a model.
* `notificationConfig`: Configuration on the content of Android notifications visible to the users.

#### getModelFile

Return a file object of the model file based on the `DownloadableModel` instance. The file may not exists.

#### requestDownloadModel

Make a request to download the model. If the model file already exists locally, it won't be downloaded.

* `model`: A [`DownloadableModel`](#downloadablemodel) instance.
* `forceDownload`: If it's true, downloader will remove the model bundle file that exists locally and to conduct the download.

#### requestStopDownload

Make a request to stop downloading a model.

#### queryStatus

Query the status of the model. The return value is a `ModelDownloadStatus` object:

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
sealed interface ModelDownloadStatus {
  data object NotOnLocal: ModelDownloadStatus
  data class DownloadInProgress(
    val totalSizeInBytes: Long,
    val downloadedSizeInBytes: Long,
  ): ModelDownloadStatus
  data class Downloaded(
    val totalSizeInBytes: Long,
  ) : ModelDownloadStatus
}
```

There are three possible value types:

* `NotOnLocal` The model file has not been downloaded or has already been deleted.
* `DownloadInProgress` The model file is still being downloaded. `totalSizeInBytes` is the total size of the file and `downloadedSizeInBytes` is the size of downloaded portion. If the total size is not available, `totalSizeInBytes` will be -1.
* `Downloaded` The file has been downloaded. `totalSizeInBytes` is the file size.

#### requestStopService

Make a request to stop the foreground service of the model downloader.

### DownloadableModel

`DownloadableModel` is an interface to describe the model can be downloaded by the LeapSDK Model Downloader.

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
interface DownloadableModel {
  val uri: Uri
  val name: String
  val localFilename: String
}
```

* `uri`: The URI of the model to download.
* `name`: A user-friendly name of the model. It will be displayed in the notification.
* `localFilename`: The filename to store the model bundle file locally.

### LeapDownloadableModel

`LeapDownloadableModel` implements [`DownloadableModel`](#downloadablemodel).
It is designed to download models from Leap Model Library. `resolve` method is provided to retrieve the model
from Leap Model Library.

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
class LeapDownloadableModel {
  companion object {
    suspend fun resolve(modelSlug: String, quantizationSlug: String) : LeapDownloadableModel?
  }
}
```

The `resolve` method accepts 2 parameters:

* `modelSlug`: The model slug that identifies the model. It is usually the lowercase string of the model name. For example, the slug of `LFM2-1.2B` is `lfm2-1.2b`.
* `quantizationSlug`: The model quantization slug. It can be found in the "Available quantizations" section of the model card.
