1 name: Release SDK Kotlin (Maven Central)
2
3 on:
4 push:
5 tags:
6 - "[0-9]+.[0-9]+.[0-9]+"
7 workflow_dispatch:
8
9 permissions:
10 contents: write
11
12 jobs:
13 publish:
14 name: Build and publish KMP library to Maven Central
15 runs-on: macos-15
16
17 env:
18 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
19 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
20 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
21 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
22 HF_TOKEN: ${{ secrets.HF_TOKEN }}
23
24 steps:
25 - name: Checkout
26 uses: actions/checkout@v6
27
28 # ── Java ──────────────────────────────────────────────────────────────────
29 - name: Set up JDK 17
30 uses: actions/setup-java@v4
31 with:
32 java-version: "17"
33 distribution: temurin
34
35 # ── Gradle ───────────────────────────────────────────────────────────────
36 - name: Set up Gradle
37 uses: gradle/actions/setup-gradle@v3
38 with:
39 gradle-version: wrapper
40 build-root-directory: sdk/kotlin
41
42 # ── Rust ──────────────────────────────────────────────────────────────────
43 - name: Install stable Rust toolchain
44 uses: dtolnay/rust-toolchain@stable
45 with:
46 targets: >-
47 aarch64-linux-android,
48 armv7-linux-androideabi,
49 x86_64-linux-android,
50 i686-linux-android,
51 aarch64-apple-darwin
52
53 - name: Cache Rust build artifacts
54 uses: actions/cache@v4
55 with:
56 path: |
57 ~/.cargo/registry
58 ~/.cargo/git
59 target/
60 key: rust-kotlin-sdk-${{ hashFiles('Cargo.toml', 'Cargo.lock', 'src/**/*.rs') }}
61 restore-keys: rust-kotlin-sdk-
62
63 # ── Android NDK ───────────────────────────────────────────────────────────
64 - name: Install Android NDK 29
65 run: |
66 echo "y" | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager \
67 "ndk;29.0.13113456" || true
68 # Fall back to whatever 29.x is already installed
69 NDK_PATH=$(ls -d $ANDROID_SDK_ROOT/ndk/29.* 2>/dev/null | sort -V | tail -1)
70 if [ -z "$NDK_PATH" ]; then
71 echo "Error: No NDK 29.x found"
72 exit 1
73 fi
74 echo "ANDROID_NDK_HOME=$NDK_PATH" >> "$GITHUB_ENV"
75 echo "Using NDK: $NDK_PATH"
76
77 - name: Install cargo-ndk
78 run: cargo install cargo-ndk --locked
79
80 # ── Native builds ─────────────────────────────────────────────────────────
81 - name: Build Android .so files (all 4 ABIs)
82 run: |
83 chmod +x sdk/kotlin/scripts/build-android.sh
84 sdk/kotlin/scripts/build-android.sh
85
86 - name: Build JVM native library (macOS Apple Silicon)
87 run: |
88 chmod +x sdk/kotlin/scripts/build-jvm.sh
89 sdk/kotlin/scripts/build-jvm.sh
90
91 # ── UniFFI bindings ───────────────────────────────────────────────────────
92 - name: Build uniffi-bindgen
93 run: cargo build --manifest-path uniffi-bindgen/Cargo.toml --release
94
95 - name: Generate Kotlin UniFFI bindings
96 run: |
97 chmod +x sdk/kotlin/scripts/generate-bindings.sh
98 sdk/kotlin/scripts/generate-bindings.sh
99
100 # ── Verify ────────────────────────────────────────────────────────────────
101 - name: Verify build inputs
102 run: |
103 echo "=== Android JNI libs ==="
104 find sdk/kotlin/lib/src/androidMain/jniLibs -name "*.so" | sort
105
106 echo "=== JVM native libs ==="
107 find sdk/kotlin/lib/src/jvmMain/resources/native -type f | sort
108
109 echo "=== UniFFI bindings ==="
110 ls -lh sdk/kotlin/lib/src/generated/kotlin/uniffi/onde/
111
112 # ── Version validation ────────────────────────────────────────────────────
113 - name: Validate tag matches Cargo.toml version
114 if: startsWith(github.ref, 'refs/tags/')
115 run: |
116 TAG="${GITHUB_REF#refs/tags/}"
117 CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/version = "//;s/"//')
118 GRADLE_VERSION=$(grep '^VERSION_NAME' sdk/kotlin/gradle.properties | sed 's/VERSION_NAME=//')
119 echo "Tag: $TAG"
120 echo "Cargo.toml: $CARGO_VERSION"
121 echo "gradle.properties: $GRADLE_VERSION"
122 if [ "$TAG" != "$CARGO_VERSION" ]; then
123 echo "::error::Tag '$TAG' does not match Cargo.toml version '$CARGO_VERSION'."
124 exit 1
125 fi
126 if [ "$TAG" != "$GRADLE_VERSION" ]; then
127 echo "::error::Tag '$TAG' does not match gradle.properties VERSION_NAME '$GRADLE_VERSION'."
128 exit 1
129 fi
130
131 # ── Publish ───────────────────────────────────────────────────────────────
132 - name: Dry-run publish (always)
133 working-directory: sdk/kotlin
134 run: ./gradlew :lib:publishToMavenCentral --dry-run --no-configuration-cache
135
136 - name: Publish and release to Maven Central (tag push only)
137 if: startsWith(github.ref, 'refs/tags/')
138 working-directory: sdk/kotlin
139 env:
140 ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.ORG_GRADLE_PROJECT_MAVENCENTRALUSERNAME }}
141 ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.ORG_GRADLE_PROJECT_MAVENCENTRALPASSWORD }}
142 ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEYID }}
143 ORG_GRADLE_PROJECT_signingKey: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEY }}
144 ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD }}
145 run: ./gradlew :lib:publishAndReleaseToMavenCentral --no-configuration-cache
146
147 # ── Artifacts ────────────────────────────────────────────────────────────
148 - name: Collect build outputs
149 run: |
150 mkdir -p dist/kotlin
151 find sdk/kotlin/lib/build/outputs/aar -name "*.aar" -exec cp {} dist/kotlin/ \;
152 find sdk/kotlin/lib/build/libs -name "*.jar" -exec cp {} dist/kotlin/ \;
153
154 - name: Upload build outputs as workflow artifact
155 uses: actions/upload-artifact@v4
156 with:
157 name: onde-inference-kotlin-${{ github.ref_name }}
158 path: dist/kotlin/
159 retention-days: 90
160
161 # ── GitHub Release ────────────────────────────────────────────────────────
162 - name: Create GitHub Release
163 if: startsWith(github.ref, 'refs/tags/')
164 uses: softprops/action-gh-release@v2
165 with:
166 tag_name: ${{ github.ref_name }}
167 name: Kotlin SDK ${{ github.ref_name }}
168 body: |
169 ## Onde Inference Kotlin SDK ${{ github.ref_name }}
170
171 On-device LLM inference for **Android** and **JVM (macOS Apple Silicon)**.
172
173 ### Add to your project
174
175 ```kotlin
176 // build.gradle.kts
177 dependencies {
178 implementation("com.ondeinference:onde-inference:${{ github.ref_name }}")
179 }
180 ```
181
182 ### What's included
183
184 | Target | Backend | Default model |
185 |--------|---------|---------------|
186 | Android (`arm64-v8a`, `armeabi-v7a`, `x86_64`, `x86`) | CPU (Candle) | Qwen 2.5 1.5B (~941 MB) |
187 | JVM (macOS Apple Silicon) | Metal | Qwen 2.5 3B (~1.93 GB) |
188
189 ### Usage
190
191 ```kotlin
192 // Android
193 val onde = OndeInference(applicationContext)
194
195 // JVM (macOS)
196 val onde = OndeInference()
197
198 // Shared API
199 val elapsed = onde.loadDefaultModel(systemPrompt = "You are helpful.")
200 val result = onde.chat("Hello!")
201 onde.stream("Tell me a story.").collect { chunk -> print(chunk.delta) }
202 ```
203
204 See the [README](https://github.com/ondeinference/onde/tree/main/sdk/kotlin/README.md) for full API docs.
205 files: dist/kotlin/*
206 draft: false
207 prerelease: false