Skip to content

Commit 25e26e0

Browse files
[AI] Add configurable model generation for AI On-Device (#8043)
Introduced `GenerationConfig`, `ModelConfig`, `ModelReleaseStage`, and `ModelPreference` to `firebase-ai-ondevice-interop` to allow for configurable model selection. Updated the internal `genaiPrompt` dependency to `1.0.0-beta2` to support the new configuration options. Deprecated the parameter-less `FirebaseAIOnDeviceGenerativeModelFactory.newGenerativeModel()` method in favor of a new overload that accepts a `GenerationConfig`. --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent e5d6670 commit 25e26e0

17 files changed

Lines changed: 325 additions & 19 deletions

File tree

ai-logic/firebase-ai-ondevice-interop/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- [feature] Added support for model selection, required for nano-v4. (#8043)
4+
35
# 16.0.0-beta01
46

57
- [feature] Initial release.

ai-logic/firebase-ai-ondevice-interop/api.txt

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ package com.google.firebase.ai.ondevice.interop {
3636
}
3737

3838
public interface FirebaseAIOnDeviceGenerativeModelFactory {
39-
method public com.google.firebase.ai.ondevice.interop.GenerativeModel newGenerativeModel();
39+
method @Deprecated public com.google.firebase.ai.ondevice.interop.GenerativeModel newGenerativeModel();
40+
method public com.google.firebase.ai.ondevice.interop.GenerativeModel newGenerativeModel(com.google.firebase.ai.ondevice.interop.GenerationConfig? generationConfig);
4041
}
4142

4243
public final class FirebaseAIOnDeviceInvalidRequestException extends com.google.firebase.ai.ondevice.interop.FirebaseAIOnDeviceException {
@@ -75,6 +76,12 @@ package com.google.firebase.ai.ondevice.interop {
7576
property public final java.util.List<com.google.firebase.ai.ondevice.interop.Candidate> candidates;
7677
}
7778

79+
public final class GenerationConfig {
80+
ctor public GenerationConfig(com.google.firebase.ai.ondevice.interop.ModelConfig modelConfig);
81+
method public com.google.firebase.ai.ondevice.interop.ModelConfig getModelConfig();
82+
property public final com.google.firebase.ai.ondevice.interop.ModelConfig modelConfig;
83+
}
84+
7885
public interface GenerativeModel {
7986
method public suspend Object? countTokens(com.google.firebase.ai.ondevice.interop.GenerateContentRequest request, kotlin.coroutines.Continuation<? super com.google.firebase.ai.ondevice.interop.CountTokensResponse>);
8087
method public suspend Object? generateContent(com.google.firebase.ai.ondevice.interop.GenerateContentRequest request, kotlin.coroutines.Continuation<? super com.google.firebase.ai.ondevice.interop.GenerateContentResponse>);
@@ -91,6 +98,24 @@ package com.google.firebase.ai.ondevice.interop {
9198
property public final android.graphics.Bitmap bitmap;
9299
}
93100

101+
public final class ModelConfig {
102+
ctor public ModelConfig(com.google.firebase.ai.ondevice.interop.ModelReleaseStage releaseStage = com.google.firebase.ai.ondevice.interop.ModelReleaseStage.STABLE, com.google.firebase.ai.ondevice.interop.ModelPreference preference = com.google.firebase.ai.ondevice.interop.ModelPreference.FULL);
103+
method public com.google.firebase.ai.ondevice.interop.ModelPreference getPreference();
104+
method public com.google.firebase.ai.ondevice.interop.ModelReleaseStage getReleaseStage();
105+
property public final com.google.firebase.ai.ondevice.interop.ModelPreference preference;
106+
property public final com.google.firebase.ai.ondevice.interop.ModelReleaseStage releaseStage;
107+
}
108+
109+
public enum ModelPreference {
110+
enum_constant public static final com.google.firebase.ai.ondevice.interop.ModelPreference FAST;
111+
enum_constant public static final com.google.firebase.ai.ondevice.interop.ModelPreference FULL;
112+
}
113+
114+
public enum ModelReleaseStage {
115+
enum_constant public static final com.google.firebase.ai.ondevice.interop.ModelReleaseStage PREVIEW;
116+
enum_constant public static final com.google.firebase.ai.ondevice.interop.ModelReleaseStage STABLE;
117+
}
118+
94119
public interface Part {
95120
}
96121

ai-logic/firebase-ai-ondevice-interop/src/main/kotlin/com/google/firebase/ai/ondevice/interop/FirebaseAIOnDeviceGenerativeModelFactory.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,19 @@ public interface FirebaseAIOnDeviceGenerativeModelFactory {
2828
*
2929
* @return A new [GenerativeModel] instance ready for use.
3030
*/
31+
@Deprecated(
32+
message = "Use newGenerativeModel(GenerationConfig?) instead",
33+
replaceWith = ReplaceWith("newGenerativeModel(null)")
34+
)
3135
public fun newGenerativeModel(): GenerativeModel
36+
37+
/**
38+
* Creates and returns a new instance of [GenerativeModel] optionally configured with
39+
* [GenerationConfig].
40+
*
41+
* @param generationConfig The configuration for the model, `null` if the default configuration
42+
* should be used.
43+
* @return A new [GenerativeModel] instance ready for use.
44+
*/
45+
public fun newGenerativeModel(generationConfig: GenerationConfig?): GenerativeModel
3246
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.ai.ondevice.interop
18+
19+
public class GenerationConfig(public val modelConfig: ModelConfig) {
20+
override fun toString(): String = "GenerationConfig(modelConfig=$modelConfig)"
21+
22+
override fun equals(other: Any?): Boolean =
23+
other is GenerationConfig && modelConfig == other.modelConfig
24+
25+
override fun hashCode(): Int = modelConfig.hashCode() ?: 0
26+
}
27+
28+
/**
29+
* Configuration parameters for model selection.
30+
*
31+
* @property releaseStage The release stage of the model to use.
32+
* @property preference The performance preference for the model.
33+
*/
34+
public class ModelConfig(
35+
public val releaseStage: ModelReleaseStage = ModelReleaseStage.STABLE,
36+
public val preference: ModelPreference = ModelPreference.FULL,
37+
) {
38+
override fun equals(other: Any?): Boolean =
39+
other is ModelConfig && releaseStage == other.releaseStage && preference == other.preference
40+
41+
override fun hashCode(): Int {
42+
var result = releaseStage.hashCode()
43+
result = 31 * result + preference.hashCode()
44+
return result
45+
}
46+
47+
override fun toString(): String {
48+
return "ModelConfig(releaseStage=$releaseStage, preference=$preference)"
49+
}
50+
}
51+
/** Defines the release stage of the model. */
52+
public enum class ModelReleaseStage {
53+
/**
54+
* Selects the latest model version that is fully tested and on consumer devices. This is the
55+
* default setting.
56+
*/
57+
STABLE,
58+
59+
/**
60+
* Selects the latest model version in the preview stage. This stage lets you test beta features
61+
* or newer model architectures before they are widely deployed.
62+
*/
63+
PREVIEW,
64+
}
65+
66+
/** Defines the performance preference for the model. */
67+
public enum class ModelPreference {
68+
/** Recommended when model accuracy and full capabilities are prioritized over speed. */
69+
FULL,
70+
71+
/** Recommended for latency-sensitive apps that require minimal response times. */
72+
FAST,
73+
}

ai-logic/firebase-ai-ondevice/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- [feature] Added support for model selection, required for nano-v4. (#8043)
4+
35
# 16.0.0-beta01
46

57
- [feature] Initial release.

ai-logic/firebase-ai-ondevice/api.txt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,21 @@ package com.google.firebase.ai.ondevice {
2525
}
2626

2727
public final class FirebaseAIOnDevice {
28-
method public suspend Object? checkStatus(kotlin.coroutines.Continuation<? super com.google.firebase.ai.ondevice.OnDeviceModelStatus>);
29-
method public kotlinx.coroutines.flow.Flow<com.google.firebase.ai.ondevice.DownloadStatus> download();
28+
method public suspend Object? checkStatus(com.google.firebase.ai.ondevice.OnDeviceModelOption option, kotlin.coroutines.Continuation<? super com.google.firebase.ai.ondevice.OnDeviceModelStatus>);
29+
method public kotlinx.coroutines.flow.Flow<com.google.firebase.ai.ondevice.DownloadStatus> download(com.google.firebase.ai.ondevice.OnDeviceModelOption option);
3030
field public static final com.google.firebase.ai.ondevice.FirebaseAIOnDevice INSTANCE;
3131
}
3232

33+
public final class OnDeviceModelOption {
34+
field public static final com.google.firebase.ai.ondevice.OnDeviceModelOption.Companion Companion;
35+
field public static final com.google.firebase.ai.ondevice.OnDeviceModelOption PREVIEW;
36+
field public static final com.google.firebase.ai.ondevice.OnDeviceModelOption PREVIEW_FAST;
37+
field public static final com.google.firebase.ai.ondevice.OnDeviceModelOption STABLE;
38+
}
39+
40+
public static final class OnDeviceModelOption.Companion {
41+
}
42+
3343
public final class OnDeviceModelStatus {
3444
field public static final com.google.firebase.ai.ondevice.OnDeviceModelStatus AVAILABLE;
3545
field public static final com.google.firebase.ai.ondevice.OnDeviceModelStatus.Companion Companion;

ai-logic/firebase-ai-ondevice/firebase-ai-ondevice.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ kotlin {
6868

6969
dependencies {
7070
implementation(libs.genai.prompt)
71-
implementation("com.google.firebase:firebase-ai-ondevice-interop:16.0.0-beta01")
71+
implementation(project(":ai-logic:firebase-ai-ondevice-interop"))
7272

7373
implementation(libs.firebase.common)
7474
implementation(libs.firebase.components)

ai-logic/firebase-ai-ondevice/src/main/kotlin/com/google/firebase/ai/ondevice/Converters.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@ import com.google.firebase.ai.ondevice.interop.CountTokensResponse
2121
import com.google.firebase.ai.ondevice.interop.FinishReason
2222
import com.google.firebase.ai.ondevice.interop.FirebaseAIOnDeviceInvalidRequestException
2323
import com.google.firebase.ai.ondevice.interop.GenerateContentResponse
24+
import com.google.firebase.ai.ondevice.interop.GenerationConfig
25+
import com.google.firebase.ai.ondevice.interop.ModelConfig
2426
import com.google.mlkit.genai.prompt.GenerateContentRequest
2527
import com.google.mlkit.genai.prompt.ImagePart
28+
import com.google.mlkit.genai.prompt.ModelPreference
29+
import com.google.mlkit.genai.prompt.ModelReleaseStage
2630
import com.google.mlkit.genai.prompt.TextPart
31+
import com.google.mlkit.genai.prompt.generationConfig
32+
import com.google.mlkit.genai.prompt.modelConfig
2733

2834
// ====================================
2935
// `Part` converter extension functions
@@ -73,6 +79,34 @@ internal fun com.google.firebase.ai.ondevice.interop.GenerateContentRequest.toMl
7379
internal fun com.google.mlkit.genai.prompt.GenerateContentResponse.toInterop():
7480
GenerateContentResponse = GenerateContentResponse(candidates.map { it.toInterop() })
7581

82+
// ================================================
83+
// `GenerationConfig` converter extension functions
84+
// ================================================
85+
internal fun GenerationConfig.toMlKit(): com.google.mlkit.genai.prompt.GenerationConfig =
86+
generationConfig {
87+
this@toMlKit.modelConfig?.let { modelConfig = it.toMlKit() }
88+
}
89+
90+
// ===========================================
91+
// `ModelConfig` converter extension functions
92+
// ===========================================
93+
internal fun ModelConfig.toMlKit(): com.google.mlkit.genai.prompt.ModelConfig = modelConfig {
94+
releaseStage = this@toMlKit.releaseStage.toMlKit()
95+
preference = this@toMlKit.preference.toMlKit()
96+
}
97+
98+
private fun com.google.firebase.ai.ondevice.interop.ModelReleaseStage.toMlKit(): Int =
99+
when (this) {
100+
com.google.firebase.ai.ondevice.interop.ModelReleaseStage.PREVIEW -> ModelReleaseStage.PREVIEW
101+
com.google.firebase.ai.ondevice.interop.ModelReleaseStage.STABLE -> ModelReleaseStage.STABLE
102+
}
103+
104+
private fun com.google.firebase.ai.ondevice.interop.ModelPreference.toMlKit(): Int =
105+
when (this) {
106+
com.google.firebase.ai.ondevice.interop.ModelPreference.FULL -> ModelPreference.FULL
107+
com.google.firebase.ai.ondevice.interop.ModelPreference.FAST -> ModelPreference.FAST
108+
}
109+
76110
private fun generateContentRequest(
77111
text: com.google.firebase.ai.ondevice.interop.TextPart,
78112
image: com.google.firebase.ai.ondevice.interop.ImagePart? = null,

ai-logic/firebase-ai-ondevice/src/main/kotlin/com/google/firebase/ai/ondevice/FirebaseAIOnDevice.kt

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ package com.google.firebase.ai.ondevice
1818

1919
import com.google.firebase.ai.ondevice.interop.FirebaseAIOnDeviceException
2020
import com.google.firebase.ai.ondevice.interop.FirebaseAIOnDeviceUnknownException
21+
import com.google.firebase.ai.ondevice.interop.GenerationConfig
2122
import com.google.mlkit.genai.common.FeatureStatus
2223
import com.google.mlkit.genai.prompt.Generation
24+
import com.google.mlkit.genai.prompt.ModelPreference as MlKitModelPreference
25+
import com.google.mlkit.genai.prompt.ModelReleaseStage as MlKitModelReleaseStage
26+
import com.google.mlkit.genai.prompt.generationConfig
27+
import com.google.mlkit.genai.prompt.modelConfig
2328
import kotlinx.coroutines.flow.Flow
2429
import kotlinx.coroutines.flow.map
2530

@@ -33,10 +38,13 @@ public object FirebaseAIOnDevice {
3338
/**
3439
* Checks the current status / availability of the on-device AI model.
3540
*
41+
* @param option The configuration option for the model.
3642
* @return An [OnDeviceModelStatus] object indicating the current state of the model.
3743
*/
38-
public suspend fun checkStatus(): OnDeviceModelStatus {
39-
return OnDeviceModelStatus.fromFeatureStatus(Generation.getClient().checkStatus())
44+
public suspend fun checkStatus(option: OnDeviceModelOption): OnDeviceModelStatus {
45+
return OnDeviceModelStatus.fromFeatureStatus(
46+
Generation.getClient(option.toMlKit()).checkStatus()
47+
)
4048
}
4149

4250
/**
@@ -46,12 +54,51 @@ public object FirebaseAIOnDevice {
4654
* Consumers should collect the flow to start the download process, and optionally process any
4755
* updates on the download state, progress, and completion or failure.
4856
*
57+
* @param option The configuration option for the model.
4958
* @return A [Flow] of [DownloadStatus] objects representing the download lifecycle.
5059
*/
51-
public fun download(): Flow<DownloadStatus> =
52-
Generation.getClient().download().map { DownloadStatus.fromMlKit(it) }
60+
public fun download(option: OnDeviceModelOption): Flow<DownloadStatus> {
61+
return Generation.getClient(option.toMlKit()).download().map { DownloadStatus.fromMlKit(it) }
62+
}
5363
}
5464

65+
/** Options for configuring the on-device AI model. */
66+
public class OnDeviceModelOption private constructor(private val value: String) {
67+
override fun toString(): String = value
68+
69+
public companion object {
70+
/** Selects the latest stable model. */
71+
@JvmField public val STABLE: OnDeviceModelOption = OnDeviceModelOption("stable")
72+
73+
/** Selects the latest preview model with full performance. */
74+
@JvmField public val PREVIEW: OnDeviceModelOption = OnDeviceModelOption("preview")
75+
76+
/** Selects the latest preview model optimized for speed. */
77+
@JvmField public val PREVIEW_FAST: OnDeviceModelOption = OnDeviceModelOption("preview_fast")
78+
}
79+
}
80+
81+
internal fun OnDeviceModelOption.toMlKit(): com.google.mlkit.genai.prompt.GenerationConfig =
82+
generationConfig {
83+
modelConfig = modelConfig {
84+
when (this@toMlKit) {
85+
OnDeviceModelOption.STABLE -> {
86+
releaseStage = MlKitModelReleaseStage.STABLE
87+
preference = MlKitModelPreference.FULL
88+
}
89+
OnDeviceModelOption.PREVIEW -> {
90+
releaseStage = MlKitModelReleaseStage.PREVIEW
91+
preference = MlKitModelPreference.FULL
92+
}
93+
OnDeviceModelOption.PREVIEW_FAST -> {
94+
releaseStage = MlKitModelReleaseStage.PREVIEW
95+
preference = MlKitModelPreference.FAST
96+
}
97+
else -> throw IllegalArgumentException("Unknown option: ${this@toMlKit}")
98+
}
99+
}
100+
}
101+
55102
/** Represents the current status of the on-device AI model. */
56103
public class OnDeviceModelStatus private constructor(private val status: Int) {
57104
public companion object {

ai-logic/firebase-ai-ondevice/src/main/kotlin/com/google/firebase/ai/ondevice/FirebaseAIOnDeviceComponent.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
package com.google.firebase.ai.ondevice
1818

1919
import com.google.firebase.ai.ondevice.interop.FirebaseAIOnDeviceGenerativeModelFactory
20+
import com.google.firebase.ai.ondevice.interop.GenerationConfig
2021
import com.google.firebase.ai.ondevice.interop.GenerativeModel
22+
import com.google.mlkit.genai.prompt.Generation
2123

2224
/**
2325
* Factory class for Firebase AI OnDevice.
@@ -26,5 +28,16 @@ import com.google.firebase.ai.ondevice.interop.GenerativeModel
2628
*/
2729
internal class FirebaseAIOnDeviceComponent : FirebaseAIOnDeviceGenerativeModelFactory {
2830

29-
override fun newGenerativeModel(): GenerativeModel = GenerativeModelImpl()
31+
@Deprecated(
32+
"Use newGenerativeModel(GenerationConfig?) instead",
33+
replaceWith = ReplaceWith("newGenerativeModel(null)")
34+
)
35+
override fun newGenerativeModel(): GenerativeModel = newGenerativeModel(null)
36+
37+
override fun newGenerativeModel(generationConfig: GenerationConfig?): GenerativeModel =
38+
if (generationConfig == null) {
39+
GenerativeModelImpl(Generation.getClient())
40+
} else {
41+
GenerativeModelImpl(Generation.getClient(generationConfig.toMlKit()))
42+
}
3043
}

0 commit comments

Comments
 (0)