Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/sdk.ai.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ jobs:
with:
product: ${{ matrix.product }}
supports_swift6: true
allow_warnings: ${{ matrix.product == 'FirebaseAI' }}
setup_command: scripts/update_vertexai_responses.sh

quickstart:
Expand Down
2 changes: 1 addition & 1 deletion FirebaseAI/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Data types used in the FirebaseAI library.

### Public Types

- **`Backend.swift`**: Used to configure the backend API (Vertex AI or Google AI).
- **`Backend.swift`**: Used to configure the backend API (Gemini Enterprise Agent Platform or Google AI).
- **`ImageConfig.swift`**: Defines the `ImageConfig` struct, used for configuring generated image properties like aspect ratio and size.
- **`Part.swift`**: Defines the `Part` protocol and conforming structs (Text, InlineData, FunctionCall, etc.).
- **`ResponseModality.swift`**: Represents types of data a model can produce (text, image, audio).
Expand Down
1 change: 1 addition & 0 deletions FirebaseAI/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# 12.16.0
- [changed] Deprecated `Backend.vertexAI` in favor of `Backend.agentPlatform` (supporting `"global"` as the default location instead of `"us-central1"`).
Comment thread
paulb777 marked this conversation as resolved.
Outdated
- [fixed] Fixed a decoding failure in `GenerateContentResponse` when the Vertex AI
backend returns citation metadata with a missing `endIndex`. (#16328)
- [fixed] Fixed an issue where `generateContentStream` could stall indefinitely
Expand Down
2 changes: 1 addition & 1 deletion FirebaseAI/Sources/AILog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ enum AILog {
case verboseLoggingEnabled = 101

// API Enablement Errors
case vertexAIInFirebaseAPIDisabled = 200
case agentPlatformInFirebaseAPIDisabled = 200

// Generative Model Configuration
case generativeModelInitialized = 1000
Expand Down
4 changes: 2 additions & 2 deletions FirebaseAI/Sources/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ enum Constants {
#if DEBUG
/// The key for an environment variable containing a Google Cloud Access Token.
///
/// This should only be used for SDK development and testing with the Vertex AI direct backend
/// that bypasses the Firebase proxy..
/// This should only be used for SDK development and testing with the Gemini
/// Enterprise Agent Platform direct backend that bypasses the Firebase proxy.
///
/// The value should is typically obtained from the gcloud CLI by calling
/// `gcloud auth print-access-token`.
Expand Down
10 changes: 5 additions & 5 deletions FirebaseAI/Sources/FirebaseAI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -379,14 +379,14 @@ public final class FirebaseAI: Sendable {
}

switch apiConfig.service {
case let .vertexAI(endpoint: _, location: location):
return vertexAIModelResourceName(modelName: modelName, location: location)
case let .agentPlatform(endpoint: _, location: location):
return agentPlatformModelResourceName(modelName: modelName, location: location)
case .googleAI:
return developerModelResourceName(modelName: modelName)
}
}

private func vertexAIModelResourceName(modelName: String, location: String) -> String {
private func agentPlatformModelResourceName(modelName: String, location: String) -> String {
guard !location.isEmpty && location
.allSatisfy({ !$0.isWhitespace && !$0.isNewline && $0 != "/" }) else {
fatalError("""
Expand All @@ -409,9 +409,9 @@ public final class FirebaseAI: Sendable {
return "models/\(modelName)"
case .firebaseProxyStaging:
return "projects/\(firebaseInfo.projectID)/models/\(modelName)"
case .vertexAIStagingBypassProxy:
case .agentPlatformStagingBypassProxy:
fatalError(
"The Vertex AI staging endpoint does not support the Gemini Developer API (Google AI)."
"The Gemini Enterprise Agent Platform staging endpoint does not support the Gemini Developer API (Google AI)."
)
#endif // DEBUG
}
Expand Down
7 changes: 4 additions & 3 deletions FirebaseAI/Sources/GenerateContentResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,8 @@ public struct PromptFeedback: Sendable {
/// > Important: If using Grounding with Google Search, you are required to comply with the
/// "Grounding with Google Search" usage requirements for your chosen API provider:
/// [Gemini Developer API](https://ai.google.dev/gemini-api/terms#grounding-with-google-search)
/// or Vertex AI Gemini API (see [Service Terms](https://cloud.google.com/terms/service-terms)
/// or Gemini Enterprise Agent Platform Gemini API (see
/// [Service Terms](https://cloud.google.com/terms/service-terms)
/// section within the Service Specific Terms).
public struct GroundingMetadata: Sendable, Equatable, Hashable {
/// A list of web search queries that the model performed to gather the grounding information.
Expand Down Expand Up @@ -473,7 +474,7 @@ public struct GroundingMetadata: Sendable, Equatable, Hashable {
public let title: String?
/// The domain of the original URI from which the content was retrieved.
///
/// This field is only populated when using the Vertex AI Gemini API.
/// This field is only populated when using the Gemini Enterprise Agent Platform Gemini API.
public let domain: String?
}

Expand Down Expand Up @@ -677,7 +678,7 @@ extension Candidate: Decodable {

extension CitationMetadata: Decodable {
enum CodingKeys: CodingKey {
case citations // Vertex AI
case citations // Gemini Enterprise Agent Platform
case citationSources // Google AI
}

Expand Down
2 changes: 1 addition & 1 deletion FirebaseAI/Sources/GenerativeAIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ struct GenerativeAIService {
private func logRPCError(_ error: BackendError) {
let projectID = firebaseInfo.projectID
if error.isVertexAIInFirebaseServiceDisabledError() {
AILog.error(code: .vertexAIInFirebaseAPIDisabled, """
AILog.error(code: .agentPlatformInFirebaseAPIDisabled, """
The Firebase AI SDK requires the Firebase AI API \
(`firebasevertexai.googleapis.com`) to be enabled in your Firebase project. Enable this API \
by visiting the Firebase Console at
Expand Down
10 changes: 5 additions & 5 deletions FirebaseAI/Sources/GenerativeModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public final class GenerativeModel: Sendable {
/// - modelName: The name of the model.
/// - modelResourceName: The model resource name corresponding with `modelName` in the backend.
/// The form depends on the backend and will be one of:
/// - Vertex AI via Firebase AI SDK:
/// - Gemini Enterprise Agent Platform via Firebase AI SDK:
/// `"projects/{projectID}/locations/{locationID}/publishers/google/models/{modelName}"`
/// - Developer API via Firebase AI SDK: `"projects/{projectID}/models/{modelName}"`
/// - Developer API via Generative Language: `"models/{modelName}"`
Expand Down Expand Up @@ -207,7 +207,7 @@ public final class GenerativeModel: Sendable {
/// ``CountTokensResponse/totalTokens``.
public func countTokens(_ content: [ModelContent]) async throws -> CountTokensResponse {
let requestContent = switch apiConfig.service {
case .vertexAI:
case .agentPlatform:
content
case .googleAI:
// The `role` defaults to "user" but is ignored in `countTokens`. However, it is erroneously
Expand All @@ -222,7 +222,7 @@ public final class GenerativeModel: Sendable {
// "models/model-name". This field is unaltered by the Firebase backend before forwarding the
// request to the Generative Language backend, which expects the form "models/model-name".
let generateContentRequestModelResourceName = switch apiConfig.service {
case .vertexAI:
case .agentPlatform:
modelResourceName
case .googleAI(endpoint: .firebaseProxyProd):
"models/\(modelName)"
Expand All @@ -231,9 +231,9 @@ public final class GenerativeModel: Sendable {
"models/\(modelName)"
case .googleAI(endpoint: .googleAIBypassProxy):
modelResourceName
case .googleAI(endpoint: .vertexAIStagingBypassProxy):
case .googleAI(endpoint: .agentPlatformStagingBypassProxy):
fatalError(
"The Vertex AI staging endpoint does not support the Gemini Developer API (Google AI)."
"The Gemini Enterprise Agent Platform staging endpoint does not support the Gemini Developer API (Google AI)."
)
#endif // DEBUG
}
Expand Down
3 changes: 2 additions & 1 deletion FirebaseAI/Sources/Safety.swift
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,8 @@ extension SafetyRating: Decodable {
HarmProbability.self, forKey: .probability
) ?? .unspecified

// The following 3 fields are only provided when using the Vertex AI backend (not Google AI).
// The following 3 fields are only provided when using the Gemini Enterprise Agent Platform
// backend (not Google AI).
probabilityScore = try container.decodeIfPresent(Float.self, forKey: .probabilityScore) ?? 0.0
severity = try container.decodeIfPresent(HarmSeverity.self, forKey: .severity) ?? .unspecified
severityScore = try container.decodeIfPresent(Float.self, forKey: .severityScore) ?? 0.0
Expand Down
2 changes: 1 addition & 1 deletion FirebaseAI/Sources/TemplateGenerateContentRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ extension TemplateGenerateContentRequest: GenerativeAIRequest {
func getURL() throws -> URL {
var urlString =
"\(apiConfig.service.endpoint.rawValue)/\(apiConfig.version.rawValue)/projects/\(projectID)"
if case let .vertexAI(_, location) = apiConfig.service {
if case let .agentPlatform(_, location) = apiConfig.service {
urlString += "/locations/\(location)"
}

Expand Down
2 changes: 1 addition & 1 deletion FirebaseAI/Sources/TemplateImagenGenerationRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ extension TemplateImagenGenerationRequest: GenerativeAIRequest where ImageType:
func getURL() throws -> URL {
var urlString =
"\(apiConfig.service.endpoint.rawValue)/\(apiConfig.version.rawValue)/projects/\(projectID)"
if case let .vertexAI(_, location) = apiConfig.service {
if case let .agentPlatform(_, location) = apiConfig.service {
urlString += "/locations/\(location)"
}
urlString += "/templates/\(template):\(ImageAPIMethod.generateImages.rawValue)"
Expand Down
6 changes: 4 additions & 2 deletions FirebaseAI/Sources/Tool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ public struct FunctionDeclaration: Sendable {
/// > Important: When using this feature, you are required to comply with the
/// "Grounding with Google Search" usage requirements for your chosen API provider:
/// [Gemini Developer API](https://ai.google.dev/gemini-api/terms#grounding-with-google-search)
/// or Vertex AI Gemini API (see [Service Terms](https://cloud.google.com/terms/service-terms)
/// or Gemini Enterprise Agent Platform Gemini API (see
/// [Service Terms](https://cloud.google.com/terms/service-terms)
/// section within the Service Specific Terms).
public struct GoogleSearch: Sendable {
public init() {}
Expand Down Expand Up @@ -284,7 +285,8 @@ public extension ToolRepresentable where Self == FirebaseAILogic.Tool {
/// > Important: When using this feature, you are required to comply with the
/// "Grounding with Google Search" usage requirements for your chosen API provider:
/// [Gemini Developer API](https://ai.google.dev/gemini-api/terms#grounding-with-google-search)
/// or Vertex AI Gemini API (see [Service Terms](https://cloud.google.com/terms/service-terms)
/// or Gemini Enterprise Agent Platform Gemini API (see
/// [Service Terms](https://cloud.google.com/terms/service-terms)
/// section within the Service Specific Terms).
///
/// - Parameters:
Expand Down
30 changes: 18 additions & 12 deletions FirebaseAI/Sources/Types/Internal/APIConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ struct APIConfig: Sendable, Hashable, Encodable {
extension APIConfig {
/// API services providing generative AI functionality.
///
/// See [Vertex AI and Google AI
/// See [Gemini Enterprise Agent Platform and Google AI
/// differences](https://cloud.google.com/vertex-ai/generative-ai/docs/overview#how-gemini-vertex-different-gemini-aistudio)
/// for a comparison of the two [API services](https://google.aip.dev/9#api-service).
enum Service: Hashable, Encodable {
/// Vertex AI Gemini API.
/// Gemini Enterprise Agent Platform Gemini API.
///
/// See the [Cloud
/// docs](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference) for
/// more details.
case vertexAI(endpoint: Endpoint, location: String)
case agentPlatform(endpoint: Endpoint, location: String)

/// The Gemini Developer API provided by Google AI.
///
Expand All @@ -57,7 +57,7 @@ extension APIConfig {
/// This must correspond with the API set in `service`.
var endpoint: Endpoint {
switch self {
case let .vertexAI(endpoint: endpoint, _):
case let .agentPlatform(endpoint: endpoint, _):
return endpoint
case let .googleAI(endpoint: endpoint):
return endpoint
Expand All @@ -72,28 +72,33 @@ extension APIConfig.Service {
enum Endpoint: String, Encodable {
/// The Firebase proxy production endpoint.
///
/// This endpoint supports both Google AI and Vertex AI.
/// This endpoint supports both Google AI and Gemini Enterprise Agent Platform.
case firebaseProxyProd = "https://firebasevertexai.googleapis.com"

#if DEBUG
/// The Firebase proxy staging endpoint; for SDK development and testing only.
///
/// This endpoint supports both the Gemini Developer API (commonly referred to as Google AI)
/// and the Gemini API in Vertex AI (commonly referred to simply as Vertex AI).
/// and the Gemini API in Gemini Enterprise Agent Platform (commonly referred to simply as
/// Gemini Enterprise Agent Platform).
case firebaseProxyStaging = "https://staging-firebasevertexai.sandbox.googleapis.com"

/// The Gemini Developer API (Google AI) direct production endpoint; for SDK development and
/// testing only.
///
/// This bypasses the Firebase proxy and directly connects to the Gemini Developer API
/// (Google AI) backend. This endpoint only supports the Gemini Developer API, not Vertex AI.
/// (Google AI) backend. This endpoint only supports the Gemini Developer API, not Gemini
/// Enterprise Agent Platform.
case googleAIBypassProxy = "https://generativelanguage.googleapis.com"

/// The Vertex AI direct staging endpoint; for SDK development and testing only.
/// The Gemini Enterprise Agent Platform direct staging endpoint; for SDK development and
/// testing only.
///
/// This bypasses the Firebase proxy and directly connects to the Vertex AI backend. This
/// endpoint only supports the Gemini API in Vertex AI, not the Gemini Developer API.
case vertexAIStagingBypassProxy = "https://staging-aiplatform.sandbox.googleapis.com"
/// This bypasses the Firebase proxy and directly connects to the Gemini Enterprise Agent
/// Platform backend. This
/// endpoint only supports the Gemini API in Gemini Enterprise Agent Platform, not the Gemini
/// Developer API.
case agentPlatformStagingBypassProxy = "https://staging-aiplatform.sandbox.googleapis.com"
#endif // DEBUG
}
}
Expand All @@ -109,7 +114,8 @@ extension APIConfig {
/// only.
case v1

/// The beta channel for version 1 of the direct Vertex AI API, when bypassing the Firebase
/// The beta channel for version 1 of the direct Gemini Enterprise Agent Platform API, when
/// bypassing the Firebase
/// proxy; for SDK development and testing only.
case v1beta1
#endif // DEBUG
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,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(_, location: location):
case let .agentPlatform(_, location: location):
"wss://\(host)/ws/google.firebase.vertexai.\(apiConfig.version.rawValue).LlmBidiService/BidiGenerateContent/locations/\(location)"
case .googleAI:
"wss://\(host)/ws/google.firebase.vertexai.\(apiConfig.version.rawValue).GenerativeService/BidiGenerateContent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ extension CountTokensRequest: Encodable {

func encode(to encoder: any Encoder) throws {
switch apiConfig.service {
case .vertexAI:
case .agentPlatform:
try encodeForVertexAI(to: encoder)
case .googleAI:
try encodeForDeveloper(to: encoder)
Expand Down
46 changes: 41 additions & 5 deletions FirebaseAI/Sources/Types/Public/Backend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,51 @@ public struct Backend {

/// Initializes a `Backend` configured for the Gemini API in Vertex AI.
///
/// Defaults to the location `us-central1`; see
/// [Vertex AI locations](https://firebase.google.com/docs/vertex-ai/locations?platform=ios#available-locations)
/// for a list of supported locations.
@available(*, deprecated, message: """
Use agentPlatform(location:) instead; note that the default location is now "global" instead of "us-central1"
""")
public static func vertexAI() -> Backend {
return Backend(
apiConfig: APIConfig(
service: .agentPlatform(endpoint: .firebaseProxyProd, location: "us-central1"),
version: .v1beta
)
)
}

/// Initializes a `Backend` configured for the Gemini API in Vertex AI.
///
/// - Parameters:
/// - location: The region identifier; see
/// [Vertex AI locations](https://firebase.google.com/docs/vertex-ai/locations?platform=ios#available-locations)
/// for a list of supported locations.
@available(*, deprecated, renamed: "agentPlatform(location:)", message: """
Vertex AI has been renamed to the Gemini Enterprise Agent Platform.
""")
public static func vertexAI(location: String) -> Backend {
return Backend(
apiConfig: APIConfig(
service: .agentPlatform(endpoint: .firebaseProxyProd, location: location),
version: .v1beta
)
)
}

/// Initializes a `Backend` configured for the Gemini Enterprise Agent Platform.
///
/// > Note: The Gemini Enterprise Agent Platform was formerly known as the Vertex AI.
///
/// - Parameters:
/// - location: The region identifier, defaulting to `us-central1`; see
/// [Vertex AI locations]
/// (https://firebase.google.com/docs/vertex-ai/locations?platform=ios#available-locations)
/// - location: The region identifier, defaulting to `global`; see
/// [Vertex AI locations](https://firebase.google.com/docs/vertex-ai/locations?platform=ios#available-locations)
/// for a list of supported locations.
public static func vertexAI(location: String = "us-central1") -> Backend {
public static func agentPlatform(location: String = "global") -> Backend {
return Backend(
apiConfig: APIConfig(
service: .vertexAI(endpoint: .firebaseProxyProd, location: location),
service: .agentPlatform(endpoint: .firebaseProxyProd, location: location),
version: .v1beta
)
)
Expand Down
3 changes: 2 additions & 1 deletion FirebaseAI/Sources/Types/Public/GeminiModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
import Foundation

#if compiler(>=6.2.3)
/// A Gemini model accessed via the Gemini Developer API or the Vertex AI API.
/// A Gemini model accessed via the Gemini Developer API or the Gemini Enterprise Agent Platform
/// API.
///
/// **Public Preview**: This API is a public preview and may be subject to change.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
/// (the "Nano Banana" models).](https://firebase.google.com/docs/ai-logic/imagen-models-migration)
/// }
///
/// Text prompts provided as inputs and images (generated or uploaded) through Imagen on Vertex AI
/// Text prompts provided as inputs and images (generated or uploaded) through Imagen on Gemini
/// Enterprise Agent Platform
/// are assessed against a list of safety filters, which include 'harmful categories' (for example,
/// `violence`, `sexual`, `derogatory`, and `toxic`). This filter level controls how aggressively to
/// filter out potentially harmful content from responses. See the
Expand Down
3 changes: 2 additions & 1 deletion FirebaseAI/Sources/Types/Public/SpeakerVoiceConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public struct SpeakerVoiceConfig: Sendable {
///
/// Find the list of supported voices for:
/// - [Gemini Developer API](https://ai.google.dev/gemini-api/docs/speech-generation)
/// - [Vertex AI Gemini API](https://docs.cloud.google.com/text-to-speech/docs/gemini-tts)
/// - [Gemini Enterprise Agent Platform Gemini
/// API](https://docs.cloud.google.com/text-to-speech/docs/gemini-tts)
// TODO(b/522397979): Update links to point to Firebase when they're live
public init(speaker: String, voiceName: String) {
self.init(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ struct CountTokensIntegrationTests {
let response = try await model.countTokens(prompt)

switch config.apiConfig.service {
case .vertexAI:
case .agentPlatform:
#expect(response.totalTokens == 65)
case .googleAI:
// The Developer API erroneously ignores the `responseSchema` when counting tokens, resulting
Expand Down
Loading
Loading