From 2ce2724014265c898ca9b5fb0d0581101ad11fef Mon Sep 17 00:00:00 2001 From: Daymon Date: Thu, 2 Oct 2025 13:08:30 -0500 Subject: [PATCH 01/16] Migrate location to apiConfig --- FirebaseAI/Sources/FirebaseAI.swift | 19 ++++++------------- .../Sources/Types/Internal/APIConfig.swift | 7 ++++++- FirebaseAI/Sources/Types/Public/Backend.swift | 18 +++++++++++------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index fdd870ecfcf..e2aec8e4a00 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -47,7 +47,6 @@ public final class FirebaseAI: Sendable { useLimitedUseAppCheckTokens: Bool = false) -> FirebaseAI { let instance = createInstance( app: app, - location: backend.location, apiConfig: backend.apiConfig, useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) @@ -188,21 +187,19 @@ public final class FirebaseAI: Sendable { let apiConfig: APIConfig - /// A map of active `FirebaseAI` instances keyed by the `FirebaseApp` name and the `location`, - /// in the format `appName:location`. + /// A map of active `FirebaseAI` instances keyed by the `FirebaseApp`, the `APIConfig`, and `useLimitedUseAppCheckTokens`. private nonisolated(unsafe) static var instances: [InstanceKey: FirebaseAI] = [:] /// Lock to manage access to the `instances` array to avoid race conditions. private nonisolated(unsafe) static var instancesLock: os_unfair_lock = .init() - let location: String? - static let defaultVertexAIAPIConfig = APIConfig( service: .vertexAI(endpoint: .firebaseProxyProd), - version: .v1beta + version: .v1beta, + location: "us-central1" ) - static func createInstance(app: FirebaseApp?, location: String?, + static func createInstance(app: FirebaseApp?, apiConfig: APIConfig, useLimitedUseAppCheckTokens: Bool) -> FirebaseAI { guard let app = app ?? FirebaseApp.app() else { @@ -216,7 +213,6 @@ public final class FirebaseAI: Sendable { let instanceKey = InstanceKey( appName: app.name, - location: location, apiConfig: apiConfig, useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) @@ -225,7 +221,6 @@ public final class FirebaseAI: Sendable { } let newInstance = FirebaseAI( app: app, - location: location, apiConfig: apiConfig, useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) @@ -233,7 +228,7 @@ public final class FirebaseAI: Sendable { return newInstance } - init(app: FirebaseApp, location: String?, apiConfig: APIConfig, + init(app: FirebaseApp, apiConfig: APIConfig, useLimitedUseAppCheckTokens: Bool) { guard let projectID = app.options.projectID else { fatalError("The Firebase app named \"\(app.name)\" has no project ID in its configuration.") @@ -254,7 +249,6 @@ public final class FirebaseAI: Sendable { useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) self.apiConfig = apiConfig - self.location = location } func modelResourceName(modelName: String) -> String { @@ -276,7 +270,7 @@ public final class FirebaseAI: Sendable { } private func vertexAIModelResourceName(modelName: String) -> String { - guard let location else { + guard let location = apiConfig.location else { fatalError("Location must be specified for the Firebase AI service.") } guard !location.isEmpty && location @@ -307,7 +301,6 @@ public final class FirebaseAI: Sendable { /// This type is `Hashable` so that it can be used as a key in the `instances` dictionary. private struct InstanceKey: Sendable, Hashable { let appName: String - let location: String? let apiConfig: APIConfig let useLimitedUseAppCheckTokens: Bool } diff --git a/FirebaseAI/Sources/Types/Internal/APIConfig.swift b/FirebaseAI/Sources/Types/Internal/APIConfig.swift index e854db25c8c..edfc781e806 100644 --- a/FirebaseAI/Sources/Types/Internal/APIConfig.swift +++ b/FirebaseAI/Sources/Types/Internal/APIConfig.swift @@ -22,14 +22,19 @@ struct APIConfig: Sendable, Hashable, Encodable { /// The version of the selected API to use, e.g., "v1". let version: Version + /// The server location to use, e.g., "us-central1" + let location: String? + /// Initializes an API configuration. /// /// - Parameters: /// - service: The API service to use for generative AI. /// - version: The version of the API to use. - init(service: Service, version: Version) { + /// - location: The server location to use. + init(service: Service, version: Version, location: String?) { self.service = service self.version = version + self.location = location } } diff --git a/FirebaseAI/Sources/Types/Public/Backend.swift b/FirebaseAI/Sources/Types/Public/Backend.swift index 132f3a2cd72..80409171196 100644 --- a/FirebaseAI/Sources/Types/Public/Backend.swift +++ b/FirebaseAI/Sources/Types/Public/Backend.swift @@ -25,26 +25,30 @@ public struct Backend { /// for a list of supported locations. public static func vertexAI(location: String = "us-central1") -> Backend { return Backend( - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta), - location: location + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd), + version: .v1beta, + location: location + ) ) } /// Initializes a `Backend` configured for the Google Developer API. public static func googleAI() -> Backend { return Backend( - apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyProd), version: .v1beta), - location: nil + apiConfig: APIConfig( + service: .googleAI(endpoint: .firebaseProxyProd), + version: .v1beta, + location: nil + ) ) } // MARK: - Internal let apiConfig: APIConfig - let location: String? - init(apiConfig: APIConfig, location: String?) { + init(apiConfig: APIConfig) { self.apiConfig = apiConfig - self.location = location } } From 6f7575d1254a0274994a8ab37118838084266e43 Mon Sep 17 00:00:00 2001 From: Daymon Date: Thu, 2 Oct 2025 13:08:43 -0500 Subject: [PATCH 02/16] Use configured location in websocket --- .../Sources/Types/Internal/Live/LiveSessionService.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift b/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift index 42f8364b90f..4f4ea8b2952 100644 --- a/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift +++ b/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift @@ -309,10 +309,9 @@ actor LiveSessionService { /// Will apply the required app check and auth headers, as the backend expects them. private nonisolated func createWebsocket() async throws -> AsyncWebSocket { let host = apiConfig.service.endpoint.rawValue.withoutPrefix("https://") - // TODO: (b/448722577) Set a location based on the api config let urlString = switch apiConfig.service { case .vertexAI: - "wss://\(host)/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/us-central1" + "wss://\(host)/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/\(apiConfig.location ?? "us-central1")" case .googleAI: "wss://\(host)/ws/google.firebase.vertexai.v1beta.GenerativeService/BidiGenerateContent" } From 7ef711cc83ec3d0b091d9f49cc2830ae609901c4 Mon Sep 17 00:00:00 2001 From: Daymon Date: Thu, 2 Oct 2025 13:09:07 -0500 Subject: [PATCH 03/16] Formatting --- FirebaseAI/Sources/FirebaseAI.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index e2aec8e4a00..e56ff787d09 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -187,7 +187,8 @@ public final class FirebaseAI: Sendable { let apiConfig: APIConfig - /// A map of active `FirebaseAI` instances keyed by the `FirebaseApp`, the `APIConfig`, and `useLimitedUseAppCheckTokens`. + /// A map of active `FirebaseAI` instances keyed by the `FirebaseApp`, the `APIConfig`, and + /// `useLimitedUseAppCheckTokens`. private nonisolated(unsafe) static var instances: [InstanceKey: FirebaseAI] = [:] /// Lock to manage access to the `instances` array to avoid race conditions. From 147aa33af0d0c05df1916cfb5c3b44cbab12584c Mon Sep 17 00:00:00 2001 From: Daymon Date: Thu, 2 Oct 2025 13:29:41 -0500 Subject: [PATCH 04/16] Revert "Analytics 12.4.0 (#15367)" This reverts commit 3098853dfabb30e4bf7fc8e6a6d653d2fc1b7923. --- FirebaseAnalytics.podspec | 2 +- GoogleAppMeasurement.podspec | 4 ++-- Package.swift | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index 356649ad3c7..ddfd6bfefcf 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/8ca614257fd008b0/FirebaseAnalytics-12.4.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/7f774173bfc50ea8/FirebaseAnalytics-12.3.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 15a0e5bb817..c1ee6cfb4e3 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/2eb2929f64cc5fb8/GoogleAppMeasurement-12.4.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/1c0181b69fa16f29/GoogleAppMeasurement-12.3.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' @@ -39,7 +39,7 @@ Pod::Spec.new do |s| s.subspec 'Default' do |ss| ss.dependency 'GoogleAppMeasurement/Core', '12.4.0' ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.4.0' - ss.ios.dependency 'GoogleAdsOnDeviceConversion', '~> 3.1.0' + ss.ios.dependency 'GoogleAdsOnDeviceConversion', '~> 3.0.0' end s.subspec 'Core' do |ss| diff --git a/Package.swift b/Package.swift index eee9fe9e212..3bcbca83686 100644 --- a/Package.swift +++ b/Package.swift @@ -329,8 +329,8 @@ let package = Package( ), .binaryTarget( name: "FirebaseAnalytics", - url: "https://dl.google.com/firebase/ios/swiftpm/12.4.0/FirebaseAnalytics.zip", - checksum: "625b4853a02b312eeb857cb6578b109d42459c65021115f864414141ff32a117" + url: "https://dl.google.com/firebase/ios/swiftpm/12.3.0/FirebaseAnalytics.zip", + checksum: "a7fcb34227d6cc0b2db9b1d3f9dd844801e5a28217f20f1daae6c3d2b7d1e8e1" ), .testTarget( name: "AnalyticsSwiftUnit", @@ -1392,7 +1392,7 @@ func googleAppMeasurementDependency() -> Package.Dependency { return .package(url: appMeasurementURL, branch: "main") } - return .package(url: appMeasurementURL, exact: "12.4.0") + return .package(url: appMeasurementURL, exact: "12.3.0") } func abseilDependency() -> Package.Dependency { From b9c926533d90be921d05fa8acd1f56f43a8eb270 Mon Sep 17 00:00:00 2001 From: Daymon Date: Thu, 2 Oct 2025 13:36:24 -0500 Subject: [PATCH 05/16] Pass location through service --- FirebaseAI/Sources/FirebaseAI.swift | 12 ++++-------- FirebaseAI/Sources/Types/Internal/APIConfig.swift | 10 +++------- .../Types/Internal/Live/LiveSessionService.swift | 4 ++-- FirebaseAI/Sources/Types/Public/Backend.swift | 4 +--- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index e56ff787d09..248f5ad9706 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -195,9 +195,8 @@ public final class FirebaseAI: Sendable { private nonisolated(unsafe) static var instancesLock: os_unfair_lock = .init() static let defaultVertexAIAPIConfig = APIConfig( - service: .vertexAI(endpoint: .firebaseProxyProd), + service: .vertexAI(endpoint: .firebaseProxyProd, location: "us-central1"), version: .v1beta, - location: "us-central1" ) static func createInstance(app: FirebaseApp?, @@ -263,17 +262,14 @@ public final class FirebaseAI: Sendable { } switch apiConfig.service { - case .vertexAI: - return vertexAIModelResourceName(modelName: modelName) + case let .vertexAI(endpoint: _, location: location): + return vertexAIModelResourceName(modelName: modelName, location: location) case .googleAI: return developerModelResourceName(modelName: modelName) } } - private func vertexAIModelResourceName(modelName: String) -> String { - guard let location = apiConfig.location else { - fatalError("Location must be specified for the Firebase AI service.") - } + private func vertexAIModelResourceName(modelName: String, location: String) -> String { guard !location.isEmpty && location .allSatisfy({ !$0.isWhitespace && !$0.isNewline && $0 != "/" }) else { fatalError(""" diff --git a/FirebaseAI/Sources/Types/Internal/APIConfig.swift b/FirebaseAI/Sources/Types/Internal/APIConfig.swift index edfc781e806..e6ce4962521 100644 --- a/FirebaseAI/Sources/Types/Internal/APIConfig.swift +++ b/FirebaseAI/Sources/Types/Internal/APIConfig.swift @@ -22,19 +22,15 @@ struct APIConfig: Sendable, Hashable, Encodable { /// The version of the selected API to use, e.g., "v1". let version: Version - /// The server location to use, e.g., "us-central1" - let location: String? - /// Initializes an API configuration. /// /// - Parameters: /// - service: The API service to use for generative AI. /// - version: The version of the API to use. /// - location: The server location to use. - init(service: Service, version: Version, location: String?) { + init(service: Service, version: Version) { self.service = service self.version = version - self.location = location } } @@ -50,7 +46,7 @@ extension APIConfig { /// See the [Cloud /// docs](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference) for /// more details. - case vertexAI(endpoint: Endpoint) + case vertexAI(endpoint: Endpoint, location: String) /// The Gemini Developer API provided by Google AI. /// @@ -62,7 +58,7 @@ extension APIConfig { /// This must correspond with the API set in `service`. var endpoint: Endpoint { switch self { - case let .vertexAI(endpoint: endpoint): + case let .vertexAI(endpoint: endpoint, location: _): return endpoint case let .googleAI(endpoint: endpoint): return endpoint diff --git a/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift b/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift index 4f4ea8b2952..9f43e12248a 100644 --- a/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift +++ b/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift @@ -310,8 +310,8 @@ actor LiveSessionService { private nonisolated func createWebsocket() async throws -> AsyncWebSocket { let host = apiConfig.service.endpoint.rawValue.withoutPrefix("https://") let urlString = switch apiConfig.service { - case .vertexAI: - "wss://\(host)/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/\(apiConfig.location ?? "us-central1")" + case let .vertexAI(endpoint: _, location: location): + "wss://\(host)/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/\(location)" case .googleAI: "wss://\(host)/ws/google.firebase.vertexai.v1beta.GenerativeService/BidiGenerateContent" } diff --git a/FirebaseAI/Sources/Types/Public/Backend.swift b/FirebaseAI/Sources/Types/Public/Backend.swift index 80409171196..49541249a0f 100644 --- a/FirebaseAI/Sources/Types/Public/Backend.swift +++ b/FirebaseAI/Sources/Types/Public/Backend.swift @@ -26,9 +26,8 @@ public struct Backend { public static func vertexAI(location: String = "us-central1") -> Backend { return Backend( apiConfig: APIConfig( - service: .vertexAI(endpoint: .firebaseProxyProd), + service: .vertexAI(endpoint: .firebaseProxyProd, location: location), version: .v1beta, - location: location ) ) } @@ -39,7 +38,6 @@ public struct Backend { apiConfig: APIConfig( service: .googleAI(endpoint: .firebaseProxyProd), version: .v1beta, - location: nil ) ) } From 3e097a9ecc4b2c5cb958d4b007edc98856517bd8 Mon Sep 17 00:00:00 2001 From: Daymon Date: Thu, 2 Oct 2025 13:38:31 -0500 Subject: [PATCH 06/16] Reapply "Analytics 12.4.0 (#15367)" This reverts commit 147aa33af0d0c05df1916cfb5c3b44cbab12584c. --- FirebaseAnalytics.podspec | 2 +- GoogleAppMeasurement.podspec | 4 ++-- Package.swift | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index ddfd6bfefcf..356649ad3c7 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/7f774173bfc50ea8/FirebaseAnalytics-12.3.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/8ca614257fd008b0/FirebaseAnalytics-12.4.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index c1ee6cfb4e3..15a0e5bb817 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/1c0181b69fa16f29/GoogleAppMeasurement-12.3.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/2eb2929f64cc5fb8/GoogleAppMeasurement-12.4.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' @@ -39,7 +39,7 @@ Pod::Spec.new do |s| s.subspec 'Default' do |ss| ss.dependency 'GoogleAppMeasurement/Core', '12.4.0' ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.4.0' - ss.ios.dependency 'GoogleAdsOnDeviceConversion', '~> 3.0.0' + ss.ios.dependency 'GoogleAdsOnDeviceConversion', '~> 3.1.0' end s.subspec 'Core' do |ss| diff --git a/Package.swift b/Package.swift index 3bcbca83686..eee9fe9e212 100644 --- a/Package.swift +++ b/Package.swift @@ -329,8 +329,8 @@ let package = Package( ), .binaryTarget( name: "FirebaseAnalytics", - url: "https://dl.google.com/firebase/ios/swiftpm/12.3.0/FirebaseAnalytics.zip", - checksum: "a7fcb34227d6cc0b2db9b1d3f9dd844801e5a28217f20f1daae6c3d2b7d1e8e1" + url: "https://dl.google.com/firebase/ios/swiftpm/12.4.0/FirebaseAnalytics.zip", + checksum: "625b4853a02b312eeb857cb6578b109d42459c65021115f864414141ff32a117" ), .testTarget( name: "AnalyticsSwiftUnit", @@ -1392,7 +1392,7 @@ func googleAppMeasurementDependency() -> Package.Dependency { return .package(url: appMeasurementURL, branch: "main") } - return .package(url: appMeasurementURL, exact: "12.3.0") + return .package(url: appMeasurementURL, exact: "12.4.0") } func abseilDependency() -> Package.Dependency { From a5f6486bd14f022da4d5c4577f73837429972499 Mon Sep 17 00:00:00 2001 From: Daymon <17409137+daymxn@users.noreply.github.com> Date: Thu, 2 Oct 2025 13:59:22 -0500 Subject: [PATCH 07/16] Update FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift b/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift index 9f43e12248a..ad4502b6943 100644 --- a/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift +++ b/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift @@ -310,7 +310,7 @@ actor LiveSessionService { private nonisolated func createWebsocket() async throws -> AsyncWebSocket { let host = apiConfig.service.endpoint.rawValue.withoutPrefix("https://") let urlString = switch apiConfig.service { - case let .vertexAI(endpoint: _, location: location): + case let .vertexAI(_, location: location): "wss://\(host)/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/\(location)" case .googleAI: "wss://\(host)/ws/google.firebase.vertexai.v1beta.GenerativeService/BidiGenerateContent" From 839378e0b26b8b8bff41691fc8b13f3fd10a9ab1 Mon Sep 17 00:00:00 2001 From: Daymon Date: Thu, 2 Oct 2025 14:00:26 -0500 Subject: [PATCH 08/16] Apply nick's suggestion --- FirebaseAI/Sources/Types/Internal/APIConfig.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAI/Sources/Types/Internal/APIConfig.swift b/FirebaseAI/Sources/Types/Internal/APIConfig.swift index e6ce4962521..0c69250f946 100644 --- a/FirebaseAI/Sources/Types/Internal/APIConfig.swift +++ b/FirebaseAI/Sources/Types/Internal/APIConfig.swift @@ -58,7 +58,7 @@ extension APIConfig { /// This must correspond with the API set in `service`. var endpoint: Endpoint { switch self { - case let .vertexAI(endpoint: endpoint, location: _): + case let .vertexAI(endpoint: endpoint, _): return endpoint case let .googleAI(endpoint: endpoint): return endpoint From 2cadfba1239ca926fc7668876c2c05b1da265555 Mon Sep 17 00:00:00 2001 From: Daymon Date: Thu, 2 Oct 2025 14:04:59 -0500 Subject: [PATCH 09/16] Use api config version --- .../Sources/Types/Internal/Live/LiveSessionService.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift b/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift index ad4502b6943..a49e34e6671 100644 --- a/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift +++ b/FirebaseAI/Sources/Types/Internal/Live/LiveSessionService.swift @@ -311,9 +311,9 @@ actor LiveSessionService { let host = apiConfig.service.endpoint.rawValue.withoutPrefix("https://") let urlString = switch apiConfig.service { case let .vertexAI(_, location: location): - "wss://\(host)/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/\(location)" + "wss://\(host)/ws/google.firebase.vertexai.\(apiConfig.version.rawValue).LlmBidiService/BidiGenerateContent/locations/\(location)" case .googleAI: - "wss://\(host)/ws/google.firebase.vertexai.v1beta.GenerativeService/BidiGenerateContent" + "wss://\(host)/ws/google.firebase.vertexai.\(apiConfig.version.rawValue).GenerativeService/BidiGenerateContent" } guard let url = URL(string: urlString) else { throw NSError( From 50cee21238fd1d3b408686f5592a25a04b1e5c8b Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 2 Oct 2025 15:09:02 -0400 Subject: [PATCH 10/16] Fix integration tests --- .../Tests/Utilities/InstanceConfig.swift | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift index df06f43c91f..cce2aa76339 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift @@ -21,19 +21,29 @@ import Testing struct InstanceConfig: Equatable, Encodable { static let vertexAI_v1beta = InstanceConfig( - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: "us-central1"), + version: .v1beta + ) ) static let vertexAI_v1beta_global = InstanceConfig( - location: "global", - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: "global"), + version: .v1beta + ) ) static let vertexAI_v1beta_global_appCheckLimitedUse = InstanceConfig( - location: "global", useLimitedUseAppCheckTokens: true, - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: "global"), + version: .v1beta + ) ) static let vertexAI_v1beta_staging = InstanceConfig( - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyStaging), version: .v1beta) + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyStaging, location: "us-central1"), + version: .v1beta + ) ) static let googleAI_v1beta = InstanceConfig( apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyProd), version: .v1beta) @@ -68,12 +78,18 @@ struct InstanceConfig: Equatable, Encodable { static let vertexAI_v1beta_appCheckNotConfigured = InstanceConfig( appName: FirebaseAppNames.appCheckNotConfigured, - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: "us-central1"), + version: .v1beta + ) ) static let vertexAI_v1beta_appCheckNotConfigured_limitedUseTokens = InstanceConfig( appName: FirebaseAppNames.appCheckNotConfigured, useLimitedUseAppCheckTokens: true, - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: "us-central1"), + version: .v1beta + ) ) static let googleAI_v1beta_appCheckNotConfigured = InstanceConfig( appName: FirebaseAppNames.appCheckNotConfigured, @@ -150,10 +166,8 @@ extension FirebaseAI { static func componentInstance(_ instanceConfig: InstanceConfig) -> FirebaseAI { switch instanceConfig.apiConfig.service { case .vertexAI: - let location = instanceConfig.location ?? "us-central1" return FirebaseAI.createInstance( app: instanceConfig.app, - location: location, apiConfig: instanceConfig.apiConfig, useLimitedUseAppCheckTokens: instanceConfig.useLimitedUseAppCheckTokens ) @@ -164,7 +178,6 @@ extension FirebaseAI { ) return FirebaseAI.createInstance( app: instanceConfig.app, - location: nil, apiConfig: instanceConfig.apiConfig, useLimitedUseAppCheckTokens: instanceConfig.useLimitedUseAppCheckTokens ) From e04e66a889db11bfa5cf8f0c93413233b427f24c Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 2 Oct 2025 16:07:32 -0400 Subject: [PATCH 11/16] Fix unit tests --- .../Tests/Unit/Types/BackendTests.swift | 9 +-- .../Unit/Types/Internal/APIConfigTests.swift | 72 ++++++++++++++---- .../Tests/Unit/VertexComponentTests.swift | 74 +++++++++++-------- 3 files changed, 104 insertions(+), 51 deletions(-) diff --git a/FirebaseAI/Tests/Unit/Types/BackendTests.swift b/FirebaseAI/Tests/Unit/Types/BackendTests.swift index e4e87784e68..d0fe40c7cbc 100644 --- a/FirebaseAI/Tests/Unit/Types/BackendTests.swift +++ b/FirebaseAI/Tests/Unit/Types/BackendTests.swift @@ -19,27 +19,25 @@ import XCTest final class BackendTests: XCTestCase { func testVertexAI_defaultLocation() { let expectedAPIConfig = APIConfig( - service: .vertexAI(endpoint: .firebaseProxyProd), + service: .vertexAI(endpoint: .firebaseProxyProd, location: "us-central1"), version: .v1beta ) let backend = Backend.vertexAI() XCTAssertEqual(backend.apiConfig, expectedAPIConfig) - XCTAssertEqual(backend.location, "us-central1") } func testVertexAI_customLocation() { + let customLocation = "europe-west1" let expectedAPIConfig = APIConfig( - service: .vertexAI(endpoint: .firebaseProxyProd), + service: .vertexAI(endpoint: .firebaseProxyProd, location: customLocation), version: .v1beta ) - let customLocation = "europe-west1" let backend = Backend.vertexAI(location: customLocation) XCTAssertEqual(backend.apiConfig, expectedAPIConfig) - XCTAssertEqual(backend.location, customLocation) } func testGoogleAI() { @@ -51,6 +49,5 @@ final class BackendTests: XCTestCase { let backend = Backend.googleAI() XCTAssertEqual(backend.apiConfig, expectedAPIConfig) - XCTAssertNil(backend.location) } } diff --git a/FirebaseAI/Tests/Unit/Types/Internal/APIConfigTests.swift b/FirebaseAI/Tests/Unit/Types/Internal/APIConfigTests.swift index fe4c290831a..937b858d40b 100644 --- a/FirebaseAI/Tests/Unit/Types/Internal/APIConfigTests.swift +++ b/FirebaseAI/Tests/Unit/Types/Internal/APIConfigTests.swift @@ -18,38 +18,70 @@ import XCTest @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) final class APIConfigTests: XCTestCase { + let defaultLocation = "us-central1" + let globalLocation = "global" + func testInitialize_vertexAI_prod_v1() { - let apiConfig = APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1) + let apiConfig = APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: defaultLocation), + version: .v1 + ) - XCTAssertEqual(apiConfig.service.endpoint.rawValue, "https://firebasevertexai.googleapis.com") + switch apiConfig.service { + case let .vertexAI(endpoint: endpoint, location: location): + XCTAssertEqual(endpoint.rawValue, "https://firebasevertexai.googleapis.com") + XCTAssertEqual(location, defaultLocation) + case .googleAI: + XCTFail("Expected .vertexAI, got .googleAI") + } XCTAssertEqual(apiConfig.version.rawValue, "v1") } func testInitialize_vertexAI_prod_v1beta() { - let apiConfig = APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + let apiConfig = APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: defaultLocation), + version: .v1beta + ) - XCTAssertEqual(apiConfig.service.endpoint.rawValue, "https://firebasevertexai.googleapis.com") + switch apiConfig.service { + case let .vertexAI(endpoint: endpoint, location: location): + XCTAssertEqual(endpoint.rawValue, "https://firebasevertexai.googleapis.com") + XCTAssertEqual(location, defaultLocation) + case .googleAI: + XCTFail("Expected .vertexAI, got .googleAI") + } XCTAssertEqual(apiConfig.version.rawValue, "v1beta") } func testInitialize_vertexAI_staging_v1() { - let apiConfig = APIConfig(service: .vertexAI(endpoint: .firebaseProxyStaging), version: .v1) - - XCTAssertEqual( - apiConfig.service.endpoint.rawValue, "https://staging-firebasevertexai.sandbox.googleapis.com" + let apiConfig = APIConfig( + service: .vertexAI(endpoint: .firebaseProxyStaging, location: defaultLocation), + version: .v1 ) + + switch apiConfig.service { + case let .vertexAI(endpoint: endpoint, location: location): + XCTAssertEqual(endpoint.rawValue, "https://staging-firebasevertexai.sandbox.googleapis.com") + XCTAssertEqual(location, defaultLocation) + case .googleAI: + XCTFail("Expected .vertexAI, got .googleAI") + } XCTAssertEqual(apiConfig.version.rawValue, "v1") } func testInitialize_vertexAI_staging_v1beta() { let apiConfig = APIConfig( - service: .vertexAI(endpoint: .firebaseProxyStaging), + service: .vertexAI(endpoint: .firebaseProxyStaging, location: defaultLocation), version: .v1beta ) - XCTAssertEqual( - apiConfig.service.endpoint.rawValue, "https://staging-firebasevertexai.sandbox.googleapis.com" - ) + switch apiConfig.service { + case let .vertexAI(endpoint: endpoint, location: location): + XCTAssertEqual(endpoint.rawValue, "https://staging-firebasevertexai.sandbox.googleapis.com") + XCTAssertEqual(location, defaultLocation) + case .googleAI: + XCTFail("Expected .vertexAI, got .googleAI") + } XCTAssertEqual(apiConfig.version.rawValue, "v1beta") } @@ -58,16 +90,24 @@ final class APIConfigTests: XCTestCase { service: .googleAI(endpoint: .firebaseProxyStaging), version: .v1beta ) - XCTAssertEqual( - apiConfig.service.endpoint.rawValue, "https://staging-firebasevertexai.sandbox.googleapis.com" - ) + switch apiConfig.service { + case .vertexAI: + XCTFail("Expected .googleAI, got .vertexAI") + case let .googleAI(endpoint: endpoint): + XCTAssertEqual(endpoint.rawValue, "https://staging-firebasevertexai.sandbox.googleapis.com") + } XCTAssertEqual(apiConfig.version.rawValue, "v1beta") } func testInitialize_developer_generativeLanguage_v1beta() { let apiConfig = APIConfig(service: .googleAI(endpoint: .googleAIBypassProxy), version: .v1beta) - XCTAssertEqual(apiConfig.service.endpoint.rawValue, "https://generativelanguage.googleapis.com") + switch apiConfig.service { + case .vertexAI: + XCTFail("Expected .googleAI, got .vertexAI") + case let .googleAI(endpoint: endpoint): + XCTAssertEqual(endpoint.rawValue, "https://generativelanguage.googleapis.com") + } XCTAssertEqual(apiConfig.version.rawValue, "v1beta") } } diff --git a/FirebaseAI/Tests/Unit/VertexComponentTests.swift b/FirebaseAI/Tests/Unit/VertexComponentTests.swift index 702c6e50871..7b1da70e6af 100644 --- a/FirebaseAI/Tests/Unit/VertexComponentTests.swift +++ b/FirebaseAI/Tests/Unit/VertexComponentTests.swift @@ -57,8 +57,9 @@ class VertexComponentTests: XCTestCase { XCTAssertNotNil(vertex) XCTAssertEqual(vertex.firebaseInfo.projectID, VertexComponentTests.projectID) XCTAssertEqual(vertex.firebaseInfo.apiKey, VertexComponentTests.apiKey) - XCTAssertEqual(vertex.location, "us-central1") - XCTAssertEqual(vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd)) + XCTAssertEqual( + vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd, location: "us-central1") + ) XCTAssertEqual(vertex.apiConfig.service.endpoint, .firebaseProxyProd) XCTAssertEqual(vertex.apiConfig.version, .v1beta) } @@ -71,8 +72,9 @@ class VertexComponentTests: XCTestCase { XCTAssertNotNil(vertex) XCTAssertEqual(vertex.firebaseInfo.projectID, VertexComponentTests.projectID) XCTAssertEqual(vertex.firebaseInfo.apiKey, VertexComponentTests.apiKey) - XCTAssertEqual(vertex.location, location) - XCTAssertEqual(vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd)) + XCTAssertEqual( + vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd, location: location) + ) XCTAssertEqual(vertex.apiConfig.service.endpoint, .firebaseProxyProd) XCTAssertEqual(vertex.apiConfig.version, .v1beta) } @@ -87,8 +89,9 @@ class VertexComponentTests: XCTestCase { XCTAssertNotNil(vertex) XCTAssertEqual(vertex.firebaseInfo.projectID, VertexComponentTests.projectID) XCTAssertEqual(vertex.firebaseInfo.apiKey, VertexComponentTests.apiKey) - XCTAssertEqual(vertex.location, location) - XCTAssertEqual(vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd)) + XCTAssertEqual( + vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd, location: location) + ) XCTAssertEqual(vertex.apiConfig.service.endpoint, .firebaseProxyProd) XCTAssertEqual(vertex.apiConfig.version, .v1beta) } @@ -154,14 +157,17 @@ class VertexComponentTests: XCTestCase { func testSameAppAndDifferentAPI_newInstanceCreated() throws { let vertex1 = FirebaseAI.createInstance( app: VertexComponentTests.app, - location: location, - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta), + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: location), + version: .v1beta + ), useLimitedUseAppCheckTokens: false ) let vertex2 = FirebaseAI.createInstance( app: VertexComponentTests.app, - location: location, - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1), + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: location), version: .v1 + ), useLimitedUseAppCheckTokens: false ) @@ -182,8 +188,10 @@ class VertexComponentTests: XCTestCase { weakApp = try XCTUnwrap(app1) let vertex = FirebaseAI( app: app1, - location: "transitory location", - apiConfig: FirebaseAI.defaultVertexAIAPIConfig, + apiConfig: APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: "transitory location"), + version: .v1beta, + ), useLimitedUseAppCheckTokens: false ) weakVertex = vertex @@ -195,13 +203,13 @@ class VertexComponentTests: XCTestCase { func testModelResourceName_vertexAI() throws { let app = try XCTUnwrap(VertexComponentTests.app) + let location = "test-location" let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location)) let model = "test-model-name" let projectID = vertex.firebaseInfo.projectID let modelResourceName = vertex.modelResourceName(modelName: model) - let location = try XCTUnwrap(vertex.location) XCTAssertEqual( modelResourceName, "projects/\(projectID)/locations/\(location)/publishers/google/models/\(model)" @@ -212,10 +220,7 @@ class VertexComponentTests: XCTestCase { let app = try XCTUnwrap(VertexComponentTests.app) let apiConfig = APIConfig(service: .googleAI(endpoint: .googleAIBypassProxy), version: .v1beta) let vertex = FirebaseAI.createInstance( - app: app, - location: nil, - apiConfig: apiConfig, - useLimitedUseAppCheckTokens: false + app: app, apiConfig: apiConfig, useLimitedUseAppCheckTokens: false ) let model = "test-model-name" @@ -231,10 +236,7 @@ class VertexComponentTests: XCTestCase { version: .v1beta ) let vertex = FirebaseAI.createInstance( - app: app, - location: nil, - apiConfig: apiConfig, - useLimitedUseAppCheckTokens: false + app: app, apiConfig: apiConfig, useLimitedUseAppCheckTokens: false ) let model = "test-model-name" let projectID = vertex.firebaseInfo.projectID @@ -244,15 +246,14 @@ class VertexComponentTests: XCTestCase { XCTAssertEqual(modelResourceName, "projects/\(projectID)/models/\(model)") } - func testGenerativeModel_vertexAI() async throws { + func testGenerativeModel_vertexAI_defaultLocation() async throws { let app = try XCTUnwrap(VertexComponentTests.app) - let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location)) + let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI()) let modelResourceName = vertex.modelResourceName(modelName: modelName) let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts) let generativeModel = vertex.generativeModel( - modelName: modelName, - systemInstruction: systemInstruction + modelName: modelName, systemInstruction: systemInstruction ) XCTAssertEqual(generativeModel.modelResourceName, modelResourceName) @@ -260,6 +261,24 @@ class VertexComponentTests: XCTestCase { XCTAssertEqual(generativeModel.apiConfig, FirebaseAI.defaultVertexAIAPIConfig) } + func testGenerativeModel_vertexAI_customLocation() async throws { + let app = try XCTUnwrap(VertexComponentTests.app) + let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location)) + let modelResourceName = vertex.modelResourceName(modelName: modelName) + let expectedAPIConfig = APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: location), version: .v1beta + ) + let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts) + + let generativeModel = vertex.generativeModel( + modelName: modelName, systemInstruction: systemInstruction + ) + + XCTAssertEqual(generativeModel.modelResourceName, modelResourceName) + XCTAssertEqual(generativeModel.systemInstruction, expectedSystemInstruction) + XCTAssertEqual(generativeModel.apiConfig, expectedAPIConfig) + } + func testGenerativeModel_developerAPI() async throws { let app = try XCTUnwrap(VertexComponentTests.app) let apiConfig = APIConfig( @@ -267,10 +286,7 @@ class VertexComponentTests: XCTestCase { version: .v1beta ) let vertex = FirebaseAI.createInstance( - app: app, - location: nil, - apiConfig: apiConfig, - useLimitedUseAppCheckTokens: false + app: app, apiConfig: apiConfig, useLimitedUseAppCheckTokens: false ) let modelResourceName = vertex.modelResourceName(modelName: modelName) let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts) From bdf2a54e65fba9f80f37d553b1b37607ac00dd49 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 2 Oct 2025 16:30:22 -0400 Subject: [PATCH 12/16] Remove trailing commas to fix Xcode 16.2 build --- FirebaseAI/Sources/Types/Public/Backend.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseAI/Sources/Types/Public/Backend.swift b/FirebaseAI/Sources/Types/Public/Backend.swift index 49541249a0f..b4b55699494 100644 --- a/FirebaseAI/Sources/Types/Public/Backend.swift +++ b/FirebaseAI/Sources/Types/Public/Backend.swift @@ -27,7 +27,7 @@ public struct Backend { return Backend( apiConfig: APIConfig( service: .vertexAI(endpoint: .firebaseProxyProd, location: location), - version: .v1beta, + version: .v1beta ) ) } @@ -37,7 +37,7 @@ public struct Backend { return Backend( apiConfig: APIConfig( service: .googleAI(endpoint: .firebaseProxyProd), - version: .v1beta, + version: .v1beta ) ) } From baf6066fe01b3b89d2902083cee02da32108a5ee Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 2 Oct 2025 16:31:25 -0400 Subject: [PATCH 13/16] Remove now unused `location` property in `InstanceConfig` --- .../Sources/Types/Internal/APIConfig.swift | 1 - .../Tests/Utilities/InstanceConfig.swift | 18 +++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/FirebaseAI/Sources/Types/Internal/APIConfig.swift b/FirebaseAI/Sources/Types/Internal/APIConfig.swift index 0c69250f946..97a8615e98a 100644 --- a/FirebaseAI/Sources/Types/Internal/APIConfig.swift +++ b/FirebaseAI/Sources/Types/Internal/APIConfig.swift @@ -27,7 +27,6 @@ struct APIConfig: Sendable, Hashable, Encodable { /// - Parameters: /// - service: The API service to use for generative AI. /// - version: The version of the API to use. - /// - location: The server location to use. init(service: Service, version: Version) { self.service = service self.version = version diff --git a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift index cce2aa76339..bf9d32c6e0d 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift @@ -109,16 +109,11 @@ struct InstanceConfig: Equatable, Encodable { ] let appName: String? - let location: String? let useLimitedUseAppCheckTokens: Bool let apiConfig: APIConfig - init(appName: String? = nil, - location: String? = nil, - useLimitedUseAppCheckTokens: Bool = false, - apiConfig: APIConfig) { + init(appName: String? = nil, useLimitedUseAppCheckTokens: Bool = false, apiConfig: APIConfig) { self.appName = appName - self.location = location self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens self.apiConfig = apiConfig } @@ -152,7 +147,12 @@ extension InstanceConfig: CustomTestStringConvertible { case .googleAIBypassProxy: " - Bypass Proxy" } - let locationSuffix = location.map { " - \($0)" } ?? "" + let locationSuffix: String + if case let .vertexAI(_, location: location) = apiConfig.service { + locationSuffix = location + } else { + locationSuffix = "" + } let appCheckLimitedUseDesignator = useLimitedUseAppCheckTokens ? " - FAC Limited-Use" : "" return """ @@ -172,10 +172,6 @@ extension FirebaseAI { useLimitedUseAppCheckTokens: instanceConfig.useLimitedUseAppCheckTokens ) case .googleAI: - assert( - instanceConfig.location == nil, - "The Developer API is global and does not support `location`." - ) return FirebaseAI.createInstance( app: instanceConfig.app, apiConfig: instanceConfig.apiConfig, From 62411ce1186c1c5a46829d5f10416d3fe4a2d470 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 2 Oct 2025 16:46:37 -0400 Subject: [PATCH 14/16] Remove another trailing comma --- FirebaseAI/Sources/FirebaseAI.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index 248f5ad9706..3bf963632e7 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -196,7 +196,7 @@ public final class FirebaseAI: Sendable { static let defaultVertexAIAPIConfig = APIConfig( service: .vertexAI(endpoint: .firebaseProxyProd, location: "us-central1"), - version: .v1beta, + version: .v1beta ) static func createInstance(app: FirebaseApp?, From 451f45b4a9194b1a003f666cda09793efc147957 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 2 Oct 2025 16:57:31 -0400 Subject: [PATCH 15/16] Remove yet another trailing comma --- FirebaseAI/Tests/Unit/VertexComponentTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAI/Tests/Unit/VertexComponentTests.swift b/FirebaseAI/Tests/Unit/VertexComponentTests.swift index 7b1da70e6af..66b3ae68576 100644 --- a/FirebaseAI/Tests/Unit/VertexComponentTests.swift +++ b/FirebaseAI/Tests/Unit/VertexComponentTests.swift @@ -190,7 +190,7 @@ class VertexComponentTests: XCTestCase { app: app1, apiConfig: APIConfig( service: .vertexAI(endpoint: .firebaseProxyProd, location: "transitory location"), - version: .v1beta, + version: .v1beta ), useLimitedUseAppCheckTokens: false ) From d1240b241c90ca0abd167b8008b79ea9a745d266 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 2 Oct 2025 17:55:57 -0400 Subject: [PATCH 16/16] Move `defaultVertexAIAPIConfig` to unit tests; unused in SDK --- FirebaseAI/Sources/FirebaseAI.swift | 5 ----- .../FirebaseAI+DefaultAPIConfig.swift | 22 +++++++++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 FirebaseAI/Tests/Unit/TestUtilities/FirebaseAI+DefaultAPIConfig.swift diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index 3bf963632e7..f9ff5ea0424 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -194,11 +194,6 @@ public final class FirebaseAI: Sendable { /// Lock to manage access to the `instances` array to avoid race conditions. private nonisolated(unsafe) static var instancesLock: os_unfair_lock = .init() - static let defaultVertexAIAPIConfig = APIConfig( - service: .vertexAI(endpoint: .firebaseProxyProd, location: "us-central1"), - version: .v1beta - ) - static func createInstance(app: FirebaseApp?, apiConfig: APIConfig, useLimitedUseAppCheckTokens: Bool) -> FirebaseAI { diff --git a/FirebaseAI/Tests/Unit/TestUtilities/FirebaseAI+DefaultAPIConfig.swift b/FirebaseAI/Tests/Unit/TestUtilities/FirebaseAI+DefaultAPIConfig.swift new file mode 100644 index 00000000000..48a596f01a4 --- /dev/null +++ b/FirebaseAI/Tests/Unit/TestUtilities/FirebaseAI+DefaultAPIConfig.swift @@ -0,0 +1,22 @@ +// 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. + +@testable import FirebaseAI + +extension FirebaseAI { + static let defaultVertexAIAPIConfig = APIConfig( + service: .vertexAI(endpoint: .firebaseProxyProd, location: "us-central1"), + version: .v1beta + ) +}