Kotlin SDK that apps depend on to call OIR capabilities. Lives at oir-sdk.
android_app {
name: "MyOirApp",
srcs: ["src/**/*.kt"],
platform_apis: true,
privileged: true,
certificate: "platform",
static_libs: [
"oir_sdk",
"oir_sdk_aosp", // AIDL companion — provides the binder adapter
"kotlinx-coroutines-android",
],
}Apps declaring <uses-permission android:name="oir.permission.USE_TEXT" /> (etc.) on a JibarOS device can consume the SDK via the published AAR (ships as part of the JibarOS SDK distribution, TBD).
Declare in your AndroidManifest.xml:
<uses-permission android:name="oir.permission.USE_TEXT" />
<uses-permission android:name="oir.permission.USE_AUDIO" />
<uses-permission android:name="oir.permission.USE_VISION" />oir.permission.USE_* are signature|privileged permissions. Platform-signed apps auto-grant; others need manual grant via PackageManager (OEM-specific flow).
Everything hangs off the Oir object.
import com.oir.OpenIntelligence
import android.app.Application
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
OpenIntelligence.installContext(this) // one-time bootstrap per process
}
}Three top-level namespaces:
OpenIntelligence.text // text.complete, text.translate, text.embed, text.classify, text.rerank
OpenIntelligence.audio // audio.transcribe, audio.synthesize, audio.vad
OpenIntelligence.vision // vision.describe, vision.detect, vision.embed, vision.ocrPlus one utility:
OpenIntelligence.isCapabilityRunnable("audio.transcribe")
// → CapabilityStatus.RUNNABLE / NO_DEFAULT_MODEL / MODEL_MISSING / CAPABILITY_NOT_FOUNDimport kotlinx.coroutines.flow.*
val options = CompletionOptions(maxTokens = 128, temperature = 0.7f)
OpenIntelligence.text.completeStream("Summarize in one sentence: …", options)
.onEach { chunk -> print(chunk.text) } // Flow<TextChunk>
.collect {}val vec: FloatArray = OpenIntelligence.text.embed("vector me")
// vec.size == 384 for MiniLMOpenIntelligence.audio.transcribeStream("/product/etc/oir/voice-sample.wav")
.collect { chunk -> println(chunk.text) }The WAV must be 16-bit PCM, mono, 16 kHz. The SDK validates this before sending and throws OirInvalidInputException on mismatch.
OpenIntelligence.vision.describeStream(
imagePath = "/sdcard/Pictures/photo.jpg",
prompt = "What is happening in this image?",
options = DescribeOptions(maxTokens = 256),
).collect { chunk -> print(chunk.text) }val objects: List<DetectedObject> = OpenIntelligence.vision.detect(
imagePath = "/sdcard/Pictures/photo.jpg",
)
// each DetectedObject has (x, y, width, height, label, score)Every suspend/Flow is structured-concurrency-aware. Cancel by cancelling the coroutine:
val job = lifecycleScope.launch {
OpenIntelligence.text.completeStream("…").collect { /* … */ }
}
// Later…
job.cancel() // Streams stop, oird cleans up the in-flight request.Under the hood, cancellation sends ICancellationSignal.cancel() to OIRService → oird, which aborts the current llama_decode / whisper_full / ORT::Run loop at the next checkpoint.
Every SDK call throws subclasses of OirException:
| Exception | Meaning | Typical cause |
|---|---|---|
OirInvalidInputException |
Input failed validation | Wrong WAV format, empty prompt, missing file |
OirModelErrorException |
Model load / inference failed | GGUF corrupt, ONNX shape mismatch |
OirCapabilityUnavailableException |
Capability declared but no model available | MODEL_MISSING or NO_DEFAULT_MODEL state |
OirPermissionDeniedException |
Missing oir.permission.USE_* |
Not platform-signed, not granted |
OirWorkerUnavailableException |
oird not reachable | Worker crashed mid-flight / not attached yet |
OirThrottledException |
Per-UID rate limit tripped | >60 reqs/min sustained. Exposes retryAfterMs (real wait until the next token, computed by RateLimiter.nextTokenWaitMs). Apps can catch + retry, or pass retryThrottle: Int = N to any suspend capability method (OpenIntelligence.text.complete(prompt, options, retryThrottle = 3)) to opt into automatic retry up to N times, respecting retryAfterMs between attempts. |
OirCancelledException |
Cancelled via coroutine cancellation | Expected; swallow or re-throw |
Streaming APIs throw from within their Flow; catch via try { … } catch (e: OirException) { … } around the .collect {}.
The SDK ships a fake implementation for unit tests:
import com.oir.testing.OirFake
import com.oir.testing.OirTestRule
class MyTest {
@get:Rule val oirRule = OirTestRule()
@Test fun completeStream_emitsExpectedChunks() = runTest {
oirRule.fake.text.completeStreamReturns("hello world".toTextChunks())
val result = OpenIntelligence.text.completeStream("prompt")
.toList().joinToString("") { it.text }
assertEquals("hello world", result)
}
}OirFake exposes programmable stubs for every capability. Tests don't need a JibarOS device; the fake replaces the binder adapter in-process.
Every Kotlin coroutine API has a Java-friendly blocking / callback wrapper under com.oir.java.*:
import com.oir.java.OirJavaText;
// Blocking — runs on the caller's thread, blocks until done.
String result = OirJavaText.complete(prompt, options);
// Async callback
OirJavaText.completeStream(prompt, options, new TextChunkCallback() {
@Override public void onChunk(TextChunk chunk) { … }
@Override public void onComplete(long totalMs) { … }
@Override public void onError(Throwable t) { … }
});The customer-facing entry point is OpenIntelligence — readable, branded, the name to use in app code. Internal helper classes that consumers may touch (errors, testing fakes, Java-interop facades) keep an Oir prefix:
| Public surface | Internal helpers |
|---|---|
OpenIntelligence.text.* |
OirException + subclasses (errors namespace) |
OpenIntelligence.audio.* |
OirFake, OirTestRule (testing namespace) |
OpenIntelligence.vision.* |
OirJavaText, OirJavaAudio, OirJavaVision (Java interop wrappers) |
OpenIntelligence.installContext |
OirContextProvider, OirImpl, OirBinderAdapter (internal package) |
The split mirrors how ML Kit reads — MLKit.vision.detect(...) is the public class, but its package is com.google.mlkit.* and its internal types are still Mlkit*Foo. The Kotlin package path here is com.oir.* for the same reason (matches OS-level identifiers like oir.permission.USE_*, oir_worker binder service, /vendor/etc/oir/oir_config.xml).
CAPABILITIES.md— capability shapes, permissions, defaultsKNOBS.md— per-request options + OEM tuningoir-demo— reference app