Skip to content

Latest commit

 

History

History
209 lines (150 loc) · 7.39 KB

File metadata and controls

209 lines (150 loc) · 7.39 KB

OIR SDK

Kotlin SDK that apps depend on to call OIR capabilities. Lives at oir-sdk.

Install

Coming from JibarOS (platform-signed priv-app)

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",
    ],
}

Third-party apps

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).

Permissions

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).

Public surface

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.ocr

Plus one utility:

OpenIntelligence.isCapabilityRunnable("audio.transcribe")
    // → CapabilityStatus.RUNNABLE / NO_DEFAULT_MODEL / MODEL_MISSING / CAPABILITY_NOT_FOUND

Examples

Streaming text completion

import 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 {}

One-shot text embedding

val vec: FloatArray = OpenIntelligence.text.embed("vector me")
// vec.size == 384 for MiniLM

Audio transcription from a WAV file

OpenIntelligence.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.

Vision describe (VLM)

OpenIntelligence.vision.describeStream(
    imagePath = "/sdcard/Pictures/photo.jpg",
    prompt    = "What is happening in this image?",
    options   = DescribeOptions(maxTokens = 256),
).collect { chunk -> print(chunk.text) }

Object detection (one-shot)

val objects: List<DetectedObject> = OpenIntelligence.vision.detect(
    imagePath = "/sdcard/Pictures/photo.jpg",
)
// each DetectedObject has (x, y, width, height, label, score)

Cancellation

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.

Error model

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 {}.

Testing

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.

Java interop

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)      { … }
});

Naming: OpenIntelligence (public) vs Oir* (internal)

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).

See also