Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
441b4a7
[Firebase AI] Add starter types for Live API
andrewheard Aug 9, 2025
af76cbc
Add placeholder types for `LiveGenerativeModel` and `LiveSession`
andrewheard Aug 9, 2025
1b5d791
Fix `BidiGenerateContentClientMessage` encoding
andrewheard Aug 10, 2025
da8c21b
Fix `BidiGenerateContentServerMessage` decoding
andrewheard Aug 10, 2025
aa3d148
Add `LiveGenerationConfig` and add to setup
andrewheard Aug 10, 2025
60003c1
Add temporary state machine in `LiveSession`
andrewheard Aug 10, 2025
3f285b8
Add `liveModel` static method to construct `LiveGenerativeModel`
andrewheard Aug 10, 2025
737d823
Emit `responses` from `LiveSession`
andrewheard Aug 10, 2025
91dd102
Temporarily display text Bidi responses in TestApp
andrewheard Aug 10, 2025
dd89e20
Refactor to use async/await and remove `URLSessionWebSocketDelegate`
andrewheard Aug 10, 2025
962b57f
Add platform availability annotations
andrewheard Aug 10, 2025
95e1908
Add `BidiGenerateContentServerMessage` availability annotation
andrewheard Aug 11, 2025
c6f3ba8
Add `AsyncWebSocket` wrapper for `URLSessionWebSocketTask`
andrewheard Aug 12, 2025
a9eb3d8
Update
daymxn Sep 9, 2025
b5b0107
Add support for SpeechConfig
daymxn Sep 9, 2025
9b83676
Minor doc fixes
daymxn Sep 9, 2025
d5e375f
Add missing ID field
daymxn Sep 9, 2025
543869e
Remove old todo comment
daymxn Sep 9, 2025
d342829
Add missing docs
daymxn Sep 9, 2025
465006e
Add docs for app check extension
daymxn Sep 9, 2025
e51cc63
Add bug for session resumption
daymxn Sep 9, 2025
3e58503
Use boolean to avoid warning
daymxn Sep 10, 2025
55b8425
Log going away instead of error
daymxn Sep 10, 2025
fa4cf24
Merge branch 'main' into dlr/firebaseai-live-api
daymxn Sep 10, 2025
0c23c7d
Add additional docs for tasks
daymxn Sep 10, 2025
71acb55
Revert andrew's prototyping changes
daymxn Sep 10, 2025
2ccca17
Add support for request options
daymxn Sep 10, 2025
00ebe13
Minor doc fixes
daymxn Sep 10, 2025
3c442a5
Revert "Analytics 12.3.0 (#15310)"
daymxn Sep 10, 2025
dba2bc0
Remove default from video realtime
daymxn Sep 17, 2025
7902349
Add the close method
daymxn Sep 17, 2025
24ef7f0
Add a todo about adding start
daymxn Sep 17, 2025
c252b0a
Fix missing id usage
daymxn Sep 17, 2025
b469e9c
Formatting
daymxn Sep 17, 2025
12f9f27
Temporarily add support for function behavior
daymxn Sep 17, 2025
c4339fa
Add official support for transcripts
daymxn Sep 25, 2025
9527026
Formatting
daymxn Sep 25, 2025
48ce789
Add changelog entry
daymxn Sep 25, 2025
240b94e
Add protoduration support
daymxn Sep 26, 2025
5670c09
Remove unnecessary structs
daymxn Sep 26, 2025
a9f4961
Use unfair lock for closeError
daymxn Sep 26, 2025
e216c19
Use unfair lock for continuation finished
daymxn Sep 26, 2025
1f545da
Make closeErorr immutable
daymxn Sep 26, 2025
279b733
Merge branch 'main' into dlr/firebaseai-live-api
daymxn Sep 26, 2025
6553b5a
Update some doc formatting
daymxn Sep 26, 2025
8b32ed4
Fix duration compile error
daymxn Sep 26, 2025
6678be2
Add docs to AsyncWebSocket
daymxn Sep 26, 2025
58aab91
Remove realtime input config
daymxn Sep 26, 2025
4c742d5
Add an error for lost connection
daymxn Sep 26, 2025
2cd1544
Formatting
daymxn Sep 26, 2025
4fce708
Remove function behavior stuff
daymxn Sep 26, 2025
dd81a84
Revert analytics changes from testing
daymxn Sep 26, 2025
a574eb4
Fix id decoding
daymxn Sep 29, 2025
712b8b4
Rename id to functionId to avoid identifiable collision
daymxn Sep 29, 2025
6ec278b
Fix available version to match usage
daymxn Sep 29, 2025
ad58739
Update reference to id field in docs
daymxn Sep 29, 2025
0f4c55b
Update other doc references to id field
daymxn Sep 29, 2025
6855efc
formatting
daymxn Sep 29, 2025
d1d878a
Fix old available version
daymxn Sep 29, 2025
e3fb8e8
Possibly fix concurrency issue
daymxn Sep 29, 2025
866b32e
Allow params to be unnamed in realtime apis
daymxn Sep 30, 2025
3b896bd
Add audio modifier to transcription names
daymxn Sep 30, 2025
34f4275
Update FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift
daymxn Sep 30, 2025
30d9896
Update FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift
daymxn Sep 30, 2025
082ccbd
Update FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift
daymxn Sep 30, 2025
956942e
Update FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift
daymxn Sep 30, 2025
319ebc2
Update FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift
daymxn Sep 30, 2025
01f18f2
Add comments explaining nested task
daymxn Sep 30, 2025
029ee0d
Use close instead on connect
daymxn Sep 30, 2025
88fa653
Move live session error to public folder
daymxn Sep 30, 2025
6332009
Use failable initializers
daymxn Sep 30, 2025
bba76c6
Formatting on comment
daymxn Sep 30, 2025
7dacdc2
Update FirebaseAI/Sources/Types/Public/Live/LiveServerContent.swift
daymxn Sep 30, 2025
e8e6370
Update FirebaseAI/Sources/Types/Public/Live/LiveServerContent.swift
daymxn Sep 30, 2025
57e2d40
Update docs for boolean value changes
daymxn Sep 30, 2025
ed06c34
Update FirebaseAI/Sources/Types/Public/Live/LiveServerContent.swift
daymxn Sep 30, 2025
68472c4
Update docs for turn complete
daymxn Sep 30, 2025
70c9f19
Update FirebaseAI/Sources/Types/Internal/Live/AsyncWebSocket.swift
daymxn Sep 30, 2025
d487279
Update FirebaseAI/Sources/Types/Internal/Live/BidiGenerateContentClie…
daymxn Sep 30, 2025
474c646
Update FirebaseAI/Sources/Types/Internal/Live/BidiGenerateContentClie…
daymxn Sep 30, 2025
29dfd73
Update FirebaseAI/Sources/Types/Internal/Live/BidiGenerateContentClie…
daymxn Sep 30, 2025
a7f5028
Update FirebaseAI/Sources/Types/Public/Live/LiveSessionErrors.swift
daymxn Sep 30, 2025
2429404
Update FirebaseAI/Sources/Types/Public/Live/LiveSessionErrors.swift
daymxn Sep 30, 2025
0939793
Update FirebaseAI/Sources/Types/Public/Live/LiveTranscription.swift
daymxn Sep 30, 2025
407ee64
Update FirebaseAI/Sources/Types/Public/Live/SpeechConfig.swift
daymxn Sep 30, 2025
fe885aa
Update available versions to exclude watchos
daymxn Sep 30, 2025
5977fe1
Add docs for audio response modality.
daymxn Sep 30, 2025
6a6b2be
Link to refdocs instead
daymxn Sep 30, 2025
9970582
Slight rewording + fix formatting on docs
daymxn Sep 30, 2025
0ada63e
Add back encodable for client message
daymxn Sep 30, 2025
814b4d4
Renaming GoAway to GoingAwayNotice for public api
daymxn Sep 30, 2025
84adb36
lint
daymxn Sep 30, 2025
166be93
Add workaround for `available(watchOS, unavailable)` being ignored
andrewheard Sep 30, 2025
9228d9b
Add `available(watchOS, unavailable)` annotations to remaining types
andrewheard Sep 30, 2025
140bfb8
Update FirebaseAI/Sources/FirebaseAI.swift
daymxn Sep 30, 2025
5a1d836
Fix doc links + default to false for nullable bools
daymxn Sep 30, 2025
86df993
Merge branch 'dlr/firebaseai-live-api' of github.com:firebase/firebas…
daymxn Sep 30, 2025
c5b1567
Rephrase live models in docs
daymxn Sep 30, 2025
850914e
Migrate to protocol instead of enum
daymxn Oct 1, 2025
ba868a2
Update doc comments per rachel's input
daymxn Oct 1, 2025
3788525
formatting
daymxn Oct 1, 2025
31570e3
Update FirebaseAI/Sources/Types/Public/Live/LiveServerContent.swift
daymxn Oct 1, 2025
12750b5
Merge branch 'dlr/firebaseai-live-api' of github.com:firebase/firebas…
daymxn Oct 1, 2025
feb838a
Update FirebaseAI/Sources/Types/Public/Live/LiveServerContent.swift
daymxn Oct 1, 2025
91e13b8
Update FirebaseAI/Sources/Types/Public/Live/LiveServerContent.swift
daymxn Oct 1, 2025
c1de7cd
Update FirebaseAI/Sources/Types/Public/Live/LiveGenerationConfig.swift
daymxn Oct 1, 2025
ca3ebb9
Update FirebaseAI/Sources/Types/Public/Live/LiveGenerationConfig.swift
daymxn Oct 1, 2025
6c999aa
Update FirebaseAI/Sources/Types/Public/Live/LiveGenerationConfig.swift
daymxn Oct 1, 2025
6e80ac0
Update FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift
daymxn Oct 1, 2025
2b3e3c3
Only add underlying error if it's present
daymxn Oct 1, 2025
dc5942f
Merge branch 'dlr/firebaseai-live-api' of github.com:firebase/firebas…
daymxn Oct 1, 2025
66ca3ca
minor comment fix
daymxn Oct 1, 2025
74ea37d
Make sendVideo internal
daymxn Oct 1, 2025
adc35d2
Revert to enum
daymxn Oct 1, 2025
27ce3fa
Rename live server message type
daymxn Oct 1, 2025
d2f48fd
Rename to LiveAudioTranscription
daymxn Oct 1, 2025
a589589
Rename function responses
daymxn Oct 1, 2025
a8c24ba
Minor doc formatting
daymxn Oct 1, 2025
2ea027d
Log json payload if we don't have a mapping
daymxn Oct 1, 2025
85f4c77
Surface setup task errors
daymxn Oct 1, 2025
7d6b4de
Remove config suffix from speech param
daymxn Oct 1, 2025
72c33d7
Use apiConfig endpoint
daymxn Oct 1, 2025
339d5f3
Rename event to payload
daymxn Oct 1, 2025
dbcf303
Remove unnecessary conformance on AsyncWebSocket
daymxn Oct 1, 2025
50aac8f
Add todo for location
daymxn Oct 1, 2025
55cbf8d
Add hanging todo for service endpoints
daymxn Oct 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions FirebaseAI/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
- [fixed] Fixed a decoding error when generating images with the
`gemini-2.5-flash-image-preview` model using `generateContentStream` or
`sendMessageStream` with the Gemini Developer API. (#15262)
- [feature] Added support for the Live API, which allows bidirectional
communication with the model in realtime.

To get started with the Live API, see the Firebase docs on
[Bidirectional streaming using the Gemini Live API](https://firebase.google.com/docs/ai-logic/live-api).
(#15309)

# 12.2.0
- [feature] Added support for returning thought summaries, which are synthesized
Expand Down
13 changes: 13 additions & 0 deletions FirebaseAI/Sources/AILog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,25 @@ enum AILog {
case executableCodeUnrecognizedLanguage = 3016
case fallbackValueUsed = 3017
case urlMetadataUnrecognizedURLRetrievalStatus = 3018
case liveSessionUnsupportedMessage = 3019
case liveSessionUnsupportedMessagePayload = 3020
case liveSessionFailedToEncodeClientMessage = 3021
case liveSessionFailedToEncodeClientMessagePayload = 3022
case liveSessionFailedToSendClientMessage = 3023
case liveSessionUnexpectedResponse = 3024
case liveSessionGoingAwaySoon = 3025
case decodedMissingProtoDurationSuffix = 3026
case decodedInvalidProtoDurationString = 3027
case decodedInvalidProtoDurationSeconds = 3028
case decodedInvalidProtoDurationNanoseconds = 3029

// SDK State Errors
case generateContentResponseNoCandidates = 4000
case generateContentResponseNoText = 4001
case appCheckTokenFetchFailed = 4002
case generateContentResponseEmptyCandidates = 4003
case invalidWebsocketURL = 4004
case duplicateLiveSessionSetupComplete = 4005

// SDK Debugging
case loadRequestStreamResponseLine = 5000
Expand Down
40 changes: 40 additions & 0 deletions FirebaseAI/Sources/FirebaseAI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,46 @@ public final class FirebaseAI: Sendable {
)
}

/// **[Public Preview]** Initializes a ``LiveGenerativeModel`` with the given parameters.
///
/// > Warning: Using the Firebase AI Logic SDKs with the Gemini Live API is in Public
/// Preview, which means that the feature is not subject to any SLA or deprecation policy and
/// could change in backwards-incompatible ways.
///
/// > Important: Only models that support the Gemini Live API (typically containing `live-*` in
/// the name) are supported.
///
/// - Parameters:
/// - modelName: The name of the model to use, for example
/// `"gemini-live-2.5-flash-preview"`;
/// see [model versions](https://firebase.google.com/docs/ai-logic/live-api?api=dev#models-that-support-capability)
/// for a list of supported models.
/// - generationConfig: The content generation parameters your model should use.
/// - tools: A list of ``Tool`` objects that the model may use to generate the next response.
/// - toolConfig: Tool configuration for any ``Tool`` specified in the request.
/// - systemInstruction: Instructions that direct the model to behave a certain way; currently
/// only text content is supported.
/// - requestOptions: Configuration parameters for sending requests to the backend.
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *)
@available(watchOS, unavailable)
public func liveModel(modelName: String,
generationConfig: LiveGenerationConfig? = nil,
tools: [Tool]? = nil,
toolConfig: ToolConfig? = nil,
systemInstruction: ModelContent? = nil,
requestOptions: RequestOptions = RequestOptions()) -> LiveGenerativeModel {
return LiveGenerativeModel(
modelResourceName: modelResourceName(modelName: modelName),
firebaseInfo: firebaseInfo,
apiConfig: apiConfig,
generationConfig: generationConfig,
tools: tools,
toolConfig: toolConfig,
systemInstruction: systemInstruction,
requestOptions: requestOptions
)
}

/// Class to enable FirebaseAI to register via the Objective-C based Firebase component system
/// to include FirebaseAI in the userAgent.
@objc(FIRVertexAIComponent) class FirebaseVertexAIComponent: NSObject {}
Expand Down
52 changes: 4 additions & 48 deletions FirebaseAI/Sources/GenerativeAIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,10 @@ struct GenerativeAIService {
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")

if let appCheck = firebaseInfo.appCheck {
let tokenResult = try await fetchAppCheckToken(appCheck: appCheck)
let tokenResult = try await appCheck.fetchAppCheckToken(
limitedUse: firebaseInfo.useLimitedUseAppCheckTokens,
domain: "GenerativeAIService"
)
urlRequest.setValue(tokenResult.token, forHTTPHeaderField: "X-Firebase-AppCheck")
if let error = tokenResult.error {
AILog.error(
Expand Down Expand Up @@ -207,53 +210,6 @@ struct GenerativeAIService {
return urlRequest
}

private func fetchAppCheckToken(appCheck: AppCheckInterop) async throws
-> FIRAppCheckTokenResultInterop {
if firebaseInfo.useLimitedUseAppCheckTokens {
if let token = await getLimitedUseAppCheckToken(appCheck: appCheck) {
return token
}

let errorMessage =
"The provided App Check token provider doesn't implement getLimitedUseToken(), but requireLimitedUseTokens was enabled."

#if Debug
fatalError(errorMessage)
#else
throw NSError(
domain: "\(Constants.baseErrorDomain).\(Self.self)",
code: AILog.MessageCode.appCheckTokenFetchFailed.rawValue,
userInfo: [NSLocalizedDescriptionKey: errorMessage]
)
#endif
}

return await appCheck.getToken(forcingRefresh: false)
}

private func getLimitedUseAppCheckToken(appCheck: AppCheckInterop) async
-> FIRAppCheckTokenResultInterop? {
// At the moment, `await` doesn’t get along with Objective-C’s optional protocol methods.
await withCheckedContinuation { (continuation: CheckedContinuation<
FIRAppCheckTokenResultInterop?,
Never
>) in
guard
firebaseInfo.useLimitedUseAppCheckTokens,
// `getLimitedUseToken(completion:)` is an optional protocol method. Optional binding
// is performed to make sure `continuation` is called even if the method’s not implemented.
let limitedUseTokenClosure = appCheck.getLimitedUseToken
else {
return continuation.resume(returning: nil)
}

limitedUseTokenClosure { tokenResult in
// The placeholder token should be used in the case of App Check error.
continuation.resume(returning: tokenResult)
}
}
}

private func httpResponse(urlResponse: URLResponse) throws -> HTTPURLResponse {
// The following condition should always be true: "Whenever you make HTTP URL load requests, any
// response objects you get back from the URLSession, NSURLConnection, or NSURLDownload class
Expand Down
1 change: 1 addition & 0 deletions FirebaseAI/Sources/Types/Internal/APIConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extension APIConfig {

extension APIConfig.Service {
/// Network addresses for generative AI API services.
// TODO: maybe remove the https:// prefix and just add it as needed? websockets use these too.
enum Endpoint: String, Encodable {
/// The Firebase proxy production endpoint.
///
Expand Down
74 changes: 74 additions & 0 deletions FirebaseAI/Sources/Types/Internal/AppCheck.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import FirebaseAppCheckInterop

/// Internal helper extension for fetching app check tokens.
///
/// Provides a common means for fetching limited use tokens, and falling back to standard tokens
/// when it's disabled (or in debug mode). This also centrializes the error, since this method is
/// used in multiple places.
extension AppCheckInterop {
/// Fetch the appcheck token.
///
/// - Parameters:
/// - limitedUse: Should the token be a limited-use token, or a standard token.
/// - domain: A string dictating where this method is being called from. Used in any thrown
/// errors, to avoid hard-to-parse traces.
func fetchAppCheckToken(limitedUse: Bool,
domain: String) async throws -> FIRAppCheckTokenResultInterop {
if limitedUse {
if let token = await getLimitedUseTokenAsync() {
return token
}

let errorMessage =
"The provided App Check token provider doesn't implement getLimitedUseToken(), but requireLimitedUseTokens was enabled."

#if Debug
fatalError(errorMessage)
#else
throw NSError(
domain: "\(Constants.baseErrorDomain).\(domain)",
code: AILog.MessageCode.appCheckTokenFetchFailed.rawValue,
userInfo: [NSLocalizedDescriptionKey: errorMessage]
)
#endif
}

return await getToken(forcingRefresh: false)
}

private func getLimitedUseTokenAsync() async
-> FIRAppCheckTokenResultInterop? {
// At the moment, `await` doesn’t get along with Objective-C’s optional protocol methods.
await withCheckedContinuation { (continuation: CheckedContinuation<
FIRAppCheckTokenResultInterop?,
Never
>) in
guard
// `getLimitedUseToken(completion:)` is an optional protocol method. Optional binding
// is performed to make sure `continuation` is called even if the method’s not implemented.
let limitedUseTokenClosure = getLimitedUseToken
else {
return continuation.resume(returning: nil)
}

limitedUseTokenClosure { tokenResult in
// The placeholder token should be used in the case of App Check error.
continuation.resume(returning: tokenResult)
}
}
}
}
9 changes: 7 additions & 2 deletions FirebaseAI/Sources/Types/Internal/InternalPart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,25 @@ struct FileData: Codable, Equatable, Sendable {
struct FunctionCall: Equatable, Sendable {
let name: String
let args: JSONObject
let id: String?

init(name: String, args: JSONObject) {
init(name: String, args: JSONObject, id: String?) {
self.name = name
self.args = args
self.id = id
}
}

@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
struct FunctionResponse: Codable, Equatable, Sendable {
let name: String
let response: JSONObject
let id: String?

init(name: String, response: JSONObject) {
init(name: String, response: JSONObject, id: String? = nil) {
self.name = name
self.response = response
self.id = id
}
}

Expand Down Expand Up @@ -135,6 +139,7 @@ extension FunctionCall: Codable {
} else {
args = JSONObject()
}
id = try container.decodeIfPresent(String.self, forKey: .id)
}
}

Expand Down
Loading
Loading