Package-level declarations

Types

Link copied to clipboard
sealed interface AiChunk

One increment of a AiProvider.completeStream reply.

Link copied to clipboard
data class AiConfig(val maxTokens: Int = 256, val temperature: Float = 0.7f, val timeoutMs: Long)
Link copied to clipboard
data class AiMessage(val role: AiMessage.Role, val content: String)
Link copied to clipboard
interface AiProvider

A cloud (or on-device) chat-completion backend — one turn in, one text reply out.

Link copied to clipboard
data class AiProviderConfig(val selectedProvider: ProviderId = ProviderId.OFFLINE_FALLBACK, val anthropicKey: String? = null, val openAiKey: String? = null, val geminiKey: String? = null, val useOnDevice: Boolean = false)
Link copied to clipboard
class AnthropicProvider(apiKey: String, engine: HttpClientEngine = httpClientEngine()) : AiProvider
Link copied to clipboard
class GeminiProvider(apiKey: String, engine: HttpClientEngine = httpClientEngine()) : AiProvider
Link copied to clipboard
data class HttpChatConfig(val endpoint: String, val mode: String? = null, val route: String? = null, val originHeader: String? = null, val requireDoneSentinel: Boolean = false)

Config for HttpChatProvider: the caller's own SSE chat backend, not a named vendor.

Link copied to clipboard
class HttpChatProvider(httpConfig: HttpChatConfig, engine: HttpClientEngine = httpClientEngine()) : AiProvider

AiProvider over a caller-supplied HTTP endpoint speaking the same data: <json> / data: [DONE] SSE contract as AnthropicProvider/OpenAiProvider/GeminiProvider — the shape cv-siddharth-kmp and Candidai were each hand-rolling their own parser for. Every reply frame decodes as HttpChatStreamEvent; the backend is expected to emit {"text":"..."} per token and close the stream (optionally preceded by a data: [DONE] line, discarded rather than decoded) rather than any vendor-specific event shape. See HttpChatConfig.requireDoneSentinel for a backend whose [DONE] isn't actually optional.

Link copied to clipboard
class OpenAiProvider(apiKey: String, engine: HttpClientEngine = httpClientEngine()) : AiProvider
Link copied to clipboard
enum class ProviderId : Enum<ProviderId>

Which provider a consumer has selected + the keys needed to build the fallback chain (buildProviderChain). ON_DEVICE and OFFLINE_FALLBACK are the two slots every consumer plugs their own AiProvider into (buildProviderChain's onDevice/fallback params) — this module doesn't ship either implementation. Naming ANTHROPIC/OPENAI/GEMINI here moves that provider to the front of buildProviderChain's cloud chain, ahead of the fixed priority order.

Link copied to clipboard
actual class SecureKeyStore

Backed by :settings's EncryptedSharedPreferences (MasterKey.AES256_GCM) store.

expect class SecureKeyStore

Where a BYOK provider API key persists between app launches.

actual class SecureKeyStore

Backed by :settings's KeychainSettings (service com.siddharth.kmp.secure).

actual class SecureKeyStore

Backed by :settings's AES-256-GCM-encrypted PropertiesSettings file (default ~/.kmp-toolkit-secure/secure_settings.enc, key file beside it, 0600).

actual class SecureKeyStore

Not secure. window.sessionStorage is plaintext, readable by any script running on the same page (including an XSS payload), and survives only the current tab's lifetime — closing the tab or opening a new one loses the key. This exists so a browser demo has somewhere to put a pasted key rather than re-prompting on every reload of the same tab; it is not the Keystore/ Keychain guarantee the other three platforms give.

Functions

Link copied to clipboard
fun buildProviderChain(config: AiProviderConfig, fallback: AiProvider, onDevice: AiProvider? = null): List<AiProvider>

Builds the provider fallback chain from config: on-device first (if enabled and onDevice is supplied) → configured cloud providers → fallback last. config.selectedProvider, when it names a cloud provider with a non-blank key, is moved to the front of the cloud group so picking a provider actually tries it first; the remaining configured providers still follow as fallbacks, in the fixed Anthropic > OpenAI > Gemini order (a no-op when nothing is selected, since ProviderId.OFFLINE_FALLBACK and ProviderId.ON_DEVICE match no cloud entry). onDevice and fallback are caller-supplied rather than hardcoded — this module ships no on-device LLM or app-specific offline fallback of its own.

Link copied to clipboard
suspend fun AiProvider.completeOrBlank(messages: List<AiMessage>, config: AiConfig = AiConfig()): String

Bridge for callers not yet migrated off the pre-AiResult complete(): collapses every AiFailure back to "", matching the old runCatching { }.getOrElse { "" } behavior.

Link copied to clipboard
suspend fun firstAvailable(chain: List<AiProvider>, fallback: AiProvider): AiProvider

Returns the first available provider in chain, or fallback if none report available.

Link copied to clipboard
fun loadAiProviderConfig(getKey: (ProviderId) -> String?, selectedProvider: ProviderId = ProviderId.OFFLINE_FALLBACK, useOnDevice: Boolean = false): AiProviderConfig

Builds an AiProviderConfig from whatever getKey returns for each cloud provider — the read side of SecureKeyStore.setKey, so a settings screen's "save key" action and buildProviderChain's "read keys" side stay in sync without the app gluing them together itself. Takes a plain function rather than a SecureKeyStore so this stays testable with a fake map in commonTest without needing a real platform store; pass store::getKey at the call site.