diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index ff5db6078e7..35d87cc537d 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased +- [removed] Removed `CountTokensResponse.totalBillableCharacters` which was + deprecated in 11.15.0. Use `totalTokens` instead. (#15056) + # 11.15.0 - [fixed] Fixed `Sendable` warnings introduced in the Xcode 26 beta. (#14947) - [added] Added support for setting `title` in string, number and array `Schema` diff --git a/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift b/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift index 3247fd5ebb5..f282b02096b 100644 --- a/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift +++ b/FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift @@ -39,31 +39,11 @@ extension CountTokensRequest: GenerativeAIRequest { /// The model's response to a count tokens request. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct CountTokensResponse: Sendable { - /// Container for deprecated properties or methods. - /// - /// This workaround allows deprecated fields to be referenced internally (for example in the - /// `init(from:)` constructor) without introducing compiler warnings. - struct Deprecated { - let totalBillableCharacters: Int? - } - /// The total number of tokens in the input given to the model as a prompt. public let totalTokens: Int - /// The total number of billable characters in the text input given to the model as a prompt. - /// - /// > Important: This does not include billable image, video or other non-text input. See - /// [Vertex AI pricing](https://firebase.google.com/docs/vertex-ai/pricing) for details. - @available(*, deprecated, message: """ - Use `totalTokens` instead; Gemini 2.0 series models and newer are always billed by token count. - """) - public var totalBillableCharacters: Int? { deprecated.totalBillableCharacters } - /// The breakdown, by modality, of how many tokens are consumed by the prompt. public let promptTokensDetails: [ModalityTokenCount] - - /// Deprecated properties or methods. - let deprecated: Deprecated } // MARK: - Codable Conformances @@ -112,7 +92,6 @@ extension CountTokensRequest: Encodable { extension CountTokensResponse: Decodable { enum CodingKeys: CodingKey { case totalTokens - case totalBillableCharacters case promptTokensDetails } @@ -121,8 +100,5 @@ extension CountTokensResponse: Decodable { totalTokens = try container.decodeIfPresent(Int.self, forKey: .totalTokens) ?? 0 promptTokensDetails = try container.decodeIfPresent([ModalityTokenCount].self, forKey: .promptTokensDetails) ?? [] - let totalBillableCharacters = - try container.decodeIfPresent(Int.self, forKey: .totalBillableCharacters) - deprecated = CountTokensResponse.Deprecated(totalBillableCharacters: totalBillableCharacters) } } diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift index 3851fe527fa..1e68b640dfb 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/CountTokensIntegrationTests.swift @@ -57,12 +57,6 @@ struct CountTokensIntegrationTests { let response = try await model.countTokens(prompt) #expect(response.totalTokens == 6) - switch config.apiConfig.service { - case .vertexAI: - #expect(response.deprecated.totalBillableCharacters == 16) - case .googleAI: - #expect(response.deprecated.totalBillableCharacters == nil) - } #expect(response.promptTokensDetails.count == 1) let promptTokensDetails = try #require(response.promptTokensDetails.first) #expect(promptTokensDetails.modality == .text) @@ -81,12 +75,6 @@ struct CountTokensIntegrationTests { let response = try await model.countTokens("What is your favourite colour?") #expect(response.totalTokens == 14) - switch config.apiConfig.service { - case .vertexAI: - #expect(response.deprecated.totalBillableCharacters == 61) - case .googleAI: - #expect(response.deprecated.totalBillableCharacters == nil) - } #expect(response.promptTokensDetails.count == 1) let promptTokensDetails = try #require(response.promptTokensDetails.first) #expect(promptTokensDetails.modality == .text) @@ -115,12 +103,10 @@ struct CountTokensIntegrationTests { switch config.apiConfig.service { case .vertexAI: #expect(response.totalTokens == 65) - #expect(response.deprecated.totalBillableCharacters == 170) case .googleAI: // The Developer API erroneously ignores the `responseSchema` when counting tokens, resulting // in a lower total count than Vertex AI. #expect(response.totalTokens == 34) - #expect(response.deprecated.totalBillableCharacters == nil) } #expect(response.promptTokensDetails.count == 1) let promptTokensDetails = try #require(response.promptTokensDetails.first) diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift index 7ec14f8fef1..c4c49d4b45f 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift @@ -85,7 +85,6 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(prompt) XCTAssertEqual(response.totalTokens, 14) - XCTAssertEqual(response.deprecated.totalBillableCharacters, 51) XCTAssertEqual(response.promptTokensDetails.count, 1) let promptTokensDetails = try XCTUnwrap(response.promptTokensDetails.first) XCTAssertEqual(promptTokensDetails.modality, .text) @@ -102,7 +101,6 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(image) XCTAssertEqual(response.totalTokens, 266) - XCTAssertEqual(response.deprecated.totalBillableCharacters, 35) XCTAssertEqual(response.promptTokensDetails.count, 2) // Image prompt + system instruction let textPromptTokensDetails = try XCTUnwrap(response.promptTokensDetails.first { $0.modality == .text @@ -122,7 +120,6 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(fileData) XCTAssertEqual(response.totalTokens, 266) - XCTAssertEqual(response.deprecated.totalBillableCharacters, 35) XCTAssertEqual(response.promptTokensDetails.count, 2) // Image prompt + system instruction let textPromptTokensDetails = try XCTUnwrap(response.promptTokensDetails.first { $0.modality == .text @@ -141,7 +138,6 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(fileData) XCTAssertEqual(response.totalTokens, 266) - XCTAssertEqual(response.deprecated.totalBillableCharacters, 35) } func testCountTokens_image_fileData_requiresUserAuth_userSignedIn() async throws { @@ -152,7 +148,6 @@ final class IntegrationTests: XCTestCase { let response = try await model.countTokens(fileData) XCTAssertEqual(response.totalTokens, 266) - XCTAssertEqual(response.deprecated.totalBillableCharacters, 35) } func testCountTokens_image_fileData_requiresUserAuth_wrongUser_permissionDenied() async throws { @@ -193,7 +188,6 @@ final class IntegrationTests: XCTestCase { ]) XCTAssertGreaterThan(response.totalTokens, 0) - XCTAssertEqual(response.deprecated.totalBillableCharacters, 71) XCTAssertEqual(response.promptTokensDetails.count, 1) let promptTokensDetails = try XCTUnwrap(response.promptTokensDetails.first) XCTAssertEqual(promptTokensDetails.modality, .text) diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index 75a15376636..b03c3a0a9f6 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -1517,7 +1517,6 @@ final class GenerativeModelVertexAITests: XCTestCase { let response = try await model.countTokens("Why is the sky blue?") XCTAssertEqual(response.totalTokens, 6) - XCTAssertEqual(response.deprecated.totalBillableCharacters, 16) } func testCountTokens_succeeds_detailed() async throws { @@ -1530,7 +1529,6 @@ final class GenerativeModelVertexAITests: XCTestCase { let response = try await model.countTokens("Why is the sky blue?") XCTAssertEqual(response.totalTokens, 1837) - XCTAssertEqual(response.deprecated.totalBillableCharacters, 117) XCTAssertEqual(response.promptTokensDetails.count, 2) XCTAssertEqual(response.promptTokensDetails[0].modality, .image) XCTAssertEqual(response.promptTokensDetails[0].tokenCount, 1806) @@ -1577,7 +1575,6 @@ final class GenerativeModelVertexAITests: XCTestCase { let response = try await model.countTokens("Why is the sky blue?") XCTAssertEqual(response.totalTokens, 6) - XCTAssertEqual(response.deprecated.totalBillableCharacters, 16) } func testCountTokens_succeeds_noBillableCharacters() async throws { @@ -1590,7 +1587,6 @@ final class GenerativeModelVertexAITests: XCTestCase { let response = try await model.countTokens(InlineDataPart(data: Data(), mimeType: "image/jpeg")) XCTAssertEqual(response.totalTokens, 258) - XCTAssertNil(response.deprecated.totalBillableCharacters) } func testCountTokens_modelNotFound() async throws {