Skip to content

Commit 191299b

Browse files
authored
Merge 98b5c02 into cf5fe2e
2 parents cf5fe2e + 98b5c02 commit 191299b

File tree

7 files changed

+216
-9
lines changed

7 files changed

+216
-9
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2025 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.vertexai.type
18+
19+
/** Versions of the Vertex AI in Firebase server API. */
20+
public class ApiVersion private constructor(internal val value: String) {
21+
public companion object {
22+
/** The stable channel for version 1 of the API. */
23+
@JvmField public val V1: ApiVersion = ApiVersion("v1")
24+
25+
/** The beta channel for version 1 of the API. */
26+
@JvmField public val V1BETA: ApiVersion = ApiVersion("v1beta")
27+
}
28+
}

firebase-vertexai/src/main/kotlin/com/google/firebase/vertexai/type/RequestOptions.kt

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,51 @@
1717
package com.google.firebase.vertexai.type
1818

1919
import kotlin.time.Duration
20-
import kotlin.time.Duration.Companion.seconds
2120
import kotlin.time.DurationUnit
2221
import kotlin.time.toDuration
2322

2423
/** Configurable options unique to how requests to the backend are performed. */
2524
public class RequestOptions
2625
internal constructor(
2726
internal val timeout: Duration,
28-
internal val endpoint: String = "https://firebasevertexai.googleapis.com",
29-
internal val apiVersion: String = "v1beta",
27+
internal val endpoint: String = DEFAULT_ENDPOINT,
28+
internal val apiVersion: String = DEFAULT_API_VERSION.value,
3029
) {
3130

3231
/**
3332
* Constructor for RequestOptions.
3433
*
3534
* @param timeoutInMillis the maximum amount of time, in milliseconds, for a request to take, from
3635
* the first request to first response.
36+
* @param apiVersion the version of the Vertex AI in Firebase API; defaults to [ApiVersion.V1BETA]
37+
* if not specified.
3738
*/
3839
@JvmOverloads
3940
public constructor(
40-
timeoutInMillis: Long = 180.seconds.inWholeMilliseconds
41-
) : this(timeout = timeoutInMillis.toDuration(DurationUnit.MILLISECONDS))
41+
timeoutInMillis: Long = DEFAULT_TIMEOUT_IN_MILLIS,
42+
apiVersion: ApiVersion = DEFAULT_API_VERSION,
43+
) : this(
44+
timeout = timeoutInMillis.toDuration(DurationUnit.MILLISECONDS),
45+
apiVersion = apiVersion.value,
46+
)
47+
48+
/**
49+
* Constructor for RequestOptions.
50+
*
51+
* @param apiVersion the version of the Vertex AI in Firebase API; defaults to [ApiVersion.V1BETA]
52+
* if not specified.
53+
*/
54+
public constructor(
55+
apiVersion: ApiVersion
56+
) : this(
57+
timeoutInMillis = DEFAULT_TIMEOUT_IN_MILLIS,
58+
apiVersion = apiVersion,
59+
)
60+
61+
internal companion object {
62+
internal const val DEFAULT_TIMEOUT_IN_MILLIS: Long = 180_000L
63+
internal const val DEFAULT_ENDPOINT: String = "https://firebasevertexai.googleapis.com"
64+
65+
internal val DEFAULT_API_VERSION: ApiVersion = ApiVersion.V1BETA
66+
}
4267
}

firebase-vertexai/src/test/java/com/google/firebase/vertexai/GenerativeModelTesting.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ internal class GenerativeModelTesting {
6060
APIController(
6161
"super_cool_test_key",
6262
"gemini-1.5-flash",
63-
RequestOptions(timeout = 5.seconds, endpoint = "https://my.custom.endpoint"),
63+
RequestOptions(5.seconds.inWholeMilliseconds),
6464
mockEngine,
6565
TEST_CLIENT_ID,
6666
null,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2025 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.vertexai.api.java;
18+
19+
import com.google.firebase.vertexai.type.ApiVersion;
20+
import com.google.firebase.vertexai.type.RequestOptions;
21+
22+
/** Build tests for the Vertex AI in Firebase Java public API surface. */
23+
final class JavaPublicApiTests {
24+
/** {@link RequestOptions} API */
25+
void requestOptionsCodeSamples() {
26+
new RequestOptions();
27+
new RequestOptions(30_000L);
28+
new RequestOptions(ApiVersion.V1);
29+
new RequestOptions(60_000L, ApiVersion.V1BETA);
30+
}
31+
}

firebase-vertexai/src/test/java/com/google/firebase/vertexai/common/APIControllerTests.kt

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ import com.google.firebase.vertexai.common.util.commonTest
2626
import com.google.firebase.vertexai.common.util.createResponses
2727
import com.google.firebase.vertexai.common.util.doBlocking
2828
import com.google.firebase.vertexai.common.util.prepareStreamingResponse
29+
import com.google.firebase.vertexai.type.ApiVersion
2930
import com.google.firebase.vertexai.type.RequestOptions
3031
import io.kotest.assertions.json.shouldContainJsonKey
3132
import io.kotest.assertions.throwables.shouldThrow
3233
import io.kotest.matchers.shouldBe
34+
import io.kotest.matchers.shouldNotBe
3335
import io.kotest.matchers.string.shouldContain
36+
import io.kotest.matchers.string.shouldStartWith
3437
import io.ktor.client.engine.mock.MockEngine
3538
import io.ktor.client.engine.mock.respond
3639
import io.ktor.content.TextContent
@@ -74,7 +77,7 @@ internal class APIControllerTests {
7477

7578
@Test
7679
fun `(generateContent) respects a custom timeout`() =
77-
commonTest(requestOptions = RequestOptions(2.seconds)) {
80+
commonTest(requestOptions = RequestOptions(2.seconds.inWholeMilliseconds)) {
7881
shouldThrow<RequestTimeoutException> {
7982
withTimeout(testTimeout) {
8083
apiController.generateContent(textGenerateContentRequest("test"))
@@ -122,7 +125,11 @@ internal class RequestFormatTests {
122125
APIController(
123126
"super_cool_test_key",
124127
"gemini-pro-1.5",
125-
RequestOptions(timeout = 5.seconds, endpoint = "https://my.custom.endpoint"),
128+
RequestOptions(
129+
timeout = 5.seconds,
130+
endpoint = "https://my.custom.endpoint",
131+
apiVersion = "v1beta"
132+
),
126133
mockEngine,
127134
TEST_CLIENT_ID,
128135
null,
@@ -138,6 +145,36 @@ internal class RequestFormatTests {
138145
mockEngine.requestHistory.first().url.host shouldBe "my.custom.endpoint"
139146
}
140147

148+
@Test
149+
fun `using custom API version`() = doBlocking {
150+
val channel = ByteChannel(autoFlush = true)
151+
val mockEngine = MockEngine {
152+
respond(channel, HttpStatusCode.OK, headersOf(HttpHeaders.ContentType, "application/json"))
153+
}
154+
prepareStreamingResponse(createResponses("Random")).forEach { channel.writeFully(it) }
155+
val controller =
156+
APIController(
157+
"super_cool_test_key",
158+
"gemini-pro-1.5",
159+
RequestOptions(timeoutInMillis = 5.seconds.inWholeMilliseconds, apiVersion = ApiVersion.V1),
160+
mockEngine,
161+
TEST_CLIENT_ID,
162+
null,
163+
)
164+
165+
withTimeout(5.seconds) {
166+
controller.generateContentStream(textGenerateContentRequest("cats")).collect {
167+
it.candidates?.isEmpty() shouldBe false
168+
channel.close()
169+
}
170+
}
171+
172+
mockEngine.requestHistory.first().url.encodedPath shouldStartWith "/${ApiVersion.V1.value}"
173+
// TODO: Update test to set ApiVersion.V1BETA when ApiVersion.V1 becomes the default and delete
174+
// the following check.
175+
RequestOptions().apiVersion shouldNotBe ApiVersion.V1.value
176+
}
177+
141178
@Test
142179
fun `client id header is set correctly in the request`() = doBlocking {
143180
val response = JSON.encodeToString(CountTokensResponse(totalTokens = 10))
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2025 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.vertexai.type
18+
19+
import com.google.firebase.vertexai.type.RequestOptions.Companion.DEFAULT_API_VERSION
20+
import com.google.firebase.vertexai.type.RequestOptions.Companion.DEFAULT_ENDPOINT
21+
import com.google.firebase.vertexai.type.RequestOptions.Companion.DEFAULT_TIMEOUT_IN_MILLIS
22+
import io.kotest.matchers.equals.shouldBeEqual
23+
import kotlin.time.DurationUnit
24+
import kotlin.time.toDuration
25+
import org.junit.Test
26+
27+
internal class RequestOptionsTests {
28+
private val defaultTimeout = DEFAULT_TIMEOUT_IN_MILLIS.toDuration(DurationUnit.MILLISECONDS)
29+
30+
@Test
31+
fun `init default values`() {
32+
val requestOptions = RequestOptions()
33+
34+
requestOptions.timeout shouldBeEqual defaultTimeout
35+
requestOptions.endpoint shouldBeEqual DEFAULT_ENDPOINT
36+
requestOptions.apiVersion shouldBeEqual DEFAULT_API_VERSION.value
37+
}
38+
39+
@Test
40+
fun `init custom timeout`() {
41+
val expectedTimeoutInMillis = 60_000L
42+
43+
val requestOptions = RequestOptions(timeoutInMillis = expectedTimeoutInMillis)
44+
45+
requestOptions.timeout shouldBeEqual
46+
expectedTimeoutInMillis.toDuration(DurationUnit.MILLISECONDS)
47+
requestOptions.endpoint shouldBeEqual DEFAULT_ENDPOINT
48+
requestOptions.apiVersion shouldBeEqual DEFAULT_API_VERSION.value
49+
}
50+
51+
@Test
52+
fun `init API version v1`() {
53+
val expectedApiVersion = ApiVersion.V1
54+
55+
val requestOptions = RequestOptions(apiVersion = expectedApiVersion)
56+
57+
requestOptions.timeout shouldBeEqual defaultTimeout
58+
requestOptions.endpoint shouldBeEqual DEFAULT_ENDPOINT
59+
requestOptions.apiVersion shouldBeEqual expectedApiVersion.value
60+
}
61+
62+
@Test
63+
fun `init API version v1beta`() {
64+
val expectedApiVersion = ApiVersion.V1BETA
65+
66+
val requestOptions = RequestOptions(apiVersion = expectedApiVersion)
67+
68+
requestOptions.timeout shouldBeEqual defaultTimeout
69+
requestOptions.endpoint shouldBeEqual DEFAULT_ENDPOINT
70+
requestOptions.apiVersion shouldBeEqual expectedApiVersion.value
71+
}
72+
73+
@Test
74+
fun `init all public options`() {
75+
val expectedTimeoutInMillis = 30_000L
76+
val expectedApiVersion = ApiVersion.V1BETA
77+
78+
val requestOptions =
79+
RequestOptions(timeoutInMillis = expectedTimeoutInMillis, apiVersion = expectedApiVersion)
80+
81+
requestOptions.timeout shouldBeEqual
82+
expectedTimeoutInMillis.toDuration(DurationUnit.MILLISECONDS)
83+
requestOptions.endpoint shouldBeEqual DEFAULT_ENDPOINT
84+
requestOptions.apiVersion shouldBeEqual expectedApiVersion.value
85+
}
86+
}

firebase-vertexai/update_responses.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
# This script replaces mock response files for Vertex AI unit tests with a fresh
1818
# clone of the shared repository of Vertex AI test data.
1919

20-
RESPONSES_VERSION='v3.*' # The major version of mock responses to use
20+
RESPONSES_VERSION='v5.*' # The major version of mock responses to use
2121
REPO_NAME="vertexai-sdk-test-data"
2222
REPO_LINK="https://github.com/FirebaseExtended/$REPO_NAME.git"
2323

0 commit comments

Comments
 (0)