Skip to content

Commit 87667c9

Browse files
authored
Merge branch 'main' into daymxn-patch-1
2 parents e73c081 + b986d2f commit 87667c9

File tree

54 files changed

+1048
-140
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1048
-140
lines changed

.github/workflows/ai-nightlies.yml renamed to .github/workflows/ai-daily-tests.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
name: Firebase AI Nightlies
1+
name: Firebase AI Daily Tests
22

33
on:
44
schedule:
55
- cron: 2 7 * * * # Runs automatically once a day
66
workflow_dispatch: # Allow triggering the workflow manually
77

8+
permissions:
9+
contents: read
10+
811
jobs:
9-
nightlies:
10-
name: "Nightlies"
12+
dailies:
13+
name: "Daily Tests"
1114
runs-on: ubuntu-latest
1215

1316
steps:
1417
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
1518
with:
16-
fetch-depth: 2
1719
submodules: true
1820

1921
- name: Enable KVM
@@ -48,7 +50,7 @@ jobs:
4850
FTL_RESULTS_DIR: ${{ format('logs/{0}/{1}_{2}/artifacts/', github.workflow, github.run_id, github.run_attempt) }}
4951
FIREBASE_APP_CHECK_DEBUG_SECRET: ${{ secrets.FIREBASE_APP_CHECK_DEBUG_SECRET }}
5052
with:
51-
api-level: 31
53+
api-level: 34
5254
arch: x86_64
5355
ram-size: 4096M
5456
heap-size: 4096M

.github/workflows/dataconnect.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ env:
3434
FDC_JAVA_VERSION: ${{ inputs.javaVersion || '17' }}
3535
FDC_ANDROID_EMULATOR_API_LEVEL: ${{ inputs.androidEmulatorApiLevel || '34' }}
3636
FDC_NODEJS_VERSION: ${{ inputs.nodeJsVersion || '20' }}
37-
FDC_FIREBASE_TOOLS_VERSION: ${{ inputs.firebaseToolsVersion || '14.12.0' }}
37+
FDC_FIREBASE_TOOLS_VERSION: ${{ inputs.firebaseToolsVersion || '14.15.1' }}
3838
FDC_FIREBASE_TOOLS_DIR: /tmp/firebase-tools
3939
FDC_FIREBASE_COMMAND: /tmp/firebase-tools/node_modules/.bin/firebase
4040
FDC_PYTHON_VERSION: ${{ inputs.pythonVersion || '3.13' }}
@@ -134,6 +134,7 @@ jobs:
134134
135135
./gradlew \
136136
--profile \
137+
--warning-mode all \
137138
${{ (inputs.gradleInfoLog && '--info') || '' }} \
138139
:firebase-dataconnect:assembleDebugAndroidTest
139140
@@ -222,7 +223,7 @@ jobs:
222223
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
223224
disable-animations: true
224225
script: |
225-
set -eux && ./gradlew ${{ (inputs.gradleInfoLog && '--info') || '' }} :firebase-dataconnect:connectedCheck :firebase-dataconnect:connectors:connectedCheck
226+
set -eux && ./gradlew --warning-mode all ${{ (inputs.gradleInfoLog && '--info') || '' }} :firebase-dataconnect:connectedCheck :firebase-dataconnect:connectors:connectedCheck
226227
227228
- name: Upload Log Files
228229
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1

.github/workflows/dataconnect_demo_app.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ on:
1818

1919
env:
2020
FDC_NODE_VERSION: ${{ inputs.nodeVersion || '20' }}
21-
FDC_FIREBASE_TOOLS_VERSION: ${{ inputs.firebaseToolsVersion || '14.12.0' }}
21+
FDC_FIREBASE_TOOLS_VERSION: ${{ inputs.firebaseToolsVersion || '14.15.1' }}
2222
FDC_JAVA_VERSION: ${{ inputs.javaVersion || '17' }}
2323
FDC_FIREBASE_TOOLS_DIR: ${{ github.workspace }}/firebase-tools
2424
FDC_FIREBASE_COMMAND: ${{ github.workspace }}/firebase-tools/node_modules/.bin/firebase
@@ -108,13 +108,15 @@ jobs:
108108
--project-dir firebase-dataconnect/demo \
109109
${{ (inputs.gradleInfoLog && '--info') || '' }} \
110110
--profile \
111+
--warning-mode all \
111112
-PdataConnect.demo.firebaseCommand=${{ env.FDC_FIREBASE_COMMAND }} \
112113
assemble test
113114
114115
- name: gradle dokkaGeneratePublicationHtml
115116
run: |
116117
set -x
117118
firebase-dataconnect/demo/gradlew \
119+
--warning-mode all \
118120
--project-dir firebase-dataconnect/demo \
119121
${{ (inputs.gradleInfoLog && '--info') || '' }} \
120122
dokkaGeneratePublicationHtml
@@ -176,6 +178,7 @@ jobs:
176178
run: |
177179
set -x
178180
firebase-dataconnect/demo/gradlew \
181+
--warning-mode all \
179182
--project-dir firebase-dataconnect/demo \
180183
--no-daemon \
181184
${{ (inputs.gradleInfoLog && '--info') || '' }} \

firebase-ai/CHANGELOG.md

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

3+
- [feature] Introduced `MissingPermissionsException`, which is thrown when the necessary permissions
4+
have not been granted by the user.
5+
- [feature] Added helper functions to `LiveSession` to allow developers to track the status of the
6+
audio session and the underlying websocket connection.
7+
- [changed] Added new values to `HarmCategory` (#7324)
8+
- [fixed] Fixed an issue that caused unknown or empty `Part`s to throw an exception. Instead, we now
9+
log them and filter them from the response (#7333)
10+
311
# 17.2.0
412

513
- [feature] Added support for returning thought summaries, which are synthesized versions of a

firebase-ai/api.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,10 @@ package com.google.firebase.ai.type {
531531
field public static final com.google.firebase.ai.type.HarmCategory DANGEROUS_CONTENT;
532532
field public static final com.google.firebase.ai.type.HarmCategory HARASSMENT;
533533
field public static final com.google.firebase.ai.type.HarmCategory HATE_SPEECH;
534+
field public static final com.google.firebase.ai.type.HarmCategory IMAGE_DANGEROUS_CONTENT;
535+
field public static final com.google.firebase.ai.type.HarmCategory IMAGE_HARASSMENT;
536+
field public static final com.google.firebase.ai.type.HarmCategory IMAGE_HATE;
537+
field public static final com.google.firebase.ai.type.HarmCategory IMAGE_SEXUALLY_EXPLICIT;
534538
field public static final com.google.firebase.ai.type.HarmCategory SEXUALLY_EXPLICIT;
535539
field public static final com.google.firebase.ai.type.HarmCategory UNKNOWN;
536540
}
@@ -879,6 +883,8 @@ package com.google.firebase.ai.type {
879883

880884
@com.google.firebase.ai.type.PublicPreviewAPI public final class LiveSession {
881885
method public suspend Object? close(kotlin.coroutines.Continuation<? super kotlin.Unit>);
886+
method public boolean isAudioConversationActive();
887+
method public boolean isClosed();
882888
method public kotlinx.coroutines.flow.Flow<com.google.firebase.ai.type.LiveServerMessage> receive();
883889
method public suspend Object? send(com.google.firebase.ai.type.Content content, kotlin.coroutines.Continuation<? super kotlin.Unit>);
884890
method public suspend Object? send(String text, kotlin.coroutines.Continuation<? super kotlin.Unit>);
@@ -918,6 +924,10 @@ package com.google.firebase.ai.type {
918924
method public static String? asTextOrNull(com.google.firebase.ai.type.Part);
919925
}
920926

927+
public final class PermissionMissingException extends com.google.firebase.ai.type.FirebaseAIException {
928+
ctor public PermissionMissingException(String message, Throwable? cause = null);
929+
}
930+
921931
public final class PromptBlockedException extends com.google.firebase.ai.type.FirebaseAIException {
922932
method public com.google.firebase.ai.type.GenerateContentResponse? getResponse();
923933
property public final com.google.firebase.ai.type.GenerateContentResponse? response;

firebase-ai/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
version=17.2.1
15+
version=17.3.0
1616
latestReleasedVersion=17.2.0

firebase-ai/src/main/kotlin/com/google/firebase/ai/LiveGenerativeModel.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ internal constructor(
5555
private val tools: List<Tool>? = null,
5656
private val systemInstruction: Content? = null,
5757
private val location: String,
58-
private val controller: APIController,
58+
private val firebaseApp: FirebaseApp,
59+
private val controller: APIController
5960
) {
6061
internal constructor(
6162
modelName: String,
@@ -78,6 +79,7 @@ internal constructor(
7879
tools,
7980
systemInstruction,
8081
location,
82+
firebaseApp,
8183
APIController(
8284
apiKey,
8385
modelName,
@@ -119,7 +121,11 @@ internal constructor(
119121
val receivedJson = JSON.parseToJsonElement(receivedJsonStr)
120122

121123
return if (receivedJson is JsonObject && "setupComplete" in receivedJson) {
122-
LiveSession(session = webSession, blockingDispatcher = blockingDispatcher)
124+
LiveSession(
125+
session = webSession,
126+
blockingDispatcher = blockingDispatcher,
127+
firebaseApp = firebaseApp
128+
)
123129
} else {
124130
webSession.close()
125131
throw ServiceConnectionHandshakeFailedException("Unable to connect to the server")

firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Content.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.google.firebase.ai.type
1818

1919
import android.graphics.Bitmap
20+
import kotlin.collections.filterNot
2021
import kotlinx.serialization.EncodeDefault
2122
import kotlinx.serialization.ExperimentalSerializationApi
2223
import kotlinx.serialization.Serializable
@@ -90,14 +91,21 @@ constructor(public val role: String? = "user", public val parts: List<Part>) {
9091
@Serializable
9192
internal data class Internal(
9293
@EncodeDefault val role: String? = "user",
93-
val parts: List<InternalPart>
94+
val parts: List<InternalPart>? = null
9495
) {
9596
internal fun toPublic(): Content {
97+
// Return empty if none of the parts is a known part
98+
if (parts == null || parts.filterNot { it is UnknownPart.Internal }.isEmpty()) {
99+
return Content(role, emptyList())
100+
}
101+
// From all the known parts, if they are all text and empty, we coalesce them into a single
102+
// one-character string part so the backend doesn't fail if we send this back as part of a
103+
// multi-turn interaction.
96104
val returnedParts =
97-
parts.map { it.toPublic() }.filterNot { it is TextPart && it.text.isEmpty() }
98-
// If all returned parts were text and empty, we coalesce them into a single one-character
99-
// string
100-
// part so the backend doesn't fail if we send this back as part of a multi-turn interaction.
105+
parts
106+
.filterNot { it is UnknownPart.Internal }
107+
.map { it.toPublic() }
108+
.filterNot { it is TextPart && it.text.isEmpty() }
101109
return Content(role, returnedParts.ifEmpty { listOf(TextPart(" ")) })
102110
}
103111
}

firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Exceptions.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@ public class AudioRecordInitializationFailedException(message: String) :
231231
public class ServiceConnectionHandshakeFailedException(message: String, cause: Throwable? = null) :
232232
FirebaseAIException(message, cause)
233233

234+
/** The request is missing a permission that is required to perform the requested operation. */
235+
public class PermissionMissingException(message: String, cause: Throwable? = null) :
236+
FirebaseAIException(message, cause)
237+
234238
/** Catch all case for exceptions not explicitly expected. */
235239
public class UnknownException internal constructor(message: String, cause: Throwable? = null) :
236240
FirebaseAIException(message, cause)

firebase-ai/src/main/kotlin/com/google/firebase/ai/type/HarmCategory.kt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ public class HarmCategory private constructor(public val ordinal: Int) {
3131
SEXUALLY_EXPLICIT -> Internal.SEXUALLY_EXPLICIT
3232
DANGEROUS_CONTENT -> Internal.DANGEROUS_CONTENT
3333
CIVIC_INTEGRITY -> Internal.CIVIC_INTEGRITY
34+
IMAGE_HATE -> Internal.IMAGE_HATE
35+
IMAGE_DANGEROUS_CONTENT -> Internal.IMAGE_DANGEROUS_CONTENT
36+
IMAGE_HARASSMENT -> Internal.IMAGE_HARASSMENT
37+
IMAGE_SEXUALLY_EXPLICIT -> Internal.IMAGE_SEXUALLY_EXPLICIT
3438
UNKNOWN -> Internal.UNKNOWN
3539
else -> throw makeMissingCaseException("HarmCategory", ordinal)
3640
}
@@ -41,7 +45,11 @@ public class HarmCategory private constructor(public val ordinal: Int) {
4145
@SerialName("HARM_CATEGORY_HATE_SPEECH") HATE_SPEECH,
4246
@SerialName("HARM_CATEGORY_SEXUALLY_EXPLICIT") SEXUALLY_EXPLICIT,
4347
@SerialName("HARM_CATEGORY_DANGEROUS_CONTENT") DANGEROUS_CONTENT,
44-
@SerialName("HARM_CATEGORY_CIVIC_INTEGRITY") CIVIC_INTEGRITY;
48+
@SerialName("HARM_CATEGORY_CIVIC_INTEGRITY") CIVIC_INTEGRITY,
49+
@SerialName("HARM_CATEGORY_IMAGE_HATE") IMAGE_HATE,
50+
@SerialName("HARM_CATEGORY_IMAGE_DANGEROUS_CONTENT") IMAGE_DANGEROUS_CONTENT,
51+
@SerialName("HARM_CATEGORY_IMAGE_HARASSMENT") IMAGE_HARASSMENT,
52+
@SerialName("HARM_CATEGORY_IMAGE_SEXUALLY_EXPLICIT") IMAGE_SEXUALLY_EXPLICIT;
4553

4654
internal object Serializer : KSerializer<Internal> by FirstOrdinalSerializer(Internal::class)
4755

@@ -52,6 +60,10 @@ public class HarmCategory private constructor(public val ordinal: Int) {
5260
SEXUALLY_EXPLICIT -> HarmCategory.SEXUALLY_EXPLICIT
5361
DANGEROUS_CONTENT -> HarmCategory.DANGEROUS_CONTENT
5462
CIVIC_INTEGRITY -> HarmCategory.CIVIC_INTEGRITY
63+
IMAGE_HATE -> HarmCategory.IMAGE_HATE
64+
IMAGE_DANGEROUS_CONTENT -> HarmCategory.IMAGE_DANGEROUS_CONTENT
65+
IMAGE_HARASSMENT -> HarmCategory.IMAGE_HARASSMENT
66+
IMAGE_SEXUALLY_EXPLICIT -> HarmCategory.IMAGE_SEXUALLY_EXPLICIT
5567
else -> HarmCategory.UNKNOWN
5668
}
5769
}
@@ -73,5 +85,17 @@ public class HarmCategory private constructor(public val ordinal: Int) {
7385

7486
/** Content that may be used to harm civic integrity. */
7587
@JvmField public val CIVIC_INTEGRITY: HarmCategory = HarmCategory(5)
88+
89+
/** Content that is image hate. */
90+
@JvmField public val IMAGE_HATE: HarmCategory = HarmCategory(6)
91+
92+
/** Image dangerous content. */
93+
@JvmField public val IMAGE_DANGEROUS_CONTENT: HarmCategory = HarmCategory(7)
94+
95+
/** Content is image harassment. */
96+
@JvmField public val IMAGE_HARASSMENT: HarmCategory = HarmCategory(8)
97+
98+
/** Image sexually explicit content. */
99+
@JvmField public val IMAGE_SEXUALLY_EXPLICIT: HarmCategory = HarmCategory(9)
76100
}
77101
}

0 commit comments

Comments
 (0)